Add NonNull convenience methods to Vec · qinheping/verify-rust-std@459f246 (original) (raw)

`@@ -603,15 +603,116 @@ impl Vec {

`

603

603

`unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) }

`

604

604

`}

`

605

605

``

606

``

`` -

/// A convenience method for hoisting the non-null precondition out of [Vec::from_raw_parts].

``

``

606

`+

#[doc(alias = "from_non_null_parts")]

`

``

607

`` +

/// Creates a Vec<T> directly from a NonNull pointer, a length, and a capacity.

``

607

608

`///

`

608

609

`/// # Safety

`

609

610

`///

`

610

``

`` -

/// See [Vec::from_raw_parts].

``

``

611

`+

/// This is highly unsafe, due to the number of invariants that aren't

`

``

612

`+

/// checked:

`

``

613

`+

///

`

``

614

`` +

/// * ptr must have been allocated using the global allocator, such as via

``

``

615

`` +

/// the [alloc::alloc] function.

``

``

616

`` +

/// * T needs to have the same alignment as what ptr was allocated with.

``

``

617

`` +

/// (T having a less strict alignment is not sufficient, the alignment really

``

``

618

`` +

/// needs to be equal to satisfy the [dealloc] requirement that memory must be

``

``

619

`+

/// allocated and deallocated with the same layout.)

`

``

620

`` +

/// * The size of T times the capacity (ie. the allocated size in bytes) needs

``

``

621

`+

/// to be the same size as the pointer was allocated with. (Because similar to

`

``

622

`` +

/// alignment, [dealloc] must be called with the same layout size.)

``

``

623

`` +

/// * length needs to be less than or equal to capacity.

``

``

624

`` +

/// * The first length values must be properly initialized values of type T.

``

``

625

`` +

/// * capacity needs to be the capacity that the pointer was allocated with.

``

``

626

`` +

/// * The allocated size in bytes must be no larger than isize::MAX.

``

``

627

`` +

/// See the safety documentation of [pointer::offset].

``

``

628

`+

///

`

``

629

`` +

/// These requirements are always upheld by any ptr that has been allocated

``

``

630

`` +

/// via Vec<T>. Other allocation sources are allowed if the invariants are

``

``

631

`+

/// upheld.

`

``

632

`+

///

`

``

633

`+

/// Violating these may cause problems like corrupting the allocator's

`

``

634

`+

/// internal data structures. For example it is normally not safe

`

``

635

`` +

/// to build a Vec<u8> from a pointer to a C char array with length

``

``

636

`` +

/// size_t, doing so is only safe if the array was initially allocated by

``

``

637

`` +

/// a Vec or String.

``

``

638

`` +

/// It's also not safe to build one from a Vec<u16> and its length, because

``

``

639

`+

/// the allocator cares about the alignment, and these two types have different

`

``

640

`` +

/// alignments. The buffer was allocated with alignment 2 (for u16), but after

``

``

641

`` +

/// turning it into a Vec<u8> it'll be deallocated with alignment 1. To avoid

``

``

642

`+

/// these issues, it is often preferable to do casting/transmuting using

`

``

643

`` +

/// [NonNull::slice_from_raw_parts] instead.

``

``

644

`+

///

`

``

645

`` +

/// The ownership of ptr is effectively transferred to the

``

``

646

`` +

/// Vec<T> which may then deallocate, reallocate or change the

``

``

647

`+

/// contents of memory pointed to by the pointer at will. Ensure

`

``

648

`+

/// that nothing else uses the pointer after calling this

`

``

649

`+

/// function.

`

``

650

`+

///

`

``

651

`` +

/// [String]: crate:🧵:String

``

``

652

`` +

/// [alloc::alloc]: crate::alloc::alloc

``

``

653

`` +

/// [dealloc]: crate::alloc::GlobalAlloc::dealloc

``

``

654

`+

///

`

``

655

`+

/// # Examples

`

``

656

`+

///

`

``

657


/// ```

``

658

`+

/// #![feature(box_vec_non_null)]

`

``

659

`+

///

`

``

660

`+

/// use std::ptr::NonNull;

`

``

661

`+

/// use std::mem;

`

``

662

`+

///

`

``

663

`+

/// let v = vec![1, 2, 3];

`

``

664

`+

///

`

``

665

`+

// FIXME Update this when vec_into_raw_parts is stabilized

`

``

666

`` +

/// // Prevent running v's destructor so we are in complete control

