@@ -29,7 +29,7 @@ use crate::trusted_len::TrustedLen;
2929/// A mutable buffer that maintains a runtime-defined alignment through resizing operations.
3030pub struct BufferMut < T > {
3131 pub ( crate ) allocation : Allocation ,
32- pub ( crate ) offset : usize ,
32+ pub ( crate ) ptr : std :: ptr :: NonNull < T > ,
3333 pub ( crate ) length : usize ,
3434 pub ( crate ) alignment : Alignment ,
3535 pub ( crate ) physical_alignment : Alignment ,
@@ -38,6 +38,11 @@ pub struct BufferMut<T> {
3838 pub ( crate ) _marker : std:: marker:: PhantomData < T > ,
3939}
4040
41+ // SAFETY: BufferMut uniquely owns its allocation and only exposes T across threads.
42+ unsafe impl < T : Send > Send for BufferMut < T > { }
43+ // SAFETY: shared access to BufferMut only exposes shared access to T.
44+ unsafe impl < T : Sync > Sync for BufferMut < T > { }
45+
4146impl < T > BufferMut < T > {
4247 /// Create a new `BufferMut` with the requested alignment and capacity.
4348 pub fn with_capacity ( capacity : usize ) -> Self {
@@ -130,9 +135,11 @@ impl<T> BufferMut<T> {
130135 } ;
131136 let allocation = Allocation :: allocate ( layout, allocator) ;
132137 let offset = allocation. ptr ( ) . as_ptr ( ) . align_offset ( actual. as_usize ( ) ) ;
138+ // SAFETY: the allocation includes enough padding to reach this aligned pointer.
139+ let ptr = unsafe { allocation. ptr ( ) . add ( offset) . cast ( ) } ;
133140 Self {
134141 allocation,
135- offset ,
142+ ptr ,
136143 length : 0 ,
137144 alignment,
138145 physical_alignment : actual,
@@ -219,9 +226,11 @@ impl<T> BufferMut<T> {
219226 . ptr ( )
220227 . as_ptr ( )
221228 . align_offset ( actual_alignment. as_usize ( ) ) ;
229+ // SAFETY: the allocation includes enough padding to reach this aligned pointer.
230+ let ptr = unsafe { allocation. ptr ( ) . add ( offset) . cast ( ) } ;
222231 Self {
223232 allocation,
224- offset ,
233+ ptr ,
225234 length : len,
226235 alignment,
227236 physical_alignment : actual_alignment,
@@ -396,7 +405,8 @@ impl<T> BufferMut<T> {
396405 }
397406
398407 if !self . overallocated {
399- return ( self . allocation . size ( ) - self . offset ) / size_of :: < T > ( ) ;
408+ let offset = self . ptr . cast :: < u8 > ( ) . addr ( ) . get ( ) - self . allocation . ptr ( ) . addr ( ) . get ( ) ;
409+ return ( self . allocation . size ( ) - offset) / size_of :: < T > ( ) ;
400410 }
401411
402412 ( self . allocation . size ( ) - self . physical_alignment . as_usize ( ) ) / size_of :: < T > ( )
@@ -405,21 +415,19 @@ impl<T> BufferMut<T> {
405415 /// Returns a raw pointer to the buffer's data.
406416 #[ inline( always) ]
407417 pub fn as_ptr ( & self ) -> * const T {
408- // SAFETY: offset always remains within the allocation.
409- unsafe { self . allocation . ptr ( ) . as_ptr ( ) . add ( self . offset ) . cast ( ) }
418+ self . ptr . as_ptr ( )
410419 }
411420
412421 /// Returns a mutable raw pointer to the buffer's data.
413422 #[ inline( always) ]
414423 pub fn as_mut_ptr ( & mut self ) -> * mut T {
415- // SAFETY: BufferMut uniquely owns the allocation and offset is in bounds.
416- unsafe { self . allocation . ptr ( ) . as_ptr ( ) . add ( self . offset ) . cast ( ) }
424+ self . ptr . as_ptr ( )
417425 }
418426
419427 /// Returns a slice over the buffer of elements of type T.
420428 #[ inline]
421429 pub fn as_slice ( & self ) -> & [ T ] {
422- // SAFETY: the allocation is live, offset is in bounds, and construction checks alignment.
430+ // SAFETY: ptr is in the live allocation and construction checks its alignment.
423431 unsafe { std:: slice:: from_raw_parts ( self . as_ptr ( ) , self . length ) }
424432 }
425433
@@ -491,7 +499,7 @@ impl<T> BufferMut<T> {
491499 let layout = Layout :: from_size_align ( allocation_size, allocation_alignment)
492500 . unwrap_or_else ( |_| vortex_panic ! ( "buffer capacity exceeds maximum allocation size" ) ) ;
493501
494- let old_offset = self . offset ;
502+ let old_offset = self . ptr . cast :: < u8 > ( ) . addr ( ) . get ( ) - self . allocation . ptr ( ) . addr ( ) . get ( ) ;
495503 let new_offset = if self . allocation . allocator ( ) . is_statically_allocated ( ) {
496504 let allocation =
497505 Allocation :: allocate ( layout, BufferAllocatorRef :: statically_allocated ( ) ) ;
@@ -502,7 +510,7 @@ impl<T> BufferMut<T> {
502510 // SAFETY: both allocations have room for the initialized elements and do not overlap.
503511 unsafe {
504512 std:: ptr:: copy_nonoverlapping (
505- self . allocation . ptr ( ) . as_ptr ( ) . add ( old_offset ) ,
513+ self . ptr . cast :: < u8 > ( ) . as_ptr ( ) ,
506514 allocation. ptr ( ) . as_ptr ( ) . add ( new_offset) ,
507515 self . length * size_of :: < T > ( ) ,
508516 ) ;
@@ -530,7 +538,8 @@ impl<T> BufferMut<T> {
530538 }
531539 new_offset
532540 } ;
533- self . offset = new_offset;
541+ // SAFETY: new_offset was computed within the allocation for physical_alignment.
542+ self . ptr = unsafe { self . allocation . ptr ( ) . add ( new_offset) . cast ( ) } ;
534543 self . physical_alignment = physical_alignment;
535544 self . overallocated = true ;
536545 }
@@ -678,7 +687,7 @@ impl<T> BufferMut<T> {
678687 pub fn into_byte_buffer ( self ) -> ByteBufferMut {
679688 ByteBufferMut {
680689 allocation : self . allocation ,
681- offset : self . offset ,
690+ ptr : self . ptr . cast ( ) ,
682691 length : self . length * size_of :: < T > ( ) ,
683692 alignment : self . alignment ,
684693 physical_alignment : self . physical_alignment ,
@@ -689,9 +698,10 @@ impl<T> BufferMut<T> {
689698
690699 /// Freeze the `BufferMut` into a `Buffer`.
691700 pub fn freeze ( self ) -> Buffer < T > {
701+ let offset = self . ptr . cast :: < u8 > ( ) . addr ( ) . get ( ) - self . allocation . ptr ( ) . addr ( ) . get ( ) ;
692702 Buffer :: from_allocation (
693703 self . allocation ,
694- self . offset ,
704+ offset,
695705 self . length ,
696706 self . alignment ,
697707 self . physical_alignment ,
@@ -756,7 +766,7 @@ impl<T> BufferMut<T> {
756766
757767 BufferMut {
758768 allocation : self . allocation ,
759- offset : self . offset ,
769+ ptr : self . ptr . cast ( ) ,
760770 length : self . length ,
761771 alignment : self . alignment ,
762772 physical_alignment : self . physical_alignment ,
@@ -1000,7 +1010,8 @@ impl Buf for ByteBufferMut {
10001010 ) ;
10011011 }
10021012 assert ! ( cnt <= self . length, "advance out of bounds" ) ;
1003- self . offset += cnt;
1013+ // SAFETY: cnt is checked against the initialized length above.
1014+ self . ptr = unsafe { self . ptr . add ( cnt) } ;
10041015 self . length -= cnt;
10051016 }
10061017}
0 commit comments