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