``

``

667

`+

/// // of the allocation.

`

``

668

`+

/// let mut v = mem::ManuallyDrop::new(v);

`

``

669

`+

///

`

``

670

`` +

/// // Pull out the various important pieces of information about v

``

``

671

`+

/// let p = unsafe { NonNull::new_unchecked(v.as_mut_ptr()) };

`

``

672

`+

/// let len = v.len();

`

``

673

`+

/// let cap = v.capacity();

`

``

674

`+

///

`

``

675

`+

/// unsafe {

`

``

676

`+

/// // Overwrite memory with 4, 5, 6

`

``

677

`+

/// for i in 0..len {

`

``

678

`+

/// p.add(i).write(4 + i);

`

``

679

`+

/// }

`

``

680

`+

///

`

``

681

`+

/// // Put everything back together into a Vec

`

``

682

`+

/// let rebuilt = Vec::from_parts(p, len, cap);

`

``

683

`+

/// assert_eq!(rebuilt, [4, 5, 6]);

`

``

684

`+

/// }

`

``

685


/// ```

``

686

`+

///

`

``

687

`+

/// Using memory that was allocated elsewhere:

`

``

688

`+

///

`

``

689


/// ```rust

``

690

`+

/// #![feature(box_vec_non_null)]

`

``

691

`+

///

`

``

692

`+

/// use std::alloc::{alloc, Layout};

`

``

693

`+

/// use std::ptr::NonNull;

`

``

694

`+

///

`

``

695

`+

/// fn main() {

`

``

696

`+

/// let layout = Layout::array::(16).expect("overflow cannot happen");

`

``

697

`+

///

`

``

698

`+

/// let vec = unsafe {

`

``

699

`+

/// let Some(mem) = NonNull::new(alloc(layout).cast::()) else {

`

``

700

`+

/// return;

`

``

701

`+

/// };

`

``

702

`+

///

`

``

703

`+

/// mem.write(1_000_000);

`

``

704

`+

///

`

``

705

`+

/// Vec::from_parts(mem, 1, 16)

`

``

706

`+

/// };

`

``

707

`+

///

`

``

708

`+

/// assert_eq!(vec, &[1_000_000]);

`

``

709

`+

/// assert_eq!(vec.capacity(), 16);

`

``

710

`+

/// }

`

``

711


/// ```

611

712

`#[inline]

`

612

``

`-

#[cfg(not(no_global_oom_handling))] // required by tests/run-make/alloc-no-oom-handling

`

613

``

`-

pub(crate) unsafe fn from_nonnull(ptr: NonNull, length: usize, capacity: usize) -> Self {

`

614

``

`-

unsafe { Self::from_nonnull_in(ptr, length, capacity, Global) }

`

``

713

`+

#[unstable(feature = "box_vec_non_null", reason = "new API", issue = "none")]

`

``

714

`+

pub unsafe fn from_parts(ptr: NonNull, length: usize, capacity: usize) -> Self {

`

``

715

`+

unsafe { Self::from_parts_in(ptr, length, capacity, Global) }

`

615

716

`}

`

616

717

`}

`

617

718

``

`@@ -830,19 +931,119 @@ impl<T, A: Allocator> Vec<T, A> {

`

830

931

`unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } }

`

831

932

`}

`

832

933

``

833

``

`` -

/// A convenience method for hoisting the non-null precondition out of [Vec::from_raw_parts_in].

``

``

934

`+

#[doc(alias = "from_non_null_parts_in")]

`

``

935

`` +

/// Creates a Vec<T, A> directly from a NonNull pointer, a length, a capacity,

``

``

936

`+

/// and an allocator.

`

834

937

`///

`

835

938

`/// # Safety

`

836

939

`///

`

837

``

`` -

/// See [Vec::from_raw_parts_in].

``

``

940

`+

/// This is highly unsafe, due to the number of invariants that aren't

`

``

941

`+

/// checked:

`

``

942

`+

///

`

``

943

`` +

/// * ptr must be [currently allocated] via the given allocator alloc.

``

``

944

`` +

/// * T needs to have the same alignment as what ptr was allocated with.

``

``

945

`` +

/// (T having a less strict alignment is not sufficient, the alignment really

``

``

946

`` +

/// needs to be equal to satisfy the [dealloc] requirement that memory must be

``

``

947

`+

/// allocated and deallocated with the same layout.)

`

``

948

