@@ -11,6 +11,35 @@ use std::str;
11
11
/// Represents a Python `bytes` object.
12
12
///
13
13
/// This type is immutable.
14
+ ///
15
+ /// # Equality
16
+ ///
17
+ /// For convenience, [`Bound<'py, PyBytes>`] implements [`PartialEq<[u8]>`] to allow comparing the
18
+ /// data in the Python bytes to a Rust `[u8]`.
19
+ ///
20
+ /// This is not always the most appropriate way to compare Python bytes, as Python bytes subclasses
21
+ /// may have different equality semantics. In situations where subclasses overriding equality might be
22
+ /// relevant, use [`PyAnyMethods::eq`], at cost of the additional overhead of a Python method call.
23
+ ///
24
+ /// ```rust
25
+ /// # use pyo3::prelude::*;
26
+ /// use pyo3::types::PyBytes;
27
+ ///
28
+ /// # Python::with_gil(|py| {
29
+ /// let py_bytes = PyBytes::new_bound(py, b"foo".as_slice());
30
+ /// // via PartialEq<[u8]>
31
+ /// assert_eq!(py_bytes, b"foo".as_slice());
32
+ ///
33
+ /// // via Python equality
34
+ /// let other = PyBytes::new_bound(py, b"foo".as_slice());
35
+ /// assert!(py_bytes.as_any().eq(other).unwrap());
36
+ ///
37
+ /// // Note that `eq` will convert it's argument to Python using `ToPyObject`,
38
+ /// // so the following does not compare equal since the slice will convert into a
39
+ /// // `list`, not a `bytes` object.
40
+ /// assert!(!py_bytes.as_any().eq(b"foo".as_slice()).unwrap());
41
+ /// # });
42
+ /// ```
14
43
#[ repr( transparent) ]
15
44
pub struct PyBytes ( PyAny ) ;
16
45
@@ -191,6 +220,106 @@ impl<I: SliceIndex<[u8]>> Index<I> for Bound<'_, PyBytes> {
191
220
}
192
221
}
193
222
223
+ /// Compares whether the Python bytes object is equal to the [u8].
224
+ ///
225
+ /// In some cases Python equality might be more appropriate; see the note on [`PyBytes`].
226
+ impl PartialEq < [ u8 ] > for Bound < ' _ , PyBytes > {
227
+ #[ inline]
228
+ fn eq ( & self , other : & [ u8 ] ) -> bool {
229
+ self . as_borrowed ( ) == * other
230
+ }
231
+ }
232
+
233
+ /// Compares whether the Python bytes object is equal to the [u8].
234
+ ///
235
+ /// In some cases Python equality might be more appropriate; see the note on [`PyBytes`].
236
+ impl PartialEq < & ' _ [ u8 ] > for Bound < ' _ , PyBytes > {
237
+ #[ inline]
238
+ fn eq ( & self , other : & & [ u8 ] ) -> bool {
239
+ self . as_borrowed ( ) == * * other
240
+ }
241
+ }
242
+
243
+ /// Compares whether the Python bytes object is equal to the [u8].
244
+ ///
245
+ /// In some cases Python equality might be more appropriate; see the note on [`PyBytes`].
246
+ impl PartialEq < Bound < ' _ , PyBytes > > for [ u8 ] {
247
+ #[ inline]
248
+ fn eq ( & self , other : & Bound < ' _ , PyBytes > ) -> bool {
249
+ * self == other. as_borrowed ( )
250
+ }
251
+ }
252
+
253
+ /// Compares whether the Python bytes object is equal to the [u8].
254
+ ///
255
+ /// In some cases Python equality might be more appropriate; see the note on [`PyBytes`].
256
+ impl PartialEq < & ' _ Bound < ' _ , PyBytes > > for [ u8 ] {
257
+ #[ inline]
258
+ fn eq ( & self , other : & & Bound < ' _ , PyBytes > ) -> bool {
259
+ * self == other. as_borrowed ( )
260
+ }
261
+ }
262
+
263
+ /// Compares whether the Python bytes object is equal to the [u8].
264
+ ///
265
+ /// In some cases Python equality might be more appropriate; see the note on [`PyBytes`].
266
+ impl PartialEq < Bound < ' _ , PyBytes > > for & ' _ [ u8 ] {
267
+ #[ inline]
268
+ fn eq ( & self , other : & Bound < ' _ , PyBytes > ) -> bool {
269
+ * * self == other. as_borrowed ( )
270
+ }
271
+ }
272
+
273
+ /// Compares whether the Python bytes object is equal to the [u8].
274
+ ///
275
+ /// In some cases Python equality might be more appropriate; see the note on [`PyBytes`].
276
+ impl PartialEq < [ u8 ] > for & ' _ Bound < ' _ , PyBytes > {
277
+ #[ inline]
278
+ fn eq ( & self , other : & [ u8 ] ) -> bool {
279
+ self . as_borrowed ( ) == other
280
+ }
281
+ }
282
+
283
+ /// Compares whether the Python bytes object is equal to the [u8].
284
+ ///
285
+ /// In some cases Python equality might be more appropriate; see the note on [`PyBytes`].
286
+ impl PartialEq < [ u8 ] > for Borrowed < ' _ , ' _ , PyBytes > {
287
+ #[ inline]
288
+ fn eq ( & self , other : & [ u8 ] ) -> bool {
289
+ self . as_bytes ( ) == other
290
+ }
291
+ }
292
+
293
+ /// Compares whether the Python bytes object is equal to the [u8].
294
+ ///
295
+ /// In some cases Python equality might be more appropriate; see the note on [`PyBytes`].
296
+ impl PartialEq < & [ u8 ] > for Borrowed < ' _ , ' _ , PyBytes > {
297
+ #[ inline]
298
+ fn eq ( & self , other : & & [ u8 ] ) -> bool {
299
+ * self == * * other
300
+ }
301
+ }
302
+
303
+ /// Compares whether the Python bytes object is equal to the [u8].
304
+ ///
305
+ /// In some cases Python equality might be more appropriate; see the note on [`PyBytes`].
306
+ impl PartialEq < Borrowed < ' _ , ' _ , PyBytes > > for [ u8 ] {
307
+ #[ inline]
308
+ fn eq ( & self , other : & Borrowed < ' _ , ' _ , PyBytes > ) -> bool {
309
+ other == self
310
+ }
311
+ }
312
+
313
+ /// Compares whether the Python bytes object is equal to the [u8].
314
+ ///
315
+ /// In some cases Python equality might be more appropriate; see the note on [`PyBytes`].
316
+ impl PartialEq < Borrowed < ' _ , ' _ , PyBytes > > for & ' _ [ u8 ] {
317
+ #[ inline]
318
+ fn eq ( & self , other : & Borrowed < ' _ , ' _ , PyBytes > ) -> bool {
319
+ other == self
320
+ }
321
+ }
322
+
194
323
#[ cfg( test) ]
195
324
mod tests {
196
325
use super :: * ;
@@ -251,4 +380,34 @@ mod tests {
251
380
. is_instance_of:: <PyValueError >( py) ) ;
252
381
} ) ;
253
382
}
383
+
384
+ #[ test]
385
+ fn test_comparisons ( ) {
386
+ Python :: with_gil ( |py| {
387
+ let b = b"hello, world" . as_slice ( ) ;
388
+ let py_bytes = PyBytes :: new_bound ( py, b) ;
389
+
390
+ assert_eq ! ( py_bytes, b"hello, world" . as_slice( ) ) ;
391
+
392
+ assert_eq ! ( py_bytes, b) ;
393
+ assert_eq ! ( & py_bytes, b) ;
394
+ assert_eq ! ( b, py_bytes) ;
395
+ assert_eq ! ( b, & py_bytes) ;
396
+
397
+ assert_eq ! ( py_bytes, * b) ;
398
+ assert_eq ! ( & py_bytes, * b) ;
399
+ assert_eq ! ( * b, py_bytes) ;
400
+ assert_eq ! ( * b, & py_bytes) ;
401
+
402
+ let py_string = py_bytes. as_borrowed ( ) ;
403
+
404
+ assert_eq ! ( py_string, b) ;
405
+ assert_eq ! ( & py_string, b) ;
406
+ assert_eq ! ( b, py_string) ;
407
+ assert_eq ! ( b, & py_string) ;
408
+
409
+ assert_eq ! ( py_string, * b) ;
410
+ assert_eq ! ( * b, py_string) ;
411
+ } )
412
+ }
254
413
}
0 commit comments