1
1
//! Implementation of the python bytearray object.
2
2
use bstr:: ByteSlice ;
3
3
use crossbeam_utils:: atomic:: AtomicCell ;
4
+ use rustpython_common:: borrow:: { BorrowedValue , BorrowedValueMut } ;
4
5
use std:: mem:: size_of;
5
6
6
7
use super :: objint:: PyIntRef ;
@@ -13,15 +14,19 @@ use crate::bytesinner::{
13
14
ByteInnerSplitOptions , ByteInnerTranslateOptions , DecodeArgs , PyBytesInner ,
14
15
} ;
15
16
use crate :: byteslike:: PyBytesLike ;
16
- use crate :: common:: lock:: { PyRwLock , PyRwLockReadGuard , PyRwLockWriteGuard } ;
17
+ use crate :: common:: lock:: {
18
+ PyRwLock , PyRwLockReadGuard , PyRwLockUpgradableReadGuard , PyRwLockWriteGuard ,
19
+ } ;
17
20
use crate :: function:: { OptionalArg , OptionalOption } ;
18
21
use crate :: obj:: objbytes:: PyBytes ;
22
+ use crate :: obj:: objmemory:: { Buffer , BufferOptions } ;
19
23
use crate :: obj:: objtuple:: PyTupleRef ;
20
24
use crate :: pyobject:: {
21
25
BorrowValue , Either , IdProtocol , IntoPyObject , PyClassImpl , PyComparisonValue , PyContext ,
22
26
PyIterable , PyObjectRef , PyRef , PyResult , PyValue , TryFromObject ,
23
27
} ;
24
28
use crate :: sliceable:: SequenceIndex ;
29
+ use crate :: slots:: BufferProtocol ;
25
30
use crate :: slots:: { Comparable , Hashable , PyComparisonOp , Unhashable } ;
26
31
use crate :: vm:: VirtualMachine ;
27
32
@@ -40,6 +45,8 @@ use crate::vm::VirtualMachine;
40
45
#[ derive( Debug ) ]
41
46
pub struct PyByteArray {
42
47
inner : PyRwLock < PyBytesInner > ,
48
+ exports : AtomicCell < usize > ,
49
+ buffer_options : PyRwLock < Option < Box < BufferOptions > > > ,
43
50
}
44
51
45
52
pub type PyByteArrayRef = PyRef < PyByteArray > ;
@@ -56,6 +63,8 @@ impl PyByteArray {
56
63
fn from_inner ( inner : PyBytesInner ) -> Self {
57
64
PyByteArray {
58
65
inner : PyRwLock :: new ( inner) ,
66
+ exports : AtomicCell :: new ( 0 ) ,
67
+ buffer_options : PyRwLock :: new ( None ) ,
59
68
}
60
69
}
61
70
@@ -66,9 +75,7 @@ impl PyByteArray {
66
75
67
76
impl From < PyBytesInner > for PyByteArray {
68
77
fn from ( inner : PyBytesInner ) -> Self {
69
- Self {
70
- inner : PyRwLock :: new ( inner) ,
71
- }
78
+ Self :: from_inner ( inner)
72
79
}
73
80
}
74
81
@@ -95,7 +102,7 @@ pub(crate) fn init(context: &PyContext) {
95
102
PyByteArrayIterator :: extend_class ( context, & context. types . bytearray_iterator_type ) ;
96
103
}
97
104
98
- #[ pyimpl( with( Hashable , Comparable ) , flags ( BASETYPE ) ) ]
105
+ #[ pyimpl( flags ( BASETYPE ) , with( Hashable , Comparable , BufferProtocol ) ) ]
99
106
impl PyByteArray {
100
107
#[ pyslot]
101
108
fn tp_new (
@@ -137,6 +144,7 @@ impl PyByteArray {
137
144
138
145
#[ pymethod( name = "__iadd__" ) ]
139
146
fn iadd ( zelf : PyRef < Self > , other : PyObjectRef , vm : & VirtualMachine ) -> PyResult < PyRef < Self > > {
147
+ zelf. try_resizable ( vm) ?;
140
148
let other = PyBytesLike :: try_from_object ( vm, other) ?;
141
149
zelf. borrow_value_mut ( ) . iadd ( other) ;
142
150
Ok ( zelf)
@@ -176,8 +184,9 @@ impl PyByteArray {
176
184
}
177
185
178
186
#[ 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)
181
190
}
182
191
183
192
#[ pymethod( name = "isalnum" ) ]
@@ -458,8 +467,10 @@ impl PyByteArray {
458
467
}
459
468
460
469
#[ 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 ( ( ) )
463
474
}
464
475
465
476
#[ pymethod( name = "copy" ) ]
@@ -468,12 +479,14 @@ impl PyByteArray {
468
479
}
469
480
470
481
#[ 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)
473
485
}
474
486
475
487
#[ pymethod( name = "extend" ) ]
476
488
fn extend ( zelf : PyRef < Self > , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
489
+ zelf. try_resizable ( vm) ?;
477
490
if zelf. is ( & value) {
478
491
zelf. borrow_value_mut ( ) . irepeat ( 2 ) ;
479
492
Ok ( ( ) )
@@ -483,14 +496,21 @@ impl PyByteArray {
483
496
}
484
497
485
498
#[ 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)
488
507
}
489
508
490
509
#[ 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) ?;
492
512
let index = index. unwrap_or ( -1 ) ;
493
- self . borrow_value_mut ( ) . pop ( index, vm)
513
+ zelf . borrow_value_mut ( ) . pop ( index, vm)
494
514
}
495
515
496
516
#[ pymethod( name = "title" ) ]
@@ -505,9 +525,10 @@ impl PyByteArray {
505
525
}
506
526
507
527
#[ 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) ?;
509
530
zelf. borrow_value_mut ( ) . irepeat ( n) ;
510
- zelf
531
+ Ok ( zelf)
511
532
}
512
533
513
534
#[ pymethod( name = "__mod__" ) ]
@@ -554,11 +575,54 @@ impl Comparable for PyByteArray {
554
575
op : PyComparisonOp ,
555
576
vm : & VirtualMachine ,
556
577
) -> 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)
559
622
} 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 ( )
562
626
}
563
627
}
564
628
0 commit comments