`` +

/// * The size of T times the capacity (ie. the allocated size in bytes) needs

``

``

949

`+

/// to be the same size as the pointer was allocated with. (Because similar to

`

``

950

`` +

/// alignment, [dealloc] must be called with the same layout size.)

``

``

951

`` +

/// * length needs to be less than or equal to capacity.

``

``

952

`` +

/// * The first length values must be properly initialized values of type T.

``

``

953

`` +

/// * capacity needs to [fit] the layout size that the pointer was allocated with.

``

``

954

`` +

/// * The allocated size in bytes must be no larger than isize::MAX.

``

``

955

`` +

/// See the safety documentation of [pointer::offset].

``

``

956

`+

///

`

``

957

`` +

/// These requirements are always upheld by any ptr that has been allocated

``

``

958

`` +

/// via Vec<T, A>. Other allocation sources are allowed if the invariants are

``

``

959

`+

/// upheld.

`

``

960

`+

///

`

``

961

`+

/// Violating these may cause problems like corrupting the allocator's

`

``

962

`+

/// internal data structures. For example it is not safe

`

``

963

`` +

/// to build a Vec<u8> from a pointer to a C char array with length size_t.

``

``

964

`` +

/// It's also not safe to build one from a Vec<u16> and its length, because

``

``

965

`+

/// the allocator cares about the alignment, and these two types have different

`

``

966

`` +

/// alignments. The buffer was allocated with alignment 2 (for u16), but after

``

``

967

`` +

/// turning it into a Vec<u8> it'll be deallocated with alignment 1.

``

``

968

`+

///

`

``

969

`` +

/// The ownership of ptr is effectively transferred to the

``

``

970

`` +

/// Vec<T> which may then deallocate, reallocate or change the

``

``

971

`+

/// contents of memory pointed to by the pointer at will. Ensure

`

``

972

`+

/// that nothing else uses the pointer after calling this

`

``

973

`+

/// function.

`

``

974

`+

///

`

``

975

`` +

/// [String]: crate:🧵:String

``

``

976

`` +

/// [dealloc]: crate::alloc::GlobalAlloc::dealloc

``

``

977

`+

/// [currently allocated]: crate::alloc::Allocator#currently-allocated-memory

`

``

978

`+

/// [fit]: crate::alloc::Allocator#memory-fitting

`

``

979

`+

///

`

``

980

`+

/// # Examples

`

``

981

`+

///

`

``

982


/// ```

``

983

`+

/// #![feature(allocator_api, box_vec_non_null)]

`

``

984

`+

///

`

``

985

`+

/// use std::alloc::System;

`

``

986

`+

///

`

``

987

`+

/// use std::ptr::NonNull;

`

``

988

`+

/// use std::mem;

`

``

989

`+

///

`

``

990

`+

/// let mut v = Vec::with_capacity_in(3, System);

`

``

991

`+

/// v.push(1);

`

``

992

`+

/// v.push(2);

`

``

993

`+

/// v.push(3);

`

``

994

`+

///

`

``

995

`+

// FIXME Update this when vec_into_raw_parts is stabilized

`

``

996

`` +

/// // Prevent running v's destructor so we are in complete control

``

``

997

`+

/// // of the allocation.

`

``

998

`+

/// let mut v = mem::ManuallyDrop::new(v);

`

``

999

`+

///

`

``

1000

`` +

/// // Pull out the various important pieces of information about v

``

``

1001

`+

/// let p = unsafe { NonNull::new_unchecked(v.as_mut_ptr()) };

`

``

1002

`+

/// let len = v.len();

`

``

1003

`+

/// let cap = v.capacity();

`

``

1004

`+

/// let alloc = v.allocator();

`

``

1005

`+

///

`

``

1006

`+

/// unsafe {

`

``

1007

`+

/// // Overwrite memory with 4, 5, 6

`

``

1008

`+

/// for i in 0..len {

`

``

1009

`+

/// p.add(i).write(4 + i);

`

``

1010

`+

/// }

`

``

1011

`+

///

`

``

1012

`+

/// // Put everything back together into a Vec

`

``

1013

`+

/// let rebuilt = Vec::from_parts_in(p, len, cap, alloc.clone());

`

``

1014

`+

/// assert_eq!(rebuilt, [4, 5, 6]);

`

``

1015

`+

/// }

`

``

1016


/// ```

``

1017

`+

///

`

``

1018

