1use std::borrow::Cow;
2
3#[cfg(feature = "experimental-inspect")]
4use crate::inspect::types::TypeInfo;
5use crate::{
6 types::PyString, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject,
7};
8
9/// Converts a Rust `str` to a Python object.
10/// See `PyString::new` for details on the conversion.
11impl ToPyObject for str {
12 #[inline]
13 fn to_object(&self, py: Python<'_>) -> PyObject {
14 PyString::new(py, self).into()
15 }
16}
17
18impl<'a> IntoPy<PyObject> for &'a str {
19 #[inline]
20 fn into_py(self, py: Python<'_>) -> PyObject {
21 PyString::new(py, self).into()
22 }
23
24 #[cfg(feature = "experimental-inspect")]
25 fn type_output() -> TypeInfo {
26 <String>::type_output()
27 }
28}
29
30impl<'a> IntoPy<Py<PyString>> for &'a str {
31 #[inline]
32 fn into_py(self, py: Python<'_>) -> Py<PyString> {
33 PyString::new(py, self).into()
34 }
35
36 #[cfg(feature = "experimental-inspect")]
37 fn type_output() -> TypeInfo {
38 <String>::type_output()
39 }
40}
41
42/// Converts a Rust `Cow<'_, str>` to a Python object.
43/// See `PyString::new` for details on the conversion.
44impl ToPyObject for Cow<'_, str> {
45 #[inline]
46 fn to_object(&self, py: Python<'_>) -> PyObject {
47 PyString::new(py, self).into()
48 }
49}
50
51impl IntoPy<PyObject> for Cow<'_, str> {
52 #[inline]
53 fn into_py(self, py: Python<'_>) -> PyObject {
54 self.to_object(py)
55 }
56
57 #[cfg(feature = "experimental-inspect")]
58 fn type_output() -> TypeInfo {
59 <String>::type_output()
60 }
61}
62
63/// Converts a Rust `String` to a Python object.
64/// See `PyString::new` for details on the conversion.
65impl ToPyObject for String {
66 #[inline]
67 fn to_object(&self, py: Python<'_>) -> PyObject {
68 PyString::new(py, self).into()
69 }
70}
71
72impl ToPyObject for char {
73 fn to_object(&self, py: Python<'_>) -> PyObject {
74 self.into_py(py)
75 }
76}
77
78impl IntoPy<PyObject> for char {
79 fn into_py(self, py: Python<'_>) -> PyObject {
80 let mut bytes: [u8; 4] = [0u8; 4];
81 PyString::new(py, self.encode_utf8(&mut bytes)).into()
82 }
83
84 #[cfg(feature = "experimental-inspect")]
85 fn type_output() -> TypeInfo {
86 <String>::type_output()
87 }
88}
89
90impl IntoPy<PyObject> for String {
91 fn into_py(self, py: Python<'_>) -> PyObject {
92 PyString::new(py, &self).into()
93 }
94
95 #[cfg(feature = "experimental-inspect")]
96 fn type_output() -> TypeInfo {
97 TypeInfo::builtin("str")
98 }
99}
100
101impl<'a> IntoPy<PyObject> for &'a String {
102 #[inline]
103 fn into_py(self, py: Python<'_>) -> PyObject {
104 PyString::new(py, self).into()
105 }
106
107 #[cfg(feature = "experimental-inspect")]
108 fn type_output() -> TypeInfo {
109 <String>::type_output()
110 }
111}
112
113/// Allows extracting strings from Python objects.
114/// Accepts Python `str` and `unicode` objects.
115impl<'source> FromPyObject<'source> for &'source str {
116 fn extract(ob: &'source PyAny) -> PyResult<Self> {
117 ob.downcast::<PyString>()?.to_str()
118 }
119
120 #[cfg(feature = "experimental-inspect")]
121 fn type_input() -> TypeInfo {
122 <String>::type_input()
123 }
124}
125
126/// Allows extracting strings from Python objects.
127/// Accepts Python `str` and `unicode` objects.
128impl FromPyObject<'_> for String {
129 fn extract(obj: &PyAny) -> PyResult<Self> {
130 obj.downcast::<PyString>()?.to_str().map(op:ToOwned::to_owned)
131 }
132
133 #[cfg(feature = "experimental-inspect")]
134 fn type_input() -> TypeInfo {
135 Self::type_output()
136 }
137}
138
139impl FromPyObject<'_> for char {
140 fn extract(obj: &PyAny) -> PyResult<Self> {
141 let s: &str = obj.downcast::<PyString>()?.to_str()?;
142 let mut iter: Chars<'_> = s.chars();
143 if let (Some(ch: char), None) = (iter.next(), iter.next()) {
144 Ok(ch)
145 } else {
146 Err(crate::exceptions::PyValueError::new_err(
147 args:"expected a string of length 1",
148 ))
149 }
150 }
151
152 #[cfg(feature = "experimental-inspect")]
153 fn type_input() -> TypeInfo {
154 <String>::type_input()
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use crate::Python;
161 use crate::{FromPyObject, IntoPy, PyObject, ToPyObject};
162 use std::borrow::Cow;
163
164 #[test]
165 fn test_cow_into_py() {
166 Python::with_gil(|py| {
167 let s = "Hello Python";
168 let py_string: PyObject = Cow::Borrowed(s).into_py(py);
169 assert_eq!(s, py_string.extract::<&str>(py).unwrap());
170 let py_string: PyObject = Cow::<str>::Owned(s.into()).into_py(py);
171 assert_eq!(s, py_string.extract::<&str>(py).unwrap());
172 })
173 }
174
175 #[test]
176 fn test_cow_to_object() {
177 Python::with_gil(|py| {
178 let s = "Hello Python";
179 let py_string = Cow::Borrowed(s).to_object(py);
180 assert_eq!(s, py_string.extract::<&str>(py).unwrap());
181 let py_string = Cow::<str>::Owned(s.into()).to_object(py);
182 assert_eq!(s, py_string.extract::<&str>(py).unwrap());
183 })
184 }
185
186 #[test]
187 fn test_non_bmp() {
188 Python::with_gil(|py| {
189 let s = "\u{1F30F}";
190 let py_string = s.to_object(py);
191 assert_eq!(s, py_string.extract::<String>(py).unwrap());
192 })
193 }
194
195 #[test]
196 fn test_extract_str() {
197 Python::with_gil(|py| {
198 let s = "Hello Python";
199 let py_string = s.to_object(py);
200
201 let s2: &str = FromPyObject::extract(py_string.as_ref(py)).unwrap();
202 assert_eq!(s, s2);
203 })
204 }
205
206 #[test]
207 fn test_extract_char() {
208 Python::with_gil(|py| {
209 let ch = '😃';
210 let py_string = ch.to_object(py);
211 let ch2: char = FromPyObject::extract(py_string.as_ref(py)).unwrap();
212 assert_eq!(ch, ch2);
213 })
214 }
215
216 #[test]
217 fn test_extract_char_err() {
218 Python::with_gil(|py| {
219 let s = "Hello Python";
220 let py_string = s.to_object(py);
221 let err: crate::PyResult<char> = FromPyObject::extract(py_string.as_ref(py));
222 assert!(err
223 .unwrap_err()
224 .to_string()
225 .contains("expected a string of length 1"));
226 })
227 }
228
229 #[test]
230 fn test_string_into_py() {
231 Python::with_gil(|py| {
232 let s = "Hello Python";
233 let s2 = s.to_owned();
234 let s3 = &s2;
235 assert_eq!(
236 s,
237 IntoPy::<PyObject>::into_py(s3, py)
238 .extract::<&str>(py)
239 .unwrap()
240 );
241 assert_eq!(
242 s,
243 IntoPy::<PyObject>::into_py(s2, py)
244 .extract::<&str>(py)
245 .unwrap()
246 );
247 assert_eq!(
248 s,
249 IntoPy::<PyObject>::into_py(s, py)
250 .extract::<&str>(py)
251 .unwrap()
252 );
253 })
254 }
255}
256