@@ -11,13 +11,13 @@ use std::{
1111 rc:: { Rc , Weak } ,
1212} ;
1313
14- use crate :: reinterpret:: { ByteRepr , OriginalAlloc , SingleOriginalAlloc , SliceOriginalAlloc } ;
14+ use crate :: reinterpret:: { ByteRepr , OriginalAlloc , with_scratch } ;
1515
1616pub type Value < T > = Rc < RefCell < T > > ;
1717
1818pub ( crate ) struct ReinterpretedView {
1919 // Pointer to the source of reinterpret
20- pub ( crate ) alloc : Rc < dyn OriginalAlloc > ,
20+ pub ( crate ) alloc : OriginalAlloc ,
2121 // C++ size of the reinterpreted view
2222 elem_byte_size : usize ,
2323}
@@ -46,7 +46,7 @@ pub enum StrongPtr<T> {
4646 offset : usize ,
4747 } ,
4848 Reinterpreted {
49- alloc : Rc < dyn OriginalAlloc > ,
49+ alloc : OriginalAlloc ,
5050 byte_offset : usize ,
5151 // Local buffer for deref(). None until first access.
5252 // Read-through: refreshed from alloc on every deref() call.
@@ -66,9 +66,10 @@ impl<T: ByteRepr> StrongPtr<T> {
6666 cell,
6767 } => {
6868 // Read-through: always re-read from the original allocation.
69- let mut buf = vec ! [ 0u8 ; T :: byte_size( ) ] ;
70- alloc. read_bytes ( * byte_offset, & mut buf) ;
71- * cell. borrow_mut ( ) = Some ( T :: from_bytes ( & buf) ) ;
69+ with_scratch ( T :: byte_size ( ) , |buf| {
70+ alloc. read_bytes ( * byte_offset, buf) ;
71+ * cell. borrow_mut ( ) = Some ( T :: from_bytes ( buf) ) ;
72+ } ) ;
7273 Ref :: map ( cell. borrow ( ) , |opt| opt. as_ref ( ) . unwrap ( ) )
7374 }
7475 }
@@ -360,7 +361,7 @@ impl<T> Ptr<T> {
360361 offset : self . offset ,
361362 } ,
362363 PtrKind :: Reinterpreted ( data) => StrongPtr :: Reinterpreted {
363- alloc : Rc :: clone ( & data. alloc ) ,
364+ alloc : data. alloc . clone ( ) ,
364365 byte_offset : self . offset ,
365366 cell : RefCell :: new ( None ) ,
366367 } ,
@@ -383,33 +384,50 @@ impl<T> Ptr<T> {
383384 return self_any. downcast_ref :: < Ptr < U > > ( ) . unwrap ( ) . clone ( ) ;
384385 }
385386
386- if U :: byte_size ( ) == 0 {
387- panic ! ( "cannot reinterpret_cast to zero-sized type" ) ;
387+ match self . original_alloc ( ) {
388+ Some ( ( alloc, byte_offset) ) => Ptr :: < U > :: from_original_alloc ( alloc, byte_offset) ,
389+ None => Ptr :: null ( ) ,
388390 }
391+ }
389392
390- let src_byte_off = self . offset . wrapping_mul ( T :: byte_size ( ) ) ;
391- let ( alloc, abs_byte_off) : ( Rc < dyn OriginalAlloc > , usize ) = match & self . kind {
392- PtrKind :: Null => return Ptr :: null ( ) ,
393+ // The original allocation this pointer refers to, together with the byte
394+ // offset of the pointer into it. None for null pointers.
395+ pub ( crate ) fn original_alloc ( & self ) -> Option < ( OriginalAlloc , usize ) >
396+ where
397+ T : ByteRepr ,
398+ {
399+ Some ( match & self . kind {
400+ PtrKind :: Null => return None ,
393401 PtrKind :: StackSingle ( weak) | PtrKind :: HeapSingle ( weak) => (
394- Rc :: new ( SingleOriginalAlloc { weak : weak . clone ( ) } ) ,
395- src_byte_off ,
402+ OriginalAlloc :: single ( weak) ,
403+ self . offset . wrapping_mul ( T :: byte_size ( ) ) ,
396404 ) ,
397405 PtrKind :: StackVec ( weak) | PtrKind :: HeapVec ( weak) => (
398- Rc :: new ( SliceOriginalAlloc { weak : weak . clone ( ) } ) ,
399- src_byte_off ,
406+ OriginalAlloc :: slice ( weak) ,
407+ self . offset . wrapping_mul ( T :: byte_size ( ) ) ,
400408 ) ,
401409 PtrKind :: StackArray ( weak) | PtrKind :: HeapArray ( weak) => (
402- Rc :: new ( SliceOriginalAlloc { weak : weak . clone ( ) } ) ,
403- src_byte_off ,
410+ OriginalAlloc :: slice ( weak) ,
411+ self . offset . wrapping_mul ( T :: byte_size ( ) ) ,
404412 ) ,
405- PtrKind :: Reinterpreted ( data) => ( Rc :: clone ( & data. alloc ) , self . offset ) ,
406- } ;
413+ PtrKind :: Reinterpreted ( data) => ( data. alloc . clone ( ) , self . offset ) ,
414+ } )
415+ }
407416
417+ // A pointer that views the bytes of `alloc`, starting at `byte_offset`, as
418+ // a sequence of `T`. This is the only allocation of a reinterpret cast.
419+ pub ( crate ) fn from_original_alloc ( alloc : OriginalAlloc , byte_offset : usize ) -> Self
420+ where
421+ T : ByteRepr ,
422+ {
423+ if T :: byte_size ( ) == 0 {
424+ panic ! ( "cannot reinterpret_cast to zero-sized type" ) ;
425+ }
408426 Ptr {
409- offset : abs_byte_off ,
427+ offset : byte_offset ,
410428 kind : PtrKind :: Reinterpreted ( Rc :: new ( ReinterpretedView {
411429 alloc,
412- elem_byte_size : U :: byte_size ( ) ,
430+ elem_byte_size : T :: byte_size ( ) ,
413431 } ) ) ,
414432 }
415433 }
@@ -438,15 +456,14 @@ impl<T> Ptr<T> {
438456 let mut borrow = rc. borrow_mut ( ) ;
439457 f ( & mut borrow[ self . offset ] )
440458 }
441- PtrKind :: Reinterpreted ( data) => {
442- let mut buf = vec ! [ 0u8 ; T :: byte_size( ) ] ;
443- data. alloc . read_bytes ( self . offset , & mut buf) ;
444- let mut val = T :: from_bytes ( & buf) ;
459+ PtrKind :: Reinterpreted ( data) => with_scratch ( T :: byte_size ( ) , |buf| {
460+ data. alloc . read_bytes ( self . offset , buf) ;
461+ let mut val = T :: from_bytes ( buf) ;
445462 let ret = f ( & mut val) ;
446- val. to_bytes ( & mut buf) ;
447- data. alloc . write_bytes ( self . offset , & buf) ;
463+ val. to_bytes ( buf) ;
464+ data. alloc . write_bytes ( self . offset , buf) ;
448465 ret
449- }
466+ } ) ,
450467 }
451468 }
452469
@@ -472,12 +489,10 @@ impl<T> Ptr<T> {
472489 let borrow = rc. borrow ( ) ;
473490 f ( & borrow[ self . offset ] )
474491 }
475- PtrKind :: Reinterpreted ( data) => {
476- let mut buf = vec ! [ 0u8 ; T :: byte_size( ) ] ;
477- data. alloc . read_bytes ( self . offset , & mut buf) ;
478- let val = T :: from_bytes ( & buf) ;
479- f ( & val)
480- }
492+ PtrKind :: Reinterpreted ( data) => with_scratch ( T :: byte_size ( ) , |buf| {
493+ data. alloc . read_bytes ( self . offset , buf) ;
494+ f ( & T :: from_bytes ( buf) )
495+ } ) ,
481496 }
482497 }
483498}
@@ -503,13 +518,12 @@ impl Ptr<u8> {
503518 let mut b = rc. borrow_mut ( ) ;
504519 f ( & mut b[ off..off + len] )
505520 }
506- PtrKind :: Reinterpreted ( data) => {
507- let mut buf = vec ! [ 0u8 ; len] ;
508- data. alloc . read_bytes ( off, & mut buf) ;
509- let r = f ( & mut buf) ;
510- data. alloc . write_bytes ( off, & buf) ;
521+ PtrKind :: Reinterpreted ( data) => with_scratch ( len, |buf| {
522+ data. alloc . read_bytes ( off, buf) ;
523+ let r = f ( buf) ;
524+ data. alloc . write_bytes ( off, buf) ;
511525 r
512- }
526+ } ) ,
513527 }
514528 }
515529
@@ -533,11 +547,10 @@ impl Ptr<u8> {
533547 let b = rc. borrow ( ) ;
534548 f ( & b[ off..off + len] )
535549 }
536- PtrKind :: Reinterpreted ( data) => {
537- let mut buf = vec ! [ 0u8 ; len] ;
538- data. alloc . read_bytes ( off, & mut buf) ;
539- f ( & buf)
540- }
550+ PtrKind :: Reinterpreted ( data) => with_scratch ( len, |buf| {
551+ data. alloc . read_bytes ( off, buf) ;
552+ f ( buf)
553+ } ) ,
541554 }
542555 }
543556
@@ -999,15 +1012,17 @@ impl<T: 'static> ByteRepr for Ptr<T> {}
9991012
10001013impl < T : ' static > Ptr < T > {
10011014 pub fn to_int ( & self ) -> usize {
1002- let mut buf = vec ! [ 0u8 ; Self :: byte_size( ) ] ;
1003- self . to_bytes ( & mut buf) ;
1004- usize:: from_bytes ( & buf[ ..std:: mem:: size_of :: < usize > ( ) ] )
1015+ with_scratch ( Self :: byte_size ( ) , |buf| {
1016+ self . to_bytes ( buf) ;
1017+ usize:: from_bytes ( & buf[ ..std:: mem:: size_of :: < usize > ( ) ] )
1018+ } )
10051019 }
10061020
10071021 pub fn from_int ( value : usize ) -> Self {
1008- let mut buf = vec ! [ 0u8 ; Self :: byte_size( ) ] ;
1009- value. to_bytes ( & mut buf[ ..std:: mem:: size_of :: < usize > ( ) ] ) ;
1010- Self :: from_bytes ( & buf)
1022+ with_scratch ( Self :: byte_size ( ) , |buf| {
1023+ value. to_bytes ( & mut buf[ ..std:: mem:: size_of :: < usize > ( ) ] ) ;
1024+ Self :: from_bytes ( buf)
1025+ } )
10111026 }
10121027}
10131028
@@ -1047,6 +1062,54 @@ mod tests {
10471062 p. decay ( ) . delete ( ) ;
10481063 }
10491064
1065+ #[ test]
1066+ fn reinterpreted_unaligned_access_spans_elements ( ) {
1067+ let p: Ptr < u16 > = Ptr :: alloc_array ( vec ! [ 0u16 ; 4 ] . into_boxed_slice ( ) ) ;
1068+ let words = p
1069+ . reinterpret_cast :: < u8 > ( )
1070+ . offset ( 2 )
1071+ . reinterpret_cast :: < u32 > ( ) ;
1072+ words. write ( 0xAABBCCDD ) ;
1073+ assert_eq ! ( words. read( ) , 0xAABBCCDD ) ;
1074+ let halves: Vec < u16 > = ( 0 ..4 ) . map ( |i| p. offset ( i) . read ( ) ) . collect ( ) ;
1075+ assert_eq ! ( halves, vec![ 0 , 0xCCDD , 0xAABB , 0 ] ) ;
1076+ p. delete ( ) ;
1077+ }
1078+
1079+ #[ test]
1080+ fn reinterpreted_u8_storage_is_read_and_written_bytewise ( ) {
1081+ let p: Ptr < u8 > = Ptr :: alloc_array ( vec ! [ 0u8 ; 16 ] . into_boxed_slice ( ) ) ;
1082+ let ints = p. reinterpret_cast :: < u32 > ( ) ;
1083+ for i in 0 ..4 {
1084+ ints. offset ( i) . write ( 0x01010101 * ( i as u32 + 1 ) ) ;
1085+ }
1086+ assert_eq ! ( p. offset( 5 ) . read( ) , 0x02 ) ;
1087+ assert_eq ! ( ints. offset( 3 ) . read( ) , 0x04040404 ) ;
1088+ // An unaligned view over the same bytes.
1089+ let unaligned = p. offset ( 1 ) . reinterpret_cast :: < u32 > ( ) ;
1090+ assert_eq ! ( unaligned. read( ) , 0x02010101 ) ;
1091+ p. delete ( ) ;
1092+ }
1093+
1094+ #[ test]
1095+ #[ should_panic]
1096+ fn reinterpreted_write_past_the_end_panics ( ) {
1097+ let p: Ptr < u32 > = Ptr :: alloc_array ( vec ! [ 0u32 ; 2 ] . into_boxed_slice ( ) ) ;
1098+ // A u32 straddling the end of the allocation.
1099+ let q = p
1100+ . reinterpret_cast :: < u8 > ( )
1101+ . offset ( 6 )
1102+ . reinterpret_cast :: < u32 > ( ) ;
1103+ q. write ( 1 ) ;
1104+ }
1105+
1106+ #[ test]
1107+ #[ should_panic]
1108+ fn reinterpreted_u8_write_past_the_end_panics ( ) {
1109+ let p: Ptr < u8 > = Ptr :: alloc_array ( vec ! [ 0u8 ; 6 ] . into_boxed_slice ( ) ) ;
1110+ p. reinterpret_cast :: < u32 > ( ) . offset ( 1 ) . write ( 1 ) ;
1111+ }
1112+
10501113 #[ test]
10511114 fn reinterpreted_cast ( ) {
10521115 let p: Ptr < u64 > = Ptr :: alloc ( 0x0807060504030201u64 ) ;
0 commit comments