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