1
- use super :: objtype:: PyTypeRef ;
2
1
use std:: { fmt:: Debug , ops:: Deref } ;
3
2
3
+ use crate :: common:: borrow:: { BorrowedValue , BorrowedValueMut } ;
4
+ use crate :: common:: hash:: PyHash ;
4
5
use crate :: obj:: objbytes:: { PyBytes , PyBytesRef } ;
5
6
use crate :: obj:: objlist:: { PyList , PyListRef } ;
6
- use crate :: obj:: {
7
- objsequence :: get_pos , objsequence :: get_slice_range , objsequence :: SequenceIndex ,
8
- objslice :: PySliceRef , objstr:: PyStr ,
9
- } ;
7
+ use crate :: obj:: objsequence :: { convert_slice , get_pos , get_slice_range , SequenceIndex } ;
8
+ use crate :: obj :: objslice :: PySliceRef ;
9
+ use crate :: obj :: objstr:: PyStr ;
10
+ use crate :: obj :: objtype :: PyTypeRef ;
10
11
use crate :: pyobject:: {
11
- IdProtocol , PyClassImpl , PyContext , PyObjectRef , PyRef , PyResult , PyThreadingConstraint ,
12
- PyValue , TypeProtocol ,
12
+ IdProtocol , PyClassImpl , PyComparisonValue , PyContext , PyObjectRef , PyRef , PyResult ,
13
+ PyThreadingConstraint , PyValue , TypeProtocol ,
13
14
} ;
14
15
use crate :: slots:: { BufferProtocol , Comparable , Hashable , PyComparisonOp } ;
15
16
use crate :: stdlib:: pystruct:: _struct:: FormatSpec ;
16
17
use crate :: VirtualMachine ;
17
- use crate :: { common:: hash:: PyHash , pyobject:: PyComparisonValue } ;
18
18
use crossbeam_utils:: atomic:: AtomicCell ;
19
19
use itertools:: Itertools ;
20
20
use num_bigint:: BigInt ;
21
21
use num_traits:: { One , Signed , ToPrimitive , Zero } ;
22
- use rustpython_common:: borrow:: { BorrowedValue , BorrowedValueMut } ;
23
22
24
23
#[ derive( Debug ) ]
25
24
pub struct BufferRef ( Box < dyn Buffer > ) ;
@@ -64,6 +63,10 @@ pub trait Buffer: Debug + PyThreadingConstraint {
64
63
Some ( self . obj_bytes_mut ( ) )
65
64
}
66
65
66
+ fn to_contiguous ( & self ) ->Vec < u8 > {
67
+ self . obj_bytes ( ) . to_vec ( )
68
+ }
69
+
67
70
fn try_resizable ( & self , vm : & VirtualMachine ) ->PyResult < ( ) > {
68
71
if self . is_resizable ( ) {
69
72
Ok ( ( ) )
@@ -374,26 +377,154 @@ impl PyMemoryView {
374
377
}
375
378
}
376
379
380
+ fn setitem_by_idx (
381
+ zelf : PyRef < Self > ,
382
+ i : isize ,
383
+ value : PyObjectRef ,
384
+ vm : & VirtualMachine ,
385
+ ) ->PyResult < ( ) > {
386
+ let i = zelf
387
+ . get_pos ( i)
388
+ . ok_or_else ( || vm. new_index_error ( "index out of range" . to_owned ( ) ) ) ?;
389
+ let itemsize = zelf. options . itemsize ;
390
+ let data = zelf. format_spec . pack ( & [ value] , vm) ?;
391
+ zelf. obj_bytes_mut ( ) [ i..i + itemsize] . copy_from_slice ( & data) ;
392
+ Ok ( ( ) )
393
+ }
394
+
395
+ fn setitem_by_slice (
396
+ zelf : PyRef < Self > ,
397
+ slice : PySliceRef ,
398
+ items : PyObjectRef ,
399
+ vm : & VirtualMachine ,
400
+ ) ->PyResult < ( ) > {
401
+ let items =try_buffer_from_object ( vm, & items) ?;
402
+ let options = items. get_options ( ) ;
403
+ let len = options. len ;
404
+ let itemsize = options. itemsize ;
405
+
406
+ if itemsize != zelf. options . itemsize {
407
+ return Err ( vm. new_type_error ( format ! (
408
+ "memoryview: invalid type for format '{}'" ,
409
+ zelf. options. format
410
+ ) ) ) ;
411
+ }
412
+
413
+ let diff_err = ||{
414
+ Err ( vm. new_value_error (
415
+ "memoryview assignment: lvalue and rvalue have different structures" . to_owned ( ) ,
416
+ ) )
417
+ } ;
418
+
419
+ if options. format != zelf. options . format {
420
+ return diff_err ( ) ;
421
+ }
422
+
423
+ let ( range, step, is_negative_step) =convert_slice ( & slice, zelf. options . len , vm) ?;
424
+
425
+ let bytes = items. to_contiguous ( ) ;
426
+ assert_eq ! ( bytes. len( ) , len* itemsize) ;
427
+
428
+ if !is_negative_step && step ==Some ( 1 ) {
429
+ if range. end - range. start != len{
430
+ return diff_err ( ) ;
431
+ }
432
+
433
+ if let Some ( mut buffer) = zelf. as_contiguous_mut ( ) {
434
+ buffer[ range. start * itemsize..range. end * itemsize] . copy_from_slice ( & bytes) ;
435
+ return Ok ( ( ) ) ;
436
+ }
437
+ }
438
+
439
+ if let Some ( step) = step{
440
+ let slicelen =if range. end > range. start {
441
+ ( range. end - range. start -1 ) / step +1
442
+ } else {
443
+ 0
444
+ } ;
445
+
446
+ if slicelen != len{
447
+ return diff_err ( ) ;
448
+ }
449
+
450
+ let indexes =if is_negative_step{
451
+ itertools:: Either :: Left ( range. rev ( ) . step_by ( step) )
452
+ } else {
453
+ itertools:: Either :: Right ( range. step_by ( step) )
454
+ } ;
455
+
456
+ let item_index =( 0 ..len) . step_by ( itemsize) ;
457
+
458
+ let mut buffer = zelf. obj_bytes_mut ( ) ;
459
+
460
+ indexes
461
+ . map ( |i| zelf. get_pos ( ias isize ) . unwrap ( ) )
462
+ . zip ( item_index)
463
+ . for_each ( |( i, item_i) |{
464
+ buffer[ i..i + itemsize] . copy_from_slice ( & bytes[ item_i..item_i + itemsize] ) ;
465
+ } ) ;
466
+ Ok ( ( ) )
467
+ } else {
468
+ let slicelen =if range. start < range. end { 1 } else { 0 } ;
469
+ if match len{
470
+ 0 => slicelen ==0 ,
471
+ 1 =>{
472
+ let mut buffer = zelf. obj_bytes_mut ( ) ;
473
+ let i = zelf. get_pos ( range. start as isize ) . unwrap ( ) ;
474
+ buffer[ i..i + itemsize] . copy_from_slice ( & bytes) ;
475
+ true
476
+ }
477
+ _ =>false ,
478
+ } {
479
+ Ok ( ( ) )
480
+ } else {
481
+ diff_err ( )
482
+ }
483
+ }
484
+ }
485
+
486
+ #[ pymethod( magic) ]
487
+ fn setitem (
488
+ zelf : PyRef < Self > ,
489
+ needle : SequenceIndex ,
490
+ value : PyObjectRef ,
491
+ vm : & VirtualMachine ,
492
+ ) ->PyResult < ( ) > {
493
+ zelf. try_not_released ( vm) ?;
494
+ if zelf. options . readonly {
495
+ return Err ( vm. new_type_error ( "cannot modify read-only memory" . to_owned ( ) ) ) ;
496
+ }
497
+ match needle{
498
+ SequenceIndex :: Int ( i) =>Self :: setitem_by_idx ( zelf, i, value, vm) ,
499
+ SequenceIndex :: Slice ( slice) =>Self :: setitem_by_slice ( zelf, slice, value, vm) ,
500
+ }
501
+ }
502
+
377
503
#[ pymethod( magic) ]
378
504
fn len ( & self , vm : & VirtualMachine ) ->PyResult < usize > {
379
505
self . try_not_released ( vm) . map ( |_|self . options . len )
380
506
}
381
507
382
- #[ pymethod]
383
- fn tobytes ( zelf : PyRef < Self > , vm : & VirtualMachine ) ->PyResult < PyBytesRef > {
384
- zelf. try_not_released ( vm) ?;
508
+ fn to_bytes_vec ( zelf : & PyRef < Self > ) ->Vec < u8 > {
385
509
if let Some ( bytes) = zelf. as_contiguous ( ) {
386
- Ok ( PyBytes :: from ( bytes. to_vec ( ) ) . into_ref ( vm ) )
510
+ bytes. to_vec ( )
387
511
} else {
388
512
let bytes =& * zelf. obj_bytes ( ) ;
389
- let bytes =( 0 ..zelf. options . len )
513
+ let len = zelf. options . len ;
514
+ let itemsize = zelf. options . itemsize ;
515
+ ( 0 ..len)
390
516
. map ( |i| zelf. get_pos ( ias isize ) . unwrap ( ) )
391
- . flat_map ( |i|( i..i + zelf. options . itemsize ) . map ( |i| bytes[ i] ) )
392
- . collect :: < Vec < u8 > > ( ) ;
393
- Ok ( PyBytes :: from ( bytes) . into_ref ( vm) )
517
+ . flat_map ( |i| bytes[ i..i + itemsize] . to_vec ( ) )
518
+ . collect ( )
394
519
}
395
520
}
396
521
522
+ #[ pymethod]
523
+ fn tobytes ( zelf : PyRef < Self > , vm : & VirtualMachine ) ->PyResult < PyBytesRef > {
524
+ zelf. try_not_released ( vm) ?;
525
+ Ok ( PyBytes :: from ( Self :: to_bytes_vec ( & zelf) ) . into_ref ( vm) )
526
+ }
527
+
397
528
#[ pymethod]
398
529
fn tolist ( zelf : PyRef < Self > , vm : & VirtualMachine ) ->PyResult < PyListRef > {
399
530
zelf. try_not_released ( vm) ?;
@@ -436,7 +567,7 @@ impl PyMemoryView {
436
567
. into_ref ( vm) )
437
568
}
438
569
439
- #[ pymethod]
570
+ #[ pymethod( magic ) ]
440
571
fn repr ( zelf : PyRef < Self > ) ->String {
441
572
if zelf. released . load ( ) {
442
573
format ! ( "<released memory at 0x{:x}>" , zelf. get_id( ) )
@@ -446,10 +577,12 @@ impl PyMemoryView {
446
577
}
447
578
448
579
fn eq ( zelf : & PyRef < Self > , other : & PyObjectRef , vm : & VirtualMachine ) ->PyResult < bool > {
449
- zelf. try_not_released ( vm) ?;
450
580
if zelf. is ( other) {
451
581
return Ok ( true ) ;
452
582
}
583
+ if zelf. released . load ( ) {
584
+ return Ok ( false ) ;
585
+ }
453
586
let options_cmp = |a : & BufferOptions , b : & BufferOptions | ->bool {
454
587
a. len == b. len && a. itemsize == b. itemsize
455
588
} ;
@@ -538,6 +671,10 @@ impl Buffer for PyMemoryViewRef {
538
671
& mut x[ self . start ..self . stop ]
539
672
} ) )
540
673
}
674
+
675
+ fn to_contiguous ( & self ) ->Vec < u8 > {
676
+ PyMemoryView :: to_bytes_vec ( self )
677
+ }
541
678
}
542
679
543
680
impl Comparable for PyMemoryView {