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
`///
`