pyo3/conversions/std/
string.rs1use std::{borrow::Cow, convert::Infallible};
2
3#[cfg(feature = "experimental-inspect")]
4use crate::inspect::types::TypeInfo;
5use crate::{
6 conversion::IntoPyObject, instance::Bound, types::PyString, Borrowed, FromPyObject, PyAny,
7 PyErr, Python,
8};
9
10impl<'py> IntoPyObject<'py> for &str {
11 type Target = PyString;
12 type Output = Bound<'py, Self::Target>;
13 type Error = Infallible;
14
15 #[cfg(feature = "experimental-inspect")]
16 const OUTPUT_TYPE: &'static str = String::OUTPUT_TYPE;
17
18 #[inline]
19 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
20 Ok(PyString::new(py, self))
21 }
22
23 #[cfg(feature = "experimental-inspect")]
24 fn type_output() -> TypeInfo {
25 <String>::type_output()
26 }
27}
28
29impl<'py> IntoPyObject<'py> for &&str {
30 type Target = PyString;
31 type Output = Bound<'py, Self::Target>;
32 type Error = Infallible;
33
34 #[cfg(feature = "experimental-inspect")]
35 const OUTPUT_TYPE: &'static str = String::OUTPUT_TYPE;
36
37 #[inline]
38 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
39 (*self).into_pyobject(py)
40 }
41
42 #[cfg(feature = "experimental-inspect")]
43 fn type_output() -> TypeInfo {
44 <String>::type_output()
45 }
46}
47
48impl<'py> IntoPyObject<'py> for Cow<'_, str> {
49 type Target = PyString;
50 type Output = Bound<'py, Self::Target>;
51 type Error = Infallible;
52
53 #[cfg(feature = "experimental-inspect")]
54 const OUTPUT_TYPE: &'static str = String::OUTPUT_TYPE;
55
56 #[inline]
57 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
58 (*self).into_pyobject(py)
59 }
60
61 #[cfg(feature = "experimental-inspect")]
62 fn type_output() -> TypeInfo {
63 <String>::type_output()
64 }
65}
66
67impl<'py> IntoPyObject<'py> for &Cow<'_, str> {
68 type Target = PyString;
69 type Output = Bound<'py, Self::Target>;
70 type Error = Infallible;
71
72 #[cfg(feature = "experimental-inspect")]
73 const OUTPUT_TYPE: &'static str = String::OUTPUT_TYPE;
74
75 #[inline]
76 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
77 (&**self).into_pyobject(py)
78 }
79
80 #[cfg(feature = "experimental-inspect")]
81 fn type_output() -> TypeInfo {
82 <String>::type_output()
83 }
84}
85
86impl<'py> IntoPyObject<'py> for char {
87 type Target = PyString;
88 type Output = Bound<'py, Self::Target>;
89 type Error = Infallible;
90
91 #[cfg(feature = "experimental-inspect")]
92 const OUTPUT_TYPE: &'static str = String::OUTPUT_TYPE;
93
94 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
95 let mut bytes = [0u8; 4];
96 Ok(PyString::new(py, self.encode_utf8(&mut bytes)))
97 }
98
99 #[cfg(feature = "experimental-inspect")]
100 fn type_output() -> TypeInfo {
101 <String>::type_output()
102 }
103}
104
105impl<'py> IntoPyObject<'py> for &char {
106 type Target = PyString;
107 type Output = Bound<'py, Self::Target>;
108 type Error = Infallible;
109
110 #[cfg(feature = "experimental-inspect")]
111 const OUTPUT_TYPE: &'static str = String::OUTPUT_TYPE;
112
113 #[inline]
114 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
115 (*self).into_pyobject(py)
116 }
117
118 #[cfg(feature = "experimental-inspect")]
119 fn type_output() -> TypeInfo {
120 <String>::type_output()
121 }
122}
123
124impl<'py> IntoPyObject<'py> for String {
125 type Target = PyString;
126 type Output = Bound<'py, Self::Target>;
127 type Error = Infallible;
128
129 #[cfg(feature = "experimental-inspect")]
130 const OUTPUT_TYPE: &'static str = "str";
131
132 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
133 Ok(PyString::new(py, &self))
134 }
135
136 #[cfg(feature = "experimental-inspect")]
137 fn type_output() -> TypeInfo {
138 TypeInfo::builtin("str")
139 }
140}
141
142impl<'py> IntoPyObject<'py> for &String {
143 type Target = PyString;
144 type Output = Bound<'py, Self::Target>;
145 type Error = Infallible;
146
147 #[cfg(feature = "experimental-inspect")]
148 const OUTPUT_TYPE: &'static str = String::OUTPUT_TYPE;
149
150 #[inline]
151 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
152 Ok(PyString::new(py, self))
153 }
154
155 #[cfg(feature = "experimental-inspect")]
156 fn type_output() -> TypeInfo {
157 <String>::type_output()
158 }
159}
160
161#[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
162impl<'a> crate::conversion::FromPyObject<'a, '_> for &'a str {
163 type Error = PyErr;
164
165 #[cfg(feature = "experimental-inspect")]
166 const INPUT_TYPE: &'static str = "str";
167
168 fn extract(ob: crate::Borrowed<'a, '_, PyAny>) -> Result<Self, Self::Error> {
169 ob.cast::<PyString>()?.to_str()
170 }
171
172 #[cfg(feature = "experimental-inspect")]
173 fn type_input() -> TypeInfo {
174 <String as crate::FromPyObject>::type_input()
175 }
176}
177
178impl<'a> crate::conversion::FromPyObject<'a, '_> for Cow<'a, str> {
179 type Error = PyErr;
180
181 #[cfg(feature = "experimental-inspect")]
182 const INPUT_TYPE: &'static str = "str";
183
184 fn extract(ob: crate::Borrowed<'a, '_, PyAny>) -> Result<Self, Self::Error> {
185 ob.cast::<PyString>()?.to_cow()
186 }
187
188 #[cfg(feature = "experimental-inspect")]
189 fn type_input() -> TypeInfo {
190 <String as crate::FromPyObject>::type_input()
191 }
192}
193
194impl FromPyObject<'_, '_> for String {
197 type Error = PyErr;
198
199 #[cfg(feature = "experimental-inspect")]
200 const INPUT_TYPE: &'static str = "str";
201
202 fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result<Self, Self::Error> {
203 obj.cast::<PyString>()?.to_cow().map(Cow::into_owned)
204 }
205
206 #[cfg(feature = "experimental-inspect")]
207 fn type_input() -> TypeInfo {
208 Self::type_output()
209 }
210}
211
212impl FromPyObject<'_, '_> for char {
213 type Error = PyErr;
214
215 #[cfg(feature = "experimental-inspect")]
216 const INPUT_TYPE: &'static str = "str";
217
218 fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result<Self, Self::Error> {
219 let s = obj.cast::<PyString>()?.to_cow()?;
220 let mut iter = s.chars();
221 if let (Some(ch), None) = (iter.next(), iter.next()) {
222 Ok(ch)
223 } else {
224 Err(crate::exceptions::PyValueError::new_err(
225 "expected a string of length 1",
226 ))
227 }
228 }
229
230 #[cfg(feature = "experimental-inspect")]
231 fn type_input() -> TypeInfo {
232 <String>::type_input()
233 }
234}
235
236#[cfg(test)]
237mod tests {
238 use crate::types::any::PyAnyMethods;
239 use crate::{IntoPyObject, Python};
240 use std::borrow::Cow;
241
242 #[test]
243 fn test_cow_into_pyobject() {
244 Python::attach(|py| {
245 let s = "Hello Python";
246 let py_string = Cow::Borrowed(s).into_pyobject(py).unwrap();
247 assert_eq!(s, py_string.extract::<Cow<'_, str>>().unwrap());
248 let py_string = Cow::<str>::Owned(s.into()).into_pyobject(py).unwrap();
249 assert_eq!(s, py_string.extract::<Cow<'_, str>>().unwrap());
250 })
251 }
252
253 #[test]
254 fn test_non_bmp() {
255 Python::attach(|py| {
256 let s = "\u{1F30F}";
257 let py_string = s.into_pyobject(py).unwrap();
258 assert_eq!(s, py_string.extract::<String>().unwrap());
259 })
260 }
261
262 #[test]
263 fn test_extract_str() {
264 Python::attach(|py| {
265 let s = "Hello Python";
266 let py_string = s.into_pyobject(py).unwrap();
267
268 let s2: Cow<'_, str> = py_string.extract().unwrap();
269 assert_eq!(s, s2);
270 })
271 }
272
273 #[test]
274 fn test_extract_char() {
275 Python::attach(|py| {
276 let ch = '😃';
277 let py_string = ch.into_pyobject(py).unwrap();
278 let ch2: char = py_string.extract().unwrap();
279 assert_eq!(ch, ch2);
280 })
281 }
282
283 #[test]
284 fn test_extract_char_err() {
285 Python::attach(|py| {
286 let s = "Hello Python";
287 let py_string = s.into_pyobject(py).unwrap();
288 let err: crate::PyResult<char> = py_string.extract();
289 assert!(err
290 .unwrap_err()
291 .to_string()
292 .contains("expected a string of length 1"));
293 })
294 }
295
296 #[test]
297 fn test_string_into_pyobject() {
298 Python::attach(|py| {
299 let s = "Hello Python";
300 let s2 = s.to_owned();
301 let s3 = &s2;
302 assert_eq!(
303 s,
304 s3.into_pyobject(py)
305 .unwrap()
306 .extract::<Cow<'_, str>>()
307 .unwrap()
308 );
309 assert_eq!(
310 s,
311 s2.into_pyobject(py)
312 .unwrap()
313 .extract::<Cow<'_, str>>()
314 .unwrap()
315 );
316 assert_eq!(
317 s,
318 s.into_pyobject(py)
319 .unwrap()
320 .extract::<Cow<'_, str>>()
321 .unwrap()
322 );
323 })
324 }
325}