`+

/// Using memory that was allocated elsewhere:

`

``

1019

`+

///

`

``

1020


/// ```rust

``

1021

`+

/// #![feature(allocator_api, box_vec_non_null)]

`

``

1022

`+

///

`

``

1023

`+

/// use std::alloc::{AllocError, Allocator, Global, Layout};

`

``

1024

`+

///

`

``

1025

`+

/// fn main() {

`

``

1026

`+

/// let layout = Layout::array::(16).expect("overflow cannot happen");

`

``

1027

`+

///

`

``

1028

`+

/// let vec = unsafe {

`

``

1029

`+

/// let mem = match Global.allocate(layout) {

`

``

1030

`+

/// Ok(mem) => mem.cast::(),

`

``

1031

`+

/// Err(AllocError) => return,

`

``

1032

`+

/// };

`

``

1033

`+

///

`

``

1034

`+

/// mem.write(1_000_000);

`

``

1035

`+

///

`

``

1036

`+

/// Vec::from_parts_in(mem, 1, 16, Global)

`

``

1037

`+

/// };

`

``

1038

`+

///

`

``

1039

`+

/// assert_eq!(vec, &[1_000_000]);

`

``

1040

`+

/// assert_eq!(vec.capacity(), 16);

`

``

1041

`+

/// }

`

``

1042


/// ```

838

1043

`#[inline]

`

839

``

`-

#[cfg(not(no_global_oom_handling))] // required by tests/run-make/alloc-no-oom-handling

`

840

``

`-

pub(crate) unsafe fn from_nonnull_in(

`

841

``

`-

ptr: NonNull,

`

842

``

`-

length: usize,

`

843

``

`-

capacity: usize,

`

844

``

`-

alloc: A,

`

845

``

`-

) -> Self {

`

``

1044

`+

#[unstable(feature = "allocator_api", reason = "new API", issue = "32838")]

`

``

1045

`+

// #[unstable(feature = "box_vec_non_null", issue = "none")]

`

``

1046

`+

pub unsafe fn from_parts_in(ptr: NonNull, length: usize, capacity: usize, alloc: A) -> Self {

`

846

1047

`unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } }

`

847

1048

`}

`

848

1049

``

`@@ -885,6 +1086,49 @@ impl<T, A: Allocator> Vec<T, A> {

`

885

1086

`(me.as_mut_ptr(), me.len(), me.capacity())

`

886

1087

`}

`

887

1088

``

``

1089

`+

#[doc(alias = "into_non_null_parts")]

`

``

1090

`` +

/// Decomposes a Vec<T> into its raw components: (NonNull pointer, length, capacity).

``

``

1091

`+

///

`

``

1092

`` +

/// Returns the NonNull pointer to the underlying data, the length of

``

``

1093

`+

/// the vector (in elements), and the allocated capacity of the

`

``

1094

`+

/// data (in elements). These are the same arguments in the same

`

``

1095

`` +

/// order as the arguments to [from_parts].

``

``

1096

`+

///

`

``

1097

`+

/// After calling this function, the caller is responsible for the

`

``

1098

`` +

/// memory previously managed by the Vec. The only way to do

``

``

1099

`` +

/// this is to convert the NonNull pointer, length, and capacity back

``

``

1100

`` +

/// into a Vec with the [from_parts] function, allowing

``

``

1101

`+

/// the destructor to perform the cleanup.

`

``

1102

`+

///

`

``

1103

`` +

/// [from_parts]: Vec::from_parts

``

``

1104

`+

///

`

``

1105

`+

/// # Examples

`

``

1106

`+

///

`

``

1107


/// ```

``

1108

`+

/// #![feature(vec_into_raw_parts, box_vec_non_null)]

`

``

1109

`+

///

`

``

1110

`+

/// let v: Vec = vec![-1, 0, 1];

`

``

1111

`+

///

`

``

1112

`+

/// let (ptr, len, cap) = v.into_parts();

`

``

1113

`+

///

`

``

1114

`+

/// let rebuilt = unsafe {

`

``

1115

`+

/// // We can now make changes to the components, such as

`

``

1116

`+

/// // transmuting the raw pointer to a compatible type.

`

``

1117

`+

/// let ptr = ptr.cast::();

`

``

1118

`+

///

`

``

1119

`+

/// Vec::from_parts(ptr, len, cap)

`

``

1120

`+

/// };

`

``

1121

