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