11//! Implementation of the python bytearray object.
22use bstr:: ByteSlice ;
33use crossbeam_utils:: atomic:: AtomicCell ;
4+ use rustpython_common:: borrow:: { BorrowedValue , BorrowedValueMut } ;
45use std:: mem:: size_of;
56
67use super :: objint:: PyIntRef ;
@@ -13,15 +14,19 @@ use crate::bytesinner::{
1314 ByteInnerSplitOptions , ByteInnerTranslateOptions , DecodeArgs , PyBytesInner ,
1415} ;
1516use crate :: byteslike:: PyBytesLike ;
16- use crate :: common:: lock:: { PyRwLock , PyRwLockReadGuard , PyRwLockWriteGuard } ;
17+ use crate :: common:: lock:: {
18+ PyRwLock , PyRwLockReadGuard , PyRwLockUpgradableReadGuard , PyRwLockWriteGuard ,
19+ } ;
1720use crate :: function:: { OptionalArg , OptionalOption } ;
1821use crate :: obj:: objbytes:: PyBytes ;
22+ use crate :: obj:: objmemory:: { Buffer , BufferOptions } ;
1923use crate :: obj:: objtuple:: PyTupleRef ;
2024use crate :: pyobject:: {
2125 BorrowValue , Either , IdProtocol , IntoPyObject , PyClassImpl , PyComparisonValue , PyContext ,
2226 PyIterable , PyObjectRef , PyRef , PyResult , PyValue , TryFromObject ,
2327} ;
2428use crate :: sliceable:: SequenceIndex ;
29+ use crate :: slots:: BufferProtocol ;
2530use crate :: slots:: { Comparable , Hashable , PyComparisonOp , Unhashable } ;
2631use crate :: vm:: VirtualMachine ;
2732
@@ -40,6 +45,8 @@ use crate::vm::VirtualMachine;
4045#[ derive( Debug ) ]
4146pub struct PyByteArray {
4247 inner : PyRwLock < PyBytesInner > ,
48+ exports : AtomicCell < usize > ,
49+ buffer_options : PyRwLock < Option < Box < BufferOptions > > > ,
4350}
4451
4552pub type PyByteArrayRef = PyRef < PyByteArray > ;
@@ -56,6 +63,8 @@ impl PyByteArray {
5663 fn from_inner ( inner : PyBytesInner ) -> Self {
5764 PyByteArray {
5865 inner : PyRwLock :: new ( inner) ,
66+ exports : AtomicCell :: new ( 0 ) ,
67+ buffer_options : PyRwLock :: new ( None ) ,
5968 }
6069 }
6170
@@ -66,9 +75,7 @@ impl PyByteArray {
6675
6776impl From < PyBytesInner > for PyByteArray {
6877 fn from ( inner : PyBytesInner ) -> Self {
69- Self {
70- inner : PyRwLock :: new ( inner) ,
71- }
78+ Self :: from_inner ( inner)
7279 }
7380}
7481
@@ -95,7 +102,7 @@ pub(crate) fn init(context: &PyContext) {
95102 PyByteArrayIterator :: extend_class ( context, & context. types . bytearray_iterator_type ) ;
96103}
97104
98- #[ pyimpl( with( Hashable , Comparable ) , flags ( BASETYPE ) ) ]
105+ #[ pyimpl( flags ( BASETYPE ) , with( Hashable , Comparable , BufferProtocol ) ) ]
99106impl PyByteArray {
100107 #[ pyslot]
101108 fn tp_new (
@@ -137,6 +144,7 @@ impl PyByteArray {
137144
138145 #[ pymethod( name = "__iadd__" ) ]
139146 fn iadd ( zelf : PyRef < Self > , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult < PyRef < Self > > {
147+ zelf. try_resizable ( vm) ?;
140148 let other = PyBytesLike :: try_from_object ( vm, other) ?;
141149 zelf. borrow_value_mut ( ) . iadd ( other) ;
142150 Ok ( zelf)
@@ -176,8 +184,9 @@ impl PyByteArray {
176184 }
177185
178186 #[ pymethod( name = "__delitem__" ) ]
179- fn delitem ( & self , needle : SequenceIndex , vm : & VirtualMachine ) -> PyResult < ( ) > {
180- self . borrow_value_mut ( ) . delitem ( needle, vm)
187+ fn delitem ( zelf : PyRef < Self > , needle : SequenceIndex , vm : & VirtualMachine ) -> PyResult < ( ) > {
188+ zelf. try_resizable ( vm) ?;
189+ zelf. borrow_value_mut ( ) . delitem ( needle, vm)
181190 }
182191
183192 #[ pymethod( name = "isalnum" ) ]
@@ -458,8 +467,10 @@ impl PyByteArray {
458467 }
459468
460469 #[ pymethod( name = "clear" ) ]
461- fn clear ( & self ) {
462- self . borrow_value_mut ( ) . elements . clear ( ) ;
470+ fn clear ( zelf : PyRef < Self > , vm : & VirtualMachine ) -> PyResult < ( ) > {
471+ zelf. try_resizable ( vm) ?;
472+ zelf. borrow_value_mut ( ) . elements . clear ( ) ;
473+ Ok ( ( ) )
463474 }
464475
465476 #[ pymethod( name = "copy" ) ]
@@ -468,12 +479,14 @@ impl PyByteArray {
468479 }
469480
470481 #[ pymethod( name = "append" ) ]
471- fn append ( & self , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
472- self . borrow_value_mut ( ) . append ( value, vm)
482+ fn append ( zelf : PyRef < Self > , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
483+ zelf. try_resizable ( vm) ?;
484+ zelf. borrow_value_mut ( ) . append ( value, vm)
473485 }
474486
475487 #[ pymethod( name = "extend" ) ]
476488 fn extend ( zelf : PyRef < Self > , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
489+ zelf. try_resizable ( vm) ?;
477490 if zelf. is ( & value) {
478491 zelf. borrow_value_mut ( ) . irepeat ( 2 ) ;
479492 Ok ( ( ) )
@@ -483,14 +496,21 @@ impl PyByteArray {
483496 }
484497
485498 #[ pymethod( name = "insert" ) ]
486- fn insert ( & self , index : isize , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
487- self . borrow_value_mut ( ) . insert ( index, value, vm)
499+ fn insert (
500+ zelf : PyRef < Self > ,
501+ index : isize ,
502+ value : PyObjectRef ,
503+ vm : & VirtualMachine ,
504+ ) -> PyResult < ( ) > {
505+ zelf. try_resizable ( vm) ?;
506+ zelf. borrow_value_mut ( ) . insert ( index, value, vm)
488507 }
489508
490509 #[ pymethod( name = "pop" ) ]
491- fn pop ( & self , index : OptionalArg < isize > , vm : & VirtualMachine ) -> PyResult < u8 > {
510+ fn pop ( zelf : PyRef < Self > , index : OptionalArg < isize > , vm : & VirtualMachine ) -> PyResult < u8 > {
511+ zelf. try_resizable ( vm) ?;
492512 let index = index. unwrap_or ( -1 ) ;
493- self . borrow_value_mut ( ) . pop ( index, vm)
513+ zelf . borrow_value_mut ( ) . pop ( index, vm)
494514 }
495515
496516 #[ pymethod( name = "title" ) ]
@@ -505,9 +525,10 @@ impl PyByteArray {
505525 }
506526
507527 #[ pymethod( name = "__imul__" ) ]
508- fn imul ( zelf : PyRef < Self > , n : isize ) -> PyRef < Self > {
528+ fn imul ( zelf : PyRef < Self > , n : isize , vm : & VirtualMachine ) -> PyResult < PyRef < Self > > {
529+ zelf. try_resizable ( vm) ?;
509530 zelf. borrow_value_mut ( ) . irepeat ( n) ;
510- zelf
531+ Ok ( zelf)
511532 }
512533
513534 #[ pymethod( name = "__mod__" ) ]
@@ -554,11 +575,54 @@ impl Comparable for PyByteArray {
554575 op : PyComparisonOp ,
555576 vm : & VirtualMachine ,
556577 ) -> PyResult < PyComparisonValue > {
557- Ok ( if let Some ( res) = op. identical_optimization ( zelf, other) {
558- res. into ( )
578+ if let Some ( res) = op. identical_optimization ( & zelf, & other) {
579+ return Ok ( res. into ( ) ) ;
580+ }
581+ Ok ( zelf. borrow_value ( ) . cmp ( other, op, vm) )
582+ }
583+ }
584+
585+ impl BufferProtocol for PyByteArray {
586+ fn get_buffer ( zelf : PyRef < Self > , _vm : & VirtualMachine ) -> PyResult < Box < dyn Buffer > > {
587+ zelf. exports . fetch_add ( 1 ) ;
588+ Ok ( Box :: new ( zelf) )
589+ }
590+ }
591+
592+ impl Buffer for PyByteArrayRef {
593+ fn obj_bytes ( & self ) -> BorrowedValue < [ u8 ] > {
594+ PyRwLockReadGuard :: map ( self . borrow_value ( ) , |x| x. elements . as_slice ( ) ) . into ( )
595+ }
596+
597+ fn obj_bytes_mut ( & self ) -> BorrowedValueMut < [ u8 ] > {
598+ PyRwLockWriteGuard :: map ( self . borrow_value_mut ( ) , |x| x. elements . as_mut_slice ( ) ) . into ( )
599+ }
600+
601+ fn release ( & self ) {
602+ let mut w = self . buffer_options . write ( ) ;
603+ if self . exports . fetch_sub ( 1 ) == 1 {
604+ * w = None ;
605+ }
606+ }
607+
608+ fn is_resizable ( & self ) -> bool {
609+ self . exports . load ( ) == 0
610+ }
611+
612+ fn get_options ( & self ) -> BorrowedValue < BufferOptions > {
613+ let guard = self . buffer_options . upgradable_read ( ) ;
614+ let guard = if guard. is_none ( ) {
615+ let mut w = PyRwLockUpgradableReadGuard :: upgrade ( guard) ;
616+ * w = Some ( Box :: new ( BufferOptions {
617+ readonly : false ,
618+ len : self . len ( ) ,
619+ ..Default :: default ( )
620+ } ) ) ;
621+ PyRwLockWriteGuard :: downgrade ( w)
559622 } else {
560- zelf. borrow_value ( ) . cmp ( other, op, vm)
561- } )
623+ PyRwLockUpgradableReadGuard :: downgrade ( guard)
624+ } ;
625+ PyRwLockReadGuard :: map ( guard, |x| x. as_ref ( ) . unwrap ( ) . as_ref ( ) ) . into ( )
562626 }
563627}
564628
0 commit comments