`+

/// assert_eq!(rebuilt, [4294967295, 0, 1]);

`

``

1122


/// ```

``

1123

`+

#[must_use = "losing the pointer will leak memory"]

`

``

1124

`+

#[unstable(feature = "box_vec_non_null", reason = "new API", issue = "none")]

`

``

1125

`+

// #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]

`

``

1126

`+

pub fn into_parts(self) -> (NonNull, usize, usize) {

`

``

1127

`+

let (ptr, len, capacity) = self.into_raw_parts();

`

``

1128

`` +

// SAFETY: A Vec always has a non-null pointer.

``

``

1129

`+

(unsafe { NonNull::new_unchecked(ptr) }, len, capacity)

`

``

1130

`+

}

`

``

1131

+

888

1132

`` /// Decomposes a Vec<T> into its raw components: (pointer, length, capacity, allocator).

``

889

1133

`///

`

890

1134

`/// Returns the raw pointer to the underlying data, the length of the vector (in elements),

`

`@@ -934,6 +1178,54 @@ impl<T, A: Allocator> Vec<T, A> {

`

934

1178

`(ptr, len, capacity, alloc)

`

935

1179

`}

`

936

1180

``

``

1181

`+

#[doc(alias = "into_non_null_parts_with_alloc")]

`

``

1182

`` +

/// Decomposes a Vec<T> into its raw components: (NonNull pointer, length, capacity, allocator).

``

``

1183

`+

///

`

``

1184

`` +

/// Returns the NonNull pointer to the underlying data, the length of the vector (in elements),

``

``

1185

`+

/// the allocated capacity of the data (in elements), and the allocator. These are the same

`

``

1186

`` +

/// arguments in the same order as the arguments to [from_parts_in].

``

``

1187

`+

///

`

``

1188

`+

/// After calling this function, the caller is responsible for the

`

``

1189

`` +

/// memory previously managed by the Vec. The only way to do

``

``

1190

`` +

/// this is to convert the NonNull pointer, length, and capacity back

``

``

1191

`` +

/// into a Vec with the [from_parts_in] function, allowing

``

``

1192

`+

/// the destructor to perform the cleanup.

`

``

1193

`+

///

`

``

1194

`` +

/// [from_parts_in]: Vec::from_parts_in

``

``

1195

`+

///

`

``

1196

`+

/// # Examples

`

``

1197

`+

///

`

``

1198


/// ```

``

1199

`+

/// #![feature(allocator_api, vec_into_raw_parts, box_vec_non_null)]

`

``

1200

`+

///

`

``

1201

`+

/// use std::alloc::System;

`

``

1202

`+

///

`

``

1203

`+

/// let mut v: Vec<i32, System> = Vec::new_in(System);

`

``

1204

`+

/// v.push(-1);

`

``

1205

`+

/// v.push(0);

`

``

1206

`+

/// v.push(1);

`

``

1207

`+

///

`

``

1208

`+

/// let (ptr, len, cap, alloc) = v.into_parts_with_alloc();

`

``

1209

`+

///

`

``

1210

`+

/// let rebuilt = unsafe {

`

``

1211

`+

/// // We can now make changes to the components, such as

`

``

1212

`+

/// // transmuting the raw pointer to a compatible type.

`

``

1213

`+

/// let ptr = ptr.cast::();

`

``

1214

`+

///

`

``

1215

`+

/// Vec::from_parts_in(ptr, len, cap, alloc)

`

``

1216

`+

/// };

`

``

1217

`+

/// assert_eq!(rebuilt, [4294967295, 0, 1]);

`

``

1218


/// ```

``

1219

`+

#[must_use = "losing the pointer will leak memory"]

`

``

1220

`+

#[unstable(feature = "allocator_api", issue = "32838")]

`

``

1221

`+

// #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "none")]

`

``

1222

`+

// #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]

`

``

1223

`+

pub fn into_parts_with_alloc(self) -> (NonNull, usize, usize, A) {

`

``

1224

`+

let (ptr, len, capacity, alloc) = self.into_raw_parts_with_alloc();

`

``

1225

`` +

// SAFETY: A Vec always has a non-null pointer.

``

``

1226

`+

(unsafe { NonNull::new_unchecked(ptr) }, len, capacity, alloc)

`

``

1227

`+

}

`

``

1228

+

937

1229

`/// Returns the total number of elements the vector can hold without

`

938

1230

`/// reallocating.

`

939

1231

`///

`