pyo3/conversions/std/
slice.rs1use std::borrow::Cow;
2
3#[cfg(feature = "experimental-inspect")]
4use crate::inspect::types::TypeInfo;
5use crate::{
6 conversion::IntoPyObject,
7 types::{PyByteArray, PyByteArrayMethods, PyBytes},
8 Bound, Py, PyAny, PyErr, PyObject, PyResult, Python,
9};
10#[allow(deprecated)]
11use crate::{IntoPy, ToPyObject};
12
13#[allow(deprecated)]
14impl IntoPy<PyObject> for &[u8] {
15 fn into_py(self, py: Python<'_>) -> PyObject {
16 PyBytes::new(py, self).unbind().into()
17 }
18}
19
20impl<'a, 'py, T> IntoPyObject<'py> for &'a [T]
21where
22 &'a T: IntoPyObject<'py>,
23 T: 'a, {
25 type Target = PyAny;
26 type Output = Bound<'py, Self::Target>;
27 type Error = PyErr;
28
29 #[inline]
34 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
35 <&T>::borrowed_sequence_into_pyobject(self, py, crate::conversion::private::Token)
36 }
37
38 #[cfg(feature = "experimental-inspect")]
39 fn type_output() -> TypeInfo {
40 TypeInfo::union_of(&[
41 TypeInfo::builtin("bytes"),
42 TypeInfo::list_of(<&T>::type_output()),
43 ])
44 }
45}
46
47impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for &'a [u8] {
48 fn from_py_object_bound(obj: crate::Borrowed<'a, '_, PyAny>) -> PyResult<Self> {
49 Ok(obj.downcast::<PyBytes>()?.as_bytes())
50 }
51
52 #[cfg(feature = "experimental-inspect")]
53 fn type_input() -> TypeInfo {
54 TypeInfo::builtin("bytes")
55 }
56}
57
58impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for Cow<'a, [u8]> {
64 fn from_py_object_bound(ob: crate::Borrowed<'a, '_, PyAny>) -> PyResult<Self> {
65 if let Ok(bytes) = ob.downcast::<PyBytes>() {
66 return Ok(Cow::Borrowed(bytes.as_bytes()));
67 }
68
69 let byte_array = ob.downcast::<PyByteArray>()?;
70 Ok(Cow::Owned(byte_array.to_vec()))
71 }
72
73 #[cfg(feature = "experimental-inspect")]
74 fn type_input() -> TypeInfo {
75 Self::type_output()
76 }
77}
78
79#[allow(deprecated)]
80impl ToPyObject for Cow<'_, [u8]> {
81 fn to_object(&self, py: Python<'_>) -> Py<PyAny> {
82 PyBytes::new(py, self.as_ref()).into()
83 }
84}
85
86#[allow(deprecated)]
87impl IntoPy<Py<PyAny>> for Cow<'_, [u8]> {
88 fn into_py(self, py: Python<'_>) -> Py<PyAny> {
89 self.into_pyobject(py).unwrap().into_any().unbind()
90 }
91}
92
93impl<'py, T> IntoPyObject<'py> for Cow<'_, [T]>
94where
95 T: Clone,
96 for<'a> &'a T: IntoPyObject<'py>,
97{
98 type Target = PyAny;
99 type Output = Bound<'py, Self::Target>;
100 type Error = PyErr;
101
102 #[inline]
107 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
108 <&T>::borrowed_sequence_into_pyobject(self.as_ref(), py, crate::conversion::private::Token)
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use std::borrow::Cow;
115
116 use crate::{
117 conversion::IntoPyObject,
118 ffi,
119 types::{any::PyAnyMethods, PyBytes, PyBytesMethods, PyList},
120 Python,
121 };
122
123 #[test]
124 fn test_extract_bytes() {
125 Python::with_gil(|py| {
126 let py_bytes = py.eval(ffi::c_str!("b'Hello Python'"), None, None).unwrap();
127 let bytes: &[u8] = py_bytes.extract().unwrap();
128 assert_eq!(bytes, b"Hello Python");
129 });
130 }
131
132 #[test]
133 fn test_cow_impl() {
134 Python::with_gil(|py| {
135 let bytes = py.eval(ffi::c_str!(r#"b"foobar""#), None, None).unwrap();
136 let cow = bytes.extract::<Cow<'_, [u8]>>().unwrap();
137 assert_eq!(cow, Cow::<[u8]>::Borrowed(b"foobar"));
138
139 let byte_array = py
140 .eval(ffi::c_str!(r#"bytearray(b"foobar")"#), None, None)
141 .unwrap();
142 let cow = byte_array.extract::<Cow<'_, [u8]>>().unwrap();
143 assert_eq!(cow, Cow::<[u8]>::Owned(b"foobar".to_vec()));
144
145 let something_else_entirely = py.eval(ffi::c_str!("42"), None, None).unwrap();
146 something_else_entirely
147 .extract::<Cow<'_, [u8]>>()
148 .unwrap_err();
149
150 let cow = Cow::<[u8]>::Borrowed(b"foobar").into_pyobject(py).unwrap();
151 assert!(cow.is_instance_of::<PyBytes>());
152
153 let cow = Cow::<[u8]>::Owned(b"foobar".to_vec())
154 .into_pyobject(py)
155 .unwrap();
156 assert!(cow.is_instance_of::<PyBytes>());
157 });
158 }
159
160 #[test]
161 fn test_slice_intopyobject_impl() {
162 Python::with_gil(|py| {
163 let bytes: &[u8] = b"foobar";
164 let obj = bytes.into_pyobject(py).unwrap();
165 assert!(obj.is_instance_of::<PyBytes>());
166 let obj = obj.downcast_into::<PyBytes>().unwrap();
167 assert_eq!(obj.as_bytes(), bytes);
168
169 let nums: &[u16] = &[0, 1, 2, 3];
170 let obj = nums.into_pyobject(py).unwrap();
171 assert!(obj.is_instance_of::<PyList>());
172 });
173 }
174
175 #[test]
176 fn test_cow_intopyobject_impl() {
177 Python::with_gil(|py| {
178 let borrowed_bytes = Cow::<[u8]>::Borrowed(b"foobar");
179 let obj = borrowed_bytes.clone().into_pyobject(py).unwrap();
180 assert!(obj.is_instance_of::<PyBytes>());
181 let obj = obj.downcast_into::<PyBytes>().unwrap();
182 assert_eq!(obj.as_bytes(), &*borrowed_bytes);
183
184 let owned_bytes = Cow::<[u8]>::Owned(b"foobar".to_vec());
185 let obj = owned_bytes.clone().into_pyobject(py).unwrap();
186 assert!(obj.is_instance_of::<PyBytes>());
187 let obj = obj.downcast_into::<PyBytes>().unwrap();
188 assert_eq!(obj.as_bytes(), &*owned_bytes);
189
190 let borrowed_nums = Cow::<[u16]>::Borrowed(&[0, 1, 2, 3]);
191 let obj = borrowed_nums.into_pyobject(py).unwrap();
192 assert!(obj.is_instance_of::<PyList>());
193
194 let owned_nums = Cow::<[u16]>::Owned(vec![0, 1, 2, 3]);
195 let obj = owned_nums.into_pyobject(py).unwrap();
196 assert!(obj.is_instance_of::<PyList>());
197 });
198 }
199}