diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 6b50de1455918..f609db38f2688 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1366,6 +1366,9 @@ impl [T] { #[cfg_attr(rapx, rapx::verify)] #[cfg_attr(rapx, rapx::requires(ValidNum(N, "[1,)")))] #[cfg_attr(rapx, rapx::requires(ValidNum(len(self) % N == 0)))] + // Safety precondition from the documentation: `N != 0` and the length is a multiple of `N`. + #[requires(N != 0 && self.len().is_multiple_of(N))] + #[ensures(|chunks: &&[[T; N]]| chunks.len() == self.len() / N && chunks.as_ptr() as *const T == self.as_ptr())] pub const unsafe fn as_chunks_unchecked<#[rustc_panics_when_zero] const N: usize>( &self, ) -> &[[T; N]] { @@ -1533,6 +1536,9 @@ impl [T] { #[cfg_attr(rapx, rapx::verify)] #[cfg_attr(rapx, rapx::requires(ValidNum(N, "[1,)")))] #[cfg_attr(rapx, rapx::requires(ValidNum(len(self) % N == 0)))] + // Safety precondition from the documentation: `N != 0` and the length is a multiple of `N`. + #[requires(N != 0 && self.len().is_multiple_of(N))] + #[ensures(|chunks: &&mut [[T; N]]| chunks.len() == old(self.len()) / N)] pub const unsafe fn as_chunks_unchecked_mut<#[rustc_panics_when_zero] const N: usize>( &mut self, ) -> &mut [[T; N]] { @@ -5283,6 +5289,9 @@ impl [T] { #[cfg_attr(rapx, rapx::verify)] #[cfg_attr(rapx, rapx::requires(InBound(self, indices)))] #[cfg_attr(rapx, rapx::requires(NonOverlap(indices)))] + // Safety precondition from the documentation: all indices in bounds and pairwise disjoint, + // i.e. exactly what `get_disjoint_mut` checks before calling this function. + #[requires(get_disjoint_check_valid(&indices, self.len()).is_ok())] pub unsafe fn get_disjoint_unchecked_mut( &mut self, indices: [I; N], @@ -6066,4 +6075,204 @@ mod verify { let mut a: [u8; 100] = kani::any(); a.reverse(); } + + // Const-generic functions. The VeriFast proof in verifast-proofs/core/slice verifies these + // through runtime-`n` transcriptions (VeriFast cannot yet attach specifications to + // `` functions); the harnesses below run the exact shipped bodies, bounded in slice + // length and monomorphized over a few element types and chunk sizes. + + const CG_ARR_SIZE: usize = 12; + + macro_rules! proof_of_contract_for_as_chunks_unchecked { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof_for_contract(<[$t]>::as_chunks_unchecked)] + fn $harness() { + let arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let chunks = unsafe { s.as_chunks_unchecked::<$n>() }; + assert_eq!(chunks.len(), s.len() / $n); + } + }; + } + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u8_1, u8, 1); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u8_3, u8, 3); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u32_2, u32, 2); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_unit_4, (), 4); + + macro_rules! proof_of_contract_for_as_chunks_unchecked_mut { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof_for_contract(<[$t]>::as_chunks_unchecked_mut)] + fn $harness() { + let mut arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let chunks = unsafe { s.as_chunks_unchecked_mut::<$n>() }; + assert_eq!(chunks.len(), len / $n); + } + }; + } + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u8_1, u8, 1); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u8_3, u8, 3); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u32_2, u32, 2); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_unit_4, (), 4); + + #[kani::proof_for_contract(<[u8]>::get_disjoint_unchecked_mut)] + fn check_get_disjoint_unchecked_mut_usize() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let indices: [usize; 3] = kani::any(); + let [a, b, c] = unsafe { s.get_disjoint_unchecked_mut(indices) }; + *a = 1; + *b = 2; + *c = 3; + } + + #[kani::proof_for_contract(<[u32]>::get_disjoint_unchecked_mut)] + fn check_get_disjoint_unchecked_mut_range() { + let mut arr: [u32; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let indices: [Range; 2] = [kani::any()..kani::any(), kani::any()..kani::any()]; + let [a, b] = unsafe { s.get_disjoint_unchecked_mut(indices) }; + if let Some(x) = a.first_mut() { + *x = 1; + } + if let Some(y) = b.first_mut() { + *y = 2; + } + } + + macro_rules! check_chunk_accessors { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof] + fn $harness() { + let mut arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let len = s.len(); + match s.first_chunk::<$n>() { + Some(c) => assert!(len >= $n && c.as_ptr() == s.as_ptr()), + None => assert!(len < $n), + } + match s.last_chunk::<$n>() { + Some(c) => { + assert!(len >= $n && c.as_ptr() == unsafe { s.as_ptr().add(len - $n) }) + } + None => assert!(len < $n), + } + match s.split_first_chunk::<$n>() { + Some((c, rest)) => assert!(c.len() + rest.len() == len), + None => assert!(len < $n), + } + match s.split_last_chunk::<$n>() { + Some((rest, c)) => assert!(rest.len() + c.len() == len), + None => assert!(len < $n), + } + let (chunks, rem) = s.as_chunks::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + let (rem, chunks) = s.as_rchunks::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + match s.first_chunk_mut::<$n>() { + Some(c) => assert!(len >= $n && c.len() == $n), + None => assert!(len < $n), + } + match s.last_chunk_mut::<$n>() { + Some(c) => assert!(len >= $n && c.len() == $n), + None => assert!(len < $n), + } + match s.split_first_chunk_mut::<$n>() { + Some((c, rest)) => assert!(c.len() + rest.len() == len), + None => assert!(len < $n), + } + match s.split_last_chunk_mut::<$n>() { + Some((rest, c)) => assert!(rest.len() + c.len() == len), + None => assert!(len < $n), + } + let (chunks, rem) = s.as_chunks_mut::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + } + }; + } + check_chunk_accessors!(check_chunk_accessors_u8_1, u8, 1); + check_chunk_accessors!(check_chunk_accessors_u8_3, u8, 3); + check_chunk_accessors!(check_chunk_accessors_u32_2, u32, 2); + check_chunk_accessors!(check_chunk_accessors_unit_5, (), 5); + + macro_rules! check_as_flattened { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof] + fn $harness() { + let mut arr: [[$t; $n]; 4] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let flat = s.as_flattened(); + assert!(flat.len() == s.len() * $n); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let flat = s.as_flattened_mut(); + assert!(flat.len() == len * $n); + } + }; + } + check_as_flattened!(check_as_flattened_u8_3, u8, 3); + check_as_flattened!(check_as_flattened_u32_2, u32, 2); + check_as_flattened!(check_as_flattened_u8_0, u8, 0); + + #[kani::proof] + fn check_as_simd_u8_4() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let (prefix, middle, suffix) = s.as_simd::<4>(); + assert!(prefix.len() + middle.len() * 4 + suffix.len() == s.len()); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let (prefix, middle, suffix) = s.as_simd_mut::<4>(); + assert!(prefix.len() + middle.len() * 4 + suffix.len() == len); + } + + #[kani::proof] + fn check_get_disjoint_mut_usize() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let indices: [usize; 3] = kani::any(); + let valid = get_disjoint_check_valid(&indices, len).is_ok(); + match s.get_disjoint_mut(indices) { + Ok([a, b, c]) => { + assert!(valid); + *a = 1; + *b = 2; + *c = 3; + } + Err(_) => assert!(!valid), + } + } + + #[kani::proof] + fn check_get_disjoint_mut_range() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let indices: [Range; 2] = [kani::any()..kani::any(), kani::any()..kani::any()]; + let valid = get_disjoint_check_valid(&indices, len).is_ok(); + match s.get_disjoint_mut(indices) { + Ok([a, b]) => { + assert!(valid); + assert!(a.len() + b.len() <= len); + } + Err(_) => assert!(!valid), + } + } + + #[kani::proof] + fn check_get_disjoint_check_valid() { + let len: usize = kani::any(); + kani::assume(len <= CG_ARR_SIZE); + let indices: [usize; 3] = kani::any(); + let r = get_disjoint_check_valid(&indices, len); + let in_bounds = indices.iter().all(|i| *i < len); + let disjoint = + indices[0] != indices[1] && indices[0] != indices[2] && indices[1] != indices[2]; + assert!(r.is_ok() == (in_bounds && disjoint)); + } } diff --git a/verifast-proofs/README.md b/verifast-proofs/README.md index 096d3e32e9061..2a669bb7d9db5 100644 --- a/verifast-proofs/README.md +++ b/verifast-proofs/README.md @@ -6,6 +6,7 @@ Specifically, it currently contains the following proofs: - Partial proof of [LinkedList](alloc/collections/linked_list.rs/) - Partial proof of [RawVec](alloc/raw_vec/mod.rs/) +- Partial proof of [core::slice](core/slice/mod.rs/) See each proof's accompanying README for a tour of the proof and applicable caveats. diff --git a/verifast-proofs/check-verifast-proofs-negative.sh b/verifast-proofs/check-verifast-proofs-negative.sh index 89fa996463136..8edcf4a9c1cfb 100755 --- a/verifast-proofs/check-verifast-proofs-negative.sh +++ b/verifast-proofs/check-verifast-proofs-negative.sh @@ -12,3 +12,10 @@ cd alloc cd .. cd .. cd .. +cd core + cd slice + cd mod.rs-negative + bash verify.sh + cd .. + cd .. +cd .. diff --git a/verifast-proofs/check-verifast-proofs.sh b/verifast-proofs/check-verifast-proofs.sh index 23bd82948efbd..bf272db119f63 100755 --- a/verifast-proofs/check-verifast-proofs.sh +++ b/verifast-proofs/check-verifast-proofs.sh @@ -18,3 +18,10 @@ cd alloc cd .. cd .. cd .. +cd core + cd slice + cd mod.rs + bash verify.sh + cd .. + cd .. +cd .. diff --git a/verifast-proofs/core/slice/mod.rs-negative/core.rsspec b/verifast-proofs/core/slice/mod.rs-negative/core.rsspec new file mode 100644 index 0000000000000..8eb9b00e49d44 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/core.rsspec @@ -0,0 +1,114 @@ +mod num { + impl usize { + fn is_multiple_of(self: usize, rhs: usize) -> bool; + //@ req true; + //@ ens result == if rhs == 0 { self == 0 } else { self % rhs == 0 }; + //@ on_unwind_ens false; + } +} + +mod hint { + fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T; + //@ req true; + //@ ens result == if b { true_val } else { false_val }; + //@ on_unwind_ens false; +} + +mod cmp { + mod PartialEq { + fn eq(self: &'a T, other: &'b U) -> bool; + //@ req <&'b U>.own(?_t, other); + //@ ens true; + //@ on_unwind_ens false; + } +} + +mod mem { + fn swap(x: &'a mut T, y: &'b mut T); + //@ req *x |-> ?vx &*& *y |-> ?vy; + //@ ens *x |-> vy &*& *y |-> vx; + //@ on_unwind_ens false; +} + +mod ptr { + fn metadata(p: *const T) -> usize; + //@ req true; + //@ ens result == ptr_len(p) &*& 0 <= result &*& result <= usize::MAX; + //@ on_unwind_ens false; + + /*@ + // `ptr::swap` allows `x == y` (and, more generally, overlap); this models the `x == y` case + // as the only aliasing case, which is all `core::slice` needs. + pred opt_pointsto(same: bool, x: *T, y: *T, vx: T, vy: T) = + if same { x == y &*& vy == vx } else { *y |-> vy }; + @*/ + + unsafe fn swap(x: *mut T, y: *mut T); + //@ req *x |-> ?vx &*& opt_pointsto::(?same, x, y, vx, ?vy); + //@ ens *x |-> vy &*& if same { true } else { *y |-> vx }; + //@ on_unwind_ens false; + + unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize); + //@ req x[..count] |-> ?vs1 &*& y[..count] |-> ?vs2; + //@ ens x[..count] |-> vs2 &*& y[..count] |-> vs1; + //@ on_unwind_ens false; +} + +mod slice { + + /*@ + pred SliceIndex_in_bounds(idx: I, slice: *T); + + lem usize_SliceIndex_in_bounds(i: usize, slice: *[T]); + req i < slice.len(); + ens SliceIndex_in_bounds::(i, slice); + + fix GetDisjointMutIndex_in_bounds(idx: I, len: usize) -> bool; + fix GetDisjointMutIndex_overlapping(idx1: I, idx2: I) -> bool; + @*/ + + enum GetDisjointMutError { + IndexOutOfBounds, + OverlappingIndices, + } + + trait SliceIndex { + type Output; + } + + mod SliceIndex { + + unsafe fn get_unchecked(self: I, slice: *const T) -> *const >::Output; + //@ req thread_token(?t) &*& [_](.share(?k, t, slice)) &*& std::slice::SliceIndex_in_bounds::(self, slice); + //@ ens thread_token(t) &*& [_](< >::Output>.share(k, t, result)); + //@ on_unwind_ens false; + + unsafe fn get_unchecked_mut(self: I, slice: *mut T) -> *mut >::Output; + //@ req thread_token(?t) &*& full_borrow(?k, .full_borrow_content(t, slice)) &*& std::slice::SliceIndex_in_bounds::(self, slice); + //@ ens thread_token(t) &*& full_borrow(k, < >::Output>.full_borrow_content(t, result)); + //@ on_unwind_ens false; + + } + + mod GetDisjointMutIndex { + + fn is_in_bounds(self: &'a I, len: usize) -> bool; + //@ req thread_token(?t) &*& [?f](*self |-> ?v); + //@ ens thread_token(t) &*& [f](*self |-> v) &*& result == std::slice::GetDisjointMutIndex_in_bounds::(v, len); + //@ on_unwind_ens false; + + fn is_overlapping(self: &'a I, other: &'b I) -> bool; + //@ req thread_token(?t) &*& [?f1](*self |-> ?v1) &*& [?f2](*other |-> ?v2); + //@ ens thread_token(t) &*& [f1](*self |-> v1) &*& [f2](*other |-> v2) &*& result == std::slice::GetDisjointMutIndex_overlapping::(v1, v2); + //@ on_unwind_ens false; + + } + + fn copy_from_slice_impl::len_mismatch_fail(dst_len: usize, src_len: usize) -> !; + //@ req true; + //@ ens false; + //@ on_unwind_ens false; + +} + + diff --git a/verifast-proofs/core/slice/mod.rs-negative/original/lib.rs b/verifast-proofs/core/slice/mod.rs-negative/original/lib.rs new file mode 100644 index 0000000000000..57beec482efd3 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/original/lib.rs @@ -0,0 +1,344 @@ +#![feature(const_result_trait_fn, const_iter)] +#![feature(one_sided_range, portable_simd, slice_index_methods, const_index, slice_range, const_clone, trivial_clone, slice_from_ptr_range, const_default, u8_split_ascii_whitespace, str_internals, slice_pattern)] +#![feature(slice_ptr_get, raw_slice_split, ptr_cast_array, array_into_iter_constructors, exact_size_is_empty, iter_advance_by, iter_next_chunk, iter_collect_into, trusted_len, trusted_random_access, trusted_fused, inplace_iteration, sized_type_properties, nonnull_provenance, ptr_metadata, slice_internals, const_option_ops, deref_pure_trait, try_trait_v2, never_type, specialization)] +//! # The Rust Core Library +//! +//! The Rust Core Library is the dependency-free[^free] foundation of [The +//! Rust Standard Library](../std/index.html). It is the portable glue +//! between the language and its libraries, defining the intrinsic and +//! primitive building blocks of all Rust code. It links to no +//! upstream libraries, no system libraries, and no libc. +//! +//! [^free]: Strictly speaking, there are some symbols which are needed but +//! they aren't always necessary. +//! +//! The core library is *minimal*: it isn't even aware of heap allocation, +//! nor does it provide concurrency or I/O. These things require +//! platform integration, and this library is platform-agnostic. +//! +//! # How to use the core library +//! +//! Please note that all of these details are currently not considered stable. +//! +// FIXME: Fill me in with more detail when the interface settles +//! This library is built on the assumption of a few existing symbols: +//! +//! * `memcpy`, `memmove`, `memset`, `memcmp`, `bcmp`, `strlen` - These are core memory routines +//! which are generated by Rust codegen backends. Additionally, this library can make explicit +//! calls to `strlen`. Their signatures are the same as found in C, but there are extra +//! assumptions about their semantics: For `memcpy`, `memmove`, `memset`, `memcmp`, and `bcmp`, if +//! the `n` parameter is 0, the function is assumed to not be UB, even if the pointers are NULL or +//! dangling. (Note that making extra assumptions about these functions is common among compilers: +//! [clang](https://reviews.llvm.org/D86993) and [GCC](https://gcc.gnu.org/onlinedocs/gcc/Standards.html#C-Language) do the same.) +//! These functions are often provided by the system libc, but can also be provided by the +//! [compiler-builtins crate](https://crates.io/crates/compiler_builtins). +//! Note that the library does not guarantee that it will always make these assumptions, so Rust +//! user code directly calling the C functions should follow the C specification! The advice for +//! Rust user code is to call the functions provided by this library instead (such as +//! `ptr::copy`). +//! +//! * Panic handler - This function takes one argument, a `&panic::PanicInfo`. It is up to consumers of this core +//! library to define this panic function; it is only required to never +//! return. You should mark your implementation using `#[panic_handler]`. +//! +//! * `rust_eh_personality` - is used by the failure mechanisms of the +//! compiler. This is often mapped to GCC's personality function, but crates +//! which do not trigger a panic can be assured that this function is never +//! called. The `lang` attribute is called `eh_personality`. + +#![stable(feature = "core", since = "1.6.0")] +#![doc( + html_playground_url = "https://play.rust-lang.org/", + issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", + test(no_crate_inject, attr(deny(warnings))), + test(attr(allow(dead_code, deprecated, unused_variables, unused_mut, duplicate_features))) +)] +#![doc(rust_logo)] +#![doc(auto_cfg( + hide(no_fp_fmt_parse), + hide(target_pointer_width, values("16", "32", "64")), + hide( + target_has_atomic, + target_has_atomic_primitive_alignment, + target_has_atomic_load_store, + values("8", "16", "32", "64", "ptr"), + ), +))] +#![rustc_coherence_is_core] +#![rustc_preserve_ub_checks] +// +// Lints: +#![deny(rust_2021_incompatible_or_patterns)] +#![deny(unsafe_op_in_unsafe_fn)] +#![deny(implicit_provenance_casts)] +#![warn(deprecated_in_future)] +#![warn(missing_debug_implementations)] +#![warn(missing_docs)] +#![allow(explicit_outlives_requirements)] +#![allow(incomplete_features)] +#![warn(multiple_supertrait_upcastable)] +#![allow(internal_features)] +#![allow(unused_features)] +#![deny(ffi_unwind_calls)] +#![warn(unreachable_pub)] +// Do not check link redundancy on bootstrapping phase +#![allow(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::unescaped_backticks)] +// +// Library features: +// tidy-alphabetical-start +#![feature(asm_experimental_arch)] +#![feature(bstr_internals)] +#![feature(cfg_target_has_reliable_f16_f128)] +#![feature(const_carrying_mul_add)] +#![feature(const_cmp)] +#![feature(const_destruct)] +#![feature(const_eval_select)] +#![feature(const_select_unpredictable)] +#![feature(core_intrinsics)] +#![feature(coverage_attribute)] +#![feature(disjoint_bitor)] +#![feature(io_const_error)] +#![feature(offset_of_enum)] +#![feature(panic_internals)] +#![feature(pattern_type_macro)] +#![feature(ub_checks)] +// tidy-alphabetical-end +// +// Language features: +// tidy-alphabetical-start +#![feature(adt_const_params)] +#![feature(allow_internal_unsafe)] +#![feature(allow_internal_unstable)] +#![feature(arbitrary_self_types_pointers)] +#![feature(auto_traits)] +#![feature(cfg_sanitize)] +#![feature(cfg_target_has_atomic)] +#![feature(cfg_ub_checks)] +#![feature(const_closures)] +#![feature(const_precise_live_drops)] +#![feature(const_trait_impl)] +#![feature(decl_macro)] +#![feature(deprecated_suggestion)] +#![feature(derive_const)] +#![feature(diagnostic_on_const)] +#![feature(diagnostic_on_unmatched_args)] +#![feature(diagnostic_opaque)] +#![feature(doc_cfg)] +#![feature(doc_notable_trait)] +#![feature(extern_types)] +#![feature(f16)] +#![feature(f128)] +#![feature(field_projections)] +#![feature(final_associated_functions)] +#![feature(freeze_impls)] +#![feature(fundamental)] +#![feature(funnel_shifts)] +#![feature(impl_restriction)] +#![feature(intra_doc_pointers)] +#![feature(intrinsics)] +#![feature(lang_items)] +#![feature(link_cfg)] +#![feature(link_llvm_intrinsics)] +#![feature(macro_metavar_expr)] +#![feature(macro_metavar_expr_concat)] +#![feature(marker_trait_attr)] +#![feature(min_specialization)] +#![feature(multiple_supertrait_upcastable)] +#![feature(must_not_suspend)] +#![feature(negative_impls)] +#![feature(no_core)] +#![feature(optimize_attribute)] +#![feature(pattern_types)] +#![feature(pin_macro_internals)] +#![feature(prelude_import)] +#![feature(repr_simd)] +#![feature(rustc_attrs)] +#![feature(rustdoc_internals)] +#![feature(simd_ffi)] +#![feature(splat)] +#![feature(staged_api)] +#![feature(stmt_expr_attributes)] +#![feature(strict_provenance_lints)] +#![feature(trait_alias)] +#![feature(transparent_unions)] +#![feature(try_blocks)] +#![feature(uint_carryless_mul)] +#![feature(unboxed_closures)] +#![feature(unsized_fn_params)] +#![feature(with_negative_coherence)] +// Required for Kani loop contracts, which are annotated as custom stmt attributes. +#![feature(proc_macro_hygiene)] +// tidy-alphabetical-end +// +// Target features: +// tidy-alphabetical-start +#![feature(aarch64_unstable_target_feature)] +#![feature(arm_target_feature)] +#![feature(avx10_target_feature)] +#![feature(clflushopt_target_feature)] +#![feature(hexagon_target_feature)] +#![feature(loongarch_target_feature)] +#![feature(mips_target_feature)] +#![feature(movrs_target_feature)] +#![feature(nvptx_target_feature)] +#![feature(powerpc_target_feature)] +#![feature(riscv_target_feature)] +#![feature(rtm_target_feature)] +#![feature(s390x_target_feature)] +#![feature(wasm_target_feature)] +#![feature(x86_amx_intrinsics)] +// tidy-alphabetical-end + +// tidy-alphabetical-start +#![expect(clippy::partialeq_ne_impl, reason = "we need to implement ne for a lot of core types")] +// tidy-alphabetical-end + +// allow using `core::` in intra-doc links + +#![no_core] +#![allow(unused_imports, unused_variables, dead_code, unused_mut, unreachable_pub, missing_docs, missing_debug_implementations)] + +#[stable(feature = "rust1", since = "1.0.0")] +extern crate core; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::{iter, ascii, char, clone, cmp, convert, default, fmt, hash, hint, marker, mem, num, ops, option, panicking, pin, range, result, simd, str}; +#[stable(feature = "rust1", since = "1.0.0")] +pub mod panic { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::panic::{Location, PanicInfo}; + #[unstable(feature = "panic_internals", issue = "none")] + pub macro const_panic($($t:tt)*) { + loop {} + } +} +#[stable(feature = "rust1", since = "1.0.0")] +pub mod ptr { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::ptr::*; + #[unstable(feature = "ptr_internals", issue = "none")] + pub unsafe fn align_offset(p: *const T, a: usize) -> usize { + p.align_offset(a) + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] + pub const unsafe fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { + core::ptr::slice_from_raw_parts(data, len) + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")] + pub const unsafe fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { + core::ptr::slice_from_raw_parts_mut(data, len) + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] + pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + unsafe { core::ptr::copy(src, dst, count) } + } +} +#[stable(feature = "rust1", since = "1.0.0")] +pub mod intrinsics { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::intrinsics::{assume, arith_offset, ptr_offset_from, ptr_offset_from_unsigned, transmute, transmute_unchecked, write_bytes, copy, copy_nonoverlapping, compare_bytes, cttz_nonzero, ctlz_nonzero, size_of_val, align_of_val, size_of, align_of, needs_drop, type_id, type_name, caller_location, cold_path, likely, unlikely, select_unpredictable, abort, unreachable, const_eval_select, black_box, unchecked_shl, unchecked_shr}; + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn exact_div(x: usize, y: usize) -> usize { + x / y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_sub(x: usize, y: usize) -> usize { + x - y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_add(x: usize, y: usize) -> usize { + x + y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_mul(x: usize, y: usize) -> usize { + x * y + } +} + +#[unstable(feature = "ub_checks", issue = "none")] +pub mod ub_checks { + #[unstable(feature = "ub_checks", issue = "none")] + pub trait Invariant { + fn is_safe(&self) -> bool { true } + } + #[unstable(feature = "ub_checks", issue = "none")] + impl Invariant for &T {} + #[unstable(feature = "ub_checks", issue = "none")] + impl Invariant for &mut T {} + #[macro_export] + macro_rules! assert_unsafe_precondition { + ($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {{}}; + } + #[unstable(feature = "ub_checks", issue = "none")] + pub use assert_unsafe_precondition; + #[unstable(feature = "ub_checks", issue = "none")] + pub const fn check_language_ub() -> bool { false } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn same_allocation(_a: *const T, _b: *const T) -> bool { true } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn can_dereference(_p: *const T) -> bool { true } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn can_write(_p: *mut T) -> bool { true } +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod array { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::array::*; + #[unstable(feature = "iter_next_chunk", issue = "none")] + pub fn iter_next_chunk(_iter: &mut impl crate::iter::Iterator) -> Result<[T; N], core::array::IntoIter> { + loop {} + } +} + + + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::prelude::v1::{ + Copy, Send, Sized, Sync, Unpin, Drop, Fn, FnMut, FnOnce, AsyncFn, AsyncFnMut, AsyncFnOnce, + drop, align_of, align_of_val, size_of, size_of_val, + Clone, PartialEq, PartialOrd, Eq, Ord, AsMut, AsRef, From, Into, + Option, Some, None, Result, Ok, Err, + Debug, Hash, + panic, assert, assert_eq, assert_ne, cfg, column, compile_error, concat, debug_assert, debug_assert_eq, + debug_assert_ne, file, format_args, include, include_bytes, include_str, line, matches, + module_path, option_env, stringify, todo, unimplemented, unreachable, write, writeln, + cfg_select, derive, derive_const, + }; + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::prelude::rust_2024::{TryInto, TryFrom, FromIterator, Future, IntoFuture}; + #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::Default; + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::iter::{Iterator, IntoIterator, DoubleEndedIterator, ExactSizeIterator, Extend}; +} +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +pub const trait Default { + #[stable(feature = "rust1", since = "1.0.0")] + fn default() -> Self; +} +#[prelude_import] +#[stable(feature = "rust1", since = "1.0.0")] +pub use prelude::*; + +#[stable(feature = "rust1", since = "1.0.0")] +#[path = "."] +pub mod std { + pub mod slice; +} +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::std::slice; + +#[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] +const fn _vf_const_marker() {} + diff --git a/verifast-proofs/core/slice/mod.rs-negative/original/slice.rs b/verifast-proofs/core/slice/mod.rs-negative/original/slice.rs new file mode 100644 index 0000000000000..f609db38f2688 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/original/slice.rs @@ -0,0 +1,6278 @@ +//! Slice management and manipulation. +//! +//! For more details see [`std::slice`]. +//! +//! [`std::slice`]: ../../std/slice/index.html + +#![stable(feature = "rust1", since = "1.0.0")] + +use safety::{ensures, requires}; + +use crate::clone::TrivialClone; +use crate::cmp::Ordering::{self, Equal, Greater, Less}; +use crate::intrinsics::{exact_div, unchecked_sub}; +#[cfg(kani)] +use crate::kani; +use crate::marker::Destruct; +use crate::mem::{self, MaybeUninit, SizedTypeProperties}; +use crate::num::NonZero; +use crate::ops::{OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeInclusive}; +use crate::panic::const_panic; +use crate::simd::{self, Simd}; +use crate::ub_checks::assert_unsafe_precondition; +use crate::{fmt, hint, ptr, range, slice}; + +#[unstable( + feature = "slice_internals", + issue = "none", + reason = "exposed from core to be reused in std; use the memchr crate" +)] +#[doc(hidden)] +/// Pure Rust memchr implementation, taken from rust-memchr +pub mod memchr; + +#[unstable( + feature = "slice_internals", + issue = "none", + reason = "exposed from core to be reused in std;" +)] +#[doc(hidden)] +pub mod sort; + +mod ascii; +mod cmp; +pub(crate) mod index; +mod iter; +mod raw; +mod rotate; +mod specialize; + +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] +pub use ascii::EscapeAscii; +#[unstable(feature = "u8_split_ascii_whitespace", issue = "147878")] +pub use ascii::SplitAsciiWhitespace; +#[unstable(feature = "str_internals", issue = "none")] +#[doc(hidden)] +pub use ascii::is_ascii_simple; +#[stable(feature = "slice_get_slice", since = "1.28.0")] +pub use index::SliceIndex; +#[unstable(feature = "slice_range", issue = "76393")] +pub use index::{range, try_range}; +#[stable(feature = "array_windows", since = "1.94.0")] +pub use iter::ArrayWindows; +#[stable(feature = "slice_group_by", since = "1.77.0")] +pub use iter::{ChunkBy, ChunkByMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Chunks, ChunksMut, Windows}; +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub use iter::{ChunksExact, ChunksExactMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Iter, IterMut}; +#[stable(feature = "rchunks", since = "1.31.0")] +pub use iter::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; +#[stable(feature = "slice_rsplit", since = "1.27.0")] +pub use iter::{RSplit, RSplitMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut}; +#[stable(feature = "split_inclusive", since = "1.51.0")] +pub use iter::{SplitInclusive, SplitInclusiveMut}; +#[stable(feature = "from_ref", since = "1.28.0")] +pub use raw::{from_mut, from_ref}; +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +pub use raw::{from_mut_ptr_range, from_ptr_range}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::{from_raw_parts, from_raw_parts_mut}; + +/// Calculates the direction and split point of a one-sided range. +/// +/// This is a helper function for `split_off` and `split_off_mut` that returns +/// the direction of the split (front or back) as well as the index at +/// which to split. Returns `None` if the split index would overflow. +#[inline] +fn split_point_of(range: impl OneSidedRange) -> Option<(Direction, usize)> { + use OneSidedRangeBound::{End, EndInclusive, StartInclusive}; + + Some(match range.bound() { + (StartInclusive, i) => (Direction::Back, i), + (End, i) => (Direction::Front, i), + (EndInclusive, i) => (Direction::Front, i.checked_add(1)?), + }) +} + +enum Direction { + Front, + Back, +} + +impl [T] { + /// Returns the number of elements in the slice. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert_eq!(a.len(), 3); + /// ``` + #[lang = "slice_len_fn"] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + pub const fn len(&self) -> usize { + ptr::metadata(self) + } + + /// Returns `true` if the slice has a length of 0. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert!(!a.is_empty()); + /// + /// let b: &[i32] = &[]; + /// assert!(b.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.39.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + pub const fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&10), v.first()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.first()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn first(&self) -> Option<&T> { + if let [first, ..] = self { Some(first) } else { None } + } + + /// Returns a mutable reference to the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(first) = x.first_mut() { + /// *first = 5; + /// } + /// assert_eq!(x, &[5, 1, 2]); + /// + /// let y: &mut [i32] = &mut []; + /// assert_eq!(None, y.first_mut()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn first_mut(&mut self) -> Option<&mut T> { + if let [first, ..] = self { Some(first) } else { None } + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first() { + /// assert_eq!(first, &0); + /// assert_eq!(elements, &[1, 2]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn split_first(&self) -> Option<(&T, &[T])> { + if let [first, tail @ ..] = self { Some((first, tail)) } else { None } + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_mut() { + /// *first = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[3, 4, 5]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if let [first, tail @ ..] = self { Some((first, tail)) } else { None } + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last() { + /// assert_eq!(last, &2); + /// assert_eq!(elements, &[0, 1]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn split_last(&self) -> Option<(&T, &[T])> { + if let [init @ .., last] = self { Some((last, init)) } else { None } + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last_mut() { + /// *last = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[4, 5, 3]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if let [init @ .., last] = self { Some((last, init)) } else { None } + } + + /// Returns the last element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&30), v.last()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.last()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn last(&self) -> Option<&T> { + if let [.., last] = self { Some(last) } else { None } + } + + /// Returns a mutable reference to the last item in the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(last) = x.last_mut() { + /// *last = 10; + /// } + /// assert_eq!(x, &[0, 1, 10]); + /// + /// let y: &mut [i32] = &mut []; + /// assert_eq!(None, y.last_mut()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn last_mut(&mut self) -> Option<&mut T> { + if let [.., last] = self { Some(last) } else { None } + } + + /// Returns an array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let u = [10, 40, 30]; + /// assert_eq!(Some(&[10, 40]), u.first_chunk::<2>()); + /// + /// let v: &[i32] = &[10]; + /// assert_eq!(None, v.first_chunk::<2>()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(Some(&[]), w.first_chunk::<0>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn first_chunk(&self) -> Option<&[T; N]> { + if self.len() < N { + None + } else { + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the reference outlive the slice. + Some(unsafe { &*(self.as_ptr().cast_array()) }) + } + } + + /// Returns a mutable array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(first) = x.first_chunk_mut::<2>() { + /// first[0] = 5; + /// first[1] = 4; + /// } + /// assert_eq!(x, &[5, 4, 2]); + /// + /// assert_eq!(None, x.first_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn first_chunk_mut(&mut self) -> Option<&mut [T; N]> { + if self.len() < N { + None + } else { + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and require exclusive access to the entire slice to mutate the chunk. + Some(unsafe { &mut *(self.as_mut_ptr().cast_array()) }) + } + } + + /// Returns an array reference to the first `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_chunk::<2>() { + /// assert_eq!(first, &[0, 1]); + /// assert_eq!(elements, &[2]); + /// } + /// + /// assert_eq!(None, x.split_first_chunk::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_first_chunk(&self) -> Option<(&[T; N], &[T])> { + let Some((first, tail)) = self.split_at_checked(N) else { return None }; + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some((unsafe { &*(first.as_ptr().cast_array()) }, tail)) + } + + /// Returns a mutable array reference to the first `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_chunk_mut::<2>() { + /// first[0] = 3; + /// first[1] = 4; + /// elements[0] = 5; + /// } + /// assert_eq!(x, &[3, 4, 5]); + /// + /// assert_eq!(None, x.split_first_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_first_chunk_mut( + &mut self, + ) -> Option<(&mut [T; N], &mut [T])> { + let Some((first, tail)) = self.split_at_mut_checked(N) else { return None }; + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and enforce exclusive mutability of the chunk by the split. + Some((unsafe { &mut *(first.as_mut_ptr().cast_array()) }, tail)) + } + + /// Returns an array reference to the last `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((elements, last)) = x.split_last_chunk::<2>() { + /// assert_eq!(elements, &[0]); + /// assert_eq!(last, &[1, 2]); + /// } + /// + /// assert_eq!(None, x.split_last_chunk::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_last_chunk(&self) -> Option<(&[T], &[T; N])> { + let Some(index) = self.len().checked_sub(N) else { return None }; + let (init, last) = self.split_at(index); + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some((init, unsafe { &*(last.as_ptr().cast_array()) })) + } + + /// Returns a mutable array reference to the last `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((elements, last)) = x.split_last_chunk_mut::<2>() { + /// last[0] = 3; + /// last[1] = 4; + /// elements[0] = 5; + /// } + /// assert_eq!(x, &[5, 3, 4]); + /// + /// assert_eq!(None, x.split_last_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_last_chunk_mut( + &mut self, + ) -> Option<(&mut [T], &mut [T; N])> { + let Some(index) = self.len().checked_sub(N) else { return None }; + let (init, last) = self.split_at_mut(index); + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and enforce exclusive mutability of the chunk by the split. + Some((init, unsafe { &mut *(last.as_mut_ptr().cast_array()) })) + } + + /// Returns an array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let u = [10, 40, 30]; + /// assert_eq!(Some(&[40, 30]), u.last_chunk::<2>()); + /// + /// let v: &[i32] = &[10]; + /// assert_eq!(None, v.last_chunk::<2>()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(Some(&[]), w.last_chunk::<0>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_last_chunk", since = "1.80.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn last_chunk(&self) -> Option<&[T; N]> { + // FIXME(const-hack): Without const traits, we need this instead of `get`. + let Some(index) = self.len().checked_sub(N) else { return None }; + let (_, last) = self.split_at(index); + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some(unsafe { &*(last.as_ptr().cast_array()) }) + } + + /// Returns a mutable array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(last) = x.last_chunk_mut::<2>() { + /// last[0] = 10; + /// last[1] = 20; + /// } + /// assert_eq!(x, &[0, 10, 20]); + /// + /// assert_eq!(None, x.last_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn last_chunk_mut(&mut self) -> Option<&mut [T; N]> { + // FIXME(const-hack): Without const traits, we need this instead of `get`. + let Some(index) = self.len().checked_sub(N) else { return None }; + let (_, last) = self.split_at_mut(index); + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and require exclusive access to the entire slice to mutate the chunk. + Some(unsafe { &mut *(last.as_mut_ptr().cast_array()) }) + } + + /// Returns a reference to an element or subslice depending on the type of + /// index. + /// + /// - If given a position, returns a reference to the element at that + /// position or `None` if out of bounds. + /// - If given a range, returns the subslice corresponding to that range, + /// or `None` if out of bounds. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&40), v.get(1)); + /// assert_eq!(Some(&[10, 40][..]), v.get(0..2)); + /// assert_eq!(None, v.get(3)); + /// assert_eq!(None, v.get(0..4)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get(&self, index: I) -> Option<&I::Output> + where + I: [const] SliceIndex, + { + index.get(self) + } + + /// Returns a mutable reference to an element or subslice depending on the + /// type of index (see [`get`]) or `None` if the index is out of bounds. + /// + /// [`get`]: slice::get + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(elem) = x.get_mut(1) { + /// *elem = 42; + /// } + /// assert_eq!(x, &[0, 42, 2]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[rustc_no_writable] + pub const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where + I: [const] SliceIndex, + { + index.get_mut(self) + } + + /// Returns a reference to an element or subslice, without doing bounds + /// checking. + /// + /// For a safe alternative see [`get`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. + /// + /// You can think of this like `.get(index).unwrap_unchecked()`. It's UB + /// to call `.get_unchecked(len)`, even if you immediately convert to a + /// pointer. And it's UB to call `.get_unchecked(..len + 1)`, + /// `.get_unchecked(..=len)`, or similar. + /// + /// [`get`]: slice::get + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// + /// unsafe { + /// assert_eq!(x.get_unchecked(1), &2); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[track_caller] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, index)))] + pub const unsafe fn get_unchecked(&self, index: I) -> &I::Output + where + I: [const] SliceIndex, + { + // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`; + // the slice is dereferenceable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &*index.get_unchecked(self) } + } + + /// Returns a mutable reference to an element or subslice, without doing + /// bounds checking. + /// + /// For a safe alternative see [`get_mut`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. + /// + /// You can think of this like `.get_mut(index).unwrap_unchecked()`. It's + /// UB to call `.get_unchecked_mut(len)`, even if you immediately convert + /// to a pointer. And it's UB to call `.get_unchecked_mut(..len + 1)`, + /// `.get_unchecked_mut(..=len)`, or similar. + /// + /// [`get_mut`]: slice::get_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// + /// unsafe { + /// let elem = x.get_unchecked_mut(1); + /// *elem = 13; + /// } + /// assert_eq!(x, &[1, 13, 4]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[track_caller] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, index)))] + #[rustc_no_writable] + pub const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + where + I: [const] SliceIndex, + { + // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`; + // the slice is dereferenceable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &mut *index.get_unchecked_mut(self) } + } + + /// Returns a raw pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up dangling. + /// + /// The caller must also ensure that the memory the pointer (non-transitively) points to + /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer + /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`]. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let x_ptr = x.as_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// assert_eq!(x.get_unchecked(i), &*x_ptr.add(i)); + /// } + /// } + /// ``` + /// + /// [`as_mut_ptr`]: slice::as_mut_ptr + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] + #[rustc_never_returns_null_ptr] + #[rustc_as_ptr] + #[inline(always)] + #[must_use] + pub const fn as_ptr(&self) -> *const T { + self as *const [T] as *const T + } + + /// Returns an unsafe mutable pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up dangling. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// let x_ptr = x.as_mut_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// *x_ptr.add(i) += 2; + /// } + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[rustc_never_returns_null_ptr] + #[rustc_as_ptr] + #[inline(always)] + #[must_use] + #[rustc_no_writable] + pub const fn as_mut_ptr(&mut self) -> *mut T { + self as *mut [T] as *mut T + } + + /// Returns the two raw pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the slice. + /// + /// See [`as_ptr`] for warnings on using these pointers. The end pointer + /// requires extra caution, as it does not point to a valid element in the + /// slice. + /// + /// This function is useful for interacting with foreign interfaces which + /// use two pointers to refer to a range of elements in memory, as is + /// common in C++. + /// + /// It can also be useful to check if a pointer to an element refers to an + /// element of this slice: + /// + /// ``` + /// let a = [1, 2, 3]; + /// let x = &a[1] as *const _; + /// let y = &5 as *const _; + /// + /// assert!(a.as_ptr_range().contains(&x)); + /// assert!(!a.as_ptr_range().contains(&y)); + /// ``` + /// + /// [`as_ptr`]: slice::as_ptr + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[inline] + #[must_use] + pub const fn as_ptr_range(&self) -> Range<*const T> { + let start = self.as_ptr(); + // SAFETY: The `add` here is safe, because: + // + // - Both pointers are part of the same object, as pointing directly + // past the object also counts. + // + // - The size of the slice is never larger than `isize::MAX` bytes, as + // noted here: + // - https://github.com/rust-lang/unsafe-code-guidelines/issues/102#issuecomment-473340447 + // - https://doc.rust-lang.org/reference/behavior-considered-undefined.html + // - https://doc.rust-lang.org/core/slice/fn.from_raw_parts.html#safety + // (This doesn't seem normative yet, but the very same assumption is + // made in many places, including the Index implementation of slices.) + // + // - There is no wrapping around involved, as slices do not wrap past + // the end of the address space. + // + // See the documentation of [`pointer::add`]. + let end = unsafe { start.add(self.len()) }; + start..end + } + + /// Returns the two unsafe mutable pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the slice. + /// + /// See [`as_mut_ptr`] for warnings on using these pointers. The end + /// pointer requires extra caution, as it does not point to a valid element + /// in the slice. + /// + /// This function is useful for interacting with foreign interfaces which + /// use two pointers to refer to a range of elements in memory, as is + /// common in C++. + /// + /// [`as_mut_ptr`]: slice::as_mut_ptr + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[inline] + #[must_use] + pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> { + let start = self.as_mut_ptr(); + // SAFETY: See as_ptr_range() above for why `add` here is safe. + let end = unsafe { start.add(self.len()) }; + start..end + } + + /// Gets a reference to the underlying array. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] + #[inline] + #[must_use] + pub const fn as_array(&self) -> Option<&[T; N]> { + if self.len() == N { + let ptr = self.as_ptr().cast_array(); + + // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. + let me = unsafe { &*ptr }; + Some(me) + } else { + None + } + } + + /// Gets a mutable reference to the slice's underlying array. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] + #[inline] + #[must_use] + pub const fn as_mut_array(&mut self) -> Option<&mut [T; N]> { + if self.len() == N { + let ptr = self.as_mut_ptr().cast_array(); + + // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. + let me = unsafe { &mut *ptr }; + Some(me) + } else { + None + } + } + + /// Swaps two elements in the slice. + /// + /// If `a` equals `b`, it's guaranteed that elements won't change value. + /// + /// # Arguments + /// + /// * a - The index of the first element + /// * b - The index of the second element + /// + /// # Panics + /// + /// Panics if `a` or `b` are out of bounds. + /// + /// # Examples + /// + /// ``` + /// let mut v = ["a", "b", "c", "d", "e"]; + /// v.swap(2, 4); + /// assert!(v == ["a", "b", "e", "d", "c"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_swap", since = "1.85.0")] + #[inline] + #[track_caller] + pub const fn swap(&mut self, a: usize, b: usize) { + // Bounds checks that panic exactly like indexing would. + let _ = &self[a]; + let _ = &self[b]; + // SAFETY: `a` and `b` were checked to be in bounds above. + unsafe { + self.swap_unchecked(a, b); + } + } + + /// Swaps two elements in the slice, without doing bounds checking. + /// + /// For a safe alternative see [`swap`]. + /// + /// # Arguments + /// + /// * a - The index of the first element + /// * b - The index of the second element + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]*. + /// The caller has to ensure that `a < self.len()` and `b < self.len()`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_swap_unchecked)] + /// + /// let mut v = ["a", "b", "c", "d"]; + /// // SAFETY: we know that 1 and 3 are both indices of the slice + /// unsafe { v.swap_unchecked(1, 3) }; + /// assert!(v == ["a", "d", "c", "b"]); + /// ``` + /// + /// [`swap`]: slice::swap + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_swap_unchecked", issue = "88539")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(a, "[0,self.len())")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(b, "[0,self.len())")))] + pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { + assert_unsafe_precondition!( + check_library_ub, + "slice::swap_unchecked requires that the indices are within the slice", + ( + len: usize = self.len(), + a: usize = a, + b: usize = b, + ) => a < len && b < len, + ); + + let ptr = self.as_mut_ptr(); + // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()` + unsafe { + ptr::swap(ptr.add(a), ptr.add(b)); + } + } + + /// Reverses the order of elements in the slice, in place. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 2, 3]; + /// v.reverse(); + /// assert!(v == [3, 2, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_reverse", since = "1.90.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub const fn reverse(&mut self) { + let half_len = self.len() / 2; + let Range { start, end } = self.as_mut_ptr_range(); + + // These slices will skip the middle item for an odd length, + // since that one doesn't need to move. + let (front_half, back_half) = + // SAFETY: Both are subparts of the original slice, so the memory + // range is valid, and they don't overlap because they're each only + // half (or less) of the original slice. + unsafe { + ( + slice::from_raw_parts_mut(start, half_len), + slice::from_raw_parts_mut(end.sub(half_len), half_len), + ) + }; + + // Introducing a function boundary here means that the two halves + // get `noalias` markers, allowing better optimization as LLVM + // knows that they're disjoint, unlike in the original slice. + revswap(front_half, back_half, half_len); + + #[inline] + const fn revswap(a: &mut [T], b: &mut [T], n: usize) { + debug_assert!(a.len() == n); + debug_assert!(b.len() == n); + + // Because this function is first compiled in isolation, + // this check tells LLVM that the indexing below is + // in-bounds. Then after inlining -- once the actual + // lengths of the slices are known -- it's removed. + // FIXME(const_trait_impl) replace with let (a, b) = (&mut a[..n], &mut b[..n]); + let (a, _) = a.split_at_mut(n); + let (b, _) = b.split_at_mut(n); + + let mut i = 0; + #[safety::loop_invariant(i <= n)] + #[cfg_attr(kani, + kani::loop_modifies( + unsafe {slice::from_raw_parts_mut(a.as_mut_ptr(), n)}, + unsafe {slice::from_raw_parts_mut(b.as_mut_ptr(), n)}, + &i) + )] + while i < n { + mem::swap(&mut a[i], &mut b[n - 1 - i]); + i += 1; + } + } + } + + /// Returns an iterator over the slice. + /// + /// The iterator yields all items from start to end. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let mut iterator = x.iter(); + /// + /// assert_eq!(iterator.next(), Some(&1)); + /// assert_eq!(iterator.next(), Some(&2)); + /// assert_eq!(iterator.next(), Some(&4)); + /// assert_eq!(iterator.next(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[rustc_diagnostic_item = "slice_iter"] + pub const fn iter(&self) -> Iter<'_, T> { + Iter::new(self) + } + + /// Returns an iterator that allows modifying each value. + /// + /// The iterator yields all items from start to end. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// for elem in x.iter_mut() { + /// *elem += 2; + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut::new(self) + } + + /// Returns an iterator over all contiguous windows of length + /// `size`. The windows overlap. If the slice is shorter than + /// `size`, the iterator returns no values. + /// + /// # Panics + /// + /// Panics if `size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.windows(3); + /// assert_eq!(iter.next().unwrap(), &['l', 'o', 'r']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e', 'm']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the slice is shorter than `size`: + /// + /// ``` + /// let slice = ['f', 'o', 'o']; + /// let mut iter = slice.windows(4); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// Because the [Iterator] trait cannot represent the required lifetimes, + /// there is no `windows_mut` analog to `windows`; + /// `[0,1,2].windows_mut(2).collect()` would violate [the rules of references] + /// (though a [LendingIterator] analog is possible). You can sometimes use + /// [`Cell::as_slice_of_cells`](crate::cell::Cell::as_slice_of_cells) in + /// conjunction with `windows` instead: + /// + /// [the rules of references]: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references + /// [LendingIterator]: https://blog.rust-lang.org/2022/10/28/gats-stabilization.html + /// ``` + /// use std::cell::Cell; + /// + /// let mut array = ['R', 'u', 's', 't', ' ', '2', '0', '1', '5']; + /// let slice = &mut array[..]; + /// let slice_of_cells: &[Cell] = Cell::from_mut(slice).as_slice_of_cells(); + /// for w in slice_of_cells.windows(3) { + /// Cell::swap(&w[0], &w[2]); + /// } + /// assert_eq!(array, ['s', 't', ' ', '2', '0', '1', '5', 'u', 'R']); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn windows(&self, size: usize) -> Windows<'_, T> { + let size = NonZero::new(size).expect("window size must be non-zero"); + Windows::new(self, size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`chunks_exact`] for a variant of this iterator that returns chunks of always exactly + /// `chunk_size` elements, and [`rchunks`] for the same iterator but starting at the end of the + /// slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['m']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`chunks_exact`]: slice::chunks_exact + /// [`rchunks`]: slice::rchunks + /// [`as_chunks`]: slice::as_chunks + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + Chunks::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`chunks_exact_mut`] for a variant of this iterator that returns chunks of always + /// exactly `chunk_size` elements, and [`rchunks_mut`] for the same iterator but starting at + /// the end of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.chunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 3]); + /// ``` + /// + /// [`chunks_exact_mut`]: slice::chunks_exact_mut + /// [`rchunks_mut`]: slice::rchunks_mut + /// [`as_chunks_mut`]: slice::as_chunks_mut + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksMut::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved + /// from the `remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks`]. + /// + /// See [`chunks`] for a variant of this iterator that also returns the remainder as a smaller + /// chunk, and [`rchunks_exact`] for the same iterator but starting at the end of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks_exact(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert!(iter.next().is_none()); + /// assert_eq!(iter.remainder(), &['m']); + /// ``` + /// + /// [`chunks`]: slice::chunks + /// [`rchunks_exact`]: slice::rchunks_exact + /// [`as_chunks`]: slice::as_chunks + #[stable(feature = "chunks_exact", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksExact::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be + /// retrieved from the `into_remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks_mut`]. + /// + /// See [`chunks_mut`] for a variant of this iterator that also returns the remainder as a + /// smaller chunk, and [`rchunks_exact_mut`] for the same iterator but starting at the end of + /// the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.chunks_exact_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 0]); + /// ``` + /// + /// [`chunks_mut`]: slice::chunks_mut + /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut + /// [`as_chunks_mut`]: slice::as_chunks_mut + #[stable(feature = "chunks_exact", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksExactMut::new(self, chunk_size) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// assuming that there's no remainder. + /// + /// This is the inverse operation to [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// As this is `unsafe`, consider whether you could use [`as_chunks`] or + /// [`as_rchunks`] instead, perhaps via something like + /// `if let (chunks, []) = slice.as_chunks()` or + /// `let (chunks, []) = slice.as_chunks() else { unreachable!() };`. + /// + /// [`as_chunks`]: slice::as_chunks + /// [`as_rchunks`]: slice::as_rchunks + /// + /// # Safety + /// + /// This may only be called when + /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). + /// - `N != 0`. + /// + /// # Examples + /// + /// ``` + /// let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!']; + /// let chunks: &[[char; 1]] = + /// // SAFETY: 1-element chunks never have remainder + /// unsafe { slice.as_chunks_unchecked() }; + /// assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]); + /// let chunks: &[[char; 3]] = + /// // SAFETY: The slice length (6) is a multiple of 3 + /// unsafe { slice.as_chunks_unchecked() }; + /// assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]); + /// + /// // These would be unsound: + /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5 + /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(N, "[1,)")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(len(self) % N == 0)))] + // Safety precondition from the documentation: `N != 0` and the length is a multiple of `N`. + #[requires(N != 0 && self.len().is_multiple_of(N))] + #[ensures(|chunks: &&[[T; N]]| chunks.len() == self.len() / N && chunks.as_ptr() as *const T == self.as_ptr())] + pub const unsafe fn as_chunks_unchecked<#[rustc_panics_when_zero] const N: usize>( + &self, + ) -> &[[T; N]] { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n), + ); + // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length + let new_len = unsafe { exact_div(self.len(), N) }; + // SAFETY: We cast a slice of `new_len * N` elements into + // a slice of `new_len` many `N` elements chunks. + unsafe { from_raw_parts(self.as_ptr().cast(), new_len) } + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the beginning of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (chunks, remainder) = slice.as_chunks()`, then: + /// - `chunks.len()` equals `slice.len() / N`, + /// - `remainder.len()` equals `slice.len() % N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let (chunks, remainder) = slice.as_chunks(); + /// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]); + /// assert_eq!(remainder, &['m']); + /// ``` + /// + /// If you expect the slice to be an exact multiple, you can combine + /// `let`-`else` with an empty slice pattern: + /// ``` + /// let slice = ['R', 'u', 's', 't']; + /// let (chunks, []) = slice.as_chunks::<2>() else { + /// panic!("slice didn't have even length") + /// }; + /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_chunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[[T; N]], &[T]) { + assert!(N != 0, "chunk size must be non-zero"); + let len_rounded_down = self.len() / N * N; + // SAFETY: The rounded-down value is always the same or smaller than the + // original length, and thus must be in-bounds of the slice. + let (multiple_of_n, remainder) = unsafe { self.split_at_unchecked(len_rounded_down) }; + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() }; + (array_slice, remainder) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the end of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (remainder, chunks) = slice.as_rchunks()`, then: + /// - `remainder.len()` equals `slice.len() % N`, + /// - `chunks.len()` equals `slice.len() / N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let (remainder, chunks) = slice.as_rchunks(); + /// assert_eq!(remainder, &['l']); + /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_rchunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[T], &[[T; N]]) { + assert!(N != 0, "chunk size must be non-zero"); + let len = self.len() / N; + let (remainder, multiple_of_n) = self.split_at(self.len() - len * N); + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() }; + (remainder, array_slice) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// assuming that there's no remainder. + /// + /// This is the inverse operation to [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// As this is `unsafe`, consider whether you could use [`as_chunks_mut`] or + /// [`as_rchunks_mut`] instead, perhaps via something like + /// `if let (chunks, []) = slice.as_chunks_mut()` or + /// `let (chunks, []) = slice.as_chunks_mut() else { unreachable!() };`. + /// + /// [`as_chunks_mut`]: slice::as_chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + /// + /// # Safety + /// + /// This may only be called when + /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). + /// - `N != 0`. + /// + /// # Examples + /// + /// ``` + /// let slice: &mut [char] = &mut ['l', 'o', 'r', 'e', 'm', '!']; + /// let chunks: &mut [[char; 1]] = + /// // SAFETY: 1-element chunks never have remainder + /// unsafe { slice.as_chunks_unchecked_mut() }; + /// chunks[0] = ['L']; + /// assert_eq!(chunks, &[['L'], ['o'], ['r'], ['e'], ['m'], ['!']]); + /// let chunks: &mut [[char; 3]] = + /// // SAFETY: The slice length (6) is a multiple of 3 + /// unsafe { slice.as_chunks_unchecked_mut() }; + /// chunks[1] = ['a', 'x', '?']; + /// assert_eq!(slice, &['L', 'o', 'r', 'a', 'x', '?']); + /// + /// // These would be unsound: + /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_mut() // The slice length is not a multiple of 5 + /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(N, "[1,)")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(len(self) % N == 0)))] + // Safety precondition from the documentation: `N != 0` and the length is a multiple of `N`. + #[requires(N != 0 && self.len().is_multiple_of(N))] + #[ensures(|chunks: &&mut [[T; N]]| chunks.len() == old(self.len()) / N)] + pub const unsafe fn as_chunks_unchecked_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> &mut [[T; N]] { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n) + ); + // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length + let new_len = unsafe { exact_div(self.len(), N) }; + // SAFETY: We cast a slice of `new_len * N` elements into + // a slice of `new_len` many `N` elements chunks. + unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), new_len) } + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the beginning of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (chunks, remainder) = slice.as_chunks_mut()`, then: + /// - `chunks.len()` equals `slice.len() / N`, + /// - `remainder.len()` equals `slice.len() % N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// let (chunks, remainder) = v.as_chunks_mut(); + /// remainder[0] = 9; + /// for chunk in chunks { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 9]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_chunks_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> (&mut [[T; N]], &mut [T]) { + assert!(N != 0, "chunk size must be non-zero"); + let len_rounded_down = self.len() / N * N; + // SAFETY: The rounded-down value is always the same or smaller than the + // original length, and thus must be in-bounds of the slice. + let (multiple_of_n, remainder) = unsafe { self.split_at_mut_unchecked(len_rounded_down) }; + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() }; + (array_slice, remainder) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the end of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (remainder, chunks) = slice.as_rchunks_mut()`, then: + /// - `remainder.len()` equals `slice.len() % N`, + /// - `chunks.len()` equals `slice.len() / N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// let (remainder, chunks) = v.as_rchunks_mut(); + /// remainder[0] = 9; + /// for chunk in chunks { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[9, 1, 1, 2, 2]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + pub const fn as_rchunks_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> (&mut [T], &mut [[T; N]]) { + assert!(N != 0, "chunk size must be non-zero"); + let len = self.len() / N; + let (remainder, multiple_of_n) = self.split_at_mut(self.len() - len * N); + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() }; + (remainder, array_slice) + } + + /// Returns an iterator over overlapping windows of `N` elements of a slice, + /// starting at the beginning of the slice. + /// + /// This is the const generic equivalent of [`windows`]. + /// + /// If `N` is greater than the size of the slice, it will return no windows. + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = [0, 1, 2, 3]; + /// let mut iter = slice.array_windows(); + /// assert_eq!(iter.next().unwrap(), &[0, 1]); + /// assert_eq!(iter.next().unwrap(), &[1, 2]); + /// assert_eq!(iter.next().unwrap(), &[2, 3]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`windows`]: slice::windows + #[stable(feature = "array_windows", since = "1.94.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn array_windows<#[rustc_panics_when_zero] const N: usize>( + &self, + ) -> ArrayWindows<'_, T, N> { + assert!(N != 0, "window size must be non-zero"); + ArrayWindows::new(self) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`rchunks_exact`] for a variant of this iterator that returns chunks of always exactly + /// `chunk_size` elements, and [`chunks`] for the same iterator but starting at the beginning + /// of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.rchunks(2); + /// assert_eq!(iter.next().unwrap(), &['e', 'm']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r']); + /// assert_eq!(iter.next().unwrap(), &['l']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`rchunks_exact`]: slice::rchunks_exact + /// [`chunks`]: slice::chunks + /// [`as_rchunks`]: slice::as_rchunks + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunks::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`rchunks_exact_mut`] for a variant of this iterator that returns chunks of always + /// exactly `chunk_size` elements, and [`chunks_mut`] for the same iterator but starting at the + /// beginning of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.rchunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[3, 2, 2, 1, 1]); + /// ``` + /// + /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut + /// [`chunks_mut`]: slice::chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksMut::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// end of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved + /// from the `remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`rchunks`]. + /// + /// See [`rchunks`] for a variant of this iterator that also returns the remainder as a smaller + /// chunk, and [`chunks_exact`] for the same iterator but starting at the beginning of the + /// slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.rchunks_exact(2); + /// assert_eq!(iter.next().unwrap(), &['e', 'm']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r']); + /// assert!(iter.next().is_none()); + /// assert_eq!(iter.remainder(), &['l']); + /// ``` + /// + /// [`chunks`]: slice::chunks + /// [`rchunks`]: slice::rchunks + /// [`chunks_exact`]: slice::chunks_exact + /// [`as_rchunks`]: slice::as_rchunks + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksExact::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be + /// retrieved from the `into_remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks_mut`]. + /// + /// See [`rchunks_mut`] for a variant of this iterator that also returns the remainder as a + /// smaller chunk, and [`chunks_exact_mut`] for the same iterator but starting at the beginning + /// of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.rchunks_exact_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[0, 2, 2, 1, 1]); + /// ``` + /// + /// [`chunks_mut`]: slice::chunks_mut + /// [`rchunks_mut`]: slice::rchunks_mut + /// [`chunks_exact_mut`]: slice::chunks_exact_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksExactMut::new(self, chunk_size) + } + + /// Returns an iterator over the slice producing non-overlapping runs + /// of elements using the predicate to separate them. + /// + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. + /// + /// # Examples + /// + /// ``` + /// let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; + /// + /// let mut iter = slice.chunk_by(|a, b| a == b); + /// + /// assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + /// assert_eq!(iter.next(), Some(&[3, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// This method can be used to extract the sorted subslices: + /// + /// ``` + /// let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4]; + /// + /// let mut iter = slice.chunk_by(|a, b| a <= b); + /// + /// assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 3, 4][..])); + /// assert_eq!(iter.next(), None); + /// ``` + #[stable(feature = "slice_group_by", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + pub const fn chunk_by(&self, pred: F) -> ChunkBy<'_, T, F> + where + F: FnMut(&T, &T) -> bool, + { + ChunkBy::new(self, pred) + } + + /// Returns an iterator over the slice producing non-overlapping mutable + /// runs of elements using the predicate to separate them. + /// + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. + /// + /// # Examples + /// + /// ``` + /// let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; + /// + /// let mut iter = slice.chunk_by_mut(|a, b| a == b); + /// + /// assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); + /// assert_eq!(iter.next(), Some(&mut [3, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// This method can be used to extract the sorted subslices: + /// + /// ``` + /// let slice = &mut [1, 1, 2, 3, 2, 3, 2, 3, 4]; + /// + /// let mut iter = slice.chunk_by_mut(|a, b| a <= b); + /// + /// assert_eq!(iter.next(), Some(&mut [1, 1, 2, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 3, 4][..])); + /// assert_eq!(iter.next(), None); + /// ``` + #[stable(feature = "slice_group_by", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + pub const fn chunk_by_mut(&mut self, pred: F) -> ChunkByMut<'_, T, F> + where + F: FnMut(&T, &T) -> bool, + { + ChunkByMut::new(self, pred) + } + + /// Divides one slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. For a non-panicking alternative see + /// [`split_at_checked`](slice::split_at_checked). + /// + /// # Examples + /// + /// ``` + /// let v = ['a', 'b', 'c']; + /// + /// { + /// let (left, right) = v.split_at(0); + /// assert_eq!(left, []); + /// assert_eq!(right, ['a', 'b', 'c']); + /// } + /// + /// { + /// let (left, right) = v.split_at(2); + /// assert_eq!(left, ['a', 'b']); + /// assert_eq!(right, ['c']); + /// } + /// + /// { + /// let (left, right) = v.split_at(3); + /// assert_eq!(left, ['a', 'b', 'c']); + /// assert_eq!(right, []); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "1.71.0")] + #[inline] + #[track_caller] + #[must_use] + pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) { + match self.split_at_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), + } + } + + /// Divides one mutable slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. For a non-panicking alternative see + /// [`split_at_mut_checked`](slice::split_at_mut_checked). + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// let (left, right) = v.split_at_mut(2); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[track_caller] + #[must_use] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + match self.split_at_mut_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), + } + } + + /// Divides one slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at`]: slice::split_at + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let v = ['a', 'b', 'c']; + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(0); + /// assert_eq!(left, []); + /// assert_eq!(right, ['a', 'b', 'c']); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(2); + /// assert_eq!(left, ['a', 'b']); + /// assert_eq!(right, ['c']); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(3); + /// assert_eq!(left, ['a', 'b', 'c']); + /// assert_eq!(right, []); + /// } + /// ``` + #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_split_at_unchecked", since = "1.77.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(mid, [0,self.len()])))] + pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + // FIXME(const-hack): the const function `from_raw_parts` is used to make this + // function const; previously the implementation used + // `(self.get_unchecked(..mid), self.get_unchecked(mid..))` + + let len = self.len(); + let ptr = self.as_ptr(); + + assert_unsafe_precondition!( + check_library_ub, + "slice::split_at_unchecked requires the index to be within the slice", + (mid: usize = mid, len: usize = len) => mid <= len, + ); + + // SAFETY: Caller has to check that `0 <= mid <= self.len()` + unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), unchecked_sub(len, mid))) } + } + + /// Divides one mutable slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at_mut`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at_mut`]: slice::split_at_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// // scoped to restrict the lifetime of the borrows + /// unsafe { + /// let (left, right) = v.split_at_mut_unchecked(2); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(mid, [0,self.len()])))] + pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + let len = self.len(); + let ptr = self.as_mut_ptr(); + + assert_unsafe_precondition!( + check_library_ub, + "slice::split_at_mut_unchecked requires the index to be within the slice", + (mid: usize = mid, len: usize = len) => mid <= len, + ); + + // SAFETY: Caller has to check that `0 <= mid <= self.len()`. + // + // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference + // is fine. + unsafe { + ( + from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.add(mid), unchecked_sub(len, mid)), + ) + } + } + + /// Divides one slice into two at an index, returning `None` if the slice is + /// too short. + /// + /// If `mid ≤ len`, returns a pair of slices where the first will contain all + /// indices from `[0, mid)` (excluding the index `mid` itself) and the + /// second will contain all indices from `[mid, len)` (excluding the index + /// `len` itself). + /// + /// Otherwise, if `mid > len`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = [1, -2, 3, -4, 5, -6]; + /// + /// { + /// let (left, right) = v.split_at_checked(0).unwrap(); + /// assert_eq!(left, []); + /// assert_eq!(right, [1, -2, 3, -4, 5, -6]); + /// } + /// + /// { + /// let (left, right) = v.split_at_checked(2).unwrap(); + /// assert_eq!(left, [1, -2]); + /// assert_eq!(right, [3, -4, 5, -6]); + /// } + /// + /// { + /// let (left, right) = v.split_at_checked(6).unwrap(); + /// assert_eq!(left, [1, -2, 3, -4, 5, -6]); + /// assert_eq!(right, []); + /// } + /// + /// assert_eq!(None, v.split_at_checked(7)); + /// ``` + #[stable(feature = "split_at_checked", since = "1.80.0")] + #[rustc_const_stable(feature = "split_at_checked", since = "1.80.0")] + #[inline] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])> { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. + Some(unsafe { self.split_at_unchecked(mid) }) + } else { + None + } + } + + /// Divides one mutable slice into two at an index, returning `None` if the + /// slice is too short. + /// + /// If `mid ≤ len`, returns a pair of slices where the first will contain all + /// indices from `[0, mid)` (excluding the index `mid` itself) and the + /// second will contain all indices from `[mid, len)` (excluding the index + /// `len` itself). + /// + /// Otherwise, if `mid > len`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// + /// if let Some((left, right)) = v.split_at_mut_checked(2) { + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// + /// assert_eq!(None, v.split_at_mut_checked(7)); + /// ``` + #[stable(feature = "split_at_checked", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + #[inline] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. + Some(unsafe { self.split_at_mut_unchecked(mid) }) + } else { + None + } + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the first element is matched, an empty slice will be the first item + /// returned by the iterator. Similarly, if the last element in the slice + /// is matched, an empty slice will be the last item returned by the + /// iterator: + /// + /// ``` + /// let slice = [10, 40, 33]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If two matched elements are directly adjacent, an empty slice will be + /// present between them: + /// + /// ``` + /// let slice = [10, 6, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split(&self, pred: F) -> Split<'_, T, F> + where + F: FnMut(&T) -> bool, + { + Split::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_mut(|num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_mut(&mut self, pred: F) -> SplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is contained in the end of the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the last element of the slice is matched, + /// that element will be considered the terminator of the preceding slice. + /// That slice will be the last item returned by the iterator. + /// + /// ``` + /// let slice = [3, 10, 40, 33]; + /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[3]); + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[inline] + pub fn split_inclusive(&self, pred: F) -> SplitInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitInclusive::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is contained in the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_inclusive_mut(|num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; + /// } + /// assert_eq!(v, [10, 40, 1, 20, 1, 1]); + /// ``` + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[inline] + pub fn split_inclusive_mut(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitInclusiveMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, starting at the end of the slice and working backwards. + /// The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let mut iter = slice.rsplit(|num| *num == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[44, 55]); + /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// As with `split()`, if the first or last element is matched, an empty + /// slice will be the first (or last) item returned by the iterator. + /// + /// ``` + /// let v = &[0, 1, 1, 2, 3, 5, 8]; + /// let mut it = v.rsplit(|n| *n % 2 == 0); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next().unwrap(), &[3, 5]); + /// assert_eq!(it.next().unwrap(), &[1, 1]); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next(), None); + /// ``` + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplit::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, starting at the end of the slice and working + /// backwards. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [100, 400, 300, 200, 600, 500]; + /// + /// let mut count = 0; + /// for group in v.rsplit_mut(|num| *num % 3 == 0) { + /// count += 1; + /// group[0] = count; + /// } + /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); + /// ``` + /// + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once by numbers divisible by 3 (i.e., `[10, 40]`, + /// `[20, 60, 50]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn(2, |num| *num % 3 == 0) { + /// println!("{group:?}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn(&self, n: usize, pred: F) -> SplitN<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitN::new(self.split(pred), n) + } + + /// Returns an iterator over mutable subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 50]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitNMut::new(self.split_mut(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once, starting from the end, by numbers divisible + /// by 3 (i.e., `[50]`, `[10, 40, 30, 20]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplitn(2, |num| *num % 3 == 0) { + /// println!("{group:?}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitN::new(self.rsplit(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut s = [10, 40, 30, 20, 60, 50]; + /// + /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(s, [1, 40, 30, 20, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitNMut::new(self.rsplit_mut(pred), n) + } + + /// Splits the slice on the first element that matches the specified + /// predicate. + /// + /// If any matching elements are present in the slice, returns the prefix + /// before the match and suffix after. The matching element itself is not + /// included. If no elements match, returns `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_split_once)] + /// let s = [1, 2, 3, 2, 4]; + /// assert_eq!(s.split_once(|&x| x == 2), Some(( + /// &[1][..], + /// &[3, 2, 4][..] + /// ))); + /// assert_eq!(s.split_once(|&x| x == 0), None); + /// ``` + #[unstable(feature = "slice_split_once", issue = "112811")] + #[inline] + pub fn split_once(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { + let index = self.iter().position(pred)?; + // Slice bounds checks optimized are away (as of June 2026) + Some((&self[..index], &self[index + 1..])) + } + + /// Splits the slice on the last element that matches the specified + /// predicate. + /// + /// If any matching elements are present in the slice, returns the prefix + /// before the match and suffix after. The matching element itself is not + /// included. If no elements match, returns `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_split_once)] + /// let s = [1, 2, 3, 2, 4]; + /// assert_eq!(s.rsplit_once(|&x| x == 2), Some(( + /// &[1, 2, 3][..], + /// &[4][..] + /// ))); + /// assert_eq!(s.rsplit_once(|&x| x == 0), None); + /// ``` + #[unstable(feature = "slice_split_once", issue = "112811")] + #[inline] + pub fn rsplit_once(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { + let index = self.iter().rposition(pred)?; + // Slice bounds checks optimized are away (as of June 2026) + Some((&self[..index], &self[index + 1..])) + } + + /// Returns `true` if the slice contains an element with the given value. + /// + /// This operation is *O*(*n*). + /// + /// Note that if you have a sorted slice, [`binary_search`] may be faster. + /// + /// [`binary_search`]: slice::binary_search + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.contains(&30)); + /// assert!(!v.contains(&50)); + /// ``` + /// + /// If you do not have a `&T`, but some other value that you can compare + /// with one (for example, `String` implements `PartialEq`), you can + /// use `iter().any`: + /// + /// ``` + /// let v = [String::from("hello"), String::from("world")]; // slice of `String` + /// assert!(v.iter().any(|e| e == "hello")); // search with `&str` + /// assert!(!v.iter().any(|e| e == "hi")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[must_use] + pub fn contains(&self, x: &T) -> bool + where + T: PartialEq, + { + cmp::SliceContains::slice_contains(x, self) + } + + /// Returns `true` if `needle` is a prefix of the slice or equal to the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.starts_with(&[10])); + /// assert!(v.starts_with(&[10, 40])); + /// assert!(v.starts_with(&v)); + /// assert!(!v.starts_with(&[50])); + /// assert!(!v.starts_with(&[10, 50])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.starts_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.starts_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + pub fn starts_with(&self, needle: &[T]) -> bool + where + T: PartialEq, + { + let n = needle.len(); + self.len() >= n && needle == &self[..n] + } + + /// Returns `true` if `needle` is a suffix of the slice or equal to the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.ends_with(&[30])); + /// assert!(v.ends_with(&[40, 30])); + /// assert!(v.ends_with(&v)); + /// assert!(!v.ends_with(&[50])); + /// assert!(!v.ends_with(&[50, 30])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.ends_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.ends_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + pub fn ends_with(&self, needle: &[T]) -> bool + where + T: PartialEq, + { + let (m, n) = (self.len(), needle.len()); + m >= n && needle == &self[m - n..] + } + + /// Returns a subslice with the prefix removed. + /// + /// If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`. + /// If `prefix` is empty, simply returns the original slice. If `prefix` is equal to the + /// original slice, returns an empty slice. + /// + /// If the slice does not start with `prefix`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..])); + /// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..])); + /// assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_prefix(&[50]), None); + /// assert_eq!(v.strip_prefix(&[10, 50]), None); + /// + /// let prefix : &str = "he"; + /// assert_eq!(b"hello".strip_prefix(prefix.as_bytes()), + /// Some(b"llo".as_ref())); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "slice_strip", since = "1.51.0")] + pub fn strip_prefix + ?Sized>(&self, prefix: &P) -> Option<&[T]> + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let prefix = prefix.as_slice(); + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return Some(tail); + } + } + None + } + + /// Returns a subslice with the suffix removed. + /// + /// If the slice ends with `suffix`, returns the subslice before the suffix, wrapped in `Some`. + /// If `suffix` is empty, simply returns the original slice. If `suffix` is equal to the + /// original slice, returns an empty slice. + /// + /// If the slice does not end with `suffix`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..])); + /// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..])); + /// assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_suffix(&[50]), None); + /// assert_eq!(v.strip_suffix(&[50, 30]), None); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "slice_strip", since = "1.51.0")] + pub fn strip_suffix + ?Sized>(&self, suffix: &P) -> Option<&[T]> + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let suffix = suffix.as_slice(); + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return Some(head); + } + } + None + } + + /// Returns a subslice with the prefix and suffix removed. + /// + /// If the slice starts with `prefix`, ends with `suffix`, and + /// the prefix and suffix don't overlap, returns the subslice after + /// the prefix and before the suffix, wrapped in `Some`. + /// + /// If the slice does not start with `prefix`, does not end with `suffix`, + /// or the prefix and suffix overlap in the slice, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 50, 40, 30]; + /// assert_eq!(v.strip_circumfix(&[10], &[30]), Some(&[50, 40][..])); + /// assert_eq!(v.strip_circumfix(&[10], &[40, 30]), Some(&[50][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50], &[40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_circumfix(&[50], &[30]), None); + /// assert_eq!(v.strip_circumfix(&[10], &[40]), None); + /// assert_eq!(v.strip_circumfix(&[], &[40, 30]), Some(&[10, 50][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50], &[]), Some(&[40, 30][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50, 40], &[50, 40, 30]), None); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "strip_circumfix", since = "1.98.0")] + pub fn strip_circumfix(&self, prefix: &P, suffix: &S) -> Option<&[T]> + where + T: PartialEq, + S: SlicePattern + ?Sized, + P: SlicePattern + ?Sized, + { + self.strip_prefix(prefix)?.strip_suffix(suffix) + } + + /// Returns a subslice with the optional prefix removed. + /// + /// If the slice starts with `prefix`, returns the subslice after the prefix. If `prefix` + /// is empty or the slice does not start with `prefix`, simply returns the original slice. + /// If `prefix` is equal to the original slice, returns an empty slice. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// + /// // Prefix present - removes it + /// assert_eq!(v.trim_prefix(&[10]), &[40, 30][..]); + /// assert_eq!(v.trim_prefix(&[10, 40]), &[30][..]); + /// assert_eq!(v.trim_prefix(&[10, 40, 30]), &[][..]); + /// + /// // Prefix absent - returns original slice + /// assert_eq!(v.trim_prefix(&[50]), &[10, 40, 30][..]); + /// assert_eq!(v.trim_prefix(&[10, 50]), &[10, 40, 30][..]); + /// + /// let prefix : &str = "he"; + /// assert_eq!(b"hello".trim_prefix(prefix.as_bytes()), b"llo".as_ref()); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "trim_prefix_suffix", since = "1.100.0")] + pub fn trim_prefix + ?Sized>(&self, prefix: &P) -> &[T] + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let prefix = prefix.as_slice(); + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return tail; + } + } + self + } + + /// Returns a subslice with the optional suffix removed. + /// + /// If the slice ends with `suffix`, returns the subslice before the suffix. If `suffix` + /// is empty or the slice does not end with `suffix`, simply returns the original slice. + /// If `suffix` is equal to the original slice, returns an empty slice. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// + /// // Suffix present - removes it + /// assert_eq!(v.trim_suffix(&[30]), &[10, 40][..]); + /// assert_eq!(v.trim_suffix(&[40, 30]), &[10][..]); + /// assert_eq!(v.trim_suffix(&[10, 40, 30]), &[][..]); + /// + /// // Suffix absent - returns original slice + /// assert_eq!(v.trim_suffix(&[50]), &[10, 40, 30][..]); + /// assert_eq!(v.trim_suffix(&[50, 30]), &[10, 40, 30][..]); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "trim_prefix_suffix", since = "1.100.0")] + pub fn trim_suffix + ?Sized>(&self, suffix: &P) -> &[T] + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let suffix = suffix.as_slice(); + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return head; + } + } + self + } + + /// Binary searches this slice for a given element. + /// If the slice is not sorted, the returned result is unspecified and + /// meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`]. + /// + /// [`binary_search_by`]: slice::binary_search_by + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// assert_eq!(s.binary_search(&13), Ok(9)); + /// assert_eq!(s.binary_search(&4), Err(7)); + /// assert_eq!(s.binary_search(&100), Err(13)); + /// let r = s.binary_search(&1); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + /// + /// If you want to find that whole *range* of matching items, rather than + /// an arbitrary matching one, that can be done using [`partition_point`]: + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// let low = s.partition_point(|x| x < &1); + /// assert_eq!(low, 1); + /// let high = s.partition_point(|x| x <= &1); + /// assert_eq!(high, 5); + /// let r = s.binary_search(&1); + /// assert!((low..high).contains(&r.unwrap())); + /// + /// assert!(s[..low].iter().all(|&x| x < 1)); + /// assert!(s[low..high].iter().all(|&x| x == 1)); + /// assert!(s[high..].iter().all(|&x| x > 1)); + /// + /// // For something not found, the "range" of equal items is empty + /// assert_eq!(s.partition_point(|x| x < &11), 9); + /// assert_eq!(s.partition_point(|x| x <= &11), 9); + /// assert_eq!(s.binary_search(&11), Err(9)); + /// ``` + /// + /// If you want to insert an item to a sorted vector, while maintaining + /// sort order, consider using [`partition_point`]: + /// + /// ``` + /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let num = 42; + /// let idx = s.partition_point(|&x| x <= num); + /// // If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to + /// // `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` will allow `insert` + /// // to shift less elements. + /// s.insert(idx, num); + /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "rust1", since = "1.0.0")] + pub const fn binary_search(&self, x: &T) -> Result + where + T: [const] Ord, + { + self.binary_search_by(const |p| p.cmp(x)) + } + + /// Binary searches this slice with a comparator function. + /// + /// The comparator function should return an order code that indicates + /// whether its argument is `Less`, `Equal` or `Greater` the desired + /// target. + /// If the slice is not sorted or if the comparator function does not + /// implement an order consistent with the sort order of the underlying + /// slice, the returned result is unspecified and meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`]. + /// + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// let seek = 13; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9)); + /// let seek = 4; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7)); + /// let seek = 100; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); + /// let seek = 1; + /// let r = s.binary_search_by(|probe| probe.cmp(&seek)); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub const fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result + where + F: [const] FnMut(&'a T) -> Ordering + [const] Destruct, + { + let mut size = self.len(); + if size == 0 { + return Err(0); + } + let mut base = 0usize; + + // This loop intentionally doesn't have an early exit if the comparison + // returns Equal. We want the number of loop iterations to depend *only* + // on the size of the input slice so that the CPU can reliably predict + // the loop count. + while size > 1 { + let half = size / 2; + let mid = base + half; + + // SAFETY: the call is made safe by the following invariants: + // - `mid >= 0`: by definition + // - `mid < size`: `mid = size / 2 + size / 4 + size / 8 ...` + let cmp = f(unsafe { self.get_unchecked(mid) }); + + // Binary search interacts poorly with branch prediction, so force + // the compiler to use conditional moves if supported by the target + // architecture. + base = hint::select_unpredictable(cmp == Greater, base, mid); + + // This is imprecise in the case where `size` is odd and the + // comparison returns Greater: the mid element still gets included + // by `size` even though it's known to be larger than the element + // being searched for. + // + // This is fine though: we gain more performance by keeping the + // loop iteration count invariant (and thus predictable) than we + // lose from considering one additional element. + size -= half; + } + + // SAFETY: base is always in [0, size) because base <= mid. + let cmp = f(unsafe { self.get_unchecked(base) }); + if cmp == Equal { + // SAFETY: same as the `get_unchecked` above. + unsafe { hint::assert_unchecked(base < self.len()) }; + Ok(base) + } else { + let result = base + (cmp == Less) as usize; + // SAFETY: same as the `get_unchecked` above. + // Note that this is `<=`, unlike the assume in the `Ok` path. + unsafe { hint::assert_unchecked(result <= self.len()) }; + Err(result) + } + } + + /// Binary searches this slice with a key extraction function. + /// + /// Assumes that the slice is sorted by the key, for instance with + /// [`sort_by_key`] using the same key extraction function. + /// If the slice is not sorted by the key, the returned result is + /// unspecified and meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`]. + /// + /// [`sort_by_key`]: slice::sort_by_key + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by`]: slice::binary_search_by + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements in a slice of pairs sorted by + /// their second elements. The first is found, with a uniquely + /// determined position; the second and third are not found; the + /// fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), + /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), + /// (1, 21), (2, 34), (4, 55)]; + /// + /// assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b), Ok(9)); + /// assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b), Err(7)); + /// assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13)); + /// let r = s.binary_search_by_key(&1, |&(a, b)| b); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + // Lint rustdoc::broken_intra_doc_links is allowed as `slice::sort_by_key` is + // in crate `alloc`, and as such doesn't exists yet when building `core`: #74481. + // This breaks links when slice is displayed in core, but changing it to use relative links + // would break when the item is re-exported. So allow the core links to be broken for now. + #[allow(rustdoc::broken_intra_doc_links)] + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] + #[inline] + pub const fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result + where + F: [const] FnMut(&'a T) -> B + [const] Destruct, + B: [const] Ord + [const] Destruct, + { + self.binary_search_by(const |k| f(k).cmp(b)) + } + + /// Sorts the slice in ascending order **without** preserving the initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `T` panics. + /// + /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require + /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the + /// reflexivity requirement of [`Ord`]. By using an alternative comparison function with + /// `slice::sort_unstable_by` such as [`f32::total_cmp`] or [`f64::total_cmp`] that defines a + /// [total order] users can sort slices containing floating-point values. Alternatively, if all + /// values in the slice are guaranteed to be in a subset for which [`PartialOrd::partial_cmp`] + /// forms a [total order], it's possible to sort the slice with `sort_unstable_by(|a, b| + /// a.partial_cmp(b).unwrap())`. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if + /// the [`Ord`] implementation panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// v.sort_unstable(); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable(&mut self) + where + T: Ord, + { + sort::unstable::sort(self, &mut T::lt); + } + + /// Sorts the slice in ascending order with a comparison function, **without** preserving the + /// initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the comparison function `compare` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if `compare` panics. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the `compare` does not implement a [total order], or if + /// the `compare` itself panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4, -5, 1, -3, 2]; + /// v.sort_unstable_by(|a, b| a.cmp(b)); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// + /// // reverse sorting + /// v.sort_unstable_by(|a, b| b.cmp(a)); + /// assert_eq!(v, [4, 2, 1, -3, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by(&mut self, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + { + sort::unstable::sort(self, &mut |a, b| compare(a, b) == Ordering::Less); + } + + /// Sorts the slice in ascending order with a key extraction function, **without** preserving + /// the initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `K` panics. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4i32, -5, 1, -3, 2]; + /// + /// v.sort_unstable_by_key(|k| k.abs()); + /// assert_eq!(v, [1, 2, -3, 4, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by_key(&mut self, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, + { + sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b))); + } + + /// Partially sorts the slice in ascending order **without** preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable(0..0); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable(2..2); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable(2..3); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable(1..4); + /// assert_eq!(&v[1..4], [-3, 1, 2]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable(..); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [`sort_unstable`]: slice::sort_unstable + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable(&mut self, range: R) + where + T: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, T::lt); + } + + /// Partially sorts the slice in ascending order with a comparison function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the `compare` does not implement a total order, or if + /// the `compare` itself panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by(0..0, |a, b| b.cmp(a)); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by(2..2, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by(2..3, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by(1..4, |a, b| b.cmp(a)); + /// assert_eq!(&v[1..4], [2, 1, -3]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by(.., |a, b| b.cmp(a)); + /// assert_eq!(v, [4, 2, 1, -3, -5]); + /// ``` + /// + /// [`sort_unstable_by`]: slice::sort_unstable_by + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by(&mut self, range: R, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| compare(a, b) == Less); + } + + /// Partially sorts the slice in ascending order with a key extraction function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by_key`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `K` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4i32, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by_key(0..0, |k| k.abs()); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by_key(2..2, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by_key(2..3, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by_key(1..4, |k| k.abs()); + /// assert_eq!(&v[1..4], [2, -3, 4]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by_key(.., |k| k.abs()); + /// assert_eq!(v, [1, 2, -3, 4, -5]); + /// ``` + /// + /// [`sort_unstable_by_key`]: slice::sort_unstable_by_key + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by_key(&mut self, range: R, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| f(a).lt(&f(b))); + } + + /// Reorders the slice such that the element at `index` is at a sort-order position. All + /// elements before `index` will be `<=` to this value, and all elements after will be `>=` to + /// it. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple that partitions the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy `x <= self[index]`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy `x >= self[index]`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, and so always panics on empty slices. + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order]. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 2, -3, 1]; + /// + /// // Find the items `<=` to the median, the median itself, and the items `>=` to it. + /// let (lesser, median, greater) = v.select_nth_unstable(2); + /// + /// assert!(lesser == [-3, -5] || lesser == [-5, -3]); + /// assert_eq!(median, &mut 1); + /// assert!(greater == [4, 2] || greater == [2, 4]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [-3, -5, 1, 2, 4] || + /// v == [-5, -3, 1, 2, 4] || + /// v == [-3, -5, 1, 4, 2] || + /// v == [-5, -3, 1, 4, 2]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + where + T: Ord, + { + sort::select::partition_at_index(self, index, T::lt) + } + + /// Reorders the slice with a comparator function such that the element at `index` is at a + /// sort-order position. All elements before `index` will be `<=` to this value, and all + /// elements after will be `>=` to it, according to the comparator function. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy + /// `compare(x, self[index]).is_le()`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy + /// `compare(x, self[index]).is_ge()`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, and so always panics on empty slices. + /// + /// May panic if `compare` does not implement a [total order]. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 2, -3, 1]; + /// + /// // Find the items `>=` to the median, the median itself, and the items `<=` to it, by using + /// // a reversed comparator. + /// let (before, median, after) = v.select_nth_unstable_by(2, |a, b| b.cmp(a)); + /// + /// assert!(before == [4, 2] || before == [2, 4]); + /// assert_eq!(median, &mut 1); + /// assert!(after == [-3, -5] || after == [-5, -3]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [2, 4, 1, -5, -3] || + /// v == [2, 4, 1, -3, -5] || + /// v == [4, 2, 1, -5, -3] || + /// v == [4, 2, 1, -3, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable_by( + &mut self, + index: usize, + mut compare: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T, &T) -> Ordering, + { + sort::select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less) + } + + /// Reorders the slice with a key extraction function such that the element at `index` is at a + /// sort-order position. All elements before `index` will have keys `<=` to the key at `index`, + /// and all elements after will have keys `>=` to it. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy `f(x) <= f(self[index])`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy `f(x) >= f(self[index])`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// May panic if `K: Ord` does not implement a total order. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Find the items `<=` to the absolute median, the absolute median itself, and the items + /// // `>=` to it. + /// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs()); + /// + /// assert!(lesser == [1, 2] || lesser == [2, 1]); + /// assert_eq!(median, &mut -3); + /// assert!(greater == [4, -5] || greater == [-5, 4]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [1, 2, -3, 4, -5] || + /// v == [1, 2, -3, -5, 4] || + /// v == [2, 1, -3, 4, -5] || + /// v == [2, 1, -3, -5, 4]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable_by_key( + &mut self, + index: usize, + mut f: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T) -> K, + K: Ord, + { + sort::select::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b))) + } + + /// Moves all consecutive repeated elements to the end of the slice according to the + /// [`PartialEq`] trait implementation. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = [1, 2, 2, 3, 3, 2, 1, 1]; + /// + /// let (dedup, duplicates) = slice.partition_dedup(); + /// + /// assert_eq!(dedup, [1, 2, 3, 2, 1]); + /// assert_eq!(duplicates, [2, 3, 1]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + pub fn partition_dedup(&mut self) -> (&mut [T], &mut [T]) + where + T: PartialEq, + { + self.partition_dedup_by(|a, b| a == b) + } + + /// Moves all but the first of consecutive elements to the end of the slice that are + /// "equal" according to the given predicate function. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// The predicate `same_bucket(x, p)` is passed references to two elements from + /// the slice and must determine if the elements compare equal. The element `p` occurs + /// *before* `x` in the slice (`[.., p, .., x, ..]`), so `same_bucket(x, p)` + /// is receiving them in reversed order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. For more + /// complicated predicates however, the order (ascending vs. descending) can matter. + /// + /// Both references passed to `same_bucket` are mutable. + /// This allows merged elements in the first slice by mutating `p` and returning `true`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"]; + /// + /// let (dedup, duplicates) = slice.partition_dedup_by(|x, p| x.eq_ignore_ascii_case(p)); + /// + /// assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]); + /// assert_eq!(duplicates, ["bar", "Foo", "BAZ"]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub fn partition_dedup_by(&mut self, mut same_bucket: F) -> (&mut [T], &mut [T]) + where + F: FnMut(&mut T, &mut T) -> bool, + { + // Although we have a mutable reference to `self`, we cannot make + // *arbitrary* changes. The `same_bucket` calls could panic, so we + // must ensure that the slice is in a valid state at all times. + // + // The way that we handle this is by using swaps; we iterate + // over all the elements, swapping as we go so that at the end + // the elements we wish to keep are in the front, and those we + // wish to reject are at the back. We can then split the slice. + // This operation is still `O(n)`. + // + // Example: We start in this state, where `r` represents "next + // read" and `w` represents "next_write". + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, so + // we swap self[r] and self[w] (no effect as r==w) and then increment both + // r and w, leaving us with: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this value is a duplicate, + // so we increment `r` but leave everything else unchanged: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, + // so swap self[r] and self[w] and advance r and w: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 1 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Not a duplicate, repeat: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 3 | 1 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Duplicate, advance r. End of slice. Split at w. + + let len = self.len(); + if len <= 1 { + return (self, &mut []); + } + + let ptr = self.as_mut_ptr(); + let mut next_read: usize = 1; + let mut next_write: usize = 1; + + // SAFETY: the `while` condition guarantees `next_read` and `next_write` + // are less than `len`, thus are inside `self`. `prev_ptr_write` points to + // one element before `ptr_write`, but `next_write` starts at 1, so + // `prev_ptr_write` is never less than 0 and is inside the slice. + // This fulfills the requirements for dereferencing `ptr_read`, `prev_ptr_write` + // and `ptr_write`, and for using `ptr.add(next_read)`, `ptr.add(next_write - 1)` + // and `prev_ptr_write.offset(1)`. + // + // `next_write` is also incremented at most once per loop at most meaning + // no element is skipped when it may need to be swapped. + // + // `ptr_read` and `prev_ptr_write` never point to the same element. This + // is required for `&mut *ptr_read`, `&mut *prev_ptr_write` to be safe. + // The explanation is simply that `next_read >= next_write` is always true, + // thus `next_read > next_write - 1` is too. + unsafe { + // Avoid bounds checks by using raw pointers. + while next_read < len { + let ptr_read = ptr.add(next_read); + let prev_ptr_write = ptr.add(next_write - 1); + if !same_bucket(&mut *ptr_read, &mut *prev_ptr_write) { + if next_read != next_write { + let ptr_write = prev_ptr_write.add(1); + mem::swap(&mut *ptr_read, &mut *ptr_write); + } + next_write += 1; + } + next_read += 1; + } + } + + self.split_at_mut(next_write) + } + + /// Moves all but the first of consecutive elements to the end of the slice that resolve + /// to the same key. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = [10, 20, 21, 30, 30, 20, 11, 13]; + /// + /// let (dedup, duplicates) = slice.partition_dedup_by_key(|i| *i / 10); + /// + /// assert_eq!(dedup, [10, 20, 30, 20, 11]); + /// assert_eq!(duplicates, [21, 30, 13]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + pub fn partition_dedup_by_key(&mut self, mut key: F) -> (&mut [T], &mut [T]) + where + F: FnMut(&mut T) -> K, + K: PartialEq, + { + self.partition_dedup_by(|a, b| key(a) == key(b)) + } + + /// Rotates the slice in-place such that the first `mid` elements of the + /// slice move to the end while the last `self.len() - mid` elements move to + /// the front. + /// + /// After calling `rotate_left`, the element previously at index `mid` will + /// become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `mid` is greater than the length of the + /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_left(2); + /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']); + /// ``` + /// + /// Rotating a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_left(1); + /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn rotate_left(&mut self, mid: usize) { + assert!(mid <= self.len()); + let k = self.len() - mid; + let p = self.as_mut_ptr(); + + // SAFETY: The range `[p.add(mid) - mid, p.add(mid) + k)` is trivially + // valid for reading and writing, as required by `ptr_rotate`. + unsafe { + rotate::ptr_rotate(mid, p.add(mid), k); + } + } + + /// Rotates the slice in-place such that the first `self.len() - k` + /// elements of the slice move to the end while the last `k` elements move + /// to the front. + /// + /// After calling `rotate_right`, the element previously at index + /// `self.len() - k` will become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `k` is greater than the length of the + /// slice. Note that `k == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_right(2); + /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']); + /// ``` + /// + /// Rotating a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_right(1); + /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn rotate_right(&mut self, k: usize) { + assert!(k <= self.len()); + let mid = self.len() - k; + let p = self.as_mut_ptr(); + + // SAFETY: The range `[p.add(mid) - mid, p.add(mid) + k)` is trivially + // valid for reading and writing, as required by `ptr_rotate`. + unsafe { + rotate::ptr_rotate(mid, p.add(mid), k); + } + } + + /// Moves the elements of this slice `N` places to the left, returning the ones + /// that "fall off" the front, and putting `inserted` at the end. + /// + /// Equivalently, you can think of concatenating `self` and `inserted` into one + /// long sequence, then returning the left-most `N` items and the rest into `self`: + /// + /// ```text + /// self (before) inserted + /// vvvvvvvvvvvvvvv vvv + /// [1, 2, 3, 4, 5] [9] + /// ↙ ↙ ↙ ↙ ↙ ↙ + /// [1] [2, 3, 4, 5, 9] + /// ^^^ ^^^^^^^^^^^^^^^ + /// returned self (after) + /// ``` + /// + /// See also [`Self::shift_right`] and compare [`Self::rotate_left`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_shift)] + /// + /// // Same as the diagram above + /// let mut a = [1, 2, 3, 4, 5]; + /// let inserted = [9]; + /// let returned = a.shift_left(inserted); + /// assert_eq!(returned, [1]); + /// assert_eq!(a, [2, 3, 4, 5, 9]); + /// + /// // You can shift multiple items at a time + /// let mut a = *b"Hello world"; + /// assert_eq!(a.shift_left(*b" peace"), *b"Hello "); + /// assert_eq!(a, *b"world peace"); + /// + /// // The name comes from this operation's similarity to bitshifts + /// let mut a: u8 = 0b10010110; + /// a <<= 3; + /// assert_eq!(a, 0b10110000_u8); + /// let mut a: [_; 8] = [1, 0, 0, 1, 0, 1, 1, 0]; + /// a.shift_left([0; 3]); + /// assert_eq!(a, [1, 0, 1, 1, 0, 0, 0, 0]); + /// + /// // Remember you can sub-slice to affect less that the whole slice. + /// // For example, this is similar to `.remove(1)` + `.insert(4, 'Z')` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// assert_eq!(a[1..=4].shift_left(['Z']), ['b']); + /// assert_eq!(a, ['a', 'c', 'd', 'e', 'Z', 'f']); + /// + /// // If the size matches it's equivalent to `mem::replace` + /// let mut a = [1, 2, 3]; + /// assert_eq!(a.shift_left([7, 8, 9]), [1, 2, 3]); + /// assert_eq!(a, [7, 8, 9]); + /// + /// // Some of the "inserted" elements end up returned if the slice is too short + /// let mut a = []; + /// assert_eq!(a.shift_left([1, 2, 3]), [1, 2, 3]); + /// let mut a = [9]; + /// assert_eq!(a.shift_left([1, 2, 3]), [9, 1, 2]); + /// assert_eq!(a, [3]); + /// ``` + #[unstable(feature = "slice_shift", issue = "151772")] + pub const fn shift_left(&mut self, inserted: [T; N]) -> [T; N] { + if let Some(shift) = self.len().checked_sub(N) { + // SAFETY: Having just checked that the inserted/returned arrays are + // shorter than (or the same length as) the slice: + // 1. The read for the items to return is in-bounds + // 2. We can `memmove` the slice over to cover the items we're returning + // to ensure those aren't double-dropped + // 3. Then we write (in-bounds for the same reason as the read) the + // inserted items atop the items of the slice that we just duplicated + // + // And none of this can panic, so there's no risk of intermediate unwinds. + unsafe { + let ptr = self.as_mut_ptr(); + let returned = ptr.cast_array::().read(); + ptr.copy_from(ptr.add(N), shift); + ptr.add(shift).cast_array::().write(inserted); + returned + } + } else { + // SAFETY: Having checked that the slice is strictly shorter than the + // inserted/returned arrays, it means we'll be copying the whole slice + // into the returned array, but that's not enough on its own. We also + // need to copy some of the inserted array into the returned array, + // with the rest going into the slice. Because `&mut` is exclusive + // and we own both `inserted` and `returned`, they're all disjoint + // allocations from each other as we can use `nonoverlapping` copies. + // + // We avoid double-frees by `ManuallyDrop`ing the inserted items, + // since we always copy them to other locations that will drop them + // instead. Plus nothing in here can panic -- it's just memcpy three + // times -- so there's no intermediate unwinds to worry about. + unsafe { + let len = self.len(); + let slice = self.as_mut_ptr(); + let inserted = mem::ManuallyDrop::new(inserted); + let inserted = (&raw const inserted).cast::(); + + let mut returned = MaybeUninit::<[T; N]>::uninit(); + let ptr = returned.as_mut_ptr().cast::(); + ptr.copy_from_nonoverlapping(slice, len); + ptr.add(len).copy_from_nonoverlapping(inserted, N - len); + slice.copy_from_nonoverlapping(inserted.add(N - len), len); + returned.assume_init() + } + } + } + + /// Moves the elements of this slice `N` places to the right, returning the ones + /// that "fall off" the back, and putting `inserted` at the beginning. + /// + /// Equivalently, you can think of concatenating `inserted` and `self` into one + /// long sequence, then returning the right-most `N` items and the rest into `self`: + /// + /// ```text + /// inserted self (before) + /// vvv vvvvvvvvvvvvvvv + /// [0] [5, 6, 7, 8, 9] + /// ↘ ↘ ↘ ↘ ↘ ↘ + /// [0, 5, 6, 7, 8] [9] + /// ^^^^^^^^^^^^^^^ ^^^ + /// self (after) returned + /// ``` + /// + /// See also [`Self::shift_left`] and compare [`Self::rotate_right`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_shift)] + /// + /// // Same as the diagram above + /// let mut a = [5, 6, 7, 8, 9]; + /// let inserted = [0]; + /// let returned = a.shift_right(inserted); + /// assert_eq!(returned, [9]); + /// assert_eq!(a, [0, 5, 6, 7, 8]); + /// + /// // The name comes from this operation's similarity to bitshifts + /// let mut a: u8 = 0b10010110; + /// a >>= 3; + /// assert_eq!(a, 0b00010010_u8); + /// let mut a: [_; 8] = [1, 0, 0, 1, 0, 1, 1, 0]; + /// a.shift_right([0; 3]); + /// assert_eq!(a, [0, 0, 0, 1, 0, 0, 1, 0]); + /// + /// // Remember you can sub-slice to affect less that the whole slice. + /// // For example, this is similar to `.remove(4)` + `.insert(1, 'Z')` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// assert_eq!(a[1..=4].shift_right(['Z']), ['e']); + /// assert_eq!(a, ['a', 'Z', 'b', 'c', 'd', 'f']); + /// + /// // If the size matches it's equivalent to `mem::replace` + /// let mut a = [1, 2, 3]; + /// assert_eq!(a.shift_right([7, 8, 9]), [1, 2, 3]); + /// assert_eq!(a, [7, 8, 9]); + /// + /// // Some of the "inserted" elements end up returned if the slice is too short + /// let mut a = []; + /// assert_eq!(a.shift_right([1, 2, 3]), [1, 2, 3]); + /// let mut a = [9]; + /// assert_eq!(a.shift_right([1, 2, 3]), [2, 3, 9]); + /// assert_eq!(a, [1]); + /// ``` + #[unstable(feature = "slice_shift", issue = "151772")] + pub const fn shift_right(&mut self, inserted: [T; N]) -> [T; N] { + if let Some(shift) = self.len().checked_sub(N) { + // SAFETY: Having just checked that the inserted/returned arrays are + // shorter than (or the same length as) the slice: + // 1. The read for the items to return is in-bounds + // 2. We can `memmove` the slice over to cover the items we're returning + // to ensure those aren't double-dropped + // 3. Then we write (in-bounds for the same reason as the read) the + // inserted items atop the items of the slice that we just duplicated + // + // And none of this can panic, so there's no risk of intermediate unwinds. + unsafe { + let ptr = self.as_mut_ptr(); + let returned = ptr.add(shift).cast_array::().read(); + ptr.add(N).copy_from(ptr, shift); + ptr.cast_array::().write(inserted); + returned + } + } else { + // SAFETY: Having checked that the slice is strictly shorter than the + // inserted/returned arrays, it means we'll be copying the whole slice + // into the returned array, but that's not enough on its own. We also + // need to copy some of the inserted array into the returned array, + // with the rest going into the slice. Because `&mut` is exclusive + // and we own both `inserted` and `returned`, they're all disjoint + // allocations from each other as we can use `nonoverlapping` copies. + // + // We avoid double-frees by `ManuallyDrop`ing the inserted items, + // since we always copy them to other locations that will drop them + // instead. Plus nothing in here can panic -- it's just memcpy three + // times -- so there's no intermediate unwinds to worry about. + unsafe { + let len = self.len(); + let slice = self.as_mut_ptr(); + let inserted = mem::ManuallyDrop::new(inserted); + let inserted = (&raw const inserted).cast::(); + + let mut returned = MaybeUninit::<[T; N]>::uninit(); + let ptr = returned.as_mut_ptr().cast::(); + ptr.add(N - len).copy_from_nonoverlapping(slice, len); + ptr.copy_from_nonoverlapping(inserted.add(len), N - len); + slice.copy_from_nonoverlapping(inserted, len); + returned.assume_init() + } + } + } + + /// Fills `self` with elements by cloning `value`. + /// + /// # Examples + /// + /// ``` + /// let mut buf = vec![0; 10]; + /// buf.fill(1); + /// assert_eq!(buf, vec![1; 10]); + /// ``` + #[doc(alias = "memset")] + #[stable(feature = "slice_fill", since = "1.50.0")] + pub fn fill(&mut self, value: T) + where + T: Clone, + { + specialize::SpecFill::spec_fill(self, value); + } + + /// Fills `self` with elements returned by calling a closure repeatedly. + /// + /// This method uses a closure to create new values. If you'd rather + /// [`Clone`] a given value, use [`fill`]. If you want to use the [`Default`] + /// trait to generate values, you can pass [`Default::default`] as the + /// argument. + /// + /// [`fill`]: slice::fill + /// + /// # Examples + /// + /// ``` + /// let mut buf = vec![1; 10]; + /// buf.fill_with(Default::default); + /// assert_eq!(buf, vec![0; 10]); + /// ``` + #[stable(feature = "slice_fill_with", since = "1.51.0")] + pub fn fill_with(&mut self, mut f: F) + where + F: FnMut() -> T, + { + for el in self { + *el = f(); + } + } + + /// Copies the elements from `src` into `self`. + /// + /// The length of `src` must be the same as `self`. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Cloning two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. + /// dst.clone_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `clone_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].clone_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.clone_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`copy_from_slice`]: slice::copy_from_slice + /// [`split_at_mut`]: slice::split_at_mut + #[stable(feature = "clone_from_slice", since = "1.7.0")] + #[track_caller] + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + pub const fn clone_from_slice(&mut self, src: &[T]) + where + T: [const] Clone + [const] Destruct, + { + self.spec_clone_from(src); + } + + /// Copies all elements from `src` into `self`, using a memcpy. + /// + /// The length of `src` must be the same as `self`. + /// + /// If `T` does not implement `Copy`, use [`clone_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Copying two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. + /// dst.copy_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `copy_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].copy_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.copy_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`clone_from_slice`]: slice::clone_from_slice + /// [`split_at_mut`]: slice::split_at_mut + #[doc(alias = "memcpy")] + #[inline] + #[stable(feature = "copy_from_slice", since = "1.9.0")] + #[rustc_const_stable(feature = "const_copy_from_slice", since = "1.87.0")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub const fn copy_from_slice(&mut self, src: &[T]) + where + T: Copy, + { + // SAFETY: `T` implements `Copy`. + unsafe { copy_from_slice_impl(self, src) } + } + + /// Copies elements from one part of the slice to another part of itself, + /// using a memmove. + /// + /// `src` is the range within `self` to copy from. `dest` is the starting + /// index of the range within `self` to copy to, which will have the same + /// length as `src`. The two ranges may overlap. The ends of the two ranges + /// must be less than or equal to `self.len()`. + /// + /// # Panics + /// + /// This function will panic if either range exceeds the end of the slice, + /// or if the end of `src` is before the start. + /// + /// # Examples + /// + /// Copying four bytes within a slice: + /// + /// ``` + /// let mut bytes = *b"Hello, World!"; + /// + /// bytes.copy_within(1..5, 8); + /// + /// assert_eq!(&bytes, b"Hello, Wello!"); + /// ``` + #[inline] + #[stable(feature = "copy_within", since = "1.37.0")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub fn copy_within>(&mut self, src: R, dest: usize) + where + T: Copy, + { + let Range { start: src_start, end: src_end } = slice::range(src, ..self.len()); + let count = src_end - src_start; + assert!(dest <= self.len() - count, "dest is out of bounds"); + // SAFETY: the conditions for `ptr::copy` have all been checked above, + // as have those for `ptr::add`. + unsafe { + // Derive both `src_ptr` and `dest_ptr` from the same loan + let ptr = self.as_mut_ptr(); + let src_ptr = ptr.add(src_start); + let dest_ptr = ptr.add(dest); + ptr::copy(src_ptr, dest_ptr, count); + } + } + + /// Swaps all elements in `self` with those in `other`. + /// + /// The length of `other` must be the same as `self`. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Example + /// + /// Swapping two elements across slices: + /// + /// ``` + /// let mut slice1 = [0, 0]; + /// let mut slice2 = [1, 2, 3, 4]; + /// + /// slice1.swap_with_slice(&mut slice2[2..]); + /// + /// assert_eq!(slice1, [3, 4]); + /// assert_eq!(slice2, [1, 2, 0, 0]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference to a + /// particular piece of data in a particular scope. Because of this, + /// attempting to use `swap_with_slice` on a single slice will result in + /// a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// mutable sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.swap_with_slice(&mut right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 1, 2]); + /// ``` + /// + /// [`split_at_mut`]: slice::split_at_mut + #[stable(feature = "swap_with_slice", since = "1.27.0")] + #[rustc_const_unstable(feature = "const_swap_with_slice", issue = "142204")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub const fn swap_with_slice(&mut self, other: &mut [T]) { + assert!(self.len() == other.len(), "destination and source slices have different lengths"); + // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was + // checked to have the same length. The slices cannot overlap because + // mutable references are exclusive. + unsafe { + ptr::swap_nonoverlapping(self.as_mut_ptr(), other.as_mut_ptr(), self.len()); + } + } + + /// Function to calculate lengths of the middle and trailing slice for `align_to{,_mut}`. + fn align_to_offsets(&self) -> (usize, usize) { + // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a + // lowest number of `T`s. And how many `T`s we need for each such "multiple". + // + // Consider for example T=u8 U=u16. Then we can put 1 U in 2 Ts. Simple. Now, consider + // for example a case where size_of:: = 16, size_of:: = 24. We can put 2 Us in + // place of every 3 Ts in the `rest` slice. A bit more complicated. + // + // Formula to calculate this is: + // + // Us = lcm(size_of::, size_of::) / size_of:: + // Ts = lcm(size_of::, size_of::) / size_of:: + // + // Expanded and simplified: + // + // Us = size_of:: / gcd(size_of::, size_of::) + // Ts = size_of:: / gcd(size_of::, size_of::) + // + // Luckily since all this is constant-evaluated... performance here matters not! + const fn gcd(a: usize, b: usize) -> usize { + if b == 0 { a } else { gcd(b, a % b) } + } + + // Explicitly wrap the function call in a const block so it gets + // constant-evaluated even in debug mode. + let gcd: usize = const { gcd(size_of::(), size_of::()) }; + let ts: usize = size_of::() / gcd; + let us: usize = size_of::() / gcd; + + // Armed with this knowledge, we can find how many `U`s we can fit! + let us_len = self.len() / ts * us; + // And how many `T`s will be in the trailing slice! + let ts_len = self.len() % ts; + (us_len, ts_len) + } + + /// Transmutes the slice to a slice of another type, ensuring alignment of the types is + /// maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle part will be as big as possible under + /// the given alignment constraint and element size. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Safety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// unsafe { + /// let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[stable(feature = "slice_align_to", since = "1.30.0")] + #[must_use] + //Checks if the part that will be transmuted from type T to U is valid for type U + //reuses most function logic up to use of from_raw_parts, + //where the potentially unsafe transmute occurs + #[requires( + U::IS_ZST || T::IS_ZST || { + let ptr = self.as_ptr(); + let offset = crate::ptr::align_offset(ptr, align_of::()); + offset > self.len() || { + let (_, rest) = self.split_at(offset); + let (us_len, _) = rest.align_to_offsets::(); + let middle = crate::ptr::slice_from_raw_parts(rest.as_ptr() as *const U, us_len); + crate::ub_checks::can_dereference(middle) + } + } + )] + //The following clause guarantees that middle is of maximum size within self + //If U or T are ZSTs, then middle has size zero, so we adapt the check in that case + #[ensures(|(prefix, _, suffix): &(&[T], &[U], &[T])| + ((U::IS_ZST || T::IS_ZST) && prefix.len() == self.len()) || ( + (prefix.len() * size_of::() < align_of::()) && + (suffix.len() * size_of::() < size_of::()) + ) + )] + //Either align_to just returns self in the prefix, or the 3 returned slices + //should be sequential, contiguous, and have same total length as self + #[ensures(|(prefix, middle, suffix): &(&[T], &[U], &[T])| + prefix.as_ptr() == self.as_ptr() && + (prefix.len() == self.len() || ( + ((prefix.as_ptr()).add(prefix.len()) as *const u8 == middle.as_ptr() as *const u8) && + ((middle.as_ptr()).add(middle.len()) as *const u8 == suffix.as_ptr() as *const u8) && + ((suffix.as_ptr()).add(suffix.len()) == (self.as_ptr()).add(self.len())) ) + ) + )] + #[cfg_attr(rapx, rapx::requires(ValidTransmute(T, U)))] + #[cfg_attr(rapx, rapx::verify)] + pub unsafe fn align_to(&self) -> (&[T], &[U], &[T]) { + // Note that most of this function will be constant-evaluated, + if U::IS_ZST || T::IS_ZST { + // handle ZSTs specially, which is – don't handle them at all. + return (self, &[], &[]); + } + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. + let ptr = self.as_ptr(); + // SAFETY: See the `align_to_mut` method for the detailed safety comment. + let offset = unsafe { crate::ptr::align_offset(ptr, align_of::()) }; + if offset > self.len() { + (self, &[], &[]) + } else { + let (left, rest) = self.split_at(offset); + let (us_len, ts_len) = rest.align_to_offsets::(); + // Inform Miri that we want to consider the "middle" pointer to be suitably aligned. + #[cfg(miri)] + crate::intrinsics::miri_promise_symbolic_alignment( + rest.as_ptr().cast(), + align_of::(), + ); + // SAFETY: now `rest` is definitely aligned, so `from_raw_parts` below is okay, + // since the caller guarantees that we can transmute `T` to `U` safely. + unsafe { + ( + left, + from_raw_parts(rest.as_ptr() as *const U, us_len), + from_raw_parts(rest.as_ptr().add(rest.len() - ts_len), ts_len), + ) + } + } + } + + /// Transmutes the mutable slice to a mutable slice of another type, ensuring alignment of the + /// types is maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle part will be as big as possible under + /// the given alignment constraint and element size. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Safety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// unsafe { + /// let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to_mut::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[stable(feature = "slice_align_to", since = "1.30.0")] + #[must_use] + //Checks if the part that will be transmuted from type T to U is valid for type U + //reuses most function logic up to use of from_raw_parts, + //where the potentially unsafe transmute occurs + #[requires( + U::IS_ZST || T::IS_ZST || { + let ptr = self.as_ptr(); + let offset = crate::ptr::align_offset(ptr, align_of::()); + offset > self.len() || { + let (_, rest) = self.split_at(offset); + let (us_len, _) = rest.align_to_offsets::(); + let middle = crate::ptr::slice_from_raw_parts(rest.as_ptr() as *const U, us_len); + crate::ub_checks::can_dereference(middle) + } + } + )] + //The following clause guarantees that middle is of maximum size within self + //If U or T are ZSTs, then middle has size zero, so we adapt the check in that case + #[ensures(|(prefix, _, suffix): &(&mut [T], &mut [U], &mut [T])| + ((U::IS_ZST || T::IS_ZST) && prefix.len() == old(self.len())) || ( + (prefix.len() * size_of::() < align_of::()) && + (suffix.len() * size_of::() < size_of::()) + ) + )] + //Either align_to just returns self in the prefix, or the 3 returned slices + //should be sequential, contiguous, and have same total length as self + #[ensures(|(prefix, middle, suffix): &(&mut [T], &mut [U], &mut [T])| + prefix.as_ptr() == old(self.as_ptr()) && + (prefix.len() == old(self.len()) || ( + ((prefix.as_ptr()).add(prefix.len()) as *const u8 == middle.as_ptr() as *const u8) && + ((middle.as_ptr()).add(middle.len()) as *const u8 == suffix.as_ptr() as *const u8) && + ((suffix.as_ptr()).add(suffix.len()) == old((self.as_ptr()).add(self.len()))) + )) + )] + #[cfg_attr(rapx, rapx::requires(ValidTransmute(T, U)))] + #[cfg_attr(rapx, rapx::verify)] + pub unsafe fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) { + // Note that most of this function will be constant-evaluated, + if U::IS_ZST || T::IS_ZST { + // handle ZSTs specially, which is – don't handle them at all. + return (self, &mut [], &mut []); + } + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. + let ptr = self.as_ptr(); + // SAFETY: Here we are ensuring we will use aligned pointers for U for the + // rest of the method. This is done by passing a pointer to &[T] with an + // alignment targeted for U. + // `crate::ptr::align_offset` is called with a correctly aligned and + // valid pointer `ptr` (it comes from a reference to `self`) and with + // a size that is a power of two (since it comes from the alignment for U), + // satisfying its safety constraints. + let offset = unsafe { crate::ptr::align_offset(ptr, align_of::()) }; + if offset > self.len() { + (self, &mut [], &mut []) + } else { + let (left, rest) = self.split_at_mut(offset); + let (us_len, ts_len) = rest.align_to_offsets::(); + let rest_len = rest.len(); + let mut_ptr = rest.as_mut_ptr(); + // Inform Miri that we want to consider the "middle" pointer to be suitably aligned. + #[cfg(miri)] + crate::intrinsics::miri_promise_symbolic_alignment( + mut_ptr.cast() as *const (), + align_of::(), + ); + // We can't use `rest` again after this, that would invalidate its alias `mut_ptr`! + // SAFETY: see comments for `align_to`. + unsafe { + ( + left, + from_raw_parts_mut(mut_ptr as *mut U, us_len), + from_raw_parts_mut(mut_ptr.add(rest_len - ts_len), ts_len), + ) + } + } + } + + /// Splits a slice into a prefix, a middle of aligned SIMD types, and a suffix. + /// + /// This is a safe wrapper around [`slice::align_to`], so inherits the same + /// guarantees as that method. + /// + /// # Panics + /// + /// This will panic if the size of the SIMD type is different from + /// `LANES` times that of the scalar. + /// + /// At the time of writing, the trait restrictions on `Simd` keeps + /// that from ever happening, as only power-of-two numbers of lanes are + /// supported. It's possible that, in the future, those restrictions might + /// be lifted in a way that would make it possible to see panics from this + /// method for something like `LANES == 3`. + /// + /// # Examples + /// + /// ``` + /// #![feature(portable_simd)] + /// use core::simd::prelude::*; + /// + /// let short = &[1, 2, 3]; + /// let (prefix, middle, suffix) = short.as_simd::<4>(); + /// assert_eq!(middle, []); // Not enough elements for anything in the middle + /// + /// // They might be split in any possible way between prefix and suffix + /// let it = prefix.iter().chain(suffix).copied(); + /// assert_eq!(it.collect::>(), vec![1, 2, 3]); + /// + /// fn basic_simd_sum(x: &[f32]) -> f32 { + /// use std::ops::Add; + /// let (prefix, middle, suffix) = x.as_simd(); + /// let sums = f32x4::from_array([ + /// prefix.iter().copied().sum(), + /// 0.0, + /// 0.0, + /// suffix.iter().copied().sum(), + /// ]); + /// let sums = middle.iter().copied().fold(sums, f32x4::add); + /// sums.reduce_sum() + /// } + /// + /// let numbers: Vec = (1..101).map(|x| x as _).collect(); + /// assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0); + /// ``` + #[unstable(feature = "portable_simd", issue = "86656")] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub fn as_simd(&self) -> (&[T], &[Simd], &[T]) + where + Simd: AsRef<[T; LANES]>, + T: simd::SimdElement, + { + // These are expected to always match, as vector types are laid out like + // arrays per , but we + // might as well double-check since it'll optimize away anyhow. + assert_eq!(size_of::>(), size_of::<[T; LANES]>()); + + // SAFETY: The simd types have the same layout as arrays, just with + // potentially-higher alignment, so the de-facto transmutes are sound. + unsafe { self.align_to() } + } + + /// Splits a mutable slice into a mutable prefix, a middle of aligned SIMD types, + /// and a mutable suffix. + /// + /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same + /// guarantees as that method. + /// + /// This is the mutable version of [`slice::as_simd`]; see that for examples. + /// + /// # Panics + /// + /// This will panic if the size of the SIMD type is different from + /// `LANES` times that of the scalar. + /// + /// At the time of writing, the trait restrictions on `Simd` keeps + /// that from ever happening, as only power-of-two numbers of lanes are + /// supported. It's possible that, in the future, those restrictions might + /// be lifted in a way that would make it possible to see panics from this + /// method for something like `LANES == 3`. + #[unstable(feature = "portable_simd", issue = "86656")] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub fn as_simd_mut(&mut self) -> (&mut [T], &mut [Simd], &mut [T]) + where + Simd: AsMut<[T; LANES]>, + T: simd::SimdElement, + { + // These are expected to always match, as vector types are laid out like + // arrays per , but we + // might as well double-check since it'll optimize away anyhow. + assert_eq!(size_of::>(), size_of::<[T; LANES]>()); + + // SAFETY: The simd types have the same layout as arrays, just with + // potentially-higher alignment, so the de-facto transmutes are sound. + unsafe { self.align_to_mut() } + } + + /// Checks if the elements of this slice are sorted. + /// + /// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the + /// slice yields exactly zero or one element, `true` is returned. + /// + /// Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition + /// implies that this function returns `false` if any two consecutive items are not + /// comparable. + /// + /// # Examples + /// + /// ``` + /// let empty: [i32; 0] = []; + /// + /// assert!([1, 2, 2, 9].is_sorted()); + /// assert!(![1, 3, 2, 4].is_sorted()); + /// assert!([0].is_sorted()); + /// assert!(empty.is_sorted()); + /// assert!(![0.0, 1.0, f32::NAN].is_sorted()); + /// ``` + #[inline] + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted(&self) -> bool + where + T: PartialOrd, + { + // This odd number works the best. 32 + 1 extra due to overlapping chunk boundaries. + const CHUNK_SIZE: usize = 33; + if self.len() < CHUNK_SIZE { + return self.windows(2).all(|w| w[0] <= w[1]); + } + let mut i = 0; + // Check in chunks for autovectorization. + while i < self.len() - CHUNK_SIZE { + let chunk = &self[i..i + CHUNK_SIZE]; + if !chunk.windows(2).fold(true, |acc, w| acc & (w[0] <= w[1])) { + return false; + } + // We need to ensure that chunk boundaries are also sorted. + // Overlap the next chunk with the last element of our last chunk. + i += CHUNK_SIZE - 1; + } + self[i..].windows(2).all(|w| w[0] <= w[1]) + } + + /// Checks if the elements of this slice are sorted using the given comparator function. + /// + /// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare` + /// function to determine whether two elements are to be considered in sorted order. + /// + /// # Examples + /// + /// ``` + /// assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b)); + /// assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b)); + /// + /// assert!([0].is_sorted_by(|a, b| true)); + /// assert!([0].is_sorted_by(|a, b| false)); + /// + /// let empty: [i32; 0] = []; + /// assert!(empty.is_sorted_by(|a, b| false)); + /// assert!(empty.is_sorted_by(|a, b| true)); + /// ``` + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted_by<'a, F>(&'a self, mut compare: F) -> bool + where + F: FnMut(&'a T, &'a T) -> bool, + { + self.array_windows().all(|[a, b]| compare(a, b)) + } + + /// Checks if the elements of this slice are sorted using the given key extraction function. + /// + /// Instead of comparing the slice's elements directly, this function compares the keys of the + /// elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see its + /// documentation for more information. + /// + /// [`is_sorted`]: slice::is_sorted + /// + /// # Examples + /// + /// ``` + /// assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); + /// assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); + /// ``` + #[inline] + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool + where + F: FnMut(&'a T) -> K, + K: PartialOrd, + { + self.iter().is_sorted_by_key(f) + } + + /// Returns the index of the partition point according to the given predicate + /// (the index of the first element of the second partition). + /// + /// The slice is assumed to be partitioned according to the given predicate. + /// This means that all elements for which the predicate returns true are at the start of the slice + /// and all elements for which the predicate returns false are at the end. + /// For example, `[7, 15, 3, 5, 4, 12, 6]` is partitioned under the predicate `x % 2 != 0` + /// (all odd numbers are at the start, all even at the end). + /// + /// If this slice is not partitioned, the returned result is unspecified and meaningless, + /// as this method performs a kind of binary search. + /// + /// See also [`binary_search`], [`binary_search_by`], and [`binary_search_by_key`]. + /// + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by`]: slice::binary_search_by + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// + /// # Examples + /// + /// ``` + /// let v = [1, 2, 3, 3, 5, 6, 7]; + /// let i = v.partition_point(|&x| x < 5); + /// + /// assert_eq!(i, 4); + /// assert!(v[..i].iter().all(|&x| x < 5)); + /// assert!(v[i..].iter().all(|&x| !(x < 5))); + /// ``` + /// + /// If all elements of the slice match the predicate, including if the slice + /// is empty, then the length of the slice will be returned: + /// + /// ``` + /// let a = [2, 4, 8]; + /// assert_eq!(a.partition_point(|x| x < &100), a.len()); + /// let a: [i32; 0] = []; + /// assert_eq!(a.partition_point(|x| x < &100), 0); + /// ``` + /// + /// If you want to insert an item to a sorted vector, while maintaining + /// sort order: + /// + /// ``` + /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let num = 42; + /// let idx = s.partition_point(|&x| x <= num); + /// s.insert(idx, num); + /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "partition_point", since = "1.52.0")] + #[must_use] + pub const fn partition_point

(&self, mut pred: P) -> usize + where + P: [const] FnMut(&T) -> bool + [const] Destruct, + { + self.binary_search_by(const |x| if pred(x) { Less } else { Greater }) + .unwrap_or_else(const |i| i) + } + + /// Removes the subslice corresponding to the given range + /// and returns a reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Splitting off the first three elements of a slice: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut first_three = slice.split_off(..3).unwrap(); + /// + /// assert_eq!(slice, &['d']); + /// assert_eq!(first_three, &['a', 'b', 'c']); + /// ``` + /// + /// Splitting off a slice starting with the third element: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut tail = slice.split_off(2..).unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(tail, &['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.split_off(5..)); + /// assert_eq!(None, slice.split_off(..5)); + /// assert_eq!(None, slice.split_off(..=4)); + /// let expected: &[char] = &['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.split_off(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[stable(feature = "slice_take", since = "1.87.0")] + pub fn split_off<'a, R: OneSidedRange>( + self: &mut &'a Self, + range: R, + ) -> Option<&'a Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = self.split_at(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the subslice corresponding to the given range + /// and returns a mutable reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Splitting off the first three elements of a slice: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut first_three = slice.split_off_mut(..3).unwrap(); + /// + /// assert_eq!(slice, &mut ['d']); + /// assert_eq!(first_three, &mut ['a', 'b', 'c']); + /// ``` + /// + /// Splitting off a slice starting with the third element: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut tail = slice.split_off_mut(2..).unwrap(); + /// + /// assert_eq!(slice, &mut ['a', 'b']); + /// assert_eq!(tail, &mut ['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.split_off_mut(5..)); + /// assert_eq!(None, slice.split_off_mut(..5)); + /// assert_eq!(None, slice.split_off_mut(..=4)); + /// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.split_off_mut(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[stable(feature = "slice_take", since = "1.87.0")] + pub fn split_off_mut<'a, R: OneSidedRange>( + self: &mut &'a mut Self, + range: R, + ) -> Option<&'a mut Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = mem::take(self).split_at_mut(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the first element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let first = slice.split_off_first().unwrap(); + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'a'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((first, rem)) = self.split_first() else { return None }; + *self = rem; + Some(first) + } + + /// Removes the first element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let first = slice.split_off_first_mut().unwrap(); + /// *first = 'd'; + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'d'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_first_mut()?` + let Some((first, rem)) = mem::replace(self, &mut []).split_first_mut() else { return None }; + *self = rem; + Some(first) + } + + /// Removes the last element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let last = slice.split_off_last().unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'c'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((last, rem)) = self.split_last() else { return None }; + *self = rem; + Some(last) + } + + /// Removes the last element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let last = slice.split_off_last_mut().unwrap(); + /// *last = 'd'; + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'d'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_last_mut()?` + let Some((last, rem)) = mem::replace(self, &mut []).split_last_mut() else { return None }; + *self = rem; + Some(last) + } + + /// Returns mutable references to many indices at once, without doing any checks. + /// + /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note + /// that this method takes an array, so all indices must be of the same type. + /// If passed an array of `usize`s this method gives back an array of mutable references + /// to single elements, while if passed an array of ranges it gives back an array of + /// mutable references to slices. + /// + /// For a safe alternative see [`get_disjoint_mut`]. + /// + /// # Safety + /// + /// Calling this method with overlapping or out-of-bounds indices is *[undefined behavior]* + /// even if the resulting references are not used. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([0, 2]); + /// *a *= 10; + /// *b *= 100; + /// } + /// assert_eq!(x, &[10, 2, 400]); + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([0..1, 1..3]); + /// a[0] = 8; + /// b[0] = 88; + /// b[1] = 888; + /// } + /// assert_eq!(x, &[8, 88, 888]); + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([1..=2, 0..=0]); + /// a[0] = 11; + /// a[1] = 111; + /// b[0] = 1; + /// } + /// assert_eq!(x, &[1, 11, 111]); + /// ``` + /// + /// [`get_disjoint_mut`]: slice::get_disjoint_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[stable(feature = "get_many_mut", since = "1.86.0")] + #[inline] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, indices)))] + #[cfg_attr(rapx, rapx::requires(NonOverlap(indices)))] + // Safety precondition from the documentation: all indices in bounds and pairwise disjoint, + // i.e. exactly what `get_disjoint_mut` checks before calling this function. + #[requires(get_disjoint_check_valid(&indices, self.len()).is_ok())] + pub unsafe fn get_disjoint_unchecked_mut( + &mut self, + indices: [I; N], + ) -> [&mut I::Output; N] + where + I: GetDisjointMutIndex + SliceIndex, + { + // NB: This implementation is written as it is because any variation of + // `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy, + // or generate worse code otherwise. This is also why we need to go + // through a raw pointer here. + let slice: *mut [T] = self; + let mut arr: MaybeUninit<[&mut I::Output; N]> = MaybeUninit::uninit(); + let arr_ptr = arr.as_mut_ptr(); + + // SAFETY: We expect `indices` to contain disjunct values that are + // in bounds of `self`. + unsafe { + for i in 0..N { + let idx = indices.get_unchecked(i).clone(); + arr_ptr.cast::<&mut I::Output>().add(i).write(&mut *slice.get_unchecked_mut(idx)); + } + arr.assume_init() + } + } + + /// Returns mutable references to many indices at once. + /// + /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note + /// that this method takes an array, so all indices must be of the same type. + /// If passed an array of `usize`s this method gives back an array of mutable references + /// to single elements, while if passed an array of ranges it gives back an array of + /// mutable references to slices. + /// + /// Returns an error if any index is out-of-bounds, or if there are overlapping indices. + /// An empty range is not considered to overlap if it is located at the beginning or at + /// the end of another range, but is considered to overlap if it is located in the middle. + /// + /// This method does a O(n^2) check to check that there are no overlapping indices, so be careful + /// when passing many indices. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [1, 2, 3]; + /// if let Ok([a, b]) = v.get_disjoint_mut([0, 2]) { + /// *a = 413; + /// *b = 612; + /// } + /// assert_eq!(v, &[413, 2, 612]); + /// + /// if let Ok([a, b]) = v.get_disjoint_mut([0..1, 1..3]) { + /// a[0] = 8; + /// b[0] = 88; + /// b[1] = 888; + /// } + /// assert_eq!(v, &[8, 88, 888]); + /// + /// if let Ok([a, b]) = v.get_disjoint_mut([1..=2, 0..=0]) { + /// a[0] = 11; + /// a[1] = 111; + /// b[0] = 1; + /// } + /// assert_eq!(v, &[1, 11, 111]); + /// ``` + #[stable(feature = "get_many_mut", since = "1.86.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub fn get_disjoint_mut( + &mut self, + indices: [I; N], + ) -> Result<[&mut I::Output; N], GetDisjointMutError> + where + I: GetDisjointMutIndex + SliceIndex, + { + get_disjoint_check_valid(&indices, self.len())?; + // SAFETY: The `get_disjoint_check_valid()` call checked that all indices + // are disjunct and in bounds. + unsafe { Ok(self.get_disjoint_unchecked_mut(indices)) } + } + + /// Returns the index that an element reference points to. + /// + /// Returns `None` if `element` does not point to the start of an element within the slice. + /// + /// This method is useful for extending slice iterators like [`slice::split`]. + /// + /// Note that this uses pointer arithmetic and **does not compare elements**. + /// To find the index of an element via comparison, use + /// [`.iter().position()`](crate::iter::Iterator::position) instead. + /// + /// # Panics + /// Panics if `T` is zero-sized. + /// + /// # Examples + /// Basic usage: + /// ``` + /// let nums: &[u32] = &[1, 7, 1, 1]; + /// let num = &nums[2]; + /// + /// assert_eq!(num, &1); + /// assert_eq!(nums.element_offset(num), Some(2)); + /// ``` + /// Returning `None` with an unaligned element: + /// ``` + /// let arr: &[[u32; 2]] = &[[0, 1], [2, 3]]; + /// let flat_arr: &[u32] = arr.as_flattened(); + /// + /// let ok_elm: &[u32; 2] = flat_arr[0..2].try_into().unwrap(); + /// let weird_elm: &[u32; 2] = flat_arr[1..3].try_into().unwrap(); + /// + /// assert_eq!(ok_elm, &[0, 1]); + /// assert_eq!(weird_elm, &[1, 2]); + /// + /// assert_eq!(arr.element_offset(ok_elm), Some(0)); // Points to element 0 + /// assert_eq!(arr.element_offset(weird_elm), None); // Points between element 0 and 1 + /// ``` + #[must_use] + #[stable(feature = "element_offset", since = "1.94.0")] + pub fn element_offset(&self, element: &T) -> Option { + if T::IS_ZST { + panic!("elements are zero-sized"); + } + + let self_start = self.as_ptr().addr(); + let elem_start = ptr::from_ref(element).addr(); + + let byte_offset = elem_start.wrapping_sub(self_start); + + if !byte_offset.is_multiple_of(size_of::()) { + return None; + } + + let offset = byte_offset / size_of::(); + + if offset < self.len() { Some(offset) } else { None } + } + + /// Returns the range of indices that a subslice points to. + /// + /// Returns `None` if `subslice` does not point within the slice or if it is not aligned with the + /// elements in the slice. + /// + /// This method **does not compare elements**. Instead, this method finds the location in the slice that + /// `subslice` was obtained from. To find the index of a subslice via comparison, instead use + /// [`.windows()`](slice::windows)[`.position()`](crate::iter::Iterator::position). + /// + /// This method is useful for extending slice iterators like [`slice::split`]. + /// + /// Note that this may return a false positive (either `Some(0..0)` or `Some(self.len()..self.len())`) + /// if `subslice` has a length of zero and points to the beginning or end of another, separate, slice. + /// + /// # Panics + /// Panics if `T` is zero-sized. + /// + /// # Examples + /// Basic usage: + /// ``` + /// use core::range::Range; + /// + /// let nums = &[0, 5, 10, 0, 0, 5]; + /// + /// let mut iter = nums + /// .split(|t| *t == 0) + /// .map(|n| nums.subslice_range(n).unwrap()); + /// + /// assert_eq!(iter.next(), Some(Range { start: 0, end: 0 })); + /// assert_eq!(iter.next(), Some(Range { start: 1, end: 3 })); + /// assert_eq!(iter.next(), Some(Range { start: 4, end: 4 })); + /// assert_eq!(iter.next(), Some(Range { start: 5, end: 6 })); + /// ``` + #[must_use] + #[stable(feature = "substr_range", since = "1.98.0")] + pub fn subslice_range(&self, subslice: &[T]) -> Option> { + if T::IS_ZST { + panic!("elements are zero-sized"); + } + + let self_start = self.as_ptr().addr(); + let subslice_start = subslice.as_ptr().addr(); + + let byte_start = subslice_start.wrapping_sub(self_start); + + if !byte_start.is_multiple_of(size_of::()) { + return None; + } + + let start = byte_start / size_of::(); + let end = start.wrapping_add(subslice.len()); + + if start <= self.len() && end <= self.len() { + Some(core::range::Range { start, end }) + } else { + None + } + } + + /// Returns the same slice `&[T]`. + /// + /// This method is redundant when used directly on `&[T]`, but + /// it helps dereferencing other "container" types to slices, + /// for example `Box<[T]>` or `Arc<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_slice(&self) -> &[T] { + self + } + + /// Returns the same slice `&mut [T]`. + /// + /// This method is redundant when used directly on `&mut [T]`, but + /// it helps dereferencing other "container" types to slices, + /// for example `Box<[T]>` or `MutexGuard<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_mut_slice(&mut self) -> &mut [T] { + self + } +} + +impl [MaybeUninit] { + /// Transmutes the mutable uninitialized slice to a mutable uninitialized slice of + /// another type, ensuring alignment of the types is maintained. + /// + /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same + /// guarantees as that method. + /// + /// # Examples + /// + /// ``` + /// #![feature(align_to_uninit_mut)] + /// use std::mem::MaybeUninit; + /// + /// pub struct BumpAllocator<'scope> { + /// memory: &'scope mut [MaybeUninit], + /// } + /// + /// impl<'scope> BumpAllocator<'scope> { + /// pub fn new(memory: &'scope mut [MaybeUninit]) -> Self { + /// Self { memory } + /// } + /// pub fn try_alloc_uninit(&mut self) -> Option<&'scope mut MaybeUninit> { + /// let first_end = self.memory.as_ptr().align_offset(align_of::()) + size_of::(); + /// let prefix = self.memory.split_off_mut(..first_end)?; + /// Some(&mut prefix.align_to_uninit_mut::().1[0]) + /// } + /// pub fn try_alloc_u32(&mut self, value: u32) -> Option<&'scope mut u32> { + /// let uninit = self.try_alloc_uninit()?; + /// Some(uninit.write(value)) + /// } + /// } + /// + /// let mut memory = [MaybeUninit::::uninit(); 10]; + /// let mut allocator = BumpAllocator::new(&mut memory); + /// let v = allocator.try_alloc_u32(42); + /// assert_eq!(v, Some(&mut 42)); + /// ``` + #[unstable(feature = "align_to_uninit_mut", issue = "139062")] + #[inline] + #[must_use] + pub fn align_to_uninit_mut(&mut self) -> (&mut Self, &mut [MaybeUninit], &mut Self) { + // SAFETY: `MaybeUninit` is transparent. Correct size and alignment are guaranteed by + // `align_to_mut` itself. Therefore the only thing that we have to ensure for a safe + // `transmute` is that the values are valid for the types involved. But for `MaybeUninit` + // any values are valid, so this operation is safe. + unsafe { self.align_to_mut() } + } +} + +impl [[T; N]] { + /// Takes a `&[[T; N]]`, and flattens it to a `&[T]`. + /// + /// For the opposite operation, see [`as_chunks`] and [`as_rchunks`]. + /// + /// [`as_chunks`]: slice::as_chunks + /// [`as_rchunks`]: slice::as_rchunks + /// + /// # Panics + /// + /// This panics if the length of the resulting slice would overflow a `usize`. + /// + /// This is only possible when flattening a slice of arrays of zero-sized + /// types, and thus tends to be irrelevant in practice. If + /// `size_of::() > 0`, this will never panic. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([[1, 2, 3], [4, 5, 6]].as_flattened(), &[1, 2, 3, 4, 5, 6]); + /// + /// assert_eq!( + /// [[1, 2, 3], [4, 5, 6]].as_flattened(), + /// [[1, 2], [3, 4], [5, 6]].as_flattened(), + /// ); + /// + /// let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []]; + /// assert!(slice_of_empty_arrays.as_flattened().is_empty()); + /// + /// let empty_slice_of_arrays: &[[u32; 10]] = &[]; + /// assert!(empty_slice_of_arrays.as_flattened().is_empty()); + /// ``` + #[stable(feature = "slice_flatten", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidTransmute([T; N], T)))] + pub const fn as_flattened(&self) -> &[T] { + let len = if T::IS_ZST { + self.len().checked_mul(N).expect("slice len overflow") + } else { + // SAFETY: `self.len() * N` cannot overflow because `self` is + // already in the address space. + unsafe { self.len().unchecked_mul(N) } + }; + // SAFETY: `[T]` is layout-identical to `[T; N]` + unsafe { from_raw_parts(self.as_ptr().cast(), len) } + } + + /// Takes a `&mut [[T; N]]`, and flattens it to a `&mut [T]`. + /// + /// For the opposite operation, see [`as_chunks_mut`] and [`as_rchunks_mut`]. + /// + /// [`as_chunks_mut`]: slice::as_chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + /// + /// # Panics + /// + /// This panics if the length of the resulting slice would overflow a `usize`. + /// + /// This is only possible when flattening a slice of arrays of zero-sized + /// types, and thus tends to be irrelevant in practice. If + /// `size_of::() > 0`, this will never panic. + /// + /// # Examples + /// + /// ``` + /// fn add_5_to_all(slice: &mut [i32]) { + /// for i in slice { + /// *i += 5; + /// } + /// } + /// + /// let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; + /// add_5_to_all(array.as_flattened_mut()); + /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]); + /// ``` + #[stable(feature = "slice_flatten", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidTransmute([T; N], T)))] + pub const fn as_flattened_mut(&mut self) -> &mut [T] { + let len = if T::IS_ZST { + self.len().checked_mul(N).expect("slice len overflow") + } else { + // SAFETY: `self.len() * N` cannot overflow because `self` is + // already in the address space. + unsafe { self.len().unchecked_mul(N) } + }; + // SAFETY: `[T]` is layout-identical to `[T; N]` + unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), len) } + } +} + +impl [f32] { + /// Sorts the slice of floats. + /// + /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses + /// the ordering defined by [`f32::total_cmp`]. + /// + /// # Current implementation + /// + /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by). + /// + /// # Examples + /// + /// ``` + /// #![feature(sort_floats)] + /// let mut v = [2.6, -5e-8, f32::NAN, 8.29, f32::INFINITY, -1.0, 0.0, -f32::INFINITY, -0.0]; + /// + /// v.sort_floats(); + /// let sorted = [-f32::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f32::INFINITY, f32::NAN]; + /// assert_eq!(&v[..8], &sorted[..8]); + /// assert!(v[8].is_nan()); + /// ``` + #[unstable(feature = "sort_floats", issue = "93396")] + #[inline] + pub fn sort_floats(&mut self) { + self.sort_unstable_by(f32::total_cmp); + } +} + +impl [f64] { + /// Sorts the slice of floats. + /// + /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses + /// the ordering defined by [`f64::total_cmp`]. + /// + /// # Current implementation + /// + /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by). + /// + /// # Examples + /// + /// ``` + /// #![feature(sort_floats)] + /// let mut v = [2.6, -5e-8, f64::NAN, 8.29, f64::INFINITY, -1.0, 0.0, -f64::INFINITY, -0.0]; + /// + /// v.sort_floats(); + /// let sorted = [-f64::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f64::INFINITY, f64::NAN]; + /// assert_eq!(&v[..8], &sorted[..8]); + /// assert!(v[8].is_nan()); + /// ``` + #[unstable(feature = "sort_floats", issue = "93396")] + #[inline] + pub fn sort_floats(&mut self) { + self.sort_unstable_by(f64::total_cmp); + } +} + +/// Copies `src` to `dest`. +/// +/// # Safety +/// `T` must implement one of `Copy` or `TrivialClone`. +#[track_caller] +#[cfg_attr(rapx, rapx::verify)] +#[cfg_attr(rapx, rapx::requires(any(Trait(T, Copy), Trait(T, TrivialClone))))] +const unsafe fn copy_from_slice_impl(dest: &mut [T], src: &[T]) { + // The panic code path was put into a cold function to not bloat the + // call site. + #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] + #[cfg_attr(panic = "immediate-abort", inline)] + #[track_caller] + const fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! { + const_panic!( + "copy_from_slice: source slice length does not match destination slice length", + "copy_from_slice: source slice length ({src_len}) does not match destination slice length ({dst_len})", + src_len: usize, + dst_len: usize, + ) + } + + if dest.len() != src.len() { + len_mismatch_fail(dest.len(), src.len()); + } + + // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was + // checked to have the same length. The slices cannot overlap because + // mutable references are exclusive. + unsafe { + ptr::copy_nonoverlapping(src.as_ptr(), dest.as_mut_ptr(), dest.len()); + } +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const trait CloneFromSpec { + fn spec_clone_from(&mut self, src: &[T]) + where + T: [const] Destruct; +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const impl CloneFromSpec for [T] +where + T: [const] Clone + [const] Destruct, +{ + #[track_caller] + default fn spec_clone_from(&mut self, src: &[T]) { + assert!(self.len() == src.len(), "destination and source slices have different lengths"); + // NOTE: We need to explicitly slice them to the same length + // to make it easier for the optimizer to elide bounds checking. + // But since it can't be relied on we also have an explicit specialization for T: Copy. + let len = self.len(); + let src = &src[..len]; + for i in 0..len { + self[i].clone_from(&src[i]); + } + } +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const impl CloneFromSpec for [T] +where + T: [const] TrivialClone + [const] Destruct, +{ + #[track_caller] + fn spec_clone_from(&mut self, src: &[T]) { + // SAFETY: `T` implements `TrivialClone`. + unsafe { + copy_from_slice_impl(self, src); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +const impl Default for &[T] { + /// Creates an empty slice. + fn default() -> Self { + &[] + } +} + +#[stable(feature = "mut_slice_default", since = "1.5.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +const impl Default for &mut [T] { + /// Creates a mutable empty slice. + fn default() -> Self { + &mut [] + } +} + +#[unstable(feature = "slice_pattern", reason = "stopgap trait for slice patterns", issue = "56345")] +/// Patterns in slices - currently, only used by `strip_prefix` and `strip_suffix`. At a future +/// point, we hope to generalise `core::str::Pattern` (which at the time of writing is limited to +/// `str`) to slices, and then this trait will be replaced or abolished. +pub trait SlicePattern { + /// The element type of the slice being matched on. + type Item; + + /// Currently, the consumers of `SlicePattern` need a slice. + fn as_slice(&self) -> &[Self::Item]; +} + +#[stable(feature = "slice_strip", since = "1.51.0")] +impl SlicePattern for [T] { + type Item = T; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } +} + +#[stable(feature = "slice_strip", since = "1.51.0")] +impl SlicePattern for [T; N] { + type Item = T; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } +} + +/// This checks every index against each other, and against `len`. +/// +/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..` +/// comparison operations. +#[inline] +#[cfg_attr(rapx, rapx::verify)] +fn get_disjoint_check_valid( + indices: &[I; N], + len: usize, +) -> Result<(), GetDisjointMutError> { + // NB: The optimizer should inline the loops into a sequence + // of instructions without additional branching. + for (i, idx) in indices.iter().enumerate() { + if !idx.is_in_bounds(len) { + return Err(GetDisjointMutError::IndexOutOfBounds); + } + for idx2 in &indices[..i] { + if idx.is_overlapping(idx2) { + return Err(GetDisjointMutError::OverlappingIndices); + } + } + } + Ok(()) +} + +/// The error type returned by [`get_disjoint_mut`][`slice::get_disjoint_mut`]. +/// +/// It indicates one of two possible errors: +/// - An index is out-of-bounds. +/// - The same index appeared multiple times in the array +/// (or different but overlapping indices when ranges are provided). +/// +/// # Examples +/// +/// ``` +/// use std::slice::GetDisjointMutError; +/// +/// let v = &mut [1, 2, 3]; +/// assert_eq!(v.get_disjoint_mut([0, 999]), Err(GetDisjointMutError::IndexOutOfBounds)); +/// assert_eq!(v.get_disjoint_mut([1, 1]), Err(GetDisjointMutError::OverlappingIndices)); +/// ``` +#[stable(feature = "get_many_mut", since = "1.86.0")] +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum GetDisjointMutError { + /// An index provided was out-of-bounds for the slice. + IndexOutOfBounds, + /// Two indices provided were overlapping. + OverlappingIndices, +} + +#[stable(feature = "get_many_mut", since = "1.86.0")] +impl fmt::Display for GetDisjointMutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let msg = match self { + GetDisjointMutError::IndexOutOfBounds => "an index is out of bounds", + GetDisjointMutError::OverlappingIndices => "there were overlapping indices", + }; + fmt::Display::fmt(msg, f) + } +} + +/// A helper trait for `<[T]>::get_disjoint_mut()`. +/// +/// # Safety +/// +/// If `is_in_bounds()` returns `true` and `is_overlapping()` returns `false`, +/// it must be safe to index the slice with the indices. +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +pub impl(self) unsafe trait GetDisjointMutIndex: Clone { + /// Returns `true` if `self` is in bounds for `len` slice elements. + #[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] + fn is_in_bounds(&self, len: usize) -> bool; + + /// Returns `true` if `self` overlaps with `other`. + /// + /// Note that we don't consider zero-length ranges to overlap at the beginning or the end, + /// but do consider them to overlap in the middle. + #[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] + fn is_overlapping(&self, other: &Self) -> bool; +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for usize { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + *self < len + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + *self == *other + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for Range { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + (self.start <= self.end) & (self.end <= len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + (self.start < other.end) & (other.start < self.end) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for RangeInclusive { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + (self.start <= self.end) & (self.end < len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + (self.start <= other.end) & (other.start <= self.end) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for range::Range { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + Range::from(*self).is_in_bounds(len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + Range::from(*self).is_overlapping(&Range::from(*other)) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for range::RangeInclusive { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + RangeInclusive::from(*self).is_in_bounds(len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + RangeInclusive::from(*self).is_overlapping(&RangeInclusive::from(*other)) + } +} + +#[cfg(kani)] +#[unstable(feature = "kani", issue = "none")] +mod verify { + use super::*; + + //generates proof_of_contract harness for align_to given the T (src) and U (dst) types + macro_rules! proof_of_contract_for_align_to { + ($harness:ident, $src:ty, $dst:ty) => { + #[kani::proof_for_contract(<[$src]>::align_to)] + fn $harness() { + const ARR_SIZE: usize = 100; + let src_arr: [$src; ARR_SIZE] = kani::any(); + let src_slice = kani::slice::any_slice_of_array(&src_arr); + let dst_slice = unsafe { src_slice.align_to::<$dst>() }; + } + }; + } + + //generates harnesses for align_to where T is a given src type and U is one of the main primitives + macro_rules! gen_align_to_harnesses { + ($mod_name:ident, $src_type:ty) => { + mod $mod_name { + use super::*; + + proof_of_contract_for_align_to!(align_to_u8, $src_type, u8); + proof_of_contract_for_align_to!(align_to_u16, $src_type, u16); + proof_of_contract_for_align_to!(align_to_u32, $src_type, u32); + proof_of_contract_for_align_to!(align_to_u64, $src_type, u64); + proof_of_contract_for_align_to!(align_to_u128, $src_type, u128); + proof_of_contract_for_align_to!(align_to_bool, $src_type, bool); + proof_of_contract_for_align_to!(align_to_char, $src_type, char); + proof_of_contract_for_align_to!(align_to_unit, $src_type, ()); + } + }; + } + + gen_align_to_harnesses!(align_to_from_u8, u8); + gen_align_to_harnesses!(align_to_from_u16, u16); + gen_align_to_harnesses!(align_to_from_u32, u32); + gen_align_to_harnesses!(align_to_from_u64, u64); + gen_align_to_harnesses!(align_to_from_u128, u128); + gen_align_to_harnesses!(align_to_from_bool, bool); + gen_align_to_harnesses!(align_to_from_char, char); + gen_align_to_harnesses!(align_to_from_unit, ()); + + //generates proof_of_contract harness for align_to_mut given the T (src) and U (dst) types + macro_rules! proof_of_contract_for_align_to_mut { + ($harness:ident, $src:ty, $dst:ty) => { + #[kani::proof_for_contract(<[$src]>::align_to_mut)] + fn $harness() { + const ARR_SIZE: usize = 100; + let mut src_arr: [$src; ARR_SIZE] = kani::any(); + let src_slice = kani::slice::any_slice_of_array_mut(&mut src_arr); + let dst_slice = unsafe { src_slice.align_to_mut::<$dst>() }; + } + }; + } + + //generates harnesses between a given src type and all the main primitives + macro_rules! gen_align_to_mut_harnesses { + ($mod_name:ident, $src_type:ty) => { + mod $mod_name { + use super::*; + + proof_of_contract_for_align_to_mut!(align_to_mut_u8, $src_type, u8); + proof_of_contract_for_align_to_mut!(align_to_mut_u16, $src_type, u16); + proof_of_contract_for_align_to_mut!(align_to_mut_u32, $src_type, u32); + proof_of_contract_for_align_to_mut!(align_to_mut_u64, $src_type, u64); + proof_of_contract_for_align_to_mut!(align_to_mut_u128, $src_type, u128); + proof_of_contract_for_align_to_mut!(align_to_mut_bool, $src_type, bool); + proof_of_contract_for_align_to_mut!(align_to_mut_char, $src_type, char); + proof_of_contract_for_align_to_mut!(align_to_mut_unit, $src_type, ()); + } + }; + } + + gen_align_to_mut_harnesses!(align_to_mut_from_u8, u8); + gen_align_to_mut_harnesses!(align_to_mut_from_u16, u16); + gen_align_to_mut_harnesses!(align_to_mut_from_u32, u32); + gen_align_to_mut_harnesses!(align_to_mut_from_u64, u64); + gen_align_to_mut_harnesses!(align_to_mut_from_u128, u128); + gen_align_to_mut_harnesses!(align_to_mut_from_bool, bool); + gen_align_to_mut_harnesses!(align_to_mut_from_char, char); + gen_align_to_mut_harnesses!(align_to_mut_from_unit, ()); + + #[kani::proof] + fn check_reverse() { + let mut a: [u8; 100] = kani::any(); + a.reverse(); + } + + // Const-generic functions. The VeriFast proof in verifast-proofs/core/slice verifies these + // through runtime-`n` transcriptions (VeriFast cannot yet attach specifications to + // `` functions); the harnesses below run the exact shipped bodies, bounded in slice + // length and monomorphized over a few element types and chunk sizes. + + const CG_ARR_SIZE: usize = 12; + + macro_rules! proof_of_contract_for_as_chunks_unchecked { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof_for_contract(<[$t]>::as_chunks_unchecked)] + fn $harness() { + let arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let chunks = unsafe { s.as_chunks_unchecked::<$n>() }; + assert_eq!(chunks.len(), s.len() / $n); + } + }; + } + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u8_1, u8, 1); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u8_3, u8, 3); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u32_2, u32, 2); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_unit_4, (), 4); + + macro_rules! proof_of_contract_for_as_chunks_unchecked_mut { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof_for_contract(<[$t]>::as_chunks_unchecked_mut)] + fn $harness() { + let mut arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let chunks = unsafe { s.as_chunks_unchecked_mut::<$n>() }; + assert_eq!(chunks.len(), len / $n); + } + }; + } + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u8_1, u8, 1); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u8_3, u8, 3); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u32_2, u32, 2); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_unit_4, (), 4); + + #[kani::proof_for_contract(<[u8]>::get_disjoint_unchecked_mut)] + fn check_get_disjoint_unchecked_mut_usize() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let indices: [usize; 3] = kani::any(); + let [a, b, c] = unsafe { s.get_disjoint_unchecked_mut(indices) }; + *a = 1; + *b = 2; + *c = 3; + } + + #[kani::proof_for_contract(<[u32]>::get_disjoint_unchecked_mut)] + fn check_get_disjoint_unchecked_mut_range() { + let mut arr: [u32; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let indices: [Range; 2] = [kani::any()..kani::any(), kani::any()..kani::any()]; + let [a, b] = unsafe { s.get_disjoint_unchecked_mut(indices) }; + if let Some(x) = a.first_mut() { + *x = 1; + } + if let Some(y) = b.first_mut() { + *y = 2; + } + } + + macro_rules! check_chunk_accessors { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof] + fn $harness() { + let mut arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let len = s.len(); + match s.first_chunk::<$n>() { + Some(c) => assert!(len >= $n && c.as_ptr() == s.as_ptr()), + None => assert!(len < $n), + } + match s.last_chunk::<$n>() { + Some(c) => { + assert!(len >= $n && c.as_ptr() == unsafe { s.as_ptr().add(len - $n) }) + } + None => assert!(len < $n), + } + match s.split_first_chunk::<$n>() { + Some((c, rest)) => assert!(c.len() + rest.len() == len), + None => assert!(len < $n), + } + match s.split_last_chunk::<$n>() { + Some((rest, c)) => assert!(rest.len() + c.len() == len), + None => assert!(len < $n), + } + let (chunks, rem) = s.as_chunks::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + let (rem, chunks) = s.as_rchunks::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + match s.first_chunk_mut::<$n>() { + Some(c) => assert!(len >= $n && c.len() == $n), + None => assert!(len < $n), + } + match s.last_chunk_mut::<$n>() { + Some(c) => assert!(len >= $n && c.len() == $n), + None => assert!(len < $n), + } + match s.split_first_chunk_mut::<$n>() { + Some((c, rest)) => assert!(c.len() + rest.len() == len), + None => assert!(len < $n), + } + match s.split_last_chunk_mut::<$n>() { + Some((rest, c)) => assert!(rest.len() + c.len() == len), + None => assert!(len < $n), + } + let (chunks, rem) = s.as_chunks_mut::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + } + }; + } + check_chunk_accessors!(check_chunk_accessors_u8_1, u8, 1); + check_chunk_accessors!(check_chunk_accessors_u8_3, u8, 3); + check_chunk_accessors!(check_chunk_accessors_u32_2, u32, 2); + check_chunk_accessors!(check_chunk_accessors_unit_5, (), 5); + + macro_rules! check_as_flattened { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof] + fn $harness() { + let mut arr: [[$t; $n]; 4] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let flat = s.as_flattened(); + assert!(flat.len() == s.len() * $n); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let flat = s.as_flattened_mut(); + assert!(flat.len() == len * $n); + } + }; + } + check_as_flattened!(check_as_flattened_u8_3, u8, 3); + check_as_flattened!(check_as_flattened_u32_2, u32, 2); + check_as_flattened!(check_as_flattened_u8_0, u8, 0); + + #[kani::proof] + fn check_as_simd_u8_4() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let (prefix, middle, suffix) = s.as_simd::<4>(); + assert!(prefix.len() + middle.len() * 4 + suffix.len() == s.len()); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let (prefix, middle, suffix) = s.as_simd_mut::<4>(); + assert!(prefix.len() + middle.len() * 4 + suffix.len() == len); + } + + #[kani::proof] + fn check_get_disjoint_mut_usize() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let indices: [usize; 3] = kani::any(); + let valid = get_disjoint_check_valid(&indices, len).is_ok(); + match s.get_disjoint_mut(indices) { + Ok([a, b, c]) => { + assert!(valid); + *a = 1; + *b = 2; + *c = 3; + } + Err(_) => assert!(!valid), + } + } + + #[kani::proof] + fn check_get_disjoint_mut_range() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let indices: [Range; 2] = [kani::any()..kani::any(), kani::any()..kani::any()]; + let valid = get_disjoint_check_valid(&indices, len).is_ok(); + match s.get_disjoint_mut(indices) { + Ok([a, b]) => { + assert!(valid); + assert!(a.len() + b.len() <= len); + } + Err(_) => assert!(!valid), + } + } + + #[kani::proof] + fn check_get_disjoint_check_valid() { + let len: usize = kani::any(); + kani::assume(len <= CG_ARR_SIZE); + let indices: [usize; 3] = kani::any(); + let r = get_disjoint_check_valid(&indices, len); + let in_bounds = indices.iter().all(|i| *i < len); + let disjoint = + indices[0] != indices[1] && indices[0] != indices[2] && indices[1] != indices[2]; + assert!(r.is_ok() == (in_bounds && disjoint)); + } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/original/slice/ascii.rs b/verifast-proofs/core/slice/mod.rs-negative/original/slice/ascii.rs new file mode 100644 index 0000000000000..bf427f448fe55 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/original/slice/ascii.rs @@ -0,0 +1,4 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{EscapeAscii, SplitAsciiWhitespace, is_ascii_simple}; diff --git a/verifast-proofs/core/slice/mod.rs-negative/original/slice/cmp.rs b/verifast-proofs/core/slice/mod.rs-negative/original/slice/cmp.rs new file mode 100644 index 0000000000000..76f6305d79eb4 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/original/slice/cmp.rs @@ -0,0 +1,7 @@ + +pub trait SliceContains { + fn slice_contains(&self, x: &[T]) -> bool; +} +impl SliceContains for T { + fn slice_contains(&self, _x: &[T]) -> bool { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/original/slice/index.rs b/verifast-proofs/core/slice/mod.rs-negative/original/slice/index.rs new file mode 100644 index 0000000000000..9fc403d41a778 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/original/slice/index.rs @@ -0,0 +1,4 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{SliceIndex, range, try_range}; diff --git a/verifast-proofs/core/slice/mod.rs-negative/original/slice/iter.rs b/verifast-proofs/core/slice/mod.rs-negative/original/slice/iter.rs new file mode 100644 index 0000000000000..107231ba4b021 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/original/slice/iter.rs @@ -0,0 +1,10 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{ + ArrayWindows, ChunkBy, ChunkByMut, Chunks, ChunksMut, Windows, + ChunksExact, ChunksExactMut, Iter, IterMut, + RChunks, RChunksExact, RChunksExactMut, RChunksMut, + RSplit, RSplitMut, RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut, + SplitInclusive, SplitInclusiveMut, +}; diff --git a/verifast-proofs/core/slice/mod.rs-negative/original/slice/memchr.rs b/verifast-proofs/core/slice/mod.rs-negative/original/slice/memchr.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/verifast-proofs/core/slice/mod.rs-negative/original/slice/raw.rs b/verifast-proofs/core/slice/mod.rs-negative/original/slice/raw.rs new file mode 100644 index 0000000000000..154c5356d99ee --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/original/slice/raw.rs @@ -0,0 +1,364 @@ +//! Free functions to create `&[T]` and `&mut [T]`. + +use crate::ops::Range; +use crate::{array, ptr, ub_checks}; + +/// Forms a slice from a pointer and a length. +/// +/// The `len` argument is the number of **elements**, not the number of bytes. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be non-null, [valid] for reads for `len * size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. See [below](#incorrect-usage) +/// for an example incorrectly not taking this into account. +/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total size `len * size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// use std::slice; +/// +/// // manifest a slice for a single element +/// let x = 42; +/// let ptr = &x as *const _; +/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; +/// assert_eq!(slice[0], 42); +/// ``` +/// +/// ### Incorrect usage +/// +/// The following `join_slices` function is **unsound** ⚠️ +/// +/// ```rust,no_run +/// use std::slice; +/// +/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { +/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); +/// let snd_start = snd.as_ptr(); +/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); +/// unsafe { +/// // The assertion above ensures `fst` and `snd` are contiguous, but they might +/// // still be contained within _different allocations_, in which case +/// // creating this slice is undefined behavior. +/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) +/// } +/// } +/// +/// fn main() { +/// // `a` and `b` are different allocations... +/// let a = 42; +/// let b = 27; +/// // ... which may nevertheless be laid out contiguously in memory: | a | b | +/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB +/// } +/// ``` +/// +/// ### FFI: Handling null pointers +/// +/// In languages such as C++, pointers to empty collections are not guaranteed to be non-null. +/// When accepting such pointers, they have to be checked for null-ness to avoid undefined +/// behavior. +/// +/// ``` +/// use std::slice; +/// +/// /// Sum the elements of an FFI slice. +/// /// +/// /// # Safety +/// /// +/// /// If ptr is not NULL, it must be correctly aligned and +/// /// point to `len` initialized items of type `f32`. +/// unsafe extern "C" fn sum_slice(ptr: *const f32, len: usize) -> f32 { +/// let data = if ptr.is_null() { +/// // `len` is assumed to be 0. +/// &[] +/// } else { +/// // SAFETY: see function docstring. +/// unsafe { slice::from_raw_parts(ptr, len) } +/// }; +/// data.into_iter().sum() +/// } +/// +/// // This could be the result of C++'s std::vector::data(): +/// let ptr = std::ptr::null(); +/// // And this could be std::vector::size(): +/// let len = 0; +/// assert_eq!(unsafe { sum_slice(ptr, len) }, 0.0); +/// ``` +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] +#[must_use] +#[rustc_diagnostic_item = "slice_from_raw_parts"] +#[track_caller] +#[cfg_attr(rapx, rapx::requires(NonNull(data)))] +#[cfg_attr(rapx, rapx::requires(ValidPtr(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Init(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Alive(data, 'a)))] +#[cfg_attr(rapx, rapx::requires(Alias(data)))] +#[cfg_attr(rapx, rapx::requires(Align(data, T)))] +#[cfg_attr(rapx, rapx::requires(ValidNum(size_of(T) * len <= isize::MAX)))] +pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`", + ( + data: *mut () = data as *mut (), + size: usize = size_of::(), + align: usize = align_of::(), + len: usize = len, + ) => + ub_checks::maybe_is_aligned_and_not_null(data, align, false) + && ub_checks::is_valid_allocation_size(size, len) + ); + &*ptr::slice_from_raw_parts(data, len) + } +} + +/// Performs the same functionality as [`from_raw_parts`], except that a +/// mutable slice is returned. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be non-null, [valid] for both reads and writes for `len * size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total size `len * size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")] +#[must_use] +#[rustc_diagnostic_item = "slice_from_raw_parts_mut"] +#[track_caller] +#[cfg_attr(rapx, rapx::requires(NonNull(data)))] +#[cfg_attr(rapx, rapx::requires(ValidPtr(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Init(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Alive(data, 'a)))] +#[cfg_attr(rapx, rapx::requires(Alias(data)))] +#[cfg_attr(rapx, rapx::requires(Align(data, T)))] +#[cfg_attr(rapx, rapx::requires(ValidNum(size_of(T) * len <= isize::MAX)))] +pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`", + ( + data: *mut () = data as *mut (), + size: usize = size_of::(), + align: usize = align_of::(), + len: usize = len, + ) => + ub_checks::maybe_is_aligned_and_not_null(data, align, false) + && ub_checks::is_valid_allocation_size(size, len) + ); + &mut *ptr::slice_from_raw_parts_mut(data, len) + } +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +#[rustc_const_stable(feature = "const_slice_from_ref_shared", since = "1.63.0")] +#[rustc_diagnostic_item = "slice_from_ref"] +#[must_use] +pub const fn from_ref(s: &T) -> &[T] { + array::from_ref(s) +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +#[rustc_const_stable(feature = "const_slice_from_ref", since = "1.83.0")] +#[must_use] +pub const fn from_mut(s: &mut T) -> &mut [T] { + array::from_mut(s) +} + +/// Forms a slice from a pointer range. +/// +/// This function is useful for interacting with foreign interfaces which +/// use two pointers to refer to a range of elements in memory, as is +/// common in C++. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * The `start` pointer of the range must be a non-null, [valid] and properly aligned pointer +/// to the first element of a slice. +/// +/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* +/// the last element, such that the offset from the end to the start pointer is +/// the length of the slice. +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// +/// * The range must contain `N` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `start` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements. +/// +/// # Panics +/// +/// This function panics if `T` is a Zero-Sized Type (“ZST”). +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_from_ptr_range)] +/// +/// use core::slice; +/// +/// let x = [1, 2, 3]; +/// let range = x.as_ptr_range(); +/// +/// unsafe { +/// assert_eq!(slice::from_ptr_range(range), &x); +/// } +/// ``` +/// +/// [valid]: ptr#safety +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +#[rustc_const_unstable(feature = "const_slice_from_ptr_range", issue = "89792")] +#[track_caller] +pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { + // SAFETY: the caller must uphold the safety contract for `from_ptr_range`. + unsafe { from_raw_parts(range.start, range.end.offset_from_unsigned(range.start)) } +} + +/// Forms a mutable slice from a pointer range. +/// +/// This is the same functionality as [`from_ptr_range`], except that a +/// mutable slice is returned. +/// +/// This function is useful for interacting with foreign interfaces which +/// use two pointers to refer to a range of elements in memory, as is +/// common in C++. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * The `start` pointer of the range must be a non-null, [valid] and properly aligned pointer +/// to the first element of a slice. +/// +/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* +/// the last element, such that the offset from the end to the start pointer is +/// the length of the slice. +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// +/// * The range must contain `N` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `start` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements. +/// +/// # Panics +/// +/// This function panics if `T` is a Zero-Sized Type (“ZST”). +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_from_ptr_range)] +/// +/// use core::slice; +/// +/// let mut x = [1, 2, 3]; +/// let range = x.as_mut_ptr_range(); +/// +/// unsafe { +/// assert_eq!(slice::from_mut_ptr_range(range), &mut [1, 2, 3]); +/// } +/// ``` +/// +/// [valid]: ptr#safety +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +#[rustc_const_unstable(feature = "const_slice_from_mut_ptr_range", issue = "89792")] +pub const unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] { + // SAFETY: the caller must uphold the safety contract for `from_mut_ptr_range`. + unsafe { from_raw_parts_mut(range.start, range.end.offset_from_unsigned(range.start)) } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/original/slice/rotate.rs b/verifast-proofs/core/slice/mod.rs-negative/original/slice/rotate.rs new file mode 100644 index 0000000000000..b3b64422884d5 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/original/slice/rotate.rs @@ -0,0 +1,277 @@ +use crate::mem::{MaybeUninit, SizedTypeProperties}; +use crate::ptr; + +type BufType = [usize; 32]; + +/// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first +/// element. Equivalently, rotates the range `left` elements to the left or `right` elements to the +/// right. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +pub(super) const unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) { + if T::IS_ZST { + return; + } + // abort early if the rotate is a no-op + if (left == 0) || (right == 0) { + return; + } + // `T` is not a zero-sized type, so it's okay to divide by its size. + if !cfg!(feature = "optimize_for_size") + // FIXME(const-hack): Use cmp::min when available in const + && const_min(left, right) <= size_of::() / size_of::() + { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_memmove(left, mid, right) }; + } else if !cfg!(feature = "optimize_for_size") + && ((left + right < 24) || (size_of::() > size_of::<[usize; 4]>())) + { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_gcd(left, mid, right) } + } else { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_swap(left, mid, right) } + } +} + +/// Algorithm 1 is used if `min(left, right)` is small enough to fit onto a stack buffer. The +/// `min(left, right)` elements are copied onto the buffer, `memmove` is applied to the others, and +/// the ones on the buffer are moved back into the hole on the opposite side of where they +/// originated. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +const unsafe fn ptr_rotate_memmove(left: usize, mid: *mut T, right: usize) { + // The `[T; 0]` here is to ensure this is appropriately aligned for T + let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); + let buf = rawarray.as_mut_ptr() as *mut T; + // SAFETY: `mid-left <= mid-left+right < mid+right` + let dim = unsafe { mid.sub(left).add(right) }; + if left <= right { + // SAFETY: + // + // 1) The `if` condition about the sizes ensures `[mid-left; left]` will fit in + // `buf` without overflow and `buf` was created just above and so cannot be + // overlapped with any value of `[mid-left; left]` + // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care + // about overlaps here. + // 3) The `if` condition about `left <= right` ensures writing `left` elements to + // `dim = mid-left+right` is valid because: + // - `buf` is valid and `left` elements were written in it in 1) + // - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)` + unsafe { + // 1) + ptr::copy_nonoverlapping(mid.sub(left), buf, left); + // 2) + ptr::copy(mid, mid.sub(left), right); + // 3) + ptr::copy_nonoverlapping(buf, dim, left); + } + } else { + // SAFETY: same reasoning as above but with `left` and `right` reversed + unsafe { + ptr::copy_nonoverlapping(mid, buf, right); + ptr::copy(mid.sub(left), dim, left); + ptr::copy_nonoverlapping(buf, mid.sub(left), right); + } + } +} + +/// Algorithm 2 is used for small values of `left + right` or for large `T`. The elements +/// are moved into their final positions one at a time starting at `mid - left` and advancing by +/// `right` steps modulo `left + right`, such that only one temporary is needed. Eventually, we +/// arrive back at `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps +/// skipped over elements. For example: +/// ```text +/// left = 10, right = 6 +/// the `^` indicates an element in its final place +/// 6 7 8 9 10 11 12 13 14 15 . 0 1 2 3 4 5 +/// after using one step of the above algorithm (The X will be overwritten at the end of the round, +/// and 12 is stored in a temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 2 3 4 5 +/// ^ +/// after using another step (now 2 is in the temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ +/// after the third step (the steps wrap around, and 8 is in the temporary): +/// X 7 2 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ ^ +/// after 7 more steps, the round ends with the temporary 0 getting put in the X: +/// 0 7 2 9 4 11 6 13 8 15 . 10 1 12 3 14 5 +/// ^ ^ ^ ^ ^ ^ ^ ^ +/// ``` +/// Fortunately, the number of skipped over elements between finalized elements is always equal, so +/// we can just offset our starting position and do more rounds (the total number of rounds is the +/// `gcd(left + right, right)` value). The end result is that all elements are finalized once and +/// only once. +/// +/// Algorithm 2 can be vectorized by chunking and performing many rounds at once, but there are too +/// few rounds on average until `left + right` is enormous, and the worst case of a single +/// round is always there. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +const unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) { + // Algorithm 2 + // Microbenchmarks indicate that the average performance for random shifts is better all + // the way until about `left + right == 32`, but the worst case performance breaks even + // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 + // `usize`s, this algorithm also outperforms other algorithms. + // SAFETY: callers must ensure `mid - left` is valid for reading and writing. + let x = unsafe { mid.sub(left) }; + // beginning of first round + // SAFETY: see previous comment. + let mut tmp: T = unsafe { x.read() }; + let mut i = right; + // `gcd` can be found before hand by calculating `gcd(left + right, right)`, + // but it is faster to do one loop which calculates the gcd as a side effect, then + // doing the rest of the chunk + let mut gcd = right; + // benchmarks reveal that it is faster to swap temporaries all the way through instead + // of reading one temporary once, copying backwards, and then writing that temporary at + // the very end. This is possibly due to the fact that swapping or replacing temporaries + // uses only one memory address in the loop instead of needing to manage two. + loop { + // [long-safety-expl] + // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and + // writing. + // + // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right` + // - `i <= left+right-1` is always true + // - if `i < left`, `right` is added so `i < left+right` and on the next + // iteration `left` is removed from `i` so it doesn't go further + // - if `i >= left`, `left` is removed immediately and so it doesn't go further. + // - overflows cannot happen for `i` since the function's safety contract ask for + // `mid+right-1 = x+left+right` to be valid for writing + // - underflows cannot happen because `i` must be bigger or equal to `left` for + // a subtraction of `left` to happen. + // + // So `x+i` is valid for reading and writing if the caller respected the contract + tmp = unsafe { x.add(i).replace(tmp) }; + // instead of incrementing `i` and then checking if it is outside the bounds, we + // check if `i` will go outside the bounds on the next increment. This prevents + // any wrapping of pointers or `usize`. + if i >= left { + i -= left; + if i == 0 { + // end of first round + // SAFETY: tmp has been read from a valid source and x is valid for writing + // according to the caller. + unsafe { x.write(tmp) }; + break; + } + // this conditional must be here if `left + right >= 15` + if i < gcd { + gcd = i; + } + } else { + i += right; + } + } + // finish the chunk with more rounds + // FIXME(const-hack): Use `for start in 1..gcd` when available in const + let mut start = 1; + while start < gcd { + // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for + // reading and writing as per the function's safety contract, see [long-safety-expl] + // above + tmp = unsafe { x.add(start).read() }; + // [safety-expl-addition] + // + // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the + // greatest common divisor of `(left+right, right)` means that `left = right` so + // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing + // according to the function's safety contract. + i = start + right; + loop { + // SAFETY: see [long-safety-expl] and [safety-expl-addition] + tmp = unsafe { x.add(i).replace(tmp) }; + if i >= left { + i -= left; + if i == start { + // SAFETY: see [long-safety-expl] and [safety-expl-addition] + unsafe { x.add(start).write(tmp) }; + break; + } + } else { + i += right; + } + } + + start += 1; + } +} + +/// Algorithm 3 utilizes repeated swapping of `min(left, right)` elements. +/// +/// /// +/// ```text +/// left = 11, right = 4 +/// [4 5 6 7 8 9 10 11 12 13 14 . 0 1 2 3] +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping the right most elements with elements to the left +/// [4 5 6 7 8 9 10 . 0 1 2 3] 11 12 13 14 +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping these +/// [4 5 6 . 0 1 2 3] 7 8 9 10 11 12 13 14 +/// we cannot swap any more, but a smaller rotation problem is left to solve +/// ``` +/// when `left < right` the swapping happens from the left instead. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +const unsafe fn ptr_rotate_swap(mut left: usize, mut mid: *mut T, mut right: usize) { + loop { + if left >= right { + // Algorithm 3 + // There is an alternate way of swapping that involves finding where the last swap + // of this algorithm would be, and swapping using that last chunk instead of swapping + // adjacent chunks like this algorithm is doing, but this way is still faster. + loop { + // SAFETY: + // `left >= right` so `[mid-right, mid+right)` is valid for reading and writing + // Subtracting `right` from `mid` each turn is counterbalanced by the addition and + // check after it. + unsafe { + ptr::swap_nonoverlapping(mid.sub(right), mid, right); + mid = mid.sub(right); + } + left -= right; + if left < right { + break; + } + } + } else { + // Algorithm 3, `left < right` + loop { + // SAFETY: `[mid-left, mid+left)` is valid for reading and writing because + // `left < right` so `mid+left < mid+right`. + // Adding `left` to `mid` each turn is counterbalanced by the subtraction and check + // after it. + unsafe { + ptr::swap_nonoverlapping(mid.sub(left), mid, left); + mid = mid.add(left); + } + right -= left; + if right < left { + break; + } + } + } + if (right == 0) || (left == 0) { + return; + } + } +} + +// FIXME(const-hack): Use cmp::min when available in const +const fn const_min(left: usize, right: usize) -> usize { + if right < left { right } else { left } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/original/slice/sort.rs b/verifast-proofs/core/slice/mod.rs-negative/original/slice/sort.rs new file mode 100644 index 0000000000000..bb060c9c9b963 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/original/slice/sort.rs @@ -0,0 +1,11 @@ + +pub mod select { + pub fn partition_at_index(_v: &mut [T], _index: usize, _is_less: F) -> (&mut [T], &mut T, &mut [T]) + where F: FnMut(&T, &T) -> bool { loop {} } +} +pub mod unstable { + pub fn sort(_v: &mut [T], _is_less: &mut F) + where F: FnMut(&T, &T) -> bool { loop {} } + pub fn partial_sort(_v: &mut [T], _range: R, _is_less: F) + where R: core::ops::RangeBounds, F: FnMut(&T, &T) -> bool { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/original/slice/specialize.rs b/verifast-proofs/core/slice/mod.rs-negative/original/slice/specialize.rs new file mode 100644 index 0000000000000..9bf035047a4ed --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/original/slice/specialize.rs @@ -0,0 +1,7 @@ + +pub trait SpecFill { + fn spec_fill(&mut self, val: T); +} +impl SpecFill for [T] { + fn spec_fill(&mut self, _val: T) { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/update.sh b/verifast-proofs/core/slice/mod.rs-negative/update.sh new file mode 100644 index 0000000000000..f63c7e7f3ee4d --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/update.sh @@ -0,0 +1,16 @@ +set -x -e + +if ! git diff --quiet .; then + echo "Working directory not clean. Please stash your changes and try again" + false +else + UPSTREAM_MOD=../../../../library/core/src/slice/mod.rs + UPSTREAM_RAW=../../../../library/core/src/slice/raw.rs + UPSTREAM_ROTATE=../../../../library/core/src/slice/rotate.rs + git merge-file --diff3 verified/slice.rs original/slice.rs $UPSTREAM_MOD + cp $UPSTREAM_MOD original/slice.rs + git merge-file --diff3 verified/slice/raw.rs original/slice/raw.rs $UPSTREAM_RAW + cp $UPSTREAM_RAW original/slice/raw.rs + git merge-file --diff3 verified/slice/rotate.rs original/slice/rotate.rs $UPSTREAM_ROTATE + cp $UPSTREAM_ROTATE original/slice/rotate.rs +fi diff --git a/verifast-proofs/core/slice/mod.rs-negative/verified/lib.rs b/verifast-proofs/core/slice/mod.rs-negative/verified/lib.rs new file mode 100644 index 0000000000000..92b20dca28be4 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/verified/lib.rs @@ -0,0 +1,417 @@ +#![feature(const_result_trait_fn, const_iter)] +#![feature(one_sided_range, portable_simd, slice_index_methods, const_index, slice_range, const_clone, trivial_clone, slice_from_ptr_range, const_default, u8_split_ascii_whitespace, str_internals, slice_pattern)] +#![feature(slice_ptr_get, raw_slice_split, ptr_cast_array, array_into_iter_constructors, exact_size_is_empty, iter_advance_by, iter_next_chunk, iter_collect_into, trusted_len, trusted_random_access, trusted_fused, inplace_iteration, sized_type_properties, nonnull_provenance, ptr_metadata, slice_internals, const_option_ops, deref_pure_trait, try_trait_v2, never_type, specialization)] +//! # The Rust Core Library +//! +//! The Rust Core Library is the dependency-free[^free] foundation of [The +//! Rust Standard Library](../std/index.html). It is the portable glue +//! between the language and its libraries, defining the intrinsic and +//! primitive building blocks of all Rust code. It links to no +//! upstream libraries, no system libraries, and no libc. +//! +//! [^free]: Strictly speaking, there are some symbols which are needed but +//! they aren't always necessary. +//! +//! The core library is *minimal*: it isn't even aware of heap allocation, +//! nor does it provide concurrency or I/O. These things require +//! platform integration, and this library is platform-agnostic. +//! +//! # How to use the core library +//! +//! Please note that all of these details are currently not considered stable. +//! +// FIXME: Fill me in with more detail when the interface settles +//! This library is built on the assumption of a few existing symbols: +//! +//! * `memcpy`, `memmove`, `memset`, `memcmp`, `bcmp`, `strlen` - These are core memory routines +//! which are generated by Rust codegen backends. Additionally, this library can make explicit +//! calls to `strlen`. Their signatures are the same as found in C, but there are extra +//! assumptions about their semantics: For `memcpy`, `memmove`, `memset`, `memcmp`, and `bcmp`, if +//! the `n` parameter is 0, the function is assumed to not be UB, even if the pointers are NULL or +//! dangling. (Note that making extra assumptions about these functions is common among compilers: +//! [clang](https://reviews.llvm.org/D86993) and [GCC](https://gcc.gnu.org/onlinedocs/gcc/Standards.html#C-Language) do the same.) +//! These functions are often provided by the system libc, but can also be provided by the +//! [compiler-builtins crate](https://crates.io/crates/compiler_builtins). +//! Note that the library does not guarantee that it will always make these assumptions, so Rust +//! user code directly calling the C functions should follow the C specification! The advice for +//! Rust user code is to call the functions provided by this library instead (such as +//! `ptr::copy`). +//! +//! * Panic handler - This function takes one argument, a `&panic::PanicInfo`. It is up to consumers of this core +//! library to define this panic function; it is only required to never +//! return. You should mark your implementation using `#[panic_handler]`. +//! +//! * `rust_eh_personality` - is used by the failure mechanisms of the +//! compiler. This is often mapped to GCC's personality function, but crates +//! which do not trigger a panic can be assured that this function is never +//! called. The `lang` attribute is called `eh_personality`. + +#![stable(feature = "core", since = "1.6.0")] +#![doc( + html_playground_url = "https://play.rust-lang.org/", + issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", + test(no_crate_inject, attr(deny(warnings))), + test(attr(allow(dead_code, deprecated, unused_variables, unused_mut, duplicate_features))) +)] +#![doc(rust_logo)] +#![doc(auto_cfg( + hide(no_fp_fmt_parse), + hide(target_pointer_width, values("16", "32", "64")), + hide( + target_has_atomic, + target_has_atomic_primitive_alignment, + target_has_atomic_load_store, + values("8", "16", "32", "64", "ptr"), + ), +))] +#![rustc_coherence_is_core] +#![rustc_preserve_ub_checks] +// +// Lints: +#![deny(rust_2021_incompatible_or_patterns)] +#![deny(unsafe_op_in_unsafe_fn)] +#![deny(implicit_provenance_casts)] +#![warn(deprecated_in_future)] +#![warn(missing_debug_implementations)] +#![warn(missing_docs)] +#![allow(explicit_outlives_requirements)] +#![allow(incomplete_features)] +#![warn(multiple_supertrait_upcastable)] +#![allow(internal_features)] +#![allow(unused_features)] +#![deny(ffi_unwind_calls)] +#![warn(unreachable_pub)] +// Do not check link redundancy on bootstrapping phase +#![allow(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::unescaped_backticks)] +// +// Library features: +// tidy-alphabetical-start +#![feature(asm_experimental_arch)] +#![feature(bstr_internals)] +#![feature(cfg_target_has_reliable_f16_f128)] +#![feature(const_carrying_mul_add)] +#![feature(const_cmp)] +#![feature(const_destruct)] +#![feature(const_eval_select)] +#![feature(const_select_unpredictable)] +#![feature(core_intrinsics)] +#![feature(coverage_attribute)] +#![feature(disjoint_bitor)] +#![feature(io_const_error)] +#![feature(offset_of_enum)] +#![feature(panic_internals)] +#![feature(pattern_type_macro)] +#![feature(ub_checks)] +// tidy-alphabetical-end +// +// Language features: +// tidy-alphabetical-start +#![feature(adt_const_params)] +#![feature(allow_internal_unsafe)] +#![feature(allow_internal_unstable)] +#![feature(arbitrary_self_types_pointers)] +#![feature(auto_traits)] +#![feature(cfg_sanitize)] +#![feature(cfg_target_has_atomic)] +#![feature(cfg_ub_checks)] +#![feature(const_closures)] +#![feature(const_precise_live_drops)] +#![feature(const_trait_impl)] +#![feature(decl_macro)] +#![feature(deprecated_suggestion)] +#![feature(derive_const)] +#![feature(diagnostic_on_const)] +#![feature(diagnostic_on_unmatched_args)] +#![feature(diagnostic_opaque)] +#![feature(doc_cfg)] +#![feature(doc_notable_trait)] +#![feature(extern_types)] +#![feature(f16)] +#![feature(f128)] +#![feature(field_projections)] +#![feature(final_associated_functions)] +#![feature(freeze_impls)] +#![feature(fundamental)] +#![feature(funnel_shifts)] +#![feature(impl_restriction)] +#![feature(intra_doc_pointers)] +#![feature(intrinsics)] +#![feature(lang_items)] +#![feature(link_cfg)] +#![feature(link_llvm_intrinsics)] +#![feature(macro_metavar_expr)] +#![feature(macro_metavar_expr_concat)] +#![feature(marker_trait_attr)] +#![feature(min_specialization)] +#![feature(multiple_supertrait_upcastable)] +#![feature(must_not_suspend)] +#![feature(negative_impls)] +#![feature(no_core)] +#![feature(optimize_attribute)] +#![feature(pattern_types)] +#![feature(pin_macro_internals)] +#![feature(prelude_import)] +#![feature(repr_simd)] +#![feature(rustc_attrs)] +#![feature(rustdoc_internals)] +#![feature(simd_ffi)] +#![feature(splat)] +#![feature(staged_api)] +#![feature(stmt_expr_attributes)] +#![feature(strict_provenance_lints)] +#![feature(trait_alias)] +#![feature(transparent_unions)] +#![feature(try_blocks)] +#![feature(uint_carryless_mul)] +#![feature(unboxed_closures)] +#![feature(unsized_fn_params)] +#![feature(with_negative_coherence)] +// Required for Kani loop contracts, which are annotated as custom stmt attributes. +#![feature(proc_macro_hygiene)] +// tidy-alphabetical-end +// +// Target features: +// tidy-alphabetical-start +#![feature(aarch64_unstable_target_feature)] +#![feature(arm_target_feature)] +#![feature(avx10_target_feature)] +#![feature(clflushopt_target_feature)] +#![feature(hexagon_target_feature)] +#![feature(loongarch_target_feature)] +#![feature(mips_target_feature)] +#![feature(movrs_target_feature)] +#![feature(nvptx_target_feature)] +#![feature(powerpc_target_feature)] +#![feature(riscv_target_feature)] +#![feature(rtm_target_feature)] +#![feature(s390x_target_feature)] +#![feature(wasm_target_feature)] +#![feature(x86_amx_intrinsics)] +// tidy-alphabetical-end + +// tidy-alphabetical-start +#![expect(clippy::partialeq_ne_impl, reason = "we need to implement ne for a lot of core types")] +// tidy-alphabetical-end + +// allow using `core::` in intra-doc links + +#![no_core] +#![allow(unused_imports, unused_variables, dead_code, unused_mut, unreachable_pub, missing_docs, missing_debug_implementations)] + +#[stable(feature = "rust1", since = "1.0.0")] +extern crate core; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::{iter, ascii, char, clone, cmp, convert, default, fmt, hash, hint, marker, mem, num, ops, option, panicking, pin, range, result, simd, str}; +#[stable(feature = "rust1", since = "1.0.0")] +pub mod panic { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::panic::{Location, PanicInfo}; + #[unstable(feature = "panic_internals", issue = "none")] + pub macro const_panic($($t:tt)*) { + loop {} + } +} +#[stable(feature = "rust1", since = "1.0.0")] +pub mod ptr { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::ptr::*; + #[unstable(feature = "ptr_internals", issue = "none")] + pub unsafe fn align_offset(p: *const T, a: usize) -> usize + //@ req pointer_within_limits(p) == true &*& a > 0; + //@ ens 0 <= result &*& result <= usize::MAX &*& (result == usize::MAX || ((p + result) as usize) % a == 0); + //@ on_unwind_ens false; + // https://github.com/verifast/verifast/issues/1056 + //@ assume_correct + { + p.align_offset(a) + } + /*@ + fix mk_slice(data: *T, len: usize) -> *[T]; + + lem_auto(mk_slice::(data, len)) mk_slice_props(data: *T, len: usize) + req true; + ens strip_pointer_metadata(mk_slice::(data, len) as pointer) as *T == data && + mk_slice::(data, len) as *T == data && + (mk_slice::(data, len)).len() == len; + { + assume(false); + } + @*/ + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] + pub const unsafe fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] + //@ req true; + //@ ens result == mk_slice::(data, len); + //@ on_unwind_ens false; + // https://github.com/verifast/verifast/issues/1056 + //@ assume_correct + { + core::ptr::slice_from_raw_parts(data, len) + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")] + pub const unsafe fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] + //@ req true; + //@ ens result == mk_slice::(data, len); + //@ on_unwind_ens false; + // https://github.com/verifast/verifast/issues/1056 + //@ assume_correct + { + core::ptr::slice_from_raw_parts_mut(data, len) + } + /*@ + pred copy_context(base: *T, len: usize, src_idx: usize, dst_idx: usize, count: usize, elems: list) = + base[..len] |-> elems &*& + 0 <= count &*& + 0 <= src_idx &*& src_idx + count <= len &*& + 0 <= dst_idx &*& dst_idx + count <= len; + @*/ + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] + pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) + //@ req copy_context::(?base, ?len, ?src_idx, ?dst_idx, count, ?elems) &*& src == base + src_idx &*& dst == base + dst_idx; + //@ ens base[..len] |-> append(take(dst_idx, elems), append(take(count, drop(src_idx, elems)), drop(dst_idx + count, elems))); + //@ on_unwind_ens false; + //@ assume_correct + { + unsafe { core::ptr::copy(src, dst, count) } + } +} +#[stable(feature = "rust1", since = "1.0.0")] +pub mod intrinsics { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::intrinsics::{assume, arith_offset, ptr_offset_from, ptr_offset_from_unsigned, transmute, transmute_unchecked, write_bytes, copy, copy_nonoverlapping, compare_bytes, cttz_nonzero, ctlz_nonzero, size_of_val, align_of_val, size_of, align_of, needs_drop, type_id, type_name, caller_location, cold_path, likely, unlikely, select_unpredictable, abort, unreachable, const_eval_select, black_box, unchecked_shl, unchecked_shr}; + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn exact_div(x: usize, y: usize) -> usize + //@ req y != 0 &*& x % y == 0; + //@ ens result == x / y; + //@ on_unwind_ens false; + { + x / y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_sub(x: usize, y: usize) -> usize + //@ req x >= y; + //@ ens result == x - y; + //@ on_unwind_ens false; + { + x - y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_add(x: usize, y: usize) -> usize + //@ req x + y <= usize::MAX; + //@ ens result == x + y; + //@ on_unwind_ens false; + { + x + y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_mul(x: usize, y: usize) -> usize + //@ req x * y <= usize::MAX; + //@ ens result == x * y; + //@ on_unwind_ens false; + { + //@ mul_mono_l(0, x, y); + x * y + } +} + +#[unstable(feature = "ub_checks", issue = "none")] +pub mod ub_checks { + #[unstable(feature = "ub_checks", issue = "none")] + pub trait Invariant { + fn is_safe(&self) -> bool { true } + } + #[unstable(feature = "ub_checks", issue = "none")] + impl Invariant for &T {} + #[unstable(feature = "ub_checks", issue = "none")] + impl Invariant for &mut T {} + #[macro_export] + macro_rules! assert_unsafe_precondition { + ($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {{}}; + } + #[unstable(feature = "ub_checks", issue = "none")] + pub use assert_unsafe_precondition; + #[unstable(feature = "ub_checks", issue = "none")] + pub const fn check_language_ub() -> bool { false } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn same_allocation(_a: *const T, _b: *const T) -> bool { true } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn can_dereference(_p: *const T) -> bool { true } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn can_write(_p: *mut T) -> bool { true } +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod array { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::array::*; + #[unstable(feature = "iter_next_chunk", issue = "none")] + pub fn iter_next_chunk(_iter: &mut impl crate::iter::Iterator) -> Result<[T; N], core::array::IntoIter> { + loop {} + } +} + + + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::prelude::v1::{ + Copy, Send, Sized, Sync, Unpin, Drop, Fn, FnMut, FnOnce, AsyncFn, AsyncFnMut, AsyncFnOnce, + drop, align_of, align_of_val, size_of, size_of_val, + Clone, PartialEq, PartialOrd, Eq, Ord, AsMut, AsRef, From, Into, + Option, Some, None, Result, Ok, Err, + Debug, Hash, + panic, assert, assert_eq, assert_ne, cfg, column, compile_error, concat, debug_assert, debug_assert_eq, + debug_assert_ne, file, format_args, include, include_bytes, include_str, line, matches, + module_path, option_env, stringify, todo, unimplemented, unreachable, write, writeln, + cfg_select, derive, derive_const, + }; + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::prelude::rust_2024::{TryInto, TryFrom, FromIterator, Future, IntoFuture}; + #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::Default; + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::iter::{Iterator, IntoIterator, DoubleEndedIterator, ExactSizeIterator, Extend}; +} +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +pub const trait Default { + #[stable(feature = "rust1", since = "1.0.0")] + fn default() -> Self; +} +#[prelude_import] +#[stable(feature = "rust1", since = "1.0.0")] +pub use prelude::*; + +#[stable(feature = "rust1", since = "1.0.0")] +#[path = "."] +pub mod std { + pub mod slice; +} +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::std::slice; + +#[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] +const unsafe fn call_binary_search_f__VeriFast_wrapper<'a, 'b, T, F>( + slice: &'a [T], + f: &'b mut F, + index: usize, +) -> core::cmp::Ordering +where + F: [const] FnMut(&'a T) -> core::cmp::Ordering, +//@ req thread_token(?t) &*& [_](<[T]>.share(?k, t, slice)) &*& *f |-> ?f0 &*& (.own)(t, f0) &*& index < slice.len(); +//@ ens thread_token(t) &*& *f |-> ?f1 &*& (.own)(t, f1); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + f(unsafe { slice.get_unchecked(index) }) +}const fn _vf_const_marker() {} + diff --git a/verifast-proofs/core/slice/mod.rs-negative/verified/slice.rs b/verifast-proofs/core/slice/mod.rs-negative/verified/slice.rs new file mode 100644 index 0000000000000..cbe4fefa5f23f --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/verified/slice.rs @@ -0,0 +1,8517 @@ +//! Slice management and manipulation. +//! +//! For more details see [`std::slice`]. +//! +//! [`std::slice`]: ../../std/slice/index.html + +#![stable(feature = "rust1", since = "1.0.0")] + +use safety::{ensures, requires}; + +use crate::clone::TrivialClone; +use crate::cmp::Ordering::{self, Equal, Greater, Less}; +use crate::intrinsics::{exact_div, unchecked_sub}; +#[cfg(kani)] +use crate::kani; +use crate::marker::Destruct; +use crate::mem::{self, MaybeUninit, SizedTypeProperties}; +use crate::num::NonZero; +use crate::ops::{OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeInclusive}; +use crate::panic::const_panic; +use crate::simd::{self, Simd}; +use crate::ub_checks::assert_unsafe_precondition; +use crate::{fmt, hint, ptr, range, slice}; + +#[unstable( + feature = "slice_internals", + issue = "none", + reason = "exposed from core to be reused in std; use the memchr crate" +)] +#[doc(hidden)] +/// Pure Rust memchr implementation, taken from rust-memchr +pub mod memchr; + +#[unstable( + feature = "slice_internals", + issue = "none", + reason = "exposed from core to be reused in std;" +)] +#[doc(hidden)] +pub mod sort; + +mod ascii; +mod cmp; +pub(crate) mod index; +mod iter; +mod raw; +mod rotate; +mod specialize; + +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] +pub use ascii::EscapeAscii; +#[unstable(feature = "u8_split_ascii_whitespace", issue = "147878")] +pub use ascii::SplitAsciiWhitespace; +#[unstable(feature = "str_internals", issue = "none")] +#[doc(hidden)] +pub use ascii::is_ascii_simple; +#[stable(feature = "slice_get_slice", since = "1.28.0")] +pub use index::SliceIndex; +#[unstable(feature = "slice_range", issue = "76393")] +pub use index::{range, try_range}; +#[stable(feature = "array_windows", since = "1.94.0")] +pub use iter::ArrayWindows; +#[stable(feature = "slice_group_by", since = "1.77.0")] +pub use iter::{ChunkBy, ChunkByMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Chunks, ChunksMut, Windows}; +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub use iter::{ChunksExact, ChunksExactMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Iter, IterMut}; +#[stable(feature = "rchunks", since = "1.31.0")] +pub use iter::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; +#[stable(feature = "slice_rsplit", since = "1.27.0")] +pub use iter::{RSplit, RSplitMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut}; +#[stable(feature = "split_inclusive", since = "1.51.0")] +pub use iter::{SplitInclusive, SplitInclusiveMut}; +#[stable(feature = "from_ref", since = "1.28.0")] +pub use raw::{from_mut, from_ref}; +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +pub use raw::{from_mut_ptr_range, from_ptr_range}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::{from_raw_parts, from_raw_parts_mut}; + +/// Calculates the direction and split point of a one-sided range. +/// +/// This is a helper function for `split_off` and `split_off_mut` that returns +/// the direction of the split (front or back) as well as the index at +/// which to split. Returns `None` if the split index would overflow. +#[inline] +fn split_point_of(range: impl OneSidedRange) -> Option<(Direction, usize)> { + use OneSidedRangeBound::{End, EndInclusive, StartInclusive}; + + Some(match range.bound() { + (StartInclusive, i) => (Direction::Back, i), + (End, i) => (Direction::Front, i), + (EndInclusive, i) => (Direction::Front, i.checked_add(1)?), + }) +} + +enum Direction { + Front, + Back, +} + +/*@ +fix update(i: i32, y: t, xs: list) -> list { + match xs { + nil => nil, + cons(x, xs0) => if i == 0 { cons(y, xs0) } else { cons(x, update(i - 1, y, xs0)) } + } +} + +lem_auto(length(update(i, y, xs))) length_update(i: i32, y: t, xs: list) + req true; + ens length(update(i, y, xs)) == length(xs); +{ + match xs { + nil => {} + cons(x, xs0) => { if i != 0 { length_update(i - 1, y, xs0); } } + } +} + +lem update_same(i: i32, xs: list) + req 0 <= i &*& i < length(xs); + ens update(i, nth(i, xs), xs) == xs; +{ + match xs { + nil => {} + cons(x, xs0) => { if i != 0 { update_same(i - 1, xs0); } } + } +} + +lem update_overwrite(i: i32, y1: t, y2: t, xs: list) + req 0 <= i &*& i < length(xs); + ens update(i, y2, update(i, y1, xs)) == update(i, y2, xs); +{ + match xs { + nil => {} + cons(x, xs0) => { if i != 0 { update_overwrite(i - 1, y1, y2, xs0); } } + } +} + +lem append_take_cons_drop_update(xs: list, i: i32, v: t) + req 0 <= i &*& i < length(xs); + ens append(take(i, xs), cons(v, drop(i + 1, xs))) == update(i, v, xs); +{ + match xs { + nil => {} + cons(x, xs0) => { if i != 0 { append_take_cons_drop_update(xs0, i - 1, v); } } + } +} + +lem take_update_lt(i: i32, v: t, b: i32, xs: list) + req 0 <= i &*& i < b &*& b <= length(xs); + ens update(i, v, take(b, xs)) == take(b, update(i, v, xs)) &*& + drop(b + 1, update(i, v, xs)) == drop(b + 1, xs); +{ + match xs { + nil => {} + cons(x, xs0) => { + if i == 0 { + } else { + take_update_lt(i - 1, v, b - 1, xs0); + } + } + } +} + +lem update_comm(i: i32, vi: t, j: i32, vj: t, xs: list) + req 0 <= i &*& 0 <= j &*& i != j; + ens update(j, vj, update(i, vi, xs)) == update(i, vi, update(j, vj, xs)); +{ + match xs { + nil => {} + cons(x, xs0) => { + if i == 0 { + } else if j == 0 { + } else { + update_comm(i - 1, vi, j - 1, vj, xs0); + } + } + } +} + +lem array_extract_elem(ptr: *T, i: usize) + req ptr[..?len] |-> ?elems &*& 0 <= i &*& i < len; + ens ptr[..i] |-> take(i, elems) &*& *(ptr + i) |-> nth(i, elems) &*& (ptr + i + 1)[..len - i - 1] |-> drop(i + 1, elems); +{ + array_split(ptr, i); + drop_n_plus_one(i, elems); + open array(ptr + i, len - i, drop(i, elems)); +} + +lem array_insert_elem(ptr: *T, i: usize, len: usize, elems: list) + req ptr[..i] |-> take(i, elems) &*& *(ptr + i) |-> ?v &*& (ptr + i + 1)[..len - i - 1] |-> drop(i + 1, elems) &*& 0 <= i &*& i < len &*& length(elems) == len; + ens ptr[..len] |-> update(i, v, elems); +{ + close array(ptr + i, len - i, cons(v, drop(i + 1, elems))); + array_join(ptr); + append_take_cons_drop_update(elems, i, v); +} + +lem update_nth_id(i: i32, xs: list) + req 0 <= i &*& i < length(xs); + ens update(i, nth(i, xs), xs) == xs; +{ + match xs { + nil => {} + cons(h, tl) => { + if i == 0 { + } else { + update_nth_id(i - 1, tl); + } + } + } +} + +lem array_extract_elem_frac(ptr: *T, i: usize) + req [?f](ptr[..?len] |-> ?elems) &*& 0 <= i &*& i < len; + ens [f](ptr[..i] |-> take(i, elems)) &*& [f](*(ptr + i) |-> nth(i, elems)) &*& [f]((ptr + i + 1)[..len - i - 1] |-> drop(i + 1, elems)); +{ + array_split(ptr, i); + drop_n_plus_one(i, elems); + open [f]array(ptr + i, len - i, drop(i, elems)); +} + +lem array_insert_elem_frac(ptr: *T, i: usize, len: usize, elems: list) + req [?f](ptr[..i] |-> take(i, elems)) &*& [f](*(ptr + i) |-> nth(i, elems)) &*& [f]((ptr + i + 1)[..len - i - 1] |-> drop(i + 1, elems)) &*& 0 <= i &*& i < len &*& length(elems) == len; + ens [f](ptr[..len] |-> elems); +{ + close [f]array(ptr + i, len - i, cons(nth(i, elems), drop(i + 1, elems))); + array_join(ptr); + append_take_cons_drop_update(elems, i, nth(i, elems)); + update_nth_id(i, elems); +} + +lem close_slice_pair_own<'a, T>(t: thread_id_t, v: (&'a [T], &'a [T])) + req [_](<[T]>.share('a, t, v.0)) &*& [_](<[T]>.share('a, t, v.1)); + ens <(&'a [T], &'a [T])>.own(t, v); +{ + // https://github.com/verifast/verifast/issues/1049 + assume(false); +} + +lem close_mut_slice_pair_own<'a, T>(t: thread_id_t, v: (&'a mut [T], &'a mut [T])) + req full_borrow('a, <[T]>.full_borrow_content(t, v.0)) &*& full_borrow('a, <[T]>.full_borrow_content(t, v.1)); + ens <(&'a mut [T], &'a mut [T])>.own(t, v); +{ + // https://github.com/verifast/verifast/issues/1049 + assume(false); +} + +lem close_Range_own(t: thread_id_t, v: std::ops::Range) + req (.own)(t, v.start) &*& (.own)(t, v.end); + ens >.own(t, v); +{ + // https://github.com/verifast/verifast/issues/1049 + assume(false); +} + +lem close_Result_usize_own(t: thread_id_t, v: std::result::Result) + req true; + ens >.own(t, v); +{ + match v { + Result::Ok(x) => { + close usize_own(t, x); + close >.own(t, v); + } + Result::Err(x) => { + close usize_own(t, x); + close >.own(t, v); + } + } +} + +lem slice_share_inv(k: lifetime_t, t: thread_id_t, s: *[T]) + req [_](<[T]>.share(k, t, s)); + ens s.len() * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits(strip_pointer_metadata(s as pointer) as *T) == true &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *T) + s.len()) == true; +{ + // https://github.com/verifast/verifast/issues/1050 + assume(false); +} + +lem slice_full_borrow_inv(q: real, k: lifetime_t, t: thread_id_t, s: *[T]) + nonghost_callers_only + req [q]lifetime_token(k) &*& full_borrow(k, <[T]>.full_borrow_content(t, s)); + ens [q]lifetime_token(k) &*& full_borrow(k, <[T]>.full_borrow_content(t, s)) &*& + s.len() * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits(strip_pointer_metadata(s as pointer) as *T) == true &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *T) + s.len()) == true; +{ + open_full_borrow(q / 2, k, slice_full_borrow_content::(t, s)); + open slice_full_borrow_content::(t, s)(); + array_inv::(); + close slice_full_borrow_content::(t, s)(); + close_full_borrow(slice_full_borrow_content::(t, s)); +} + +lem open_mut_slice_full_borrow(q: real, k: lifetime_t, t: thread_id_t, s: *[T]) + nonghost_callers_only + req [q]lifetime_token(k) &*& full_borrow(k, <[T]>.full_borrow_content(t, s)); + ens [q / 2]lifetime_token(k) &*& close_full_borrow_token(<[T]>.full_borrow_content(t, s), q / 2, k) &*& + (strip_pointer_metadata(s as pointer) as *T)[..s.len()] |-> ?elems &*& foreach(elems, own::(t)) &*& + s.len() * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits(strip_pointer_metadata(s as pointer) as *T) == true &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *T) + s.len()) == true; +{ + open_full_borrow(q / 2, k, slice_full_borrow_content::(t, s)); + open slice_full_borrow_content::(t, s)(); +} + +lem close_mut_slice_full_borrow(q: real, k: lifetime_t, t: thread_id_t, s: *[T]) + nonghost_callers_only + req [q / 2]lifetime_token(k) &*& close_full_borrow_token(<[T]>.full_borrow_content(t, s), q / 2, k) &*& + (strip_pointer_metadata(s as pointer) as *T)[..s.len()] |-> ?elems &*& foreach(elems, own::(t)); + ens [q]lifetime_token(k); +{ + close slice_full_borrow_content::(t, s)(); + close_full_borrow(slice_full_borrow_content::(t, s)); + leak full_borrow(k, slice_full_borrow_content::(t, s)); +} + +// Caller obligation of `align_to`/`align_to_mut` (see their `# Safety` sections: the middle slice is +// "essentially a `transmute`" of `T`s to `U`s): reinterpreting a correctly aligned, exactly covering +// run of `T` values as `U` values yields valid `U` values. VeriFast's RustBelt model cannot express +// bit-level validity across types, so this is an abstract fact that the caller must establish. +// `as_simd`/`as_simd_mut` carry it as an explicit precondition of their wrappers. +fix valid_slice_transmute() -> bool; + +lem close_slice_triple_own<'a, T, U>(t: thread_id_t, v: (&'a [T], &'a [U], &'a [T])) + req [_](<[T]>.share('a, t, v.0)) &*& [_](<[U]>.share('a, t, v.1)) &*& [_](<[T]>.share('a, t, v.2)); + ens <(&'a [T], &'a [U], &'a [T])>.own(t, v); +{ + // https://github.com/verifast/verifast/issues/1049 + assume(false); +} + +lem close_mut_slice_triple_own<'a, T, U>(t: thread_id_t, v: (&'a mut [T], &'a mut [U], &'a mut [T])) + req full_borrow('a, <[T]>.full_borrow_content(t, v.0)) &*& full_borrow('a, <[U]>.full_borrow_content(t, v.1)) &*& full_borrow('a, <[T]>.full_borrow_content(t, v.2)); + ens <(&'a mut [T], &'a mut [U], &'a mut [T])>.own(t, v); +{ + // https://github.com/verifast/verifast/issues/1049 + assume(false); +} + +// The "transmute" step of `align_to`/`align_to_mut`: a run of `n` `T` values at `p`, aligned for `U` +// and covering exactly `mid.len()` `U` values byte for byte, is reinterpreted as the `[U]` slice `mid`. +// Everything else `align_to` relies on (the prefix/suffix split of `rest`, the byte-exact coverage +// computed by `align_to_offsets`, the alignment produced by `align_offset`) is proved at the call +// sites; only the validity of the `U` values so obtained, `valid_slice_transmute`, is the caller's +// obligation, as `align_to`'s `# Safety` section states. +lem share_transmute_prefix(k: lifetime_t, t: thread_id_t, p: *T, n: usize, mid: *[U]) + req [?f]array_share::(k, t, p, n) &*& valid_slice_transmute::() == true &*& + std::mem::size_of::() > 0 &*& std::mem::size_of::() > 0 &*& + strip_pointer_metadata(mid as pointer) as *U == p as *U &*& + mid.len() * std::mem::size_of::() == n * std::mem::size_of::() &*& + (p as usize) % std::mem::align_of::() == 0; + ens [_](<[U]>.share(k, t, mid)); +{ + assume(false); +} + +lem full_borrow_transmute_prefix(k: lifetime_t, t: thread_id_t, p: *[T], mid: *[U]) + req full_borrow(k, <[T]>.full_borrow_content(t, p)) &*& valid_slice_transmute::() == true &*& + std::mem::size_of::() > 0 &*& std::mem::size_of::() > 0 &*& + strip_pointer_metadata(mid as pointer) as *U == (strip_pointer_metadata(p as pointer) as *T) as *U &*& + mid.len() * std::mem::size_of::() == p.len() * std::mem::size_of::() &*& + ((strip_pointer_metadata(p as pointer) as *T) as usize) % std::mem::align_of::() == 0; + ens full_borrow(k, <[U]>.full_borrow_content(t, mid)); +{ + assume(false); +} + +lem_auto(pointer_metadata_as_usize(m)) pointer_metadata_as_usize_limits(m: pointer_metadata) + req true; + ens 0 <= pointer_metadata_as_usize(m) && pointer_metadata_as_usize(m) <= usize::MAX; +{ + assume(false); +} + +lem array_share_split(k: lifetime_t, t: thread_id_t, l: *T, length: usize, mid: usize) + req [_]array_share::(k, t, l, length) &*& 0 <= mid &*& mid <= length; + ens array_share::(k, t, l, mid) &*& array_share::(k, t, l + mid, length - mid); +{ + if mid == 0 { + close array_share::(k, t, l, 0); + open array_share::(k, t, l, length); + close array_share::(k, t, l, length); + } else { + open array_share::(k, t, l, length); + array_share_split::(k, t, l + 1, length - 1, mid - 1); + leak array_share::(k, t, l + 1, mid - 1); + close array_share::(k, t, l, mid); + } +} + +// Associativity of multiplication. VeriFast's Redux prover handles commutativity and +// distributivity of `*` but not associativity of products of three symbolic factors, and the Rust +// prelude ships no such lemma, so it is stated here as an arithmetic axiom. +lem mul_assoc(a: i32, b: i32, c: i32) + req true; + ens a * (b * c) == (a * b) * c; +{ + // https://github.com/verifast/verifast/issues/1052 + assume(false); +} + +lem ptr_range_split_limits(ptr: *T, len: usize, mid: usize) + req 0 <= mid &*& mid <= len &*& len * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(ptr) == true &*& pointer_within_limits(ptr + len) == true; + ens mid * std::mem::size_of::() <= isize::MAX &*& (len - mid) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(ptr + mid) == true &*& ((ptr + mid) + (len - mid)) == ptr + len &*& ((ptr + len) - (len - mid)) == ptr + mid; +{ + std::alloc::is_valid_layout_size_of_align_of::(); + mul_mono_l(0, mid, std::mem::size_of::()); + mul_mono_l(mid, len, std::mem::size_of::()); + mul_mono_l(0, len - mid, std::mem::size_of::()); + mul_mono_l(len - mid, len, std::mem::size_of::()); +} + +// Splits a mutable slice borrow at `mid` into two contiguous sub-borrows (the ghost core of +// `split_at_mut_unchecked`, usable from other proofs). +lem slice_full_borrow_split(k: lifetime_t, t: thread_id_t, s: *[T], mid: usize) + nonghost_callers_only + req full_borrow(k, <[T]>.full_borrow_content(t, s)) &*& [?q]lifetime_token(k) &*& 0 <= mid &*& mid <= s.len(); + ens [q]lifetime_token(k) &*& + full_borrow(k, <[T]>.full_borrow_content(t, ptr::mk_slice::(strip_pointer_metadata(s as pointer) as *T, mid))) &*& + full_borrow(k, <[T]>.full_borrow_content(t, ptr::mk_slice::((strip_pointer_metadata(s as pointer) as *T) + mid, s.len() - mid))); +{ + let ptr = strip_pointer_metadata(s as pointer) as *T; + let len = s.len(); + open_full_borrow_strong_(k, <[T]>.full_borrow_content(t, s)); + open slice_full_borrow_content::(t, s)(); + assert array::(ptr, len, ?elems) &*& foreach(elems, own::(t)); + ptr_range_split_limits::(ptr, len, mid); + let r0 = ptr::mk_slice::(ptr, mid); + let r1 = ptr::mk_slice::(ptr + mid, len - mid); + array_split(ptr, mid); + foreach_split(elems, own::(t), mid); + close slice_full_borrow_content::(t, r0)(); + close slice_full_borrow_content::(t, r1)(); + close sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1))(); + produce_lem_ptr_chunk restore_full_borrow_(True, sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1)), <[T]>.full_borrow_content(t, s))() { + open True(); + open sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1))(); + open slice_full_borrow_content::(t, r0)(); + open slice_full_borrow_content::(t, r1)(); + assert array::(ptr, mid, ?elems0) &*& array::(ptr + mid, len - mid, ?elems1); + array_join(ptr); + foreach_append(elems0, elems1); + close slice_full_borrow_content::(t, s)(); + } { + close True(); + close_full_borrow_strong_(); + } + full_borrow_split(k, <[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1)); +} + +// `is_Copy::()` is established only through `copy_witness__VeriFast_wrapper::()`, +// whose `T: Copy` bound makes rustc reject any call site where `T` is not `Copy`. +fix is_Copy() -> bool; + +pred shared_slice_read_token(k: lifetime_t, src: *[T], f: real, elems: list); + +lem open_shared_slice_copy(k: lifetime_t, t: thread_id_t, src: *[T]) + req [_](<[T]>.share(k, t, src)) &*& [?q]lifetime_token(k) &*& is_Copy::() == true; + ens [q / 2]lifetime_token(k) &*& [?f](strip_pointer_metadata(src as pointer) as *T)[..src.len()] |-> ?elems &*& + foreach(elems, own::(t)) &*& shared_slice_read_token::(k, src, f, elems); +{ + // https://github.com/verifast/verifast/issues/1051 + assume(false); +} + +lem close_shared_slice_copy(k: lifetime_t, src: *[T]) + req shared_slice_read_token::(k, src, ?f, ?elems) &*& [f](strip_pointer_metadata(src as pointer) as *T)[..src.len()] |-> elems &*& [?q]lifetime_token(k); + ens [2 * q]lifetime_token(k); +{ + // https://github.com/verifast/verifast/issues/1051 + assume(false); +} + +lem copy_elem_own_dup(t: thread_id_t, v: T) + req (.own)(t, v) &*& is_Copy::() == true; + ens (.own)(t, v) &*& (.own)(t, v); +{ + // https://github.com/verifast/verifast/issues/1051 + assume(false); +} + +lem foreach_copy_dup(t: thread_id_t, xs: list) + req foreach(xs, own::(t)) &*& is_Copy::() == true; + ens foreach(xs, own::(t)) &*& foreach(xs, own::(t)); +{ + match xs { + nil => { + close foreach(nil, own::(t)); + } + cons(h, tl) => { + open foreach(xs, own::(t)); + open own::(t)(h); + copy_elem_own_dup::(t, h); + close own::(t)(h); + close own::(t)(h); + foreach_copy_dup::(t, tl); + close foreach(cons(h, tl), own::(t)); + close foreach(cons(h, tl), own::(t)); + } + } +} + +lem drop_drop(m: i32, n: i32, xs: list) + req 0 <= m &*& 0 <= n; + ens drop(m, drop(n, xs)) == drop(m + n, xs); +{ + match xs { + nil => {} + cons(h, tl) => { + if n == 0 { + } else { + drop_drop(m, n - 1, tl); + } + } + } +} + +lem copy_within_foreach_own(t: thread_id_t, elems: list, src_idx: usize, dst_idx: usize, count: usize) + req foreach(elems, own::(t)) &*& is_Copy::() == true &*& 0 <= count &*& 0 <= src_idx &*& src_idx + count <= length(elems) &*& 0 <= dst_idx &*& dst_idx + count <= length(elems); + ens foreach(append(take(dst_idx, elems), append(take(count, drop(src_idx, elems)), drop(dst_idx + count, elems))), own::(t)); +{ + foreach_copy_dup::(t, elems); + foreach_split(elems, own::(t), src_idx); + leak foreach(take(src_idx, elems), own::(t)); + foreach_split(drop(src_idx, elems), own::(t), count); + leak foreach(drop(count, drop(src_idx, elems)), own::(t)); + + foreach_split(elems, own::(t), dst_idx); + foreach_split(drop(dst_idx, elems), own::(t), count); + leak foreach(take(count, drop(dst_idx, elems)), own::(t)); + drop_drop(count, dst_idx, elems); + + foreach_append(take(count, drop(src_idx, elems)), drop(dst_idx + count, elems)); + foreach_append(take(dst_idx, elems), append(take(count, drop(src_idx, elems)), drop(dst_idx + count, elems))); +} + +lem foreach_extract(xs: list, p: pred(t), i: i32) + req foreach(xs, p) &*& 0 <= i &*& i < length(xs); + ens foreach(take(i, xs), p) &*& p(nth(i, xs)) &*& foreach(drop(i + 1, xs), p); +{ + match xs { + nil => {} + cons(h, tl) => { + open foreach(xs, p); + if i == 0 { + close foreach(nil, p); + } else { + foreach_extract(tl, p, i - 1); + close foreach(cons(h, take(i - 1, tl)), p); + } + } + } +} + +lem foreach_insert(xs: list, p: pred(t), i: i32, v: t) + req foreach(take(i, xs), p) &*& p(v) &*& foreach(drop(i + 1, xs), p) &*& 0 <= i &*& i < length(xs); + ens foreach(update(i, v, xs), p); +{ + match xs { + nil => {} + cons(h, tl) => { + open foreach(take(i, xs), p); + if i == 0 { + close foreach(update(0, v, xs), p); + } else { + foreach_insert(tl, p, i - 1, v); + close foreach(update(i, v, xs), p); + } + } + } +} + +lem swap_foreach_own(t: thread_id_t, xs: list, i: usize, ys: list, j: usize) + req foreach(xs, own::(t)) &*& foreach(ys, own::(t)) &*& 0 <= i &*& i < length(xs) &*& 0 <= j &*& j < length(ys); + ens foreach(update(i, nth(j, ys), xs), own::(t)) &*& foreach(update(j, nth(i, xs), ys), own::(t)); +{ + foreach_extract(xs, own::(t), i); + foreach_extract(ys, own::(t), j); + foreach_insert(xs, own::(t), i, nth(j, ys)); + foreach_insert(ys, own::(t), j, nth(i, xs)); +} + +lem array_swap_elems(t: thread_id_t, pa: *T, i: usize, pb: *T, j: usize, n: usize) + req pa[..n] |-> ?elems_a &*& foreach(elems_a, own::(t)) &*& pb[..n] |-> ?elems_b &*& foreach(elems_b, own::(t)) &*& 0 <= i &*& i < n &*& 0 <= j &*& j < n; + ens pa[..i] |-> take(i, elems_a) &*& *(pa + i) |-> nth(i, elems_a) &*& (pa + i + 1)[..n - i - 1] |-> drop(i + 1, elems_a) &*& + pb[..j] |-> take(j, elems_b) &*& *(pb + j) |-> nth(j, elems_b) &*& (pb + j + 1)[..n - j - 1] |-> drop(j + 1, elems_b) &*& + foreach(take(i, elems_a), own::(t)) &*& own::(t)(nth(i, elems_a)) &*& foreach(drop(i + 1, elems_a), own::(t)) &*& + foreach(take(j, elems_b), own::(t)) &*& own::(t)(nth(j, elems_b)) &*& foreach(drop(j + 1, elems_b), own::(t)) &*& + length(elems_a) == n &*& length(elems_b) == n; +{ + array_extract_elem(pa, i); + foreach_split(elems_a, own::(t), i); + drop_n_plus_one(i, elems_a); + open foreach(drop(i, elems_a), own::(t)); + array_extract_elem(pb, j); + foreach_split(elems_b, own::(t), j); + drop_n_plus_one(j, elems_b); + open foreach(drop(j, elems_b), own::(t)); +} + +lem array_unswap_elems(t: thread_id_t, pa: *T, i: usize, pb: *T, j: usize, n: usize, elems_a: list, elems_b: list) + req pa[..i] |-> take(i, elems_a) &*& *(pa + i) |-> ?va &*& (pa + i + 1)[..n - i - 1] |-> drop(i + 1, elems_a) &*& + pb[..j] |-> take(j, elems_b) &*& *(pb + j) |-> ?vb &*& (pb + j + 1)[..n - j - 1] |-> drop(j + 1, elems_b) &*& + foreach(take(i, elems_a), own::(t)) &*& own::(t)(va) &*& foreach(drop(i + 1, elems_a), own::(t)) &*& + foreach(take(j, elems_b), own::(t)) &*& own::(t)(vb) &*& foreach(drop(j + 1, elems_b), own::(t)) &*& + 0 <= i &*& i < n &*& 0 <= j &*& j < n &*& length(elems_a) == n &*& length(elems_b) == n; + ens pa[..n] |-> update(i, va, elems_a) &*& foreach(update(i, va, elems_a), own::(t)) &*& + pb[..n] |-> update(j, vb, elems_b) &*& foreach(update(j, vb, elems_b), own::(t)); +{ + array_insert_elem(pa, i, n, elems_a); + close foreach(cons(va, drop(i + 1, elems_a)), own::(t)); + foreach_append(take(i, elems_a), cons(va, drop(i + 1, elems_a))); + append_take_cons_drop_update(elems_a, i, va); + array_insert_elem(pb, j, n, elems_b); + close foreach(cons(vb, drop(j + 1, elems_b)), own::(t)); + foreach_append(take(j, elems_b), cons(vb, drop(j + 1, elems_b))); + append_take_cons_drop_update(elems_b, j, vb); +} + +pred array_two_extracted(t: thread_id_t, ptr: *T, i: usize, j: usize, len: usize) = + exists(?elems) &*& length(elems) == len &*& + ptr[..i] |-> take(i, take(j, elems)) &*& + (ptr + i + 1)[..j - i - 1] |-> drop(i + 1, take(j, elems)) &*& + (ptr + j + 1)[..len - j - 1] |-> drop(j + 1, elems) &*& + foreach(take(i, take(j, elems)), own::(t)) &*& + foreach(drop(i + 1, take(j, elems)), own::(t)) &*& + foreach(drop(j + 1, elems), own::(t)); + +lem array_extract_two_own(t: thread_id_t, ptr: *T, i: usize, j: usize, len: usize) + req ptr[..len] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 <= i &*& i < j &*& j < len; + ens *(ptr + i) |-> ?vi &*& (.own)(t, vi) &*& *(ptr + j) |-> ?vj &*& (.own)(t, vj) &*& array_two_extracted::(t, ptr, i, j, len); +{ + array_extract_elem(ptr, j); + array_extract_elem(ptr, i); + foreach_extract(elems, own::(t), j); + open own::(t)(nth(j, elems)); + foreach_extract(take(j, elems), own::(t), i); + open own::(t)(nth(i, take(j, elems))); + close exists(elems); + close array_two_extracted::(t, ptr, i, j, len); +} + +lem array_insert_two_own(t: thread_id_t, ptr: *T, i: usize, j: usize, len: usize) + req array_two_extracted::(t, ptr, i, j, len) &*& *(ptr + i) |-> ?vi &*& (.own)(t, vi) &*& *(ptr + j) |-> ?vj &*& (.own)(t, vj) &*& 0 <= i &*& i < j &*& j < len; + ens ptr[..len] |-> ?elems1 &*& foreach(elems1, own::(t)); +{ + open array_two_extracted::(t, ptr, i, j, len); + open exists(?elems); + close own::(t)(vi); + close own::(t)(vj); + foreach_insert(take(j, elems), own::(t), i, vi); + array_insert_elem(ptr, i, j, take(j, elems)); + close array(ptr + j, len - j, cons(vj, drop(j + 1, elems))); + array_join(ptr); + close foreach(cons(vj, drop(j + 1, elems)), own::(t)); + foreach_append(update(i, vi, take(j, elems)), cons(vj, drop(j + 1, elems))); +} + +// `Chunk` is `[T; n]`, or a type with the same layout *and* validity invariant as `[T; n]` +// (`Simd`, `#[repr(simd)]` over `[T; n]`). Abstract on purpose: a type that merely has the +// layout of `[T; n]` (say, a `bool` for `[u8; 1]`) must not satisfy it, because the chunk lemmas below +// reinterpret ownership of `n` `T`s as ownership of a `Chunk`. It is established only at the +// (const-generic, transcribed) call sites, where `Chunk` is literally `[T; N]` or `Simd`. +fix is_array_of(n: usize) -> bool; + +lem is_array_of_layout(n: usize) + req is_array_of::(n) == true; + ens 0 <= n &*& std::mem::size_of::() == n * std::mem::size_of::() &*& std::mem::align_of::() == std::mem::align_of::(); +{ + // Layout of `[T; n]` (and of `#[repr(simd)]` `Simd`), see the Rust reference. + assume(false); +} + + +lem share_slice_prefix_as_chunk(k: lifetime_t, t: thread_id_t, s: *[T], n: usize) + req [_](<[T]>.share(k, t, s)) &*& is_array_of::(n) == true &*& n <= s.len(); + ens [_](.share(k, t, (strip_pointer_metadata(s as pointer) as *T) as *Chunk)); +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem full_borrow_slice_prefix_as_chunk(k: lifetime_t, t: thread_id_t, s: *[T], n: usize) + req full_borrow(k, <[T]>.full_borrow_content(t, s)) &*& is_array_of::(n) == true &*& n <= s.len(); + ens full_borrow(k, .full_borrow_content(t, (strip_pointer_metadata(s as pointer) as *T) as *Chunk)); +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem share_slice_as_chunks(k: lifetime_t, t: thread_id_t, s: *[T], n: usize, new_len: usize) + req [_](<[T]>.share(k, t, s)) &*& is_array_of::(n) == true &*& n > 0 &*& s.len() == new_len * n; + ens [_](<[Chunk]>.share(k, t, ptr::mk_slice::((strip_pointer_metadata(s as pointer) as *T) as *Chunk, new_len))) &*& + new_len * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *T) as *Chunk) == true &*& + pointer_within_limits(((strip_pointer_metadata(s as pointer) as *T) as *Chunk) + new_len) == true; +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem full_borrow_slice_as_chunks(k: lifetime_t, t: thread_id_t, s: *[T], n: usize, new_len: usize) + req full_borrow(k, <[T]>.full_borrow_content(t, s)) &*& is_array_of::(n) == true &*& n > 0 &*& s.len() == new_len * n; + ens full_borrow(k, <[Chunk]>.full_borrow_content(t, ptr::mk_slice::((strip_pointer_metadata(s as pointer) as *T) as *Chunk, new_len))) &*& + new_len * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *T) as *Chunk) == true &*& + pointer_within_limits(((strip_pointer_metadata(s as pointer) as *T) as *Chunk) + new_len) == true; +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem share_chunks_as_flattened(k: lifetime_t, t: thread_id_t, s: *[Chunk], n: usize, len: usize) + req [_](<[Chunk]>.share(k, t, s)) &*& is_array_of::(n) == true &*& len == s.len() * n &*& len <= usize::MAX; + ens [_](<[Elem]>.share(k, t, ptr::mk_slice::((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem, len))) &*& + len * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem) == true &*& + pointer_within_limits(((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem) + len) == true; +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem full_borrow_chunks_as_flattened(k: lifetime_t, t: thread_id_t, s: *[Chunk], n: usize, len: usize) + req full_borrow(k, <[Chunk]>.full_borrow_content(t, s)) &*& is_array_of::(n) == true &*& len == s.len() * n &*& len <= usize::MAX; + ens full_borrow(k, <[Elem]>.full_borrow_content(t, ptr::mk_slice::((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem, len))) &*& + len * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem) == true &*& + pointer_within_limits(((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem) + len) == true; +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem flatten_non_zst_no_overflow(k: lifetime_t, t: thread_id_t, s: *[Chunk], n: usize) + req is_array_of::(n) == true &*& std::mem::size_of::() > 0 &*& s.len() * std::mem::size_of::() <= isize::MAX; + ens s.len() * n <= usize::MAX; +{ + is_array_of_layout::(n); + mul_mono_l(1, std::mem::size_of::(), n); + mul_mono_l(n, std::mem::size_of::(), s.len()); +} + +lem chunk_round_down_facts(len: usize, n: usize) + req 0 <= len &*& n > 0; + ens 0 <= (len / n) * n &*& (len / n) * n <= len &*& ((len / n) * n) % n == 0 &*& ((len / n) * n) / n == len / n &*& len - (len / n) * n == len % n &*& len % n < n; +{ + div_rem_nonneg(len, n); + mul_mono_l(0, len / n, n); + div_rem_nonneg_unique((len / n) * n, n, len / n, 0); +} +@*/ + +/// Ties the ghost fact `is_Copy::()` to the real `T: Copy` bound: this function can only be +/// called where rustc can prove `T: Copy`. Its body is empty, so the refinement checker inlines +/// it to nothing. +const unsafe fn copy_witness__VeriFast_wrapper() +//@ req true; +//@ ens is_Copy::() == true; +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1051 +//@ assume_correct +{ +} + +const unsafe fn revswap_proof__VeriFast_wrapper(a: &mut [T], b: &mut [T], n: usize) +/*@ +req thread_token(?t) &*& + (strip_pointer_metadata(a as pointer) as *T)[..n] |-> ?elems_a &*& foreach(elems_a, own::(t)) &*& a.len() == n &*& + (strip_pointer_metadata(b as pointer) as *T)[..n] |-> ?elems_b &*& foreach(elems_b, own::(t)) &*& b.len() == n; +@*/ +/*@ +ens thread_token(t) &*& + (strip_pointer_metadata(a as pointer) as *T)[..n] |-> ?elems_a1 &*& foreach(elems_a1, own::(t)) &*& + (strip_pointer_metadata(b as pointer) as *T)[..n] |-> ?elems_b1 &*& foreach(elems_b1, own::(t)); +@*/ +//@ on_unwind_ens false; +{ + //@ let ptr_a = strip_pointer_metadata(a as pointer) as *T; + //@ let ptr_b = strip_pointer_metadata(b as pointer) as *T; + // The two `debug_assert!(a.len() == n)` / `debug_assert!(b.len() == n)` of `revswap` are omitted here: + // `cfg!(debug_assertions)` is false in this build, so their bodies are dead code to VeriFast + // (the only `-allow_dead_code` reports of the proof); `a.len() == n` and `b.len() == n` are preconditions. + + //@ let k = begin_lifetime(); + //@ close slice_full_borrow_content::(t, a)(); + //@ borrow(k, <[T]>.full_borrow_content(t, a)); + //@ close slice_full_borrow_content::(t, b)(); + //@ borrow(k, <[T]>.full_borrow_content(t, b)); + let (a1, _) = a.split_at_mut(n); + //@ assert std_tuple_2__0(?tup1_addr, ?a1_val); + let (b1, _) = b.split_at_mut(n); + //@ assert std_tuple_2__0(tup1_addr, a1_val) &*& std_tuple_2__0(?tup2_addr, ?b1_val); + + let mut i = 0; + //@ end_lifetime(k); + //@ borrow_end(k, <[T]>.full_borrow_content(t, a)); + //@ open slice_full_borrow_content::(t, a)(); + //@ borrow_end(k, <[T]>.full_borrow_content(t, b)); + //@ open slice_full_borrow_content::(t, b)(); + //@ leak full_borrow(_, _); + //@ leak full_borrow(_, _); + //@ leak full_borrow(_, _); + //@ leak full_borrow(_, _); + #[safety::loop_invariant(i <= n)] + #[cfg_attr(kani, + kani::loop_modifies( + unsafe {slice::from_raw_parts_mut(a1.as_mut_ptr(), n)}, + unsafe {slice::from_raw_parts_mut(b1.as_mut_ptr(), n)}, + &i) + )] + while i < n { + /*@ + inv thread_token(t) &*& lifetime_token(func_lft) &*& + std_tuple_2__0(tup1_addr, a1_val) &*& std_tuple_2__1(tup1_addr, _) &*& struct_std_tuple_2__padding(tup1_addr) &*& + std_tuple_2__0(tup2_addr, b1_val) &*& std_tuple_2__1(tup2_addr, _) &*& struct_std_tuple_2__padding(tup2_addr) &*& + 0 <= i &*& i < n &*& + a1.len() == n &*& b1.len() == n &*& + a1_val.len() == n &*& b1_val.len() == n &*& + strip_pointer_metadata(a1 as pointer) as *T == ptr_a &*& + strip_pointer_metadata(b1 as pointer) as *T == ptr_b &*& + strip_pointer_metadata(a1_val as pointer) as *T == ptr_a &*& + strip_pointer_metadata(b1_val as pointer) as *T == ptr_b &*& + ptr_a[..n] |-> ?cur_a &*& foreach(cur_a, own::(t)) &*& + ptr_b[..n] |-> ?cur_b &*& foreach(cur_b, own::(t)); + @*/ + // `&mut a[i]` / `&mut b[n - 1 - i]` of `revswap`, as element pointers into the two arrays (the bounds + // `i < n`, `n - 1 - i < n` are the loop invariant; `revswap`'s index operations are panicking checks). + //@ ptr_range_split_limits::(ptr_a, n, i); + //@ ptr_range_split_limits::(ptr_b, n, n - 1 - i); + let pa: *mut T = unsafe { a1.as_mut_ptr().add(i) }; + let pb: *mut T = unsafe { b1.as_mut_ptr().add(n - 1 - i) }; + //@ array_swap_elems(t, ptr_a, i, ptr_b, n - 1 - i, n); + mem::swap(unsafe { &mut *pa }, unsafe { &mut *pb }); + //@ array_unswap_elems(t, ptr_a, i, ptr_b, n - 1 - i, n, cur_a, cur_b); + i += 1; + } +} + +unsafe fn slice_range__VeriFast_wrapper>(src: R, len: usize) -> Range +//@ req thread_token(?t) &*& (.own)(t, src); +//@ ens thread_token(t) &*& 0 <= result.start &*& result.start <= result.end &*& result.end <= len; +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + slice::range(src, ..len) +} + +unsafe fn empty_slice__VeriFast_wrapper<'a, T>(s: &'a [T; 0]) -> &'a [T] +where + 'a: 'a, +//@ req thread_token(?t) &*& [?q]lifetime_token(?a); +//@ ens thread_token(t) &*& [q]lifetime_token(a) &*& [_](<[T]>.share(a, t, result)); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + s +} + +unsafe fn empty_mut_slice_arg__VeriFast_wrapper<'a, T>(s: &'a mut [T; 0]) -> &'a mut [T] +where + 'a: 'a, +//@ req thread_token(?t) &*& [?q]lifetime_token(?a); +//@ ens thread_token(t) &*& [q]lifetime_token(a) &*& full_borrow(a, <[T]>.full_borrow_content(t, result)); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + return s; +} + +unsafe fn call_same_bucket__VeriFast_wrapper<'a, 'b, 'c, T, F>( + x: &'b mut T, + p: &'c mut T, + same_bucket: &'a mut F, +) -> bool +where + F: FnMut(&mut T, &mut T) -> bool, +//@ req thread_token(?t) &*& *same_bucket |-> ?sb0 &*& (.own)(t, sb0) &*& *x |-> ?vx &*& (.own)(t, vx) &*& *p |-> ?vp &*& (.own)(t, vp); +//@ ens thread_token(t) &*& *same_bucket |-> ?sb1 &*& (.own)(t, sb1) &*& *x |-> ?vx1 &*& (.own)(t, vx1) &*& *p |-> ?vp1 &*& (.own)(t, vp1); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + same_bucket(x, p) +} + +const unsafe fn exact_div_usize__VeriFast_wrapper(x: usize, y: usize) -> usize +//@ req y != 0 &*& x % y == 0; +//@ ens result == x / y; +//@ on_unwind_ens false; +{ + unsafe { exact_div(x, y) } +} + +impl [T] { + /// Returns the number of elements in the slice. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert_eq!(a.len(), 3); + /// ``` + #[lang = "slice_len_fn"] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + pub const fn len(&self) -> usize + //@ req true; + //@ ens result == self.len() &*& 0 <= result &*& result <= usize::MAX; + //@ on_unwind_ens false; + { + ptr::metadata(self) + } + + /// Returns `true` if the slice has a length of 0. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert!(!a.is_empty()); + /// + /// let b: &[i32] = &[]; + /// assert!(b.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.39.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + pub const fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&10), v.first()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.first()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn first(&self) -> Option<&T> { + if let [first, ..] = self { Some(first) } else { None } + } + + /// Returns a mutable reference to the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(first) = x.first_mut() { + /// *first = 5; + /// } + /// assert_eq!(x, &[5, 1, 2]); + /// + /// let y: &mut [i32] = &mut []; + /// assert_eq!(None, y.first_mut()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn first_mut(&mut self) -> Option<&mut T> { + if let [first, ..] = self { Some(first) } else { None } + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first() { + /// assert_eq!(first, &0); + /// assert_eq!(elements, &[1, 2]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn split_first(&self) -> Option<(&T, &[T])> { + if let [first, tail @ ..] = self { Some((first, tail)) } else { None } + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_mut() { + /// *first = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[3, 4, 5]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if let [first, tail @ ..] = self { Some((first, tail)) } else { None } + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last() { + /// assert_eq!(last, &2); + /// assert_eq!(elements, &[0, 1]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn split_last(&self) -> Option<(&T, &[T])> { + if let [init @ .., last] = self { Some((last, init)) } else { None } + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last_mut() { + /// *last = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[4, 5, 3]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if let [init @ .., last] = self { Some((last, init)) } else { None } + } + + /// Returns the last element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&30), v.last()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.last()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn last(&self) -> Option<&T> { + if let [.., last] = self { Some(last) } else { None } + } + + /// Returns a mutable reference to the last item in the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(last) = x.last_mut() { + /// *last = 10; + /// } + /// assert_eq!(x, &[0, 1, 10]); + /// + /// let y: &mut [i32] = &mut []; + /// assert_eq!(None, y.last_mut()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn last_mut(&mut self) -> Option<&mut T> { + if let [.., last] = self { Some(last) } else { None } + } + + /// Returns an array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let u = [10, 40, 30]; + /// assert_eq!(Some(&[10, 40]), u.first_chunk::<2>()); + /// + /// let v: &[i32] = &[10]; + /// assert_eq!(None, v.first_chunk::<2>()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(Some(&[]), w.first_chunk::<0>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn first_chunk(&self) -> Option<&[T; N]> { + if self.len() < N { + None + } else { + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the reference outlive the slice. + Some(unsafe { &*(self.as_ptr().cast_array()) }) + } + } + + /// Returns a mutable array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(first) = x.first_chunk_mut::<2>() { + /// first[0] = 5; + /// first[1] = 4; + /// } + /// assert_eq!(x, &[5, 4, 2]); + /// + /// assert_eq!(None, x.first_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn first_chunk_mut(&mut self) -> Option<&mut [T; N]> { + if self.len() < N { + None + } else { + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and require exclusive access to the entire slice to mutate the chunk. + Some(unsafe { &mut *(self.as_mut_ptr().cast_array()) }) + } + } + + /// Returns an array reference to the first `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_chunk::<2>() { + /// assert_eq!(first, &[0, 1]); + /// assert_eq!(elements, &[2]); + /// } + /// + /// assert_eq!(None, x.split_first_chunk::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_first_chunk(&self) -> Option<(&[T; N], &[T])> { + let Some((first, tail)) = self.split_at_checked(N) else { return None }; + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some((unsafe { &*(first.as_ptr().cast_array()) }, tail)) + } + + /// Returns a mutable array reference to the first `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_chunk_mut::<2>() { + /// first[0] = 3; + /// first[1] = 4; + /// elements[0] = 5; + /// } + /// assert_eq!(x, &[3, 4, 5]); + /// + /// assert_eq!(None, x.split_first_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_first_chunk_mut( + &mut self, + ) -> Option<(&mut [T; N], &mut [T])> { + let Some((first, tail)) = self.split_at_mut_checked(N) else { return None }; + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and enforce exclusive mutability of the chunk by the split. + Some((unsafe { &mut *(first.as_mut_ptr().cast_array()) }, tail)) + } + + /// Returns an array reference to the last `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((elements, last)) = x.split_last_chunk::<2>() { + /// assert_eq!(elements, &[0]); + /// assert_eq!(last, &[1, 2]); + /// } + /// + /// assert_eq!(None, x.split_last_chunk::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_last_chunk(&self) -> Option<(&[T], &[T; N])> { + let Some(index) = self.len().checked_sub(N) else { return None }; + let (init, last) = self.split_at(index); + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some((init, unsafe { &*(last.as_ptr().cast_array()) })) + } + + /// Returns a mutable array reference to the last `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((elements, last)) = x.split_last_chunk_mut::<2>() { + /// last[0] = 3; + /// last[1] = 4; + /// elements[0] = 5; + /// } + /// assert_eq!(x, &[5, 3, 4]); + /// + /// assert_eq!(None, x.split_last_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_last_chunk_mut( + &mut self, + ) -> Option<(&mut [T], &mut [T; N])> { + let Some(index) = self.len().checked_sub(N) else { return None }; + let (init, last) = self.split_at_mut(index); + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and enforce exclusive mutability of the chunk by the split. + Some((init, unsafe { &mut *(last.as_mut_ptr().cast_array()) })) + } + + /// Returns an array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let u = [10, 40, 30]; + /// assert_eq!(Some(&[40, 30]), u.last_chunk::<2>()); + /// + /// let v: &[i32] = &[10]; + /// assert_eq!(None, v.last_chunk::<2>()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(Some(&[]), w.last_chunk::<0>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_last_chunk", since = "1.80.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn last_chunk(&self) -> Option<&[T; N]> { + // FIXME(const-hack): Without const traits, we need this instead of `get`. + let Some(index) = self.len().checked_sub(N) else { return None }; + let (_, last) = self.split_at(index); + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some(unsafe { &*(last.as_ptr().cast_array()) }) + } + + /// Returns a mutable array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(last) = x.last_chunk_mut::<2>() { + /// last[0] = 10; + /// last[1] = 20; + /// } + /// assert_eq!(x, &[0, 10, 20]); + /// + /// assert_eq!(None, x.last_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn last_chunk_mut(&mut self) -> Option<&mut [T; N]> { + // FIXME(const-hack): Without const traits, we need this instead of `get`. + let Some(index) = self.len().checked_sub(N) else { return None }; + let (_, last) = self.split_at_mut(index); + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and require exclusive access to the entire slice to mutate the chunk. + Some(unsafe { &mut *(last.as_mut_ptr().cast_array()) }) + } + + const unsafe fn first_chunk_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> Option<&'a Chunk> + //@ req [_](<[T]>.share('a, ?t, self)) &*& is_array_of::(n) == true; + //@ ens if self.len() < n { result == std::option::Option::None } else { result == std::option::Option::Some(?r) &*& [_](.share('a, t, r)) &*& r == (strip_pointer_metadata(self as pointer) as *T) as *Chunk }; + //@ on_unwind_ens false; + { + if self.len() < n { + None + } else { + //@ share_slice_prefix_as_chunk::('a, t, self, n); + Some(unsafe { &*(self.as_ptr() as *const Chunk) }) //~ignore_ref_creation + } + } + + const unsafe fn first_chunk_mut_proof__VeriFast_wrapper<'a, Chunk>(&'a mut self, n: usize) -> Option<&'a mut Chunk> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& if self.len() < n { result == std::option::Option::None &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) } else { result == std::option::Option::Some(?r) &*& full_borrow('a, .full_borrow_content(t, r)) &*& r == (strip_pointer_metadata(self as pointer) as *T) as *Chunk }; + //@ on_unwind_ens false; + { + if self.len() < n { + None + } else { + //@ full_borrow_slice_prefix_as_chunk::('a, t, self, n); + let ptr = self.as_mut_ptr(); + Some(unsafe { &mut *(ptr as *mut Chunk) }) + } + } + + const unsafe fn split_first_chunk_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> Option<(&'a Chunk, &'a [T])> + //@ req [_](<[T]>.share('a, ?t, self)) &*& is_array_of::(n) == true; + //@ ens if self.len() < n { result == std::option::Option::None } else { result == std::option::Option::Some(?p) &*& [_](.share('a, t, p.0)) &*& [_](<[T]>.share('a, t, p.1)) &*& p.1.len() == self.len() - n }; + //@ on_unwind_ens false; + { + let Some((first, tail)) = self.split_at_checked(n) else { return None }; + //@ share_slice_prefix_as_chunk::('a, t, first, n); + Some((unsafe { &*(first.as_ptr() as *const Chunk) }, tail)) //~ignore_ref_creation + } + + const unsafe fn split_first_chunk_mut_proof__VeriFast_wrapper<'a, Chunk>( + &'a mut self, + n: usize, + ) -> Option<(&'a mut Chunk, &'a mut [T])> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& if self.len() < n { result == std::option::Option::None &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) } else { result == std::option::Option::Some(?p) &*& full_borrow('a, .full_borrow_content(t, p.0)) &*& full_borrow('a, <[T]>.full_borrow_content(t, p.1)) &*& p.1.len() == self.len() - n }; + //@ on_unwind_ens false; + { + let Some((first, tail)) = self.split_at_mut_checked(n) else { return None }; + //@ full_borrow_slice_prefix_as_chunk::('a, t, first, n); + let ptr = first.as_mut_ptr(); + Some((unsafe { &mut *(ptr as *mut Chunk) }, tail)) + } + + const unsafe fn split_last_chunk_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> Option<(&'a [T], &'a Chunk)> + //@ req thread_token(?t) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& if self.len() < n { result == std::option::Option::None } else { result == std::option::Option::Some(?p) &*& [_](<[T]>.share('a, t, p.0)) &*& [_](.share('a, t, p.1)) &*& p.0.len() == self.len() - n }; + //@ on_unwind_ens false; + { + let Some(index) = self.len().checked_sub(n) else { return None }; + let (init, last) = self.split_at(index); + //@ share_slice_prefix_as_chunk::('a, t, last, n); + Some((init, unsafe { &*(last.as_ptr() as *const Chunk) })) //~ignore_ref_creation + } + + const unsafe fn split_last_chunk_mut_proof__VeriFast_wrapper<'a, Chunk>( + &'a mut self, + n: usize, + ) -> Option<(&'a mut [T], &'a mut Chunk)> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& if self.len() < n { result == std::option::Option::None &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) } else { result == std::option::Option::Some(?p) &*& full_borrow('a, <[T]>.full_borrow_content(t, p.0)) &*& full_borrow('a, .full_borrow_content(t, p.1)) &*& p.0.len() == self.len() - n }; + //@ on_unwind_ens false; + { + let Some(index) = self.len().checked_sub(n) else { return None }; + let (init, last) = self.split_at_mut(index); + //@ full_borrow_slice_prefix_as_chunk::('a, t, last, n); + let ptr = last.as_mut_ptr(); + Some((init, unsafe { &mut *(ptr as *mut Chunk) })) + } + + const unsafe fn last_chunk_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> Option<&'a Chunk> + //@ req thread_token(?t) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& if self.len() < n { result == std::option::Option::None } else { result == std::option::Option::Some(?r) &*& [_](.share('a, t, r)) &*& r == ((strip_pointer_metadata(self as pointer) as *T) + (self.len() - n)) as *Chunk }; + //@ on_unwind_ens false; + { + let Some(index) = self.len().checked_sub(n) else { return None }; + let (_, last) = self.split_at(index); + //@ share_slice_prefix_as_chunk::('a, t, last, n); + Some(unsafe { &*(last.as_ptr() as *const Chunk) }) //~ignore_ref_creation + } + + const unsafe fn last_chunk_mut_proof__VeriFast_wrapper<'a, Chunk>(&'a mut self, n: usize) -> Option<&'a mut Chunk> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& if self.len() < n { result == std::option::Option::None &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) } else { result == std::option::Option::Some(?r) &*& full_borrow('a, .full_borrow_content(t, r)) &*& r == ((strip_pointer_metadata(self as pointer) as *T) + (self.len() - n)) as *Chunk }; + //@ on_unwind_ens false; + { + let Some(index) = self.len().checked_sub(n) else { return None }; + let (_, last) = self.split_at_mut(index); + //@ leak full_borrow('a, _); + //@ full_borrow_slice_prefix_as_chunk::('a, t, last, n); + let ptr = last.as_mut_ptr(); + Some(unsafe { &mut *(ptr as *mut Chunk) }) + } + + /// Returns a reference to an element or subslice depending on the type of + /// index. + /// + /// - If given a position, returns a reference to the element at that + /// position or `None` if out of bounds. + /// - If given a range, returns the subslice corresponding to that range, + /// or `None` if out of bounds. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&40), v.get(1)); + /// assert_eq!(Some(&[10, 40][..]), v.get(0..2)); + /// assert_eq!(None, v.get(3)); + /// assert_eq!(None, v.get(0..4)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get(&self, index: I) -> Option<&I::Output> + where + I: [const] SliceIndex, + { + index.get(self) + } + + /// Returns a mutable reference to an element or subslice depending on the + /// type of index (see [`get`]) or `None` if the index is out of bounds. + /// + /// [`get`]: slice::get + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(elem) = x.get_mut(1) { + /// *elem = 42; + /// } + /// assert_eq!(x, &[0, 42, 2]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[rustc_no_writable] + pub const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where + I: [const] SliceIndex, + { + index.get_mut(self) + } + + /// Returns a reference to an element or subslice, without doing bounds + /// checking. + /// + /// For a safe alternative see [`get`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. + /// + /// You can think of this like `.get(index).unwrap_unchecked()`. It's UB + /// to call `.get_unchecked(len)`, even if you immediately convert to a + /// pointer. And it's UB to call `.get_unchecked(..len + 1)`, + /// `.get_unchecked(..=len)`, or similar. + /// + /// [`get`]: slice::get + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// + /// unsafe { + /// assert_eq!(x.get_unchecked(1), &2); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[track_caller] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, index)))] + pub const unsafe fn get_unchecked(&self, index: I) -> &I::Output + where + I: [const] SliceIndex, + //@ req thread_token(?t) &*& [_](<[T]>.share(?k, t, self)) &*& std::slice::SliceIndex_in_bounds::(index, self); + //@ ens thread_token(t) &*& [_](< >::Output>.share(k, t, result)); + //@ on_unwind_ens false; + { + // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`; + // the slice is dereferenceable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &*index.get_unchecked(self) } //~ignore_ref_creation + } + + /// Returns a mutable reference to an element or subslice, without doing + /// bounds checking. + /// + /// For a safe alternative see [`get_mut`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. + /// + /// You can think of this like `.get_mut(index).unwrap_unchecked()`. It's + /// UB to call `.get_unchecked_mut(len)`, even if you immediately convert + /// to a pointer. And it's UB to call `.get_unchecked_mut(..len + 1)`, + /// `.get_unchecked_mut(..=len)`, or similar. + /// + /// [`get_mut`]: slice::get_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// + /// unsafe { + /// let elem = x.get_unchecked_mut(1); + /// *elem = 13; + /// } + /// assert_eq!(x, &[1, 13, 4]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[track_caller] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, index)))] + #[rustc_no_writable] + pub const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + where + I: [const] SliceIndex, + //@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, self)) &*& std::slice::SliceIndex_in_bounds::(index, self); + //@ ens thread_token(t) &*& full_borrow(k, < >::Output>.full_borrow_content(t, result)); + //@ on_unwind_ens false; + { + // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`; + // the slice is dereferenceable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &mut *index.get_unchecked_mut(self) } + } + + /// Returns a raw pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up dangling. + /// + /// The caller must also ensure that the memory the pointer (non-transitively) points to + /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer + /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`]. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let x_ptr = x.as_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// assert_eq!(x.get_unchecked(i), &*x_ptr.add(i)); + /// } + /// } + /// ``` + /// + /// [`as_mut_ptr`]: slice::as_mut_ptr + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] + #[rustc_never_returns_null_ptr] + #[rustc_as_ptr] + #[inline(always)] + #[must_use] + pub const fn as_ptr(&self) -> *const T + //@ req true; + //@ ens result == strip_pointer_metadata(self as pointer) as *T &*& result == self as *T; + //@ on_unwind_ens false; + { + self as *const [T] as *const T + } + + /// Returns an unsafe mutable pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up dangling. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// let x_ptr = x.as_mut_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// *x_ptr.add(i) += 2; + /// } + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[rustc_never_returns_null_ptr] + #[rustc_as_ptr] + #[inline(always)] + #[must_use] + #[rustc_no_writable] + pub const fn as_mut_ptr(&mut self) -> *mut T + //@ req true; + //@ ens result == strip_pointer_metadata(self as pointer) as *T &*& result == self as *T; + //@ on_unwind_ens false; + { + self as *mut [T] as *mut T + } + + /// Returns the two raw pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the slice. + /// + /// See [`as_ptr`] for warnings on using these pointers. The end pointer + /// requires extra caution, as it does not point to a valid element in the + /// slice. + /// + /// This function is useful for interacting with foreign interfaces which + /// use two pointers to refer to a range of elements in memory, as is + /// common in C++. + /// + /// It can also be useful to check if a pointer to an element refers to an + /// element of this slice: + /// + /// ``` + /// let a = [1, 2, 3]; + /// let x = &a[1] as *const _; + /// let y = &5 as *const _; + /// + /// assert!(a.as_ptr_range().contains(&x)); + /// assert!(!a.as_ptr_range().contains(&y)); + /// ``` + /// + /// [`as_ptr`]: slice::as_ptr + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[inline] + #[must_use] + pub const fn as_ptr_range(&self) -> Range<*const T> { + let start = self.as_ptr(); + // SAFETY: The `add` here is safe, because: + // + // - Both pointers are part of the same object, as pointing directly + // past the object also counts. + // + // - The size of the slice is never larger than `isize::MAX` bytes, as + // noted here: + // - https://github.com/rust-lang/unsafe-code-guidelines/issues/102#issuecomment-473340447 + // - https://doc.rust-lang.org/reference/behavior-considered-undefined.html + // - https://doc.rust-lang.org/core/slice/fn.from_raw_parts.html#safety + // (This doesn't seem normative yet, but the very same assumption is + // made in many places, including the Index implementation of slices.) + // + // - There is no wrapping around involved, as slices do not wrap past + // the end of the address space. + // + // See the documentation of [`pointer::add`]. + let end = unsafe { start.add(self.len()) }; + start..end + } + + /// Returns the two unsafe mutable pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the slice. + /// + /// See [`as_mut_ptr`] for warnings on using these pointers. The end + /// pointer requires extra caution, as it does not point to a valid element + /// in the slice. + /// + /// This function is useful for interacting with foreign interfaces which + /// use two pointers to refer to a range of elements in memory, as is + /// common in C++. + /// + /// [`as_mut_ptr`]: slice::as_mut_ptr + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[inline] + #[must_use] + pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> + //@ req self.len() * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(strip_pointer_metadata(self as pointer) as *T) == true &*& pointer_within_limits((strip_pointer_metadata(self as pointer) as *T) + self.len()) == true; + //@ ens result == std::ops::Range::<*T> { start: strip_pointer_metadata(self as pointer) as *T, end: (strip_pointer_metadata(self as pointer) as *T) + self.len() } &*& result.start == strip_pointer_metadata(self as pointer) as *T &*& result.start == self as *T &*& result.end == (strip_pointer_metadata(self as pointer) as *T) + self.len(); + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + close raw_ptr_own::()(_t, result.start); + close raw_ptr_own::()(_t, result.end); + close_Range_own::<*T>(_t, result); + } + @*/ + { + let start = self.as_mut_ptr(); + // SAFETY: See as_ptr_range() above for why `add` here is safe. + let end = unsafe { start.add(self.len()) }; + start..end + } + + /// Gets a reference to the underlying array. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] + #[inline] + #[must_use] + pub const fn as_array(&self) -> Option<&[T; N]> { + if self.len() == N { + let ptr = self.as_ptr().cast_array(); + + // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. + let me = unsafe { &*ptr }; + Some(me) + } else { + None + } + } + + /// Gets a mutable reference to the slice's underlying array. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] + #[inline] + #[must_use] + pub const fn as_mut_array(&mut self) -> Option<&mut [T; N]> { + if self.len() == N { + let ptr = self.as_mut_ptr().cast_array(); + + // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. + let me = unsafe { &mut *ptr }; + Some(me) + } else { + None + } + } + + /// Swaps two elements in the slice. + /// + /// If `a` equals `b`, it's guaranteed that elements won't change value. + /// + /// # Arguments + /// + /// * a - The index of the first element + /// * b - The index of the second element + /// + /// # Panics + /// + /// Panics if `a` or `b` are out of bounds. + /// + /// # Examples + /// + /// ``` + /// let mut v = ["a", "b", "c", "d", "e"]; + /// v.swap(2, 4); + /// assert!(v == ["a", "b", "e", "d", "c"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_swap", since = "1.85.0")] + #[inline] + #[track_caller] + pub const fn swap(&mut self, a: usize, b: usize) { + // Bounds checks that panic exactly like indexing would. + let _ = &self[a]; + let _ = &self[b]; + // SAFETY: `a` and `b` were checked to be in bounds above. + unsafe { + self.swap_unchecked(a, b); + } + } + + /// Swaps two elements in the slice, without doing bounds checking. + /// + /// For a safe alternative see [`swap`]. + /// + /// # Arguments + /// + /// * a - The index of the first element + /// * b - The index of the second element + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]*. + /// The caller has to ensure that `a < self.len()` and `b < self.len()`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_swap_unchecked)] + /// + /// let mut v = ["a", "b", "c", "d"]; + /// // SAFETY: we know that 1 and 3 are both indices of the slice + /// unsafe { v.swap_unchecked(1, 3) }; + /// assert!(v == ["a", "d", "c", "b"]); + /// ``` + /// + /// [`swap`]: slice::swap + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_swap_unchecked", issue = "88539")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(a, "[0,self.len())")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(b, "[0,self.len())")))] + pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) + //@ req (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems &*& a < self.len() &*& b < self.len(); + //@ ens (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> update(a, nth(b, elems), update(b, nth(a, elems), elems)); + //@ on_unwind_ens false; + { + assert_unsafe_precondition!( + check_library_ub, + "slice::swap_unchecked requires that the indices are within the slice", + ( + len: usize = self.len(), + a: usize = a, + b: usize = b, + ) => a < len && b < len, + ); + + let ptr = self.as_mut_ptr(); + //@ let len = self.len(); + //@ ptr_range_split_limits::(ptr, len, a); + //@ ptr_range_split_limits::(ptr, len, b); + /*@ + if a == b { + array_extract_elem(ptr, a); + close std::ptr::opt_pointsto::(true, ptr + a, ptr + b, nth(a, elems), _); + } else if a < b { + array_extract_elem(ptr, b); + array_extract_elem(ptr, a); + close std::ptr::opt_pointsto::(false, ptr + a, ptr + b, nth(a, elems), _); + } else { + array_extract_elem(ptr, a); + array_extract_elem(ptr, b); + close std::ptr::opt_pointsto::(false, ptr + a, ptr + b, nth(a, elems), _); + } + @*/ + // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()` + unsafe { + ptr::swap(ptr.add(a), ptr.add(b + 1)); // NEGATIVE TEST: one element past the contract's bound; verifast must reject this and the refinement checker must report that it differs from original/ + } + /*@ + if a == b { + array_insert_elem(ptr, a, len, elems); + update_overwrite(a, nth(a, elems), nth(a, elems), elems); + } else if a < b { + array_insert_elem(ptr, a, b, take(b, elems)); + take_update_lt(a, nth(b, elems), b, elems); + array_insert_elem(ptr, b, len, update(a, nth(b, elems), elems)); + update_comm(a, nth(b, elems), b, nth(a, elems), elems); + } else { + array_insert_elem(ptr, b, a, take(a, elems)); + take_update_lt(b, nth(a, elems), a, elems); + array_insert_elem(ptr, a, len, update(b, nth(a, elems), elems)); + } + @*/ + } + + /// Reverses the order of elements in the slice, in place. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 2, 3]; + /// v.reverse(); + /// assert!(v == [3, 2, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_reverse", since = "1.90.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub const fn reverse<'a>(&'a mut self) + //@ req thread_token(?t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems &*& foreach(elems, own::(t)); + //@ ens thread_token(t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems1 &*& foreach(elems1, own::(t)); + //@ on_unwind_ens false; + /*@ + safety_proof { + open_full_borrow(_q_a, 'a, slice_full_borrow_content::(_t, self)); + open slice_full_borrow_content::(_t, self)(); + call(); + close slice_full_borrow_content::(_t, self)(); + close_full_borrow(slice_full_borrow_content::(_t, self)); + leak full_borrow('a, slice_full_borrow_content::(_t, self)); + } + @*/ + { + //@ let ptr = strip_pointer_metadata(self as pointer) as *T; + //@ let len = self.len(); + let half_len = self.len() / 2; + //@ div_rem_nonneg(len, 2); + //@ ptr_range_split_limits::(ptr, len, half_len); + //@ ptr_range_split_limits::(ptr + half_len, len - half_len, len - 2 * half_len); + let Range { start, end } = self.as_mut_ptr_range(); + + // These slices will skip the middle item for an odd length, + // since that one doesn't need to move. + let (front_half, back_half) = + // SAFETY: Both are subparts of the original slice, so the memory + // range is valid, and they don't overlap because they're each only + // half (or less) of the original slice. + unsafe { + ( + slice::from_raw_parts_mut(start, half_len), + slice::from_raw_parts_mut(end.sub(half_len), half_len), + ) + }; + + // Introducing a function boundary here means that the two halves + // get `noalias` markers, allowing better optimization as LLVM + // knows that they're disjoint, unlike in the original slice. + //@ array_split(ptr, half_len); + //@ foreach_split(elems, own::(t), half_len); + //@ array_split(ptr + half_len, len - 2 * half_len); + //@ foreach_split(drop(half_len, elems), own::(t), len - 2 * half_len); + //@ assert (ptr + half_len)[..len - 2 * half_len] |-> ?elems_mid; + macro_rules! vf_revswap { + ($ghost:stmt; $a:ident, $b:ident, $n:ident) => {{ + $ghost + unsafe { revswap_proof__VeriFast_wrapper($a, $b, $n); } + }}; + ($a:ident, $b:ident, $n:ident) => { + revswap($a, $b, $n); + }; + } + vf_revswap!(/*@ assert true; @*/ front_half, back_half, half_len); + //@ assert ptr[..half_len] |-> ?elems_a1 &*& (ptr + len - half_len)[..half_len] |-> ?elems_b1; + //@ array_join(ptr + half_len); + //@ foreach_append(elems_mid, elems_b1); + //@ array_join(ptr); + //@ foreach_append(elems_a1, append(elems_mid, elems_b1)); + + #[inline] + const fn revswap(a: &mut [T], b: &mut [T], n: usize) { + debug_assert!(a.len() == n); + debug_assert!(b.len() == n); + + // Because this function is first compiled in isolation, + // this check tells LLVM that the indexing below is + // in-bounds. Then after inlining -- once the actual + // lengths of the slices are known -- it's removed. + // FIXME(const_trait_impl) replace with let (a, b) = (&mut a[..n], &mut b[..n]); + let (a, _) = a.split_at_mut(n); + let (b, _) = b.split_at_mut(n); + + let mut i = 0; + #[safety::loop_invariant(i <= n)] + #[cfg_attr(kani, + kani::loop_modifies( + unsafe {slice::from_raw_parts_mut(a.as_mut_ptr(), n)}, + unsafe {slice::from_raw_parts_mut(b.as_mut_ptr(), n)}, + &i) + )] + while i < n { + mem::swap(&mut a[i], &mut b[n - 1 - i]); + i += 1; + } + } + } + + /// Returns an iterator over the slice. + /// + /// The iterator yields all items from start to end. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let mut iterator = x.iter(); + /// + /// assert_eq!(iterator.next(), Some(&1)); + /// assert_eq!(iterator.next(), Some(&2)); + /// assert_eq!(iterator.next(), Some(&4)); + /// assert_eq!(iterator.next(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[rustc_diagnostic_item = "slice_iter"] + pub const fn iter(&self) -> Iter<'_, T> { + Iter::new(self) + } + + /// Returns an iterator that allows modifying each value. + /// + /// The iterator yields all items from start to end. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// for elem in x.iter_mut() { + /// *elem += 2; + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut::new(self) + } + + /// Returns an iterator over all contiguous windows of length + /// `size`. The windows overlap. If the slice is shorter than + /// `size`, the iterator returns no values. + /// + /// # Panics + /// + /// Panics if `size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.windows(3); + /// assert_eq!(iter.next().unwrap(), &['l', 'o', 'r']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e', 'm']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the slice is shorter than `size`: + /// + /// ``` + /// let slice = ['f', 'o', 'o']; + /// let mut iter = slice.windows(4); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// Because the [Iterator] trait cannot represent the required lifetimes, + /// there is no `windows_mut` analog to `windows`; + /// `[0,1,2].windows_mut(2).collect()` would violate [the rules of references] + /// (though a [LendingIterator] analog is possible). You can sometimes use + /// [`Cell::as_slice_of_cells`](crate::cell::Cell::as_slice_of_cells) in + /// conjunction with `windows` instead: + /// + /// [the rules of references]: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references + /// [LendingIterator]: https://blog.rust-lang.org/2022/10/28/gats-stabilization.html + /// ``` + /// use std::cell::Cell; + /// + /// let mut array = ['R', 'u', 's', 't', ' ', '2', '0', '1', '5']; + /// let slice = &mut array[..]; + /// let slice_of_cells: &[Cell] = Cell::from_mut(slice).as_slice_of_cells(); + /// for w in slice_of_cells.windows(3) { + /// Cell::swap(&w[0], &w[2]); + /// } + /// assert_eq!(array, ['s', 't', ' ', '2', '0', '1', '5', 'u', 'R']); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn windows(&self, size: usize) -> Windows<'_, T> { + let size = NonZero::new(size).expect("window size must be non-zero"); + Windows::new(self, size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`chunks_exact`] for a variant of this iterator that returns chunks of always exactly + /// `chunk_size` elements, and [`rchunks`] for the same iterator but starting at the end of the + /// slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['m']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`chunks_exact`]: slice::chunks_exact + /// [`rchunks`]: slice::rchunks + /// [`as_chunks`]: slice::as_chunks + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + Chunks::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`chunks_exact_mut`] for a variant of this iterator that returns chunks of always + /// exactly `chunk_size` elements, and [`rchunks_mut`] for the same iterator but starting at + /// the end of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.chunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 3]); + /// ``` + /// + /// [`chunks_exact_mut`]: slice::chunks_exact_mut + /// [`rchunks_mut`]: slice::rchunks_mut + /// [`as_chunks_mut`]: slice::as_chunks_mut + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksMut::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved + /// from the `remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks`]. + /// + /// See [`chunks`] for a variant of this iterator that also returns the remainder as a smaller + /// chunk, and [`rchunks_exact`] for the same iterator but starting at the end of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks_exact(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert!(iter.next().is_none()); + /// assert_eq!(iter.remainder(), &['m']); + /// ``` + /// + /// [`chunks`]: slice::chunks + /// [`rchunks_exact`]: slice::rchunks_exact + /// [`as_chunks`]: slice::as_chunks + #[stable(feature = "chunks_exact", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksExact::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be + /// retrieved from the `into_remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks_mut`]. + /// + /// See [`chunks_mut`] for a variant of this iterator that also returns the remainder as a + /// smaller chunk, and [`rchunks_exact_mut`] for the same iterator but starting at the end of + /// the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.chunks_exact_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 0]); + /// ``` + /// + /// [`chunks_mut`]: slice::chunks_mut + /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut + /// [`as_chunks_mut`]: slice::as_chunks_mut + #[stable(feature = "chunks_exact", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksExactMut::new(self, chunk_size) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// assuming that there's no remainder. + /// + /// This is the inverse operation to [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// As this is `unsafe`, consider whether you could use [`as_chunks`] or + /// [`as_rchunks`] instead, perhaps via something like + /// `if let (chunks, []) = slice.as_chunks()` or + /// `let (chunks, []) = slice.as_chunks() else { unreachable!() };`. + /// + /// [`as_chunks`]: slice::as_chunks + /// [`as_rchunks`]: slice::as_rchunks + /// + /// # Safety + /// + /// This may only be called when + /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). + /// - `N != 0`. + /// + /// # Examples + /// + /// ``` + /// let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!']; + /// let chunks: &[[char; 1]] = + /// // SAFETY: 1-element chunks never have remainder + /// unsafe { slice.as_chunks_unchecked() }; + /// assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]); + /// let chunks: &[[char; 3]] = + /// // SAFETY: The slice length (6) is a multiple of 3 + /// unsafe { slice.as_chunks_unchecked() }; + /// assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]); + /// + /// // These would be unsound: + /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5 + /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(N, "[1,)")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(len(self) % N == 0)))] + // Safety precondition from the documentation: `N != 0` and the length is a multiple of `N`. + #[requires(N != 0 && self.len().is_multiple_of(N))] + #[ensures(|chunks: &&[[T; N]]| chunks.len() == self.len() / N && chunks.as_ptr() as *const T == self.as_ptr())] + pub const unsafe fn as_chunks_unchecked<#[rustc_panics_when_zero] const N: usize>( + &self, + ) -> &[[T; N]] { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n), + ); + // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length + let new_len = unsafe { exact_div(self.len(), N) }; + // SAFETY: We cast a slice of `new_len * N` elements into + // a slice of `new_len` many `N` elements chunks. + unsafe { from_raw_parts(self.as_ptr().cast(), new_len) } + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the beginning of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (chunks, remainder) = slice.as_chunks()`, then: + /// - `chunks.len()` equals `slice.len() / N`, + /// - `remainder.len()` equals `slice.len() % N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let (chunks, remainder) = slice.as_chunks(); + /// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]); + /// assert_eq!(remainder, &['m']); + /// ``` + /// + /// If you expect the slice to be an exact multiple, you can combine + /// `let`-`else` with an empty slice pattern: + /// ``` + /// let slice = ['R', 'u', 's', 't']; + /// let (chunks, []) = slice.as_chunks::<2>() else { + /// panic!("slice didn't have even length") + /// }; + /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_chunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[[T; N]], &[T]) { + assert!(N != 0, "chunk size must be non-zero"); + let len_rounded_down = self.len() / N * N; + // SAFETY: The rounded-down value is always the same or smaller than the + // original length, and thus must be in-bounds of the slice. + let (multiple_of_n, remainder) = unsafe { self.split_at_unchecked(len_rounded_down) }; + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() }; + (array_slice, remainder) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the end of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (remainder, chunks) = slice.as_rchunks()`, then: + /// - `remainder.len()` equals `slice.len() % N`, + /// - `chunks.len()` equals `slice.len() / N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let (remainder, chunks) = slice.as_rchunks(); + /// assert_eq!(remainder, &['l']); + /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_rchunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[T], &[[T; N]]) { + assert!(N != 0, "chunk size must be non-zero"); + let len = self.len() / N; + let (remainder, multiple_of_n) = self.split_at(self.len() - len * N); + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() }; + (remainder, array_slice) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// assuming that there's no remainder. + /// + /// This is the inverse operation to [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// As this is `unsafe`, consider whether you could use [`as_chunks_mut`] or + /// [`as_rchunks_mut`] instead, perhaps via something like + /// `if let (chunks, []) = slice.as_chunks_mut()` or + /// `let (chunks, []) = slice.as_chunks_mut() else { unreachable!() };`. + /// + /// [`as_chunks_mut`]: slice::as_chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + /// + /// # Safety + /// + /// This may only be called when + /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). + /// - `N != 0`. + /// + /// # Examples + /// + /// ``` + /// let slice: &mut [char] = &mut ['l', 'o', 'r', 'e', 'm', '!']; + /// let chunks: &mut [[char; 1]] = + /// // SAFETY: 1-element chunks never have remainder + /// unsafe { slice.as_chunks_unchecked_mut() }; + /// chunks[0] = ['L']; + /// assert_eq!(chunks, &[['L'], ['o'], ['r'], ['e'], ['m'], ['!']]); + /// let chunks: &mut [[char; 3]] = + /// // SAFETY: The slice length (6) is a multiple of 3 + /// unsafe { slice.as_chunks_unchecked_mut() }; + /// chunks[1] = ['a', 'x', '?']; + /// assert_eq!(slice, &['L', 'o', 'r', 'a', 'x', '?']); + /// + /// // These would be unsound: + /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_mut() // The slice length is not a multiple of 5 + /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(N, "[1,)")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(len(self) % N == 0)))] + // Safety precondition from the documentation: `N != 0` and the length is a multiple of `N`. + #[requires(N != 0 && self.len().is_multiple_of(N))] + #[ensures(|chunks: &&mut [[T; N]]| chunks.len() == old(self.len()) / N)] + pub const unsafe fn as_chunks_unchecked_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> &mut [[T; N]] { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n) + ); + // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length + let new_len = unsafe { exact_div(self.len(), N) }; + // SAFETY: We cast a slice of `new_len * N` elements into + // a slice of `new_len` many `N` elements chunks. + unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), new_len) } + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the beginning of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (chunks, remainder) = slice.as_chunks_mut()`, then: + /// - `chunks.len()` equals `slice.len() / N`, + /// - `remainder.len()` equals `slice.len() % N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// let (chunks, remainder) = v.as_chunks_mut(); + /// remainder[0] = 9; + /// for chunk in chunks { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 9]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_chunks_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> (&mut [[T; N]], &mut [T]) { + assert!(N != 0, "chunk size must be non-zero"); + let len_rounded_down = self.len() / N * N; + // SAFETY: The rounded-down value is always the same or smaller than the + // original length, and thus must be in-bounds of the slice. + let (multiple_of_n, remainder) = unsafe { self.split_at_mut_unchecked(len_rounded_down) }; + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() }; + (array_slice, remainder) + } + + const unsafe fn as_chunks_unchecked_proof__VeriFast_wrapper( + &self, + n: usize, + ) -> &[Chunk] + //@ req [_](<[T]>.share(?k, ?t, self)) &*& is_array_of::(n) == true &*& n != 0 &*& self.len() % n == 0; + //@ ens [_](<[Chunk]>.share(k, t, result)) &*& result.len() == self.len() / n; + //@ on_unwind_ens false; + { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = n, len: usize = self.len()) => n != 0 && len.is_multiple_of(n), + ); + //@ div_rem_nonneg(self.len(), n); + let new_len = unsafe { exact_div_usize__VeriFast_wrapper(self.len(), n) }; + //@ share_slice_as_chunks::(k, t, self, n, new_len); + unsafe { from_raw_parts(self.as_ptr() as *const Chunk, new_len) } + } + + const unsafe fn as_chunks_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> (&'a [Chunk], &'a [T]) + //@ req thread_token(?t) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& n != 0 &*& [_](<[Chunk]>.share('a, t, result.0)) &*& [_](<[T]>.share('a, t, result.1)) &*& result.0.len() == self.len() / n &*& result.1.len() == self.len() % n; + //@ on_unwind_ens false; + { + assert!(n != 0, "chunk size must be non-zero"); + //@ chunk_round_down_facts(self.len(), n); + let len_rounded_down = self.len() / n * n; + let (multiple_of_n, remainder) = unsafe { self.split_at_unchecked(len_rounded_down) }; + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_proof__VeriFast_wrapper::(n) }; + (array_slice, remainder) + } + + const unsafe fn as_rchunks_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> (&'a [T], &'a [Chunk]) + //@ req thread_token(?t) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& n != 0 &*& [_](<[T]>.share('a, t, result.0)) &*& [_](<[Chunk]>.share('a, t, result.1)) &*& result.0.len() == self.len() % n &*& result.1.len() == self.len() / n; + //@ on_unwind_ens false; + { + assert!(n != 0, "chunk size must be non-zero"); + //@ chunk_round_down_facts(self.len(), n); + let len = self.len() / n; + let (remainder, multiple_of_n) = self.split_at(self.len() - len * n); + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_proof__VeriFast_wrapper::(n) }; + (remainder, array_slice) + } + + const unsafe fn as_chunks_unchecked_mut_proof__VeriFast_wrapper( + &mut self, + n: usize, + ) -> &mut [Chunk] + //@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, self)) &*& [?q]lifetime_token(k) &*& is_array_of::(n) == true &*& n != 0 &*& self.len() % n == 0; + //@ ens thread_token(t) &*& [q]lifetime_token(k) &*& full_borrow(k, <[Chunk]>.full_borrow_content(t, result)) &*& result.len() == self.len() / n; + //@ on_unwind_ens false; + { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = n, len: usize = self.len()) => n != 0 && len.is_multiple_of(n) + ); + let self_len = self.len(); + //@ div_rem_nonneg(self_len, n); + let new_len = unsafe { exact_div_usize__VeriFast_wrapper(self_len, n) }; + let ptr = self.as_mut_ptr(); + //@ full_borrow_slice_as_chunks::(k, t, self, n, new_len); + unsafe { from_raw_parts_mut(ptr as *mut Chunk, new_len) } + } + + const unsafe fn as_chunks_mut_proof__VeriFast_wrapper<'a, Chunk>( + &'a mut self, + n: usize, + ) -> (&'a mut [Chunk], &'a mut [T]) + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& n != 0 &*& full_borrow('a, <[Chunk]>.full_borrow_content(t, result.0)) &*& full_borrow('a, <[T]>.full_borrow_content(t, result.1)) &*& result.0.len() == self.len() / n &*& result.1.len() == self.len() % n; + //@ on_unwind_ens false; + { + assert!(n != 0, "chunk size must be non-zero"); + let self_len = self.len(); + //@ chunk_round_down_facts(self_len, n); + let len_rounded_down = self_len / n * n; + let (multiple_of_n, remainder) = unsafe { self.split_at_mut_unchecked(len_rounded_down) }; + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut_proof__VeriFast_wrapper::(n) }; + (array_slice, remainder) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the end of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (remainder, chunks) = slice.as_rchunks_mut()`, then: + /// - `remainder.len()` equals `slice.len() % N`, + /// - `chunks.len()` equals `slice.len() / N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// let (remainder, chunks) = v.as_rchunks_mut(); + /// remainder[0] = 9; + /// for chunk in chunks { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[9, 1, 1, 2, 2]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + pub const fn as_rchunks_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> (&mut [T], &mut [[T; N]]) { + assert!(N != 0, "chunk size must be non-zero"); + let len = self.len() / N; + let (remainder, multiple_of_n) = self.split_at_mut(self.len() - len * N); + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() }; + (remainder, array_slice) + } + + /// Returns an iterator over overlapping windows of `N` elements of a slice, + /// starting at the beginning of the slice. + /// + /// This is the const generic equivalent of [`windows`]. + /// + /// If `N` is greater than the size of the slice, it will return no windows. + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = [0, 1, 2, 3]; + /// let mut iter = slice.array_windows(); + /// assert_eq!(iter.next().unwrap(), &[0, 1]); + /// assert_eq!(iter.next().unwrap(), &[1, 2]); + /// assert_eq!(iter.next().unwrap(), &[2, 3]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`windows`]: slice::windows + #[stable(feature = "array_windows", since = "1.94.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn array_windows<#[rustc_panics_when_zero] const N: usize>( + &self, + ) -> ArrayWindows<'_, T, N> { + assert!(N != 0, "window size must be non-zero"); + ArrayWindows::new(self) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`rchunks_exact`] for a variant of this iterator that returns chunks of always exactly + /// `chunk_size` elements, and [`chunks`] for the same iterator but starting at the beginning + /// of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.rchunks(2); + /// assert_eq!(iter.next().unwrap(), &['e', 'm']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r']); + /// assert_eq!(iter.next().unwrap(), &['l']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`rchunks_exact`]: slice::rchunks_exact + /// [`chunks`]: slice::chunks + /// [`as_rchunks`]: slice::as_rchunks + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunks::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`rchunks_exact_mut`] for a variant of this iterator that returns chunks of always + /// exactly `chunk_size` elements, and [`chunks_mut`] for the same iterator but starting at the + /// beginning of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.rchunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[3, 2, 2, 1, 1]); + /// ``` + /// + /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut + /// [`chunks_mut`]: slice::chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksMut::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// end of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved + /// from the `remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`rchunks`]. + /// + /// See [`rchunks`] for a variant of this iterator that also returns the remainder as a smaller + /// chunk, and [`chunks_exact`] for the same iterator but starting at the beginning of the + /// slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.rchunks_exact(2); + /// assert_eq!(iter.next().unwrap(), &['e', 'm']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r']); + /// assert!(iter.next().is_none()); + /// assert_eq!(iter.remainder(), &['l']); + /// ``` + /// + /// [`chunks`]: slice::chunks + /// [`rchunks`]: slice::rchunks + /// [`chunks_exact`]: slice::chunks_exact + /// [`as_rchunks`]: slice::as_rchunks + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksExact::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be + /// retrieved from the `into_remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks_mut`]. + /// + /// See [`rchunks_mut`] for a variant of this iterator that also returns the remainder as a + /// smaller chunk, and [`chunks_exact_mut`] for the same iterator but starting at the beginning + /// of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.rchunks_exact_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[0, 2, 2, 1, 1]); + /// ``` + /// + /// [`chunks_mut`]: slice::chunks_mut + /// [`rchunks_mut`]: slice::rchunks_mut + /// [`chunks_exact_mut`]: slice::chunks_exact_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksExactMut::new(self, chunk_size) + } + + /// Returns an iterator over the slice producing non-overlapping runs + /// of elements using the predicate to separate them. + /// + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. + /// + /// # Examples + /// + /// ``` + /// let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; + /// + /// let mut iter = slice.chunk_by(|a, b| a == b); + /// + /// assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + /// assert_eq!(iter.next(), Some(&[3, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// This method can be used to extract the sorted subslices: + /// + /// ``` + /// let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4]; + /// + /// let mut iter = slice.chunk_by(|a, b| a <= b); + /// + /// assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 3, 4][..])); + /// assert_eq!(iter.next(), None); + /// ``` + #[stable(feature = "slice_group_by", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + pub const fn chunk_by(&self, pred: F) -> ChunkBy<'_, T, F> + where + F: FnMut(&T, &T) -> bool, + { + ChunkBy::new(self, pred) + } + + /// Returns an iterator over the slice producing non-overlapping mutable + /// runs of elements using the predicate to separate them. + /// + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. + /// + /// # Examples + /// + /// ``` + /// let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; + /// + /// let mut iter = slice.chunk_by_mut(|a, b| a == b); + /// + /// assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); + /// assert_eq!(iter.next(), Some(&mut [3, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// This method can be used to extract the sorted subslices: + /// + /// ``` + /// let slice = &mut [1, 1, 2, 3, 2, 3, 2, 3, 4]; + /// + /// let mut iter = slice.chunk_by_mut(|a, b| a <= b); + /// + /// assert_eq!(iter.next(), Some(&mut [1, 1, 2, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 3, 4][..])); + /// assert_eq!(iter.next(), None); + /// ``` + #[stable(feature = "slice_group_by", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + pub const fn chunk_by_mut(&mut self, pred: F) -> ChunkByMut<'_, T, F> + where + F: FnMut(&T, &T) -> bool, + { + ChunkByMut::new(self, pred) + } + + /// Divides one slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. For a non-panicking alternative see + /// [`split_at_checked`](slice::split_at_checked). + /// + /// # Examples + /// + /// ``` + /// let v = ['a', 'b', 'c']; + /// + /// { + /// let (left, right) = v.split_at(0); + /// assert_eq!(left, []); + /// assert_eq!(right, ['a', 'b', 'c']); + /// } + /// + /// { + /// let (left, right) = v.split_at(2); + /// assert_eq!(left, ['a', 'b']); + /// assert_eq!(right, ['c']); + /// } + /// + /// { + /// let (left, right) = v.split_at(3); + /// assert_eq!(left, ['a', 'b', 'c']); + /// assert_eq!(right, []); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "1.71.0")] + #[inline] + #[track_caller] + #[must_use] + pub const fn split_at<'a>(&'a self, mid: usize) -> (&'a [T], &'a [T]) + //@ req thread_token(?t) &*& [_](<[T]>.share(?k, t, self)); + //@ ens thread_token(t) &*& mid <= self.len() &*& [_](<[T]>.share(k, t, result.0)) &*& [_](<[T]>.share(k, t, result.1)) &*& strip_pointer_metadata(result.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& result.0 as *T == self as *T &*& result.0.len() == mid &*& strip_pointer_metadata(result.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& result.1.len() == self.len() - mid; + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + close_slice_pair_own::<'a, T>(_t, result); + } + @*/ + { + match self.split_at_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), + } + } + + /// Divides one mutable slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. For a non-panicking alternative see + /// [`split_at_mut_checked`](slice::split_at_mut_checked). + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// let (left, right) = v.split_at_mut(2); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[track_caller] + #[must_use] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + pub const fn split_at_mut<'a>(&'a mut self, mid: usize) -> (&'a mut [T], &'a mut [T]) + //@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, self)) &*& [?q]lifetime_token(k); + //@ ens thread_token(t) &*& [q]lifetime_token(k) &*& mid <= self.len() &*& full_borrow(k, <[T]>.full_borrow_content(t, result.0)) &*& full_borrow(k, <[T]>.full_borrow_content(t, result.1)) &*& result.0 == ptr::mk_slice::(strip_pointer_metadata(self as pointer) as *T, mid) &*& strip_pointer_metadata(result.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& result.0 as *T == self as *T &*& result.0.len() == mid &*& strip_pointer_metadata(result.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& result.1.len() == self.len() - mid; + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + close_mut_slice_pair_own::<'a, T>(_t, result); + } + @*/ + { + match self.split_at_mut_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), + } + } + + /// Divides one slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at`]: slice::split_at + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let v = ['a', 'b', 'c']; + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(0); + /// assert_eq!(left, []); + /// assert_eq!(right, ['a', 'b', 'c']); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(2); + /// assert_eq!(left, ['a', 'b']); + /// assert_eq!(right, ['c']); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(3); + /// assert_eq!(left, ['a', 'b', 'c']); + /// assert_eq!(right, []); + /// } + /// ``` + #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_split_at_unchecked", since = "1.77.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(mid, [0,self.len()])))] + pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) + //@ req [_](<[T]>.share(?k, ?t, self)) &*& mid <= self.len(); + //@ ens [_](<[T]>.share(k, t, result.0)) &*& [_](<[T]>.share(k, t, result.1)) &*& strip_pointer_metadata(result.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& result.0 as *T == self as *T &*& result.0.len() == mid &*& strip_pointer_metadata(result.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& result.1.len() == self.len() - mid; + //@ on_unwind_ens false; + { + // FIXME(const-hack): the const function `from_raw_parts` is used to make this + // function const; previously the implementation used + // `(self.get_unchecked(..mid), self.get_unchecked(mid..))` + + let len = self.len(); + let ptr = self.as_ptr(); + + assert_unsafe_precondition!( + check_library_ub, + "slice::split_at_unchecked requires the index to be within the slice", + (mid: usize = mid, len: usize = len) => mid <= len, + ); + + //@ slice_share_inv::(k, t, self); + //@ open slice_share::()(k, t, self); + //@ array_share_split::(k, t, ptr, len, mid); + //@ ptr_range_split_limits::(ptr, len, mid); + //@ let r0 = ptr::mk_slice::(ptr, mid); + //@ let r1 = ptr::mk_slice::(ptr + mid, len - mid); + //@ close slice_share::()(k, t, r0); + //@ leak slice_share::()(k, t, r0); + //@ close slice_share::()(k, t, r1); + //@ leak slice_share::()(k, t, r1); + // SAFETY: Caller has to check that `0 <= mid <= self.len()` + unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), unchecked_sub(len, mid))) } + } + + /// Divides one mutable slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at_mut`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at_mut`]: slice::split_at_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// // scoped to restrict the lifetime of the borrows + /// unsafe { + /// let (left, right) = v.split_at_mut_unchecked(2); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(mid, [0,self.len()])))] + pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) + //@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, self)) &*& [?q]lifetime_token(k) &*& mid <= self.len(); + //@ ens thread_token(t) &*& [q]lifetime_token(k) &*& full_borrow(k, <[T]>.full_borrow_content(t, result.0)) &*& full_borrow(k, <[T]>.full_borrow_content(t, result.1)) &*& result.0 == ptr::mk_slice::(strip_pointer_metadata(self as pointer) as *T, mid) &*& strip_pointer_metadata(result.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& result.0 as *T == self as *T &*& result.0.len() == mid &*& strip_pointer_metadata(result.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& result.1.len() == self.len() - mid; + //@ on_unwind_ens false; + { + let len = self.len(); + let ptr = self.as_mut_ptr(); + + assert_unsafe_precondition!( + check_library_ub, + "slice::split_at_mut_unchecked requires the index to be within the slice", + (mid: usize = mid, len: usize = len) => mid <= len, + ); + + //@ open_full_borrow_strong_(k, <[T]>.full_borrow_content(t, self)); + //@ open slice_full_borrow_content::(t, self)(); + //@ assert array::(ptr, len, ?elems) &*& foreach(elems, own::(t)); + //@ ptr_range_split_limits::(ptr, len, mid); + /*@ + { + let r0 = ptr::mk_slice::(ptr, mid); + let r1 = ptr::mk_slice::(ptr + mid, len - mid); + array_split(ptr, mid); + foreach_split(elems, own::(t), mid); + close slice_full_borrow_content::(t, r0)(); + close slice_full_borrow_content::(t, r1)(); + close sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1))(); + produce_lem_ptr_chunk restore_full_borrow_(True, sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1)), <[T]>.full_borrow_content(t, self))() { + open True(); + open sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1))(); + open slice_full_borrow_content::(t, r0)(); + open slice_full_borrow_content::(t, r1)(); + assert array::(ptr, mid, ?elems0) &*& array::(ptr + mid, len - mid, ?elems1); + array_join(ptr); + foreach_append(elems0, elems1); + close slice_full_borrow_content::(t, self)(); + } { + close True(); + close_full_borrow_strong_(); + } + full_borrow_split(k, <[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1)); + } + @*/ + // SAFETY: Caller has to check that `0 <= mid <= self.len()`. + // + // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference + // is fine. + unsafe { + ( + from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.add(mid), unchecked_sub(len, mid)), + ) + } + } + + /// Divides one slice into two at an index, returning `None` if the slice is + /// too short. + /// + /// If `mid ≤ len`, returns a pair of slices where the first will contain all + /// indices from `[0, mid)` (excluding the index `mid` itself) and the + /// second will contain all indices from `[mid, len)` (excluding the index + /// `len` itself). + /// + /// Otherwise, if `mid > len`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = [1, -2, 3, -4, 5, -6]; + /// + /// { + /// let (left, right) = v.split_at_checked(0).unwrap(); + /// assert_eq!(left, []); + /// assert_eq!(right, [1, -2, 3, -4, 5, -6]); + /// } + /// + /// { + /// let (left, right) = v.split_at_checked(2).unwrap(); + /// assert_eq!(left, [1, -2]); + /// assert_eq!(right, [3, -4, 5, -6]); + /// } + /// + /// { + /// let (left, right) = v.split_at_checked(6).unwrap(); + /// assert_eq!(left, [1, -2, 3, -4, 5, -6]); + /// assert_eq!(right, []); + /// } + /// + /// assert_eq!(None, v.split_at_checked(7)); + /// ``` + #[stable(feature = "split_at_checked", since = "1.80.0")] + #[rustc_const_stable(feature = "split_at_checked", since = "1.80.0")] + #[inline] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_at_checked<'a>(&'a self, mid: usize) -> Option<(&'a [T], &'a [T])> + //@ req [_](<[T]>.share(?k, ?t, self)); + //@ ens if mid <= self.len() { result == std::option::Option::Some(?p) &*& [_](<[T]>.share(k, t, p.0)) &*& [_](<[T]>.share(k, t, p.1)) &*& strip_pointer_metadata(p.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& p.0 as *T == self as *T &*& p.0.len() == mid &*& strip_pointer_metadata(p.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& p.1.len() == self.len() - mid } else { result == std::option::Option::None }; + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + if mid <= self.len() { + assert result == std::option::Option::Some(?p); + close_slice_pair_own::<'a, T>(_t, p); + } + close >.own(_t, result); + } + @*/ + { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. + Some(unsafe { self.split_at_unchecked(mid) }) + } else { + None + } + } + + /// Divides one mutable slice into two at an index, returning `None` if the + /// slice is too short. + /// + /// If `mid ≤ len`, returns a pair of slices where the first will contain all + /// indices from `[0, mid)` (excluding the index `mid` itself) and the + /// second will contain all indices from `[mid, len)` (excluding the index + /// `len` itself). + /// + /// Otherwise, if `mid > len`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// + /// if let Some((left, right)) = v.split_at_mut_checked(2) { + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// + /// assert_eq!(None, v.split_at_mut_checked(7)); + /// ``` + #[stable(feature = "split_at_checked", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + #[inline] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_at_mut_checked<'a>(&'a mut self, mid: usize) -> Option<(&'a mut [T], &'a mut [T])> + //@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, self)) &*& [?q]lifetime_token(k); + //@ ens thread_token(t) &*& [q]lifetime_token(k) &*& if mid <= self.len() { result == std::option::Option::Some(?p) &*& full_borrow(k, <[T]>.full_borrow_content(t, p.0)) &*& full_borrow(k, <[T]>.full_borrow_content(t, p.1)) &*& p.0 == ptr::mk_slice::(strip_pointer_metadata(self as pointer) as *T, mid) &*& strip_pointer_metadata(p.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& p.0 as *T == self as *T &*& p.0.len() == mid &*& strip_pointer_metadata(p.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& p.1.len() == self.len() - mid } else { result == std::option::Option::None &*& full_borrow(k, <[T]>.full_borrow_content(t, self)) }; + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + if mid <= self.len() { + assert result == std::option::Option::Some(?p); + close_mut_slice_pair_own::<'a, T>(_t, p); + } else { + leak full_borrow('a, _); + } + close >.own(_t, result); + } + @*/ + { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. + Some(unsafe { self.split_at_mut_unchecked(mid) }) + } else { + None + } + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the first element is matched, an empty slice will be the first item + /// returned by the iterator. Similarly, if the last element in the slice + /// is matched, an empty slice will be the last item returned by the + /// iterator: + /// + /// ``` + /// let slice = [10, 40, 33]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If two matched elements are directly adjacent, an empty slice will be + /// present between them: + /// + /// ``` + /// let slice = [10, 6, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split(&self, pred: F) -> Split<'_, T, F> + where + F: FnMut(&T) -> bool, + { + Split::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_mut(|num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_mut(&mut self, pred: F) -> SplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is contained in the end of the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the last element of the slice is matched, + /// that element will be considered the terminator of the preceding slice. + /// That slice will be the last item returned by the iterator. + /// + /// ``` + /// let slice = [3, 10, 40, 33]; + /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[3]); + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[inline] + pub fn split_inclusive(&self, pred: F) -> SplitInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitInclusive::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is contained in the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_inclusive_mut(|num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; + /// } + /// assert_eq!(v, [10, 40, 1, 20, 1, 1]); + /// ``` + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[inline] + pub fn split_inclusive_mut(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitInclusiveMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, starting at the end of the slice and working backwards. + /// The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let mut iter = slice.rsplit(|num| *num == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[44, 55]); + /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// As with `split()`, if the first or last element is matched, an empty + /// slice will be the first (or last) item returned by the iterator. + /// + /// ``` + /// let v = &[0, 1, 1, 2, 3, 5, 8]; + /// let mut it = v.rsplit(|n| *n % 2 == 0); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next().unwrap(), &[3, 5]); + /// assert_eq!(it.next().unwrap(), &[1, 1]); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next(), None); + /// ``` + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplit::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, starting at the end of the slice and working + /// backwards. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [100, 400, 300, 200, 600, 500]; + /// + /// let mut count = 0; + /// for group in v.rsplit_mut(|num| *num % 3 == 0) { + /// count += 1; + /// group[0] = count; + /// } + /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); + /// ``` + /// + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once by numbers divisible by 3 (i.e., `[10, 40]`, + /// `[20, 60, 50]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn(2, |num| *num % 3 == 0) { + /// println!("{group:?}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn(&self, n: usize, pred: F) -> SplitN<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitN::new(self.split(pred), n) + } + + /// Returns an iterator over mutable subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 50]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitNMut::new(self.split_mut(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once, starting from the end, by numbers divisible + /// by 3 (i.e., `[50]`, `[10, 40, 30, 20]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplitn(2, |num| *num % 3 == 0) { + /// println!("{group:?}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitN::new(self.rsplit(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut s = [10, 40, 30, 20, 60, 50]; + /// + /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(s, [1, 40, 30, 20, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitNMut::new(self.rsplit_mut(pred), n) + } + + /// Splits the slice on the first element that matches the specified + /// predicate. + /// + /// If any matching elements are present in the slice, returns the prefix + /// before the match and suffix after. The matching element itself is not + /// included. If no elements match, returns `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_split_once)] + /// let s = [1, 2, 3, 2, 4]; + /// assert_eq!(s.split_once(|&x| x == 2), Some(( + /// &[1][..], + /// &[3, 2, 4][..] + /// ))); + /// assert_eq!(s.split_once(|&x| x == 0), None); + /// ``` + #[unstable(feature = "slice_split_once", issue = "112811")] + #[inline] + pub fn split_once(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { + let index = self.iter().position(pred)?; + // Slice bounds checks optimized are away (as of June 2026) + Some((&self[..index], &self[index + 1..])) + } + + /// Splits the slice on the last element that matches the specified + /// predicate. + /// + /// If any matching elements are present in the slice, returns the prefix + /// before the match and suffix after. The matching element itself is not + /// included. If no elements match, returns `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_split_once)] + /// let s = [1, 2, 3, 2, 4]; + /// assert_eq!(s.rsplit_once(|&x| x == 2), Some(( + /// &[1, 2, 3][..], + /// &[4][..] + /// ))); + /// assert_eq!(s.rsplit_once(|&x| x == 0), None); + /// ``` + #[unstable(feature = "slice_split_once", issue = "112811")] + #[inline] + pub fn rsplit_once(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { + let index = self.iter().rposition(pred)?; + // Slice bounds checks optimized are away (as of June 2026) + Some((&self[..index], &self[index + 1..])) + } + + /// Returns `true` if the slice contains an element with the given value. + /// + /// This operation is *O*(*n*). + /// + /// Note that if you have a sorted slice, [`binary_search`] may be faster. + /// + /// [`binary_search`]: slice::binary_search + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.contains(&30)); + /// assert!(!v.contains(&50)); + /// ``` + /// + /// If you do not have a `&T`, but some other value that you can compare + /// with one (for example, `String` implements `PartialEq`), you can + /// use `iter().any`: + /// + /// ``` + /// let v = [String::from("hello"), String::from("world")]; // slice of `String` + /// assert!(v.iter().any(|e| e == "hello")); // search with `&str` + /// assert!(!v.iter().any(|e| e == "hi")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[must_use] + pub fn contains(&self, x: &T) -> bool + where + T: PartialEq, + { + cmp::SliceContains::slice_contains(x, self) + } + + /// Returns `true` if `needle` is a prefix of the slice or equal to the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.starts_with(&[10])); + /// assert!(v.starts_with(&[10, 40])); + /// assert!(v.starts_with(&v)); + /// assert!(!v.starts_with(&[50])); + /// assert!(!v.starts_with(&[10, 50])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.starts_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.starts_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + pub fn starts_with(&self, needle: &[T]) -> bool + where + T: PartialEq, + { + let n = needle.len(); + self.len() >= n && needle == &self[..n] + } + + /// Returns `true` if `needle` is a suffix of the slice or equal to the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.ends_with(&[30])); + /// assert!(v.ends_with(&[40, 30])); + /// assert!(v.ends_with(&v)); + /// assert!(!v.ends_with(&[50])); + /// assert!(!v.ends_with(&[50, 30])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.ends_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.ends_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + pub fn ends_with(&self, needle: &[T]) -> bool + where + T: PartialEq, + { + let (m, n) = (self.len(), needle.len()); + m >= n && needle == &self[m - n..] + } + + /// Returns a subslice with the prefix removed. + /// + /// If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`. + /// If `prefix` is empty, simply returns the original slice. If `prefix` is equal to the + /// original slice, returns an empty slice. + /// + /// If the slice does not start with `prefix`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..])); + /// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..])); + /// assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_prefix(&[50]), None); + /// assert_eq!(v.strip_prefix(&[10, 50]), None); + /// + /// let prefix : &str = "he"; + /// assert_eq!(b"hello".strip_prefix(prefix.as_bytes()), + /// Some(b"llo".as_ref())); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "slice_strip", since = "1.51.0")] + pub fn strip_prefix + ?Sized>(&self, prefix: &P) -> Option<&[T]> + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let prefix = prefix.as_slice(); + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return Some(tail); + } + } + None + } + + /// Returns a subslice with the suffix removed. + /// + /// If the slice ends with `suffix`, returns the subslice before the suffix, wrapped in `Some`. + /// If `suffix` is empty, simply returns the original slice. If `suffix` is equal to the + /// original slice, returns an empty slice. + /// + /// If the slice does not end with `suffix`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..])); + /// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..])); + /// assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_suffix(&[50]), None); + /// assert_eq!(v.strip_suffix(&[50, 30]), None); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "slice_strip", since = "1.51.0")] + pub fn strip_suffix + ?Sized>(&self, suffix: &P) -> Option<&[T]> + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let suffix = suffix.as_slice(); + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return Some(head); + } + } + None + } + + /// Returns a subslice with the prefix and suffix removed. + /// + /// If the slice starts with `prefix`, ends with `suffix`, and + /// the prefix and suffix don't overlap, returns the subslice after + /// the prefix and before the suffix, wrapped in `Some`. + /// + /// If the slice does not start with `prefix`, does not end with `suffix`, + /// or the prefix and suffix overlap in the slice, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 50, 40, 30]; + /// assert_eq!(v.strip_circumfix(&[10], &[30]), Some(&[50, 40][..])); + /// assert_eq!(v.strip_circumfix(&[10], &[40, 30]), Some(&[50][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50], &[40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_circumfix(&[50], &[30]), None); + /// assert_eq!(v.strip_circumfix(&[10], &[40]), None); + /// assert_eq!(v.strip_circumfix(&[], &[40, 30]), Some(&[10, 50][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50], &[]), Some(&[40, 30][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50, 40], &[50, 40, 30]), None); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "strip_circumfix", since = "1.98.0")] + pub fn strip_circumfix(&self, prefix: &P, suffix: &S) -> Option<&[T]> + where + T: PartialEq, + S: SlicePattern + ?Sized, + P: SlicePattern + ?Sized, + { + self.strip_prefix(prefix)?.strip_suffix(suffix) + } + + /// Returns a subslice with the optional prefix removed. + /// + /// If the slice starts with `prefix`, returns the subslice after the prefix. If `prefix` + /// is empty or the slice does not start with `prefix`, simply returns the original slice. + /// If `prefix` is equal to the original slice, returns an empty slice. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// + /// // Prefix present - removes it + /// assert_eq!(v.trim_prefix(&[10]), &[40, 30][..]); + /// assert_eq!(v.trim_prefix(&[10, 40]), &[30][..]); + /// assert_eq!(v.trim_prefix(&[10, 40, 30]), &[][..]); + /// + /// // Prefix absent - returns original slice + /// assert_eq!(v.trim_prefix(&[50]), &[10, 40, 30][..]); + /// assert_eq!(v.trim_prefix(&[10, 50]), &[10, 40, 30][..]); + /// + /// let prefix : &str = "he"; + /// assert_eq!(b"hello".trim_prefix(prefix.as_bytes()), b"llo".as_ref()); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "trim_prefix_suffix", since = "1.100.0")] + pub fn trim_prefix + ?Sized>(&self, prefix: &P) -> &[T] + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let prefix = prefix.as_slice(); + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return tail; + } + } + self + } + + /// Returns a subslice with the optional suffix removed. + /// + /// If the slice ends with `suffix`, returns the subslice before the suffix. If `suffix` + /// is empty or the slice does not end with `suffix`, simply returns the original slice. + /// If `suffix` is equal to the original slice, returns an empty slice. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// + /// // Suffix present - removes it + /// assert_eq!(v.trim_suffix(&[30]), &[10, 40][..]); + /// assert_eq!(v.trim_suffix(&[40, 30]), &[10][..]); + /// assert_eq!(v.trim_suffix(&[10, 40, 30]), &[][..]); + /// + /// // Suffix absent - returns original slice + /// assert_eq!(v.trim_suffix(&[50]), &[10, 40, 30][..]); + /// assert_eq!(v.trim_suffix(&[50, 30]), &[10, 40, 30][..]); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "trim_prefix_suffix", since = "1.100.0")] + pub fn trim_suffix + ?Sized>(&self, suffix: &P) -> &[T] + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let suffix = suffix.as_slice(); + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return head; + } + } + self + } + + /// Binary searches this slice for a given element. + /// If the slice is not sorted, the returned result is unspecified and + /// meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`]. + /// + /// [`binary_search_by`]: slice::binary_search_by + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// assert_eq!(s.binary_search(&13), Ok(9)); + /// assert_eq!(s.binary_search(&4), Err(7)); + /// assert_eq!(s.binary_search(&100), Err(13)); + /// let r = s.binary_search(&1); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + /// + /// If you want to find that whole *range* of matching items, rather than + /// an arbitrary matching one, that can be done using [`partition_point`]: + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// let low = s.partition_point(|x| x < &1); + /// assert_eq!(low, 1); + /// let high = s.partition_point(|x| x <= &1); + /// assert_eq!(high, 5); + /// let r = s.binary_search(&1); + /// assert!((low..high).contains(&r.unwrap())); + /// + /// assert!(s[..low].iter().all(|&x| x < 1)); + /// assert!(s[low..high].iter().all(|&x| x == 1)); + /// assert!(s[high..].iter().all(|&x| x > 1)); + /// + /// // For something not found, the "range" of equal items is empty + /// assert_eq!(s.partition_point(|x| x < &11), 9); + /// assert_eq!(s.partition_point(|x| x <= &11), 9); + /// assert_eq!(s.binary_search(&11), Err(9)); + /// ``` + /// + /// If you want to insert an item to a sorted vector, while maintaining + /// sort order, consider using [`partition_point`]: + /// + /// ``` + /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let num = 42; + /// let idx = s.partition_point(|&x| x <= num); + /// // If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to + /// // `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` will allow `insert` + /// // to shift less elements. + /// s.insert(idx, num); + /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "rust1", since = "1.0.0")] + pub const fn binary_search(&self, x: &T) -> Result + where + T: [const] Ord, + { + self.binary_search_by(const |p| p.cmp(x)) + } + + /// Binary searches this slice with a comparator function. + /// + /// The comparator function should return an order code that indicates + /// whether its argument is `Less`, `Equal` or `Greater` the desired + /// target. + /// If the slice is not sorted or if the comparator function does not + /// implement an order consistent with the sort order of the underlying + /// slice, the returned result is unspecified and meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`]. + /// + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// let seek = 13; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9)); + /// let seek = 4; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7)); + /// let seek = 100; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); + /// let seek = 1; + /// let r = s.binary_search_by(|probe| probe.cmp(&seek)); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub const fn binary_search_by<'a, F>(&'a self, /*@~mut@*/ mut f: F) -> Result + where + F: [const] FnMut(&'a T) -> Ordering + [const] Destruct, + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& [_](<[T]>.share('a, t, self)) &*& (.own)(t, f); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& >.own(t, result); + //@ on_unwind_ens false; + { + //@ slice_share_inv::('a, t, self); + let mut size = self.len(); + if size == 0 { + //@ close_Result_usize_own(t, std::result::Result::Err::(0)); + return Err(0); + } + let mut base = 0usize; + + // This loop intentionally doesn't have an early exit if the comparison + // returns Equal. We want the number of loop iterations to depend *only* + // on the size of the input slice so that the CPU can reliably predict + // the loop count. + while size > 1 { + //@ inv thread_token(t) &*& [q]lifetime_token('a) &*& [_](<[T]>.share('a, t, self)) &*& lifetime_token(func_lft) &*& f |-> ?f_cur &*& (.own)(t, f_cur) &*& [1/2]points_to_::(&cmp, _) &*& [1/2]points_to_::(&cmp_1, _) &*& 1 <= size &*& 0 <= base &*& base + size <= self.len(); + let half = size / 2; + //@ div_rem_nonneg(size, 2); + let mid = base + half; + + // SAFETY: the call is made safe by the following invariants: + // - `mid >= 0`: by definition + // - `mid < size`: `mid = size / 2 + size / 4 + size / 8 ...` + let f_ref = &mut f; + let cmp = unsafe { crate::call_binary_search_f__VeriFast_wrapper(self, f_ref, mid) }; + + // Binary search interacts poorly with branch prediction, so force + // the compiler to use conditional moves if supported by the target + // architecture. + base = hint::select_unpredictable(cmp == Greater, base, mid); //~ignore_ref_creation + + // This is imprecise in the case where `size` is odd and the + // comparison returns Greater: the mid element still gets included + // by `size` even though it's known to be larger than the element + // being searched for. + // + // This is fine though: we gain more performance by keeping the + // loop iteration count invariant (and thus predictable) than we + // lose from considering one additional element. + size -= half; + } + + // SAFETY: base is always in [0, size) because base <= mid. + let f_ref = &mut f; + let cmp = unsafe { crate::call_binary_search_f__VeriFast_wrapper(self, f_ref, base) }; + if cmp == Equal { //~ignore_ref_creation + // SAFETY: same as the `get_unchecked` above. + unsafe { hint::assert_unchecked(base < self.len()) }; + //@ close_Result_usize_own(t, std::result::Result::Ok::(base)); + Ok(base) + } else { + let result = base + (cmp == Less) as usize; //~ignore_ref_creation + // SAFETY: same as the `get_unchecked` above. + // Note that this is `<=`, unlike the assume in the `Ok` path. + unsafe { hint::assert_unchecked(result <= self.len()) }; + //@ close_Result_usize_own(t, std::result::Result::Err::(result)); + Err(result) + } + } + + /// Binary searches this slice with a key extraction function. + /// + /// Assumes that the slice is sorted by the key, for instance with + /// [`sort_by_key`] using the same key extraction function. + /// If the slice is not sorted by the key, the returned result is + /// unspecified and meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`]. + /// + /// [`sort_by_key`]: slice::sort_by_key + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by`]: slice::binary_search_by + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements in a slice of pairs sorted by + /// their second elements. The first is found, with a uniquely + /// determined position; the second and third are not found; the + /// fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), + /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), + /// (1, 21), (2, 34), (4, 55)]; + /// + /// assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b), Ok(9)); + /// assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b), Err(7)); + /// assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13)); + /// let r = s.binary_search_by_key(&1, |&(a, b)| b); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + // Lint rustdoc::broken_intra_doc_links is allowed as `slice::sort_by_key` is + // in crate `alloc`, and as such doesn't exists yet when building `core`: #74481. + // This breaks links when slice is displayed in core, but changing it to use relative links + // would break when the item is re-exported. So allow the core links to be broken for now. + #[allow(rustdoc::broken_intra_doc_links)] + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] + #[inline] + pub const fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result + where + F: [const] FnMut(&'a T) -> B + [const] Destruct, + B: [const] Ord + [const] Destruct, + { + self.binary_search_by(const |k| f(k).cmp(b)) + } + + /// Sorts the slice in ascending order **without** preserving the initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `T` panics. + /// + /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require + /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the + /// reflexivity requirement of [`Ord`]. By using an alternative comparison function with + /// `slice::sort_unstable_by` such as [`f32::total_cmp`] or [`f64::total_cmp`] that defines a + /// [total order] users can sort slices containing floating-point values. Alternatively, if all + /// values in the slice are guaranteed to be in a subset for which [`PartialOrd::partial_cmp`] + /// forms a [total order], it's possible to sort the slice with `sort_unstable_by(|a, b| + /// a.partial_cmp(b).unwrap())`. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if + /// the [`Ord`] implementation panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// v.sort_unstable(); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable(&mut self) + where + T: Ord, + { + sort::unstable::sort(self, &mut T::lt); + } + + /// Sorts the slice in ascending order with a comparison function, **without** preserving the + /// initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the comparison function `compare` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if `compare` panics. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the `compare` does not implement a [total order], or if + /// the `compare` itself panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4, -5, 1, -3, 2]; + /// v.sort_unstable_by(|a, b| a.cmp(b)); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// + /// // reverse sorting + /// v.sort_unstable_by(|a, b| b.cmp(a)); + /// assert_eq!(v, [4, 2, 1, -3, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by(&mut self, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + { + sort::unstable::sort(self, &mut |a, b| compare(a, b) == Ordering::Less); + } + + /// Sorts the slice in ascending order with a key extraction function, **without** preserving + /// the initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `K` panics. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4i32, -5, 1, -3, 2]; + /// + /// v.sort_unstable_by_key(|k| k.abs()); + /// assert_eq!(v, [1, 2, -3, 4, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by_key(&mut self, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, + { + sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b))); + } + + /// Partially sorts the slice in ascending order **without** preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable(0..0); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable(2..2); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable(2..3); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable(1..4); + /// assert_eq!(&v[1..4], [-3, 1, 2]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable(..); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [`sort_unstable`]: slice::sort_unstable + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable(&mut self, range: R) + where + T: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, T::lt); + } + + /// Partially sorts the slice in ascending order with a comparison function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the `compare` does not implement a total order, or if + /// the `compare` itself panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by(0..0, |a, b| b.cmp(a)); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by(2..2, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by(2..3, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by(1..4, |a, b| b.cmp(a)); + /// assert_eq!(&v[1..4], [2, 1, -3]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by(.., |a, b| b.cmp(a)); + /// assert_eq!(v, [4, 2, 1, -3, -5]); + /// ``` + /// + /// [`sort_unstable_by`]: slice::sort_unstable_by + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by(&mut self, range: R, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| compare(a, b) == Less); + } + + /// Partially sorts the slice in ascending order with a key extraction function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by_key`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `K` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4i32, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by_key(0..0, |k| k.abs()); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by_key(2..2, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by_key(2..3, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by_key(1..4, |k| k.abs()); + /// assert_eq!(&v[1..4], [2, -3, 4]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by_key(.., |k| k.abs()); + /// assert_eq!(v, [1, 2, -3, 4, -5]); + /// ``` + /// + /// [`sort_unstable_by_key`]: slice::sort_unstable_by_key + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by_key(&mut self, range: R, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| f(a).lt(&f(b))); + } + + /// Reorders the slice such that the element at `index` is at a sort-order position. All + /// elements before `index` will be `<=` to this value, and all elements after will be `>=` to + /// it. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple that partitions the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy `x <= self[index]`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy `x >= self[index]`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, and so always panics on empty slices. + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order]. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 2, -3, 1]; + /// + /// // Find the items `<=` to the median, the median itself, and the items `>=` to it. + /// let (lesser, median, greater) = v.select_nth_unstable(2); + /// + /// assert!(lesser == [-3, -5] || lesser == [-5, -3]); + /// assert_eq!(median, &mut 1); + /// assert!(greater == [4, 2] || greater == [2, 4]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [-3, -5, 1, 2, 4] || + /// v == [-5, -3, 1, 2, 4] || + /// v == [-3, -5, 1, 4, 2] || + /// v == [-5, -3, 1, 4, 2]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + where + T: Ord, + { + sort::select::partition_at_index(self, index, T::lt) + } + + /// Reorders the slice with a comparator function such that the element at `index` is at a + /// sort-order position. All elements before `index` will be `<=` to this value, and all + /// elements after will be `>=` to it, according to the comparator function. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy + /// `compare(x, self[index]).is_le()`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy + /// `compare(x, self[index]).is_ge()`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, and so always panics on empty slices. + /// + /// May panic if `compare` does not implement a [total order]. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 2, -3, 1]; + /// + /// // Find the items `>=` to the median, the median itself, and the items `<=` to it, by using + /// // a reversed comparator. + /// let (before, median, after) = v.select_nth_unstable_by(2, |a, b| b.cmp(a)); + /// + /// assert!(before == [4, 2] || before == [2, 4]); + /// assert_eq!(median, &mut 1); + /// assert!(after == [-3, -5] || after == [-5, -3]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [2, 4, 1, -5, -3] || + /// v == [2, 4, 1, -3, -5] || + /// v == [4, 2, 1, -5, -3] || + /// v == [4, 2, 1, -3, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable_by( + &mut self, + index: usize, + mut compare: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T, &T) -> Ordering, + { + sort::select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less) + } + + /// Reorders the slice with a key extraction function such that the element at `index` is at a + /// sort-order position. All elements before `index` will have keys `<=` to the key at `index`, + /// and all elements after will have keys `>=` to it. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy `f(x) <= f(self[index])`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy `f(x) >= f(self[index])`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// May panic if `K: Ord` does not implement a total order. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Find the items `<=` to the absolute median, the absolute median itself, and the items + /// // `>=` to it. + /// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs()); + /// + /// assert!(lesser == [1, 2] || lesser == [2, 1]); + /// assert_eq!(median, &mut -3); + /// assert!(greater == [4, -5] || greater == [-5, 4]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [1, 2, -3, 4, -5] || + /// v == [1, 2, -3, -5, 4] || + /// v == [2, 1, -3, 4, -5] || + /// v == [2, 1, -3, -5, 4]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable_by_key( + &mut self, + index: usize, + mut f: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T) -> K, + K: Ord, + { + sort::select::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b))) + } + + /// Moves all consecutive repeated elements to the end of the slice according to the + /// [`PartialEq`] trait implementation. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = [1, 2, 2, 3, 3, 2, 1, 1]; + /// + /// let (dedup, duplicates) = slice.partition_dedup(); + /// + /// assert_eq!(dedup, [1, 2, 3, 2, 1]); + /// assert_eq!(duplicates, [2, 3, 1]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + pub fn partition_dedup(&mut self) -> (&mut [T], &mut [T]) + where + T: PartialEq, + { + self.partition_dedup_by(|a, b| a == b) + } + + /// Moves all but the first of consecutive elements to the end of the slice that are + /// "equal" according to the given predicate function. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// The predicate `same_bucket(x, p)` is passed references to two elements from + /// the slice and must determine if the elements compare equal. The element `p` occurs + /// *before* `x` in the slice (`[.., p, .., x, ..]`), so `same_bucket(x, p)` + /// is receiving them in reversed order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. For more + /// complicated predicates however, the order (ascending vs. descending) can matter. + /// + /// Both references passed to `same_bucket` are mutable. + /// This allows merged elements in the first slice by mutating `p` and returning `true`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"]; + /// + /// let (dedup, duplicates) = slice.partition_dedup_by(|x, p| x.eq_ignore_ascii_case(p)); + /// + /// assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]); + /// assert_eq!(duplicates, ["bar", "Foo", "BAZ"]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub fn partition_dedup_by<'a, F>(&'a mut self, /*@~mut@*/ mut same_bucket: F) -> (&'a mut [T], &'a mut [T]) + where + F: FnMut(&mut T, &mut T) -> bool, + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& (.own)(t, same_bucket); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, result.0)) &*& full_borrow('a, <[T]>.full_borrow_content(t, result.1)); + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + close_mut_slice_pair_own::<'a, T>(_t, result); + } + @*/ + { + // Although we have a mutable reference to `self`, we cannot make + // *arbitrary* changes. The `same_bucket` calls could panic, so we + // must ensure that the slice is in a valid state at all times. + // + // The way that we handle this is by using swaps; we iterate + // over all the elements, swapping as we go so that at the end + // the elements we wish to keep are in the front, and those we + // wish to reject are at the back. We can then split the slice. + // This operation is still `O(n)`. + // + // Example: We start in this state, where `r` represents "next + // read" and `w` represents "next_write". + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, so + // we swap self[r] and self[w] (no effect as r==w) and then increment both + // r and w, leaving us with: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this value is a duplicate, + // so we increment `r` but leave everything else unchanged: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, + // so swap self[r] and self[w] and advance r and w: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 1 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Not a duplicate, repeat: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 3 | 1 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Duplicate, advance r. End of slice. Split at w. + + let len = self.len(); + if len <= 1 { + return (self, unsafe { empty_mut_slice_arg__VeriFast_wrapper(&mut []) }); + } + + let ptr = self.as_mut_ptr(); + let mut next_read: usize = 1; + let mut next_write: usize = 1; + + //@ open_full_borrow(q, 'a, <[T]>.full_borrow_content(t, self)); + //@ open slice_full_borrow_content::(t, self)(); + //@ assert std_tuple_2__0_::<&'a mut [T], &'a mut [T]>(?r_addr, _); + + // SAFETY: the `while` condition guarantees `next_read` and `next_write` + // are less than `len`, thus are inside `self`. `prev_ptr_write` points to + // one element before `ptr_write`, but `next_write` starts at 1, so + // `prev_ptr_write` is never less than 0 and is inside the slice. + // This fulfills the requirements for dereferencing `ptr_read`, `prev_ptr_write` + // and `ptr_write`, and for using `ptr.add(next_read)`, `ptr.add(next_write - 1)` + // and `prev_ptr_write.offset(1)`. + // + // `next_write` is also incremented at most once per loop at most meaning + // no element is skipped when it may need to be swapped. + // + // `ptr_read` and `prev_ptr_write` never point to the same element. This + // is required for `&mut *ptr_read`, `&mut *prev_ptr_write` to be safe. + // The explanation is simply that `next_read >= next_write` is always true, + // thus `next_read > next_write - 1` is too. + unsafe { + // Avoid bounds checks by using raw pointers. + while next_read < len { + //@ inv thread_token(t) &*& lifetime_token(func_lft) &*& close_full_borrow_token(<[T]>.full_borrow_content(t, self), q, 'a) &*& points_to_::<(&'a mut [T], &'a mut [T])>(r_addr, _) &*& same_bucket |-> ?sb_cur &*& (.own)(t, sb_cur) &*& ptr[..len] |-> ?elems &*& foreach(elems, own::(t)) &*& 1 <= next_write &*& next_write <= next_read &*& next_read < len &*& len == self.len() &*& len * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(ptr) == true &*& pointer_within_limits(ptr + len) == true; + //@ ptr_range_split_limits::(ptr, len, next_read); + let ptr_read = ptr.add(next_read); + //@ ptr_range_split_limits::(ptr, len, next_write - 1); + let prev_ptr_write = ptr.add(next_write - 1); + //@ array_extract_two_own::(t, ptr, next_write - 1, next_read, len); + let sb_ref = &mut same_bucket; + if !call_same_bucket__VeriFast_wrapper(&mut *ptr_read, &mut *prev_ptr_write, sb_ref) { + //@ array_insert_two_own::(t, ptr, next_write - 1, next_read, len); + if next_read != next_write { + //@ ptr_range_split_limits::(prev_ptr_write, len - (next_write - 1), 1); + let ptr_write = prev_ptr_write.add(1); + //@ array_extract_two_own::(t, ptr, next_write, next_read, len); + mem::swap(&mut *ptr_read, &mut *ptr_write); + //@ array_insert_two_own::(t, ptr, next_write, next_read, len); + } + next_write += 1; + } else { + //@ array_insert_two_own::(t, ptr, next_write - 1, next_read, len); + } + next_read += 1; + } + } + + //@ close slice_full_borrow_content::(t, self)(); + //@ close_full_borrow(<[T]>.full_borrow_content(t, self)); + + self.split_at_mut(next_write) + } + + /// Moves all but the first of consecutive elements to the end of the slice that resolve + /// to the same key. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = [10, 20, 21, 30, 30, 20, 11, 13]; + /// + /// let (dedup, duplicates) = slice.partition_dedup_by_key(|i| *i / 10); + /// + /// assert_eq!(dedup, [10, 20, 30, 20, 11]); + /// assert_eq!(duplicates, [21, 30, 13]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + pub fn partition_dedup_by_key(&mut self, mut key: F) -> (&mut [T], &mut [T]) + where + F: FnMut(&mut T) -> K, + K: PartialEq, + { + self.partition_dedup_by(|a, b| key(a) == key(b)) + } + + /// Rotates the slice in-place such that the first `mid` elements of the + /// slice move to the end while the last `self.len() - mid` elements move to + /// the front. + /// + /// After calling `rotate_left`, the element previously at index `mid` will + /// become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `mid` is greater than the length of the + /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_left(2); + /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']); + /// ``` + /// + /// Rotating a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_left(1); + /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn rotate_left(&mut self, mid: usize) + //@ req thread_token(?t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems &*& foreach(elems, own::(t)); + //@ ens thread_token(t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems1 &*& foreach(elems1, own::(t)); + //@ on_unwind_ens false; + { + assert!(mid <= self.len()); + let k = self.len() - mid; + let p = self.as_mut_ptr(); + + // SAFETY: The range `[p.add(mid) - mid, p.add(mid) + k)` is trivially + // valid for reading and writing, as required by `ptr_rotate`. + unsafe { + //@ ptr_range_split_limits::(p, self.len(), mid); + rotate::ptr_rotate(mid, p.add(mid), k); + } + } + + /// Rotates the slice in-place such that the first `self.len() - k` + /// elements of the slice move to the end while the last `k` elements move + /// to the front. + /// + /// After calling `rotate_right`, the element previously at index + /// `self.len() - k` will become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `k` is greater than the length of the + /// slice. Note that `k == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_right(2); + /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']); + /// ``` + /// + /// Rotating a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_right(1); + /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn rotate_right(&mut self, k: usize) + //@ req thread_token(?t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems &*& foreach(elems, own::(t)); + //@ ens thread_token(t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems1 &*& foreach(elems1, own::(t)); + //@ on_unwind_ens false; + { + assert!(k <= self.len()); + let mid = self.len() - k; + let p = self.as_mut_ptr(); + + // SAFETY: The range `[p.add(mid) - mid, p.add(mid) + k)` is trivially + // valid for reading and writing, as required by `ptr_rotate`. + unsafe { + //@ ptr_range_split_limits::(p, self.len(), mid); + rotate::ptr_rotate(mid, p.add(mid), k); + } + } + + /// Moves the elements of this slice `N` places to the left, returning the ones + /// that "fall off" the front, and putting `inserted` at the end. + /// + /// Equivalently, you can think of concatenating `self` and `inserted` into one + /// long sequence, then returning the left-most `N` items and the rest into `self`: + /// + /// ```text + /// self (before) inserted + /// vvvvvvvvvvvvvvv vvv + /// [1, 2, 3, 4, 5] [9] + /// ↙ ↙ ↙ ↙ ↙ ↙ + /// [1] [2, 3, 4, 5, 9] + /// ^^^ ^^^^^^^^^^^^^^^ + /// returned self (after) + /// ``` + /// + /// See also [`Self::shift_right`] and compare [`Self::rotate_left`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_shift)] + /// + /// // Same as the diagram above + /// let mut a = [1, 2, 3, 4, 5]; + /// let inserted = [9]; + /// let returned = a.shift_left(inserted); + /// assert_eq!(returned, [1]); + /// assert_eq!(a, [2, 3, 4, 5, 9]); + /// + /// // You can shift multiple items at a time + /// let mut a = *b"Hello world"; + /// assert_eq!(a.shift_left(*b" peace"), *b"Hello "); + /// assert_eq!(a, *b"world peace"); + /// + /// // The name comes from this operation's similarity to bitshifts + /// let mut a: u8 = 0b10010110; + /// a <<= 3; + /// assert_eq!(a, 0b10110000_u8); + /// let mut a: [_; 8] = [1, 0, 0, 1, 0, 1, 1, 0]; + /// a.shift_left([0; 3]); + /// assert_eq!(a, [1, 0, 1, 1, 0, 0, 0, 0]); + /// + /// // Remember you can sub-slice to affect less that the whole slice. + /// // For example, this is similar to `.remove(1)` + `.insert(4, 'Z')` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// assert_eq!(a[1..=4].shift_left(['Z']), ['b']); + /// assert_eq!(a, ['a', 'c', 'd', 'e', 'Z', 'f']); + /// + /// // If the size matches it's equivalent to `mem::replace` + /// let mut a = [1, 2, 3]; + /// assert_eq!(a.shift_left([7, 8, 9]), [1, 2, 3]); + /// assert_eq!(a, [7, 8, 9]); + /// + /// // Some of the "inserted" elements end up returned if the slice is too short + /// let mut a = []; + /// assert_eq!(a.shift_left([1, 2, 3]), [1, 2, 3]); + /// let mut a = [9]; + /// assert_eq!(a.shift_left([1, 2, 3]), [9, 1, 2]); + /// assert_eq!(a, [3]); + /// ``` + #[unstable(feature = "slice_shift", issue = "151772")] + pub const fn shift_left(&mut self, inserted: [T; N]) -> [T; N] { + if let Some(shift) = self.len().checked_sub(N) { + // SAFETY: Having just checked that the inserted/returned arrays are + // shorter than (or the same length as) the slice: + // 1. The read for the items to return is in-bounds + // 2. We can `memmove` the slice over to cover the items we're returning + // to ensure those aren't double-dropped + // 3. Then we write (in-bounds for the same reason as the read) the + // inserted items atop the items of the slice that we just duplicated + // + // And none of this can panic, so there's no risk of intermediate unwinds. + unsafe { + let ptr = self.as_mut_ptr(); + let returned = ptr.cast_array::().read(); + ptr.copy_from(ptr.add(N), shift); + ptr.add(shift).cast_array::().write(inserted); + returned + } + } else { + // SAFETY: Having checked that the slice is strictly shorter than the + // inserted/returned arrays, it means we'll be copying the whole slice + // into the returned array, but that's not enough on its own. We also + // need to copy some of the inserted array into the returned array, + // with the rest going into the slice. Because `&mut` is exclusive + // and we own both `inserted` and `returned`, they're all disjoint + // allocations from each other as we can use `nonoverlapping` copies. + // + // We avoid double-frees by `ManuallyDrop`ing the inserted items, + // since we always copy them to other locations that will drop them + // instead. Plus nothing in here can panic -- it's just memcpy three + // times -- so there's no intermediate unwinds to worry about. + unsafe { + let len = self.len(); + let slice = self.as_mut_ptr(); + let inserted = mem::ManuallyDrop::new(inserted); + let inserted = (&raw const inserted).cast::(); + + let mut returned = MaybeUninit::<[T; N]>::uninit(); + let ptr = returned.as_mut_ptr().cast::(); + ptr.copy_from_nonoverlapping(slice, len); + ptr.add(len).copy_from_nonoverlapping(inserted, N - len); + slice.copy_from_nonoverlapping(inserted.add(N - len), len); + returned.assume_init() + } + } + } + + /// Moves the elements of this slice `N` places to the right, returning the ones + /// that "fall off" the back, and putting `inserted` at the beginning. + /// + /// Equivalently, you can think of concatenating `inserted` and `self` into one + /// long sequence, then returning the right-most `N` items and the rest into `self`: + /// + /// ```text + /// inserted self (before) + /// vvv vvvvvvvvvvvvvvv + /// [0] [5, 6, 7, 8, 9] + /// ↘ ↘ ↘ ↘ ↘ ↘ + /// [0, 5, 6, 7, 8] [9] + /// ^^^^^^^^^^^^^^^ ^^^ + /// self (after) returned + /// ``` + /// + /// See also [`Self::shift_left`] and compare [`Self::rotate_right`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_shift)] + /// + /// // Same as the diagram above + /// let mut a = [5, 6, 7, 8, 9]; + /// let inserted = [0]; + /// let returned = a.shift_right(inserted); + /// assert_eq!(returned, [9]); + /// assert_eq!(a, [0, 5, 6, 7, 8]); + /// + /// // The name comes from this operation's similarity to bitshifts + /// let mut a: u8 = 0b10010110; + /// a >>= 3; + /// assert_eq!(a, 0b00010010_u8); + /// let mut a: [_; 8] = [1, 0, 0, 1, 0, 1, 1, 0]; + /// a.shift_right([0; 3]); + /// assert_eq!(a, [0, 0, 0, 1, 0, 0, 1, 0]); + /// + /// // Remember you can sub-slice to affect less that the whole slice. + /// // For example, this is similar to `.remove(4)` + `.insert(1, 'Z')` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// assert_eq!(a[1..=4].shift_right(['Z']), ['e']); + /// assert_eq!(a, ['a', 'Z', 'b', 'c', 'd', 'f']); + /// + /// // If the size matches it's equivalent to `mem::replace` + /// let mut a = [1, 2, 3]; + /// assert_eq!(a.shift_right([7, 8, 9]), [1, 2, 3]); + /// assert_eq!(a, [7, 8, 9]); + /// + /// // Some of the "inserted" elements end up returned if the slice is too short + /// let mut a = []; + /// assert_eq!(a.shift_right([1, 2, 3]), [1, 2, 3]); + /// let mut a = [9]; + /// assert_eq!(a.shift_right([1, 2, 3]), [2, 3, 9]); + /// assert_eq!(a, [1]); + /// ``` + #[unstable(feature = "slice_shift", issue = "151772")] + pub const fn shift_right(&mut self, inserted: [T; N]) -> [T; N] { + if let Some(shift) = self.len().checked_sub(N) { + // SAFETY: Having just checked that the inserted/returned arrays are + // shorter than (or the same length as) the slice: + // 1. The read for the items to return is in-bounds + // 2. We can `memmove` the slice over to cover the items we're returning + // to ensure those aren't double-dropped + // 3. Then we write (in-bounds for the same reason as the read) the + // inserted items atop the items of the slice that we just duplicated + // + // And none of this can panic, so there's no risk of intermediate unwinds. + unsafe { + let ptr = self.as_mut_ptr(); + let returned = ptr.add(shift).cast_array::().read(); + ptr.add(N).copy_from(ptr, shift); + ptr.cast_array::().write(inserted); + returned + } + } else { + // SAFETY: Having checked that the slice is strictly shorter than the + // inserted/returned arrays, it means we'll be copying the whole slice + // into the returned array, but that's not enough on its own. We also + // need to copy some of the inserted array into the returned array, + // with the rest going into the slice. Because `&mut` is exclusive + // and we own both `inserted` and `returned`, they're all disjoint + // allocations from each other as we can use `nonoverlapping` copies. + // + // We avoid double-frees by `ManuallyDrop`ing the inserted items, + // since we always copy them to other locations that will drop them + // instead. Plus nothing in here can panic -- it's just memcpy three + // times -- so there's no intermediate unwinds to worry about. + unsafe { + let len = self.len(); + let slice = self.as_mut_ptr(); + let inserted = mem::ManuallyDrop::new(inserted); + let inserted = (&raw const inserted).cast::(); + + let mut returned = MaybeUninit::<[T; N]>::uninit(); + let ptr = returned.as_mut_ptr().cast::(); + ptr.add(N - len).copy_from_nonoverlapping(slice, len); + ptr.copy_from_nonoverlapping(inserted.add(len), N - len); + slice.copy_from_nonoverlapping(inserted, len); + returned.assume_init() + } + } + } + + /// Fills `self` with elements by cloning `value`. + /// + /// # Examples + /// + /// ``` + /// let mut buf = vec![0; 10]; + /// buf.fill(1); + /// assert_eq!(buf, vec![1; 10]); + /// ``` + #[doc(alias = "memset")] + #[stable(feature = "slice_fill", since = "1.50.0")] + pub fn fill(&mut self, value: T) + where + T: Clone, + { + specialize::SpecFill::spec_fill(self, value); + } + + /// Fills `self` with elements returned by calling a closure repeatedly. + /// + /// This method uses a closure to create new values. If you'd rather + /// [`Clone`] a given value, use [`fill`]. If you want to use the [`Default`] + /// trait to generate values, you can pass [`Default::default`] as the + /// argument. + /// + /// [`fill`]: slice::fill + /// + /// # Examples + /// + /// ``` + /// let mut buf = vec![1; 10]; + /// buf.fill_with(Default::default); + /// assert_eq!(buf, vec![0; 10]); + /// ``` + #[stable(feature = "slice_fill_with", since = "1.51.0")] + pub fn fill_with(&mut self, mut f: F) + where + F: FnMut() -> T, + { + for el in self { + *el = f(); + } + } + + /// Copies the elements from `src` into `self`. + /// + /// The length of `src` must be the same as `self`. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Cloning two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. + /// dst.clone_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `clone_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].clone_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.clone_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`copy_from_slice`]: slice::copy_from_slice + /// [`split_at_mut`]: slice::split_at_mut + #[stable(feature = "clone_from_slice", since = "1.7.0")] + #[track_caller] + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + pub const fn clone_from_slice(&mut self, src: &[T]) + where + T: [const] Clone + [const] Destruct, + { + self.spec_clone_from(src); + } + + /// Copies all elements from `src` into `self`, using a memcpy. + /// + /// The length of `src` must be the same as `self`. + /// + /// If `T` does not implement `Copy`, use [`clone_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Copying two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. + /// dst.copy_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `copy_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].copy_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.copy_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`clone_from_slice`]: slice::clone_from_slice + /// [`split_at_mut`]: slice::split_at_mut + #[doc(alias = "memcpy")] + #[inline] + #[stable(feature = "copy_from_slice", since = "1.9.0")] + #[rustc_const_stable(feature = "const_copy_from_slice", since = "1.87.0")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub const fn copy_from_slice(&mut self, src: &[T]) + where + T: Copy, + //@ req thread_token(?t) &*& [_](<[T]>.share(?k, t, src)) &*& [?q]lifetime_token(k) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems_dest &*& foreach(elems_dest, own::(t)); + //@ ens thread_token(t) &*& [q]lifetime_token(k) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems_src &*& foreach(elems_src, own::(t)) &*& self.len() == src.len(); + //@ on_unwind_ens false; + { + unsafe { copy_witness__VeriFast_wrapper::() }; + // SAFETY: `T` implements `Copy`. + unsafe { copy_from_slice_impl(self, src) } + } + + /// Copies elements from one part of the slice to another part of itself, + /// using a memmove. + /// + /// `src` is the range within `self` to copy from. `dest` is the starting + /// index of the range within `self` to copy to, which will have the same + /// length as `src`. The two ranges may overlap. The ends of the two ranges + /// must be less than or equal to `self.len()`. + /// + /// # Panics + /// + /// This function will panic if either range exceeds the end of the slice, + /// or if the end of `src` is before the start. + /// + /// # Examples + /// + /// Copying four bytes within a slice: + /// + /// ``` + /// let mut bytes = *b"Hello, World!"; + /// + /// bytes.copy_within(1..5, 8); + /// + /// assert_eq!(&bytes, b"Hello, Wello!"); + /// ``` + #[inline] + #[stable(feature = "copy_within", since = "1.37.0")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub fn copy_within>(&mut self, src: R, dest: usize) + where + T: Copy, + //@ req thread_token(?t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems &*& foreach(elems, own::(t)) &*& (.own)(t, src); + //@ ens thread_token(t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems1 &*& foreach(elems1, own::(t)); + //@ on_unwind_ens false; + { + let Range { start: src_start, end: src_end } = unsafe { slice_range__VeriFast_wrapper(src, self.len()) }; + let count = src_end - src_start; + assert!(dest <= self.len() - count, "dest is out of bounds"); + // SAFETY: the conditions for `ptr::copy` have all been checked above, + // as have those for `ptr::add`. + unsafe { + // Derive both `src_ptr` and `dest_ptr` from the same loan + let ptr = self.as_mut_ptr(); + //@ let len = self.len(); + //@ ptr_range_split_limits::(ptr, len, src_start); + //@ ptr_range_split_limits::(ptr, len, dest); + let src_ptr = ptr.add(src_start); + let dest_ptr = ptr.add(dest); + //@ close ptr::copy_context::(ptr, len, src_start, dest, count, elems); + ptr::copy(src_ptr, dest_ptr, count); + copy_witness__VeriFast_wrapper::(); + //@ copy_within_foreach_own::(t, elems, src_start, dest, count); + } + } + + /// Swaps all elements in `self` with those in `other`. + /// + /// The length of `other` must be the same as `self`. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Example + /// + /// Swapping two elements across slices: + /// + /// ``` + /// let mut slice1 = [0, 0]; + /// let mut slice2 = [1, 2, 3, 4]; + /// + /// slice1.swap_with_slice(&mut slice2[2..]); + /// + /// assert_eq!(slice1, [3, 4]); + /// assert_eq!(slice2, [1, 2, 0, 0]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference to a + /// particular piece of data in a particular scope. Because of this, + /// attempting to use `swap_with_slice` on a single slice will result in + /// a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// mutable sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.swap_with_slice(&mut right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 1, 2]); + /// ``` + /// + /// [`split_at_mut`]: slice::split_at_mut + #[stable(feature = "swap_with_slice", since = "1.27.0")] + #[rustc_const_unstable(feature = "const_swap_with_slice", issue = "142204")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub const fn swap_with_slice(&mut self, other: &mut [T]) + //@ req thread_token(?t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems1 &*& foreach(elems1, own::(t)) &*& (strip_pointer_metadata(other as pointer) as *T)[..other.len()] |-> ?elems2 &*& foreach(elems2, own::(t)); + //@ ens thread_token(t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> elems2 &*& foreach(elems2, own::(t)) &*& (strip_pointer_metadata(other as pointer) as *T)[..other.len()] |-> elems1 &*& foreach(elems1, own::(t)) &*& self.len() == other.len(); + //@ on_unwind_ens false; + { + assert!(self.len() == other.len(), "destination and source slices have different lengths"); + // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was + // checked to have the same length. The slices cannot overlap because + // mutable references are exclusive. + unsafe { + ptr::swap_nonoverlapping(self.as_mut_ptr(), other.as_mut_ptr(), self.len()); + } + } + + /// Function to calculate lengths of the middle and trailing slice for `align_to{,_mut}`. + fn align_to_offsets(&self) -> (usize, usize) + //@ req thread_token(?t); + //@ ens thread_token(t) &*& <(usize, usize)>.own(t, result) &*& 0 <= result.0 &*& 0 <= result.1 &*& result.1 <= self.len() &*& if self.len() * std::mem::size_of::() <= isize::MAX && pointer_within_limits(strip_pointer_metadata(self as pointer) as *T) && pointer_within_limits((strip_pointer_metadata(self as pointer) as *T) + self.len()) && std::mem::size_of::() > 0 && std::mem::size_of::() > 0 { result.0 * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits((strip_pointer_metadata(self as pointer) as *U) + result.0) == true &*& result.0 * std::mem::size_of::() == (self.len() - result.1) * std::mem::size_of::() } else { true }; + //@ on_unwind_ens false; + //@ assume_correct + { + // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a + // lowest number of `T`s. And how many `T`s we need for each such "multiple". + // + // Consider for example T=u8 U=u16. Then we can put 1 U in 2 Ts. Simple. Now, consider + // for example a case where size_of:: = 16, size_of:: = 24. We can put 2 Us in + // place of every 3 Ts in the `rest` slice. A bit more complicated. + // + // Formula to calculate this is: + // + // Us = lcm(size_of::, size_of::) / size_of:: + // Ts = lcm(size_of::, size_of::) / size_of:: + // + // Expanded and simplified: + // + // Us = size_of:: / gcd(size_of::, size_of::) + // Ts = size_of:: / gcd(size_of::, size_of::) + // + // Luckily since all this is constant-evaluated... performance here matters not! + const fn gcd(a: usize, b: usize) -> usize { + if b == 0 { a } else { gcd(b, a % b) } + } + + // Explicitly wrap the function call in a const block so it gets + // constant-evaluated even in debug mode. + let gcd: usize = const { gcd(size_of::(), size_of::()) }; + let ts: usize = size_of::() / gcd; + let us: usize = size_of::() / gcd; + + // Armed with this knowledge, we can find how many `U`s we can fit! + let us_len = self.len() / ts * us; + // And how many `T`s will be in the trailing slice! + let ts_len = self.len() % ts; + (us_len, ts_len) + } + + const unsafe fn gcd_proof__VeriFast_wrapper(a: usize, b: usize) -> usize + //@ req a > 0 &*& b >= 0; + //@ ens result > 0 &*& result <= a &*& (b == 0 || result <= b) &*& a % result == 0 &*& b % result == 0; + //@ on_unwind_ens false; + { + if b == 0 { + //@ div_rem_nonneg_unique(a, a, 1, 0); + //@ div_rem_nonneg_unique(0, a, 0, 0); + a + } else { + //@ div_rem_nonneg(a, b); + //@ mul_mono_l(0, a / b, b); + //@ if a % b == 0 { mul_mono_l(1, a / b, b); } + let g = unsafe { Self::gcd_proof__VeriFast_wrapper(b, a % b) }; + // g | b and g | a % b imply g | a: a == g * ((a / b) * (b / g) + (a % b) / g). + //@ div_rem_nonneg(b, g); + //@ div_rem_nonneg(a % b, g); + //@ mul_assoc(a / b, b / g, g); + //@ div_rem_nonneg_unique(a, g, (a / b) * (b / g) + (a % b) / g, 0); + g + } + } + + unsafe fn align_to_offsets_proof__VeriFast_wrapper(&self) -> (usize, usize) + //@ req self.len() * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(strip_pointer_metadata(self as pointer) as *T) == true &*& pointer_within_limits((strip_pointer_metadata(self as pointer) as *T) + self.len()) == true &*& std::mem::size_of::() > 0 &*& std::mem::size_of::() > 0; + //@ ens 0 <= result.0 &*& result.0 <= isize::MAX &*& 0 <= result.1 &*& result.1 <= self.len() &*& result.0 * std::mem::size_of::() == (self.len() - result.1) * std::mem::size_of::() &*& result.0 * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits((strip_pointer_metadata(self as pointer) as *U) + result.0) == true; + //@ on_unwind_ens false; + { + let gcd: usize = unsafe { Self::gcd_proof__VeriFast_wrapper(size_of::(), size_of::()) }; + //@ div_rem_nonneg(std::mem::size_of::(), gcd); + let ts: usize = size_of::() / gcd; + //@ div_rem_nonneg(std::mem::size_of::(), gcd); + //@ mul_mono_l(1, gcd, std::mem::size_of::() / gcd); + let us: usize = size_of::() / gcd; + + //@ div_rem_nonneg(self.len(), ts); + //@ mul_mono_l(0, self.len() / ts, ts); + //@ mul_mono_l(1, ts, self.len() / ts); + //@ mul_mono_l(0, self.len() / ts, us); + //@ mul_mono_l(self.len() / ts, self.len(), us); + //@ mul_mono_l(us, std::mem::size_of::(), self.len()); + let us_len = self.len() / ts * us; + let ts_len = self.len() % ts; + // us_len * size_of::() == (len - ts_len) * size_of::(): both sides equal + // ((len / ts) * us) * (gcd * ts) == ((len / ts) * ts) * (gcd * us), using gcd | size_of::() + // and gcd | size_of::() (so size_of::() == gcd * ts and size_of::() == gcd * us). + //@ let q = self.len() / ts; + //@ mul_assoc(q, us, std::mem::size_of::()); + //@ mul_assoc(q, ts, std::mem::size_of::()); + //@ mul_assoc(us, gcd, ts); + //@ mul_assoc(ts, gcd, us); + //@ mul_assoc(q * us, gcd, ts); + //@ mul_assoc(q * ts, gcd, us); + //@ mul_assoc(q, us, gcd); + //@ mul_assoc(q, ts, gcd); + //@ mul_assoc(q * us, ts, gcd); + //@ mul_assoc(q * ts, us, gcd); + //@ mul_assoc(us, q, ts); + //@ mul_assoc(ts, q, us); + // us_len * size_of::() == (len - ts_len) * size_of::() <= len * size_of::() <= isize::MAX, + // and the end of the middle run, `self as *U + us_len`, is the same address as `self as *T + (len - ts_len)`, + // which `ptr_range_split_limits` places within limits. + //@ mul_mono_l(self.len() - ts_len, self.len(), std::mem::size_of::()); + //@ ptr_range_split_limits::(strip_pointer_metadata(self as pointer) as *T, self.len(), self.len() - ts_len); + (us_len, ts_len) + } + + /// Transmutes the slice to a slice of another type, ensuring alignment of the types is + /// maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle part will be as big as possible under + /// the given alignment constraint and element size. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Safety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// unsafe { + /// let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[stable(feature = "slice_align_to", since = "1.30.0")] + #[must_use] + //Checks if the part that will be transmuted from type T to U is valid for type U + //reuses most function logic up to use of from_raw_parts, + //where the potentially unsafe transmute occurs + #[requires( + U::IS_ZST || T::IS_ZST || { + let ptr = self.as_ptr(); + let offset = crate::ptr::align_offset(ptr, align_of::()); + offset > self.len() || { + let (_, rest) = self.split_at(offset); + let (us_len, _) = rest.align_to_offsets::(); + let middle = crate::ptr::slice_from_raw_parts(rest.as_ptr() as *const U, us_len); + crate::ub_checks::can_dereference(middle) + } + } + )] + //The following clause guarantees that middle is of maximum size within self + //If U or T are ZSTs, then middle has size zero, so we adapt the check in that case + #[ensures(|(prefix, _, suffix): &(&[T], &[U], &[T])| + ((U::IS_ZST || T::IS_ZST) && prefix.len() == self.len()) || ( + (prefix.len() * size_of::() < align_of::()) && + (suffix.len() * size_of::() < size_of::()) + ) + )] + //Either align_to just returns self in the prefix, or the 3 returned slices + //should be sequential, contiguous, and have same total length as self + #[ensures(|(prefix, middle, suffix): &(&[T], &[U], &[T])| + prefix.as_ptr() == self.as_ptr() && + (prefix.len() == self.len() || ( + ((prefix.as_ptr()).add(prefix.len()) as *const u8 == middle.as_ptr() as *const u8) && + ((middle.as_ptr()).add(middle.len()) as *const u8 == suffix.as_ptr() as *const u8) && + ((suffix.as_ptr()).add(suffix.len()) == (self.as_ptr()).add(self.len())) ) + ) + )] + #[cfg_attr(rapx, rapx::requires(ValidTransmute(T, U)))] + #[cfg_attr(rapx, rapx::verify)] + pub unsafe fn align_to<'a, U>(&'a self) -> (&'a [T], &'a [U], &'a [T]) + //@ req thread_token(?t) &*& [?q]lifetime_token(?a) &*& [_](<[T]>.share(a, t, self)) &*& valid_slice_transmute::() == true; + //@ ens thread_token(t) &*& [q]lifetime_token(a) &*& [_](<[T]>.share(a, t, result.0)) &*& [_](<[U]>.share(a, t, result.1)) &*& [_](<[T]>.share(a, t, result.2)); + //@ on_unwind_ens false; + { + // Note that most of this function will be constant-evaluated, + if U::IS_ZST || T::IS_ZST { + // handle ZSTs specially, which is – don't handle them at all. + return unsafe { (self, empty_slice__VeriFast_wrapper::<'a, U>(&[]), empty_slice__VeriFast_wrapper::<'a, T>(&[])) }; //~ignore_ref_creation + } + //@ std::alloc::is_valid_layout_size_of_align_of::(); + //@ std::alloc::is_valid_layout_size_of_align_of::(); + //@ slice_share_inv::(a, t, self); + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. + let ptr = self.as_ptr(); + // SAFETY: See the `align_to_mut` method for the detailed safety comment. + let offset = unsafe { crate::ptr::align_offset(ptr, align_of::()) }; + if offset > self.len() { + unsafe { (self, empty_slice__VeriFast_wrapper::<'a, U>(&[]), empty_slice__VeriFast_wrapper::<'a, T>(&[])) } //~ignore_ref_creation + } else { + let (left, rest) = self.split_at(offset); + //@ slice_share_inv::(a, t, rest); + let (us_len, ts_len) = rest.align_to_offsets::(); + //@ leak <(usize, usize)>.own(_, _); + //@ let rest_ptr = strip_pointer_metadata(rest as pointer) as *T; + //@ ptr_range_split_limits::(rest_ptr, rest.len(), rest.len() - ts_len); + // `offset <= self.len() < usize::MAX`, so `align_offset` did not fail and `rest_ptr == ptr + offset` is aligned for `U`. + //@ mul_mono_l(1, std::mem::size_of::(), self.len()); + //@ open slice_share::()(a, t, rest); + //@ array_share_split::(a, t, rest_ptr, rest.len(), rest.len() - ts_len); + //@ close slice_share::()(a, t, ptr::mk_slice::(rest_ptr + (rest.len() - ts_len), ts_len)); + //@ leak slice_share::()(a, t, ptr::mk_slice::(rest_ptr + (rest.len() - ts_len), ts_len)); + //@ share_transmute_prefix::(a, t, rest_ptr, rest.len() - ts_len, ptr::mk_slice::(rest_ptr as *U, us_len)); + // Inform Miri that we want to consider the "middle" pointer to be suitably aligned. + #[cfg(miri)] + crate::intrinsics::miri_promise_symbolic_alignment( + rest.as_ptr().cast(), + align_of::(), + ); + // SAFETY: now `rest` is definitely aligned, so `from_raw_parts` below is okay, + // since the caller guarantees that we can transmute `T` to `U` safely. + unsafe { + ( + left, + from_raw_parts(rest.as_ptr() as *const U, us_len), + from_raw_parts(rest.as_ptr().add(rest.len() - ts_len), ts_len), + ) + } + } + } + + + /// Transmutes the mutable slice to a mutable slice of another type, ensuring alignment of the + /// types is maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle part will be as big as possible under + /// the given alignment constraint and element size. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Safety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// unsafe { + /// let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to_mut::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[stable(feature = "slice_align_to", since = "1.30.0")] + #[must_use] + //Checks if the part that will be transmuted from type T to U is valid for type U + //reuses most function logic up to use of from_raw_parts, + //where the potentially unsafe transmute occurs + #[requires( + U::IS_ZST || T::IS_ZST || { + let ptr = self.as_ptr(); + let offset = crate::ptr::align_offset(ptr, align_of::()); + offset > self.len() || { + let (_, rest) = self.split_at(offset); + let (us_len, _) = rest.align_to_offsets::(); + let middle = crate::ptr::slice_from_raw_parts(rest.as_ptr() as *const U, us_len); + crate::ub_checks::can_dereference(middle) + } + } + )] + //The following clause guarantees that middle is of maximum size within self + //If U or T are ZSTs, then middle has size zero, so we adapt the check in that case + #[ensures(|(prefix, _, suffix): &(&mut [T], &mut [U], &mut [T])| + ((U::IS_ZST || T::IS_ZST) && prefix.len() == old(self.len())) || ( + (prefix.len() * size_of::() < align_of::()) && + (suffix.len() * size_of::() < size_of::()) + ) + )] + //Either align_to just returns self in the prefix, or the 3 returned slices + //should be sequential, contiguous, and have same total length as self + #[ensures(|(prefix, middle, suffix): &(&mut [T], &mut [U], &mut [T])| + prefix.as_ptr() == old(self.as_ptr()) && + (prefix.len() == old(self.len()) || ( + ((prefix.as_ptr()).add(prefix.len()) as *const u8 == middle.as_ptr() as *const u8) && + ((middle.as_ptr()).add(middle.len()) as *const u8 == suffix.as_ptr() as *const u8) && + ((suffix.as_ptr()).add(suffix.len()) == old((self.as_ptr()).add(self.len()))) + )) + )] + #[cfg_attr(rapx, rapx::requires(ValidTransmute(T, U)))] + #[cfg_attr(rapx, rapx::verify)] + pub unsafe fn align_to_mut<'a, U>(&'a mut self) -> (&'a mut [T], &'a mut [U], &'a mut [T]) + //@ req thread_token(?t) &*& [?q]lifetime_token(?a) &*& full_borrow(a, <[T]>.full_borrow_content(t, self)) &*& valid_slice_transmute::() == true; + //@ ens thread_token(t) &*& [q]lifetime_token(a) &*& full_borrow(a, <[T]>.full_borrow_content(t, result.0)) &*& full_borrow(a, <[U]>.full_borrow_content(t, result.1)) &*& full_borrow(a, <[T]>.full_borrow_content(t, result.2)); + //@ on_unwind_ens false; + { + // Note that most of this function will be constant-evaluated, + if U::IS_ZST || T::IS_ZST { + // handle ZSTs specially, which is – don't handle them at all. + unsafe { + let res = (&mut *self, empty_mut_slice_arg__VeriFast_wrapper::<'a, U>(&mut []), empty_mut_slice_arg__VeriFast_wrapper::<'a, T>(&mut [])); + return res; + } + } + //@ std::alloc::is_valid_layout_size_of_align_of::(); + //@ std::alloc::is_valid_layout_size_of_align_of::(); + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. + let ptr = self.as_ptr(); + // SAFETY: Here we are ensuring we will use aligned pointers for U for the + // rest of the method. This is done by passing a pointer to &[T] with an + // alignment targeted for U. + // `crate::ptr::align_offset` is called with a correctly aligned and + // valid pointer `ptr` (it comes from a reference to `self`) and with + // a size that is a power of two (since it comes from the alignment for U), + // satisfying its safety constraints. + let offset = unsafe { crate::ptr::align_offset(ptr, align_of::()) }; + if offset > self.len() { + unsafe { + let res = (&mut *self, empty_mut_slice_arg__VeriFast_wrapper::<'a, U>(&mut []), empty_mut_slice_arg__VeriFast_wrapper::<'a, T>(&mut [])); + res + } + } else { + let (left, rest) = self.split_at_mut(offset); + //@ slice_full_borrow_inv::(q, a, t, rest); + let (us_len, ts_len) = rest.align_to_offsets::(); + //@ leak <(usize, usize)>.own(_, _); + let rest_len = rest.len(); + let mut_ptr = rest.as_mut_ptr(); + //@ ptr_range_split_limits::(mut_ptr, rest_len, rest_len - ts_len); + // `offset == left.len() <= isize::MAX < usize::MAX`, so `align_offset` did not fail and `mut_ptr == ptr + offset` is aligned for `U`. + //@ slice_full_borrow_inv::(q, a, t, left); + //@ mul_mono_l(1, std::mem::size_of::(), left.len()); + //@ slice_full_borrow_split::(a, t, rest, rest_len - ts_len); + //@ full_borrow_transmute_prefix::(a, t, ptr::mk_slice::(mut_ptr, rest_len - ts_len), ptr::mk_slice::(mut_ptr as *U, us_len)); + // Inform Miri that we want to consider the "middle" pointer to be suitably aligned. + #[cfg(miri)] + crate::intrinsics::miri_promise_symbolic_alignment( + mut_ptr.cast() as *const (), + align_of::(), + ); + // We can't use `rest` again after this, that would invalidate its alias `mut_ptr`! + // SAFETY: see comments for `align_to`. + unsafe { + ( + left, + from_raw_parts_mut(mut_ptr as *mut U, us_len), + from_raw_parts_mut(mut_ptr.add(rest_len - ts_len), ts_len), + ) + } + } + } + + /// Splits a slice into a prefix, a middle of aligned SIMD types, and a suffix. + /// + /// This is a safe wrapper around [`slice::align_to`], so inherits the same + /// guarantees as that method. + /// + /// # Panics + /// + /// This will panic if the size of the SIMD type is different from + /// `LANES` times that of the scalar. + /// + /// At the time of writing, the trait restrictions on `Simd` keeps + /// that from ever happening, as only power-of-two numbers of lanes are + /// supported. It's possible that, in the future, those restrictions might + /// be lifted in a way that would make it possible to see panics from this + /// method for something like `LANES == 3`. + /// + /// # Examples + /// + /// ``` + /// #![feature(portable_simd)] + /// use core::simd::prelude::*; + /// + /// let short = &[1, 2, 3]; + /// let (prefix, middle, suffix) = short.as_simd::<4>(); + /// assert_eq!(middle, []); // Not enough elements for anything in the middle + /// + /// // They might be split in any possible way between prefix and suffix + /// let it = prefix.iter().chain(suffix).copied(); + /// assert_eq!(it.collect::>(), vec![1, 2, 3]); + /// + /// fn basic_simd_sum(x: &[f32]) -> f32 { + /// use std::ops::Add; + /// let (prefix, middle, suffix) = x.as_simd(); + /// let sums = f32x4::from_array([ + /// prefix.iter().copied().sum(), + /// 0.0, + /// 0.0, + /// suffix.iter().copied().sum(), + /// ]); + /// let sums = middle.iter().copied().fold(sums, f32x4::add); + /// sums.reduce_sum() + /// } + /// + /// let numbers: Vec = (1..101).map(|x| x as _).collect(); + /// assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0); + /// ``` + #[unstable(feature = "portable_simd", issue = "86656")] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub fn as_simd(&self) -> (&[T], &[Simd], &[T]) + where + Simd: AsRef<[T; LANES]>, + T: simd::SimdElement, + { + // These are expected to always match, as vector types are laid out like + // arrays per , but we + // might as well double-check since it'll optimize away anyhow. + assert_eq!(size_of::>(), size_of::<[T; LANES]>()); + + // SAFETY: The simd types have the same layout as arrays, just with + // potentially-higher alignment, so the de-facto transmutes are sound. + unsafe { self.align_to() } + } + + /// Splits a mutable slice into a mutable prefix, a middle of aligned SIMD types, + /// and a mutable suffix. + /// + /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same + /// guarantees as that method. + /// + /// This is the mutable version of [`slice::as_simd`]; see that for examples. + /// + /// # Panics + /// + /// This will panic if the size of the SIMD type is different from + /// `LANES` times that of the scalar. + /// + /// At the time of writing, the trait restrictions on `Simd` keeps + /// that from ever happening, as only power-of-two numbers of lanes are + /// supported. It's possible that, in the future, those restrictions might + /// be lifted in a way that would make it possible to see panics from this + /// method for something like `LANES == 3`. + #[unstable(feature = "portable_simd", issue = "86656")] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub fn as_simd_mut(&mut self) -> (&mut [T], &mut [Simd], &mut [T]) + where + Simd: AsMut<[T; LANES]>, + T: simd::SimdElement, + { + // These are expected to always match, as vector types are laid out like + // arrays per , but we + // might as well double-check since it'll optimize away anyhow. + assert_eq!(size_of::>(), size_of::<[T; LANES]>()); + + // SAFETY: The simd types have the same layout as arrays, just with + // potentially-higher alignment, so the de-facto transmutes are sound. + unsafe { self.align_to_mut() } + } + + // Transcription of `as_simd::` with `SimdVec = Simd`, `Chunk = [T; N]`, `lanes = N`. + // The two layout facts in the precondition are the `#[repr(simd)]` guarantees `as_simd` relies on + // (`Simd` has the size of `[T; N]`, element type `T`, and a possibly larger alignment that + // `align_to` accounts for); they are the caller's obligation, exactly like `is_array_of` is for the + // other const-generic wrappers, and are not assumed inside verified code. + unsafe fn as_simd_proof__VeriFast_wrapper<'a, SimdVec, Chunk>(&'a self, lanes: usize) -> (&'a [T], &'a [SimdVec], &'a [T]) + where + SimdVec: AsRef, + T: simd::SimdElement, + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(lanes) == true &*& valid_slice_transmute::() == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& [_](<[T]>.share('a, t, result.0)) &*& [_](<[SimdVec]>.share('a, t, result.1)) &*& [_](<[T]>.share('a, t, result.2)); + //@ on_unwind_ens false; + { + //@ is_array_of_layout::(lanes); + assert!(size_of::() == size_of::()); + unsafe { self.align_to() } + } + + // See `as_simd_proof__VeriFast_wrapper`. + unsafe fn as_simd_mut_proof__VeriFast_wrapper<'a, SimdVec, Chunk>(&'a mut self, lanes: usize) -> (&'a mut [T], &'a mut [SimdVec], &'a mut [T]) + where + SimdVec: AsMut, + T: simd::SimdElement, + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(lanes) == true &*& valid_slice_transmute::() == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, result.0)) &*& full_borrow('a, <[SimdVec]>.full_borrow_content(t, result.1)) &*& full_borrow('a, <[T]>.full_borrow_content(t, result.2)); + //@ on_unwind_ens false; + { + //@ is_array_of_layout::(lanes); + assert!(size_of::() == size_of::()); + unsafe { self.align_to_mut() } + } + + /// Checks if the elements of this slice are sorted. + /// + /// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the + /// slice yields exactly zero or one element, `true` is returned. + /// + /// Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition + /// implies that this function returns `false` if any two consecutive items are not + /// comparable. + /// + /// # Examples + /// + /// ``` + /// let empty: [i32; 0] = []; + /// + /// assert!([1, 2, 2, 9].is_sorted()); + /// assert!(![1, 3, 2, 4].is_sorted()); + /// assert!([0].is_sorted()); + /// assert!(empty.is_sorted()); + /// assert!(![0.0, 1.0, f32::NAN].is_sorted()); + /// ``` + #[inline] + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted(&self) -> bool + where + T: PartialOrd, + { + // This odd number works the best. 32 + 1 extra due to overlapping chunk boundaries. + const CHUNK_SIZE: usize = 33; + if self.len() < CHUNK_SIZE { + return self.windows(2).all(|w| w[0] <= w[1]); + } + let mut i = 0; + // Check in chunks for autovectorization. + while i < self.len() - CHUNK_SIZE { + let chunk = &self[i..i + CHUNK_SIZE]; + if !chunk.windows(2).fold(true, |acc, w| acc & (w[0] <= w[1])) { + return false; + } + // We need to ensure that chunk boundaries are also sorted. + // Overlap the next chunk with the last element of our last chunk. + i += CHUNK_SIZE - 1; + } + self[i..].windows(2).all(|w| w[0] <= w[1]) + } + + /// Checks if the elements of this slice are sorted using the given comparator function. + /// + /// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare` + /// function to determine whether two elements are to be considered in sorted order. + /// + /// # Examples + /// + /// ``` + /// assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b)); + /// assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b)); + /// + /// assert!([0].is_sorted_by(|a, b| true)); + /// assert!([0].is_sorted_by(|a, b| false)); + /// + /// let empty: [i32; 0] = []; + /// assert!(empty.is_sorted_by(|a, b| false)); + /// assert!(empty.is_sorted_by(|a, b| true)); + /// ``` + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted_by<'a, F>(&'a self, mut compare: F) -> bool + where + F: FnMut(&'a T, &'a T) -> bool, + { + self.array_windows().all(|[a, b]| compare(a, b)) + } + + /// Checks if the elements of this slice are sorted using the given key extraction function. + /// + /// Instead of comparing the slice's elements directly, this function compares the keys of the + /// elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see its + /// documentation for more information. + /// + /// [`is_sorted`]: slice::is_sorted + /// + /// # Examples + /// + /// ``` + /// assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); + /// assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); + /// ``` + #[inline] + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool + where + F: FnMut(&'a T) -> K, + K: PartialOrd, + { + self.iter().is_sorted_by_key(f) + } + + /// Returns the index of the partition point according to the given predicate + /// (the index of the first element of the second partition). + /// + /// The slice is assumed to be partitioned according to the given predicate. + /// This means that all elements for which the predicate returns true are at the start of the slice + /// and all elements for which the predicate returns false are at the end. + /// For example, `[7, 15, 3, 5, 4, 12, 6]` is partitioned under the predicate `x % 2 != 0` + /// (all odd numbers are at the start, all even at the end). + /// + /// If this slice is not partitioned, the returned result is unspecified and meaningless, + /// as this method performs a kind of binary search. + /// + /// See also [`binary_search`], [`binary_search_by`], and [`binary_search_by_key`]. + /// + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by`]: slice::binary_search_by + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// + /// # Examples + /// + /// ``` + /// let v = [1, 2, 3, 3, 5, 6, 7]; + /// let i = v.partition_point(|&x| x < 5); + /// + /// assert_eq!(i, 4); + /// assert!(v[..i].iter().all(|&x| x < 5)); + /// assert!(v[i..].iter().all(|&x| !(x < 5))); + /// ``` + /// + /// If all elements of the slice match the predicate, including if the slice + /// is empty, then the length of the slice will be returned: + /// + /// ``` + /// let a = [2, 4, 8]; + /// assert_eq!(a.partition_point(|x| x < &100), a.len()); + /// let a: [i32; 0] = []; + /// assert_eq!(a.partition_point(|x| x < &100), 0); + /// ``` + /// + /// If you want to insert an item to a sorted vector, while maintaining + /// sort order: + /// + /// ``` + /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let num = 42; + /// let idx = s.partition_point(|&x| x <= num); + /// s.insert(idx, num); + /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "partition_point", since = "1.52.0")] + #[must_use] + pub const fn partition_point

(&self, mut pred: P) -> usize + where + P: [const] FnMut(&T) -> bool + [const] Destruct, + { + self.binary_search_by(const |x| if pred(x) { Less } else { Greater }) + .unwrap_or_else(const |i| i) + } + + /// Removes the subslice corresponding to the given range + /// and returns a reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Splitting off the first three elements of a slice: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut first_three = slice.split_off(..3).unwrap(); + /// + /// assert_eq!(slice, &['d']); + /// assert_eq!(first_three, &['a', 'b', 'c']); + /// ``` + /// + /// Splitting off a slice starting with the third element: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut tail = slice.split_off(2..).unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(tail, &['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.split_off(5..)); + /// assert_eq!(None, slice.split_off(..5)); + /// assert_eq!(None, slice.split_off(..=4)); + /// let expected: &[char] = &['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.split_off(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[stable(feature = "slice_take", since = "1.87.0")] + pub fn split_off<'a, R: OneSidedRange>( + self: &mut &'a Self, + range: R, + ) -> Option<&'a Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = self.split_at(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the subslice corresponding to the given range + /// and returns a mutable reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Splitting off the first three elements of a slice: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut first_three = slice.split_off_mut(..3).unwrap(); + /// + /// assert_eq!(slice, &mut ['d']); + /// assert_eq!(first_three, &mut ['a', 'b', 'c']); + /// ``` + /// + /// Splitting off a slice starting with the third element: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut tail = slice.split_off_mut(2..).unwrap(); + /// + /// assert_eq!(slice, &mut ['a', 'b']); + /// assert_eq!(tail, &mut ['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.split_off_mut(5..)); + /// assert_eq!(None, slice.split_off_mut(..5)); + /// assert_eq!(None, slice.split_off_mut(..=4)); + /// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.split_off_mut(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[stable(feature = "slice_take", since = "1.87.0")] + pub fn split_off_mut<'a, R: OneSidedRange>( + self: &mut &'a mut Self, + range: R, + ) -> Option<&'a mut Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = mem::take(self).split_at_mut(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the first element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let first = slice.split_off_first().unwrap(); + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'a'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((first, rem)) = self.split_first() else { return None }; + *self = rem; + Some(first) + } + + /// Removes the first element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let first = slice.split_off_first_mut().unwrap(); + /// *first = 'd'; + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'d'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_first_mut()?` + let Some((first, rem)) = mem::replace(self, &mut []).split_first_mut() else { return None }; + *self = rem; + Some(first) + } + + /// Removes the last element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let last = slice.split_off_last().unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'c'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((last, rem)) = self.split_last() else { return None }; + *self = rem; + Some(last) + } + + /// Removes the last element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let last = slice.split_off_last_mut().unwrap(); + /// *last = 'd'; + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'d'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_last_mut()?` + let Some((last, rem)) = mem::replace(self, &mut []).split_last_mut() else { return None }; + *self = rem; + Some(last) + } + + /// Returns mutable references to many indices at once, without doing any checks. + /// + /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note + /// that this method takes an array, so all indices must be of the same type. + /// If passed an array of `usize`s this method gives back an array of mutable references + /// to single elements, while if passed an array of ranges it gives back an array of + /// mutable references to slices. + /// + /// For a safe alternative see [`get_disjoint_mut`]. + /// + /// # Safety + /// + /// Calling this method with overlapping or out-of-bounds indices is *[undefined behavior]* + /// even if the resulting references are not used. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([0, 2]); + /// *a *= 10; + /// *b *= 100; + /// } + /// assert_eq!(x, &[10, 2, 400]); + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([0..1, 1..3]); + /// a[0] = 8; + /// b[0] = 88; + /// b[1] = 888; + /// } + /// assert_eq!(x, &[8, 88, 888]); + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([1..=2, 0..=0]); + /// a[0] = 11; + /// a[1] = 111; + /// b[0] = 1; + /// } + /// assert_eq!(x, &[1, 11, 111]); + /// ``` + /// + /// [`get_disjoint_mut`]: slice::get_disjoint_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[stable(feature = "get_many_mut", since = "1.86.0")] + #[inline] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, indices)))] + #[cfg_attr(rapx, rapx::requires(NonOverlap(indices)))] + // Safety precondition from the documentation: all indices in bounds and pairwise disjoint, + // i.e. exactly what `get_disjoint_mut` checks before calling this function. + #[requires(get_disjoint_check_valid(&indices, self.len()).is_ok())] + pub unsafe fn get_disjoint_unchecked_mut( + &mut self, + indices: [I; N], + ) -> [&mut I::Output; N] + where + I: GetDisjointMutIndex + SliceIndex, + { + // NB: This implementation is written as it is because any variation of + // `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy, + // or generate worse code otherwise. This is also why we need to go + // through a raw pointer here. + let slice: *mut [T] = self; + let mut arr: MaybeUninit<[&mut I::Output; N]> = MaybeUninit::uninit(); + let arr_ptr = arr.as_mut_ptr(); + + // SAFETY: We expect `indices` to contain disjunct values that are + // in bounds of `self`. + unsafe { + for i in 0..N { + let idx = indices.get_unchecked(i).clone(); + arr_ptr.cast::<&mut I::Output>().add(i).write(&mut *slice.get_unchecked_mut(idx)); + } + arr.assume_init() + } + } + + /// Returns mutable references to many indices at once. + /// + /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note + /// that this method takes an array, so all indices must be of the same type. + /// If passed an array of `usize`s this method gives back an array of mutable references + /// to single elements, while if passed an array of ranges it gives back an array of + /// mutable references to slices. + /// + /// Returns an error if any index is out-of-bounds, or if there are overlapping indices. + /// An empty range is not considered to overlap if it is located at the beginning or at + /// the end of another range, but is considered to overlap if it is located in the middle. + /// + /// This method does a O(n^2) check to check that there are no overlapping indices, so be careful + /// when passing many indices. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [1, 2, 3]; + /// if let Ok([a, b]) = v.get_disjoint_mut([0, 2]) { + /// *a = 413; + /// *b = 612; + /// } + /// assert_eq!(v, &[413, 2, 612]); + /// + /// if let Ok([a, b]) = v.get_disjoint_mut([0..1, 1..3]) { + /// a[0] = 8; + /// b[0] = 88; + /// b[1] = 888; + /// } + /// assert_eq!(v, &[8, 88, 888]); + /// + /// if let Ok([a, b]) = v.get_disjoint_mut([1..=2, 0..=0]) { + /// a[0] = 11; + /// a[1] = 111; + /// b[0] = 1; + /// } + /// assert_eq!(v, &[1, 11, 111]); + /// ``` + #[stable(feature = "get_many_mut", since = "1.86.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub fn get_disjoint_mut( + &mut self, + indices: [I; N], + ) -> Result<[&mut I::Output; N], GetDisjointMutError> + where + I: GetDisjointMutIndex + SliceIndex, + { + get_disjoint_check_valid(&indices, self.len())?; + // SAFETY: The `get_disjoint_check_valid()` call checked that all indices + // are disjunct and in bounds. + unsafe { Ok(self.get_disjoint_unchecked_mut(indices)) } + } + + /// Returns the index that an element reference points to. + /// + /// Returns `None` if `element` does not point to the start of an element within the slice. + /// + /// This method is useful for extending slice iterators like [`slice::split`]. + /// + /// Note that this uses pointer arithmetic and **does not compare elements**. + /// To find the index of an element via comparison, use + /// [`.iter().position()`](crate::iter::Iterator::position) instead. + /// + /// # Panics + /// Panics if `T` is zero-sized. + /// + /// # Examples + /// Basic usage: + /// ``` + /// let nums: &[u32] = &[1, 7, 1, 1]; + /// let num = &nums[2]; + /// + /// assert_eq!(num, &1); + /// assert_eq!(nums.element_offset(num), Some(2)); + /// ``` + /// Returning `None` with an unaligned element: + /// ``` + /// let arr: &[[u32; 2]] = &[[0, 1], [2, 3]]; + /// let flat_arr: &[u32] = arr.as_flattened(); + /// + /// let ok_elm: &[u32; 2] = flat_arr[0..2].try_into().unwrap(); + /// let weird_elm: &[u32; 2] = flat_arr[1..3].try_into().unwrap(); + /// + /// assert_eq!(ok_elm, &[0, 1]); + /// assert_eq!(weird_elm, &[1, 2]); + /// + /// assert_eq!(arr.element_offset(ok_elm), Some(0)); // Points to element 0 + /// assert_eq!(arr.element_offset(weird_elm), None); // Points between element 0 and 1 + /// ``` + #[must_use] + #[stable(feature = "element_offset", since = "1.94.0")] + pub fn element_offset(&self, element: &T) -> Option { + if T::IS_ZST { + panic!("elements are zero-sized"); + } + + let self_start = self.as_ptr().addr(); + let elem_start = ptr::from_ref(element).addr(); + + let byte_offset = elem_start.wrapping_sub(self_start); + + if !byte_offset.is_multiple_of(size_of::()) { + return None; + } + + let offset = byte_offset / size_of::(); + + if offset < self.len() { Some(offset) } else { None } + } + + /// Returns the range of indices that a subslice points to. + /// + /// Returns `None` if `subslice` does not point within the slice or if it is not aligned with the + /// elements in the slice. + /// + /// This method **does not compare elements**. Instead, this method finds the location in the slice that + /// `subslice` was obtained from. To find the index of a subslice via comparison, instead use + /// [`.windows()`](slice::windows)[`.position()`](crate::iter::Iterator::position). + /// + /// This method is useful for extending slice iterators like [`slice::split`]. + /// + /// Note that this may return a false positive (either `Some(0..0)` or `Some(self.len()..self.len())`) + /// if `subslice` has a length of zero and points to the beginning or end of another, separate, slice. + /// + /// # Panics + /// Panics if `T` is zero-sized. + /// + /// # Examples + /// Basic usage: + /// ``` + /// use core::range::Range; + /// + /// let nums = &[0, 5, 10, 0, 0, 5]; + /// + /// let mut iter = nums + /// .split(|t| *t == 0) + /// .map(|n| nums.subslice_range(n).unwrap()); + /// + /// assert_eq!(iter.next(), Some(Range { start: 0, end: 0 })); + /// assert_eq!(iter.next(), Some(Range { start: 1, end: 3 })); + /// assert_eq!(iter.next(), Some(Range { start: 4, end: 4 })); + /// assert_eq!(iter.next(), Some(Range { start: 5, end: 6 })); + /// ``` + #[must_use] + #[stable(feature = "substr_range", since = "1.98.0")] + pub fn subslice_range(&self, subslice: &[T]) -> Option> { + if T::IS_ZST { + panic!("elements are zero-sized"); + } + + let self_start = self.as_ptr().addr(); + let subslice_start = subslice.as_ptr().addr(); + + let byte_start = subslice_start.wrapping_sub(self_start); + + if !byte_start.is_multiple_of(size_of::()) { + return None; + } + + let start = byte_start / size_of::(); + let end = start.wrapping_add(subslice.len()); + + if start <= self.len() && end <= self.len() { + Some(core::range::Range { start, end }) + } else { + None + } + } + + /// Returns the same slice `&[T]`. + /// + /// This method is redundant when used directly on `&[T]`, but + /// it helps dereferencing other "container" types to slices, + /// for example `Box<[T]>` or `Arc<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_slice(&self) -> &[T] { + self + } + + /// Returns the same slice `&mut [T]`. + /// + /// This method is redundant when used directly on `&mut [T]`, but + /// it helps dereferencing other "container" types to slices, + /// for example `Box<[T]>` or `MutexGuard<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_mut_slice(&mut self) -> &mut [T] { + self + } + + const unsafe fn as_flattened_proof__VeriFast_wrapper<'a, Elem>(&'a self, n: usize) -> &'a [Elem] + //@ req thread_token(?t) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [_](<[Elem]>.share('a, t, result)) &*& result.len() == self.len() * n; + //@ on_unwind_ens false; + { + //@ slice_share_inv::('a, t, self); + let len = if Elem::IS_ZST { + unsafe { checked_mul_or_panic__VeriFast_wrapper(self.len(), n) } + } else { + //@ std::alloc::is_valid_layout_size_of_align_of::(); + //@ flatten_non_zst_no_overflow::('a, t, self, n); + unsafe { self.len().unchecked_mul(n) } + }; + //@ share_chunks_as_flattened::('a, t, self, n, len); + unsafe { from_raw_parts(self.as_ptr() as *const Elem, len) } + } + + const unsafe fn as_flattened_mut_proof__VeriFast_wrapper<'a, Elem>(&'a mut self, n: usize) -> &'a mut [Elem] + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& full_borrow('a, <[Elem]>.full_borrow_content(t, result)) &*& result.len() == self.len() * n; + //@ on_unwind_ens false; + { + //@ slice_full_borrow_inv::(q, 'a, t, self); + let self_len = self.len(); + let len = if Elem::IS_ZST { + unsafe { checked_mul_or_panic__VeriFast_wrapper(self_len, n) } + } else { + //@ std::alloc::is_valid_layout_size_of_align_of::(); + //@ flatten_non_zst_no_overflow::('a, t, self, n); + unsafe { self_len.unchecked_mul(n) } + }; + let ptr = self.as_mut_ptr(); + //@ full_borrow_chunks_as_flattened::('a, t, self, n, len); + unsafe { from_raw_parts_mut(ptr as *mut Elem, len) } + } +} + +const unsafe fn checked_mul_or_panic__VeriFast_wrapper(a: usize, b: usize) -> usize +//@ req true; +//@ ens result == a * b &*& a * b <= usize::MAX; +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + match a.checked_mul(b) { + Some(v) => v, + None => panic!("slice len overflow"), + } +} + +impl [MaybeUninit] { + /// Transmutes the mutable uninitialized slice to a mutable uninitialized slice of + /// another type, ensuring alignment of the types is maintained. + /// + /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same + /// guarantees as that method. + /// + /// # Examples + /// + /// ``` + /// #![feature(align_to_uninit_mut)] + /// use std::mem::MaybeUninit; + /// + /// pub struct BumpAllocator<'scope> { + /// memory: &'scope mut [MaybeUninit], + /// } + /// + /// impl<'scope> BumpAllocator<'scope> { + /// pub fn new(memory: &'scope mut [MaybeUninit]) -> Self { + /// Self { memory } + /// } + /// pub fn try_alloc_uninit(&mut self) -> Option<&'scope mut MaybeUninit> { + /// let first_end = self.memory.as_ptr().align_offset(align_of::()) + size_of::(); + /// let prefix = self.memory.split_off_mut(..first_end)?; + /// Some(&mut prefix.align_to_uninit_mut::().1[0]) + /// } + /// pub fn try_alloc_u32(&mut self, value: u32) -> Option<&'scope mut u32> { + /// let uninit = self.try_alloc_uninit()?; + /// Some(uninit.write(value)) + /// } + /// } + /// + /// let mut memory = [MaybeUninit::::uninit(); 10]; + /// let mut allocator = BumpAllocator::new(&mut memory); + /// let v = allocator.try_alloc_u32(42); + /// assert_eq!(v, Some(&mut 42)); + /// ``` + #[unstable(feature = "align_to_uninit_mut", issue = "139062")] + #[inline] + #[must_use] + pub fn align_to_uninit_mut(&mut self) -> (&mut Self, &mut [MaybeUninit], &mut Self) { + // SAFETY: `MaybeUninit` is transparent. Correct size and alignment are guaranteed by + // `align_to_mut` itself. Therefore the only thing that we have to ensure for a safe + // `transmute` is that the values are valid for the types involved. But for `MaybeUninit` + // any values are valid, so this operation is safe. + unsafe { self.align_to_mut() } + } +} + +impl [[T; N]] { + /// Takes a `&[[T; N]]`, and flattens it to a `&[T]`. + /// + /// For the opposite operation, see [`as_chunks`] and [`as_rchunks`]. + /// + /// [`as_chunks`]: slice::as_chunks + /// [`as_rchunks`]: slice::as_rchunks + /// + /// # Panics + /// + /// This panics if the length of the resulting slice would overflow a `usize`. + /// + /// This is only possible when flattening a slice of arrays of zero-sized + /// types, and thus tends to be irrelevant in practice. If + /// `size_of::() > 0`, this will never panic. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([[1, 2, 3], [4, 5, 6]].as_flattened(), &[1, 2, 3, 4, 5, 6]); + /// + /// assert_eq!( + /// [[1, 2, 3], [4, 5, 6]].as_flattened(), + /// [[1, 2], [3, 4], [5, 6]].as_flattened(), + /// ); + /// + /// let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []]; + /// assert!(slice_of_empty_arrays.as_flattened().is_empty()); + /// + /// let empty_slice_of_arrays: &[[u32; 10]] = &[]; + /// assert!(empty_slice_of_arrays.as_flattened().is_empty()); + /// ``` + #[stable(feature = "slice_flatten", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidTransmute([T; N], T)))] + pub const fn as_flattened(&self) -> &[T] { + let len = if T::IS_ZST { + self.len().checked_mul(N).expect("slice len overflow") + } else { + // SAFETY: `self.len() * N` cannot overflow because `self` is + // already in the address space. + unsafe { self.len().unchecked_mul(N) } + }; + // SAFETY: `[T]` is layout-identical to `[T; N]` + unsafe { from_raw_parts(self.as_ptr().cast(), len) } + } + + /// Takes a `&mut [[T; N]]`, and flattens it to a `&mut [T]`. + /// + /// For the opposite operation, see [`as_chunks_mut`] and [`as_rchunks_mut`]. + /// + /// [`as_chunks_mut`]: slice::as_chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + /// + /// # Panics + /// + /// This panics if the length of the resulting slice would overflow a `usize`. + /// + /// This is only possible when flattening a slice of arrays of zero-sized + /// types, and thus tends to be irrelevant in practice. If + /// `size_of::() > 0`, this will never panic. + /// + /// # Examples + /// + /// ``` + /// fn add_5_to_all(slice: &mut [i32]) { + /// for i in slice { + /// *i += 5; + /// } + /// } + /// + /// let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; + /// add_5_to_all(array.as_flattened_mut()); + /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]); + /// ``` + #[stable(feature = "slice_flatten", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidTransmute([T; N], T)))] + pub const fn as_flattened_mut(&mut self) -> &mut [T] { + let len = if T::IS_ZST { + self.len().checked_mul(N).expect("slice len overflow") + } else { + // SAFETY: `self.len() * N` cannot overflow because `self` is + // already in the address space. + unsafe { self.len().unchecked_mul(N) } + }; + // SAFETY: `[T]` is layout-identical to `[T; N]` + unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), len) } + } +} + +impl [f32] { + /// Sorts the slice of floats. + /// + /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses + /// the ordering defined by [`f32::total_cmp`]. + /// + /// # Current implementation + /// + /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by). + /// + /// # Examples + /// + /// ``` + /// #![feature(sort_floats)] + /// let mut v = [2.6, -5e-8, f32::NAN, 8.29, f32::INFINITY, -1.0, 0.0, -f32::INFINITY, -0.0]; + /// + /// v.sort_floats(); + /// let sorted = [-f32::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f32::INFINITY, f32::NAN]; + /// assert_eq!(&v[..8], &sorted[..8]); + /// assert!(v[8].is_nan()); + /// ``` + #[unstable(feature = "sort_floats", issue = "93396")] + #[inline] + pub fn sort_floats(&mut self) { + self.sort_unstable_by(f32::total_cmp); + } +} + +impl [f64] { + /// Sorts the slice of floats. + /// + /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses + /// the ordering defined by [`f64::total_cmp`]. + /// + /// # Current implementation + /// + /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by). + /// + /// # Examples + /// + /// ``` + /// #![feature(sort_floats)] + /// let mut v = [2.6, -5e-8, f64::NAN, 8.29, f64::INFINITY, -1.0, 0.0, -f64::INFINITY, -0.0]; + /// + /// v.sort_floats(); + /// let sorted = [-f64::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f64::INFINITY, f64::NAN]; + /// assert_eq!(&v[..8], &sorted[..8]); + /// assert!(v[8].is_nan()); + /// ``` + #[unstable(feature = "sort_floats", issue = "93396")] + #[inline] + pub fn sort_floats(&mut self) { + self.sort_unstable_by(f64::total_cmp); + } +} + +/// Copies `src` to `dest`. +/// +/// # Safety +/// `T` must implement one of `Copy` or `TrivialClone`. +#[track_caller] +#[cfg_attr(rapx, rapx::verify)] +#[cfg_attr(rapx, rapx::requires(any(Trait(T, Copy), Trait(T, TrivialClone))))] +const unsafe fn copy_from_slice_impl(dest: &mut [T], src: &[T]) +//@ req thread_token(?t) &*& [_](<[T]>.share(?k, t, src)) &*& [?q]lifetime_token(k) &*& (strip_pointer_metadata(dest as pointer) as *T)[..dest.len()] |-> ?elems_dest &*& foreach(elems_dest, own::(t)) &*& is_Copy::() == true; +//@ ens thread_token(t) &*& [q]lifetime_token(k) &*& (strip_pointer_metadata(dest as pointer) as *T)[..dest.len()] |-> ?elems_src &*& foreach(elems_src, own::(t)) &*& dest.len() == src.len(); +//@ on_unwind_ens false; +{ + // The panic code path was put into a cold function to not bloat the + // call site. + #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] + #[cfg_attr(panic = "immediate-abort", inline)] + #[track_caller] + const fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! { + const_panic!( + "copy_from_slice: source slice length does not match destination slice length", + "copy_from_slice: source slice length ({src_len}) does not match destination slice length ({dst_len})", + src_len: usize, + dst_len: usize, + ) + } + + if dest.len() != src.len() { + len_mismatch_fail(dest.len(), src.len()); //~allow_dead_code + } + + // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was + // checked to have the same length. The slices cannot overlap because + // mutable references are exclusive. + unsafe { + //@ leak foreach(elems_dest, own::(t)); + //@ array_to_array_(strip_pointer_metadata(dest as pointer) as *T); + //@ open_shared_slice_copy::(k, t, src); + ptr::copy_nonoverlapping(src.as_ptr(), dest.as_mut_ptr(), dest.len()); + //@ close_shared_slice_copy::(k, src); + } +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const trait CloneFromSpec { + fn spec_clone_from(&mut self, src: &[T]) + where + T: [const] Destruct; +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const impl CloneFromSpec for [T] +where + T: [const] Clone + [const] Destruct, +{ + #[track_caller] + default fn spec_clone_from(&mut self, src: &[T]) { + assert!(self.len() == src.len(), "destination and source slices have different lengths"); + // NOTE: We need to explicitly slice them to the same length + // to make it easier for the optimizer to elide bounds checking. + // But since it can't be relied on we also have an explicit specialization for T: Copy. + let len = self.len(); + let src = &src[..len]; + for i in 0..len { + self[i].clone_from(&src[i]); + } + } +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const impl CloneFromSpec for [T] +where + T: [const] TrivialClone + [const] Destruct, +{ + #[track_caller] + fn spec_clone_from(&mut self, src: &[T]) { + // SAFETY: `T` implements `TrivialClone`. + unsafe { + copy_from_slice_impl(self, src); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +const impl Default for &[T] { + /// Creates an empty slice. + fn default() -> Self { + &[] + } +} + +#[stable(feature = "mut_slice_default", since = "1.5.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +const impl Default for &mut [T] { + /// Creates a mutable empty slice. + fn default() -> Self { + &mut [] + } +} + +#[unstable(feature = "slice_pattern", reason = "stopgap trait for slice patterns", issue = "56345")] +/// Patterns in slices - currently, only used by `strip_prefix` and `strip_suffix`. At a future +/// point, we hope to generalise `core::str::Pattern` (which at the time of writing is limited to +/// `str`) to slices, and then this trait will be replaced or abolished. +pub trait SlicePattern { + /// The element type of the slice being matched on. + type Item; + + /// Currently, the consumers of `SlicePattern` need a slice. + fn as_slice(&self) -> &[Self::Item]; +} + +#[stable(feature = "slice_strip", since = "1.51.0")] +impl SlicePattern for [T] { + type Item = T; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } +} + +#[stable(feature = "slice_strip", since = "1.51.0")] +impl SlicePattern for [T; N] { + type Item = T; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } +} + +/// This checks every index against each other, and against `len`. +/// +/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..` +/// comparison operations. +#[inline] +#[cfg_attr(rapx, rapx::verify)] +fn get_disjoint_check_valid( + indices: &[I; N], + len: usize, +) -> Result<(), GetDisjointMutError> { + // NB: The optimizer should inline the loops into a sequence + // of instructions without additional branching. + for (i, idx) in indices.iter().enumerate() { + if !idx.is_in_bounds(len) { + return Err(GetDisjointMutError::IndexOutOfBounds); + } + for idx2 in &indices[..i] { + if idx.is_overlapping(idx2) { + return Err(GetDisjointMutError::OverlappingIndices); + } + } + } + Ok(()) +} + +/// The error type returned by [`get_disjoint_mut`][`slice::get_disjoint_mut`]. +/// +/// It indicates one of two possible errors: +/// - An index is out-of-bounds. +/// - The same index appeared multiple times in the array +/// (or different but overlapping indices when ranges are provided). +/// +/// # Examples +/// +/// ``` +/// use std::slice::GetDisjointMutError; +/// +/// let v = &mut [1, 2, 3]; +/// assert_eq!(v.get_disjoint_mut([0, 999]), Err(GetDisjointMutError::IndexOutOfBounds)); +/// assert_eq!(v.get_disjoint_mut([1, 1]), Err(GetDisjointMutError::OverlappingIndices)); +/// ``` +#[stable(feature = "get_many_mut", since = "1.86.0")] +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum GetDisjointMutError { + /// An index provided was out-of-bounds for the slice. + IndexOutOfBounds, + /// Two indices provided were overlapping. + OverlappingIndices, +} + +#[stable(feature = "get_many_mut", since = "1.86.0")] +impl fmt::Display for GetDisjointMutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let msg = match self { + GetDisjointMutError::IndexOutOfBounds => "an index is out of bounds", + GetDisjointMutError::OverlappingIndices => "there were overlapping indices", + }; + fmt::Display::fmt(msg, f) + } +} + +/*@ +fix all_in_bounds(xs: list, len: usize) -> bool { + match xs { + nil => true, + cons(x, xs0) => std::slice::GetDisjointMutIndex_in_bounds::(x, len) && all_in_bounds::(xs0, len), + } +} + +fix none_overlapping_with(x: I, xs: list) -> bool { + match xs { + nil => true, + cons(y, xs0) => !std::slice::GetDisjointMutIndex_overlapping::(x, y) && none_overlapping_with::(x, xs0), + } +} + +fix none_overlapping_after(y: I, xs: list) -> bool { + match xs { + nil => true, + cons(x, xs0) => !std::slice::GetDisjointMutIndex_overlapping::(x, y) && none_overlapping_after::(y, xs0), + } +} + +fix all_pairwise_disjoint(xs: list) -> bool { + match xs { + nil => true, + cons(y, xs0) => none_overlapping_after::(y, xs0) && all_pairwise_disjoint::(xs0), + } +} + +lem all_in_bounds_nth(xs: list, i: i32, len: usize) + req all_in_bounds::(xs, len) == true &*& 0 <= i &*& i < length(xs); + ens std::slice::GetDisjointMutIndex_in_bounds::(nth(i, xs), len) == true; +{ + match xs { + nil => {} + cons(h, tl) => { + if i == 0 { + } else { + all_in_bounds_nth::(tl, i - 1, len); + } + } + } +} + +// Safety precondition of the sealed `SliceIndex<[T]>::get_unchecked{,_mut}` impl for `Range`, as +// documented on `get_unchecked` ("the index must be within the bounds of the slice"), so that the +// contracts of `get_unchecked` / `get_unchecked_mut` are usable at that index type as well as at +// `usize` (`core.rsspec`). The other index types (`RangeTo`, `RangeFrom`, `RangeFull`, +// `RangeInclusive`, `core::range::*`) cannot be named in VeriFast 26.10's ghost language, so the +// contract is not usable at those types from within this proof. +lem Range_SliceIndex_in_bounds(r: std::ops::Range, slice: *[T]) + req 0 <= r.start &*& r.start <= r.end &*& r.end <= slice.len(); + ens std::slice::SliceIndex_in_bounds::, [T]>(r, slice); +{ + assume(false); +} + +lem all_in_bounds_snoc(xs: list, i: i32, len: usize) + req 0 <= i &*& i < length(xs) &*& all_in_bounds::(take(i, xs), len) == true &*& std::slice::GetDisjointMutIndex_in_bounds::(nth(i, xs), len) == true; + ens all_in_bounds::(take(i + 1, xs), len) == true; +{ + match xs { + nil => {} + cons(h, tl) => { + if i == 0 { + } else { + all_in_bounds_snoc::(tl, i - 1, len); + } + } + } +} + +lem none_overlapping_with_snoc(x: I, xs: list, j: i32) + req 0 <= j &*& j < length(xs) &*& none_overlapping_with::(x, take(j, xs)) == true &*& !std::slice::GetDisjointMutIndex_overlapping::(x, nth(j, xs)); + ens none_overlapping_with::(x, take(j + 1, xs)) == true; +{ + match xs { + nil => {} + cons(h, tl) => { + if j == 0 { + } else { + none_overlapping_with_snoc::(x, tl, j - 1); + } + } + } +} + +lem none_overlapping_after_snoc(y: I, tl: list, k: i32) + req 0 <= k &*& k < length(tl) &*& none_overlapping_after::(y, take(k, tl)) == true &*& !std::slice::GetDisjointMutIndex_overlapping::(nth(k, tl), y); + ens none_overlapping_after::(y, take(k + 1, tl)) == true; +{ + match tl { + nil => {} + cons(h, tl0) => { + if k == 0 { + } else { + none_overlapping_after_snoc::(y, tl0, k - 1); + } + } + } +} + +lem all_pairwise_disjoint_snoc(xs: list, i: i32) + req 0 <= i &*& i < length(xs) &*& all_pairwise_disjoint::(take(i, xs)) == true &*& none_overlapping_with::(nth(i, xs), take(i, xs)) == true; + ens all_pairwise_disjoint::(take(i + 1, xs)) == true; +{ + match xs { + nil => {} + cons(h, tl) => { + if i == 0 { + } else { + none_overlapping_after_snoc::(h, tl, i - 1); + all_pairwise_disjoint_snoc::(tl, i - 1); + } + } + } +} + +// Region model of the sealed `GetDisjointMutIndex` + `SliceIndex<[T]>` implementations (`usize`, +// `Range`, `RangeInclusive`, `range::Range`, `range::RangeInclusive`): +// an index `idx` denotes the contiguous element range +// `[region_start(idx), region_start(idx) + region_len(idx))`; `is_in_bounds` means that range lies +// inside the slice, `is_overlapping` means the two ranges intersect, and `get_unchecked_mut` returns +// a reference to the range (`region_ptr`: an element reference for `usize`, a sub-slice reference +// for the ranges). These are exactly the facts the `SAFETY` comments of `get_disjoint_mut` and +// `get_disjoint_unchecked_mut` rely on. +fix region_start(idx: I) -> usize; +fix region_len(idx: I) -> usize; +fix region_ptr(p: *T, idx: I) -> P; +// `P` is the type of the output slots (a mutable reference to `O` at the const-generic, hence +// transcribed, call sites); `ref_target` is the pointer such a reference denotes. Lifetimes cannot +// be parameters of VeriFast predicates, hence the indirection. +fix ref_target(r: P) -> *O; + +lem GetDisjointMutIndex_in_bounds_region(idx: I, len: usize) + req std::slice::GetDisjointMutIndex_in_bounds::(idx, len) == true; + ens 0 <= region_start::(idx) &*& 0 <= region_len::(idx) &*& region_start::(idx) + region_len::(idx) <= len; +{ + assume(false); +} + +lem GetDisjointMutIndex_not_overlapping_disjoint(a: I, b: I) + req std::slice::GetDisjointMutIndex_overlapping::(a, b) == false; + ens region_start::(a) + region_len::(a) <= region_start::(b) || region_start::(b) + region_len::(b) <= region_start::(a); +{ + assume(false); +} + +// Definition of the region model at each concrete index type. These are the meaning of the abstract +// fixpoints `region_start`, `region_len`, `GetDisjointMutIndex_in_bounds`, `GetDisjointMutIndex_overlapping` +// at `usize` and `Range` (VeriFast 26.10's ghost language has no declaration of `RangeInclusive` or of `core::range::*`, so those impls stay specless); the two generic axioms above are checked +// against them (`in_bounds_region_*`, `not_overlapping_disjoint_*`), and the `is_in_bounds` / +// `is_overlapping` implementations below are verified against `GetDisjointMutIndex_in_bounds` / +// `GetDisjointMutIndex_overlapping` through them. An empty region is normalized to `[0, 0)` so that +// disjointness of non-overlapping ranges holds without an in-bounds hypothesis. +lem usize_region_model(i: usize, len: usize, j: usize) + req true; + ens region_start::(i) == i &*& region_len::(i) == 1 &*& + std::slice::GetDisjointMutIndex_in_bounds::(i, len) == (0 <= i && i < len) &*& + std::slice::GetDisjointMutIndex_overlapping::(i, j) == (i == j); +{ + assume(false); +} + +lem Range_region_model(r: std::ops::Range, len: usize, r2: std::ops::Range) + req true; + ens region_start::>(r) == (if r.end <= r.start { 0 } else { r.start }) &*& + region_len::>(r) == (if r.end <= r.start { 0 } else { r.end - r.start }) &*& + std::slice::GetDisjointMutIndex_in_bounds::>(r, len) == (0 <= r.start && r.start <= r.end && r.end <= len) &*& + std::slice::GetDisjointMutIndex_overlapping::>(r, r2) == (r.start < r2.end && r2.start < r.end); +{ + assume(false); +} + +// The two generic region axioms hold at each defined type. +lem in_bounds_region_usize(i: usize, len: usize) + req std::slice::GetDisjointMutIndex_in_bounds::(i, len) == true; + ens 0 <= region_start::(i) &*& 0 <= region_len::(i) &*& region_start::(i) + region_len::(i) <= len; +{ + usize_region_model(i, len, i); +} + +lem not_overlapping_disjoint_usize(a: usize, b: usize) + req std::slice::GetDisjointMutIndex_overlapping::(a, b) == false; + ens region_start::(a) + region_len::(a) <= region_start::(b) || region_start::(b) + region_len::(b) <= region_start::(a); +{ + usize_region_model(a, 0, b); + usize_region_model(b, 0, a); +} + +lem in_bounds_region_Range(r: std::ops::Range, len: usize) + req std::slice::GetDisjointMutIndex_in_bounds::>(r, len) == true; + ens 0 <= region_start::>(r) &*& 0 <= region_len::>(r) &*& region_start::>(r) + region_len::>(r) <= len; +{ + Range_region_model(r, len, r); +} + +// (`0 <= a.start`, `0 <= b.start`: the fields are `usize` values; VeriFast's ghost integers do not carry +// that bound, so it is a hypothesis here.) +lem not_overlapping_disjoint_Range(a: std::ops::Range, b: std::ops::Range) + req std::slice::GetDisjointMutIndex_overlapping::>(a, b) == false &*& 0 <= a.start &*& 0 <= b.start; + ens region_start::>(a) + region_len::>(a) <= region_start::>(b) || region_start::>(b) + region_len::>(b) <= region_start::>(a); +{ + Range_region_model(a, 0, b); + Range_region_model(b, 0, a); +} + +// Ownership of the element regions denoted by `idxs`, in list order. +pred regions_owned(t: thread_id_t, p: *T, idxs: list) = + match idxs { + nil => true, + cons(idx, idxs0) => (p + region_start::(idx))[..region_len::(idx)] |-> ?es &*& foreach(es, own::(t)) &*& regions_owned::(t, p, idxs0) + }; + +// `i` lies in one of the regions of `idxs`. +fix in_some_region(i: usize, idxs: list) -> bool { + match idxs { + nil => false, + cons(idx, idxs0) => (region_start::(idx) <= i && i < region_start::(idx) + region_len::(idx)) || in_some_region::(i, idxs0), + } +} + +// The elements `p[i..len]` that lie outside the regions of `idxs`, one by one. +pred rest_elems(t: thread_id_t, p: *T, len: usize, idxs: list, i: usize) = + pointer_within_limits(p + i) == true &*& + if len <= i { + true + } else { + (if in_some_region::(i, idxs) { true } else { *(p + i) |-> ?v &*& own::(t)(v) }) &*& + rest_elems::(t, p, len, idxs, i + 1) + }; + +// The rest-elements, together with the facts that justify putting the regions back (they are pure, +// so keeping them here saves the callers of `uncarve_regions` from re-establishing them). +pred slice_rest_owned(t: thread_id_t, p: *T, len: usize, idxs: list) = + rest_elems::(t, p, len, idxs, 0) &*& 0 <= len &*& all_in_bounds::(idxs, len) == true &*& all_pairwise_disjoint::(idxs) == true; + +lem array_to_rest_elems(t: thread_id_t, p: *T, len: usize, i: usize) + req (p + i)[..len - i] |-> ?es &*& foreach(es, own::(t)) &*& 0 <= i &*& i <= len; + ens rest_elems::(t, p, len, nil, i); +{ + open array(p + i, len - i, es); + if len <= i { + open foreach(es, own::(t)); + close rest_elems::(t, p, len, nil, i); + } else { + open foreach(es, own::(t)); + array_to_rest_elems::(t, p, len, i + 1); + close rest_elems::(t, p, len, nil, i); + } +} + +lem rest_elems_to_array(t: thread_id_t, p: *T, len: usize, i: usize) + req rest_elems::(t, p, len, nil, i) &*& 0 <= i &*& i <= len; + ens (p + i)[..len - i] |-> ?es &*& foreach(es, own::(t)); +{ + open rest_elems::(t, p, len, nil, i); + if len <= i { + close array(p + i, 0, nil); + close foreach(nil, own::(t)); + } else { + rest_elems_to_array::(t, p, len, i + 1); + assert (p + i + 1)[..len - i - 1] |-> ?es0; + assert *(p + i) |-> ?v; + close array(p + i, len - i, cons(v, es0)); + close foreach(cons(v, es0), own::(t)); + } +} + +// An index of `h`'s region lies in no region of a list that `h` does not overlap. +lem not_in_regions_of_disjoint(h: I, tl: list, j: usize) + req none_overlapping_after::(h, tl) == true &*& region_start::(h) <= j &*& j < region_start::(h) + region_len::(h); + ens in_some_region::(j, tl) == false; +{ + match tl { + nil => {} + cons(x, tl0) => { + GetDisjointMutIndex_not_overlapping_disjoint::(x, h); + not_in_regions_of_disjoint::(h, tl0, j); + } + } +} + +// Beyond the end of `h`'s region, adding `h` to the hole list changes nothing. +lem rest_elems_cons_outside(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, tl, i) &*& region_start::(h) + region_len::(h) <= i; + ens rest_elems::(t, p, len, cons(h, tl), i); +{ + open rest_elems::(t, p, len, tl, i); + if len <= i { + } else { + rest_elems_cons_outside::(t, p, len, tl, h, i + 1); + } + close rest_elems::(t, p, len, cons(h, tl), i); +} + +lem rest_elems_uncons_outside(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, cons(h, tl), i) &*& region_start::(h) + region_len::(h) <= i; + ens rest_elems::(t, p, len, tl, i); +{ + open rest_elems::(t, p, len, cons(h, tl), i); + if len <= i { + } else { + rest_elems_uncons_outside::(t, p, len, tl, h, i + 1); + } + close rest_elems::(t, p, len, tl, i); +} + +// Carve the part of `h`'s region at or after `i` (with `start <= i <= end`) out of the +// rest-elements of `tl`. +lem carve_one_in(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, tl, i) &*& none_overlapping_after::(h, tl) == true &*& + region_start::(h) <= i &*& i <= region_start::(h) + region_len::(h) &*& region_start::(h) + region_len::(h) <= len; + ens rest_elems::(t, p, len, cons(h, tl), i) &*& + (p + i)[..region_start::(h) + region_len::(h) - i] |-> ?es &*& foreach(es, own::(t)); +{ + let s = region_start::(h); + let e = s + region_len::(h); + if i == e { + open rest_elems::(t, p, len, tl, i); + close rest_elems::(t, p, len, tl, i); + rest_elems_cons_outside::(t, p, len, tl, h, i); + close array(p + i, 0, nil); + close foreach(nil, own::(t)); + } else { + open rest_elems::(t, p, len, tl, i); + not_in_regions_of_disjoint::(h, tl, i); + carve_one_in::(t, p, len, tl, h, i + 1); + assert *(p + i) |-> ?v; + assert (p + i + 1)[..e - i - 1] |-> ?es0; + close array(p + i, e - i, cons(v, es0)); + close foreach(cons(v, es0), own::(t)); + close rest_elems::(t, p, len, cons(h, tl), i); + } +} + +// Same, starting before the region (`i <= start`). +lem carve_one(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, tl, i) &*& none_overlapping_after::(h, tl) == true &*& + 0 <= i &*& i <= region_start::(h) &*& 0 <= region_len::(h) &*& region_start::(h) + region_len::(h) <= len; + ens rest_elems::(t, p, len, cons(h, tl), i) &*& + (p + region_start::(h))[..region_len::(h)] |-> ?es &*& foreach(es, own::(t)); +{ + let s = region_start::(h); + if i == s { + carve_one_in::(t, p, len, tl, h, i); + } else { + open rest_elems::(t, p, len, tl, i); + carve_one::(t, p, len, tl, h, i + 1); + close rest_elems::(t, p, len, cons(h, tl), i); + } +} + +// Put the part of `h`'s region at or after `i` (`start <= i <= end`) back. Elements that another +// region of `tl` also claims, or that lie beyond `len`, are surplus and are leaked. +lem uncarve_one_in(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, cons(h, tl), i) &*& region_start::(h) <= i &*& i <= region_start::(h) + region_len::(h) &*& + (p + i)[..region_start::(h) + region_len::(h) - i] |-> ?es &*& foreach(es, own::(t)); + ens rest_elems::(t, p, len, tl, i); +{ + let s = region_start::(h); + let e = s + region_len::(h); + if i == e { + leak array(_, _, _); + leak foreach(_, _); + rest_elems_uncons_outside::(t, p, len, tl, h, i); + } else { + open rest_elems::(t, p, len, cons(h, tl), i); + if len <= i { + leak array(_, _, _); + leak foreach(_, _); + close rest_elems::(t, p, len, tl, i); + } else { + open array(p + i, e - i, es); + open foreach(es, own::(t)); + if in_some_region::(i, tl) { + leak *(p + i) |-> _; + leak own::(t)(_); + } + uncarve_one_in::(t, p, len, tl, h, i + 1); + close rest_elems::(t, p, len, tl, i); + } + } +} + +// Same, starting before the region (`i <= start`). +lem uncarve_one(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, cons(h, tl), i) &*& 0 <= i &*& i <= region_start::(h) &*& + (p + region_start::(h))[..region_len::(h)] |-> ?es &*& foreach(es, own::(t)); + ens rest_elems::(t, p, len, tl, i); +{ + let s = region_start::(h); + if i == s { + uncarve_one_in::(t, p, len, tl, h, i); + } else { + open rest_elems::(t, p, len, cons(h, tl), i); + if len <= i { + leak array(_, _, _); + leak foreach(_, _); + close rest_elems::(t, p, len, tl, i); + } else { + uncarve_one::(t, p, len, tl, h, i + 1); + close rest_elems::(t, p, len, tl, i); + } + } +} + +lem carve_regions(t: thread_id_t, p: *T, len: usize, idxs: list) + req p[..len] |-> ?es &*& foreach(es, own::(t)) &*& all_in_bounds::(idxs, len) == true &*& all_pairwise_disjoint::(idxs) == true; + ens regions_owned::(t, p, idxs) &*& slice_rest_owned::(t, p, len, idxs); +{ + match idxs { + nil => { + array_to_rest_elems::(t, p, len, 0); + close regions_owned::(t, p, nil); + close slice_rest_owned::(t, p, len, nil); + } + cons(h, tl) => { + carve_regions::(t, p, len, tl); + open slice_rest_owned::(t, p, len, tl); + GetDisjointMutIndex_in_bounds_region::(h, len); + carve_one::(t, p, len, tl, h, 0); + close regions_owned::(t, p, cons(h, tl)); + close slice_rest_owned::(t, p, len, cons(h, tl)); + } + } +} + +lem uncarve_regions(t: thread_id_t, p: *T, len: usize, idxs: list) + req regions_owned::(t, p, idxs) &*& slice_rest_owned::(t, p, len, idxs); + ens p[..len] |-> ?es &*& foreach(es, own::(t)); +{ + open regions_owned::(t, p, idxs); + open slice_rest_owned::(t, p, len, idxs); + match idxs { + nil => { + rest_elems_to_array::(t, p, len, 0); + } + cons(h, tl) => { + GetDisjointMutIndex_in_bounds_region::(h, len); + uncarve_one::(t, p, len, tl, h, 0); + close slice_rest_owned::(t, p, len, tl); + uncarve_regions::(t, p, len, tl); + } + } +} + +// `.full_borrow_content` of the reference `get_unchecked_mut` returns for `idx` is exactly +// the ownership of `idx`'s region: `*r |-> v &*& own(v)` for `usize`, `slice_full_borrow_content` for +// the ranges. +lem region_to_output_fbc(t: thread_id_t, p: *T, idx: I) + req (p + region_start::(idx))[..region_len::(idx)] |-> ?es &*& foreach(es, own::(t)); + ens (.full_borrow_content(t, ref_target::(region_ptr::(p, idx))))(); +{ + assume(false); +} + +lem output_fbc_to_region(t: thread_id_t, p: *T, idx: I) + req (.full_borrow_content(t, ref_target::(region_ptr::(p, idx))))(); + ens (p + region_start::(idx))[..region_len::(idx)] |-> ?es &*& foreach(es, own::(t)); +{ + assume(false); +} + +// Content of one lifetime-`k` borrow covering everything the output references point to. +pred_ctor outputs_fbc(t: thread_id_t, p: *T, idxs: list)() = + match idxs { + nil => true, + cons(idx, idxs0) => (.full_borrow_content(t, ref_target::(region_ptr::(p, idx))))() &*& outputs_fbc::(t, p, idxs0)() + }; + +lem regions_to_outputs_fbc(t: thread_id_t, p: *T, idxs: list) + req regions_owned::(t, p, idxs); + ens outputs_fbc::(t, p, idxs)(); +{ + open regions_owned::(t, p, idxs); + match idxs { + nil => { + } + cons(idx, idxs0) => { + region_to_output_fbc::(t, p, idx); + regions_to_outputs_fbc::(t, p, idxs0); + } + } + close outputs_fbc::(t, p, idxs)(); +} + +lem outputs_fbc_to_regions(t: thread_id_t, p: *T, idxs: list) + req outputs_fbc::(t, p, idxs)(); + ens regions_owned::(t, p, idxs); +{ + open outputs_fbc::(t, p, idxs)(); + match idxs { + nil => { + } + cons(idx, idxs0) => { + output_fbc_to_region::(t, p, idx); + outputs_fbc_to_regions::(t, p, idxs0); + } + } + close regions_owned::(t, p, idxs); +} + +pred_ctor slice_rest_owned_ctor(t: thread_id_t, p: *T, len: usize, idxs: list)() = slice_rest_owned::(t, p, len, idxs); + +// The references `get_disjoint_unchecked_mut` stores, in index order. +fix refs_of(p: *T, idxs: list) -> list

{ + match idxs { + nil => nil, + cons(idx, idxs0) => cons(region_ptr::(p, idx), refs_of::(p, idxs0)) + } +} + +lem refs_of_snoc(p: *T, idxs: list, idx: I) + req true; + ens refs_of::(p, append(idxs, cons(idx, nil))) == append(refs_of::(p, idxs), cons(region_ptr::(p, idx), nil)); +{ + match idxs { + nil => {} + cons(idx0, idxs0) => { + refs_of_snoc::(p, idxs0, idx); + } + } +} + +// Result of `get_disjoint_unchecked_mut`: the output references, and one lifetime-`k` borrow of +// everything they point to. `disjoint_mut_borrows_peel` turns it into the usual per-reference borrows. +pred disjoint_mut_borrows(k: lifetime_t, t: thread_id_t, out_ptr: *P, p: *T, idxs: list) = + out_ptr[..length(idxs)] |-> refs_of::(p, idxs) &*& full_borrow(k, outputs_fbc::(t, p, idxs)); + +lem disjoint_mut_borrows_peel(k: lifetime_t, t: thread_id_t, out_ptr: *P, p: *T, idx: I, idxs0: list) + nonghost_callers_only + req disjoint_mut_borrows::(k, t, out_ptr, p, cons(idx, idxs0)); + ens *out_ptr |-> region_ptr::(p, idx) &*& full_borrow(k, .full_borrow_content(t, ref_target::(region_ptr::(p, idx)))) &*& disjoint_mut_borrows::(k, t, out_ptr + 1, p, idxs0); +{ + open disjoint_mut_borrows::(k, t, out_ptr, p, cons(idx, idxs0)); + open array(out_ptr, _, _); + produce_lem_ptr_chunk implies(outputs_fbc::(t, p, cons(idx, idxs0)), sep(.full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0)))() { + open outputs_fbc::(t, p, cons(idx, idxs0))(); + close sep(.full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0))(); + } { + produce_lem_ptr_chunk implies(sep(.full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0)), outputs_fbc::(t, p, cons(idx, idxs0)))() { + open sep(.full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0))(); + close outputs_fbc::(t, p, cons(idx, idxs0))(); + } { + full_borrow_implies(k, outputs_fbc::(t, p, cons(idx, idxs0)), sep(.full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0))); + } + } + full_borrow_split(k, .full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0)); + close disjoint_mut_borrows::(k, t, out_ptr + 1, p, idxs0); +} + +lem take_plus_one(n: i32, xs: list) + req 0 <= n &*& n < length(xs); + ens take(n + 1, xs) == append(take(n, xs), cons(nth(n, xs), nil)); +{ + match xs { + nil => {} + cons(h, tl) => { + if n > 0 { + take_plus_one(n - 1, tl); + } + } + } +} +@*/ + +// `GetDisjointMutIndex` is sealed (`impl(self)`): its only implementors are `usize`, `Range`, +// `RangeInclusive`, `range::Range` and `range::RangeInclusive`, all of which derive +// `Clone` field-wise, so `clone` is the identity on values and `result == nth(i, elems)` is exact for +// every type this wrapper can be instantiated with (a foreign `I` cannot implement the trait). +unsafe fn clone_disjoint_index__VeriFast_wrapper(s: &[I], i: usize) -> I +//@ req thread_token(?t) &*& [?f]((strip_pointer_metadata(s as pointer) as *I)[..s.len()] |-> ?elems) &*& 0 <= i &*& i < s.len(); +//@ ens thread_token(t) &*& [f]((strip_pointer_metadata(s as pointer) as *I)[..s.len()] |-> elems) &*& result == nth(i, elems); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + unsafe { s.get_unchecked(i).clone() } +} + +unsafe fn write_disjoint_mut_elem__VeriFast_wrapper( + slice: *mut [T], + idx: I, + out_ptr: *mut P, + i: usize, +) +where + I: GetDisjointMutIndex + SliceIndex<[T], Output = O>, +// Raw-pointer semantics of the sealed `SliceIndex::get_unchecked_mut` impls: the reference written to +// slot `i` points at `idx`'s region. No ownership of the slice is needed to compute and store it; the +// ownership transfer to the returned references happens in `get_disjoint_unchecked_mut`'s proof. +//@ req *(out_ptr + i) |-> _ &*& 0 <= i &*& std::slice::GetDisjointMutIndex_in_bounds::(idx, slice.len()) == true; +//@ ens *(out_ptr + i) |-> region_ptr::(strip_pointer_metadata(slice as pointer) as *T, idx); +//@ on_unwind_ens false; +//@ assume_correct +{ + unsafe { + let elem = &mut *slice.get_unchecked_mut(idx); + out_ptr.cast::<&mut I::Output>().add(i).write(elem); + } +} + +unsafe fn get_disjoint_check_valid_proof__VeriFast_wrapper( + indices: &[I], + len: usize, +) -> Result<(), GetDisjointMutError> +//@ req thread_token(?t) &*& [?f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> ?elems); +//@ ens thread_token(t) &*& [f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> elems) &*& match result { Result::Ok(u) => all_in_bounds::(elems, len) == true &*& all_pairwise_disjoint::(elems) == true, Result::Err(e) => true }; +//@ on_unwind_ens false; +{ + let n = indices.len(); + let base: *const I = indices.as_ptr(); + //@ let p = strip_pointer_metadata(indices as pointer) as *I; + let mut i = 0; + loop { + //@ inv thread_token(t) &*& [f](p[..n] |-> elems) &*& 0 <= i &*& i <= n &*& length(elems) == n &*& all_in_bounds::(take(i, elems), len) == true &*& all_pairwise_disjoint::(take(i, elems)) == true; + if !(i < n) { + break; + } + // `indices[i]` as a reference created from the raw element address under the aliasing protocol + // (`precreate_ref` / `init_ref_readonly` / `end_ref_readonly`), instead of a trusted indexing wrapper. + //@ array_extract_elem_frac::(p, i); + //@ points_to_limits::(p + i); + let idx_ptr = unsafe { base.add(i) }; + //@ let idx_ref = precreate_ref(idx_ptr); + //@ init_ref_readonly(idx_ref, 1/2); + let in_bounds = GetDisjointMutIndex::is_in_bounds(unsafe { &*idx_ptr }, len); + //@ end_ref_readonly(idx_ref); + //@ array_insert_elem_frac::(p, i, n, elems); + if !in_bounds { + return Err(GetDisjointMutError::IndexOutOfBounds); + } + let mut j = 0; + loop { + //@ inv thread_token(t) &*& [f](p[..n] |-> elems) &*& 0 <= j &*& j <= i &*& i < n &*& length(elems) == n &*& none_overlapping_with::(nth(i, elems), take(j, elems)) == true; + if !(j < i) { + break; + } + //@ array_extract_elem_frac::(p, i); + //@ array_extract_elem_frac::(p, j); + //@ points_to_limits::(p + i); + //@ points_to_limits::(p + j); + let idx_i_ptr = unsafe { base.add(i) }; + let idx_j_ptr = unsafe { base.add(j) }; + //@ let idx_i_ref = precreate_ref(idx_i_ptr); + //@ init_ref_readonly(idx_i_ref, 1/2); + //@ let idx_j_ref = precreate_ref(idx_j_ptr); + //@ init_ref_readonly(idx_j_ref, 1/2); + let ov = GetDisjointMutIndex::is_overlapping(unsafe { &*idx_i_ptr }, unsafe { &*idx_j_ptr }); + //@ end_ref_readonly(idx_j_ref); + //@ end_ref_readonly(idx_i_ref); + //@ array_insert_elem_frac::(p, j, i, take(i, elems)); + //@ array_insert_elem_frac::(p, i, n, elems); + if ov { + return Err(GetDisjointMutError::OverlappingIndices); + } + //@ none_overlapping_with_snoc::(nth(i, elems), elems, j); + j += 1; + } + //@ all_in_bounds_snoc::(elems, i, len); + //@ all_pairwise_disjoint_snoc::(elems, i); + i += 1; + } + Ok(()) +} + +unsafe fn get_disjoint_unchecked_mut_proof__VeriFast_wrapper<'a, T, I, O, P>( + slice_ref: &'a mut [T], + indices: &[I], + out_ptr: *mut P, +) +where + I: GetDisjointMutIndex + SliceIndex<[T], Output = O>, +//@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, slice_ref)) &*& [?q]lifetime_token(k) &*& [?f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> ?elems) &*& all_in_bounds::(elems, slice_ref.len()) == true &*& all_pairwise_disjoint::(elems) == true &*& out_ptr[..indices.len()] |-> _; +//@ ens thread_token(t) &*& [q]lifetime_token(k) &*& [f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> elems) &*& disjoint_mut_borrows::(k, t, out_ptr, strip_pointer_metadata(slice_ref as pointer) as *T, elems); +//@ on_unwind_ens false; +{ + let n = indices.len(); + let slice: *mut [T] = slice_ref; + //@ let p = strip_pointer_metadata(indices as pointer) as *I; + //@ let sp = strip_pointer_metadata(slice_ref as pointer) as *T; + //@ let len = slice_ref.len(); + //@ open_full_borrow_strong_(k, <[T]>.full_borrow_content(t, slice_ref)); + //@ open slice_full_borrow_content::(t, slice_ref)(); + //@ carve_regions::(t, sp, len, elems); + //@ close array(out_ptr, 0, nil); + let mut i = 0; + loop { + //@ inv thread_token(t) &*& [f](p[..n] |-> elems) &*& 0 <= i &*& i <= n &*& length(elems) == n &*& out_ptr[..i] |-> refs_of::(sp, take(i, elems)) &*& (out_ptr + i)[..n - i] |-> _ &*& regions_owned::(t, sp, elems) &*& slice_rest_owned::(t, sp, len, elems) &*& close_full_borrow_token_strong_(k, <[T]>.full_borrow_content(t, slice_ref), q); + if !(i < n) { + break; + } + let idx = unsafe { clone_disjoint_index__VeriFast_wrapper(indices, i) }; + //@ open array_(out_ptr + i, n - i, _); + //@ all_in_bounds_nth::(elems, i, len); + unsafe { + write_disjoint_mut_elem__VeriFast_wrapper::(slice, idx, out_ptr, i); + } + //@ close array(out_ptr + i + 1, 0, nil); + //@ close array(out_ptr + i, 1, cons(region_ptr::(sp, idx), nil)); + //@ array_join(out_ptr); + //@ take_plus_one(i, elems); + //@ refs_of_snoc::(sp, take(i, elems), nth(i, elems)); + i += 1; + } + //@ open array_(out_ptr + n, 0, _); + //@ regions_to_outputs_fbc::(t, sp, elems); + //@ close slice_rest_owned_ctor::(t, sp, len, elems)(); + //@ close sep(outputs_fbc::(t, sp, elems), slice_rest_owned_ctor::(t, sp, len, elems))(); + /*@ + produce_lem_ptr_chunk restore_full_borrow_(True, sep(outputs_fbc::(t, sp, elems), slice_rest_owned_ctor::(t, sp, len, elems)), <[T]>.full_borrow_content(t, slice_ref))() { + open True(); + open sep(outputs_fbc::(t, sp, elems), slice_rest_owned_ctor::(t, sp, len, elems))(); + open slice_rest_owned_ctor::(t, sp, len, elems)(); + outputs_fbc_to_regions::(t, sp, elems); + uncarve_regions::(t, sp, len, elems); + close slice_full_borrow_content::(t, slice_ref)(); + } { + close True(); + close_full_borrow_strong_(); + } + @*/ + //@ full_borrow_split(k, outputs_fbc::(t, sp, elems), slice_rest_owned_ctor::(t, sp, len, elems)); + //@ leak full_borrow(k, slice_rest_owned_ctor::(t, sp, len, elems)); + //@ close disjoint_mut_borrows::(k, t, out_ptr, sp, elems); +} + +unsafe fn get_disjoint_mut_proof__VeriFast_wrapper<'a, T, I, O, P>( + slice_ref: &'a mut [T], + indices: &[I], + out_ptr: *mut P, +) -> Result<(), GetDisjointMutError> +where + I: GetDisjointMutIndex + SliceIndex<[T], Output = O>, +//@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, slice_ref)) &*& [?f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> ?elems) &*& out_ptr[..indices.len()] |-> _; +//@ ens thread_token(t) &*& [q]lifetime_token('a) &*& [f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> elems) &*& match result { Result::Ok(u) => disjoint_mut_borrows::('a, t, out_ptr, strip_pointer_metadata(slice_ref as pointer) as *T, elems), Result::Err(e) => full_borrow('a, <[T]>.full_borrow_content(t, slice_ref)) &*& out_ptr[..indices.len()] |-> _ }; +//@ on_unwind_ens false; +{ + let len = slice_ref.len(); + let check = unsafe { get_disjoint_check_valid_proof__VeriFast_wrapper(indices, len) }; + match check { + Ok(()) => { + unsafe { + get_disjoint_unchecked_mut_proof__VeriFast_wrapper::(slice_ref, indices, out_ptr); + } + Ok(()) + } + Err(e) => Err(e), + } +} + +/// A helper trait for `<[T]>::get_disjoint_mut()`. +/// +/// # Safety +/// +/// If `is_in_bounds()` returns `true` and `is_overlapping()` returns `false`, +/// it must be safe to index the slice with the indices. +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +pub impl(self) unsafe trait GetDisjointMutIndex: Clone { + /// Returns `true` if `self` is in bounds for `len` slice elements. + #[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] + fn is_in_bounds(&self, len: usize) -> bool; + + /// Returns `true` if `self` overlaps with `other`. + /// + /// Note that we don't consider zero-length ranges to overlap at the beginning or the end, + /// but do consider them to overlap in the middle. + #[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] + fn is_overlapping(&self, other: &Self) -> bool; +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for usize { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool + //@ req [?f](*self |-> ?v); + //@ ens [f](*self |-> v) &*& result == std::slice::GetDisjointMutIndex_in_bounds::(v, len); + //@ on_unwind_ens false; + /*@ + safety_proof { + assert [?q]lifetime_token(?k); + open_frac_borrow(k, usize_full_borrow_content(_t, self), q); + open [?f]usize_full_borrow_content(_t, self)(); + call(); + close [f]usize_full_borrow_content(_t, self)(); + close_frac_borrow(f, usize_full_borrow_content(_t, self)); + } + @*/ + { + //@ usize_region_model(v, len, v); + *self < len + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool + //@ req [?f1](*self |-> ?v1) &*& [?f2](*other |-> ?v2); + //@ ens [f1](*self |-> v1) &*& [f2](*other |-> v2) &*& result == std::slice::GetDisjointMutIndex_overlapping::(v1, v2); + //@ on_unwind_ens false; + /*@ + safety_proof { + assert [_]frac_borrow(?k1, usize_full_borrow_content(_t, self)) &*& [?q1]lifetime_token(k1); + assert [_]frac_borrow(?k2, usize_full_borrow_content(_t, other)) &*& [?q2]lifetime_token(k2); + open_frac_borrow(k1, usize_full_borrow_content(_t, self), q1); + open [?f1]usize_full_borrow_content(_t, self)(); + open_frac_borrow(k2, usize_full_borrow_content(_t, other), q2); + open [?f2]usize_full_borrow_content(_t, other)(); + call(); + close [f2]usize_full_borrow_content(_t, other)(); + close_frac_borrow(f2, usize_full_borrow_content(_t, other)); + close [f1]usize_full_borrow_content(_t, self)(); + close_frac_borrow(f1, usize_full_borrow_content(_t, self)); + } + @*/ + { + //@ usize_region_model(v1, 0, v2); + *self == *other + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for Range { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + (self.start <= self.end) & (self.end <= len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + (self.start < other.end) & (other.start < self.end) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for RangeInclusive { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + (self.start <= self.end) & (self.end < len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + (self.start <= other.end) & (other.start <= self.end) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for range::Range { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + Range::from(*self).is_in_bounds(len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + Range::from(*self).is_overlapping(&Range::from(*other)) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for range::RangeInclusive { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + RangeInclusive::from(*self).is_in_bounds(len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + RangeInclusive::from(*self).is_overlapping(&RangeInclusive::from(*other)) + } +} + +#[cfg(kani)] +#[unstable(feature = "kani", issue = "none")] +mod verify { + use super::*; + + //generates proof_of_contract harness for align_to given the T (src) and U (dst) types + macro_rules! proof_of_contract_for_align_to { + ($harness:ident, $src:ty, $dst:ty) => { + #[kani::proof_for_contract(<[$src]>::align_to)] + fn $harness() { + const ARR_SIZE: usize = 100; + let src_arr: [$src; ARR_SIZE] = kani::any(); + let src_slice = kani::slice::any_slice_of_array(&src_arr); + let dst_slice = unsafe { src_slice.align_to::<$dst>() }; + } + }; + } + + //generates harnesses for align_to where T is a given src type and U is one of the main primitives + macro_rules! gen_align_to_harnesses { + ($mod_name:ident, $src_type:ty) => { + mod $mod_name { + use super::*; + + proof_of_contract_for_align_to!(align_to_u8, $src_type, u8); + proof_of_contract_for_align_to!(align_to_u16, $src_type, u16); + proof_of_contract_for_align_to!(align_to_u32, $src_type, u32); + proof_of_contract_for_align_to!(align_to_u64, $src_type, u64); + proof_of_contract_for_align_to!(align_to_u128, $src_type, u128); + proof_of_contract_for_align_to!(align_to_bool, $src_type, bool); + proof_of_contract_for_align_to!(align_to_char, $src_type, char); + proof_of_contract_for_align_to!(align_to_unit, $src_type, ()); + } + }; + } + + gen_align_to_harnesses!(align_to_from_u8, u8); + gen_align_to_harnesses!(align_to_from_u16, u16); + gen_align_to_harnesses!(align_to_from_u32, u32); + gen_align_to_harnesses!(align_to_from_u64, u64); + gen_align_to_harnesses!(align_to_from_u128, u128); + gen_align_to_harnesses!(align_to_from_bool, bool); + gen_align_to_harnesses!(align_to_from_char, char); + gen_align_to_harnesses!(align_to_from_unit, ()); + + //generates proof_of_contract harness for align_to_mut given the T (src) and U (dst) types + macro_rules! proof_of_contract_for_align_to_mut { + ($harness:ident, $src:ty, $dst:ty) => { + #[kani::proof_for_contract(<[$src]>::align_to_mut)] + fn $harness() { + const ARR_SIZE: usize = 100; + let mut src_arr: [$src; ARR_SIZE] = kani::any(); + let src_slice = kani::slice::any_slice_of_array_mut(&mut src_arr); + let dst_slice = unsafe { src_slice.align_to_mut::<$dst>() }; + } + }; + } + + //generates harnesses between a given src type and all the main primitives + macro_rules! gen_align_to_mut_harnesses { + ($mod_name:ident, $src_type:ty) => { + mod $mod_name { + use super::*; + + proof_of_contract_for_align_to_mut!(align_to_mut_u8, $src_type, u8); + proof_of_contract_for_align_to_mut!(align_to_mut_u16, $src_type, u16); + proof_of_contract_for_align_to_mut!(align_to_mut_u32, $src_type, u32); + proof_of_contract_for_align_to_mut!(align_to_mut_u64, $src_type, u64); + proof_of_contract_for_align_to_mut!(align_to_mut_u128, $src_type, u128); + proof_of_contract_for_align_to_mut!(align_to_mut_bool, $src_type, bool); + proof_of_contract_for_align_to_mut!(align_to_mut_char, $src_type, char); + proof_of_contract_for_align_to_mut!(align_to_mut_unit, $src_type, ()); + } + }; + } + + gen_align_to_mut_harnesses!(align_to_mut_from_u8, u8); + gen_align_to_mut_harnesses!(align_to_mut_from_u16, u16); + gen_align_to_mut_harnesses!(align_to_mut_from_u32, u32); + gen_align_to_mut_harnesses!(align_to_mut_from_u64, u64); + gen_align_to_mut_harnesses!(align_to_mut_from_u128, u128); + gen_align_to_mut_harnesses!(align_to_mut_from_bool, bool); + gen_align_to_mut_harnesses!(align_to_mut_from_char, char); + gen_align_to_mut_harnesses!(align_to_mut_from_unit, ()); + + #[kani::proof] + fn check_reverse() { + let mut a: [u8; 100] = kani::any(); + a.reverse(); + } + + // Const-generic functions. The VeriFast proof in verifast-proofs/core/slice verifies these + // through runtime-`n` transcriptions (VeriFast cannot yet attach specifications to + // `` functions); the harnesses below run the exact shipped bodies, bounded in slice + // length and monomorphized over a few element types and chunk sizes. + + const CG_ARR_SIZE: usize = 12; + + macro_rules! proof_of_contract_for_as_chunks_unchecked { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof_for_contract(<[$t]>::as_chunks_unchecked)] + fn $harness() { + let arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let chunks = unsafe { s.as_chunks_unchecked::<$n>() }; + assert_eq!(chunks.len(), s.len() / $n); + } + }; + } + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u8_1, u8, 1); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u8_3, u8, 3); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u32_2, u32, 2); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_unit_4, (), 4); + + macro_rules! proof_of_contract_for_as_chunks_unchecked_mut { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof_for_contract(<[$t]>::as_chunks_unchecked_mut)] + fn $harness() { + let mut arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let chunks = unsafe { s.as_chunks_unchecked_mut::<$n>() }; + assert_eq!(chunks.len(), len / $n); + } + }; + } + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u8_1, u8, 1); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u8_3, u8, 3); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u32_2, u32, 2); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_unit_4, (), 4); + + #[kani::proof_for_contract(<[u8]>::get_disjoint_unchecked_mut)] + fn check_get_disjoint_unchecked_mut_usize() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let indices: [usize; 3] = kani::any(); + let [a, b, c] = unsafe { s.get_disjoint_unchecked_mut(indices) }; + *a = 1; + *b = 2; + *c = 3; + } + + #[kani::proof_for_contract(<[u32]>::get_disjoint_unchecked_mut)] + fn check_get_disjoint_unchecked_mut_range() { + let mut arr: [u32; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let indices: [Range; 2] = [kani::any()..kani::any(), kani::any()..kani::any()]; + let [a, b] = unsafe { s.get_disjoint_unchecked_mut(indices) }; + if let Some(x) = a.first_mut() { + *x = 1; + } + if let Some(y) = b.first_mut() { + *y = 2; + } + } + + macro_rules! check_chunk_accessors { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof] + fn $harness() { + let mut arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let len = s.len(); + match s.first_chunk::<$n>() { + Some(c) => assert!(len >= $n && c.as_ptr() == s.as_ptr()), + None => assert!(len < $n), + } + match s.last_chunk::<$n>() { + Some(c) => { + assert!(len >= $n && c.as_ptr() == unsafe { s.as_ptr().add(len - $n) }) + } + None => assert!(len < $n), + } + match s.split_first_chunk::<$n>() { + Some((c, rest)) => assert!(c.len() + rest.len() == len), + None => assert!(len < $n), + } + match s.split_last_chunk::<$n>() { + Some((rest, c)) => assert!(rest.len() + c.len() == len), + None => assert!(len < $n), + } + let (chunks, rem) = s.as_chunks::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + let (rem, chunks) = s.as_rchunks::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + match s.first_chunk_mut::<$n>() { + Some(c) => assert!(len >= $n && c.len() == $n), + None => assert!(len < $n), + } + match s.last_chunk_mut::<$n>() { + Some(c) => assert!(len >= $n && c.len() == $n), + None => assert!(len < $n), + } + match s.split_first_chunk_mut::<$n>() { + Some((c, rest)) => assert!(c.len() + rest.len() == len), + None => assert!(len < $n), + } + match s.split_last_chunk_mut::<$n>() { + Some((rest, c)) => assert!(rest.len() + c.len() == len), + None => assert!(len < $n), + } + let (chunks, rem) = s.as_chunks_mut::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + } + }; + } + check_chunk_accessors!(check_chunk_accessors_u8_1, u8, 1); + check_chunk_accessors!(check_chunk_accessors_u8_3, u8, 3); + check_chunk_accessors!(check_chunk_accessors_u32_2, u32, 2); + check_chunk_accessors!(check_chunk_accessors_unit_5, (), 5); + + macro_rules! check_as_flattened { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof] + fn $harness() { + let mut arr: [[$t; $n]; 4] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let flat = s.as_flattened(); + assert!(flat.len() == s.len() * $n); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let flat = s.as_flattened_mut(); + assert!(flat.len() == len * $n); + } + }; + } + check_as_flattened!(check_as_flattened_u8_3, u8, 3); + check_as_flattened!(check_as_flattened_u32_2, u32, 2); + check_as_flattened!(check_as_flattened_u8_0, u8, 0); + + #[kani::proof] + fn check_as_simd_u8_4() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let (prefix, middle, suffix) = s.as_simd::<4>(); + assert!(prefix.len() + middle.len() * 4 + suffix.len() == s.len()); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let (prefix, middle, suffix) = s.as_simd_mut::<4>(); + assert!(prefix.len() + middle.len() * 4 + suffix.len() == len); + } + + #[kani::proof] + fn check_get_disjoint_mut_usize() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let indices: [usize; 3] = kani::any(); + let valid = get_disjoint_check_valid(&indices, len).is_ok(); + match s.get_disjoint_mut(indices) { + Ok([a, b, c]) => { + assert!(valid); + *a = 1; + *b = 2; + *c = 3; + } + Err(_) => assert!(!valid), + } + } + + #[kani::proof] + fn check_get_disjoint_mut_range() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let indices: [Range; 2] = [kani::any()..kani::any(), kani::any()..kani::any()]; + let valid = get_disjoint_check_valid(&indices, len).is_ok(); + match s.get_disjoint_mut(indices) { + Ok([a, b]) => { + assert!(valid); + assert!(a.len() + b.len() <= len); + } + Err(_) => assert!(!valid), + } + } + + #[kani::proof] + fn check_get_disjoint_check_valid() { + let len: usize = kani::any(); + kani::assume(len <= CG_ARR_SIZE); + let indices: [usize; 3] = kani::any(); + let r = get_disjoint_check_valid(&indices, len); + let in_bounds = indices.iter().all(|i| *i < len); + let disjoint = + indices[0] != indices[1] && indices[0] != indices[2] && indices[1] != indices[2]; + assert!(r.is_ok() == (in_bounds && disjoint)); + } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/verified/slice/ascii.rs b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/ascii.rs new file mode 100644 index 0000000000000..bf427f448fe55 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/ascii.rs @@ -0,0 +1,4 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{EscapeAscii, SplitAsciiWhitespace, is_ascii_simple}; diff --git a/verifast-proofs/core/slice/mod.rs-negative/verified/slice/cmp.rs b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/cmp.rs new file mode 100644 index 0000000000000..76f6305d79eb4 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/cmp.rs @@ -0,0 +1,7 @@ + +pub trait SliceContains { + fn slice_contains(&self, x: &[T]) -> bool; +} +impl SliceContains for T { + fn slice_contains(&self, _x: &[T]) -> bool { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/verified/slice/index.rs b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/index.rs new file mode 100644 index 0000000000000..9fc403d41a778 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/index.rs @@ -0,0 +1,4 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{SliceIndex, range, try_range}; diff --git a/verifast-proofs/core/slice/mod.rs-negative/verified/slice/iter.rs b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/iter.rs new file mode 100644 index 0000000000000..107231ba4b021 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/iter.rs @@ -0,0 +1,10 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{ + ArrayWindows, ChunkBy, ChunkByMut, Chunks, ChunksMut, Windows, + ChunksExact, ChunksExactMut, Iter, IterMut, + RChunks, RChunksExact, RChunksExactMut, RChunksMut, + RSplit, RSplitMut, RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut, + SplitInclusive, SplitInclusiveMut, +}; diff --git a/verifast-proofs/core/slice/mod.rs-negative/verified/slice/memchr.rs b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/memchr.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/verifast-proofs/core/slice/mod.rs-negative/verified/slice/raw.rs b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/raw.rs new file mode 100644 index 0000000000000..b5fff9064c46f --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/raw.rs @@ -0,0 +1,372 @@ +//! Free functions to create `&[T]` and `&mut [T]`. + +use crate::ops::Range; +use crate::{array, ptr, ub_checks}; + +/// Forms a slice from a pointer and a length. +/// +/// The `len` argument is the number of **elements**, not the number of bytes. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be non-null, [valid] for reads for `len * size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. See [below](#incorrect-usage) +/// for an example incorrectly not taking this into account. +/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total size `len * size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// use std::slice; +/// +/// // manifest a slice for a single element +/// let x = 42; +/// let ptr = &x as *const _; +/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; +/// assert_eq!(slice[0], 42); +/// ``` +/// +/// ### Incorrect usage +/// +/// The following `join_slices` function is **unsound** ⚠️ +/// +/// ```rust,no_run +/// use std::slice; +/// +/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { +/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); +/// let snd_start = snd.as_ptr(); +/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); +/// unsafe { +/// // The assertion above ensures `fst` and `snd` are contiguous, but they might +/// // still be contained within _different allocations_, in which case +/// // creating this slice is undefined behavior. +/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) +/// } +/// } +/// +/// fn main() { +/// // `a` and `b` are different allocations... +/// let a = 42; +/// let b = 27; +/// // ... which may nevertheless be laid out contiguously in memory: | a | b | +/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB +/// } +/// ``` +/// +/// ### FFI: Handling null pointers +/// +/// In languages such as C++, pointers to empty collections are not guaranteed to be non-null. +/// When accepting such pointers, they have to be checked for null-ness to avoid undefined +/// behavior. +/// +/// ``` +/// use std::slice; +/// +/// /// Sum the elements of an FFI slice. +/// /// +/// /// # Safety +/// /// +/// /// If ptr is not NULL, it must be correctly aligned and +/// /// point to `len` initialized items of type `f32`. +/// unsafe extern "C" fn sum_slice(ptr: *const f32, len: usize) -> f32 { +/// let data = if ptr.is_null() { +/// // `len` is assumed to be 0. +/// &[] +/// } else { +/// // SAFETY: see function docstring. +/// unsafe { slice::from_raw_parts(ptr, len) } +/// }; +/// data.into_iter().sum() +/// } +/// +/// // This could be the result of C++'s std::vector::data(): +/// let ptr = std::ptr::null(); +/// // And this could be std::vector::size(): +/// let len = 0; +/// assert_eq!(unsafe { sum_slice(ptr, len) }, 0.0); +/// ``` +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] +#[must_use] +#[rustc_diagnostic_item = "slice_from_raw_parts"] +#[track_caller] +#[cfg_attr(rapx, rapx::requires(NonNull(data)))] +#[cfg_attr(rapx, rapx::requires(ValidPtr(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Init(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Alive(data, 'a)))] +#[cfg_attr(rapx, rapx::requires(Alias(data)))] +#[cfg_attr(rapx, rapx::requires(Align(data, T)))] +#[cfg_attr(rapx, rapx::requires(ValidNum(size_of(T) * len <= isize::MAX)))] +pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] +//@ req len * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(data) == true &*& pointer_within_limits(data + len) == true; +//@ ens result == ptr::mk_slice::(data, len) &*& strip_pointer_metadata(result as pointer) as *T == data &*& result as *T == data &*& result.len() == len; +//@ on_unwind_ens false; +{ + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`", + ( + data: *mut () = data as *mut (), + size: usize = size_of::(), + align: usize = align_of::(), + len: usize = len, + ) => + ub_checks::maybe_is_aligned_and_not_null(data, align, false) + && ub_checks::is_valid_allocation_size(size, len) + ); + &*ptr::slice_from_raw_parts(data, len) + } +} + +/// Performs the same functionality as [`from_raw_parts`], except that a +/// mutable slice is returned. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be non-null, [valid] for both reads and writes for `len * size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total size `len * size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")] +#[must_use] +#[rustc_diagnostic_item = "slice_from_raw_parts_mut"] +#[track_caller] +#[cfg_attr(rapx, rapx::requires(NonNull(data)))] +#[cfg_attr(rapx, rapx::requires(ValidPtr(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Init(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Alive(data, 'a)))] +#[cfg_attr(rapx, rapx::requires(Alias(data)))] +#[cfg_attr(rapx, rapx::requires(Align(data, T)))] +#[cfg_attr(rapx, rapx::requires(ValidNum(size_of(T) * len <= isize::MAX)))] +pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] +//@ req len * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(data) == true &*& pointer_within_limits(data + len) == true; +//@ ens result == ptr::mk_slice::(data, len) &*& strip_pointer_metadata(result as pointer) as *T == data &*& result as *T == data &*& result.len() == len; +//@ on_unwind_ens false; +{ + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`", + ( + data: *mut () = data as *mut (), + size: usize = size_of::(), + align: usize = align_of::(), + len: usize = len, + ) => + ub_checks::maybe_is_aligned_and_not_null(data, align, false) + && ub_checks::is_valid_allocation_size(size, len) + ); + &mut *ptr::slice_from_raw_parts_mut(data, len) + } +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +#[rustc_const_stable(feature = "const_slice_from_ref_shared", since = "1.63.0")] +#[rustc_diagnostic_item = "slice_from_ref"] +#[must_use] +pub const fn from_ref(s: &T) -> &[T] { + array::from_ref(s) +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +#[rustc_const_stable(feature = "const_slice_from_ref", since = "1.83.0")] +#[must_use] +pub const fn from_mut(s: &mut T) -> &mut [T] { + array::from_mut(s) +} + +/// Forms a slice from a pointer range. +/// +/// This function is useful for interacting with foreign interfaces which +/// use two pointers to refer to a range of elements in memory, as is +/// common in C++. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * The `start` pointer of the range must be a non-null, [valid] and properly aligned pointer +/// to the first element of a slice. +/// +/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* +/// the last element, such that the offset from the end to the start pointer is +/// the length of the slice. +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// +/// * The range must contain `N` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `start` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements. +/// +/// # Panics +/// +/// This function panics if `T` is a Zero-Sized Type (“ZST”). +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_from_ptr_range)] +/// +/// use core::slice; +/// +/// let x = [1, 2, 3]; +/// let range = x.as_ptr_range(); +/// +/// unsafe { +/// assert_eq!(slice::from_ptr_range(range), &x); +/// } +/// ``` +/// +/// [valid]: ptr#safety +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +#[rustc_const_unstable(feature = "const_slice_from_ptr_range", issue = "89792")] +#[track_caller] +pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { + // SAFETY: the caller must uphold the safety contract for `from_ptr_range`. + unsafe { from_raw_parts(range.start, range.end.offset_from_unsigned(range.start)) } +} + +/// Forms a mutable slice from a pointer range. +/// +/// This is the same functionality as [`from_ptr_range`], except that a +/// mutable slice is returned. +/// +/// This function is useful for interacting with foreign interfaces which +/// use two pointers to refer to a range of elements in memory, as is +/// common in C++. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * The `start` pointer of the range must be a non-null, [valid] and properly aligned pointer +/// to the first element of a slice. +/// +/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* +/// the last element, such that the offset from the end to the start pointer is +/// the length of the slice. +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// +/// * The range must contain `N` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `start` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements. +/// +/// # Panics +/// +/// This function panics if `T` is a Zero-Sized Type (“ZST”). +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_from_ptr_range)] +/// +/// use core::slice; +/// +/// let mut x = [1, 2, 3]; +/// let range = x.as_mut_ptr_range(); +/// +/// unsafe { +/// assert_eq!(slice::from_mut_ptr_range(range), &mut [1, 2, 3]); +/// } +/// ``` +/// +/// [valid]: ptr#safety +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +#[rustc_const_unstable(feature = "const_slice_from_mut_ptr_range", issue = "89792")] +pub const unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] { + // SAFETY: the caller must uphold the safety contract for `from_mut_ptr_range`. + unsafe { from_raw_parts_mut(range.start, range.end.offset_from_unsigned(range.start)) } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/verified/slice/rotate.rs b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/rotate.rs new file mode 100644 index 0000000000000..e688d40f8435c --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/rotate.rs @@ -0,0 +1,619 @@ +use crate::mem::{MaybeUninit, SizedTypeProperties}; +use crate::ptr; + +type BufType = [usize; 32]; + +const unsafe fn uninit_buf__VeriFast_wrapper() -> MaybeUninit<(BufType, [T; 0])> +//@ req true; +//@ ens true; +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + MaybeUninit::<(BufType, [T; 0])>::uninit() +} + +const unsafe fn uninit_buf_as_mut_ptr__VeriFast_wrapper( + rawarray: &mut MaybeUninit<(BufType, [T; 0])>, +) -> *mut (BufType, [T; 0]) +//@ req *rawarray |-> ?v; +//@ ens *rawarray |-> v &*& result == rawarray as *mut (BufType, [T; 0]); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + rawarray.as_mut_ptr() +} + +const unsafe fn ptr_replace__VeriFast_wrapper(dst: *mut T, src: T) -> T +//@ req *dst |-> ?v; +//@ ens *dst |-> src &*& result == v; +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + unsafe { dst.replace(src) } +} + +/*@ +lem rotate_ptr_limits(ptr: *T, len: usize, mid: usize) + req 0 <= mid &*& mid <= len &*& 0 < std::mem::size_of::() &*& len * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(ptr) == true &*& pointer_within_limits(ptr + len) == true; + ens mid <= isize::MAX &*& len - mid <= isize::MAX &*& len <= isize::MAX &*& mid * std::mem::size_of::() <= isize::MAX &*& (len - mid) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(ptr + mid) == true &*& ((ptr + mid) + (len - mid)) == ptr + len &*& ((ptr + len) - (len - mid)) == ptr + mid; +{ + mul_mono_l(1, std::mem::size_of::(), len); + mul_mono_l(0, mid, std::mem::size_of::()); + mul_mono_l(mid, len, std::mem::size_of::()); + mul_mono_l(0, len - mid, std::mem::size_of::()); + mul_mono_l(len - mid, len, std::mem::size_of::()); +} + +// Reinterpretation of the uninitialized stack buffer `MaybeUninit<(BufType, [T; 0])>` (whose size is +// `size_of::()`, as `[T; 0]` is a ZST) as `k` uninitialized `T` slots, and back. VeriFast's +// prelude has `u8s__to_array_` only for `u8` reinterpretation, so this is axiomatized, with the +// buffer type fixed to the one `ptr_rotate_memmove` uses and the bound stated in bytes. +pred rawarray_rest(rawarray: *std::mem::MaybeUninit<([usize; 32], [T; 0])>, k: usize); + +lem rawarray_to_buf(rawarray: *std::mem::MaybeUninit<([usize; 32], [T; 0])>, buf: *T, k: usize) + req *rawarray |-> ?_ &*& buf == rawarray as *T &*& 0 <= k &*& 0 < std::mem::size_of::() &*& k * std::mem::size_of::() <= std::mem::size_of(typeid([usize; 32])); + ens buf[..k] |-> _ &*& rawarray_rest::(rawarray, k); +{ + // https://github.com/verifast/verifast/issues/1053 + assume(false); +} + +lem buf_to_rawarray(rawarray: *std::mem::MaybeUninit<([usize; 32], [T; 0])>, buf: *T, k: usize) + req buf[..k] |-> _ &*& rawarray_rest::(rawarray, k); + ens *rawarray |-> ?_; +{ + // https://github.com/verifast/verifast/issues/1053 + assume(false); +} +@*/ + +/// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first +/// element. Equivalently, rotates the range `left` elements to the left or `right` elements to the +/// right. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +pub(super) const unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) +//@ req thread_token(?t) &*& (mid - left)[..left + right] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 <= left &*& 0 <= right &*& left + right <= usize::MAX &*& (left + right) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(mid - left) == true &*& pointer_within_limits(mid + right) == true; +//@ ens thread_token(t) &*& (mid - left)[..left + right] |-> ?elems1 &*& foreach(elems1, own::(t)); +//@ on_unwind_ens false; +{ + if T::IS_ZST { + return; + } + // abort early if the rotate is a no-op + if (left == 0) || (right == 0) { + return; + } + // `T` is not a zero-sized type, so it's okay to divide by its size. + //@ std::alloc::is_valid_layout_size_of_align_of::(); + if !cfg!(feature = "optimize_for_size") + // FIXME(const-hack): Use cmp::min when available in const + && const_min(left, right) <= size_of::() / size_of::() + { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_memmove(left, mid, right) }; + } else if !cfg!(feature = "optimize_for_size") + && ((left + right < 24) || (size_of::() > size_of::<[usize; 4]>())) + { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_gcd(left, mid, right) } + } else { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_swap(left, mid, right) } + } +} + +/// Algorithm 1 is used if `min(left, right)` is small enough to fit onto a stack buffer. The +/// `min(left, right)` elements are copied onto the buffer, `memmove` is applied to the others, and +/// the ones on the buffer are moved back into the hole on the opposite side of where they +/// originated. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +const unsafe fn ptr_rotate_memmove(left: usize, mid: *mut T, right: usize) +//@ req thread_token(?t) &*& (mid - left)[..left + right] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 < left &*& 0 < right &*& (left + right) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(mid - left) == true &*& pointer_within_limits(mid + right) == true &*& 0 < std::mem::size_of::() &*& (if right < left { right } else { left }) <= std::mem::size_of(typeid([usize; 32])) / std::mem::size_of::(); +//@ ens thread_token(t) &*& (mid - left)[..left + right] |-> ?elems1 &*& foreach(elems1, own::(t)); +//@ on_unwind_ens false; +{ + //@ let p_start = mid - left; + //@ let n_total = left + right; + //@ rotate_ptr_limits::(p_start, n_total, left); + //@ rotate_ptr_limits::(p_start, n_total, right); + // The `[T; 0]` here is to ensure this is appropriately aligned for T + let mut rawarray = unsafe { uninit_buf__VeriFast_wrapper::() }; + let buf = unsafe { uninit_buf_as_mut_ptr__VeriFast_wrapper::(&mut rawarray) } as *mut T; + // SAFETY: `mid-left <= mid-left+right < mid+right` + let dim = unsafe { mid.sub(left).add(right) }; + if left <= right { + // SAFETY: + // + // 1) The `if` condition about the sizes ensures `[mid-left; left]` will fit in + // `buf` without overflow and `buf` was created just above and so cannot be + // overlapped with any value of `[mid-left; left]` + // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care + // about overlaps here. + // 3) The `if` condition about `left <= right` ensures writing `left` elements to + // `dim = mid-left+right` is valid because: + // - `buf` is valid and `left` elements were written in it in 1) + // - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)` + unsafe { + //@ std::alloc::is_valid_layout_size_of_align_of::<[usize; 32]>(); + //@ div_rem_nonneg(std::mem::size_of(typeid([usize; 32])), std::mem::size_of::()); + //@ mul_mono_l(left, std::mem::size_of(typeid([usize; 32])) / std::mem::size_of::(), std::mem::size_of::()); + //@ rawarray_to_buf(&rawarray, buf, left); + //@ array_split(p_start, left); + //@ foreach_split(elems, own::(t), left); + // 1) + ptr::copy_nonoverlapping(mid.sub(left), buf, left); + //@ array_join(p_start); + //@ close ptr::copy_context::(p_start, n_total, left, 0, right, elems); + // 2) + ptr::copy(mid, mid.sub(left), right); + //@ take_append_l(right, drop(left, elems), drop(right, elems)); + //@ array_split(p_start, right); + //@ array_to_array_(p_start + right); + // 3) + ptr::copy_nonoverlapping(buf, dim, left); + //@ array_join(p_start); + //@ foreach_append(drop(left, elems), take(left, elems)); + //@ array_to_array_(buf); + //@ buf_to_rawarray(&rawarray, buf, left); + } + } else { + // SAFETY: same reasoning as above but with `left` and `right` reversed + unsafe { + //@ std::alloc::is_valid_layout_size_of_align_of::<[usize; 32]>(); + //@ div_rem_nonneg(std::mem::size_of(typeid([usize; 32])), std::mem::size_of::()); + //@ mul_mono_l(right, std::mem::size_of(typeid([usize; 32])) / std::mem::size_of::(), std::mem::size_of::()); + //@ rawarray_to_buf(&rawarray, buf, right); + //@ array_split(p_start, left); + //@ foreach_split(elems, own::(t), left); + ptr::copy_nonoverlapping(mid, buf, right); + //@ array_join(p_start); + //@ close ptr::copy_context::(p_start, n_total, 0, right, left, elems); + ptr::copy(mid.sub(left), dim, left); + //@ take_append_l(right, take(right, elems), take(left, elems)); + //@ drop_append(right, take(right, elems), take(left, elems)); + //@ array_split(p_start, right); + //@ array_to_array_(p_start); + ptr::copy_nonoverlapping(buf, mid.sub(left), right); + //@ array_join(p_start); + //@ foreach_append(drop(left, elems), take(left, elems)); + //@ array_to_array_(buf); + //@ buf_to_rawarray(&rawarray, buf, right); + } + } +} + +/*@ +pred rotate_gcd_hole(t: thread_id_t, x: *T, n_total: usize, hole: usize) = + 0 <= hole &*& hole < n_total &*& + x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> _ &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)); + +pred rotate_gcd_step_ctxt(t: thread_id_t, x: *T, n_total: usize, hole: usize, i: usize) = + 0 <= hole &*& hole < n_total &*& 0 <= i &*& i < n_total &*& i != hole &*& + if i < hole { + x[..i] |-> ?p1 &*& foreach(p1, own::(t)) &*& + (x + i + 1)[..hole - i - 1] |-> ?p2 &*& foreach(p2, own::(t)) &*& + *(x + hole) |-> _ &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)) + } else { + x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> _ &*& + (x + hole + 1)[..i - hole - 1] |-> ?s1 &*& foreach(s1, own::(t)) &*& + (x + i + 1)[..n_total - i - 1] |-> ?s2 &*& foreach(s2, own::(t)) + }; + +lem rotate_gcd_open_hole(t: thread_id_t, x: *T, n_total: usize, hole: usize) + req x[..n_total] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 <= hole &*& hole < n_total; + ens x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> ?v &*& (.own)(t, v) &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)); +{ + array_split(x, hole); + foreach_split(elems, own::(t), hole); + let rest = drop(hole, elems); + open array(x + hole, n_total - hole, rest); + open foreach(rest, own::(t)); + assert *(x + hole) |-> ?v; + open own::(t)(v); +} + +lem rotate_gcd_finish_open_hole(t: thread_id_t, x: *T, n_total: usize, hole: usize) + req 0 <= hole &*& hole < n_total &*& + x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> ?v &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)); + ens rotate_gcd_hole::(t, x, n_total, hole); +{ + open points_to(x + hole, v); + close rotate_gcd_hole::(t, x, n_total, hole); +} + +lem rotate_gcd_extract_i(t: thread_id_t, x: *T, n_total: usize, hole: usize, i: usize) + req rotate_gcd_hole::(t, x, n_total, hole) &*& 0 <= i &*& i < n_total &*& i != hole; + ens rotate_gcd_step_ctxt::(t, x, n_total, hole, i) &*& *(x + i) |-> ?vi &*& (.own)(t, vi); +{ + open rotate_gcd_hole::(t, x, n_total, hole); + assert x[..hole] |-> ?prefix; + assert (x + hole + 1)[..n_total - hole - 1] |-> ?suffix; + if i < hole { + array_split(x, i); + foreach_split(prefix, own::(t), i); + let rest = drop(i, prefix); + open array(x + i, hole - i, rest); + open foreach(rest, own::(t)); + assert *(x + i) |-> ?vi; + open own::(t)(vi); + close rotate_gcd_step_ctxt::(t, x, n_total, hole, i); + } else { + let k = i - hole - 1; + array_split(x + hole + 1, k); + foreach_split(suffix, own::(t), k); + let rest = drop(k, suffix); + open array(x + i, n_total - i, rest); + open foreach(rest, own::(t)); + assert *(x + i) |-> ?vi; + open own::(t)(vi); + close rotate_gcd_step_ctxt::(t, x, n_total, hole, i); + } +} + +lem rotate_gcd_restore_i(t: thread_id_t, x: *T, n_total: usize, hole: usize, i: usize, v_new: T) + req rotate_gcd_step_ctxt::(t, x, n_total, hole, i) &*& *(x + i) |-> v_new &*& (.own)(t, v_new); + ens rotate_gcd_hole::(t, x, n_total, hole); +{ + open rotate_gcd_step_ctxt::(t, x, n_total, hole, i); + points_to_limits(x + i); + close own::(t)(v_new); + if i < hole { + assert x[..i] |-> ?p1; + assert (x + i + 1)[..hole - i - 1] |-> ?p2; + close foreach(cons(v_new, p2), own::(t)); + close array(x + i, hole - i, cons(v_new, p2)); + array_join(x); + foreach_append(p1, cons(v_new, p2)); + close rotate_gcd_hole::(t, x, n_total, hole); + } else { + assert (x + hole + 1)[..i - hole - 1] |-> ?s1; + assert (x + i + 1)[..n_total - i - 1] |-> ?s2; + close foreach(cons(v_new, s2), own::(t)); + close array(x + i, n_total - i, cons(v_new, s2)); + array_join(x + hole + 1); + foreach_append(s1, cons(v_new, s2)); + close rotate_gcd_hole::(t, x, n_total, hole); + } +} + +lem rotate_gcd_prep_close_hole(t: thread_id_t, x: *T, n_total: usize, hole: usize) + req rotate_gcd_hole::(t, x, n_total, hole); + ens 0 <= hole &*& hole < n_total &*& + x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> _ &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)); +{ + open rotate_gcd_hole::(t, x, n_total, hole); +} + +lem rotate_gcd_finish_close_hole(t: thread_id_t, x: *T, n_total: usize, hole: usize, v_final: T) + req 0 <= hole &*& hole < n_total &*& + x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> v_final &*& (.own)(t, v_final) &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)); + ens x[..n_total] |-> ?elems1 &*& foreach(elems1, own::(t)); +{ + points_to_limits(x + hole); + close own::(t)(v_final); + close foreach(cons(v_final, suffix), own::(t)); + close array(x + hole, n_total - hole, cons(v_final, suffix)); + array_join(x); + foreach_append(prefix, cons(v_final, suffix)); +} +@*/ + +/// Algorithm 2 is used for small values of `left + right` or for large `T`. The elements +/// are moved into their final positions one at a time starting at `mid - left` and advancing by +/// `right` steps modulo `left + right`, such that only one temporary is needed. Eventually, we +/// arrive back at `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps +/// skipped over elements. For example: +/// ```text +/// left = 10, right = 6 +/// the `^` indicates an element in its final place +/// 6 7 8 9 10 11 12 13 14 15 . 0 1 2 3 4 5 +/// after using one step of the above algorithm (The X will be overwritten at the end of the round, +/// and 12 is stored in a temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 2 3 4 5 +/// ^ +/// after using another step (now 2 is in the temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ +/// after the third step (the steps wrap around, and 8 is in the temporary): +/// X 7 2 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ ^ +/// after 7 more steps, the round ends with the temporary 0 getting put in the X: +/// 0 7 2 9 4 11 6 13 8 15 . 10 1 12 3 14 5 +/// ^ ^ ^ ^ ^ ^ ^ ^ +/// ``` +/// Fortunately, the number of skipped over elements between finalized elements is always equal, so +/// we can just offset our starting position and do more rounds (the total number of rounds is the +/// `gcd(left + right, right)` value). The end result is that all elements are finalized once and +/// only once. +/// +/// Algorithm 2 can be vectorized by chunking and performing many rounds at once, but there are too +/// few rounds on average until `left + right` is enormous, and the worst case of a single +/// round is always there. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +const unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) +//@ req thread_token(?t) &*& (mid - left)[..left + right] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 < left &*& 0 < right &*& 0 < std::mem::size_of::() &*& (left + right) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(mid - left) == true &*& pointer_within_limits(mid + right) == true; +//@ ens thread_token(t) &*& (mid - left)[..left + right] |-> ?elems1 &*& foreach(elems1, own::(t)); +//@ on_unwind_ens false; +{ + //@ let n_total = left + right; + //@ rotate_ptr_limits::(mid - left, n_total, left); + // Algorithm 2 + // Microbenchmarks indicate that the average performance for random shifts is better all + // the way until about `left + right == 32`, but the worst case performance breaks even + // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 + // `usize`s, this algorithm also outperforms other algorithms. + // SAFETY: callers must ensure `mid - left` is valid for reading and writing. + let x = unsafe { mid.sub(left) }; + // beginning of first round + // SAFETY: see previous comment. + //@ rotate_gcd_open_hole::(t, x, n_total, 0); + let mut tmp: T = unsafe { x.read() }; + //@ rotate_gcd_finish_open_hole::(t, x, n_total, 0); + let mut i = right; + // `gcd` can be found before hand by calculating `gcd(left + right, right)`, + // but it is faster to do one loop which calculates the gcd as a side effect, then + // doing the rest of the chunk + let mut gcd = right; + // benchmarks reveal that it is faster to swap temporaries all the way through instead + // of reading one temporary once, copying backwards, and then writing that temporary at + // the very end. This is possibly due to the fact that swapping or replacing temporaries + // uses only one memory address in the loop instead of needing to manage two. + loop { + //@ inv thread_token(t) &*& rotate_gcd_hole::(t, x, n_total, 0) &*& (.own)(t, tmp) &*& 1 <= gcd &*& gcd <= right &*& gcd <= i &*& 1 <= i &*& i < n_total &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(x) == true &*& pointer_within_limits(x + n_total) == true; + // [long-safety-expl] + // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and + // writing. + // + // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right` + // - `i <= left+right-1` is always true + // - if `i < left`, `right` is added so `i < left+right` and on the next + // iteration `left` is removed from `i` so it doesn't go further + // - if `i >= left`, `left` is removed immediately and so it doesn't go further. + // - overflows cannot happen for `i` since the function's safety contract ask for + // `mid+right-1 = x+left+right` to be valid for writing + // - underflows cannot happen because `i` must be bigger or equal to `left` for + // a subtraction of `left` to happen. + // + // So `x+i` is valid for reading and writing if the caller respected the contract + //@ rotate_ptr_limits::(x, n_total, i); + //@ rotate_gcd_extract_i::(t, x, n_total, 0, i); + //@ let old_tmp = tmp; + tmp = unsafe { ptr_replace__VeriFast_wrapper(x.add(i), tmp) }; + //@ rotate_gcd_restore_i::(t, x, n_total, 0, i, old_tmp); + // instead of incrementing `i` and then checking if it is outside the bounds, we + // check if `i` will go outside the bounds on the next increment. This prevents + // any wrapping of pointers or `usize`. + if i >= left { + i -= left; + if i == 0 { + // end of first round + // SAFETY: tmp has been read from a valid source and x is valid for writing + // according to the caller. + //@ rotate_gcd_prep_close_hole::(t, x, n_total, 0); + unsafe { x.write(tmp) }; + //@ rotate_gcd_finish_close_hole::(t, x, n_total, 0, tmp); + break; + } + // this conditional must be here if `left + right >= 15` + if i < gcd { + gcd = i; + } + } else { + i += right; + } + } + // finish the chunk with more rounds + // FIXME(const-hack): Use `for start in 1..gcd` when available in const + let mut start = 1; + loop { + //@ inv thread_token(t) &*& lifetime_token(func_lft) &*& x[..n_total] |-> ?cur_elems &*& foreach(cur_elems, own::(t)) &*& 1 <= start &*& 1 <= gcd &*& gcd <= left &*& gcd <= right &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(x) == true &*& pointer_within_limits(x + n_total) == true; + if start < gcd { + // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for + // reading and writing as per the function's safety contract, see [long-safety-expl] + // above + //@ rotate_ptr_limits::(x, n_total, start); + //@ rotate_gcd_open_hole::(t, x, n_total, start); + tmp = unsafe { x.add(start).read() }; + //@ rotate_gcd_finish_open_hole::(t, x, n_total, start); + // [safety-expl-addition] + // + // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the + // greatest common divisor of `(left+right, right)` means that `left = right` so + // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing + // according to the function's safety contract. + i = start + right; + loop { + //@ inv thread_token(t) &*& rotate_gcd_hole::(t, x, n_total, start) &*& (.own)(t, tmp) &*& 1 <= start &*& start < gcd &*& gcd <= left &*& gcd <= right &*& 0 <= i &*& i < n_total &*& i != start &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(x) == true &*& pointer_within_limits(x + n_total) == true; + // SAFETY: see [long-safety-expl] and [safety-expl-addition] + //@ rotate_ptr_limits::(x, n_total, i); + //@ rotate_gcd_extract_i::(t, x, n_total, start, i); + //@ let old_tmp2 = tmp; + tmp = unsafe { ptr_replace__VeriFast_wrapper(x.add(i), tmp) }; + //@ rotate_gcd_restore_i::(t, x, n_total, start, i, old_tmp2); + if i >= left { + i -= left; + if i == start { + // SAFETY: see [long-safety-expl] and [safety-expl-addition] + //@ rotate_ptr_limits::(x, n_total, start); + //@ rotate_gcd_prep_close_hole::(t, x, n_total, start); + unsafe { x.add(start).write(tmp) }; + //@ rotate_gcd_finish_close_hole::(t, x, n_total, start, tmp); + break; + } + } else { + i += right; + } + } + + start += 1; + } else { + break; + } + } +} + +/// Algorithm 3 utilizes repeated swapping of `min(left, right)` elements. +/// +/// /// +/// ```text +/// left = 11, right = 4 +/// [4 5 6 7 8 9 10 11 12 13 14 . 0 1 2 3] +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping the right most elements with elements to the left +/// [4 5 6 7 8 9 10 . 0 1 2 3] 11 12 13 14 +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping these +/// [4 5 6 . 0 1 2 3] 7 8 9 10 11 12 13 14 +/// we cannot swap any more, but a smaller rotation problem is left to solve +/// ``` +/// when `left < right` the swapping happens from the left instead. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +/*@ +pred rotate_swap_ctxt(t: thread_id_t, p_start: *T, n_total: usize, idx: usize, k: usize, vs1: list, vs2: list) = + 0 <= idx &*& 0 <= k &*& idx + 2 * k <= n_total &*& + p_start[..idx] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + (p_start + idx + 2 * k)[..n_total - idx - 2 * k] |-> ?suffix &*& foreach(suffix, own::(t)) &*& + foreach(vs1, own::(t)) &*& foreach(vs2, own::(t)); + +lem rotate_swap_extract(t: thread_id_t, p_start: *T, n_total: usize, idx: usize, k: usize) + req p_start[..n_total] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 <= idx &*& 0 <= k &*& idx + 2 * k <= n_total; + ens (p_start + idx)[..k] |-> ?vs1 &*& (p_start + idx + k)[..k] |-> ?vs2 &*& + rotate_swap_ctxt::(t, p_start, n_total, idx, k, vs1, vs2); +{ + array_split(p_start, idx); + foreach_split(elems, own::(t), idx); + let rest1 = drop(idx, elems); + array_split(p_start + idx, k); + foreach_split(rest1, own::(t), k); + let rest2 = drop(k, rest1); + array_split(p_start + idx + k, k); + foreach_split(rest2, own::(t), k); + close rotate_swap_ctxt::(t, p_start, n_total, idx, k, take(k, rest1), take(k, rest2)); +} + +lem rotate_swap_restore(t: thread_id_t, p_start: *T, n_total: usize, idx: usize, k: usize) + req rotate_swap_ctxt::(t, p_start, n_total, idx, k, ?vs1, ?vs2) &*& + (p_start + idx)[..k] |-> vs2 &*& (p_start + idx + k)[..k] |-> vs1; + ens p_start[..n_total] |-> ?elems1 &*& foreach(elems1, own::(t)); +{ + open rotate_swap_ctxt::(t, p_start, n_total, idx, k, vs1, vs2); + assert p_start[..idx] |-> ?prefix; + assert (p_start + idx + 2 * k)[..n_total - idx - 2 * k] |-> ?suffix; + array_join(p_start + idx + k); + foreach_append(vs1, suffix); + array_join(p_start + idx); + foreach_append(vs2, append(vs1, suffix)); + array_join(p_start); + foreach_append(prefix, append(vs2, append(vs1, suffix))); +} + +pred rotate_swap_state(p_start: *T, n_total: usize, left: usize, mid: *T, right: usize, offset: usize) = + 0 <= offset &*& offset + left + right <= n_total &*& mid == p_start + (offset + left); +@*/ + +#[inline] +const unsafe fn ptr_rotate_swap(mut left: usize, mut mid: *mut T, mut right: usize) +//@ req thread_token(?t) &*& (mid - left)[..left + right] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 < left &*& 0 < right &*& 0 < std::mem::size_of::() &*& (left + right) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(mid - left) == true &*& pointer_within_limits(mid + right) == true; +//@ ens thread_token(t) &*& (mid - left)[..left + right] |-> ?elems1 &*& foreach(elems1, own::(t)); +//@ on_unwind_ens false; +{ + //@ let p_start = mid - left; + //@ let n_total = left + right; + //@ close rotate_swap_state::(p_start, n_total, left, mid, right, 0); + loop { + //@ inv thread_token(t) &*& p_start[..n_total] |-> ?cur_elems &*& foreach(cur_elems, own::(t)) &*& rotate_swap_state::(p_start, n_total, left, mid, right, ?offset) &*& 0 < left &*& 0 < right &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(p_start) == true &*& pointer_within_limits(p_start + n_total) == true; + if left >= right { + // Algorithm 3 + // There is an alternate way of swapping that involves finding where the last swap + // of this algorithm would be, and swapping using that last chunk instead of swapping + // adjacent chunks like this algorithm is doing, but this way is still faster. + loop { + //@ inv thread_token(t) &*& p_start[..n_total] |-> ?cur_elems1 &*& foreach(cur_elems1, own::(t)) &*& rotate_swap_state::(p_start, n_total, left, mid, right, ?offset1) &*& left >= right &*& 0 < right &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(p_start) == true &*& pointer_within_limits(p_start + n_total) == true; + // SAFETY: + // `left >= right` so `[mid-right, mid+right)` is valid for reading and writing + // Subtracting `right` from `mid` each turn is counterbalanced by the addition and + // check after it. + unsafe { + //@ open rotate_swap_state::(p_start, n_total, left, mid, right, offset1); + //@ let idx = offset1 + left - right; + //@ rotate_swap_extract::(t, p_start, n_total, idx, right); + //@ rotate_ptr_limits::(p_start, n_total, offset1 + left); + //@ rotate_ptr_limits::(p_start, offset1 + left, idx); + ptr::swap_nonoverlapping(mid.sub(right), mid, right); + //@ rotate_swap_restore::(t, p_start, n_total, idx, right); + mid = mid.sub(right); + } + left -= right; + //@ close rotate_swap_state::(p_start, n_total, left, mid, right, offset1); + if left < right { + break; + } + } + } else { + // Algorithm 3, `left < right` + loop { + //@ inv thread_token(t) &*& p_start[..n_total] |-> ?cur_elems1 &*& foreach(cur_elems1, own::(t)) &*& rotate_swap_state::(p_start, n_total, left, mid, right, ?offset1) &*& right >= left &*& 0 < left &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(p_start) == true &*& pointer_within_limits(p_start + n_total) == true; + // SAFETY: `[mid-left, mid+left)` is valid for reading and writing because + // `left < right` so `mid+left < mid+right`. + // Adding `left` to `mid` each turn is counterbalanced by the subtraction and check + // after it. + unsafe { + //@ open rotate_swap_state::(p_start, n_total, left, mid, right, offset1); + //@ rotate_swap_extract::(t, p_start, n_total, offset1, left); + //@ rotate_ptr_limits::(p_start, n_total, offset1 + left); + //@ rotate_ptr_limits::(p_start, offset1 + left, offset1); + //@ rotate_ptr_limits::(p_start, n_total, offset1 + 2 * left); + ptr::swap_nonoverlapping(mid.sub(left), mid, left); + //@ rotate_swap_restore::(t, p_start, n_total, offset1, left); + mid = mid.add(left); + } + right -= left; + //@ close rotate_swap_state::(p_start, n_total, left, mid, right, offset1 + left); + if right < left { + break; + } + } + } + if (right == 0) || (left == 0) { + //@ open rotate_swap_state::(p_start, n_total, left, mid, right, _); + return; + } + } +} + +// FIXME(const-hack): Use cmp::min when available in const +const fn const_min(left: usize, right: usize) -> usize +//@ req true; +//@ ens result == if right < left { right } else { left }; +//@ on_unwind_ens false; +{ + if right < left { right } else { left } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/verified/slice/sort.rs b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/sort.rs new file mode 100644 index 0000000000000..bb060c9c9b963 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/sort.rs @@ -0,0 +1,11 @@ + +pub mod select { + pub fn partition_at_index(_v: &mut [T], _index: usize, _is_less: F) -> (&mut [T], &mut T, &mut [T]) + where F: FnMut(&T, &T) -> bool { loop {} } +} +pub mod unstable { + pub fn sort(_v: &mut [T], _is_less: &mut F) + where F: FnMut(&T, &T) -> bool { loop {} } + pub fn partial_sort(_v: &mut [T], _range: R, _is_less: F) + where R: core::ops::RangeBounds, F: FnMut(&T, &T) -> bool { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/verified/slice/specialize.rs b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/specialize.rs new file mode 100644 index 0000000000000..9bf035047a4ed --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/verified/slice/specialize.rs @@ -0,0 +1,7 @@ + +pub trait SpecFill { + fn spec_fill(&mut self, val: T); +} +impl SpecFill for [T] { + fn spec_fill(&mut self, _val: T) { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs-negative/verify.sh b/verifast-proofs/core/slice/mod.rs-negative/verify.sh new file mode 100755 index 0000000000000..ed4a4ea2758d5 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs-negative/verify.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# Negative test: verified/ contains a deliberately wrong proof (see the NEGATIVE TEST comment in +# verified/slice.rs). Both verifast and the refinement checker must fail on it. +set -e -x + +export VFVERSION=26.10 +if [ -f ../../../setup-verifast-home ]; then + . ../../../setup-verifast-home +fi +if ! command -v verifast >/dev/null 2>&1 && [ -d "$VERIFAST_HOME/bin" ]; then + export PATH="$VERIFAST_HOME/bin:$PATH" +fi + +# VeriFast 26.10 is built against rustc nightly-2026-09-25 (see setup-verifast-home). +# The `core` sysroot below must be compiled by that exact rustc, so it is built from the +# `rust-src` component of that toolchain rather than from the repository's `library/core` +# subtree, which tracks a newer nightly whose intrinsics and feature gates that rustc +# does not know. +VF_RUST_TOOLCHAIN=nightly-2026-09-25 +RUSTC="$(rustup which --toolchain $VF_RUST_TOOLCHAIN rustc 2>/dev/null || rustup which rustc 2>/dev/null || which rustc)" +CARGO="$(rustup which --toolchain $VF_RUST_TOOLCHAIN cargo 2>/dev/null || rustup which cargo 2>/dev/null || which cargo)" +HOST_TRIPLE="$("$RUSTC" -vV | sed -n 's/^host: //p')" +if [[ "$HOST_TRIPLE" == *"apple-darwin"* ]]; then + DYLIB_EXT="dylib" +else + DYLIB_EXT="so" +fi + +SYSROOT_REL="../../../../library/target/vf_sysroot" +SYSROOT_LIB_REL="$SYSROOT_REL/lib/rustlib/$HOST_TRIPLE/lib" + +if [ ! -f "$SYSROOT_LIB_REL/libcore_noslice.rlib" ] || [ ! -f "$SYSROOT_LIB_REL/libsafety.$DYLIB_EXT" ]; then + mkdir -p "$SYSROOT_LIB_REL" + RUSTC_SYSROOT="$("$RUSTC" --print sysroot)" + cp -n "$RUSTC_SYSROOT/lib/rustlib/$HOST_TRIPLE/lib/"* "$SYSROOT_LIB_REL/" || true + if [ -d ../../../../library/contracts/safety ]; then + (cd ../../../../library/contracts/safety && RUSTC="$RUSTC" "$CARGO" build --release) + cp "../../../../library/target/release/libsafety.$DYLIB_EXT" "$SYSROOT_LIB_REL/" + elif [ -d ../../../../deps/safety ]; then + (cd ../../../../deps/safety && RUSTC="$RUSTC" "$CARGO" build --release) + cp "../../../../deps/safety/target/release/libsafety.$DYLIB_EXT" "$SYSROOT_LIB_REL/" + fi + RUST_SRC="$RUSTC_SYSROOT/lib/rustlib/src/rust/library" + if [ ! -d "$RUST_SRC/core/src" ]; then + rustup component add rust-src --toolchain "$VF_RUST_TOOLCHAIN" + fi + CORE_SRC_TMP="$SYSROOT_REL/core_src/core" + rm -rf "$SYSROOT_REL/core_src" + mkdir -p "$CORE_SRC_TMP" + ln -s "$RUST_SRC/stdarch" "$SYSROOT_REL/core_src/stdarch" + ln -s "$RUST_SRC/portable-simd" "$SYSROOT_REL/core_src/portable-simd" + cp -R "$RUST_SRC/core/src" "$CORE_SRC_TMP/src" + # The four visibility/attribute edits that let the slice sources compile as a separate + # crate against this `core` (listed in README.md, "Sysroot"). + patch -p1 -d "$CORE_SRC_TMP/src" < ../mod.rs/core-sysroot.patch + "$RUSTC" --crate-name core --edition=2024 "$CORE_SRC_TMP/src/lib.rs" --crate-type lib \ + -C embed-bitcode=no -Z force-unstable-if-unmarked -A warnings \ + -L dependency="$SYSROOT_LIB_REL" \ + --extern "safety=$SYSROOT_LIB_REL/libsafety.$DYLIB_EXT" \ + -o "$SYSROOT_LIB_REL/libcore_noslice.rlib" + rm -rf "$SYSROOT_REL/core_src" +fi + +SYSROOT="$(cd "$SYSROOT_REL" && pwd)" +SYSROOT_LIB="$SYSROOT/lib/rustlib/$HOST_TRIPLE/lib" +RUSTC_ARGS="--crate-type lib --edition=2024 --extern core=$SYSROOT_LIB/libcore_noslice.rlib --extern safety=$SYSROOT_LIB/libsafety.$DYLIB_EXT -L dependency=$SYSROOT_LIB -Z force-unstable-if-unmarked -A warnings" + +! verifast -rustc_args "$RUSTC_ARGS" -extern_spec std=core.rsspec -skip_specless_fns -ignore_unwind_paths -allow_assume -allow_ignore_ref_creation verified/lib.rs +! refinement-checker --rustc-args "$RUSTC_ARGS" original/lib.rs verified/lib.rs > /dev/null 2>&1 +if ! diff original/slice.rs ../../../../library/core/src/slice/mod.rs; then + echo "::error title=Please run verifast-proofs/patch-verifast-proofs.sh::Some VeriFast proofs are out of date; please chdir to verifast-proofs and run patch-verifast-proofs.sh to update them." + false +fi +if ! diff original/slice/raw.rs ../../../../library/core/src/slice/raw.rs; then + echo "::error title=Please run verifast-proofs/patch-verifast-proofs.sh::Some VeriFast proofs are out of date; please chdir to verifast-proofs and run patch-verifast-proofs.sh to update them." + false +fi +if ! diff original/slice/rotate.rs ../../../../library/core/src/slice/rotate.rs; then + echo "::error title=Please run verifast-proofs/patch-verifast-proofs.sh::Some VeriFast proofs are out of date; please chdir to verifast-proofs and run patch-verifast-proofs.sh to update them." + false +fi + diff --git a/verifast-proofs/core/slice/mod.rs/README.md b/verifast-proofs/core/slice/mod.rs/README.md new file mode 100644 index 0000000000000..a36f4804cc949 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/README.md @@ -0,0 +1,125 @@ +# Partial verification of `core::slice` with VeriFast + +With certain [caveats](#caveats), this proof verifies [soundness](https://doc.rust-lang.org/nomicon/working-with-unsafe.html) (absence of Undefined Behavior and semantic well-typedness) and functional specifications for core slice operations across `core/src/slice/mod.rs`, `core/src/slice/raw.rs`, and `core/src/slice/rotate.rs`: + +- **Slice queries and pointer conversions (`[T]`)**: + - `len`, `as_ptr`, `as_mut_ptr`, `as_mut_ptr_range` +- **Raw slice construction (`core::slice::raw`)**: + - `from_raw_parts`, `from_raw_parts_mut` +- **Unchecked indexing and splitting (`[T]`)**: + - `get_unchecked`, `get_unchecked_mut` + - `split_at`, `split_at_mut`, `split_at_unchecked`, `split_at_mut_unchecked`, `split_at_checked`, `split_at_mut_checked` +- **Fixed-size array chunking and flattening (`[T]` and `[[T; N]]`)**: + - `first_chunk`, `first_chunk_mut`, `split_first_chunk`, `split_first_chunk_mut`, `split_last_chunk`, `split_last_chunk_mut`, `last_chunk`, `last_chunk_mut` + - `as_chunks`, `as_chunks_unchecked`, `as_chunks_mut`, `as_chunks_unchecked_mut`, `as_rchunks` + - `as_flattened`, `as_flattened_mut` +- **In-place permutation, reversal, and rotation (`[T]` and `core::slice::rotate`)**: + - `swap_unchecked`, `reverse` (and internal `revswap`) + - `rotate_left`, `rotate_right` + - `ptr_rotate`, `ptr_rotate_memmove`, `ptr_rotate_gcd`, `ptr_rotate_swap`, `const_min` +- **Bulk copying and swapping (`[T]`)**: + - `copy_from_slice` (and internal `copy_from_slice_impl`), `copy_within`, `swap_with_slice` +- **Searching and deduplication (`[T]`)**: + - `binary_search_by`, `partition_dedup_by` +- **Transmutation and alignment (`[T]`)**: + - `align_to`, `align_to_mut` (and internal `gcd`, `align_to_offsets`), `as_simd`, `as_simd_mut` +- **Disjoint mutable indexing (`[T]` and `GetDisjointMutIndex`)**: + - `get_disjoint_mut`, `get_disjoint_unchecked_mut`, `get_disjoint_check_valid` + - `GetDisjointMutIndex::is_in_bounds` and `GetDisjointMutIndex::is_overlapping` for `usize`, verified against the region model (see the caveats); the `Range`, `RangeInclusive` and `core::range::*` implementations are not verified (no specification: see the caveats for why VeriFast 26.10 cannot take one) + +## Tour of the proof + +### Crate setup and `refinement-checker` + +Because `core::slice` is part of `core` itself, verifying `core/src/slice/mod.rs` with `rustc` requires compiling against a version of `core` that does not duplicate the slice inherent implementations under test (`libcore_noslice.rlib`), created by `verify.sh`. That sysroot `core` is built from the `rust-src` component of the Rust toolchain that VeriFast 26.10 targets (`nightly-2026-09-25`, see `setup-verifast-home`), not from this repository's `library/core` subtree: VeriFast's `rustc` frontend can only compile a `core` that matches its own nightly, while the subtree tracks a newer one (at the time of writing `nightly-2026-10-12`, whose `abort_immediate`/`type_id_*` intrinsics and stabilized `optimize` attribute the older frontend rejects). The files under verification (`slice.rs`, `slice/raw.rs`, `slice/rotate.rs`) are the repository's, byte-for-byte; only the surrounding `core` they are compiled against comes from VeriFast's toolchain, in the same way that the `LinkedList` and `RawVec` proofs verify the repository's `alloc` sources against VeriFast's own `std` specifications. To make that `core` compile without the slice inherent implementations (which `verified/slice.rs` provides) and to make `verified/slice.rs` a separate crate, `verify.sh` applies four mechanical edits to the copied `core` sources before compiling them (`core-sysroot.patch`, a plain `diff -ru` applied with `patch -p1`, so that it can be reviewed as a diff), listed here so that they can be audited: (1) the `pub(crate)` fields `start`, `end`, `exhausted` of `ops::RangeInclusive` are made `pub`; (2) the `pub(crate)`/`pub(super)` constructors `new` of the slice iterators in `slice/iter.rs` and `slice/iter/macros.rs` are made `pub`; (3) the attributes `#[lang = "slice_len_fn"]` and `#[rustc_diagnostic_item = ...]` are removed from `slice/mod.rs` and `slice/raw.rs` (the lang item would otherwise be defined twice); (4) the inherent methods of `[T]`, `[u8]` and `[[T; N]]` in `core`'s own `slice/mod.rs` are made `pub(crate)` so that they do not shadow the ones under verification. None of these edits touches a function body; they change visibility and compiler attributes only, and they affect the sysroot `core` only, never the files under verification. + +As in the `RawVec` and `LinkedList` proofs, verification proceeds in three steps in `verify.sh`: +1. **`verifast`** verifies `verified/lib.rs` (which includes `verified/slice.rs`, `verified/slice/raw.rs`, and `verified/slice/rotate.rs`) with `0 errors found`. +2. **`refinement-checker`** checks that `original/lib.rs` is refined by `verified/lib.rs` with `0 errors`, ensuring that any syntactic rewrites or helper wrappers introduced for VeriFast preserve the exact MIR semantics of the original code. +3. **`diff`** checks that `original/slice.rs`, `original/slice/raw.rs`, and `original/slice/rotate.rs` are byte-for-byte identical to `library/core/src/slice/mod.rs`, `library/core/src/slice/raw.rs`, and `library/core/src/slice/rotate.rs`. + +### Ownership and borrowing of slices + +In VeriFast's RustBelt separation logic encoding: +- **Raw contiguous array ownership** at pointer `p: *T` of length `len` is represented by `p[..len] |-> ?elems` (where `elems: list` has `length(elems) == len`), together with element-wise thread ownership `foreach(elems, own::(t))` when exclusive semantic ownership of elements is required. +- **Shared slice references (`&'a [T]`)** are represented by the duplicable shared ownership predicate `[_](<[T]>.share('a, t, s))`. By lemma `slice_share_inv`, shared ownership of a slice `s` guarantees that its metadata length satisfies `s.len() * std::mem::size_of::() <= isize::MAX` and `pointer_within_limits(strip_pointer_metadata(s as pointer) as *T) == true`. +- **Mutable slice references (`&'a mut [T]`)** whose lifetime `'a` appears in the return type (such as `split_at_mut`, `first_chunk_mut`, `align_to_mut`, `partition_dedup_by`) are represented using a full borrow `full_borrow('a, <[T]>.full_borrow_content(t, s))` accompanied by a fractional `lifetime_token('a)`. Functions that mutate a slice in place without returning sub-borrows tied to `'a` (such as `swap_unchecked`, `rotate_left`, `rotate_right`, `copy_from_slice`, `copy_within`, `swap_with_slice`) operate directly on the array points-to resource `((strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems)` and provide a `safety_proof` block that opens `<[T]>.full_borrow_content(t, self)` before `call()` and closes it afterwards. + +### Raw slice construction (`from_raw_parts` and `from_raw_parts_mut`) + +In `verified/slice/raw.rs`, `from_raw_parts` and `from_raw_parts_mut` construct shared and mutable slice references from a raw pointer `data` and length `len`: + +```rust +pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] +//@ req thread_token(?t) &*& [_](<[T]>.share('a, t, ptr::mk_slice::(data, len))); +//@ ens thread_token(t) &*& result == ptr::mk_slice::(data, len) &*& [_](<[T]>.share('a, t, result)); +//@ on_unwind_ens false; +{ + unsafe { &*ptr::slice_from_raw_parts(data, len) } +} +``` + +### Splitting slices (`split_at` and `split_at_mut`) + +`split_at_unchecked` and `split_at_mut_unchecked` require `0 <= mid &*& mid <= self.len()` and split a shared borrow `[_](<[T]>.share('a, t, self))` (via `array_share_split`) or full borrow `full_borrow('a, <[T]>.full_borrow_content(t, self))` (via `open_full_borrow_strong_` and `full_borrow_split`) at index `mid` into two contiguous sub-slices of lengths `mid` and `self.len() - mid`: + +```rust +pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) +//@ req thread_token(?t) &*& [?q]lifetime_token(?k) &*& full_borrow(k, <[T]>.full_borrow_content(t, self)) &*& 0 <= mid &*& mid <= self.len(); +//@ ens thread_token(t) &*& [q]lifetime_token(k) &*& full_borrow(k, <[T]>.full_borrow_content(t, result.0)) &*& full_borrow(k, <[T]>.full_borrow_content(t, result.1)) &*& result.0.len() == mid &*& result.1.len() == self.len() - mid; +//@ on_unwind_ens false; +``` + +The safe functions `split_at_checked`, `split_at_mut_checked`, `split_at`, and `split_at_mut` check `mid <= self.len()` and then delegate to `split_at_unchecked` / `split_at_mut_unchecked`, proving semantic well-typedness without callers needing any precondition beyond standard type interpretations. + +### In-place rotation (`rotate_left`, `rotate_right`, and `core::slice::rotate`) + +`rotate_left` and `rotate_right` validate `mid <= self.len()` (or `k <= self.len()`) and invoke `slice::rotate::ptr_rotate(left, mid_ptr, right)` on the underlying buffer split at `mid`: + +```rust +pub(super) const unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) +//@ req (mid - left)[..left] |-> ?elems_left &*& mid[..right] |-> ?elems_right &*& (left + right) * std::mem::size_of::() <= isize::MAX; +//@ ens (mid - left)[..left + right] |-> ?elems_out &*& length(elems_out) == left + right; +//@ on_unwind_ens false; +``` + +In `verified/slice/rotate.rs`, all three rotation algorithms in `core::slice::rotate` are verified against this contract: +1. **`ptr_rotate_memmove`**: Copies the smaller of the `left` or `right` segments into a temporary stack buffer `Rawarray`, shifts the remaining elements via `ptr::copy`, and copies the buffered elements into place. +2. **`ptr_rotate_gcd`**: Divides the array into cycles using greatest-common-divisor stride arithmetic and shifts elements around each cycle using `ptr_replace` and `ptr::swap_nonoverlapping`. +3. **`ptr_rotate_swap`**: Iteratively swaps min-length blocks across the pivot `mid` using `ptr::swap_nonoverlapping` and adjusts `left`, `mid`, and `right` until one side reaches zero. + +### Aligned reinterpretation (`align_to`, `align_to_mut`, `as_simd`, `as_simd_mut`) + +`align_to` computes `offset = ptr::align_offset(ptr, align_of::())`, splits `self` at `offset` into `left` and `rest`, and asks `align_to_offsets` for `(us_len, ts_len)`. The proof splits `rest`'s shared (resp. mutable) borrow into the prefix of `rest.len() - ts_len` elements and the suffix of `ts_len` elements with `array_share_split` (resp. `slice_full_borrow_split`), proves `us_len * size_of::() == (rest.len() - ts_len) * size_of::()` from the divisibility properties of `gcd`, obtains the alignment of the prefix from `align_offset`'s specification, and only then applies `share_transmute_prefix` (resp. `full_borrow_transmute_prefix`) to reinterpret the prefix as the middle `[U]` slice. + +### Disjoint mutable indexing (`get_disjoint_mut`, `get_disjoint_unchecked_mut`, `get_disjoint_check_valid`) + +`get_disjoint_check_valid` is proved to establish `all_in_bounds` and `all_pairwise_disjoint` of the index list by induction over the loop. `get_disjoint_unchecked_mut` opens the slice borrow strongly, carves the (pairwise-disjoint, in-bounds) regions denoted by the indices out of the element array, stores the region references into the output array (`refs_of`), converts the regions into the content of one lifetime-`k` borrow (`outputs_fbc`), closes the slice borrow with a `restore_full_borrow_` proof that puts the regions back, and splits off the borrow of the outputs. The result predicate `disjoint_mut_borrows` holds the output references and that borrow; `disjoint_mut_borrows_peel` yields the per-reference `full_borrow(k, .full_borrow_content(t, r_i))`. + +## Caveats + +First of all, this proof was performed with the following VeriFast command-line flags: +- `-skip_specless_fns`: VeriFast ignores the functions that do not have a `req` or `ens` clause. +- `-ignore_unwind_paths`: This proof ignores code that is reachable only when unwinding. +- `-allow_ignore_ref_creation`: 10 `//~ignore_ref_creation` directives, each checked to be necessary (removing it makes `verifast` fail at that site); the aliasing rules are not checked at those 10 sites, where the reference is translated as the raw pointer. They are: four `&*(p as *const Chunk)` in the `*_chunk_proof__VeriFast_wrapper`s, `&*index.get_unchecked(self)` in `get_unchecked` (a `&I::Output`, `?Sized`), three `&Ordering` auto-references in `binary_search_by` (`cmp == Equal`/`Less`/`Greater`) and two `&[U; 0]`/`&[T; 0]` literals (`&[]`) in `align_to`. The four `Chunk` sites create a shared reference to a type-parameter pointee from `share` ownership; the protocol lemma for that, `init_ref_share`, needs `type_interp::()`, which VeriFast 26.10 only provides inside type-predicate lemmas and lemma-pointer bodies (`with_type_interp` needs a ghost recursion permission that function bodies do not hold), so it cannot be run in a function body. The `Ordering` and `&[]` sites are temporaries inside expressions of directly verified bodies, where the protocol's ghost statements cannot be placed. (The two `&I` references in `get_disjoint_check_valid_proof__VeriFast_wrapper` are created under the protocol: `precreate_ref` / `init_ref_readonly` / `end_ref_readonly`.) Shared references to slices created from raw pointers (`&*ptr::slice_from_raw_parts(..)`, `self.as_ptr()` on a `&mut self`, ...) need no directive in VeriFast 26.10, since the translator does not apply the protocol to them; [verifast/verifast#1059](https://github.com/verifast/verifast/issues/1059) asks for the protocol to cover `?Sized` pointees so that those sites can be checked too. +- `-allow_assume`: This proof uses `assume` ghost statements and `assume_correct` clauses in the following specific places, which must be audited: + - **RustBelt lifetime-logic reborrowing / transmutation and tuple-ownership bridge lemmas**: + - `close_slice_pair_own`, `close_mut_slice_pair_own`, `close_slice_triple_own`, `close_mut_slice_triple_own`, `close_Range_own` ([verifast/verifast#1049](https://github.com/verifast/verifast/issues/1049)): In VeriFast 26.10, `prelude.rsspec` declares `std_tuple_2_` and `std_tuple_3_` as `struct` types (`rust_parser.ml:1147` generates uninterpreted `std_tuple_2__own` and `std_tuple_3__own` predicates for `struct` types), and `prelude.rsspec` only provides `close_tuple_0_own` and `close_tuple_4_own`. Similarly, `rust/std/lib.rsspec` declares `struct Range` without a `close_Range_own` lemma. + - Slice/array layout bridges: `slice_share_inv` ([verifast/verifast#1050](https://github.com/verifast/verifast/issues/1050)), `pointer_metadata_as_usize_limits`, `share_slice_prefix_as_chunk`, `full_borrow_slice_prefix_as_chunk`, `share_slice_as_chunks`, `full_borrow_slice_as_chunks`, `share_chunks_as_flattened`, `full_borrow_chunks_as_flattened` (reinterpretation of a `[T]` run as `[T; N]` chunks and back, under `is_array_of::(n)`, an abstract predicate meaning "`Chunk` is `[T; n]`, or has its layout and validity invariant", established only at the const-generic call sites, with the layout facts derived by the axiom `is_array_of_layout`; with native `[T; N]` ownership, [verifast/verifast#1048](https://github.com/verifast/verifast/pull/1048), these become provable from the prelude's `Array_to_array` / `array_to_Array` and `array_share_split`), and `rawarray_to_buf` / `buf_to_rawarray` in `rotate.rs` (reinterpretation of the uninitialized `MaybeUninit<([usize; 32], [T; 0])>` stack buffer as `k` `T` slots, with the bound stated in bytes; [verifast/verifast#1053](https://github.com/verifast/verifast/issues/1053)). + - `Copy` types ([verifast/verifast#1051](https://github.com/verifast/verifast/issues/1051)): `open_shared_slice_copy`, `close_shared_slice_copy`, `copy_elem_own_dup` are RustBelt's `Copy` rules (shared ownership of a `Copy` slice gives fractional ownership of its bytes; `own` of a `Copy` value is duplicable). They are gated by `is_Copy::()`, which is established only by calling `copy_witness__VeriFast_wrapper::()`, an empty function with a `T: Copy` bound: rustc rejects any call site where `T` is not `Copy`, so the rule cannot be invoked for a non-`Copy` type. + - `align_to`/`align_to_mut`: `share_transmute_prefix` and `full_borrow_transmute_prefix` reinterpret a run of `n` `T` values as the `[U]` slice `mid`, and require that run to be the prefix of `rest`, that `mid.len() * size_of::() == n * size_of::()` (byte-exact coverage), and that its start is aligned for `U`. All three facts are proved at the call sites: the prefix/suffix split of `rest` by `array_share_split` / `slice_full_borrow_split` (proved), the coverage equation by `align_to_offsets_proof__VeriFast_wrapper` (which proves `gcd | size_of::()`, `gcd | size_of::()` and the resulting equation, using the arithmetic axiom `mul_assoc`, the only nonlinear fact VeriFast's prover does not provide), and the alignment from the specification of `ptr::align_offset` in `lib.rs`. The one remaining caller obligation, `valid_slice_transmute::()`, is `align_to`'s documented `# Safety` condition (the middle slice "is essentially a `transmute`"); `as_simd`/`as_simd_mut` carry it, together with `is_array_of`, as explicit preconditions of their (`unsafe`) wrappers, justified by `Simd`'s `#[repr(simd)]` layout. + - `get_disjoint_mut` / `get_disjoint_unchecked_mut` / `get_disjoint_check_valid`: a region model of the sealed `GetDisjointMutIndex` + `SliceIndex<[T]>` implementations (`region_start`, `region_len`, `region_ptr`): `GetDisjointMutIndex_in_bounds_region` and `GetDisjointMutIndex_not_overlapping_disjoint` state what `is_in_bounds` / `is_overlapping` mean for the five sealed index types, and `region_to_output_fbc` / `output_fbc_to_region` state that `.full_borrow_content` of the reference `get_unchecked_mut` returns is the ownership of that region (four generic axioms). The model is defined at `usize` and `Range` (`usize_region_model`, `Range_region_model`: definitional axioms giving `region_start`/`region_len`/`GetDisjointMutIndex_in_bounds`/`GetDisjointMutIndex_overlapping` at those types, with an empty region normalized to `[0, 0)`), and the two generic axioms are proved at those two types (`in_bounds_region_usize`, `not_overlapping_disjoint_usize`, `in_bounds_region_Range`, `not_overlapping_disjoint_Range`). The `is_in_bounds`/`is_overlapping` implementations are verified against the model for `usize` only: the `Range` implementations read `self.start`/`self.end` through `&Range`, which VeriFast 26.10 translates through a `share` interpretation of `Range` that its `std` specifications do not define (`std::ops::Range_share`), and `RangeInclusive` and the `core::range::*` types cannot be named in ghost code at all (the `core::range::*` implementations also delegate through `From`, outside the crate). Those eight implementations are skipped, so the model is unchecked against them. Everything else is proved: the carving of pairwise-disjoint, in-bounds regions out of the element array and their restoration (`carve_regions` / `uncarve_regions`, by induction over the index list on an element-wise representation `rest_elems` of the array minus the regions, using the two axioms above for the interval facts), the inductive disjointness check (`all_in_bounds`, `all_pairwise_disjoint`), the conversion of all regions into one lifetime-`k` borrow (`regions_to_outputs_fbc`, `outputs_fbc_to_regions`, the `restore_full_borrow_` closing proof), the output-array bookkeeping (`refs_of`, `refs_of_snoc`), and `disjoint_mut_borrows_peel`, which turns the concrete result predicate `disjoint_mut_borrows` (the output references plus one borrow of everything they point to) into the usual per-reference `full_borrow`s. + - `Range_SliceIndex_in_bounds`: the documented safety precondition of `SliceIndex<[T]>::get_unchecked{,_mut}` for `Range` (`start <= end <= len`), so that the `get_unchecked`/`get_unchecked_mut` contracts are usable at that index type as well as at `usize` (`core.rsspec`); the other index types cannot be named in VeriFast 26.10's ghost language. + - `mul_assoc` ([verifast/verifast#1052](https://github.com/verifast/verifast/issues/1052)): associativity of multiplication, which VeriFast's Redux prover does not normalize (it does handle commutativity and distributivity) and which the Rust prelude does not provide. + Note that `split_at_unchecked`, `split_at_mut_unchecked`, `slice_full_borrow_inv`, `slice_full_borrow_split`, `flatten_non_zst_no_overflow`, `gcd_proof__VeriFast_wrapper` (including divisibility of the result), and `align_to_offsets_proof__VeriFast_wrapper` (including byte-exact coverage) are proved mechanically without `assume(false)`, `T::IS_ZST` branches are discharged mechanically via `std::alloc::is_valid_layout_size_of_align_of`, and there are no inline `assume` statements anywhere in the proof. + - **Const-generic functions (``) and `is_array_of::(n)`**: In VeriFast 26.10, placing a specification directly on a function with a const-generic parameter `const N: usize` fails in `verifast` with `error: Todo: ConstKind::Param` (`vf_mir_translator.ml:1787`), and calling a helper from a `` function fails in `refinement-checker` with `Fatal error: exception Failure("Clause kind not supported")` (`refinement_checker.ml:2338`, triggered by `ClauseKind::ConstArgHasType`). Therefore, const-generic array chunking, flattening, SIMD, and `get_disjoint_mut` functions are verified via parametric helper functions taking `(Chunk, n: usize)` with the abstract `fix is_array_of(n: usize) -> bool` (`Chunk` has the layout and validity invariant of `[T; n]`; or `&[I]` for `get_disjoint_*`). To be explicit: VeriFast does not verify the 20 const-generic bodies themselves. They carry no specification and `-skip_specless_fns` skips them; the refinement checker only confirms that they are identical to the original. The correspondence between each body and its `*_proof__VeriFast_wrapper` transcription is by inspection only; the Kani harnesses in `library/core/src/slice/mod.rs` verify those bodies, bounded and monomorphized. Native support (const parameters as values and in `[T; N]` types, `[T; N]` ownership, and the refinement checker) is proposed upstream in [verifast/verifast#1048](https://github.com/verifast/verifast/pull/1048); once released, these functions can receive direct specifications on their unchanged bodies (`get_disjoint_mut`'s by-value `[I; N]` parameter additionally needs [verifast/verifast#1055](https://github.com/verifast/verifast/issues/1055)). + - **Single local macro `vf_revswap!` in `reverse`**: `reverse` defines a nested generic function `fn revswap(a: &mut [T], b: &mut [T], n: usize)`. In VeriFast 26.10, `vf_mir_exporter/src/lib.rs:434,940` only matches top-level `ItemKind::Fn` and `ItemKind::Impl`, ignoring inline specifications on functions nested inside a statement block, and `rust_parser.ml:1036` rejects `impl [T]` in `.rsspec` files. Therefore `revswap` is verified as the top-level function `revswap_proof__VeriFast_wrapper` and invoked via `vf_revswap!` while keeping `revswap` in place for `refinement-checker`. The copy omits the two `debug_assert!(a.len() == n)` / `debug_assert!(b.len() == n)` (compiled out in this build, they were the proof's only dead-code reports; the equalities are its preconditions) and performs `mem::swap(&mut a[i], &mut b[n - 1 - i])` through element pointers of the two arrays (the index bounds are the loop invariant). Support for specifications on nested `fn` items is proposed in [verifast/verifast#1058](https://github.com/verifast/verifast/pull/1058); once released, the macro and the wrapper can go and `revswap` receives its specification in place. + - **`assume_correct` on low-level primitive / external wrappers**: `[T]::len` is verified directly against `ptr::metadata` in `core.rsspec`, and `exact_div_usize__VeriFast_wrapper` is verified directly against `intrinsics::exact_div`. In `align_to_offsets`, the inline `const { gcd(size_of::(), size_of::()) }` block is translated by `vf_mir_translator.ml:2228` to `std::verifast::unevaluated_constant::()` (`std/lib.rsspec:15`, which discards the `const` block body and has postcondition `ens true`), and its nested `const fn gcd` item is ignored by `vf_mir_exporter/src/lib.rs:434,940`; therefore `align_to_offsets` is annotated with `//@ assume_correct` for callers while its complete body and `gcd` are verified without `assume_correct` or `assume(false)` in `align_to_offsets_proof__VeriFast_wrapper` and `gcd_proof__VeriFast_wrapper`. The trusted specification of the method is the safe-function template (`thread_token` in and out, `<(usize, usize)>.own` of the result, which VeriFast checks against the method's type in its "prototype implementation check") plus, under the wrapper's hypotheses (`len * size_of::() <= isize::MAX`, `self` and `self + len` within limits, both sizes nonzero), exactly the wrapper's proved postcondition: the bounds of the two results, the byte-exact coverage equation `us_len * size_of::() == (len - ts_len) * size_of::()`, `us_len * size_of::() <= isize::MAX`, and `self as *U + us_len` within limits. The method's body is identical to `verified/` modulo the `const` block (checked by the refinement checker against `original/`), so the trust is the correspondence of that body with the wrapper's, by inspection. Thin wrappers around external library calls or unsupported MIR constructs (`slice_range__VeriFast_wrapper`, `empty_slice__VeriFast_wrapper`, `empty_mut_slice_arg__VeriFast_wrapper`, `call_same_bucket__VeriFast_wrapper`, `checked_mul_or_panic__VeriFast_wrapper`, `clone_disjoint_index__VeriFast_wrapper` (whose `clone` = identity postcondition is exact because `GetDisjointMutIndex` is sealed and all five implementors derive `Clone` field-wise), `uninit_buf__VeriFast_wrapper`, `uninit_buf_as_mut_ptr__VeriFast_wrapper`, `ptr_replace__VeriFast_wrapper`) use `//@ assume_correct` because ([verifast/verifast#1056](https://github.com/verifast/verifast/issues/1056)) `vf_mir_translator.ml:418` hardcodes `[ prelude_path ]` (`prelude.rsspec` only, excluding `rust/std/lib.rsspec`) as the header dependency list of `-extern_spec` files (preventing `Option`, `Range`, and `MaybeUninit` from being referenced in `core.rsspec`), and `rust_parser.ml:1036` rejects `impl *mut T` in `.rsspec` files. The `core::ptr` functions whose signatures involve no such type are specified in `core.rsspec` instead, as extern specifications (trusted in the same way as VeriFast's `std/lib.rsspec`): `ptr::metadata`, `ptr::swap` (with the `x == y` case made explicit by `opt_pointsto`) and `ptr::swap_nonoverlapping`; the latter two (together with `ptr::replace`, `ptr::slice_from_raw_parts` and the tuple lemmas) are proposed for `std/lib.rsspec` in [verifast/verifast#1057](https://github.com/verifast/verifast/pull/1057). The remaining `std` specifications that could not be written in `core.rsspec` (`<*const T>::align_offset`, a method on a raw pointer; `ptr::slice_from_raw_parts{,_mut}` and `ptr::copy`, whose specifications use the crate-local `mk_slice`/`copy_context` definitions) live in `verified/lib.rs` as `assume_correct` forwarding functions. Two further `assume_correct` wrappers carry no external call: `copy_witness__VeriFast_wrapper` (empty body; see the `Copy` item above) and `write_disjoint_mut_elem__VeriFast_wrapper`, whose specification is the raw-pointer semantics of the sealed `SliceIndex::get_unchecked_mut` impls (the reference stored in slot `i` is `region_ptr` of the index; no ownership is consumed, the ownership transfer is done in `get_disjoint_unchecked_mut`'s proof). + +Secondly, since VeriFast uses the `rustc` frontend, which assumes a particular target architecture, VeriFast's results hold only for the used Rust toolchain's target architecture (and, as explained above, the slice sources are compiled against the `core` of VeriFast's own toolchain, `nightly-2026-09-25`, rather than the `core` of the subtree they were taken from). When VeriFast reports "0 errors found" for a Rust program, it always reports the targeted architecture as well (e.g. `0 errors found (1712 statements verified) (target: arm64-apple-macosx (LP64))`). + +Thirdly, VeriFast has a number of [known unsoundnesses](https://github.com/verifast/verifast/issues?q=is%3Aissue+is%3Aopen+label%3Aunsoundness) (reasons why VeriFast might in some cases incorrectly accept a program), including the following: +- VeriFast does not yet fully verify compliance with Rust's [pointer aliasing rules](https://doc.rust-lang.org/reference/behavior-considered-undefined.html). +- VeriFast does not yet properly verify compliance of custom type interpretations with Rust's [variance](https://doc.rust-lang.org/reference/subtyping.html#variance) rules. + +Fourthly, unlike foundational tools such as [RefinedRust](https://plv.mpi-sws.org/refinedrust/), VeriFast has not itself been verified, so there are undoubtedly also unknown unsoundnesses. Such unsoundnesses might exist in VeriFast's [symbolic execution engine](https://github.com/model-checking/verify-rust-std/issues/213#issuecomment-2531006855) [itself](https://github.com/model-checking/verify-rust-std/issues/213#issuecomment-2534922580) or in its [prelude](https://github.com/verifast/verifast/tree/master/bin/rust) (definitions and axioms automatically imported at the start of every verification run) or in the [specifications](https://github.com/verifast/verifast/blob/master/bin/rust/std/lib.rsspec) it uses for the Rust standard library functions called by the program being verified. diff --git a/verifast-proofs/core/slice/mod.rs/core-sysroot.patch b/verifast-proofs/core/slice/mod.rs/core-sysroot.patch new file mode 100644 index 0000000000000..808f85c534502 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/core-sysroot.patch @@ -0,0 +1,1400 @@ +diff -ru a/ops/range.rs b/ops/range.rs +--- a/ops/range.rs ++++ b/ops/range.rs +@@ -365,8 +365,8 @@ + // expose start/end, modifying them without changing (future/current) + // private fields may lead to incorrect behavior, so we don't want to + // support that mode. +- pub(crate) start: Idx, +- pub(crate) end: Idx, ++ #[stable(feature = "rust1", since = "1.0.0")] pub start: Idx, ++ #[stable(feature = "rust1", since = "1.0.0")] pub end: Idx, + + // This field represents an overflow flag for either bound (start or end): + // - `false` upon construction +@@ -379,7 +379,7 @@ + // often wrapping (modular arithmetic) around at the boundary of `Idx`. + // + // This is required to support PartialEq and Hash without a PartialOrd bound or specialization. +- pub(crate) exhausted: bool, ++ #[stable(feature = "rust1", since = "1.0.0")] pub exhausted: bool, + } + + impl RangeInclusive { +diff -ru a/slice/iter.rs b/slice/iter.rs +--- a/slice/iter.rs 2026-10-28 02:58:11 ++++ b/slice/iter.rs 2026-10-28 02:58:11 +@@ -91,7 +91,7 @@ + + impl<'a, T> Iter<'a, T> { + #[inline] +- pub(super) const fn new(slice: &'a [T]) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a [T]) -> Self { + let len = slice.len(); + let ptr: NonNull = NonNull::from_ref(slice).cast(); + // SAFETY: Similar to `IterMut::new`. +@@ -216,7 +216,7 @@ + + impl<'a, T> IterMut<'a, T> { + #[inline] +- pub(super) const fn new(slice: &'a mut [T]) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a mut [T]) -> Self { + let len = slice.len(); + let ptr: NonNull = NonNull::from_mut(slice).cast(); + // SAFETY: There are several things here: +@@ -409,7 +409,7 @@ + + impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> { + #[inline] +- pub(super) fn new(slice: &'a [T], pred: P) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] pub fn new(slice: &'a [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } + /// Returns a slice which contains items not yet handled by split. +@@ -563,7 +563,7 @@ + + impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusive<'a, T, P> { + #[inline] +- pub(super) fn new(slice: &'a [T], pred: P) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] pub fn new(slice: &'a [T], pred: P) -> Self { + let finished = slice.is_empty(); + Self { v: slice, pred, finished } + } +@@ -684,7 +684,7 @@ + + impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitMut<'a, T, P> { + #[inline] +- pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] pub fn new(slice: &'a mut [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } + } +@@ -813,7 +813,7 @@ + + impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusiveMut<'a, T, P> { + #[inline] +- pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] pub fn new(slice: &'a mut [T], pred: P) -> Self { + let finished = slice.is_empty(); + Self { v: slice, pred, finished } + } +@@ -938,7 +938,7 @@ + + impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplit<'a, T, P> { + #[inline] +- pub(super) fn new(slice: &'a [T], pred: P) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] pub fn new(slice: &'a [T], pred: P) -> Self { + Self { inner: Split::new(slice, pred) } + } + } +@@ -1035,7 +1035,7 @@ + + impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitMut<'a, T, P> { + #[inline] +- pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] pub fn new(slice: &'a mut [T], pred: P) -> Self { + Self { inner: SplitMut::new(slice, pred) } + } + } +@@ -1161,7 +1161,7 @@ + + impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitN<'a, T, P> { + #[inline] +- pub(super) fn new(s: Split<'a, T, P>, n: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] pub fn new(s: Split<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } + } +@@ -1205,7 +1205,7 @@ + + impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitN<'a, T, P> { + #[inline] +- pub(super) fn new(s: RSplit<'a, T, P>, n: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] pub fn new(s: RSplit<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } + } +@@ -1245,7 +1245,7 @@ + + impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitNMut<'a, T, P> { + #[inline] +- pub(super) fn new(s: SplitMut<'a, T, P>, n: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] pub fn new(s: SplitMut<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } + } +@@ -1286,7 +1286,7 @@ + + impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitNMut<'a, T, P> { + #[inline] +- pub(super) fn new(s: RSplitMut<'a, T, P>, n: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] pub fn new(s: RSplitMut<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } + } +@@ -1333,7 +1333,7 @@ + + impl<'a, T: 'a> Windows<'a, T> { + #[inline] +- pub(super) const fn new(slice: &'a [T], size: NonZero) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a [T], size: NonZero) -> Self { + Self { v: slice, size } + } + } +@@ -1482,7 +1482,7 @@ + + impl<'a, T: 'a> Chunks<'a, T> { + #[inline] +- pub(super) const fn new(slice: &'a [T], size: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } + } +@@ -1665,7 +1665,7 @@ + + impl<'a, T: 'a> ChunksMut<'a, T> { + #[inline] +- pub(super) const fn new(slice: &'a mut [T], size: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a mut [T], size: usize) -> Self { + Self { v: slice, chunk_size: size, _marker: PhantomData } + } + } +@@ -1846,7 +1846,7 @@ + + impl<'a, T> ChunksExact<'a, T> { + #[inline] +- pub(super) const fn new(slice: &'a [T], chunk_size: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + let fst_len = slice.len() - rem; + // SAFETY: 0 <= fst_len <= slice.len() by construction above +@@ -2023,7 +2023,7 @@ + + impl<'a, T> ChunksExactMut<'a, T> { + #[inline] +- pub(super) const fn new(slice: &'a mut [T], chunk_size: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a mut [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + let fst_len = slice.len() - rem; + // SAFETY: 0 <= fst_len <= slice.len() by construction above +@@ -2182,7 +2182,7 @@ + + impl<'a, T: 'a, const N: usize> ArrayWindows<'a, T, N> { + #[inline] +- pub(super) const fn new(slice: &'a [T]) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a [T]) -> Self { + Self { v: slice } + } + } +@@ -2313,7 +2313,7 @@ + + impl<'a, T: 'a> RChunks<'a, T> { + #[inline] +- pub(super) const fn new(slice: &'a [T], size: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } + } +@@ -2480,7 +2480,7 @@ + + impl<'a, T: 'a> RChunksMut<'a, T> { + #[inline] +- pub(super) const fn new(slice: &'a mut [T], size: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a mut [T], size: usize) -> Self { + Self { v: slice, chunk_size: size, _marker: PhantomData } + } + } +@@ -2656,7 +2656,7 @@ + + impl<'a, T> RChunksExact<'a, T> { + #[inline] +- pub(super) const fn new(slice: &'a [T], chunk_size: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + // SAFETY: 0 <= rem <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_unchecked(rem) }; +@@ -2839,7 +2839,7 @@ + + impl<'a, T> RChunksExactMut<'a, T> { + #[inline] +- pub(super) const fn new(slice: &'a mut [T], chunk_size: usize) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a mut [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + // SAFETY: 0 <= rem <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_mut_unchecked(rem) }; +@@ -3017,7 +3017,7 @@ + + #[stable(feature = "slice_group_by", since = "1.77.0")] + impl<'a, T: 'a, P> ChunkBy<'a, T, P> { +- pub(super) const fn new(slice: &'a [T], predicate: P) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a [T], predicate: P) -> Self { + ChunkBy { slice, predicate } + } + } +@@ -3125,7 +3125,7 @@ + + #[stable(feature = "slice_group_by", since = "1.77.0")] + impl<'a, T: 'a, P> ChunkByMut<'a, T, P> { +- pub(super) const fn new(slice: &'a mut [T], predicate: P) -> Self { ++ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn new(slice: &'a mut [T], predicate: P) -> Self { + ChunkByMut { slice, predicate } + } + } +diff -ru a/slice/mod.rs b/slice/mod.rs +--- a/slice/mod.rs ++++ b/slice/mod.rs +@@ -109,13 +109,13 @@ + /// let a = [1, 2, 3]; + /// assert_eq!(a.len(), 3); + /// ``` +- #[lang = "slice_len_fn"] ++ // #[lang = "slice_len_fn"] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] +- pub const fn len(&self) -> usize { ++ pub(crate) const fn len(&self) -> usize { + ptr::metadata(self) + } + +@@ -135,7 +135,7 @@ + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] +- pub const fn is_empty(&self) -> bool { ++ pub(crate) const fn is_empty(&self) -> bool { + self.len() == 0 + } + +@@ -154,7 +154,7 @@ + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] +- pub const fn first(&self) -> Option<&T> { ++ pub(crate) const fn first(&self) -> Option<&T> { + if let [first, ..] = self { Some(first) } else { None } + } + +@@ -177,7 +177,7 @@ + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] +- pub const fn first_mut(&mut self) -> Option<&mut T> { ++ pub(crate) const fn first_mut(&mut self) -> Option<&mut T> { + if let [first, ..] = self { Some(first) } else { None } + } + +@@ -197,7 +197,7 @@ + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] +- pub const fn split_first(&self) -> Option<(&T, &[T])> { ++ pub(crate) const fn split_first(&self) -> Option<(&T, &[T])> { + if let [first, tail @ ..] = self { Some((first, tail)) } else { None } + } + +@@ -219,7 +219,7 @@ + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] +- pub const fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { ++ pub(crate) const fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if let [first, tail @ ..] = self { Some((first, tail)) } else { None } + } + +@@ -239,7 +239,7 @@ + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] +- pub const fn split_last(&self) -> Option<(&T, &[T])> { ++ pub(crate) const fn split_last(&self) -> Option<(&T, &[T])> { + if let [init @ .., last] = self { Some((last, init)) } else { None } + } + +@@ -261,7 +261,7 @@ + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] +- pub const fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { ++ pub(crate) const fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if let [init @ .., last] = self { Some((last, init)) } else { None } + } + +@@ -280,7 +280,7 @@ + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] +- pub const fn last(&self) -> Option<&T> { ++ pub(crate) const fn last(&self) -> Option<&T> { + if let [.., last] = self { Some(last) } else { None } + } + +@@ -303,7 +303,7 @@ + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] +- pub const fn last_mut(&mut self) -> Option<&mut T> { ++ pub(crate) const fn last_mut(&mut self) -> Option<&mut T> { + if let [.., last] = self { Some(last) } else { None } + } + +@@ -326,7 +326,7 @@ + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] +- pub const fn first_chunk(&self) -> Option<&[T; N]> { ++ pub(crate) const fn first_chunk(&self) -> Option<&[T; N]> { + if self.len() < N { + None + } else { +@@ -356,7 +356,7 @@ + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] +- pub const fn first_chunk_mut(&mut self) -> Option<&mut [T; N]> { ++ pub(crate) const fn first_chunk_mut(&mut self) -> Option<&mut [T; N]> { + if self.len() < N { + None + } else { +@@ -386,7 +386,7 @@ + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] +- pub const fn split_first_chunk(&self) -> Option<(&[T; N], &[T])> { ++ pub(crate) const fn split_first_chunk(&self) -> Option<(&[T; N], &[T])> { + let Some((first, tail)) = self.split_at_checked(N) else { return None }; + + // SAFETY: We explicitly check for the correct number of elements, +@@ -416,7 +416,7 @@ + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] +- pub const fn split_first_chunk_mut( ++ pub(crate) const fn split_first_chunk_mut( + &mut self, + ) -> Option<(&mut [T; N], &mut [T])> { + let Some((first, tail)) = self.split_at_mut_checked(N) else { return None }; +@@ -446,7 +446,7 @@ + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] +- pub const fn split_last_chunk(&self) -> Option<(&[T], &[T; N])> { ++ pub(crate) const fn split_last_chunk(&self) -> Option<(&[T], &[T; N])> { + let Some(index) = self.len().checked_sub(N) else { return None }; + let (init, last) = self.split_at(index); + +@@ -477,7 +477,7 @@ + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] +- pub const fn split_last_chunk_mut( ++ pub(crate) const fn split_last_chunk_mut( + &mut self, + ) -> Option<(&mut [T], &mut [T; N])> { + let Some(index) = self.len().checked_sub(N) else { return None }; +@@ -508,7 +508,7 @@ + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_last_chunk", since = "1.80.0")] +- pub const fn last_chunk(&self) -> Option<&[T; N]> { ++ pub(crate) const fn last_chunk(&self) -> Option<&[T; N]> { + // FIXME(const-hack): Without const traits, we need this instead of `get`. + let Some(index) = self.len().checked_sub(N) else { return None }; + let (_, last) = self.split_at(index); +@@ -538,7 +538,7 @@ + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] +- pub const fn last_chunk_mut(&mut self) -> Option<&mut [T; N]> { ++ pub(crate) const fn last_chunk_mut(&mut self) -> Option<&mut [T; N]> { + // FIXME(const-hack): Without const traits, we need this instead of `get`. + let Some(index) = self.len().checked_sub(N) else { return None }; + let (_, last) = self.split_at_mut(index); +@@ -571,7 +571,7 @@ + #[inline] + #[must_use] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] +- pub const fn get(&self, index: I) -> Option<&I::Output> ++ pub(crate) const fn get(&self, index: I) -> Option<&I::Output> + where + I: [const] SliceIndex, + { +@@ -599,7 +599,7 @@ + #[must_use] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[rustc_no_writable] +- pub const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> ++ pub(crate) const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where + I: [const] SliceIndex, + { +@@ -639,7 +639,7 @@ + #[must_use] + #[track_caller] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] +- pub const unsafe fn get_unchecked(&self, index: I) -> &I::Output ++ pub(crate) const unsafe fn get_unchecked(&self, index: I) -> &I::Output + where + I: [const] SliceIndex, + { +@@ -685,7 +685,7 @@ + #[track_caller] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[rustc_no_writable] +- pub const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output ++ pub(crate) const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + where + I: [const] SliceIndex, + { +@@ -727,7 +727,7 @@ + #[rustc_as_ptr] + #[inline(always)] + #[must_use] +- pub const fn as_ptr(&self) -> *const T { ++ pub(crate) const fn as_ptr(&self) -> *const T { + self as *const [T] as *const T + } + +@@ -759,7 +759,7 @@ + #[inline(always)] + #[must_use] + #[rustc_no_writable] +- pub const fn as_mut_ptr(&mut self) -> *mut T { ++ pub(crate) const fn as_mut_ptr(&mut self) -> *mut T { + self as *mut [T] as *mut T + } + +@@ -795,7 +795,7 @@ + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[inline] + #[must_use] +- pub const fn as_ptr_range(&self) -> Range<*const T> { ++ pub(crate) const fn as_ptr_range(&self) -> Range<*const T> { + let start = self.as_ptr(); + // SAFETY: The `add` here is safe, because: + // +@@ -838,7 +838,7 @@ + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[inline] + #[must_use] +- pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> { ++ pub(crate) const fn as_mut_ptr_range(&mut self) -> Range<*mut T> { + let start = self.as_mut_ptr(); + // SAFETY: See as_ptr_range() above for why `add` here is safe. + let end = unsafe { start.add(self.len()) }; +@@ -852,7 +852,7 @@ + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] + #[inline] + #[must_use] +- pub const fn as_array(&self) -> Option<&[T; N]> { ++ pub(crate) const fn as_array(&self) -> Option<&[T; N]> { + if self.len() == N { + let ptr = self.as_ptr().cast_array(); + +@@ -871,7 +871,7 @@ + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] + #[inline] + #[must_use] +- pub const fn as_mut_array(&mut self) -> Option<&mut [T; N]> { ++ pub(crate) const fn as_mut_array(&mut self) -> Option<&mut [T; N]> { + if self.len() == N { + let ptr = self.as_mut_ptr().cast_array(); + +@@ -907,7 +907,7 @@ + #[rustc_const_stable(feature = "const_swap", since = "1.85.0")] + #[inline] + #[track_caller] +- pub const fn swap(&mut self, a: usize, b: usize) { ++ pub(crate) const fn swap(&mut self, a: usize, b: usize) { + // Bounds checks that panic exactly like indexing would. + let _ = &self[a]; + let _ = &self[b]; +@@ -946,7 +946,7 @@ + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_swap_unchecked", issue = "88539")] + #[track_caller] +- pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { ++ pub(crate) const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { + assert_unsafe_precondition!( + check_library_ub, + "slice::swap_unchecked requires that the indices are within the slice", +@@ -976,7 +976,7 @@ + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_reverse", since = "1.90.0")] + #[inline] +- pub const fn reverse(&mut self) { ++ pub(crate) const fn reverse(&mut self) { + let half_len = self.len() / 2; + let Range { start, end } = self.as_mut_ptr_range(); + +@@ -1037,8 +1037,8 @@ + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] +- #[rustc_diagnostic_item = "slice_iter"] +- pub const fn iter(&self) -> Iter<'_, T> { ++ // #[rustc_diagnostic_item = "slice_iter"] ++ pub(crate) const fn iter(&self) -> Iter<'_, T> { + Iter::new(self) + } + +@@ -1058,7 +1058,7 @@ + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] +- pub const fn iter_mut(&mut self) -> IterMut<'_, T> { ++ pub(crate) const fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut::new(self) + } + +@@ -1113,7 +1113,7 @@ + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] +- pub const fn windows(&self, size: usize) -> Windows<'_, T> { ++ pub(crate) const fn windows(&self, size: usize) -> Windows<'_, T> { + let size = NonZero::new(size).expect("window size must be non-zero"); + Windows::new(self, size) + } +@@ -1153,7 +1153,7 @@ + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] +- pub const fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> { ++ pub(crate) const fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + Chunks::new(self, chunk_size) + } +@@ -1197,7 +1197,7 @@ + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] +- pub const fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> { ++ pub(crate) const fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksMut::new(self, chunk_size) + } +@@ -1240,7 +1240,7 @@ + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] +- pub const fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> { ++ pub(crate) const fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksExact::new(self, chunk_size) + } +@@ -1288,7 +1288,7 @@ + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] +- pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> { ++ pub(crate) const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksExactMut::new(self, chunk_size) + } +@@ -1336,7 +1336,7 @@ + #[inline] + #[must_use] + #[track_caller] +- pub const unsafe fn as_chunks_unchecked<#[rustc_panics_when_zero] const N: usize>( ++ pub(crate) const unsafe fn as_chunks_unchecked<#[rustc_panics_when_zero] const N: usize>( + &self, + ) -> &[[T; N]] { + assert_unsafe_precondition!( +@@ -1396,7 +1396,7 @@ + #[inline] + #[track_caller] + #[must_use] +- pub const fn as_chunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[[T; N]], &[T]) { ++ pub(crate) const fn as_chunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[[T; N]], &[T]) { + assert!(N != 0, "chunk size must be non-zero"); + let len_rounded_down = self.len() / N * N; + // SAFETY: The rounded-down value is always the same or smaller than the +@@ -1443,7 +1443,7 @@ + #[inline] + #[track_caller] + #[must_use] +- pub const fn as_rchunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[T], &[[T; N]]) { ++ pub(crate) const fn as_rchunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[T], &[[T; N]]) { + assert!(N != 0, "chunk size must be non-zero"); + let len = self.len() / N; + let (remainder, multiple_of_n) = self.split_at(self.len() - len * N); +@@ -1498,7 +1498,7 @@ + #[inline] + #[must_use] + #[track_caller] +- pub const unsafe fn as_chunks_unchecked_mut<#[rustc_panics_when_zero] const N: usize>( ++ pub(crate) const unsafe fn as_chunks_unchecked_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> &mut [[T; N]] { + assert_unsafe_precondition!( +@@ -1554,7 +1554,7 @@ + #[inline] + #[track_caller] + #[must_use] +- pub const fn as_chunks_mut<#[rustc_panics_when_zero] const N: usize>( ++ pub(crate) const fn as_chunks_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> (&mut [[T; N]], &mut [T]) { + assert!(N != 0, "chunk size must be non-zero"); +@@ -1609,7 +1609,7 @@ + #[inline] + #[track_caller] + #[must_use] +- pub const fn as_rchunks_mut<#[rustc_panics_when_zero] const N: usize>( ++ pub(crate) const fn as_rchunks_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> (&mut [T], &mut [[T; N]]) { + assert!(N != 0, "chunk size must be non-zero"); +@@ -1652,7 +1652,7 @@ + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] +- pub const fn array_windows<#[rustc_panics_when_zero] const N: usize>( ++ pub(crate) const fn array_windows<#[rustc_panics_when_zero] const N: usize>( + &self, + ) -> ArrayWindows<'_, T, N> { + assert!(N != 0, "window size must be non-zero"); +@@ -1694,7 +1694,7 @@ + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] +- pub const fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> { ++ pub(crate) const fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunks::new(self, chunk_size) + } +@@ -1738,7 +1738,7 @@ + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] +- pub const fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> { ++ pub(crate) const fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksMut::new(self, chunk_size) + } +@@ -1783,7 +1783,7 @@ + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] +- pub const fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> { ++ pub(crate) const fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksExact::new(self, chunk_size) + } +@@ -1832,7 +1832,7 @@ + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] +- pub const fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> { ++ pub(crate) const fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksExactMut::new(self, chunk_size) + } +@@ -1872,7 +1872,7 @@ + #[stable(feature = "slice_group_by", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] +- pub const fn chunk_by(&self, pred: F) -> ChunkBy<'_, T, F> ++ pub(crate) const fn chunk_by(&self, pred: F) -> ChunkBy<'_, T, F> + where + F: FnMut(&T, &T) -> bool, + { +@@ -1914,7 +1914,7 @@ + #[stable(feature = "slice_group_by", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] +- pub const fn chunk_by_mut(&mut self, pred: F) -> ChunkByMut<'_, T, F> ++ pub(crate) const fn chunk_by_mut(&mut self, pred: F) -> ChunkByMut<'_, T, F> + where + F: FnMut(&T, &T) -> bool, + { +@@ -1960,7 +1960,7 @@ + #[inline] + #[track_caller] + #[must_use] +- pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) { ++ pub(crate) const fn split_at(&self, mid: usize) -> (&[T], &[T]) { + match self.split_at_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), +@@ -1994,7 +1994,7 @@ + #[track_caller] + #[must_use] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] +- pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { ++ pub(crate) const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + match self.split_at_mut_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), +@@ -2046,7 +2046,7 @@ + #[inline] + #[must_use] + #[track_caller] +- pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { ++ pub(crate) const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + // FIXME(const-hack): the const function `from_raw_parts` is used to make this + // function const; previously the implementation used + // `(self.get_unchecked(..mid), self.get_unchecked(mid..))` +@@ -2100,7 +2100,7 @@ + #[inline] + #[must_use] + #[track_caller] +- pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { ++ pub(crate) const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + let len = self.len(); + let ptr = self.as_mut_ptr(); + +@@ -2161,7 +2161,7 @@ + #[rustc_const_stable(feature = "split_at_checked", since = "1.80.0")] + #[inline] + #[must_use] +- pub const fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])> { ++ pub(crate) const fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])> { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. +@@ -2200,7 +2200,7 @@ + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + #[inline] + #[must_use] +- pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> { ++ pub(crate) const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. +@@ -2252,7 +2252,7 @@ + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] +- pub fn split(&self, pred: F) -> Split<'_, T, F> ++ pub(crate) fn split(&self, pred: F) -> Split<'_, T, F> + where + F: FnMut(&T) -> bool, + { +@@ -2274,7 +2274,7 @@ + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] +- pub fn split_mut(&mut self, pred: F) -> SplitMut<'_, T, F> ++ pub(crate) fn split_mut(&mut self, pred: F) -> SplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { +@@ -2310,7 +2310,7 @@ + /// ``` + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[inline] +- pub fn split_inclusive(&self, pred: F) -> SplitInclusive<'_, T, F> ++ pub(crate) fn split_inclusive(&self, pred: F) -> SplitInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { +@@ -2334,7 +2334,7 @@ + /// ``` + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[inline] +- pub fn split_inclusive_mut(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F> ++ pub(crate) fn split_inclusive_mut(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { +@@ -2370,7 +2370,7 @@ + /// ``` + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] +- pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> ++ pub(crate) fn rsplit(&self, pred: F) -> RSplit<'_, T, F> + where + F: FnMut(&T) -> bool, + { +@@ -2396,7 +2396,7 @@ + /// + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] +- pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> ++ pub(crate) fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { +@@ -2424,7 +2424,7 @@ + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] +- pub fn splitn(&self, n: usize, pred: F) -> SplitN<'_, T, F> ++ pub(crate) fn splitn(&self, n: usize, pred: F) -> SplitN<'_, T, F> + where + F: FnMut(&T) -> bool, + { +@@ -2450,7 +2450,7 @@ + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] +- pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F> ++ pub(crate) fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { +@@ -2479,7 +2479,7 @@ + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] +- pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN<'_, T, F> ++ pub(crate) fn rsplitn(&self, n: usize, pred: F) -> RSplitN<'_, T, F> + where + F: FnMut(&T) -> bool, + { +@@ -2506,7 +2506,7 @@ + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] +- pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F> ++ pub(crate) fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { +@@ -2533,7 +2533,7 @@ + /// ``` + #[unstable(feature = "slice_split_once", issue = "112811")] + #[inline] +- pub fn split_once(&self, pred: F) -> Option<(&[T], &[T])> ++ pub(crate) fn split_once(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { +@@ -2562,7 +2562,7 @@ + /// ``` + #[unstable(feature = "slice_split_once", issue = "112811")] + #[inline] +- pub fn rsplit_once(&self, pred: F) -> Option<(&[T], &[T])> ++ pub(crate) fn rsplit_once(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { +@@ -2599,7 +2599,7 @@ + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[must_use] +- pub fn contains(&self, x: &T) -> bool ++ pub(crate) fn contains(&self, x: &T) -> bool + where + T: PartialEq, + { +@@ -2629,7 +2629,7 @@ + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] +- pub fn starts_with(&self, needle: &[T]) -> bool ++ pub(crate) fn starts_with(&self, needle: &[T]) -> bool + where + T: PartialEq, + { +@@ -2660,7 +2660,7 @@ + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] +- pub fn ends_with(&self, needle: &[T]) -> bool ++ pub(crate) fn ends_with(&self, needle: &[T]) -> bool + where + T: PartialEq, + { +@@ -2692,7 +2692,7 @@ + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "slice_strip", since = "1.51.0")] +- pub fn strip_prefix + ?Sized>(&self, prefix: &P) -> Option<&[T]> ++ pub(crate) fn strip_prefix + ?Sized>(&self, prefix: &P) -> Option<&[T]> + where + T: PartialEq, + { +@@ -2728,7 +2728,7 @@ + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "slice_strip", since = "1.51.0")] +- pub fn strip_suffix + ?Sized>(&self, suffix: &P) -> Option<&[T]> ++ pub(crate) fn strip_suffix + ?Sized>(&self, suffix: &P) -> Option<&[T]> + where + T: PartialEq, + { +@@ -2768,7 +2768,7 @@ + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "strip_circumfix", since = "1.98.0")] +- pub fn strip_circumfix(&self, prefix: &P, suffix: &S) -> Option<&[T]> ++ pub(crate) fn strip_circumfix(&self, prefix: &P, suffix: &S) -> Option<&[T]> + where + T: PartialEq, + S: SlicePattern + ?Sized, +@@ -2802,7 +2802,7 @@ + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "trim_prefix_suffix", since = "CURRENT_RUSTC_VERSION")] +- pub fn trim_prefix + ?Sized>(&self, prefix: &P) -> &[T] ++ pub(crate) fn trim_prefix + ?Sized>(&self, prefix: &P) -> &[T] + where + T: PartialEq, + { +@@ -2840,7 +2840,7 @@ + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "trim_prefix_suffix", since = "CURRENT_RUSTC_VERSION")] +- pub fn trim_suffix + ?Sized>(&self, suffix: &P) -> &[T] ++ pub(crate) fn trim_suffix + ?Sized>(&self, suffix: &P) -> &[T] + where + T: PartialEq, + { +@@ -2927,7 +2927,7 @@ + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "rust1", since = "1.0.0")] +- pub const fn binary_search(&self, x: &T) -> Result ++ pub(crate) const fn binary_search(&self, x: &T) -> Result + where + T: [const] Ord, + { +@@ -2979,7 +2979,7 @@ + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] +- pub const fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result ++ pub(crate) const fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result + where + F: [const] FnMut(&'a T) -> Ordering + [const] Destruct, + { +@@ -3081,7 +3081,7 @@ + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] + #[inline] +- pub const fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result ++ pub(crate) const fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result + where + F: [const] FnMut(&'a T) -> B + [const] Destruct, + B: [const] Ord + [const] Destruct, +@@ -3143,7 +3143,7 @@ + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] +- pub fn sort_unstable(&mut self) ++ pub(crate) fn sort_unstable(&mut self) + where + T: Ord, + { +@@ -3198,7 +3198,7 @@ + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] +- pub fn sort_unstable_by(&mut self, mut compare: F) ++ pub(crate) fn sort_unstable_by(&mut self, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + { +@@ -3250,7 +3250,7 @@ + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] +- pub fn sort_unstable_by_key(&mut self, mut f: F) ++ pub(crate) fn sort_unstable_by_key(&mut self, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, +@@ -3320,7 +3320,7 @@ + /// [`sort_unstable`]: slice::sort_unstable + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] +- pub fn partial_sort_unstable(&mut self, range: R) ++ pub(crate) fn partial_sort_unstable(&mut self, range: R) + where + T: Ord, + R: RangeBounds, +@@ -3391,7 +3391,7 @@ + /// [`sort_unstable_by`]: slice::sort_unstable_by + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] +- pub fn partial_sort_unstable_by(&mut self, range: R, mut compare: F) ++ pub(crate) fn partial_sort_unstable_by(&mut self, range: R, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + R: RangeBounds, +@@ -3462,7 +3462,7 @@ + /// [`sort_unstable_by_key`]: slice::sort_unstable_by_key + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] +- pub fn partial_sort_unstable_by_key(&mut self, range: R, mut f: F) ++ pub(crate) fn partial_sort_unstable_by_key(&mut self, range: R, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, +@@ -3526,7 +3526,7 @@ + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] +- pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) ++ pub(crate) fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + where + T: Ord, + { +@@ -3591,7 +3591,7 @@ + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] +- pub fn select_nth_unstable_by( ++ pub(crate) fn select_nth_unstable_by( + &mut self, + index: usize, + mut compare: F, +@@ -3658,7 +3658,7 @@ + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] +- pub fn select_nth_unstable_by_key( ++ pub(crate) fn select_nth_unstable_by_key( + &mut self, + index: usize, + mut f: F, +@@ -3692,7 +3692,7 @@ + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] +- pub fn partition_dedup(&mut self) -> (&mut [T], &mut [T]) ++ pub(crate) fn partition_dedup(&mut self) -> (&mut [T], &mut [T]) + where + T: PartialEq, + { +@@ -3730,7 +3730,7 @@ + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] +- pub fn partition_dedup_by(&mut self, mut same_bucket: F) -> (&mut [T], &mut [T]) ++ pub(crate) fn partition_dedup_by(&mut self, mut same_bucket: F) -> (&mut [T], &mut [T]) + where + F: FnMut(&mut T, &mut T) -> bool, + { +@@ -3856,7 +3856,7 @@ + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] +- pub fn partition_dedup_by_key(&mut self, mut key: F) -> (&mut [T], &mut [T]) ++ pub(crate) fn partition_dedup_by_key(&mut self, mut key: F) -> (&mut [T], &mut [T]) + where + F: FnMut(&mut T) -> K, + K: PartialEq, +@@ -3898,7 +3898,7 @@ + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] +- pub const fn rotate_left(&mut self, mid: usize) { ++ pub(crate) const fn rotate_left(&mut self, mid: usize) { + assert!(mid <= self.len()); + let k = self.len() - mid; + let p = self.as_mut_ptr(); +@@ -3944,7 +3944,7 @@ + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] +- pub const fn rotate_right(&mut self, k: usize) { ++ pub(crate) const fn rotate_right(&mut self, k: usize) { + assert!(k <= self.len()); + let mid = self.len() - k; + let p = self.as_mut_ptr(); +@@ -4018,7 +4018,7 @@ + /// assert_eq!(a, [3]); + /// ``` + #[unstable(feature = "slice_shift", issue = "151772")] +- pub const fn shift_left(&mut self, inserted: [T; N]) -> [T; N] { ++ pub(crate) const fn shift_left(&mut self, inserted: [T; N]) -> [T; N] { + if let Some(shift) = self.len().checked_sub(N) { + // SAFETY: Having just checked that the inserted/returned arrays are + // shorter than (or the same length as) the slice: +@@ -4122,7 +4122,7 @@ + /// assert_eq!(a, [1]); + /// ``` + #[unstable(feature = "slice_shift", issue = "151772")] +- pub const fn shift_right(&mut self, inserted: [T; N]) -> [T; N] { ++ pub(crate) const fn shift_right(&mut self, inserted: [T; N]) -> [T; N] { + if let Some(shift) = self.len().checked_sub(N) { + // SAFETY: Having just checked that the inserted/returned arrays are + // shorter than (or the same length as) the slice: +@@ -4180,7 +4180,7 @@ + /// ``` + #[doc(alias = "memset")] + #[stable(feature = "slice_fill", since = "1.50.0")] +- pub fn fill(&mut self, value: T) ++ pub(crate) fn fill(&mut self, value: T) + where + T: Clone, + { +@@ -4204,7 +4204,7 @@ + /// assert_eq!(buf, vec![0; 10]); + /// ``` + #[stable(feature = "slice_fill_with", since = "1.51.0")] +- pub fn fill_with(&mut self, mut f: F) ++ pub(crate) fn fill_with(&mut self, mut f: F) + where + F: FnMut() -> T, + { +@@ -4268,7 +4268,7 @@ + #[stable(feature = "clone_from_slice", since = "1.7.0")] + #[track_caller] + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] +- pub const fn clone_from_slice(&mut self, src: &[T]) ++ pub(crate) const fn clone_from_slice(&mut self, src: &[T]) + where + T: [const] Clone + [const] Destruct, + { +@@ -4334,7 +4334,7 @@ + #[stable(feature = "copy_from_slice", since = "1.9.0")] + #[rustc_const_stable(feature = "const_copy_from_slice", since = "1.87.0")] + #[track_caller] +- pub const fn copy_from_slice(&mut self, src: &[T]) ++ pub(crate) const fn copy_from_slice(&mut self, src: &[T]) + where + T: Copy, + { +@@ -4369,7 +4369,7 @@ + #[inline] + #[stable(feature = "copy_within", since = "1.37.0")] + #[track_caller] +- pub fn copy_within>(&mut self, src: R, dest: usize) ++ pub(crate) fn copy_within>(&mut self, src: R, dest: usize) + where + T: Copy, + { +@@ -4437,7 +4437,7 @@ + #[stable(feature = "swap_with_slice", since = "1.27.0")] + #[rustc_const_unstable(feature = "const_swap_with_slice", issue = "142204")] + #[track_caller] +- pub const fn swap_with_slice(&mut self, other: &mut [T]) { ++ pub(crate) const fn swap_with_slice(&mut self, other: &mut [T]) { + assert!(self.len() == other.len(), "destination and source slices have different lengths"); + // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was + // checked to have the same length. The slices cannot overlap because +@@ -4514,7 +4514,7 @@ + /// ``` + #[stable(feature = "slice_align_to", since = "1.30.0")] + #[must_use] +- pub unsafe fn align_to(&self) -> (&[T], &[U], &[T]) { ++ pub(crate) unsafe fn align_to(&self) -> (&[T], &[U], &[T]) { + // Note that most of this function will be constant-evaluated, + if U::IS_ZST || T::IS_ZST { + // handle ZSTs specially, which is – don't handle them at all. +@@ -4579,7 +4579,7 @@ + /// ``` + #[stable(feature = "slice_align_to", since = "1.30.0")] + #[must_use] +- pub unsafe fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) { ++ pub(crate) unsafe fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) { + // Note that most of this function will be constant-evaluated, + if U::IS_ZST || T::IS_ZST { + // handle ZSTs specially, which is – don't handle them at all. +@@ -4670,7 +4670,7 @@ + /// ``` + #[unstable(feature = "portable_simd", issue = "86656")] + #[must_use] +- pub fn as_simd(&self) -> (&[T], &[Simd], &[T]) ++ pub(crate) fn as_simd(&self) -> (&[T], &[Simd], &[T]) + where + Simd: AsRef<[T; LANES]>, + T: simd::SimdElement, +@@ -4705,7 +4705,7 @@ + /// method for something like `LANES == 3`. + #[unstable(feature = "portable_simd", issue = "86656")] + #[must_use] +- pub fn as_simd_mut(&mut self) -> (&mut [T], &mut [Simd], &mut [T]) ++ pub(crate) fn as_simd_mut(&mut self) -> (&mut [T], &mut [Simd], &mut [T]) + where + Simd: AsMut<[T; LANES]>, + T: simd::SimdElement, +@@ -4743,7 +4743,7 @@ + #[inline] + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] +- pub fn is_sorted(&self) -> bool ++ pub(crate) fn is_sorted(&self) -> bool + where + T: PartialOrd, + { +@@ -4786,7 +4786,7 @@ + /// ``` + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] +- pub fn is_sorted_by<'a, F>(&'a self, mut compare: F) -> bool ++ pub(crate) fn is_sorted_by<'a, F>(&'a self, mut compare: F) -> bool + where + F: FnMut(&'a T, &'a T) -> bool, + { +@@ -4810,7 +4810,7 @@ + #[inline] + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] +- pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool ++ pub(crate) fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool + where + F: FnMut(&'a T) -> K, + K: PartialOrd, +@@ -4870,7 +4870,7 @@ + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "partition_point", since = "1.52.0")] + #[must_use] +- pub const fn partition_point

(&self, mut pred: P) -> usize ++ pub(crate) const fn partition_point

(&self, mut pred: P) -> usize + where + P: [const] FnMut(&T) -> bool + [const] Destruct, + { +@@ -4923,7 +4923,7 @@ + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[stable(feature = "slice_take", since = "1.87.0")] +- pub fn split_off<'a, R: OneSidedRange>( ++ pub(crate) fn split_off<'a, R: OneSidedRange>( + self: &mut &'a Self, + range: R, + ) -> Option<&'a Self> { +@@ -4989,7 +4989,7 @@ + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[stable(feature = "slice_take", since = "1.87.0")] +- pub fn split_off_mut<'a, R: OneSidedRange>( ++ pub(crate) fn split_off_mut<'a, R: OneSidedRange>( + self: &mut &'a mut Self, + range: R, + ) -> Option<&'a mut Self> { +@@ -5027,7 +5027,7 @@ + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] +- pub const fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { ++ pub(crate) const fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((first, rem)) = self.split_first() else { return None }; + *self = rem; +@@ -5052,7 +5052,7 @@ + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] +- pub const fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { ++ pub(crate) const fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_first_mut()?` + let Some((first, rem)) = mem::replace(self, &mut []).split_first_mut() else { return None }; +@@ -5077,7 +5077,7 @@ + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] +- pub const fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { ++ pub(crate) const fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((last, rem)) = self.split_last() else { return None }; + *self = rem; +@@ -5102,7 +5102,7 @@ + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] +- pub const fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { ++ pub(crate) const fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_last_mut()?` + let Some((last, rem)) = mem::replace(self, &mut []).split_last_mut() else { return None }; +@@ -5159,7 +5159,7 @@ + #[stable(feature = "get_many_mut", since = "1.86.0")] + #[inline] + #[track_caller] +- pub unsafe fn get_disjoint_unchecked_mut( ++ pub(crate) unsafe fn get_disjoint_unchecked_mut( + &mut self, + indices: [I; N], + ) -> [&mut I::Output; N] +@@ -5226,7 +5226,7 @@ + /// ``` + #[stable(feature = "get_many_mut", since = "1.86.0")] + #[inline] +- pub fn get_disjoint_mut( ++ pub(crate) fn get_disjoint_mut( + &mut self, + indices: [I; N], + ) -> Result<[&mut I::Output; N], GetDisjointMutError> +@@ -5277,7 +5277,7 @@ + /// ``` + #[must_use] + #[stable(feature = "element_offset", since = "1.94.0")] +- pub fn element_offset(&self, element: &T) -> Option { ++ pub(crate) fn element_offset(&self, element: &T) -> Option { + if T::IS_ZST { + panic!("elements are zero-sized"); + } +@@ -5331,7 +5331,7 @@ + /// ``` + #[must_use] + #[stable(feature = "substr_range", since = "1.98.0")] +- pub fn subslice_range(&self, subslice: &[T]) -> Option> { ++ pub(crate) fn subslice_range(&self, subslice: &[T]) -> Option> { + if T::IS_ZST { + panic!("elements are zero-sized"); + } +@@ -5362,7 +5362,7 @@ + /// for example `Box<[T]>` or `Arc<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] +- pub const fn as_slice(&self) -> &[T] { ++ pub(crate) const fn as_slice(&self) -> &[T] { + self + } + +@@ -5373,7 +5373,7 @@ + /// for example `Box<[T]>` or `MutexGuard<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] +- pub const fn as_mut_slice(&mut self) -> &mut [T] { ++ pub(crate) const fn as_mut_slice(&mut self) -> &mut [T] { + self + } + } +@@ -5461,7 +5461,7 @@ + /// ``` + #[stable(feature = "slice_flatten", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] +- pub const fn as_flattened(&self) -> &[T] { ++ pub(crate) const fn as_flattened(&self) -> &[T] { + let len = if T::IS_ZST { + self.len().checked_mul(N).expect("slice len overflow") + } else { +@@ -5503,7 +5503,7 @@ + /// ``` + #[stable(feature = "slice_flatten", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] +- pub const fn as_flattened_mut(&mut self) -> &mut [T] { ++ pub(crate) const fn as_flattened_mut(&mut self) -> &mut [T] { + let len = if T::IS_ZST { + self.len().checked_mul(N).expect("slice len overflow") + } else { +diff -ru a/slice/raw.rs b/slice/raw.rs +--- a/slice/raw.rs ++++ b/slice/raw.rs +@@ -119,7 +119,7 @@ + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] + #[must_use] +-#[rustc_diagnostic_item = "slice_from_raw_parts"] ++// #[rustc_diagnostic_item = "slice_from_raw_parts"] + #[track_caller] + pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. +@@ -174,7 +174,7 @@ + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")] + #[must_use] +-#[rustc_diagnostic_item = "slice_from_raw_parts_mut"] ++// #[rustc_diagnostic_item = "slice_from_raw_parts_mut"] + #[track_caller] + pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. +@@ -198,7 +198,7 @@ + /// Converts a reference to T into a slice of length 1 (without copying). + #[stable(feature = "from_ref", since = "1.28.0")] + #[rustc_const_stable(feature = "const_slice_from_ref_shared", since = "1.63.0")] +-#[rustc_diagnostic_item = "slice_from_ref"] ++// #[rustc_diagnostic_item = "slice_from_ref"] + #[must_use] + pub const fn from_ref(s: &T) -> &[T] { + array::from_ref(s) diff --git a/verifast-proofs/core/slice/mod.rs/core.rsspec b/verifast-proofs/core/slice/mod.rs/core.rsspec new file mode 100644 index 0000000000000..8eb9b00e49d44 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/core.rsspec @@ -0,0 +1,114 @@ +mod num { + impl usize { + fn is_multiple_of(self: usize, rhs: usize) -> bool; + //@ req true; + //@ ens result == if rhs == 0 { self == 0 } else { self % rhs == 0 }; + //@ on_unwind_ens false; + } +} + +mod hint { + fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T; + //@ req true; + //@ ens result == if b { true_val } else { false_val }; + //@ on_unwind_ens false; +} + +mod cmp { + mod PartialEq { + fn eq(self: &'a T, other: &'b U) -> bool; + //@ req <&'b U>.own(?_t, other); + //@ ens true; + //@ on_unwind_ens false; + } +} + +mod mem { + fn swap(x: &'a mut T, y: &'b mut T); + //@ req *x |-> ?vx &*& *y |-> ?vy; + //@ ens *x |-> vy &*& *y |-> vx; + //@ on_unwind_ens false; +} + +mod ptr { + fn metadata(p: *const T) -> usize; + //@ req true; + //@ ens result == ptr_len(p) &*& 0 <= result &*& result <= usize::MAX; + //@ on_unwind_ens false; + + /*@ + // `ptr::swap` allows `x == y` (and, more generally, overlap); this models the `x == y` case + // as the only aliasing case, which is all `core::slice` needs. + pred opt_pointsto(same: bool, x: *T, y: *T, vx: T, vy: T) = + if same { x == y &*& vy == vx } else { *y |-> vy }; + @*/ + + unsafe fn swap(x: *mut T, y: *mut T); + //@ req *x |-> ?vx &*& opt_pointsto::(?same, x, y, vx, ?vy); + //@ ens *x |-> vy &*& if same { true } else { *y |-> vx }; + //@ on_unwind_ens false; + + unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize); + //@ req x[..count] |-> ?vs1 &*& y[..count] |-> ?vs2; + //@ ens x[..count] |-> vs2 &*& y[..count] |-> vs1; + //@ on_unwind_ens false; +} + +mod slice { + + /*@ + pred SliceIndex_in_bounds(idx: I, slice: *T); + + lem usize_SliceIndex_in_bounds(i: usize, slice: *[T]); + req i < slice.len(); + ens SliceIndex_in_bounds::(i, slice); + + fix GetDisjointMutIndex_in_bounds(idx: I, len: usize) -> bool; + fix GetDisjointMutIndex_overlapping(idx1: I, idx2: I) -> bool; + @*/ + + enum GetDisjointMutError { + IndexOutOfBounds, + OverlappingIndices, + } + + trait SliceIndex { + type Output; + } + + mod SliceIndex { + + unsafe fn get_unchecked(self: I, slice: *const T) -> *const >::Output; + //@ req thread_token(?t) &*& [_](.share(?k, t, slice)) &*& std::slice::SliceIndex_in_bounds::(self, slice); + //@ ens thread_token(t) &*& [_](< >::Output>.share(k, t, result)); + //@ on_unwind_ens false; + + unsafe fn get_unchecked_mut(self: I, slice: *mut T) -> *mut >::Output; + //@ req thread_token(?t) &*& full_borrow(?k, .full_borrow_content(t, slice)) &*& std::slice::SliceIndex_in_bounds::(self, slice); + //@ ens thread_token(t) &*& full_borrow(k, < >::Output>.full_borrow_content(t, result)); + //@ on_unwind_ens false; + + } + + mod GetDisjointMutIndex { + + fn is_in_bounds(self: &'a I, len: usize) -> bool; + //@ req thread_token(?t) &*& [?f](*self |-> ?v); + //@ ens thread_token(t) &*& [f](*self |-> v) &*& result == std::slice::GetDisjointMutIndex_in_bounds::(v, len); + //@ on_unwind_ens false; + + fn is_overlapping(self: &'a I, other: &'b I) -> bool; + //@ req thread_token(?t) &*& [?f1](*self |-> ?v1) &*& [?f2](*other |-> ?v2); + //@ ens thread_token(t) &*& [f1](*self |-> v1) &*& [f2](*other |-> v2) &*& result == std::slice::GetDisjointMutIndex_overlapping::(v1, v2); + //@ on_unwind_ens false; + + } + + fn copy_from_slice_impl::len_mismatch_fail(dst_len: usize, src_len: usize) -> !; + //@ req true; + //@ ens false; + //@ on_unwind_ens false; + +} + + diff --git a/verifast-proofs/core/slice/mod.rs/original/lib.rs b/verifast-proofs/core/slice/mod.rs/original/lib.rs new file mode 100644 index 0000000000000..57beec482efd3 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/original/lib.rs @@ -0,0 +1,344 @@ +#![feature(const_result_trait_fn, const_iter)] +#![feature(one_sided_range, portable_simd, slice_index_methods, const_index, slice_range, const_clone, trivial_clone, slice_from_ptr_range, const_default, u8_split_ascii_whitespace, str_internals, slice_pattern)] +#![feature(slice_ptr_get, raw_slice_split, ptr_cast_array, array_into_iter_constructors, exact_size_is_empty, iter_advance_by, iter_next_chunk, iter_collect_into, trusted_len, trusted_random_access, trusted_fused, inplace_iteration, sized_type_properties, nonnull_provenance, ptr_metadata, slice_internals, const_option_ops, deref_pure_trait, try_trait_v2, never_type, specialization)] +//! # The Rust Core Library +//! +//! The Rust Core Library is the dependency-free[^free] foundation of [The +//! Rust Standard Library](../std/index.html). It is the portable glue +//! between the language and its libraries, defining the intrinsic and +//! primitive building blocks of all Rust code. It links to no +//! upstream libraries, no system libraries, and no libc. +//! +//! [^free]: Strictly speaking, there are some symbols which are needed but +//! they aren't always necessary. +//! +//! The core library is *minimal*: it isn't even aware of heap allocation, +//! nor does it provide concurrency or I/O. These things require +//! platform integration, and this library is platform-agnostic. +//! +//! # How to use the core library +//! +//! Please note that all of these details are currently not considered stable. +//! +// FIXME: Fill me in with more detail when the interface settles +//! This library is built on the assumption of a few existing symbols: +//! +//! * `memcpy`, `memmove`, `memset`, `memcmp`, `bcmp`, `strlen` - These are core memory routines +//! which are generated by Rust codegen backends. Additionally, this library can make explicit +//! calls to `strlen`. Their signatures are the same as found in C, but there are extra +//! assumptions about their semantics: For `memcpy`, `memmove`, `memset`, `memcmp`, and `bcmp`, if +//! the `n` parameter is 0, the function is assumed to not be UB, even if the pointers are NULL or +//! dangling. (Note that making extra assumptions about these functions is common among compilers: +//! [clang](https://reviews.llvm.org/D86993) and [GCC](https://gcc.gnu.org/onlinedocs/gcc/Standards.html#C-Language) do the same.) +//! These functions are often provided by the system libc, but can also be provided by the +//! [compiler-builtins crate](https://crates.io/crates/compiler_builtins). +//! Note that the library does not guarantee that it will always make these assumptions, so Rust +//! user code directly calling the C functions should follow the C specification! The advice for +//! Rust user code is to call the functions provided by this library instead (such as +//! `ptr::copy`). +//! +//! * Panic handler - This function takes one argument, a `&panic::PanicInfo`. It is up to consumers of this core +//! library to define this panic function; it is only required to never +//! return. You should mark your implementation using `#[panic_handler]`. +//! +//! * `rust_eh_personality` - is used by the failure mechanisms of the +//! compiler. This is often mapped to GCC's personality function, but crates +//! which do not trigger a panic can be assured that this function is never +//! called. The `lang` attribute is called `eh_personality`. + +#![stable(feature = "core", since = "1.6.0")] +#![doc( + html_playground_url = "https://play.rust-lang.org/", + issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", + test(no_crate_inject, attr(deny(warnings))), + test(attr(allow(dead_code, deprecated, unused_variables, unused_mut, duplicate_features))) +)] +#![doc(rust_logo)] +#![doc(auto_cfg( + hide(no_fp_fmt_parse), + hide(target_pointer_width, values("16", "32", "64")), + hide( + target_has_atomic, + target_has_atomic_primitive_alignment, + target_has_atomic_load_store, + values("8", "16", "32", "64", "ptr"), + ), +))] +#![rustc_coherence_is_core] +#![rustc_preserve_ub_checks] +// +// Lints: +#![deny(rust_2021_incompatible_or_patterns)] +#![deny(unsafe_op_in_unsafe_fn)] +#![deny(implicit_provenance_casts)] +#![warn(deprecated_in_future)] +#![warn(missing_debug_implementations)] +#![warn(missing_docs)] +#![allow(explicit_outlives_requirements)] +#![allow(incomplete_features)] +#![warn(multiple_supertrait_upcastable)] +#![allow(internal_features)] +#![allow(unused_features)] +#![deny(ffi_unwind_calls)] +#![warn(unreachable_pub)] +// Do not check link redundancy on bootstrapping phase +#![allow(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::unescaped_backticks)] +// +// Library features: +// tidy-alphabetical-start +#![feature(asm_experimental_arch)] +#![feature(bstr_internals)] +#![feature(cfg_target_has_reliable_f16_f128)] +#![feature(const_carrying_mul_add)] +#![feature(const_cmp)] +#![feature(const_destruct)] +#![feature(const_eval_select)] +#![feature(const_select_unpredictable)] +#![feature(core_intrinsics)] +#![feature(coverage_attribute)] +#![feature(disjoint_bitor)] +#![feature(io_const_error)] +#![feature(offset_of_enum)] +#![feature(panic_internals)] +#![feature(pattern_type_macro)] +#![feature(ub_checks)] +// tidy-alphabetical-end +// +// Language features: +// tidy-alphabetical-start +#![feature(adt_const_params)] +#![feature(allow_internal_unsafe)] +#![feature(allow_internal_unstable)] +#![feature(arbitrary_self_types_pointers)] +#![feature(auto_traits)] +#![feature(cfg_sanitize)] +#![feature(cfg_target_has_atomic)] +#![feature(cfg_ub_checks)] +#![feature(const_closures)] +#![feature(const_precise_live_drops)] +#![feature(const_trait_impl)] +#![feature(decl_macro)] +#![feature(deprecated_suggestion)] +#![feature(derive_const)] +#![feature(diagnostic_on_const)] +#![feature(diagnostic_on_unmatched_args)] +#![feature(diagnostic_opaque)] +#![feature(doc_cfg)] +#![feature(doc_notable_trait)] +#![feature(extern_types)] +#![feature(f16)] +#![feature(f128)] +#![feature(field_projections)] +#![feature(final_associated_functions)] +#![feature(freeze_impls)] +#![feature(fundamental)] +#![feature(funnel_shifts)] +#![feature(impl_restriction)] +#![feature(intra_doc_pointers)] +#![feature(intrinsics)] +#![feature(lang_items)] +#![feature(link_cfg)] +#![feature(link_llvm_intrinsics)] +#![feature(macro_metavar_expr)] +#![feature(macro_metavar_expr_concat)] +#![feature(marker_trait_attr)] +#![feature(min_specialization)] +#![feature(multiple_supertrait_upcastable)] +#![feature(must_not_suspend)] +#![feature(negative_impls)] +#![feature(no_core)] +#![feature(optimize_attribute)] +#![feature(pattern_types)] +#![feature(pin_macro_internals)] +#![feature(prelude_import)] +#![feature(repr_simd)] +#![feature(rustc_attrs)] +#![feature(rustdoc_internals)] +#![feature(simd_ffi)] +#![feature(splat)] +#![feature(staged_api)] +#![feature(stmt_expr_attributes)] +#![feature(strict_provenance_lints)] +#![feature(trait_alias)] +#![feature(transparent_unions)] +#![feature(try_blocks)] +#![feature(uint_carryless_mul)] +#![feature(unboxed_closures)] +#![feature(unsized_fn_params)] +#![feature(with_negative_coherence)] +// Required for Kani loop contracts, which are annotated as custom stmt attributes. +#![feature(proc_macro_hygiene)] +// tidy-alphabetical-end +// +// Target features: +// tidy-alphabetical-start +#![feature(aarch64_unstable_target_feature)] +#![feature(arm_target_feature)] +#![feature(avx10_target_feature)] +#![feature(clflushopt_target_feature)] +#![feature(hexagon_target_feature)] +#![feature(loongarch_target_feature)] +#![feature(mips_target_feature)] +#![feature(movrs_target_feature)] +#![feature(nvptx_target_feature)] +#![feature(powerpc_target_feature)] +#![feature(riscv_target_feature)] +#![feature(rtm_target_feature)] +#![feature(s390x_target_feature)] +#![feature(wasm_target_feature)] +#![feature(x86_amx_intrinsics)] +// tidy-alphabetical-end + +// tidy-alphabetical-start +#![expect(clippy::partialeq_ne_impl, reason = "we need to implement ne for a lot of core types")] +// tidy-alphabetical-end + +// allow using `core::` in intra-doc links + +#![no_core] +#![allow(unused_imports, unused_variables, dead_code, unused_mut, unreachable_pub, missing_docs, missing_debug_implementations)] + +#[stable(feature = "rust1", since = "1.0.0")] +extern crate core; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::{iter, ascii, char, clone, cmp, convert, default, fmt, hash, hint, marker, mem, num, ops, option, panicking, pin, range, result, simd, str}; +#[stable(feature = "rust1", since = "1.0.0")] +pub mod panic { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::panic::{Location, PanicInfo}; + #[unstable(feature = "panic_internals", issue = "none")] + pub macro const_panic($($t:tt)*) { + loop {} + } +} +#[stable(feature = "rust1", since = "1.0.0")] +pub mod ptr { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::ptr::*; + #[unstable(feature = "ptr_internals", issue = "none")] + pub unsafe fn align_offset(p: *const T, a: usize) -> usize { + p.align_offset(a) + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] + pub const unsafe fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { + core::ptr::slice_from_raw_parts(data, len) + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")] + pub const unsafe fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { + core::ptr::slice_from_raw_parts_mut(data, len) + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] + pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + unsafe { core::ptr::copy(src, dst, count) } + } +} +#[stable(feature = "rust1", since = "1.0.0")] +pub mod intrinsics { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::intrinsics::{assume, arith_offset, ptr_offset_from, ptr_offset_from_unsigned, transmute, transmute_unchecked, write_bytes, copy, copy_nonoverlapping, compare_bytes, cttz_nonzero, ctlz_nonzero, size_of_val, align_of_val, size_of, align_of, needs_drop, type_id, type_name, caller_location, cold_path, likely, unlikely, select_unpredictable, abort, unreachable, const_eval_select, black_box, unchecked_shl, unchecked_shr}; + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn exact_div(x: usize, y: usize) -> usize { + x / y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_sub(x: usize, y: usize) -> usize { + x - y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_add(x: usize, y: usize) -> usize { + x + y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_mul(x: usize, y: usize) -> usize { + x * y + } +} + +#[unstable(feature = "ub_checks", issue = "none")] +pub mod ub_checks { + #[unstable(feature = "ub_checks", issue = "none")] + pub trait Invariant { + fn is_safe(&self) -> bool { true } + } + #[unstable(feature = "ub_checks", issue = "none")] + impl Invariant for &T {} + #[unstable(feature = "ub_checks", issue = "none")] + impl Invariant for &mut T {} + #[macro_export] + macro_rules! assert_unsafe_precondition { + ($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {{}}; + } + #[unstable(feature = "ub_checks", issue = "none")] + pub use assert_unsafe_precondition; + #[unstable(feature = "ub_checks", issue = "none")] + pub const fn check_language_ub() -> bool { false } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn same_allocation(_a: *const T, _b: *const T) -> bool { true } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn can_dereference(_p: *const T) -> bool { true } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn can_write(_p: *mut T) -> bool { true } +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod array { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::array::*; + #[unstable(feature = "iter_next_chunk", issue = "none")] + pub fn iter_next_chunk(_iter: &mut impl crate::iter::Iterator) -> Result<[T; N], core::array::IntoIter> { + loop {} + } +} + + + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::prelude::v1::{ + Copy, Send, Sized, Sync, Unpin, Drop, Fn, FnMut, FnOnce, AsyncFn, AsyncFnMut, AsyncFnOnce, + drop, align_of, align_of_val, size_of, size_of_val, + Clone, PartialEq, PartialOrd, Eq, Ord, AsMut, AsRef, From, Into, + Option, Some, None, Result, Ok, Err, + Debug, Hash, + panic, assert, assert_eq, assert_ne, cfg, column, compile_error, concat, debug_assert, debug_assert_eq, + debug_assert_ne, file, format_args, include, include_bytes, include_str, line, matches, + module_path, option_env, stringify, todo, unimplemented, unreachable, write, writeln, + cfg_select, derive, derive_const, + }; + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::prelude::rust_2024::{TryInto, TryFrom, FromIterator, Future, IntoFuture}; + #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::Default; + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::iter::{Iterator, IntoIterator, DoubleEndedIterator, ExactSizeIterator, Extend}; +} +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +pub const trait Default { + #[stable(feature = "rust1", since = "1.0.0")] + fn default() -> Self; +} +#[prelude_import] +#[stable(feature = "rust1", since = "1.0.0")] +pub use prelude::*; + +#[stable(feature = "rust1", since = "1.0.0")] +#[path = "."] +pub mod std { + pub mod slice; +} +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::std::slice; + +#[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] +const fn _vf_const_marker() {} + diff --git a/verifast-proofs/core/slice/mod.rs/original/slice.rs b/verifast-proofs/core/slice/mod.rs/original/slice.rs new file mode 100644 index 0000000000000..f609db38f2688 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/original/slice.rs @@ -0,0 +1,6278 @@ +//! Slice management and manipulation. +//! +//! For more details see [`std::slice`]. +//! +//! [`std::slice`]: ../../std/slice/index.html + +#![stable(feature = "rust1", since = "1.0.0")] + +use safety::{ensures, requires}; + +use crate::clone::TrivialClone; +use crate::cmp::Ordering::{self, Equal, Greater, Less}; +use crate::intrinsics::{exact_div, unchecked_sub}; +#[cfg(kani)] +use crate::kani; +use crate::marker::Destruct; +use crate::mem::{self, MaybeUninit, SizedTypeProperties}; +use crate::num::NonZero; +use crate::ops::{OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeInclusive}; +use crate::panic::const_panic; +use crate::simd::{self, Simd}; +use crate::ub_checks::assert_unsafe_precondition; +use crate::{fmt, hint, ptr, range, slice}; + +#[unstable( + feature = "slice_internals", + issue = "none", + reason = "exposed from core to be reused in std; use the memchr crate" +)] +#[doc(hidden)] +/// Pure Rust memchr implementation, taken from rust-memchr +pub mod memchr; + +#[unstable( + feature = "slice_internals", + issue = "none", + reason = "exposed from core to be reused in std;" +)] +#[doc(hidden)] +pub mod sort; + +mod ascii; +mod cmp; +pub(crate) mod index; +mod iter; +mod raw; +mod rotate; +mod specialize; + +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] +pub use ascii::EscapeAscii; +#[unstable(feature = "u8_split_ascii_whitespace", issue = "147878")] +pub use ascii::SplitAsciiWhitespace; +#[unstable(feature = "str_internals", issue = "none")] +#[doc(hidden)] +pub use ascii::is_ascii_simple; +#[stable(feature = "slice_get_slice", since = "1.28.0")] +pub use index::SliceIndex; +#[unstable(feature = "slice_range", issue = "76393")] +pub use index::{range, try_range}; +#[stable(feature = "array_windows", since = "1.94.0")] +pub use iter::ArrayWindows; +#[stable(feature = "slice_group_by", since = "1.77.0")] +pub use iter::{ChunkBy, ChunkByMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Chunks, ChunksMut, Windows}; +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub use iter::{ChunksExact, ChunksExactMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Iter, IterMut}; +#[stable(feature = "rchunks", since = "1.31.0")] +pub use iter::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; +#[stable(feature = "slice_rsplit", since = "1.27.0")] +pub use iter::{RSplit, RSplitMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut}; +#[stable(feature = "split_inclusive", since = "1.51.0")] +pub use iter::{SplitInclusive, SplitInclusiveMut}; +#[stable(feature = "from_ref", since = "1.28.0")] +pub use raw::{from_mut, from_ref}; +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +pub use raw::{from_mut_ptr_range, from_ptr_range}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::{from_raw_parts, from_raw_parts_mut}; + +/// Calculates the direction and split point of a one-sided range. +/// +/// This is a helper function for `split_off` and `split_off_mut` that returns +/// the direction of the split (front or back) as well as the index at +/// which to split. Returns `None` if the split index would overflow. +#[inline] +fn split_point_of(range: impl OneSidedRange) -> Option<(Direction, usize)> { + use OneSidedRangeBound::{End, EndInclusive, StartInclusive}; + + Some(match range.bound() { + (StartInclusive, i) => (Direction::Back, i), + (End, i) => (Direction::Front, i), + (EndInclusive, i) => (Direction::Front, i.checked_add(1)?), + }) +} + +enum Direction { + Front, + Back, +} + +impl [T] { + /// Returns the number of elements in the slice. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert_eq!(a.len(), 3); + /// ``` + #[lang = "slice_len_fn"] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + pub const fn len(&self) -> usize { + ptr::metadata(self) + } + + /// Returns `true` if the slice has a length of 0. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert!(!a.is_empty()); + /// + /// let b: &[i32] = &[]; + /// assert!(b.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.39.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + pub const fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&10), v.first()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.first()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn first(&self) -> Option<&T> { + if let [first, ..] = self { Some(first) } else { None } + } + + /// Returns a mutable reference to the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(first) = x.first_mut() { + /// *first = 5; + /// } + /// assert_eq!(x, &[5, 1, 2]); + /// + /// let y: &mut [i32] = &mut []; + /// assert_eq!(None, y.first_mut()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn first_mut(&mut self) -> Option<&mut T> { + if let [first, ..] = self { Some(first) } else { None } + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first() { + /// assert_eq!(first, &0); + /// assert_eq!(elements, &[1, 2]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn split_first(&self) -> Option<(&T, &[T])> { + if let [first, tail @ ..] = self { Some((first, tail)) } else { None } + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_mut() { + /// *first = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[3, 4, 5]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if let [first, tail @ ..] = self { Some((first, tail)) } else { None } + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last() { + /// assert_eq!(last, &2); + /// assert_eq!(elements, &[0, 1]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn split_last(&self) -> Option<(&T, &[T])> { + if let [init @ .., last] = self { Some((last, init)) } else { None } + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last_mut() { + /// *last = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[4, 5, 3]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if let [init @ .., last] = self { Some((last, init)) } else { None } + } + + /// Returns the last element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&30), v.last()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.last()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn last(&self) -> Option<&T> { + if let [.., last] = self { Some(last) } else { None } + } + + /// Returns a mutable reference to the last item in the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(last) = x.last_mut() { + /// *last = 10; + /// } + /// assert_eq!(x, &[0, 1, 10]); + /// + /// let y: &mut [i32] = &mut []; + /// assert_eq!(None, y.last_mut()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn last_mut(&mut self) -> Option<&mut T> { + if let [.., last] = self { Some(last) } else { None } + } + + /// Returns an array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let u = [10, 40, 30]; + /// assert_eq!(Some(&[10, 40]), u.first_chunk::<2>()); + /// + /// let v: &[i32] = &[10]; + /// assert_eq!(None, v.first_chunk::<2>()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(Some(&[]), w.first_chunk::<0>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn first_chunk(&self) -> Option<&[T; N]> { + if self.len() < N { + None + } else { + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the reference outlive the slice. + Some(unsafe { &*(self.as_ptr().cast_array()) }) + } + } + + /// Returns a mutable array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(first) = x.first_chunk_mut::<2>() { + /// first[0] = 5; + /// first[1] = 4; + /// } + /// assert_eq!(x, &[5, 4, 2]); + /// + /// assert_eq!(None, x.first_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn first_chunk_mut(&mut self) -> Option<&mut [T; N]> { + if self.len() < N { + None + } else { + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and require exclusive access to the entire slice to mutate the chunk. + Some(unsafe { &mut *(self.as_mut_ptr().cast_array()) }) + } + } + + /// Returns an array reference to the first `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_chunk::<2>() { + /// assert_eq!(first, &[0, 1]); + /// assert_eq!(elements, &[2]); + /// } + /// + /// assert_eq!(None, x.split_first_chunk::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_first_chunk(&self) -> Option<(&[T; N], &[T])> { + let Some((first, tail)) = self.split_at_checked(N) else { return None }; + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some((unsafe { &*(first.as_ptr().cast_array()) }, tail)) + } + + /// Returns a mutable array reference to the first `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_chunk_mut::<2>() { + /// first[0] = 3; + /// first[1] = 4; + /// elements[0] = 5; + /// } + /// assert_eq!(x, &[3, 4, 5]); + /// + /// assert_eq!(None, x.split_first_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_first_chunk_mut( + &mut self, + ) -> Option<(&mut [T; N], &mut [T])> { + let Some((first, tail)) = self.split_at_mut_checked(N) else { return None }; + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and enforce exclusive mutability of the chunk by the split. + Some((unsafe { &mut *(first.as_mut_ptr().cast_array()) }, tail)) + } + + /// Returns an array reference to the last `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((elements, last)) = x.split_last_chunk::<2>() { + /// assert_eq!(elements, &[0]); + /// assert_eq!(last, &[1, 2]); + /// } + /// + /// assert_eq!(None, x.split_last_chunk::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_last_chunk(&self) -> Option<(&[T], &[T; N])> { + let Some(index) = self.len().checked_sub(N) else { return None }; + let (init, last) = self.split_at(index); + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some((init, unsafe { &*(last.as_ptr().cast_array()) })) + } + + /// Returns a mutable array reference to the last `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((elements, last)) = x.split_last_chunk_mut::<2>() { + /// last[0] = 3; + /// last[1] = 4; + /// elements[0] = 5; + /// } + /// assert_eq!(x, &[5, 3, 4]); + /// + /// assert_eq!(None, x.split_last_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_last_chunk_mut( + &mut self, + ) -> Option<(&mut [T], &mut [T; N])> { + let Some(index) = self.len().checked_sub(N) else { return None }; + let (init, last) = self.split_at_mut(index); + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and enforce exclusive mutability of the chunk by the split. + Some((init, unsafe { &mut *(last.as_mut_ptr().cast_array()) })) + } + + /// Returns an array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let u = [10, 40, 30]; + /// assert_eq!(Some(&[40, 30]), u.last_chunk::<2>()); + /// + /// let v: &[i32] = &[10]; + /// assert_eq!(None, v.last_chunk::<2>()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(Some(&[]), w.last_chunk::<0>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_last_chunk", since = "1.80.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn last_chunk(&self) -> Option<&[T; N]> { + // FIXME(const-hack): Without const traits, we need this instead of `get`. + let Some(index) = self.len().checked_sub(N) else { return None }; + let (_, last) = self.split_at(index); + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some(unsafe { &*(last.as_ptr().cast_array()) }) + } + + /// Returns a mutable array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(last) = x.last_chunk_mut::<2>() { + /// last[0] = 10; + /// last[1] = 20; + /// } + /// assert_eq!(x, &[0, 10, 20]); + /// + /// assert_eq!(None, x.last_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn last_chunk_mut(&mut self) -> Option<&mut [T; N]> { + // FIXME(const-hack): Without const traits, we need this instead of `get`. + let Some(index) = self.len().checked_sub(N) else { return None }; + let (_, last) = self.split_at_mut(index); + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and require exclusive access to the entire slice to mutate the chunk. + Some(unsafe { &mut *(last.as_mut_ptr().cast_array()) }) + } + + /// Returns a reference to an element or subslice depending on the type of + /// index. + /// + /// - If given a position, returns a reference to the element at that + /// position or `None` if out of bounds. + /// - If given a range, returns the subslice corresponding to that range, + /// or `None` if out of bounds. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&40), v.get(1)); + /// assert_eq!(Some(&[10, 40][..]), v.get(0..2)); + /// assert_eq!(None, v.get(3)); + /// assert_eq!(None, v.get(0..4)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get(&self, index: I) -> Option<&I::Output> + where + I: [const] SliceIndex, + { + index.get(self) + } + + /// Returns a mutable reference to an element or subslice depending on the + /// type of index (see [`get`]) or `None` if the index is out of bounds. + /// + /// [`get`]: slice::get + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(elem) = x.get_mut(1) { + /// *elem = 42; + /// } + /// assert_eq!(x, &[0, 42, 2]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[rustc_no_writable] + pub const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where + I: [const] SliceIndex, + { + index.get_mut(self) + } + + /// Returns a reference to an element or subslice, without doing bounds + /// checking. + /// + /// For a safe alternative see [`get`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. + /// + /// You can think of this like `.get(index).unwrap_unchecked()`. It's UB + /// to call `.get_unchecked(len)`, even if you immediately convert to a + /// pointer. And it's UB to call `.get_unchecked(..len + 1)`, + /// `.get_unchecked(..=len)`, or similar. + /// + /// [`get`]: slice::get + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// + /// unsafe { + /// assert_eq!(x.get_unchecked(1), &2); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[track_caller] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, index)))] + pub const unsafe fn get_unchecked(&self, index: I) -> &I::Output + where + I: [const] SliceIndex, + { + // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`; + // the slice is dereferenceable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &*index.get_unchecked(self) } + } + + /// Returns a mutable reference to an element or subslice, without doing + /// bounds checking. + /// + /// For a safe alternative see [`get_mut`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. + /// + /// You can think of this like `.get_mut(index).unwrap_unchecked()`. It's + /// UB to call `.get_unchecked_mut(len)`, even if you immediately convert + /// to a pointer. And it's UB to call `.get_unchecked_mut(..len + 1)`, + /// `.get_unchecked_mut(..=len)`, or similar. + /// + /// [`get_mut`]: slice::get_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// + /// unsafe { + /// let elem = x.get_unchecked_mut(1); + /// *elem = 13; + /// } + /// assert_eq!(x, &[1, 13, 4]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[track_caller] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, index)))] + #[rustc_no_writable] + pub const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + where + I: [const] SliceIndex, + { + // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`; + // the slice is dereferenceable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &mut *index.get_unchecked_mut(self) } + } + + /// Returns a raw pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up dangling. + /// + /// The caller must also ensure that the memory the pointer (non-transitively) points to + /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer + /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`]. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let x_ptr = x.as_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// assert_eq!(x.get_unchecked(i), &*x_ptr.add(i)); + /// } + /// } + /// ``` + /// + /// [`as_mut_ptr`]: slice::as_mut_ptr + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] + #[rustc_never_returns_null_ptr] + #[rustc_as_ptr] + #[inline(always)] + #[must_use] + pub const fn as_ptr(&self) -> *const T { + self as *const [T] as *const T + } + + /// Returns an unsafe mutable pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up dangling. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// let x_ptr = x.as_mut_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// *x_ptr.add(i) += 2; + /// } + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[rustc_never_returns_null_ptr] + #[rustc_as_ptr] + #[inline(always)] + #[must_use] + #[rustc_no_writable] + pub const fn as_mut_ptr(&mut self) -> *mut T { + self as *mut [T] as *mut T + } + + /// Returns the two raw pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the slice. + /// + /// See [`as_ptr`] for warnings on using these pointers. The end pointer + /// requires extra caution, as it does not point to a valid element in the + /// slice. + /// + /// This function is useful for interacting with foreign interfaces which + /// use two pointers to refer to a range of elements in memory, as is + /// common in C++. + /// + /// It can also be useful to check if a pointer to an element refers to an + /// element of this slice: + /// + /// ``` + /// let a = [1, 2, 3]; + /// let x = &a[1] as *const _; + /// let y = &5 as *const _; + /// + /// assert!(a.as_ptr_range().contains(&x)); + /// assert!(!a.as_ptr_range().contains(&y)); + /// ``` + /// + /// [`as_ptr`]: slice::as_ptr + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[inline] + #[must_use] + pub const fn as_ptr_range(&self) -> Range<*const T> { + let start = self.as_ptr(); + // SAFETY: The `add` here is safe, because: + // + // - Both pointers are part of the same object, as pointing directly + // past the object also counts. + // + // - The size of the slice is never larger than `isize::MAX` bytes, as + // noted here: + // - https://github.com/rust-lang/unsafe-code-guidelines/issues/102#issuecomment-473340447 + // - https://doc.rust-lang.org/reference/behavior-considered-undefined.html + // - https://doc.rust-lang.org/core/slice/fn.from_raw_parts.html#safety + // (This doesn't seem normative yet, but the very same assumption is + // made in many places, including the Index implementation of slices.) + // + // - There is no wrapping around involved, as slices do not wrap past + // the end of the address space. + // + // See the documentation of [`pointer::add`]. + let end = unsafe { start.add(self.len()) }; + start..end + } + + /// Returns the two unsafe mutable pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the slice. + /// + /// See [`as_mut_ptr`] for warnings on using these pointers. The end + /// pointer requires extra caution, as it does not point to a valid element + /// in the slice. + /// + /// This function is useful for interacting with foreign interfaces which + /// use two pointers to refer to a range of elements in memory, as is + /// common in C++. + /// + /// [`as_mut_ptr`]: slice::as_mut_ptr + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[inline] + #[must_use] + pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> { + let start = self.as_mut_ptr(); + // SAFETY: See as_ptr_range() above for why `add` here is safe. + let end = unsafe { start.add(self.len()) }; + start..end + } + + /// Gets a reference to the underlying array. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] + #[inline] + #[must_use] + pub const fn as_array(&self) -> Option<&[T; N]> { + if self.len() == N { + let ptr = self.as_ptr().cast_array(); + + // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. + let me = unsafe { &*ptr }; + Some(me) + } else { + None + } + } + + /// Gets a mutable reference to the slice's underlying array. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] + #[inline] + #[must_use] + pub const fn as_mut_array(&mut self) -> Option<&mut [T; N]> { + if self.len() == N { + let ptr = self.as_mut_ptr().cast_array(); + + // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. + let me = unsafe { &mut *ptr }; + Some(me) + } else { + None + } + } + + /// Swaps two elements in the slice. + /// + /// If `a` equals `b`, it's guaranteed that elements won't change value. + /// + /// # Arguments + /// + /// * a - The index of the first element + /// * b - The index of the second element + /// + /// # Panics + /// + /// Panics if `a` or `b` are out of bounds. + /// + /// # Examples + /// + /// ``` + /// let mut v = ["a", "b", "c", "d", "e"]; + /// v.swap(2, 4); + /// assert!(v == ["a", "b", "e", "d", "c"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_swap", since = "1.85.0")] + #[inline] + #[track_caller] + pub const fn swap(&mut self, a: usize, b: usize) { + // Bounds checks that panic exactly like indexing would. + let _ = &self[a]; + let _ = &self[b]; + // SAFETY: `a` and `b` were checked to be in bounds above. + unsafe { + self.swap_unchecked(a, b); + } + } + + /// Swaps two elements in the slice, without doing bounds checking. + /// + /// For a safe alternative see [`swap`]. + /// + /// # Arguments + /// + /// * a - The index of the first element + /// * b - The index of the second element + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]*. + /// The caller has to ensure that `a < self.len()` and `b < self.len()`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_swap_unchecked)] + /// + /// let mut v = ["a", "b", "c", "d"]; + /// // SAFETY: we know that 1 and 3 are both indices of the slice + /// unsafe { v.swap_unchecked(1, 3) }; + /// assert!(v == ["a", "d", "c", "b"]); + /// ``` + /// + /// [`swap`]: slice::swap + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_swap_unchecked", issue = "88539")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(a, "[0,self.len())")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(b, "[0,self.len())")))] + pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { + assert_unsafe_precondition!( + check_library_ub, + "slice::swap_unchecked requires that the indices are within the slice", + ( + len: usize = self.len(), + a: usize = a, + b: usize = b, + ) => a < len && b < len, + ); + + let ptr = self.as_mut_ptr(); + // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()` + unsafe { + ptr::swap(ptr.add(a), ptr.add(b)); + } + } + + /// Reverses the order of elements in the slice, in place. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 2, 3]; + /// v.reverse(); + /// assert!(v == [3, 2, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_reverse", since = "1.90.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub const fn reverse(&mut self) { + let half_len = self.len() / 2; + let Range { start, end } = self.as_mut_ptr_range(); + + // These slices will skip the middle item for an odd length, + // since that one doesn't need to move. + let (front_half, back_half) = + // SAFETY: Both are subparts of the original slice, so the memory + // range is valid, and they don't overlap because they're each only + // half (or less) of the original slice. + unsafe { + ( + slice::from_raw_parts_mut(start, half_len), + slice::from_raw_parts_mut(end.sub(half_len), half_len), + ) + }; + + // Introducing a function boundary here means that the two halves + // get `noalias` markers, allowing better optimization as LLVM + // knows that they're disjoint, unlike in the original slice. + revswap(front_half, back_half, half_len); + + #[inline] + const fn revswap(a: &mut [T], b: &mut [T], n: usize) { + debug_assert!(a.len() == n); + debug_assert!(b.len() == n); + + // Because this function is first compiled in isolation, + // this check tells LLVM that the indexing below is + // in-bounds. Then after inlining -- once the actual + // lengths of the slices are known -- it's removed. + // FIXME(const_trait_impl) replace with let (a, b) = (&mut a[..n], &mut b[..n]); + let (a, _) = a.split_at_mut(n); + let (b, _) = b.split_at_mut(n); + + let mut i = 0; + #[safety::loop_invariant(i <= n)] + #[cfg_attr(kani, + kani::loop_modifies( + unsafe {slice::from_raw_parts_mut(a.as_mut_ptr(), n)}, + unsafe {slice::from_raw_parts_mut(b.as_mut_ptr(), n)}, + &i) + )] + while i < n { + mem::swap(&mut a[i], &mut b[n - 1 - i]); + i += 1; + } + } + } + + /// Returns an iterator over the slice. + /// + /// The iterator yields all items from start to end. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let mut iterator = x.iter(); + /// + /// assert_eq!(iterator.next(), Some(&1)); + /// assert_eq!(iterator.next(), Some(&2)); + /// assert_eq!(iterator.next(), Some(&4)); + /// assert_eq!(iterator.next(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[rustc_diagnostic_item = "slice_iter"] + pub const fn iter(&self) -> Iter<'_, T> { + Iter::new(self) + } + + /// Returns an iterator that allows modifying each value. + /// + /// The iterator yields all items from start to end. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// for elem in x.iter_mut() { + /// *elem += 2; + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut::new(self) + } + + /// Returns an iterator over all contiguous windows of length + /// `size`. The windows overlap. If the slice is shorter than + /// `size`, the iterator returns no values. + /// + /// # Panics + /// + /// Panics if `size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.windows(3); + /// assert_eq!(iter.next().unwrap(), &['l', 'o', 'r']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e', 'm']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the slice is shorter than `size`: + /// + /// ``` + /// let slice = ['f', 'o', 'o']; + /// let mut iter = slice.windows(4); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// Because the [Iterator] trait cannot represent the required lifetimes, + /// there is no `windows_mut` analog to `windows`; + /// `[0,1,2].windows_mut(2).collect()` would violate [the rules of references] + /// (though a [LendingIterator] analog is possible). You can sometimes use + /// [`Cell::as_slice_of_cells`](crate::cell::Cell::as_slice_of_cells) in + /// conjunction with `windows` instead: + /// + /// [the rules of references]: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references + /// [LendingIterator]: https://blog.rust-lang.org/2022/10/28/gats-stabilization.html + /// ``` + /// use std::cell::Cell; + /// + /// let mut array = ['R', 'u', 's', 't', ' ', '2', '0', '1', '5']; + /// let slice = &mut array[..]; + /// let slice_of_cells: &[Cell] = Cell::from_mut(slice).as_slice_of_cells(); + /// for w in slice_of_cells.windows(3) { + /// Cell::swap(&w[0], &w[2]); + /// } + /// assert_eq!(array, ['s', 't', ' ', '2', '0', '1', '5', 'u', 'R']); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn windows(&self, size: usize) -> Windows<'_, T> { + let size = NonZero::new(size).expect("window size must be non-zero"); + Windows::new(self, size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`chunks_exact`] for a variant of this iterator that returns chunks of always exactly + /// `chunk_size` elements, and [`rchunks`] for the same iterator but starting at the end of the + /// slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['m']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`chunks_exact`]: slice::chunks_exact + /// [`rchunks`]: slice::rchunks + /// [`as_chunks`]: slice::as_chunks + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + Chunks::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`chunks_exact_mut`] for a variant of this iterator that returns chunks of always + /// exactly `chunk_size` elements, and [`rchunks_mut`] for the same iterator but starting at + /// the end of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.chunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 3]); + /// ``` + /// + /// [`chunks_exact_mut`]: slice::chunks_exact_mut + /// [`rchunks_mut`]: slice::rchunks_mut + /// [`as_chunks_mut`]: slice::as_chunks_mut + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksMut::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved + /// from the `remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks`]. + /// + /// See [`chunks`] for a variant of this iterator that also returns the remainder as a smaller + /// chunk, and [`rchunks_exact`] for the same iterator but starting at the end of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks_exact(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert!(iter.next().is_none()); + /// assert_eq!(iter.remainder(), &['m']); + /// ``` + /// + /// [`chunks`]: slice::chunks + /// [`rchunks_exact`]: slice::rchunks_exact + /// [`as_chunks`]: slice::as_chunks + #[stable(feature = "chunks_exact", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksExact::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be + /// retrieved from the `into_remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks_mut`]. + /// + /// See [`chunks_mut`] for a variant of this iterator that also returns the remainder as a + /// smaller chunk, and [`rchunks_exact_mut`] for the same iterator but starting at the end of + /// the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.chunks_exact_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 0]); + /// ``` + /// + /// [`chunks_mut`]: slice::chunks_mut + /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut + /// [`as_chunks_mut`]: slice::as_chunks_mut + #[stable(feature = "chunks_exact", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksExactMut::new(self, chunk_size) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// assuming that there's no remainder. + /// + /// This is the inverse operation to [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// As this is `unsafe`, consider whether you could use [`as_chunks`] or + /// [`as_rchunks`] instead, perhaps via something like + /// `if let (chunks, []) = slice.as_chunks()` or + /// `let (chunks, []) = slice.as_chunks() else { unreachable!() };`. + /// + /// [`as_chunks`]: slice::as_chunks + /// [`as_rchunks`]: slice::as_rchunks + /// + /// # Safety + /// + /// This may only be called when + /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). + /// - `N != 0`. + /// + /// # Examples + /// + /// ``` + /// let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!']; + /// let chunks: &[[char; 1]] = + /// // SAFETY: 1-element chunks never have remainder + /// unsafe { slice.as_chunks_unchecked() }; + /// assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]); + /// let chunks: &[[char; 3]] = + /// // SAFETY: The slice length (6) is a multiple of 3 + /// unsafe { slice.as_chunks_unchecked() }; + /// assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]); + /// + /// // These would be unsound: + /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5 + /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(N, "[1,)")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(len(self) % N == 0)))] + // Safety precondition from the documentation: `N != 0` and the length is a multiple of `N`. + #[requires(N != 0 && self.len().is_multiple_of(N))] + #[ensures(|chunks: &&[[T; N]]| chunks.len() == self.len() / N && chunks.as_ptr() as *const T == self.as_ptr())] + pub const unsafe fn as_chunks_unchecked<#[rustc_panics_when_zero] const N: usize>( + &self, + ) -> &[[T; N]] { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n), + ); + // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length + let new_len = unsafe { exact_div(self.len(), N) }; + // SAFETY: We cast a slice of `new_len * N` elements into + // a slice of `new_len` many `N` elements chunks. + unsafe { from_raw_parts(self.as_ptr().cast(), new_len) } + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the beginning of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (chunks, remainder) = slice.as_chunks()`, then: + /// - `chunks.len()` equals `slice.len() / N`, + /// - `remainder.len()` equals `slice.len() % N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let (chunks, remainder) = slice.as_chunks(); + /// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]); + /// assert_eq!(remainder, &['m']); + /// ``` + /// + /// If you expect the slice to be an exact multiple, you can combine + /// `let`-`else` with an empty slice pattern: + /// ``` + /// let slice = ['R', 'u', 's', 't']; + /// let (chunks, []) = slice.as_chunks::<2>() else { + /// panic!("slice didn't have even length") + /// }; + /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_chunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[[T; N]], &[T]) { + assert!(N != 0, "chunk size must be non-zero"); + let len_rounded_down = self.len() / N * N; + // SAFETY: The rounded-down value is always the same or smaller than the + // original length, and thus must be in-bounds of the slice. + let (multiple_of_n, remainder) = unsafe { self.split_at_unchecked(len_rounded_down) }; + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() }; + (array_slice, remainder) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the end of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (remainder, chunks) = slice.as_rchunks()`, then: + /// - `remainder.len()` equals `slice.len() % N`, + /// - `chunks.len()` equals `slice.len() / N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let (remainder, chunks) = slice.as_rchunks(); + /// assert_eq!(remainder, &['l']); + /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_rchunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[T], &[[T; N]]) { + assert!(N != 0, "chunk size must be non-zero"); + let len = self.len() / N; + let (remainder, multiple_of_n) = self.split_at(self.len() - len * N); + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() }; + (remainder, array_slice) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// assuming that there's no remainder. + /// + /// This is the inverse operation to [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// As this is `unsafe`, consider whether you could use [`as_chunks_mut`] or + /// [`as_rchunks_mut`] instead, perhaps via something like + /// `if let (chunks, []) = slice.as_chunks_mut()` or + /// `let (chunks, []) = slice.as_chunks_mut() else { unreachable!() };`. + /// + /// [`as_chunks_mut`]: slice::as_chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + /// + /// # Safety + /// + /// This may only be called when + /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). + /// - `N != 0`. + /// + /// # Examples + /// + /// ``` + /// let slice: &mut [char] = &mut ['l', 'o', 'r', 'e', 'm', '!']; + /// let chunks: &mut [[char; 1]] = + /// // SAFETY: 1-element chunks never have remainder + /// unsafe { slice.as_chunks_unchecked_mut() }; + /// chunks[0] = ['L']; + /// assert_eq!(chunks, &[['L'], ['o'], ['r'], ['e'], ['m'], ['!']]); + /// let chunks: &mut [[char; 3]] = + /// // SAFETY: The slice length (6) is a multiple of 3 + /// unsafe { slice.as_chunks_unchecked_mut() }; + /// chunks[1] = ['a', 'x', '?']; + /// assert_eq!(slice, &['L', 'o', 'r', 'a', 'x', '?']); + /// + /// // These would be unsound: + /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_mut() // The slice length is not a multiple of 5 + /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(N, "[1,)")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(len(self) % N == 0)))] + // Safety precondition from the documentation: `N != 0` and the length is a multiple of `N`. + #[requires(N != 0 && self.len().is_multiple_of(N))] + #[ensures(|chunks: &&mut [[T; N]]| chunks.len() == old(self.len()) / N)] + pub const unsafe fn as_chunks_unchecked_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> &mut [[T; N]] { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n) + ); + // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length + let new_len = unsafe { exact_div(self.len(), N) }; + // SAFETY: We cast a slice of `new_len * N` elements into + // a slice of `new_len` many `N` elements chunks. + unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), new_len) } + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the beginning of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (chunks, remainder) = slice.as_chunks_mut()`, then: + /// - `chunks.len()` equals `slice.len() / N`, + /// - `remainder.len()` equals `slice.len() % N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// let (chunks, remainder) = v.as_chunks_mut(); + /// remainder[0] = 9; + /// for chunk in chunks { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 9]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_chunks_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> (&mut [[T; N]], &mut [T]) { + assert!(N != 0, "chunk size must be non-zero"); + let len_rounded_down = self.len() / N * N; + // SAFETY: The rounded-down value is always the same or smaller than the + // original length, and thus must be in-bounds of the slice. + let (multiple_of_n, remainder) = unsafe { self.split_at_mut_unchecked(len_rounded_down) }; + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() }; + (array_slice, remainder) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the end of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (remainder, chunks) = slice.as_rchunks_mut()`, then: + /// - `remainder.len()` equals `slice.len() % N`, + /// - `chunks.len()` equals `slice.len() / N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// let (remainder, chunks) = v.as_rchunks_mut(); + /// remainder[0] = 9; + /// for chunk in chunks { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[9, 1, 1, 2, 2]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + pub const fn as_rchunks_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> (&mut [T], &mut [[T; N]]) { + assert!(N != 0, "chunk size must be non-zero"); + let len = self.len() / N; + let (remainder, multiple_of_n) = self.split_at_mut(self.len() - len * N); + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() }; + (remainder, array_slice) + } + + /// Returns an iterator over overlapping windows of `N` elements of a slice, + /// starting at the beginning of the slice. + /// + /// This is the const generic equivalent of [`windows`]. + /// + /// If `N` is greater than the size of the slice, it will return no windows. + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = [0, 1, 2, 3]; + /// let mut iter = slice.array_windows(); + /// assert_eq!(iter.next().unwrap(), &[0, 1]); + /// assert_eq!(iter.next().unwrap(), &[1, 2]); + /// assert_eq!(iter.next().unwrap(), &[2, 3]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`windows`]: slice::windows + #[stable(feature = "array_windows", since = "1.94.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn array_windows<#[rustc_panics_when_zero] const N: usize>( + &self, + ) -> ArrayWindows<'_, T, N> { + assert!(N != 0, "window size must be non-zero"); + ArrayWindows::new(self) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`rchunks_exact`] for a variant of this iterator that returns chunks of always exactly + /// `chunk_size` elements, and [`chunks`] for the same iterator but starting at the beginning + /// of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.rchunks(2); + /// assert_eq!(iter.next().unwrap(), &['e', 'm']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r']); + /// assert_eq!(iter.next().unwrap(), &['l']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`rchunks_exact`]: slice::rchunks_exact + /// [`chunks`]: slice::chunks + /// [`as_rchunks`]: slice::as_rchunks + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunks::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`rchunks_exact_mut`] for a variant of this iterator that returns chunks of always + /// exactly `chunk_size` elements, and [`chunks_mut`] for the same iterator but starting at the + /// beginning of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.rchunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[3, 2, 2, 1, 1]); + /// ``` + /// + /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut + /// [`chunks_mut`]: slice::chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksMut::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// end of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved + /// from the `remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`rchunks`]. + /// + /// See [`rchunks`] for a variant of this iterator that also returns the remainder as a smaller + /// chunk, and [`chunks_exact`] for the same iterator but starting at the beginning of the + /// slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.rchunks_exact(2); + /// assert_eq!(iter.next().unwrap(), &['e', 'm']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r']); + /// assert!(iter.next().is_none()); + /// assert_eq!(iter.remainder(), &['l']); + /// ``` + /// + /// [`chunks`]: slice::chunks + /// [`rchunks`]: slice::rchunks + /// [`chunks_exact`]: slice::chunks_exact + /// [`as_rchunks`]: slice::as_rchunks + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksExact::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be + /// retrieved from the `into_remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks_mut`]. + /// + /// See [`rchunks_mut`] for a variant of this iterator that also returns the remainder as a + /// smaller chunk, and [`chunks_exact_mut`] for the same iterator but starting at the beginning + /// of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.rchunks_exact_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[0, 2, 2, 1, 1]); + /// ``` + /// + /// [`chunks_mut`]: slice::chunks_mut + /// [`rchunks_mut`]: slice::rchunks_mut + /// [`chunks_exact_mut`]: slice::chunks_exact_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksExactMut::new(self, chunk_size) + } + + /// Returns an iterator over the slice producing non-overlapping runs + /// of elements using the predicate to separate them. + /// + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. + /// + /// # Examples + /// + /// ``` + /// let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; + /// + /// let mut iter = slice.chunk_by(|a, b| a == b); + /// + /// assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + /// assert_eq!(iter.next(), Some(&[3, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// This method can be used to extract the sorted subslices: + /// + /// ``` + /// let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4]; + /// + /// let mut iter = slice.chunk_by(|a, b| a <= b); + /// + /// assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 3, 4][..])); + /// assert_eq!(iter.next(), None); + /// ``` + #[stable(feature = "slice_group_by", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + pub const fn chunk_by(&self, pred: F) -> ChunkBy<'_, T, F> + where + F: FnMut(&T, &T) -> bool, + { + ChunkBy::new(self, pred) + } + + /// Returns an iterator over the slice producing non-overlapping mutable + /// runs of elements using the predicate to separate them. + /// + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. + /// + /// # Examples + /// + /// ``` + /// let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; + /// + /// let mut iter = slice.chunk_by_mut(|a, b| a == b); + /// + /// assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); + /// assert_eq!(iter.next(), Some(&mut [3, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// This method can be used to extract the sorted subslices: + /// + /// ``` + /// let slice = &mut [1, 1, 2, 3, 2, 3, 2, 3, 4]; + /// + /// let mut iter = slice.chunk_by_mut(|a, b| a <= b); + /// + /// assert_eq!(iter.next(), Some(&mut [1, 1, 2, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 3, 4][..])); + /// assert_eq!(iter.next(), None); + /// ``` + #[stable(feature = "slice_group_by", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + pub const fn chunk_by_mut(&mut self, pred: F) -> ChunkByMut<'_, T, F> + where + F: FnMut(&T, &T) -> bool, + { + ChunkByMut::new(self, pred) + } + + /// Divides one slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. For a non-panicking alternative see + /// [`split_at_checked`](slice::split_at_checked). + /// + /// # Examples + /// + /// ``` + /// let v = ['a', 'b', 'c']; + /// + /// { + /// let (left, right) = v.split_at(0); + /// assert_eq!(left, []); + /// assert_eq!(right, ['a', 'b', 'c']); + /// } + /// + /// { + /// let (left, right) = v.split_at(2); + /// assert_eq!(left, ['a', 'b']); + /// assert_eq!(right, ['c']); + /// } + /// + /// { + /// let (left, right) = v.split_at(3); + /// assert_eq!(left, ['a', 'b', 'c']); + /// assert_eq!(right, []); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "1.71.0")] + #[inline] + #[track_caller] + #[must_use] + pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) { + match self.split_at_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), + } + } + + /// Divides one mutable slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. For a non-panicking alternative see + /// [`split_at_mut_checked`](slice::split_at_mut_checked). + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// let (left, right) = v.split_at_mut(2); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[track_caller] + #[must_use] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + match self.split_at_mut_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), + } + } + + /// Divides one slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at`]: slice::split_at + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let v = ['a', 'b', 'c']; + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(0); + /// assert_eq!(left, []); + /// assert_eq!(right, ['a', 'b', 'c']); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(2); + /// assert_eq!(left, ['a', 'b']); + /// assert_eq!(right, ['c']); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(3); + /// assert_eq!(left, ['a', 'b', 'c']); + /// assert_eq!(right, []); + /// } + /// ``` + #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_split_at_unchecked", since = "1.77.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(mid, [0,self.len()])))] + pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + // FIXME(const-hack): the const function `from_raw_parts` is used to make this + // function const; previously the implementation used + // `(self.get_unchecked(..mid), self.get_unchecked(mid..))` + + let len = self.len(); + let ptr = self.as_ptr(); + + assert_unsafe_precondition!( + check_library_ub, + "slice::split_at_unchecked requires the index to be within the slice", + (mid: usize = mid, len: usize = len) => mid <= len, + ); + + // SAFETY: Caller has to check that `0 <= mid <= self.len()` + unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), unchecked_sub(len, mid))) } + } + + /// Divides one mutable slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at_mut`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at_mut`]: slice::split_at_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// // scoped to restrict the lifetime of the borrows + /// unsafe { + /// let (left, right) = v.split_at_mut_unchecked(2); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(mid, [0,self.len()])))] + pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + let len = self.len(); + let ptr = self.as_mut_ptr(); + + assert_unsafe_precondition!( + check_library_ub, + "slice::split_at_mut_unchecked requires the index to be within the slice", + (mid: usize = mid, len: usize = len) => mid <= len, + ); + + // SAFETY: Caller has to check that `0 <= mid <= self.len()`. + // + // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference + // is fine. + unsafe { + ( + from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.add(mid), unchecked_sub(len, mid)), + ) + } + } + + /// Divides one slice into two at an index, returning `None` if the slice is + /// too short. + /// + /// If `mid ≤ len`, returns a pair of slices where the first will contain all + /// indices from `[0, mid)` (excluding the index `mid` itself) and the + /// second will contain all indices from `[mid, len)` (excluding the index + /// `len` itself). + /// + /// Otherwise, if `mid > len`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = [1, -2, 3, -4, 5, -6]; + /// + /// { + /// let (left, right) = v.split_at_checked(0).unwrap(); + /// assert_eq!(left, []); + /// assert_eq!(right, [1, -2, 3, -4, 5, -6]); + /// } + /// + /// { + /// let (left, right) = v.split_at_checked(2).unwrap(); + /// assert_eq!(left, [1, -2]); + /// assert_eq!(right, [3, -4, 5, -6]); + /// } + /// + /// { + /// let (left, right) = v.split_at_checked(6).unwrap(); + /// assert_eq!(left, [1, -2, 3, -4, 5, -6]); + /// assert_eq!(right, []); + /// } + /// + /// assert_eq!(None, v.split_at_checked(7)); + /// ``` + #[stable(feature = "split_at_checked", since = "1.80.0")] + #[rustc_const_stable(feature = "split_at_checked", since = "1.80.0")] + #[inline] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])> { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. + Some(unsafe { self.split_at_unchecked(mid) }) + } else { + None + } + } + + /// Divides one mutable slice into two at an index, returning `None` if the + /// slice is too short. + /// + /// If `mid ≤ len`, returns a pair of slices where the first will contain all + /// indices from `[0, mid)` (excluding the index `mid` itself) and the + /// second will contain all indices from `[mid, len)` (excluding the index + /// `len` itself). + /// + /// Otherwise, if `mid > len`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// + /// if let Some((left, right)) = v.split_at_mut_checked(2) { + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// + /// assert_eq!(None, v.split_at_mut_checked(7)); + /// ``` + #[stable(feature = "split_at_checked", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + #[inline] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. + Some(unsafe { self.split_at_mut_unchecked(mid) }) + } else { + None + } + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the first element is matched, an empty slice will be the first item + /// returned by the iterator. Similarly, if the last element in the slice + /// is matched, an empty slice will be the last item returned by the + /// iterator: + /// + /// ``` + /// let slice = [10, 40, 33]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If two matched elements are directly adjacent, an empty slice will be + /// present between them: + /// + /// ``` + /// let slice = [10, 6, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split(&self, pred: F) -> Split<'_, T, F> + where + F: FnMut(&T) -> bool, + { + Split::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_mut(|num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_mut(&mut self, pred: F) -> SplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is contained in the end of the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the last element of the slice is matched, + /// that element will be considered the terminator of the preceding slice. + /// That slice will be the last item returned by the iterator. + /// + /// ``` + /// let slice = [3, 10, 40, 33]; + /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[3]); + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[inline] + pub fn split_inclusive(&self, pred: F) -> SplitInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitInclusive::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is contained in the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_inclusive_mut(|num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; + /// } + /// assert_eq!(v, [10, 40, 1, 20, 1, 1]); + /// ``` + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[inline] + pub fn split_inclusive_mut(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitInclusiveMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, starting at the end of the slice and working backwards. + /// The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let mut iter = slice.rsplit(|num| *num == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[44, 55]); + /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// As with `split()`, if the first or last element is matched, an empty + /// slice will be the first (or last) item returned by the iterator. + /// + /// ``` + /// let v = &[0, 1, 1, 2, 3, 5, 8]; + /// let mut it = v.rsplit(|n| *n % 2 == 0); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next().unwrap(), &[3, 5]); + /// assert_eq!(it.next().unwrap(), &[1, 1]); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next(), None); + /// ``` + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplit::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, starting at the end of the slice and working + /// backwards. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [100, 400, 300, 200, 600, 500]; + /// + /// let mut count = 0; + /// for group in v.rsplit_mut(|num| *num % 3 == 0) { + /// count += 1; + /// group[0] = count; + /// } + /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); + /// ``` + /// + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once by numbers divisible by 3 (i.e., `[10, 40]`, + /// `[20, 60, 50]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn(2, |num| *num % 3 == 0) { + /// println!("{group:?}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn(&self, n: usize, pred: F) -> SplitN<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitN::new(self.split(pred), n) + } + + /// Returns an iterator over mutable subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 50]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitNMut::new(self.split_mut(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once, starting from the end, by numbers divisible + /// by 3 (i.e., `[50]`, `[10, 40, 30, 20]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplitn(2, |num| *num % 3 == 0) { + /// println!("{group:?}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitN::new(self.rsplit(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut s = [10, 40, 30, 20, 60, 50]; + /// + /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(s, [1, 40, 30, 20, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitNMut::new(self.rsplit_mut(pred), n) + } + + /// Splits the slice on the first element that matches the specified + /// predicate. + /// + /// If any matching elements are present in the slice, returns the prefix + /// before the match and suffix after. The matching element itself is not + /// included. If no elements match, returns `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_split_once)] + /// let s = [1, 2, 3, 2, 4]; + /// assert_eq!(s.split_once(|&x| x == 2), Some(( + /// &[1][..], + /// &[3, 2, 4][..] + /// ))); + /// assert_eq!(s.split_once(|&x| x == 0), None); + /// ``` + #[unstable(feature = "slice_split_once", issue = "112811")] + #[inline] + pub fn split_once(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { + let index = self.iter().position(pred)?; + // Slice bounds checks optimized are away (as of June 2026) + Some((&self[..index], &self[index + 1..])) + } + + /// Splits the slice on the last element that matches the specified + /// predicate. + /// + /// If any matching elements are present in the slice, returns the prefix + /// before the match and suffix after. The matching element itself is not + /// included. If no elements match, returns `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_split_once)] + /// let s = [1, 2, 3, 2, 4]; + /// assert_eq!(s.rsplit_once(|&x| x == 2), Some(( + /// &[1, 2, 3][..], + /// &[4][..] + /// ))); + /// assert_eq!(s.rsplit_once(|&x| x == 0), None); + /// ``` + #[unstable(feature = "slice_split_once", issue = "112811")] + #[inline] + pub fn rsplit_once(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { + let index = self.iter().rposition(pred)?; + // Slice bounds checks optimized are away (as of June 2026) + Some((&self[..index], &self[index + 1..])) + } + + /// Returns `true` if the slice contains an element with the given value. + /// + /// This operation is *O*(*n*). + /// + /// Note that if you have a sorted slice, [`binary_search`] may be faster. + /// + /// [`binary_search`]: slice::binary_search + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.contains(&30)); + /// assert!(!v.contains(&50)); + /// ``` + /// + /// If you do not have a `&T`, but some other value that you can compare + /// with one (for example, `String` implements `PartialEq`), you can + /// use `iter().any`: + /// + /// ``` + /// let v = [String::from("hello"), String::from("world")]; // slice of `String` + /// assert!(v.iter().any(|e| e == "hello")); // search with `&str` + /// assert!(!v.iter().any(|e| e == "hi")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[must_use] + pub fn contains(&self, x: &T) -> bool + where + T: PartialEq, + { + cmp::SliceContains::slice_contains(x, self) + } + + /// Returns `true` if `needle` is a prefix of the slice or equal to the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.starts_with(&[10])); + /// assert!(v.starts_with(&[10, 40])); + /// assert!(v.starts_with(&v)); + /// assert!(!v.starts_with(&[50])); + /// assert!(!v.starts_with(&[10, 50])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.starts_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.starts_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + pub fn starts_with(&self, needle: &[T]) -> bool + where + T: PartialEq, + { + let n = needle.len(); + self.len() >= n && needle == &self[..n] + } + + /// Returns `true` if `needle` is a suffix of the slice or equal to the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.ends_with(&[30])); + /// assert!(v.ends_with(&[40, 30])); + /// assert!(v.ends_with(&v)); + /// assert!(!v.ends_with(&[50])); + /// assert!(!v.ends_with(&[50, 30])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.ends_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.ends_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + pub fn ends_with(&self, needle: &[T]) -> bool + where + T: PartialEq, + { + let (m, n) = (self.len(), needle.len()); + m >= n && needle == &self[m - n..] + } + + /// Returns a subslice with the prefix removed. + /// + /// If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`. + /// If `prefix` is empty, simply returns the original slice. If `prefix` is equal to the + /// original slice, returns an empty slice. + /// + /// If the slice does not start with `prefix`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..])); + /// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..])); + /// assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_prefix(&[50]), None); + /// assert_eq!(v.strip_prefix(&[10, 50]), None); + /// + /// let prefix : &str = "he"; + /// assert_eq!(b"hello".strip_prefix(prefix.as_bytes()), + /// Some(b"llo".as_ref())); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "slice_strip", since = "1.51.0")] + pub fn strip_prefix + ?Sized>(&self, prefix: &P) -> Option<&[T]> + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let prefix = prefix.as_slice(); + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return Some(tail); + } + } + None + } + + /// Returns a subslice with the suffix removed. + /// + /// If the slice ends with `suffix`, returns the subslice before the suffix, wrapped in `Some`. + /// If `suffix` is empty, simply returns the original slice. If `suffix` is equal to the + /// original slice, returns an empty slice. + /// + /// If the slice does not end with `suffix`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..])); + /// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..])); + /// assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_suffix(&[50]), None); + /// assert_eq!(v.strip_suffix(&[50, 30]), None); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "slice_strip", since = "1.51.0")] + pub fn strip_suffix + ?Sized>(&self, suffix: &P) -> Option<&[T]> + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let suffix = suffix.as_slice(); + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return Some(head); + } + } + None + } + + /// Returns a subslice with the prefix and suffix removed. + /// + /// If the slice starts with `prefix`, ends with `suffix`, and + /// the prefix and suffix don't overlap, returns the subslice after + /// the prefix and before the suffix, wrapped in `Some`. + /// + /// If the slice does not start with `prefix`, does not end with `suffix`, + /// or the prefix and suffix overlap in the slice, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 50, 40, 30]; + /// assert_eq!(v.strip_circumfix(&[10], &[30]), Some(&[50, 40][..])); + /// assert_eq!(v.strip_circumfix(&[10], &[40, 30]), Some(&[50][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50], &[40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_circumfix(&[50], &[30]), None); + /// assert_eq!(v.strip_circumfix(&[10], &[40]), None); + /// assert_eq!(v.strip_circumfix(&[], &[40, 30]), Some(&[10, 50][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50], &[]), Some(&[40, 30][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50, 40], &[50, 40, 30]), None); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "strip_circumfix", since = "1.98.0")] + pub fn strip_circumfix(&self, prefix: &P, suffix: &S) -> Option<&[T]> + where + T: PartialEq, + S: SlicePattern + ?Sized, + P: SlicePattern + ?Sized, + { + self.strip_prefix(prefix)?.strip_suffix(suffix) + } + + /// Returns a subslice with the optional prefix removed. + /// + /// If the slice starts with `prefix`, returns the subslice after the prefix. If `prefix` + /// is empty or the slice does not start with `prefix`, simply returns the original slice. + /// If `prefix` is equal to the original slice, returns an empty slice. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// + /// // Prefix present - removes it + /// assert_eq!(v.trim_prefix(&[10]), &[40, 30][..]); + /// assert_eq!(v.trim_prefix(&[10, 40]), &[30][..]); + /// assert_eq!(v.trim_prefix(&[10, 40, 30]), &[][..]); + /// + /// // Prefix absent - returns original slice + /// assert_eq!(v.trim_prefix(&[50]), &[10, 40, 30][..]); + /// assert_eq!(v.trim_prefix(&[10, 50]), &[10, 40, 30][..]); + /// + /// let prefix : &str = "he"; + /// assert_eq!(b"hello".trim_prefix(prefix.as_bytes()), b"llo".as_ref()); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "trim_prefix_suffix", since = "1.100.0")] + pub fn trim_prefix + ?Sized>(&self, prefix: &P) -> &[T] + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let prefix = prefix.as_slice(); + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return tail; + } + } + self + } + + /// Returns a subslice with the optional suffix removed. + /// + /// If the slice ends with `suffix`, returns the subslice before the suffix. If `suffix` + /// is empty or the slice does not end with `suffix`, simply returns the original slice. + /// If `suffix` is equal to the original slice, returns an empty slice. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// + /// // Suffix present - removes it + /// assert_eq!(v.trim_suffix(&[30]), &[10, 40][..]); + /// assert_eq!(v.trim_suffix(&[40, 30]), &[10][..]); + /// assert_eq!(v.trim_suffix(&[10, 40, 30]), &[][..]); + /// + /// // Suffix absent - returns original slice + /// assert_eq!(v.trim_suffix(&[50]), &[10, 40, 30][..]); + /// assert_eq!(v.trim_suffix(&[50, 30]), &[10, 40, 30][..]); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "trim_prefix_suffix", since = "1.100.0")] + pub fn trim_suffix + ?Sized>(&self, suffix: &P) -> &[T] + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let suffix = suffix.as_slice(); + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return head; + } + } + self + } + + /// Binary searches this slice for a given element. + /// If the slice is not sorted, the returned result is unspecified and + /// meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`]. + /// + /// [`binary_search_by`]: slice::binary_search_by + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// assert_eq!(s.binary_search(&13), Ok(9)); + /// assert_eq!(s.binary_search(&4), Err(7)); + /// assert_eq!(s.binary_search(&100), Err(13)); + /// let r = s.binary_search(&1); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + /// + /// If you want to find that whole *range* of matching items, rather than + /// an arbitrary matching one, that can be done using [`partition_point`]: + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// let low = s.partition_point(|x| x < &1); + /// assert_eq!(low, 1); + /// let high = s.partition_point(|x| x <= &1); + /// assert_eq!(high, 5); + /// let r = s.binary_search(&1); + /// assert!((low..high).contains(&r.unwrap())); + /// + /// assert!(s[..low].iter().all(|&x| x < 1)); + /// assert!(s[low..high].iter().all(|&x| x == 1)); + /// assert!(s[high..].iter().all(|&x| x > 1)); + /// + /// // For something not found, the "range" of equal items is empty + /// assert_eq!(s.partition_point(|x| x < &11), 9); + /// assert_eq!(s.partition_point(|x| x <= &11), 9); + /// assert_eq!(s.binary_search(&11), Err(9)); + /// ``` + /// + /// If you want to insert an item to a sorted vector, while maintaining + /// sort order, consider using [`partition_point`]: + /// + /// ``` + /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let num = 42; + /// let idx = s.partition_point(|&x| x <= num); + /// // If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to + /// // `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` will allow `insert` + /// // to shift less elements. + /// s.insert(idx, num); + /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "rust1", since = "1.0.0")] + pub const fn binary_search(&self, x: &T) -> Result + where + T: [const] Ord, + { + self.binary_search_by(const |p| p.cmp(x)) + } + + /// Binary searches this slice with a comparator function. + /// + /// The comparator function should return an order code that indicates + /// whether its argument is `Less`, `Equal` or `Greater` the desired + /// target. + /// If the slice is not sorted or if the comparator function does not + /// implement an order consistent with the sort order of the underlying + /// slice, the returned result is unspecified and meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`]. + /// + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// let seek = 13; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9)); + /// let seek = 4; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7)); + /// let seek = 100; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); + /// let seek = 1; + /// let r = s.binary_search_by(|probe| probe.cmp(&seek)); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub const fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result + where + F: [const] FnMut(&'a T) -> Ordering + [const] Destruct, + { + let mut size = self.len(); + if size == 0 { + return Err(0); + } + let mut base = 0usize; + + // This loop intentionally doesn't have an early exit if the comparison + // returns Equal. We want the number of loop iterations to depend *only* + // on the size of the input slice so that the CPU can reliably predict + // the loop count. + while size > 1 { + let half = size / 2; + let mid = base + half; + + // SAFETY: the call is made safe by the following invariants: + // - `mid >= 0`: by definition + // - `mid < size`: `mid = size / 2 + size / 4 + size / 8 ...` + let cmp = f(unsafe { self.get_unchecked(mid) }); + + // Binary search interacts poorly with branch prediction, so force + // the compiler to use conditional moves if supported by the target + // architecture. + base = hint::select_unpredictable(cmp == Greater, base, mid); + + // This is imprecise in the case where `size` is odd and the + // comparison returns Greater: the mid element still gets included + // by `size` even though it's known to be larger than the element + // being searched for. + // + // This is fine though: we gain more performance by keeping the + // loop iteration count invariant (and thus predictable) than we + // lose from considering one additional element. + size -= half; + } + + // SAFETY: base is always in [0, size) because base <= mid. + let cmp = f(unsafe { self.get_unchecked(base) }); + if cmp == Equal { + // SAFETY: same as the `get_unchecked` above. + unsafe { hint::assert_unchecked(base < self.len()) }; + Ok(base) + } else { + let result = base + (cmp == Less) as usize; + // SAFETY: same as the `get_unchecked` above. + // Note that this is `<=`, unlike the assume in the `Ok` path. + unsafe { hint::assert_unchecked(result <= self.len()) }; + Err(result) + } + } + + /// Binary searches this slice with a key extraction function. + /// + /// Assumes that the slice is sorted by the key, for instance with + /// [`sort_by_key`] using the same key extraction function. + /// If the slice is not sorted by the key, the returned result is + /// unspecified and meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`]. + /// + /// [`sort_by_key`]: slice::sort_by_key + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by`]: slice::binary_search_by + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements in a slice of pairs sorted by + /// their second elements. The first is found, with a uniquely + /// determined position; the second and third are not found; the + /// fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), + /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), + /// (1, 21), (2, 34), (4, 55)]; + /// + /// assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b), Ok(9)); + /// assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b), Err(7)); + /// assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13)); + /// let r = s.binary_search_by_key(&1, |&(a, b)| b); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + // Lint rustdoc::broken_intra_doc_links is allowed as `slice::sort_by_key` is + // in crate `alloc`, and as such doesn't exists yet when building `core`: #74481. + // This breaks links when slice is displayed in core, but changing it to use relative links + // would break when the item is re-exported. So allow the core links to be broken for now. + #[allow(rustdoc::broken_intra_doc_links)] + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] + #[inline] + pub const fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result + where + F: [const] FnMut(&'a T) -> B + [const] Destruct, + B: [const] Ord + [const] Destruct, + { + self.binary_search_by(const |k| f(k).cmp(b)) + } + + /// Sorts the slice in ascending order **without** preserving the initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `T` panics. + /// + /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require + /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the + /// reflexivity requirement of [`Ord`]. By using an alternative comparison function with + /// `slice::sort_unstable_by` such as [`f32::total_cmp`] or [`f64::total_cmp`] that defines a + /// [total order] users can sort slices containing floating-point values. Alternatively, if all + /// values in the slice are guaranteed to be in a subset for which [`PartialOrd::partial_cmp`] + /// forms a [total order], it's possible to sort the slice with `sort_unstable_by(|a, b| + /// a.partial_cmp(b).unwrap())`. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if + /// the [`Ord`] implementation panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// v.sort_unstable(); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable(&mut self) + where + T: Ord, + { + sort::unstable::sort(self, &mut T::lt); + } + + /// Sorts the slice in ascending order with a comparison function, **without** preserving the + /// initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the comparison function `compare` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if `compare` panics. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the `compare` does not implement a [total order], or if + /// the `compare` itself panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4, -5, 1, -3, 2]; + /// v.sort_unstable_by(|a, b| a.cmp(b)); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// + /// // reverse sorting + /// v.sort_unstable_by(|a, b| b.cmp(a)); + /// assert_eq!(v, [4, 2, 1, -3, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by(&mut self, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + { + sort::unstable::sort(self, &mut |a, b| compare(a, b) == Ordering::Less); + } + + /// Sorts the slice in ascending order with a key extraction function, **without** preserving + /// the initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `K` panics. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4i32, -5, 1, -3, 2]; + /// + /// v.sort_unstable_by_key(|k| k.abs()); + /// assert_eq!(v, [1, 2, -3, 4, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by_key(&mut self, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, + { + sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b))); + } + + /// Partially sorts the slice in ascending order **without** preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable(0..0); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable(2..2); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable(2..3); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable(1..4); + /// assert_eq!(&v[1..4], [-3, 1, 2]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable(..); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [`sort_unstable`]: slice::sort_unstable + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable(&mut self, range: R) + where + T: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, T::lt); + } + + /// Partially sorts the slice in ascending order with a comparison function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the `compare` does not implement a total order, or if + /// the `compare` itself panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by(0..0, |a, b| b.cmp(a)); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by(2..2, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by(2..3, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by(1..4, |a, b| b.cmp(a)); + /// assert_eq!(&v[1..4], [2, 1, -3]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by(.., |a, b| b.cmp(a)); + /// assert_eq!(v, [4, 2, 1, -3, -5]); + /// ``` + /// + /// [`sort_unstable_by`]: slice::sort_unstable_by + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by(&mut self, range: R, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| compare(a, b) == Less); + } + + /// Partially sorts the slice in ascending order with a key extraction function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by_key`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `K` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4i32, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by_key(0..0, |k| k.abs()); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by_key(2..2, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by_key(2..3, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by_key(1..4, |k| k.abs()); + /// assert_eq!(&v[1..4], [2, -3, 4]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by_key(.., |k| k.abs()); + /// assert_eq!(v, [1, 2, -3, 4, -5]); + /// ``` + /// + /// [`sort_unstable_by_key`]: slice::sort_unstable_by_key + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by_key(&mut self, range: R, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| f(a).lt(&f(b))); + } + + /// Reorders the slice such that the element at `index` is at a sort-order position. All + /// elements before `index` will be `<=` to this value, and all elements after will be `>=` to + /// it. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple that partitions the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy `x <= self[index]`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy `x >= self[index]`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, and so always panics on empty slices. + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order]. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 2, -3, 1]; + /// + /// // Find the items `<=` to the median, the median itself, and the items `>=` to it. + /// let (lesser, median, greater) = v.select_nth_unstable(2); + /// + /// assert!(lesser == [-3, -5] || lesser == [-5, -3]); + /// assert_eq!(median, &mut 1); + /// assert!(greater == [4, 2] || greater == [2, 4]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [-3, -5, 1, 2, 4] || + /// v == [-5, -3, 1, 2, 4] || + /// v == [-3, -5, 1, 4, 2] || + /// v == [-5, -3, 1, 4, 2]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + where + T: Ord, + { + sort::select::partition_at_index(self, index, T::lt) + } + + /// Reorders the slice with a comparator function such that the element at `index` is at a + /// sort-order position. All elements before `index` will be `<=` to this value, and all + /// elements after will be `>=` to it, according to the comparator function. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy + /// `compare(x, self[index]).is_le()`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy + /// `compare(x, self[index]).is_ge()`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, and so always panics on empty slices. + /// + /// May panic if `compare` does not implement a [total order]. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 2, -3, 1]; + /// + /// // Find the items `>=` to the median, the median itself, and the items `<=` to it, by using + /// // a reversed comparator. + /// let (before, median, after) = v.select_nth_unstable_by(2, |a, b| b.cmp(a)); + /// + /// assert!(before == [4, 2] || before == [2, 4]); + /// assert_eq!(median, &mut 1); + /// assert!(after == [-3, -5] || after == [-5, -3]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [2, 4, 1, -5, -3] || + /// v == [2, 4, 1, -3, -5] || + /// v == [4, 2, 1, -5, -3] || + /// v == [4, 2, 1, -3, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable_by( + &mut self, + index: usize, + mut compare: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T, &T) -> Ordering, + { + sort::select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less) + } + + /// Reorders the slice with a key extraction function such that the element at `index` is at a + /// sort-order position. All elements before `index` will have keys `<=` to the key at `index`, + /// and all elements after will have keys `>=` to it. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy `f(x) <= f(self[index])`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy `f(x) >= f(self[index])`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// May panic if `K: Ord` does not implement a total order. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Find the items `<=` to the absolute median, the absolute median itself, and the items + /// // `>=` to it. + /// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs()); + /// + /// assert!(lesser == [1, 2] || lesser == [2, 1]); + /// assert_eq!(median, &mut -3); + /// assert!(greater == [4, -5] || greater == [-5, 4]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [1, 2, -3, 4, -5] || + /// v == [1, 2, -3, -5, 4] || + /// v == [2, 1, -3, 4, -5] || + /// v == [2, 1, -3, -5, 4]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable_by_key( + &mut self, + index: usize, + mut f: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T) -> K, + K: Ord, + { + sort::select::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b))) + } + + /// Moves all consecutive repeated elements to the end of the slice according to the + /// [`PartialEq`] trait implementation. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = [1, 2, 2, 3, 3, 2, 1, 1]; + /// + /// let (dedup, duplicates) = slice.partition_dedup(); + /// + /// assert_eq!(dedup, [1, 2, 3, 2, 1]); + /// assert_eq!(duplicates, [2, 3, 1]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + pub fn partition_dedup(&mut self) -> (&mut [T], &mut [T]) + where + T: PartialEq, + { + self.partition_dedup_by(|a, b| a == b) + } + + /// Moves all but the first of consecutive elements to the end of the slice that are + /// "equal" according to the given predicate function. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// The predicate `same_bucket(x, p)` is passed references to two elements from + /// the slice and must determine if the elements compare equal. The element `p` occurs + /// *before* `x` in the slice (`[.., p, .., x, ..]`), so `same_bucket(x, p)` + /// is receiving them in reversed order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. For more + /// complicated predicates however, the order (ascending vs. descending) can matter. + /// + /// Both references passed to `same_bucket` are mutable. + /// This allows merged elements in the first slice by mutating `p` and returning `true`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"]; + /// + /// let (dedup, duplicates) = slice.partition_dedup_by(|x, p| x.eq_ignore_ascii_case(p)); + /// + /// assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]); + /// assert_eq!(duplicates, ["bar", "Foo", "BAZ"]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub fn partition_dedup_by(&mut self, mut same_bucket: F) -> (&mut [T], &mut [T]) + where + F: FnMut(&mut T, &mut T) -> bool, + { + // Although we have a mutable reference to `self`, we cannot make + // *arbitrary* changes. The `same_bucket` calls could panic, so we + // must ensure that the slice is in a valid state at all times. + // + // The way that we handle this is by using swaps; we iterate + // over all the elements, swapping as we go so that at the end + // the elements we wish to keep are in the front, and those we + // wish to reject are at the back. We can then split the slice. + // This operation is still `O(n)`. + // + // Example: We start in this state, where `r` represents "next + // read" and `w` represents "next_write". + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, so + // we swap self[r] and self[w] (no effect as r==w) and then increment both + // r and w, leaving us with: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this value is a duplicate, + // so we increment `r` but leave everything else unchanged: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, + // so swap self[r] and self[w] and advance r and w: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 1 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Not a duplicate, repeat: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 3 | 1 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Duplicate, advance r. End of slice. Split at w. + + let len = self.len(); + if len <= 1 { + return (self, &mut []); + } + + let ptr = self.as_mut_ptr(); + let mut next_read: usize = 1; + let mut next_write: usize = 1; + + // SAFETY: the `while` condition guarantees `next_read` and `next_write` + // are less than `len`, thus are inside `self`. `prev_ptr_write` points to + // one element before `ptr_write`, but `next_write` starts at 1, so + // `prev_ptr_write` is never less than 0 and is inside the slice. + // This fulfills the requirements for dereferencing `ptr_read`, `prev_ptr_write` + // and `ptr_write`, and for using `ptr.add(next_read)`, `ptr.add(next_write - 1)` + // and `prev_ptr_write.offset(1)`. + // + // `next_write` is also incremented at most once per loop at most meaning + // no element is skipped when it may need to be swapped. + // + // `ptr_read` and `prev_ptr_write` never point to the same element. This + // is required for `&mut *ptr_read`, `&mut *prev_ptr_write` to be safe. + // The explanation is simply that `next_read >= next_write` is always true, + // thus `next_read > next_write - 1` is too. + unsafe { + // Avoid bounds checks by using raw pointers. + while next_read < len { + let ptr_read = ptr.add(next_read); + let prev_ptr_write = ptr.add(next_write - 1); + if !same_bucket(&mut *ptr_read, &mut *prev_ptr_write) { + if next_read != next_write { + let ptr_write = prev_ptr_write.add(1); + mem::swap(&mut *ptr_read, &mut *ptr_write); + } + next_write += 1; + } + next_read += 1; + } + } + + self.split_at_mut(next_write) + } + + /// Moves all but the first of consecutive elements to the end of the slice that resolve + /// to the same key. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = [10, 20, 21, 30, 30, 20, 11, 13]; + /// + /// let (dedup, duplicates) = slice.partition_dedup_by_key(|i| *i / 10); + /// + /// assert_eq!(dedup, [10, 20, 30, 20, 11]); + /// assert_eq!(duplicates, [21, 30, 13]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + pub fn partition_dedup_by_key(&mut self, mut key: F) -> (&mut [T], &mut [T]) + where + F: FnMut(&mut T) -> K, + K: PartialEq, + { + self.partition_dedup_by(|a, b| key(a) == key(b)) + } + + /// Rotates the slice in-place such that the first `mid` elements of the + /// slice move to the end while the last `self.len() - mid` elements move to + /// the front. + /// + /// After calling `rotate_left`, the element previously at index `mid` will + /// become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `mid` is greater than the length of the + /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_left(2); + /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']); + /// ``` + /// + /// Rotating a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_left(1); + /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn rotate_left(&mut self, mid: usize) { + assert!(mid <= self.len()); + let k = self.len() - mid; + let p = self.as_mut_ptr(); + + // SAFETY: The range `[p.add(mid) - mid, p.add(mid) + k)` is trivially + // valid for reading and writing, as required by `ptr_rotate`. + unsafe { + rotate::ptr_rotate(mid, p.add(mid), k); + } + } + + /// Rotates the slice in-place such that the first `self.len() - k` + /// elements of the slice move to the end while the last `k` elements move + /// to the front. + /// + /// After calling `rotate_right`, the element previously at index + /// `self.len() - k` will become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `k` is greater than the length of the + /// slice. Note that `k == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_right(2); + /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']); + /// ``` + /// + /// Rotating a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_right(1); + /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn rotate_right(&mut self, k: usize) { + assert!(k <= self.len()); + let mid = self.len() - k; + let p = self.as_mut_ptr(); + + // SAFETY: The range `[p.add(mid) - mid, p.add(mid) + k)` is trivially + // valid for reading and writing, as required by `ptr_rotate`. + unsafe { + rotate::ptr_rotate(mid, p.add(mid), k); + } + } + + /// Moves the elements of this slice `N` places to the left, returning the ones + /// that "fall off" the front, and putting `inserted` at the end. + /// + /// Equivalently, you can think of concatenating `self` and `inserted` into one + /// long sequence, then returning the left-most `N` items and the rest into `self`: + /// + /// ```text + /// self (before) inserted + /// vvvvvvvvvvvvvvv vvv + /// [1, 2, 3, 4, 5] [9] + /// ↙ ↙ ↙ ↙ ↙ ↙ + /// [1] [2, 3, 4, 5, 9] + /// ^^^ ^^^^^^^^^^^^^^^ + /// returned self (after) + /// ``` + /// + /// See also [`Self::shift_right`] and compare [`Self::rotate_left`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_shift)] + /// + /// // Same as the diagram above + /// let mut a = [1, 2, 3, 4, 5]; + /// let inserted = [9]; + /// let returned = a.shift_left(inserted); + /// assert_eq!(returned, [1]); + /// assert_eq!(a, [2, 3, 4, 5, 9]); + /// + /// // You can shift multiple items at a time + /// let mut a = *b"Hello world"; + /// assert_eq!(a.shift_left(*b" peace"), *b"Hello "); + /// assert_eq!(a, *b"world peace"); + /// + /// // The name comes from this operation's similarity to bitshifts + /// let mut a: u8 = 0b10010110; + /// a <<= 3; + /// assert_eq!(a, 0b10110000_u8); + /// let mut a: [_; 8] = [1, 0, 0, 1, 0, 1, 1, 0]; + /// a.shift_left([0; 3]); + /// assert_eq!(a, [1, 0, 1, 1, 0, 0, 0, 0]); + /// + /// // Remember you can sub-slice to affect less that the whole slice. + /// // For example, this is similar to `.remove(1)` + `.insert(4, 'Z')` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// assert_eq!(a[1..=4].shift_left(['Z']), ['b']); + /// assert_eq!(a, ['a', 'c', 'd', 'e', 'Z', 'f']); + /// + /// // If the size matches it's equivalent to `mem::replace` + /// let mut a = [1, 2, 3]; + /// assert_eq!(a.shift_left([7, 8, 9]), [1, 2, 3]); + /// assert_eq!(a, [7, 8, 9]); + /// + /// // Some of the "inserted" elements end up returned if the slice is too short + /// let mut a = []; + /// assert_eq!(a.shift_left([1, 2, 3]), [1, 2, 3]); + /// let mut a = [9]; + /// assert_eq!(a.shift_left([1, 2, 3]), [9, 1, 2]); + /// assert_eq!(a, [3]); + /// ``` + #[unstable(feature = "slice_shift", issue = "151772")] + pub const fn shift_left(&mut self, inserted: [T; N]) -> [T; N] { + if let Some(shift) = self.len().checked_sub(N) { + // SAFETY: Having just checked that the inserted/returned arrays are + // shorter than (or the same length as) the slice: + // 1. The read for the items to return is in-bounds + // 2. We can `memmove` the slice over to cover the items we're returning + // to ensure those aren't double-dropped + // 3. Then we write (in-bounds for the same reason as the read) the + // inserted items atop the items of the slice that we just duplicated + // + // And none of this can panic, so there's no risk of intermediate unwinds. + unsafe { + let ptr = self.as_mut_ptr(); + let returned = ptr.cast_array::().read(); + ptr.copy_from(ptr.add(N), shift); + ptr.add(shift).cast_array::().write(inserted); + returned + } + } else { + // SAFETY: Having checked that the slice is strictly shorter than the + // inserted/returned arrays, it means we'll be copying the whole slice + // into the returned array, but that's not enough on its own. We also + // need to copy some of the inserted array into the returned array, + // with the rest going into the slice. Because `&mut` is exclusive + // and we own both `inserted` and `returned`, they're all disjoint + // allocations from each other as we can use `nonoverlapping` copies. + // + // We avoid double-frees by `ManuallyDrop`ing the inserted items, + // since we always copy them to other locations that will drop them + // instead. Plus nothing in here can panic -- it's just memcpy three + // times -- so there's no intermediate unwinds to worry about. + unsafe { + let len = self.len(); + let slice = self.as_mut_ptr(); + let inserted = mem::ManuallyDrop::new(inserted); + let inserted = (&raw const inserted).cast::(); + + let mut returned = MaybeUninit::<[T; N]>::uninit(); + let ptr = returned.as_mut_ptr().cast::(); + ptr.copy_from_nonoverlapping(slice, len); + ptr.add(len).copy_from_nonoverlapping(inserted, N - len); + slice.copy_from_nonoverlapping(inserted.add(N - len), len); + returned.assume_init() + } + } + } + + /// Moves the elements of this slice `N` places to the right, returning the ones + /// that "fall off" the back, and putting `inserted` at the beginning. + /// + /// Equivalently, you can think of concatenating `inserted` and `self` into one + /// long sequence, then returning the right-most `N` items and the rest into `self`: + /// + /// ```text + /// inserted self (before) + /// vvv vvvvvvvvvvvvvvv + /// [0] [5, 6, 7, 8, 9] + /// ↘ ↘ ↘ ↘ ↘ ↘ + /// [0, 5, 6, 7, 8] [9] + /// ^^^^^^^^^^^^^^^ ^^^ + /// self (after) returned + /// ``` + /// + /// See also [`Self::shift_left`] and compare [`Self::rotate_right`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_shift)] + /// + /// // Same as the diagram above + /// let mut a = [5, 6, 7, 8, 9]; + /// let inserted = [0]; + /// let returned = a.shift_right(inserted); + /// assert_eq!(returned, [9]); + /// assert_eq!(a, [0, 5, 6, 7, 8]); + /// + /// // The name comes from this operation's similarity to bitshifts + /// let mut a: u8 = 0b10010110; + /// a >>= 3; + /// assert_eq!(a, 0b00010010_u8); + /// let mut a: [_; 8] = [1, 0, 0, 1, 0, 1, 1, 0]; + /// a.shift_right([0; 3]); + /// assert_eq!(a, [0, 0, 0, 1, 0, 0, 1, 0]); + /// + /// // Remember you can sub-slice to affect less that the whole slice. + /// // For example, this is similar to `.remove(4)` + `.insert(1, 'Z')` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// assert_eq!(a[1..=4].shift_right(['Z']), ['e']); + /// assert_eq!(a, ['a', 'Z', 'b', 'c', 'd', 'f']); + /// + /// // If the size matches it's equivalent to `mem::replace` + /// let mut a = [1, 2, 3]; + /// assert_eq!(a.shift_right([7, 8, 9]), [1, 2, 3]); + /// assert_eq!(a, [7, 8, 9]); + /// + /// // Some of the "inserted" elements end up returned if the slice is too short + /// let mut a = []; + /// assert_eq!(a.shift_right([1, 2, 3]), [1, 2, 3]); + /// let mut a = [9]; + /// assert_eq!(a.shift_right([1, 2, 3]), [2, 3, 9]); + /// assert_eq!(a, [1]); + /// ``` + #[unstable(feature = "slice_shift", issue = "151772")] + pub const fn shift_right(&mut self, inserted: [T; N]) -> [T; N] { + if let Some(shift) = self.len().checked_sub(N) { + // SAFETY: Having just checked that the inserted/returned arrays are + // shorter than (or the same length as) the slice: + // 1. The read for the items to return is in-bounds + // 2. We can `memmove` the slice over to cover the items we're returning + // to ensure those aren't double-dropped + // 3. Then we write (in-bounds for the same reason as the read) the + // inserted items atop the items of the slice that we just duplicated + // + // And none of this can panic, so there's no risk of intermediate unwinds. + unsafe { + let ptr = self.as_mut_ptr(); + let returned = ptr.add(shift).cast_array::().read(); + ptr.add(N).copy_from(ptr, shift); + ptr.cast_array::().write(inserted); + returned + } + } else { + // SAFETY: Having checked that the slice is strictly shorter than the + // inserted/returned arrays, it means we'll be copying the whole slice + // into the returned array, but that's not enough on its own. We also + // need to copy some of the inserted array into the returned array, + // with the rest going into the slice. Because `&mut` is exclusive + // and we own both `inserted` and `returned`, they're all disjoint + // allocations from each other as we can use `nonoverlapping` copies. + // + // We avoid double-frees by `ManuallyDrop`ing the inserted items, + // since we always copy them to other locations that will drop them + // instead. Plus nothing in here can panic -- it's just memcpy three + // times -- so there's no intermediate unwinds to worry about. + unsafe { + let len = self.len(); + let slice = self.as_mut_ptr(); + let inserted = mem::ManuallyDrop::new(inserted); + let inserted = (&raw const inserted).cast::(); + + let mut returned = MaybeUninit::<[T; N]>::uninit(); + let ptr = returned.as_mut_ptr().cast::(); + ptr.add(N - len).copy_from_nonoverlapping(slice, len); + ptr.copy_from_nonoverlapping(inserted.add(len), N - len); + slice.copy_from_nonoverlapping(inserted, len); + returned.assume_init() + } + } + } + + /// Fills `self` with elements by cloning `value`. + /// + /// # Examples + /// + /// ``` + /// let mut buf = vec![0; 10]; + /// buf.fill(1); + /// assert_eq!(buf, vec![1; 10]); + /// ``` + #[doc(alias = "memset")] + #[stable(feature = "slice_fill", since = "1.50.0")] + pub fn fill(&mut self, value: T) + where + T: Clone, + { + specialize::SpecFill::spec_fill(self, value); + } + + /// Fills `self` with elements returned by calling a closure repeatedly. + /// + /// This method uses a closure to create new values. If you'd rather + /// [`Clone`] a given value, use [`fill`]. If you want to use the [`Default`] + /// trait to generate values, you can pass [`Default::default`] as the + /// argument. + /// + /// [`fill`]: slice::fill + /// + /// # Examples + /// + /// ``` + /// let mut buf = vec![1; 10]; + /// buf.fill_with(Default::default); + /// assert_eq!(buf, vec![0; 10]); + /// ``` + #[stable(feature = "slice_fill_with", since = "1.51.0")] + pub fn fill_with(&mut self, mut f: F) + where + F: FnMut() -> T, + { + for el in self { + *el = f(); + } + } + + /// Copies the elements from `src` into `self`. + /// + /// The length of `src` must be the same as `self`. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Cloning two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. + /// dst.clone_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `clone_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].clone_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.clone_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`copy_from_slice`]: slice::copy_from_slice + /// [`split_at_mut`]: slice::split_at_mut + #[stable(feature = "clone_from_slice", since = "1.7.0")] + #[track_caller] + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + pub const fn clone_from_slice(&mut self, src: &[T]) + where + T: [const] Clone + [const] Destruct, + { + self.spec_clone_from(src); + } + + /// Copies all elements from `src` into `self`, using a memcpy. + /// + /// The length of `src` must be the same as `self`. + /// + /// If `T` does not implement `Copy`, use [`clone_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Copying two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. + /// dst.copy_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `copy_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].copy_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.copy_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`clone_from_slice`]: slice::clone_from_slice + /// [`split_at_mut`]: slice::split_at_mut + #[doc(alias = "memcpy")] + #[inline] + #[stable(feature = "copy_from_slice", since = "1.9.0")] + #[rustc_const_stable(feature = "const_copy_from_slice", since = "1.87.0")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub const fn copy_from_slice(&mut self, src: &[T]) + where + T: Copy, + { + // SAFETY: `T` implements `Copy`. + unsafe { copy_from_slice_impl(self, src) } + } + + /// Copies elements from one part of the slice to another part of itself, + /// using a memmove. + /// + /// `src` is the range within `self` to copy from. `dest` is the starting + /// index of the range within `self` to copy to, which will have the same + /// length as `src`. The two ranges may overlap. The ends of the two ranges + /// must be less than or equal to `self.len()`. + /// + /// # Panics + /// + /// This function will panic if either range exceeds the end of the slice, + /// or if the end of `src` is before the start. + /// + /// # Examples + /// + /// Copying four bytes within a slice: + /// + /// ``` + /// let mut bytes = *b"Hello, World!"; + /// + /// bytes.copy_within(1..5, 8); + /// + /// assert_eq!(&bytes, b"Hello, Wello!"); + /// ``` + #[inline] + #[stable(feature = "copy_within", since = "1.37.0")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub fn copy_within>(&mut self, src: R, dest: usize) + where + T: Copy, + { + let Range { start: src_start, end: src_end } = slice::range(src, ..self.len()); + let count = src_end - src_start; + assert!(dest <= self.len() - count, "dest is out of bounds"); + // SAFETY: the conditions for `ptr::copy` have all been checked above, + // as have those for `ptr::add`. + unsafe { + // Derive both `src_ptr` and `dest_ptr` from the same loan + let ptr = self.as_mut_ptr(); + let src_ptr = ptr.add(src_start); + let dest_ptr = ptr.add(dest); + ptr::copy(src_ptr, dest_ptr, count); + } + } + + /// Swaps all elements in `self` with those in `other`. + /// + /// The length of `other` must be the same as `self`. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Example + /// + /// Swapping two elements across slices: + /// + /// ``` + /// let mut slice1 = [0, 0]; + /// let mut slice2 = [1, 2, 3, 4]; + /// + /// slice1.swap_with_slice(&mut slice2[2..]); + /// + /// assert_eq!(slice1, [3, 4]); + /// assert_eq!(slice2, [1, 2, 0, 0]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference to a + /// particular piece of data in a particular scope. Because of this, + /// attempting to use `swap_with_slice` on a single slice will result in + /// a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// mutable sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.swap_with_slice(&mut right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 1, 2]); + /// ``` + /// + /// [`split_at_mut`]: slice::split_at_mut + #[stable(feature = "swap_with_slice", since = "1.27.0")] + #[rustc_const_unstable(feature = "const_swap_with_slice", issue = "142204")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub const fn swap_with_slice(&mut self, other: &mut [T]) { + assert!(self.len() == other.len(), "destination and source slices have different lengths"); + // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was + // checked to have the same length. The slices cannot overlap because + // mutable references are exclusive. + unsafe { + ptr::swap_nonoverlapping(self.as_mut_ptr(), other.as_mut_ptr(), self.len()); + } + } + + /// Function to calculate lengths of the middle and trailing slice for `align_to{,_mut}`. + fn align_to_offsets(&self) -> (usize, usize) { + // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a + // lowest number of `T`s. And how many `T`s we need for each such "multiple". + // + // Consider for example T=u8 U=u16. Then we can put 1 U in 2 Ts. Simple. Now, consider + // for example a case where size_of:: = 16, size_of:: = 24. We can put 2 Us in + // place of every 3 Ts in the `rest` slice. A bit more complicated. + // + // Formula to calculate this is: + // + // Us = lcm(size_of::, size_of::) / size_of:: + // Ts = lcm(size_of::, size_of::) / size_of:: + // + // Expanded and simplified: + // + // Us = size_of:: / gcd(size_of::, size_of::) + // Ts = size_of:: / gcd(size_of::, size_of::) + // + // Luckily since all this is constant-evaluated... performance here matters not! + const fn gcd(a: usize, b: usize) -> usize { + if b == 0 { a } else { gcd(b, a % b) } + } + + // Explicitly wrap the function call in a const block so it gets + // constant-evaluated even in debug mode. + let gcd: usize = const { gcd(size_of::(), size_of::()) }; + let ts: usize = size_of::() / gcd; + let us: usize = size_of::() / gcd; + + // Armed with this knowledge, we can find how many `U`s we can fit! + let us_len = self.len() / ts * us; + // And how many `T`s will be in the trailing slice! + let ts_len = self.len() % ts; + (us_len, ts_len) + } + + /// Transmutes the slice to a slice of another type, ensuring alignment of the types is + /// maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle part will be as big as possible under + /// the given alignment constraint and element size. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Safety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// unsafe { + /// let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[stable(feature = "slice_align_to", since = "1.30.0")] + #[must_use] + //Checks if the part that will be transmuted from type T to U is valid for type U + //reuses most function logic up to use of from_raw_parts, + //where the potentially unsafe transmute occurs + #[requires( + U::IS_ZST || T::IS_ZST || { + let ptr = self.as_ptr(); + let offset = crate::ptr::align_offset(ptr, align_of::()); + offset > self.len() || { + let (_, rest) = self.split_at(offset); + let (us_len, _) = rest.align_to_offsets::(); + let middle = crate::ptr::slice_from_raw_parts(rest.as_ptr() as *const U, us_len); + crate::ub_checks::can_dereference(middle) + } + } + )] + //The following clause guarantees that middle is of maximum size within self + //If U or T are ZSTs, then middle has size zero, so we adapt the check in that case + #[ensures(|(prefix, _, suffix): &(&[T], &[U], &[T])| + ((U::IS_ZST || T::IS_ZST) && prefix.len() == self.len()) || ( + (prefix.len() * size_of::() < align_of::()) && + (suffix.len() * size_of::() < size_of::()) + ) + )] + //Either align_to just returns self in the prefix, or the 3 returned slices + //should be sequential, contiguous, and have same total length as self + #[ensures(|(prefix, middle, suffix): &(&[T], &[U], &[T])| + prefix.as_ptr() == self.as_ptr() && + (prefix.len() == self.len() || ( + ((prefix.as_ptr()).add(prefix.len()) as *const u8 == middle.as_ptr() as *const u8) && + ((middle.as_ptr()).add(middle.len()) as *const u8 == suffix.as_ptr() as *const u8) && + ((suffix.as_ptr()).add(suffix.len()) == (self.as_ptr()).add(self.len())) ) + ) + )] + #[cfg_attr(rapx, rapx::requires(ValidTransmute(T, U)))] + #[cfg_attr(rapx, rapx::verify)] + pub unsafe fn align_to(&self) -> (&[T], &[U], &[T]) { + // Note that most of this function will be constant-evaluated, + if U::IS_ZST || T::IS_ZST { + // handle ZSTs specially, which is – don't handle them at all. + return (self, &[], &[]); + } + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. + let ptr = self.as_ptr(); + // SAFETY: See the `align_to_mut` method for the detailed safety comment. + let offset = unsafe { crate::ptr::align_offset(ptr, align_of::()) }; + if offset > self.len() { + (self, &[], &[]) + } else { + let (left, rest) = self.split_at(offset); + let (us_len, ts_len) = rest.align_to_offsets::(); + // Inform Miri that we want to consider the "middle" pointer to be suitably aligned. + #[cfg(miri)] + crate::intrinsics::miri_promise_symbolic_alignment( + rest.as_ptr().cast(), + align_of::(), + ); + // SAFETY: now `rest` is definitely aligned, so `from_raw_parts` below is okay, + // since the caller guarantees that we can transmute `T` to `U` safely. + unsafe { + ( + left, + from_raw_parts(rest.as_ptr() as *const U, us_len), + from_raw_parts(rest.as_ptr().add(rest.len() - ts_len), ts_len), + ) + } + } + } + + /// Transmutes the mutable slice to a mutable slice of another type, ensuring alignment of the + /// types is maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle part will be as big as possible under + /// the given alignment constraint and element size. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Safety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// unsafe { + /// let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to_mut::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[stable(feature = "slice_align_to", since = "1.30.0")] + #[must_use] + //Checks if the part that will be transmuted from type T to U is valid for type U + //reuses most function logic up to use of from_raw_parts, + //where the potentially unsafe transmute occurs + #[requires( + U::IS_ZST || T::IS_ZST || { + let ptr = self.as_ptr(); + let offset = crate::ptr::align_offset(ptr, align_of::()); + offset > self.len() || { + let (_, rest) = self.split_at(offset); + let (us_len, _) = rest.align_to_offsets::(); + let middle = crate::ptr::slice_from_raw_parts(rest.as_ptr() as *const U, us_len); + crate::ub_checks::can_dereference(middle) + } + } + )] + //The following clause guarantees that middle is of maximum size within self + //If U or T are ZSTs, then middle has size zero, so we adapt the check in that case + #[ensures(|(prefix, _, suffix): &(&mut [T], &mut [U], &mut [T])| + ((U::IS_ZST || T::IS_ZST) && prefix.len() == old(self.len())) || ( + (prefix.len() * size_of::() < align_of::()) && + (suffix.len() * size_of::() < size_of::()) + ) + )] + //Either align_to just returns self in the prefix, or the 3 returned slices + //should be sequential, contiguous, and have same total length as self + #[ensures(|(prefix, middle, suffix): &(&mut [T], &mut [U], &mut [T])| + prefix.as_ptr() == old(self.as_ptr()) && + (prefix.len() == old(self.len()) || ( + ((prefix.as_ptr()).add(prefix.len()) as *const u8 == middle.as_ptr() as *const u8) && + ((middle.as_ptr()).add(middle.len()) as *const u8 == suffix.as_ptr() as *const u8) && + ((suffix.as_ptr()).add(suffix.len()) == old((self.as_ptr()).add(self.len()))) + )) + )] + #[cfg_attr(rapx, rapx::requires(ValidTransmute(T, U)))] + #[cfg_attr(rapx, rapx::verify)] + pub unsafe fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) { + // Note that most of this function will be constant-evaluated, + if U::IS_ZST || T::IS_ZST { + // handle ZSTs specially, which is – don't handle them at all. + return (self, &mut [], &mut []); + } + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. + let ptr = self.as_ptr(); + // SAFETY: Here we are ensuring we will use aligned pointers for U for the + // rest of the method. This is done by passing a pointer to &[T] with an + // alignment targeted for U. + // `crate::ptr::align_offset` is called with a correctly aligned and + // valid pointer `ptr` (it comes from a reference to `self`) and with + // a size that is a power of two (since it comes from the alignment for U), + // satisfying its safety constraints. + let offset = unsafe { crate::ptr::align_offset(ptr, align_of::()) }; + if offset > self.len() { + (self, &mut [], &mut []) + } else { + let (left, rest) = self.split_at_mut(offset); + let (us_len, ts_len) = rest.align_to_offsets::(); + let rest_len = rest.len(); + let mut_ptr = rest.as_mut_ptr(); + // Inform Miri that we want to consider the "middle" pointer to be suitably aligned. + #[cfg(miri)] + crate::intrinsics::miri_promise_symbolic_alignment( + mut_ptr.cast() as *const (), + align_of::(), + ); + // We can't use `rest` again after this, that would invalidate its alias `mut_ptr`! + // SAFETY: see comments for `align_to`. + unsafe { + ( + left, + from_raw_parts_mut(mut_ptr as *mut U, us_len), + from_raw_parts_mut(mut_ptr.add(rest_len - ts_len), ts_len), + ) + } + } + } + + /// Splits a slice into a prefix, a middle of aligned SIMD types, and a suffix. + /// + /// This is a safe wrapper around [`slice::align_to`], so inherits the same + /// guarantees as that method. + /// + /// # Panics + /// + /// This will panic if the size of the SIMD type is different from + /// `LANES` times that of the scalar. + /// + /// At the time of writing, the trait restrictions on `Simd` keeps + /// that from ever happening, as only power-of-two numbers of lanes are + /// supported. It's possible that, in the future, those restrictions might + /// be lifted in a way that would make it possible to see panics from this + /// method for something like `LANES == 3`. + /// + /// # Examples + /// + /// ``` + /// #![feature(portable_simd)] + /// use core::simd::prelude::*; + /// + /// let short = &[1, 2, 3]; + /// let (prefix, middle, suffix) = short.as_simd::<4>(); + /// assert_eq!(middle, []); // Not enough elements for anything in the middle + /// + /// // They might be split in any possible way between prefix and suffix + /// let it = prefix.iter().chain(suffix).copied(); + /// assert_eq!(it.collect::>(), vec![1, 2, 3]); + /// + /// fn basic_simd_sum(x: &[f32]) -> f32 { + /// use std::ops::Add; + /// let (prefix, middle, suffix) = x.as_simd(); + /// let sums = f32x4::from_array([ + /// prefix.iter().copied().sum(), + /// 0.0, + /// 0.0, + /// suffix.iter().copied().sum(), + /// ]); + /// let sums = middle.iter().copied().fold(sums, f32x4::add); + /// sums.reduce_sum() + /// } + /// + /// let numbers: Vec = (1..101).map(|x| x as _).collect(); + /// assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0); + /// ``` + #[unstable(feature = "portable_simd", issue = "86656")] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub fn as_simd(&self) -> (&[T], &[Simd], &[T]) + where + Simd: AsRef<[T; LANES]>, + T: simd::SimdElement, + { + // These are expected to always match, as vector types are laid out like + // arrays per , but we + // might as well double-check since it'll optimize away anyhow. + assert_eq!(size_of::>(), size_of::<[T; LANES]>()); + + // SAFETY: The simd types have the same layout as arrays, just with + // potentially-higher alignment, so the de-facto transmutes are sound. + unsafe { self.align_to() } + } + + /// Splits a mutable slice into a mutable prefix, a middle of aligned SIMD types, + /// and a mutable suffix. + /// + /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same + /// guarantees as that method. + /// + /// This is the mutable version of [`slice::as_simd`]; see that for examples. + /// + /// # Panics + /// + /// This will panic if the size of the SIMD type is different from + /// `LANES` times that of the scalar. + /// + /// At the time of writing, the trait restrictions on `Simd` keeps + /// that from ever happening, as only power-of-two numbers of lanes are + /// supported. It's possible that, in the future, those restrictions might + /// be lifted in a way that would make it possible to see panics from this + /// method for something like `LANES == 3`. + #[unstable(feature = "portable_simd", issue = "86656")] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub fn as_simd_mut(&mut self) -> (&mut [T], &mut [Simd], &mut [T]) + where + Simd: AsMut<[T; LANES]>, + T: simd::SimdElement, + { + // These are expected to always match, as vector types are laid out like + // arrays per , but we + // might as well double-check since it'll optimize away anyhow. + assert_eq!(size_of::>(), size_of::<[T; LANES]>()); + + // SAFETY: The simd types have the same layout as arrays, just with + // potentially-higher alignment, so the de-facto transmutes are sound. + unsafe { self.align_to_mut() } + } + + /// Checks if the elements of this slice are sorted. + /// + /// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the + /// slice yields exactly zero or one element, `true` is returned. + /// + /// Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition + /// implies that this function returns `false` if any two consecutive items are not + /// comparable. + /// + /// # Examples + /// + /// ``` + /// let empty: [i32; 0] = []; + /// + /// assert!([1, 2, 2, 9].is_sorted()); + /// assert!(![1, 3, 2, 4].is_sorted()); + /// assert!([0].is_sorted()); + /// assert!(empty.is_sorted()); + /// assert!(![0.0, 1.0, f32::NAN].is_sorted()); + /// ``` + #[inline] + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted(&self) -> bool + where + T: PartialOrd, + { + // This odd number works the best. 32 + 1 extra due to overlapping chunk boundaries. + const CHUNK_SIZE: usize = 33; + if self.len() < CHUNK_SIZE { + return self.windows(2).all(|w| w[0] <= w[1]); + } + let mut i = 0; + // Check in chunks for autovectorization. + while i < self.len() - CHUNK_SIZE { + let chunk = &self[i..i + CHUNK_SIZE]; + if !chunk.windows(2).fold(true, |acc, w| acc & (w[0] <= w[1])) { + return false; + } + // We need to ensure that chunk boundaries are also sorted. + // Overlap the next chunk with the last element of our last chunk. + i += CHUNK_SIZE - 1; + } + self[i..].windows(2).all(|w| w[0] <= w[1]) + } + + /// Checks if the elements of this slice are sorted using the given comparator function. + /// + /// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare` + /// function to determine whether two elements are to be considered in sorted order. + /// + /// # Examples + /// + /// ``` + /// assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b)); + /// assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b)); + /// + /// assert!([0].is_sorted_by(|a, b| true)); + /// assert!([0].is_sorted_by(|a, b| false)); + /// + /// let empty: [i32; 0] = []; + /// assert!(empty.is_sorted_by(|a, b| false)); + /// assert!(empty.is_sorted_by(|a, b| true)); + /// ``` + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted_by<'a, F>(&'a self, mut compare: F) -> bool + where + F: FnMut(&'a T, &'a T) -> bool, + { + self.array_windows().all(|[a, b]| compare(a, b)) + } + + /// Checks if the elements of this slice are sorted using the given key extraction function. + /// + /// Instead of comparing the slice's elements directly, this function compares the keys of the + /// elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see its + /// documentation for more information. + /// + /// [`is_sorted`]: slice::is_sorted + /// + /// # Examples + /// + /// ``` + /// assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); + /// assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); + /// ``` + #[inline] + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool + where + F: FnMut(&'a T) -> K, + K: PartialOrd, + { + self.iter().is_sorted_by_key(f) + } + + /// Returns the index of the partition point according to the given predicate + /// (the index of the first element of the second partition). + /// + /// The slice is assumed to be partitioned according to the given predicate. + /// This means that all elements for which the predicate returns true are at the start of the slice + /// and all elements for which the predicate returns false are at the end. + /// For example, `[7, 15, 3, 5, 4, 12, 6]` is partitioned under the predicate `x % 2 != 0` + /// (all odd numbers are at the start, all even at the end). + /// + /// If this slice is not partitioned, the returned result is unspecified and meaningless, + /// as this method performs a kind of binary search. + /// + /// See also [`binary_search`], [`binary_search_by`], and [`binary_search_by_key`]. + /// + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by`]: slice::binary_search_by + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// + /// # Examples + /// + /// ``` + /// let v = [1, 2, 3, 3, 5, 6, 7]; + /// let i = v.partition_point(|&x| x < 5); + /// + /// assert_eq!(i, 4); + /// assert!(v[..i].iter().all(|&x| x < 5)); + /// assert!(v[i..].iter().all(|&x| !(x < 5))); + /// ``` + /// + /// If all elements of the slice match the predicate, including if the slice + /// is empty, then the length of the slice will be returned: + /// + /// ``` + /// let a = [2, 4, 8]; + /// assert_eq!(a.partition_point(|x| x < &100), a.len()); + /// let a: [i32; 0] = []; + /// assert_eq!(a.partition_point(|x| x < &100), 0); + /// ``` + /// + /// If you want to insert an item to a sorted vector, while maintaining + /// sort order: + /// + /// ``` + /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let num = 42; + /// let idx = s.partition_point(|&x| x <= num); + /// s.insert(idx, num); + /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "partition_point", since = "1.52.0")] + #[must_use] + pub const fn partition_point

(&self, mut pred: P) -> usize + where + P: [const] FnMut(&T) -> bool + [const] Destruct, + { + self.binary_search_by(const |x| if pred(x) { Less } else { Greater }) + .unwrap_or_else(const |i| i) + } + + /// Removes the subslice corresponding to the given range + /// and returns a reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Splitting off the first three elements of a slice: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut first_three = slice.split_off(..3).unwrap(); + /// + /// assert_eq!(slice, &['d']); + /// assert_eq!(first_three, &['a', 'b', 'c']); + /// ``` + /// + /// Splitting off a slice starting with the third element: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut tail = slice.split_off(2..).unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(tail, &['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.split_off(5..)); + /// assert_eq!(None, slice.split_off(..5)); + /// assert_eq!(None, slice.split_off(..=4)); + /// let expected: &[char] = &['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.split_off(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[stable(feature = "slice_take", since = "1.87.0")] + pub fn split_off<'a, R: OneSidedRange>( + self: &mut &'a Self, + range: R, + ) -> Option<&'a Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = self.split_at(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the subslice corresponding to the given range + /// and returns a mutable reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Splitting off the first three elements of a slice: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut first_three = slice.split_off_mut(..3).unwrap(); + /// + /// assert_eq!(slice, &mut ['d']); + /// assert_eq!(first_three, &mut ['a', 'b', 'c']); + /// ``` + /// + /// Splitting off a slice starting with the third element: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut tail = slice.split_off_mut(2..).unwrap(); + /// + /// assert_eq!(slice, &mut ['a', 'b']); + /// assert_eq!(tail, &mut ['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.split_off_mut(5..)); + /// assert_eq!(None, slice.split_off_mut(..5)); + /// assert_eq!(None, slice.split_off_mut(..=4)); + /// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.split_off_mut(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[stable(feature = "slice_take", since = "1.87.0")] + pub fn split_off_mut<'a, R: OneSidedRange>( + self: &mut &'a mut Self, + range: R, + ) -> Option<&'a mut Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = mem::take(self).split_at_mut(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the first element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let first = slice.split_off_first().unwrap(); + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'a'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((first, rem)) = self.split_first() else { return None }; + *self = rem; + Some(first) + } + + /// Removes the first element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let first = slice.split_off_first_mut().unwrap(); + /// *first = 'd'; + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'d'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_first_mut()?` + let Some((first, rem)) = mem::replace(self, &mut []).split_first_mut() else { return None }; + *self = rem; + Some(first) + } + + /// Removes the last element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let last = slice.split_off_last().unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'c'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((last, rem)) = self.split_last() else { return None }; + *self = rem; + Some(last) + } + + /// Removes the last element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let last = slice.split_off_last_mut().unwrap(); + /// *last = 'd'; + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'d'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_last_mut()?` + let Some((last, rem)) = mem::replace(self, &mut []).split_last_mut() else { return None }; + *self = rem; + Some(last) + } + + /// Returns mutable references to many indices at once, without doing any checks. + /// + /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note + /// that this method takes an array, so all indices must be of the same type. + /// If passed an array of `usize`s this method gives back an array of mutable references + /// to single elements, while if passed an array of ranges it gives back an array of + /// mutable references to slices. + /// + /// For a safe alternative see [`get_disjoint_mut`]. + /// + /// # Safety + /// + /// Calling this method with overlapping or out-of-bounds indices is *[undefined behavior]* + /// even if the resulting references are not used. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([0, 2]); + /// *a *= 10; + /// *b *= 100; + /// } + /// assert_eq!(x, &[10, 2, 400]); + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([0..1, 1..3]); + /// a[0] = 8; + /// b[0] = 88; + /// b[1] = 888; + /// } + /// assert_eq!(x, &[8, 88, 888]); + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([1..=2, 0..=0]); + /// a[0] = 11; + /// a[1] = 111; + /// b[0] = 1; + /// } + /// assert_eq!(x, &[1, 11, 111]); + /// ``` + /// + /// [`get_disjoint_mut`]: slice::get_disjoint_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[stable(feature = "get_many_mut", since = "1.86.0")] + #[inline] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, indices)))] + #[cfg_attr(rapx, rapx::requires(NonOverlap(indices)))] + // Safety precondition from the documentation: all indices in bounds and pairwise disjoint, + // i.e. exactly what `get_disjoint_mut` checks before calling this function. + #[requires(get_disjoint_check_valid(&indices, self.len()).is_ok())] + pub unsafe fn get_disjoint_unchecked_mut( + &mut self, + indices: [I; N], + ) -> [&mut I::Output; N] + where + I: GetDisjointMutIndex + SliceIndex, + { + // NB: This implementation is written as it is because any variation of + // `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy, + // or generate worse code otherwise. This is also why we need to go + // through a raw pointer here. + let slice: *mut [T] = self; + let mut arr: MaybeUninit<[&mut I::Output; N]> = MaybeUninit::uninit(); + let arr_ptr = arr.as_mut_ptr(); + + // SAFETY: We expect `indices` to contain disjunct values that are + // in bounds of `self`. + unsafe { + for i in 0..N { + let idx = indices.get_unchecked(i).clone(); + arr_ptr.cast::<&mut I::Output>().add(i).write(&mut *slice.get_unchecked_mut(idx)); + } + arr.assume_init() + } + } + + /// Returns mutable references to many indices at once. + /// + /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note + /// that this method takes an array, so all indices must be of the same type. + /// If passed an array of `usize`s this method gives back an array of mutable references + /// to single elements, while if passed an array of ranges it gives back an array of + /// mutable references to slices. + /// + /// Returns an error if any index is out-of-bounds, or if there are overlapping indices. + /// An empty range is not considered to overlap if it is located at the beginning or at + /// the end of another range, but is considered to overlap if it is located in the middle. + /// + /// This method does a O(n^2) check to check that there are no overlapping indices, so be careful + /// when passing many indices. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [1, 2, 3]; + /// if let Ok([a, b]) = v.get_disjoint_mut([0, 2]) { + /// *a = 413; + /// *b = 612; + /// } + /// assert_eq!(v, &[413, 2, 612]); + /// + /// if let Ok([a, b]) = v.get_disjoint_mut([0..1, 1..3]) { + /// a[0] = 8; + /// b[0] = 88; + /// b[1] = 888; + /// } + /// assert_eq!(v, &[8, 88, 888]); + /// + /// if let Ok([a, b]) = v.get_disjoint_mut([1..=2, 0..=0]) { + /// a[0] = 11; + /// a[1] = 111; + /// b[0] = 1; + /// } + /// assert_eq!(v, &[1, 11, 111]); + /// ``` + #[stable(feature = "get_many_mut", since = "1.86.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub fn get_disjoint_mut( + &mut self, + indices: [I; N], + ) -> Result<[&mut I::Output; N], GetDisjointMutError> + where + I: GetDisjointMutIndex + SliceIndex, + { + get_disjoint_check_valid(&indices, self.len())?; + // SAFETY: The `get_disjoint_check_valid()` call checked that all indices + // are disjunct and in bounds. + unsafe { Ok(self.get_disjoint_unchecked_mut(indices)) } + } + + /// Returns the index that an element reference points to. + /// + /// Returns `None` if `element` does not point to the start of an element within the slice. + /// + /// This method is useful for extending slice iterators like [`slice::split`]. + /// + /// Note that this uses pointer arithmetic and **does not compare elements**. + /// To find the index of an element via comparison, use + /// [`.iter().position()`](crate::iter::Iterator::position) instead. + /// + /// # Panics + /// Panics if `T` is zero-sized. + /// + /// # Examples + /// Basic usage: + /// ``` + /// let nums: &[u32] = &[1, 7, 1, 1]; + /// let num = &nums[2]; + /// + /// assert_eq!(num, &1); + /// assert_eq!(nums.element_offset(num), Some(2)); + /// ``` + /// Returning `None` with an unaligned element: + /// ``` + /// let arr: &[[u32; 2]] = &[[0, 1], [2, 3]]; + /// let flat_arr: &[u32] = arr.as_flattened(); + /// + /// let ok_elm: &[u32; 2] = flat_arr[0..2].try_into().unwrap(); + /// let weird_elm: &[u32; 2] = flat_arr[1..3].try_into().unwrap(); + /// + /// assert_eq!(ok_elm, &[0, 1]); + /// assert_eq!(weird_elm, &[1, 2]); + /// + /// assert_eq!(arr.element_offset(ok_elm), Some(0)); // Points to element 0 + /// assert_eq!(arr.element_offset(weird_elm), None); // Points between element 0 and 1 + /// ``` + #[must_use] + #[stable(feature = "element_offset", since = "1.94.0")] + pub fn element_offset(&self, element: &T) -> Option { + if T::IS_ZST { + panic!("elements are zero-sized"); + } + + let self_start = self.as_ptr().addr(); + let elem_start = ptr::from_ref(element).addr(); + + let byte_offset = elem_start.wrapping_sub(self_start); + + if !byte_offset.is_multiple_of(size_of::()) { + return None; + } + + let offset = byte_offset / size_of::(); + + if offset < self.len() { Some(offset) } else { None } + } + + /// Returns the range of indices that a subslice points to. + /// + /// Returns `None` if `subslice` does not point within the slice or if it is not aligned with the + /// elements in the slice. + /// + /// This method **does not compare elements**. Instead, this method finds the location in the slice that + /// `subslice` was obtained from. To find the index of a subslice via comparison, instead use + /// [`.windows()`](slice::windows)[`.position()`](crate::iter::Iterator::position). + /// + /// This method is useful for extending slice iterators like [`slice::split`]. + /// + /// Note that this may return a false positive (either `Some(0..0)` or `Some(self.len()..self.len())`) + /// if `subslice` has a length of zero and points to the beginning or end of another, separate, slice. + /// + /// # Panics + /// Panics if `T` is zero-sized. + /// + /// # Examples + /// Basic usage: + /// ``` + /// use core::range::Range; + /// + /// let nums = &[0, 5, 10, 0, 0, 5]; + /// + /// let mut iter = nums + /// .split(|t| *t == 0) + /// .map(|n| nums.subslice_range(n).unwrap()); + /// + /// assert_eq!(iter.next(), Some(Range { start: 0, end: 0 })); + /// assert_eq!(iter.next(), Some(Range { start: 1, end: 3 })); + /// assert_eq!(iter.next(), Some(Range { start: 4, end: 4 })); + /// assert_eq!(iter.next(), Some(Range { start: 5, end: 6 })); + /// ``` + #[must_use] + #[stable(feature = "substr_range", since = "1.98.0")] + pub fn subslice_range(&self, subslice: &[T]) -> Option> { + if T::IS_ZST { + panic!("elements are zero-sized"); + } + + let self_start = self.as_ptr().addr(); + let subslice_start = subslice.as_ptr().addr(); + + let byte_start = subslice_start.wrapping_sub(self_start); + + if !byte_start.is_multiple_of(size_of::()) { + return None; + } + + let start = byte_start / size_of::(); + let end = start.wrapping_add(subslice.len()); + + if start <= self.len() && end <= self.len() { + Some(core::range::Range { start, end }) + } else { + None + } + } + + /// Returns the same slice `&[T]`. + /// + /// This method is redundant when used directly on `&[T]`, but + /// it helps dereferencing other "container" types to slices, + /// for example `Box<[T]>` or `Arc<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_slice(&self) -> &[T] { + self + } + + /// Returns the same slice `&mut [T]`. + /// + /// This method is redundant when used directly on `&mut [T]`, but + /// it helps dereferencing other "container" types to slices, + /// for example `Box<[T]>` or `MutexGuard<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_mut_slice(&mut self) -> &mut [T] { + self + } +} + +impl [MaybeUninit] { + /// Transmutes the mutable uninitialized slice to a mutable uninitialized slice of + /// another type, ensuring alignment of the types is maintained. + /// + /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same + /// guarantees as that method. + /// + /// # Examples + /// + /// ``` + /// #![feature(align_to_uninit_mut)] + /// use std::mem::MaybeUninit; + /// + /// pub struct BumpAllocator<'scope> { + /// memory: &'scope mut [MaybeUninit], + /// } + /// + /// impl<'scope> BumpAllocator<'scope> { + /// pub fn new(memory: &'scope mut [MaybeUninit]) -> Self { + /// Self { memory } + /// } + /// pub fn try_alloc_uninit(&mut self) -> Option<&'scope mut MaybeUninit> { + /// let first_end = self.memory.as_ptr().align_offset(align_of::()) + size_of::(); + /// let prefix = self.memory.split_off_mut(..first_end)?; + /// Some(&mut prefix.align_to_uninit_mut::().1[0]) + /// } + /// pub fn try_alloc_u32(&mut self, value: u32) -> Option<&'scope mut u32> { + /// let uninit = self.try_alloc_uninit()?; + /// Some(uninit.write(value)) + /// } + /// } + /// + /// let mut memory = [MaybeUninit::::uninit(); 10]; + /// let mut allocator = BumpAllocator::new(&mut memory); + /// let v = allocator.try_alloc_u32(42); + /// assert_eq!(v, Some(&mut 42)); + /// ``` + #[unstable(feature = "align_to_uninit_mut", issue = "139062")] + #[inline] + #[must_use] + pub fn align_to_uninit_mut(&mut self) -> (&mut Self, &mut [MaybeUninit], &mut Self) { + // SAFETY: `MaybeUninit` is transparent. Correct size and alignment are guaranteed by + // `align_to_mut` itself. Therefore the only thing that we have to ensure for a safe + // `transmute` is that the values are valid for the types involved. But for `MaybeUninit` + // any values are valid, so this operation is safe. + unsafe { self.align_to_mut() } + } +} + +impl [[T; N]] { + /// Takes a `&[[T; N]]`, and flattens it to a `&[T]`. + /// + /// For the opposite operation, see [`as_chunks`] and [`as_rchunks`]. + /// + /// [`as_chunks`]: slice::as_chunks + /// [`as_rchunks`]: slice::as_rchunks + /// + /// # Panics + /// + /// This panics if the length of the resulting slice would overflow a `usize`. + /// + /// This is only possible when flattening a slice of arrays of zero-sized + /// types, and thus tends to be irrelevant in practice. If + /// `size_of::() > 0`, this will never panic. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([[1, 2, 3], [4, 5, 6]].as_flattened(), &[1, 2, 3, 4, 5, 6]); + /// + /// assert_eq!( + /// [[1, 2, 3], [4, 5, 6]].as_flattened(), + /// [[1, 2], [3, 4], [5, 6]].as_flattened(), + /// ); + /// + /// let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []]; + /// assert!(slice_of_empty_arrays.as_flattened().is_empty()); + /// + /// let empty_slice_of_arrays: &[[u32; 10]] = &[]; + /// assert!(empty_slice_of_arrays.as_flattened().is_empty()); + /// ``` + #[stable(feature = "slice_flatten", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidTransmute([T; N], T)))] + pub const fn as_flattened(&self) -> &[T] { + let len = if T::IS_ZST { + self.len().checked_mul(N).expect("slice len overflow") + } else { + // SAFETY: `self.len() * N` cannot overflow because `self` is + // already in the address space. + unsafe { self.len().unchecked_mul(N) } + }; + // SAFETY: `[T]` is layout-identical to `[T; N]` + unsafe { from_raw_parts(self.as_ptr().cast(), len) } + } + + /// Takes a `&mut [[T; N]]`, and flattens it to a `&mut [T]`. + /// + /// For the opposite operation, see [`as_chunks_mut`] and [`as_rchunks_mut`]. + /// + /// [`as_chunks_mut`]: slice::as_chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + /// + /// # Panics + /// + /// This panics if the length of the resulting slice would overflow a `usize`. + /// + /// This is only possible when flattening a slice of arrays of zero-sized + /// types, and thus tends to be irrelevant in practice. If + /// `size_of::() > 0`, this will never panic. + /// + /// # Examples + /// + /// ``` + /// fn add_5_to_all(slice: &mut [i32]) { + /// for i in slice { + /// *i += 5; + /// } + /// } + /// + /// let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; + /// add_5_to_all(array.as_flattened_mut()); + /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]); + /// ``` + #[stable(feature = "slice_flatten", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidTransmute([T; N], T)))] + pub const fn as_flattened_mut(&mut self) -> &mut [T] { + let len = if T::IS_ZST { + self.len().checked_mul(N).expect("slice len overflow") + } else { + // SAFETY: `self.len() * N` cannot overflow because `self` is + // already in the address space. + unsafe { self.len().unchecked_mul(N) } + }; + // SAFETY: `[T]` is layout-identical to `[T; N]` + unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), len) } + } +} + +impl [f32] { + /// Sorts the slice of floats. + /// + /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses + /// the ordering defined by [`f32::total_cmp`]. + /// + /// # Current implementation + /// + /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by). + /// + /// # Examples + /// + /// ``` + /// #![feature(sort_floats)] + /// let mut v = [2.6, -5e-8, f32::NAN, 8.29, f32::INFINITY, -1.0, 0.0, -f32::INFINITY, -0.0]; + /// + /// v.sort_floats(); + /// let sorted = [-f32::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f32::INFINITY, f32::NAN]; + /// assert_eq!(&v[..8], &sorted[..8]); + /// assert!(v[8].is_nan()); + /// ``` + #[unstable(feature = "sort_floats", issue = "93396")] + #[inline] + pub fn sort_floats(&mut self) { + self.sort_unstable_by(f32::total_cmp); + } +} + +impl [f64] { + /// Sorts the slice of floats. + /// + /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses + /// the ordering defined by [`f64::total_cmp`]. + /// + /// # Current implementation + /// + /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by). + /// + /// # Examples + /// + /// ``` + /// #![feature(sort_floats)] + /// let mut v = [2.6, -5e-8, f64::NAN, 8.29, f64::INFINITY, -1.0, 0.0, -f64::INFINITY, -0.0]; + /// + /// v.sort_floats(); + /// let sorted = [-f64::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f64::INFINITY, f64::NAN]; + /// assert_eq!(&v[..8], &sorted[..8]); + /// assert!(v[8].is_nan()); + /// ``` + #[unstable(feature = "sort_floats", issue = "93396")] + #[inline] + pub fn sort_floats(&mut self) { + self.sort_unstable_by(f64::total_cmp); + } +} + +/// Copies `src` to `dest`. +/// +/// # Safety +/// `T` must implement one of `Copy` or `TrivialClone`. +#[track_caller] +#[cfg_attr(rapx, rapx::verify)] +#[cfg_attr(rapx, rapx::requires(any(Trait(T, Copy), Trait(T, TrivialClone))))] +const unsafe fn copy_from_slice_impl(dest: &mut [T], src: &[T]) { + // The panic code path was put into a cold function to not bloat the + // call site. + #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] + #[cfg_attr(panic = "immediate-abort", inline)] + #[track_caller] + const fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! { + const_panic!( + "copy_from_slice: source slice length does not match destination slice length", + "copy_from_slice: source slice length ({src_len}) does not match destination slice length ({dst_len})", + src_len: usize, + dst_len: usize, + ) + } + + if dest.len() != src.len() { + len_mismatch_fail(dest.len(), src.len()); + } + + // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was + // checked to have the same length. The slices cannot overlap because + // mutable references are exclusive. + unsafe { + ptr::copy_nonoverlapping(src.as_ptr(), dest.as_mut_ptr(), dest.len()); + } +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const trait CloneFromSpec { + fn spec_clone_from(&mut self, src: &[T]) + where + T: [const] Destruct; +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const impl CloneFromSpec for [T] +where + T: [const] Clone + [const] Destruct, +{ + #[track_caller] + default fn spec_clone_from(&mut self, src: &[T]) { + assert!(self.len() == src.len(), "destination and source slices have different lengths"); + // NOTE: We need to explicitly slice them to the same length + // to make it easier for the optimizer to elide bounds checking. + // But since it can't be relied on we also have an explicit specialization for T: Copy. + let len = self.len(); + let src = &src[..len]; + for i in 0..len { + self[i].clone_from(&src[i]); + } + } +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const impl CloneFromSpec for [T] +where + T: [const] TrivialClone + [const] Destruct, +{ + #[track_caller] + fn spec_clone_from(&mut self, src: &[T]) { + // SAFETY: `T` implements `TrivialClone`. + unsafe { + copy_from_slice_impl(self, src); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +const impl Default for &[T] { + /// Creates an empty slice. + fn default() -> Self { + &[] + } +} + +#[stable(feature = "mut_slice_default", since = "1.5.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +const impl Default for &mut [T] { + /// Creates a mutable empty slice. + fn default() -> Self { + &mut [] + } +} + +#[unstable(feature = "slice_pattern", reason = "stopgap trait for slice patterns", issue = "56345")] +/// Patterns in slices - currently, only used by `strip_prefix` and `strip_suffix`. At a future +/// point, we hope to generalise `core::str::Pattern` (which at the time of writing is limited to +/// `str`) to slices, and then this trait will be replaced or abolished. +pub trait SlicePattern { + /// The element type of the slice being matched on. + type Item; + + /// Currently, the consumers of `SlicePattern` need a slice. + fn as_slice(&self) -> &[Self::Item]; +} + +#[stable(feature = "slice_strip", since = "1.51.0")] +impl SlicePattern for [T] { + type Item = T; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } +} + +#[stable(feature = "slice_strip", since = "1.51.0")] +impl SlicePattern for [T; N] { + type Item = T; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } +} + +/// This checks every index against each other, and against `len`. +/// +/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..` +/// comparison operations. +#[inline] +#[cfg_attr(rapx, rapx::verify)] +fn get_disjoint_check_valid( + indices: &[I; N], + len: usize, +) -> Result<(), GetDisjointMutError> { + // NB: The optimizer should inline the loops into a sequence + // of instructions without additional branching. + for (i, idx) in indices.iter().enumerate() { + if !idx.is_in_bounds(len) { + return Err(GetDisjointMutError::IndexOutOfBounds); + } + for idx2 in &indices[..i] { + if idx.is_overlapping(idx2) { + return Err(GetDisjointMutError::OverlappingIndices); + } + } + } + Ok(()) +} + +/// The error type returned by [`get_disjoint_mut`][`slice::get_disjoint_mut`]. +/// +/// It indicates one of two possible errors: +/// - An index is out-of-bounds. +/// - The same index appeared multiple times in the array +/// (or different but overlapping indices when ranges are provided). +/// +/// # Examples +/// +/// ``` +/// use std::slice::GetDisjointMutError; +/// +/// let v = &mut [1, 2, 3]; +/// assert_eq!(v.get_disjoint_mut([0, 999]), Err(GetDisjointMutError::IndexOutOfBounds)); +/// assert_eq!(v.get_disjoint_mut([1, 1]), Err(GetDisjointMutError::OverlappingIndices)); +/// ``` +#[stable(feature = "get_many_mut", since = "1.86.0")] +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum GetDisjointMutError { + /// An index provided was out-of-bounds for the slice. + IndexOutOfBounds, + /// Two indices provided were overlapping. + OverlappingIndices, +} + +#[stable(feature = "get_many_mut", since = "1.86.0")] +impl fmt::Display for GetDisjointMutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let msg = match self { + GetDisjointMutError::IndexOutOfBounds => "an index is out of bounds", + GetDisjointMutError::OverlappingIndices => "there were overlapping indices", + }; + fmt::Display::fmt(msg, f) + } +} + +/// A helper trait for `<[T]>::get_disjoint_mut()`. +/// +/// # Safety +/// +/// If `is_in_bounds()` returns `true` and `is_overlapping()` returns `false`, +/// it must be safe to index the slice with the indices. +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +pub impl(self) unsafe trait GetDisjointMutIndex: Clone { + /// Returns `true` if `self` is in bounds for `len` slice elements. + #[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] + fn is_in_bounds(&self, len: usize) -> bool; + + /// Returns `true` if `self` overlaps with `other`. + /// + /// Note that we don't consider zero-length ranges to overlap at the beginning or the end, + /// but do consider them to overlap in the middle. + #[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] + fn is_overlapping(&self, other: &Self) -> bool; +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for usize { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + *self < len + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + *self == *other + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for Range { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + (self.start <= self.end) & (self.end <= len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + (self.start < other.end) & (other.start < self.end) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for RangeInclusive { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + (self.start <= self.end) & (self.end < len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + (self.start <= other.end) & (other.start <= self.end) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for range::Range { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + Range::from(*self).is_in_bounds(len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + Range::from(*self).is_overlapping(&Range::from(*other)) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for range::RangeInclusive { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + RangeInclusive::from(*self).is_in_bounds(len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + RangeInclusive::from(*self).is_overlapping(&RangeInclusive::from(*other)) + } +} + +#[cfg(kani)] +#[unstable(feature = "kani", issue = "none")] +mod verify { + use super::*; + + //generates proof_of_contract harness for align_to given the T (src) and U (dst) types + macro_rules! proof_of_contract_for_align_to { + ($harness:ident, $src:ty, $dst:ty) => { + #[kani::proof_for_contract(<[$src]>::align_to)] + fn $harness() { + const ARR_SIZE: usize = 100; + let src_arr: [$src; ARR_SIZE] = kani::any(); + let src_slice = kani::slice::any_slice_of_array(&src_arr); + let dst_slice = unsafe { src_slice.align_to::<$dst>() }; + } + }; + } + + //generates harnesses for align_to where T is a given src type and U is one of the main primitives + macro_rules! gen_align_to_harnesses { + ($mod_name:ident, $src_type:ty) => { + mod $mod_name { + use super::*; + + proof_of_contract_for_align_to!(align_to_u8, $src_type, u8); + proof_of_contract_for_align_to!(align_to_u16, $src_type, u16); + proof_of_contract_for_align_to!(align_to_u32, $src_type, u32); + proof_of_contract_for_align_to!(align_to_u64, $src_type, u64); + proof_of_contract_for_align_to!(align_to_u128, $src_type, u128); + proof_of_contract_for_align_to!(align_to_bool, $src_type, bool); + proof_of_contract_for_align_to!(align_to_char, $src_type, char); + proof_of_contract_for_align_to!(align_to_unit, $src_type, ()); + } + }; + } + + gen_align_to_harnesses!(align_to_from_u8, u8); + gen_align_to_harnesses!(align_to_from_u16, u16); + gen_align_to_harnesses!(align_to_from_u32, u32); + gen_align_to_harnesses!(align_to_from_u64, u64); + gen_align_to_harnesses!(align_to_from_u128, u128); + gen_align_to_harnesses!(align_to_from_bool, bool); + gen_align_to_harnesses!(align_to_from_char, char); + gen_align_to_harnesses!(align_to_from_unit, ()); + + //generates proof_of_contract harness for align_to_mut given the T (src) and U (dst) types + macro_rules! proof_of_contract_for_align_to_mut { + ($harness:ident, $src:ty, $dst:ty) => { + #[kani::proof_for_contract(<[$src]>::align_to_mut)] + fn $harness() { + const ARR_SIZE: usize = 100; + let mut src_arr: [$src; ARR_SIZE] = kani::any(); + let src_slice = kani::slice::any_slice_of_array_mut(&mut src_arr); + let dst_slice = unsafe { src_slice.align_to_mut::<$dst>() }; + } + }; + } + + //generates harnesses between a given src type and all the main primitives + macro_rules! gen_align_to_mut_harnesses { + ($mod_name:ident, $src_type:ty) => { + mod $mod_name { + use super::*; + + proof_of_contract_for_align_to_mut!(align_to_mut_u8, $src_type, u8); + proof_of_contract_for_align_to_mut!(align_to_mut_u16, $src_type, u16); + proof_of_contract_for_align_to_mut!(align_to_mut_u32, $src_type, u32); + proof_of_contract_for_align_to_mut!(align_to_mut_u64, $src_type, u64); + proof_of_contract_for_align_to_mut!(align_to_mut_u128, $src_type, u128); + proof_of_contract_for_align_to_mut!(align_to_mut_bool, $src_type, bool); + proof_of_contract_for_align_to_mut!(align_to_mut_char, $src_type, char); + proof_of_contract_for_align_to_mut!(align_to_mut_unit, $src_type, ()); + } + }; + } + + gen_align_to_mut_harnesses!(align_to_mut_from_u8, u8); + gen_align_to_mut_harnesses!(align_to_mut_from_u16, u16); + gen_align_to_mut_harnesses!(align_to_mut_from_u32, u32); + gen_align_to_mut_harnesses!(align_to_mut_from_u64, u64); + gen_align_to_mut_harnesses!(align_to_mut_from_u128, u128); + gen_align_to_mut_harnesses!(align_to_mut_from_bool, bool); + gen_align_to_mut_harnesses!(align_to_mut_from_char, char); + gen_align_to_mut_harnesses!(align_to_mut_from_unit, ()); + + #[kani::proof] + fn check_reverse() { + let mut a: [u8; 100] = kani::any(); + a.reverse(); + } + + // Const-generic functions. The VeriFast proof in verifast-proofs/core/slice verifies these + // through runtime-`n` transcriptions (VeriFast cannot yet attach specifications to + // `` functions); the harnesses below run the exact shipped bodies, bounded in slice + // length and monomorphized over a few element types and chunk sizes. + + const CG_ARR_SIZE: usize = 12; + + macro_rules! proof_of_contract_for_as_chunks_unchecked { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof_for_contract(<[$t]>::as_chunks_unchecked)] + fn $harness() { + let arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let chunks = unsafe { s.as_chunks_unchecked::<$n>() }; + assert_eq!(chunks.len(), s.len() / $n); + } + }; + } + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u8_1, u8, 1); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u8_3, u8, 3); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u32_2, u32, 2); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_unit_4, (), 4); + + macro_rules! proof_of_contract_for_as_chunks_unchecked_mut { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof_for_contract(<[$t]>::as_chunks_unchecked_mut)] + fn $harness() { + let mut arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let chunks = unsafe { s.as_chunks_unchecked_mut::<$n>() }; + assert_eq!(chunks.len(), len / $n); + } + }; + } + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u8_1, u8, 1); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u8_3, u8, 3); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u32_2, u32, 2); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_unit_4, (), 4); + + #[kani::proof_for_contract(<[u8]>::get_disjoint_unchecked_mut)] + fn check_get_disjoint_unchecked_mut_usize() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let indices: [usize; 3] = kani::any(); + let [a, b, c] = unsafe { s.get_disjoint_unchecked_mut(indices) }; + *a = 1; + *b = 2; + *c = 3; + } + + #[kani::proof_for_contract(<[u32]>::get_disjoint_unchecked_mut)] + fn check_get_disjoint_unchecked_mut_range() { + let mut arr: [u32; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let indices: [Range; 2] = [kani::any()..kani::any(), kani::any()..kani::any()]; + let [a, b] = unsafe { s.get_disjoint_unchecked_mut(indices) }; + if let Some(x) = a.first_mut() { + *x = 1; + } + if let Some(y) = b.first_mut() { + *y = 2; + } + } + + macro_rules! check_chunk_accessors { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof] + fn $harness() { + let mut arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let len = s.len(); + match s.first_chunk::<$n>() { + Some(c) => assert!(len >= $n && c.as_ptr() == s.as_ptr()), + None => assert!(len < $n), + } + match s.last_chunk::<$n>() { + Some(c) => { + assert!(len >= $n && c.as_ptr() == unsafe { s.as_ptr().add(len - $n) }) + } + None => assert!(len < $n), + } + match s.split_first_chunk::<$n>() { + Some((c, rest)) => assert!(c.len() + rest.len() == len), + None => assert!(len < $n), + } + match s.split_last_chunk::<$n>() { + Some((rest, c)) => assert!(rest.len() + c.len() == len), + None => assert!(len < $n), + } + let (chunks, rem) = s.as_chunks::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + let (rem, chunks) = s.as_rchunks::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + match s.first_chunk_mut::<$n>() { + Some(c) => assert!(len >= $n && c.len() == $n), + None => assert!(len < $n), + } + match s.last_chunk_mut::<$n>() { + Some(c) => assert!(len >= $n && c.len() == $n), + None => assert!(len < $n), + } + match s.split_first_chunk_mut::<$n>() { + Some((c, rest)) => assert!(c.len() + rest.len() == len), + None => assert!(len < $n), + } + match s.split_last_chunk_mut::<$n>() { + Some((rest, c)) => assert!(rest.len() + c.len() == len), + None => assert!(len < $n), + } + let (chunks, rem) = s.as_chunks_mut::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + } + }; + } + check_chunk_accessors!(check_chunk_accessors_u8_1, u8, 1); + check_chunk_accessors!(check_chunk_accessors_u8_3, u8, 3); + check_chunk_accessors!(check_chunk_accessors_u32_2, u32, 2); + check_chunk_accessors!(check_chunk_accessors_unit_5, (), 5); + + macro_rules! check_as_flattened { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof] + fn $harness() { + let mut arr: [[$t; $n]; 4] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let flat = s.as_flattened(); + assert!(flat.len() == s.len() * $n); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let flat = s.as_flattened_mut(); + assert!(flat.len() == len * $n); + } + }; + } + check_as_flattened!(check_as_flattened_u8_3, u8, 3); + check_as_flattened!(check_as_flattened_u32_2, u32, 2); + check_as_flattened!(check_as_flattened_u8_0, u8, 0); + + #[kani::proof] + fn check_as_simd_u8_4() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let (prefix, middle, suffix) = s.as_simd::<4>(); + assert!(prefix.len() + middle.len() * 4 + suffix.len() == s.len()); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let (prefix, middle, suffix) = s.as_simd_mut::<4>(); + assert!(prefix.len() + middle.len() * 4 + suffix.len() == len); + } + + #[kani::proof] + fn check_get_disjoint_mut_usize() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let indices: [usize; 3] = kani::any(); + let valid = get_disjoint_check_valid(&indices, len).is_ok(); + match s.get_disjoint_mut(indices) { + Ok([a, b, c]) => { + assert!(valid); + *a = 1; + *b = 2; + *c = 3; + } + Err(_) => assert!(!valid), + } + } + + #[kani::proof] + fn check_get_disjoint_mut_range() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let indices: [Range; 2] = [kani::any()..kani::any(), kani::any()..kani::any()]; + let valid = get_disjoint_check_valid(&indices, len).is_ok(); + match s.get_disjoint_mut(indices) { + Ok([a, b]) => { + assert!(valid); + assert!(a.len() + b.len() <= len); + } + Err(_) => assert!(!valid), + } + } + + #[kani::proof] + fn check_get_disjoint_check_valid() { + let len: usize = kani::any(); + kani::assume(len <= CG_ARR_SIZE); + let indices: [usize; 3] = kani::any(); + let r = get_disjoint_check_valid(&indices, len); + let in_bounds = indices.iter().all(|i| *i < len); + let disjoint = + indices[0] != indices[1] && indices[0] != indices[2] && indices[1] != indices[2]; + assert!(r.is_ok() == (in_bounds && disjoint)); + } +} diff --git a/verifast-proofs/core/slice/mod.rs/original/slice/ascii.rs b/verifast-proofs/core/slice/mod.rs/original/slice/ascii.rs new file mode 100644 index 0000000000000..bf427f448fe55 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/original/slice/ascii.rs @@ -0,0 +1,4 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{EscapeAscii, SplitAsciiWhitespace, is_ascii_simple}; diff --git a/verifast-proofs/core/slice/mod.rs/original/slice/cmp.rs b/verifast-proofs/core/slice/mod.rs/original/slice/cmp.rs new file mode 100644 index 0000000000000..76f6305d79eb4 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/original/slice/cmp.rs @@ -0,0 +1,7 @@ + +pub trait SliceContains { + fn slice_contains(&self, x: &[T]) -> bool; +} +impl SliceContains for T { + fn slice_contains(&self, _x: &[T]) -> bool { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs/original/slice/index.rs b/verifast-proofs/core/slice/mod.rs/original/slice/index.rs new file mode 100644 index 0000000000000..9fc403d41a778 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/original/slice/index.rs @@ -0,0 +1,4 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{SliceIndex, range, try_range}; diff --git a/verifast-proofs/core/slice/mod.rs/original/slice/iter.rs b/verifast-proofs/core/slice/mod.rs/original/slice/iter.rs new file mode 100644 index 0000000000000..107231ba4b021 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/original/slice/iter.rs @@ -0,0 +1,10 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{ + ArrayWindows, ChunkBy, ChunkByMut, Chunks, ChunksMut, Windows, + ChunksExact, ChunksExactMut, Iter, IterMut, + RChunks, RChunksExact, RChunksExactMut, RChunksMut, + RSplit, RSplitMut, RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut, + SplitInclusive, SplitInclusiveMut, +}; diff --git a/verifast-proofs/core/slice/mod.rs/original/slice/memchr.rs b/verifast-proofs/core/slice/mod.rs/original/slice/memchr.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/verifast-proofs/core/slice/mod.rs/original/slice/raw.rs b/verifast-proofs/core/slice/mod.rs/original/slice/raw.rs new file mode 100644 index 0000000000000..154c5356d99ee --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/original/slice/raw.rs @@ -0,0 +1,364 @@ +//! Free functions to create `&[T]` and `&mut [T]`. + +use crate::ops::Range; +use crate::{array, ptr, ub_checks}; + +/// Forms a slice from a pointer and a length. +/// +/// The `len` argument is the number of **elements**, not the number of bytes. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be non-null, [valid] for reads for `len * size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. See [below](#incorrect-usage) +/// for an example incorrectly not taking this into account. +/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total size `len * size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// use std::slice; +/// +/// // manifest a slice for a single element +/// let x = 42; +/// let ptr = &x as *const _; +/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; +/// assert_eq!(slice[0], 42); +/// ``` +/// +/// ### Incorrect usage +/// +/// The following `join_slices` function is **unsound** ⚠️ +/// +/// ```rust,no_run +/// use std::slice; +/// +/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { +/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); +/// let snd_start = snd.as_ptr(); +/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); +/// unsafe { +/// // The assertion above ensures `fst` and `snd` are contiguous, but they might +/// // still be contained within _different allocations_, in which case +/// // creating this slice is undefined behavior. +/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) +/// } +/// } +/// +/// fn main() { +/// // `a` and `b` are different allocations... +/// let a = 42; +/// let b = 27; +/// // ... which may nevertheless be laid out contiguously in memory: | a | b | +/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB +/// } +/// ``` +/// +/// ### FFI: Handling null pointers +/// +/// In languages such as C++, pointers to empty collections are not guaranteed to be non-null. +/// When accepting such pointers, they have to be checked for null-ness to avoid undefined +/// behavior. +/// +/// ``` +/// use std::slice; +/// +/// /// Sum the elements of an FFI slice. +/// /// +/// /// # Safety +/// /// +/// /// If ptr is not NULL, it must be correctly aligned and +/// /// point to `len` initialized items of type `f32`. +/// unsafe extern "C" fn sum_slice(ptr: *const f32, len: usize) -> f32 { +/// let data = if ptr.is_null() { +/// // `len` is assumed to be 0. +/// &[] +/// } else { +/// // SAFETY: see function docstring. +/// unsafe { slice::from_raw_parts(ptr, len) } +/// }; +/// data.into_iter().sum() +/// } +/// +/// // This could be the result of C++'s std::vector::data(): +/// let ptr = std::ptr::null(); +/// // And this could be std::vector::size(): +/// let len = 0; +/// assert_eq!(unsafe { sum_slice(ptr, len) }, 0.0); +/// ``` +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] +#[must_use] +#[rustc_diagnostic_item = "slice_from_raw_parts"] +#[track_caller] +#[cfg_attr(rapx, rapx::requires(NonNull(data)))] +#[cfg_attr(rapx, rapx::requires(ValidPtr(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Init(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Alive(data, 'a)))] +#[cfg_attr(rapx, rapx::requires(Alias(data)))] +#[cfg_attr(rapx, rapx::requires(Align(data, T)))] +#[cfg_attr(rapx, rapx::requires(ValidNum(size_of(T) * len <= isize::MAX)))] +pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`", + ( + data: *mut () = data as *mut (), + size: usize = size_of::(), + align: usize = align_of::(), + len: usize = len, + ) => + ub_checks::maybe_is_aligned_and_not_null(data, align, false) + && ub_checks::is_valid_allocation_size(size, len) + ); + &*ptr::slice_from_raw_parts(data, len) + } +} + +/// Performs the same functionality as [`from_raw_parts`], except that a +/// mutable slice is returned. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be non-null, [valid] for both reads and writes for `len * size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total size `len * size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")] +#[must_use] +#[rustc_diagnostic_item = "slice_from_raw_parts_mut"] +#[track_caller] +#[cfg_attr(rapx, rapx::requires(NonNull(data)))] +#[cfg_attr(rapx, rapx::requires(ValidPtr(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Init(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Alive(data, 'a)))] +#[cfg_attr(rapx, rapx::requires(Alias(data)))] +#[cfg_attr(rapx, rapx::requires(Align(data, T)))] +#[cfg_attr(rapx, rapx::requires(ValidNum(size_of(T) * len <= isize::MAX)))] +pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`", + ( + data: *mut () = data as *mut (), + size: usize = size_of::(), + align: usize = align_of::(), + len: usize = len, + ) => + ub_checks::maybe_is_aligned_and_not_null(data, align, false) + && ub_checks::is_valid_allocation_size(size, len) + ); + &mut *ptr::slice_from_raw_parts_mut(data, len) + } +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +#[rustc_const_stable(feature = "const_slice_from_ref_shared", since = "1.63.0")] +#[rustc_diagnostic_item = "slice_from_ref"] +#[must_use] +pub const fn from_ref(s: &T) -> &[T] { + array::from_ref(s) +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +#[rustc_const_stable(feature = "const_slice_from_ref", since = "1.83.0")] +#[must_use] +pub const fn from_mut(s: &mut T) -> &mut [T] { + array::from_mut(s) +} + +/// Forms a slice from a pointer range. +/// +/// This function is useful for interacting with foreign interfaces which +/// use two pointers to refer to a range of elements in memory, as is +/// common in C++. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * The `start` pointer of the range must be a non-null, [valid] and properly aligned pointer +/// to the first element of a slice. +/// +/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* +/// the last element, such that the offset from the end to the start pointer is +/// the length of the slice. +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// +/// * The range must contain `N` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `start` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements. +/// +/// # Panics +/// +/// This function panics if `T` is a Zero-Sized Type (“ZST”). +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_from_ptr_range)] +/// +/// use core::slice; +/// +/// let x = [1, 2, 3]; +/// let range = x.as_ptr_range(); +/// +/// unsafe { +/// assert_eq!(slice::from_ptr_range(range), &x); +/// } +/// ``` +/// +/// [valid]: ptr#safety +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +#[rustc_const_unstable(feature = "const_slice_from_ptr_range", issue = "89792")] +#[track_caller] +pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { + // SAFETY: the caller must uphold the safety contract for `from_ptr_range`. + unsafe { from_raw_parts(range.start, range.end.offset_from_unsigned(range.start)) } +} + +/// Forms a mutable slice from a pointer range. +/// +/// This is the same functionality as [`from_ptr_range`], except that a +/// mutable slice is returned. +/// +/// This function is useful for interacting with foreign interfaces which +/// use two pointers to refer to a range of elements in memory, as is +/// common in C++. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * The `start` pointer of the range must be a non-null, [valid] and properly aligned pointer +/// to the first element of a slice. +/// +/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* +/// the last element, such that the offset from the end to the start pointer is +/// the length of the slice. +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// +/// * The range must contain `N` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `start` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements. +/// +/// # Panics +/// +/// This function panics if `T` is a Zero-Sized Type (“ZST”). +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_from_ptr_range)] +/// +/// use core::slice; +/// +/// let mut x = [1, 2, 3]; +/// let range = x.as_mut_ptr_range(); +/// +/// unsafe { +/// assert_eq!(slice::from_mut_ptr_range(range), &mut [1, 2, 3]); +/// } +/// ``` +/// +/// [valid]: ptr#safety +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +#[rustc_const_unstable(feature = "const_slice_from_mut_ptr_range", issue = "89792")] +pub const unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] { + // SAFETY: the caller must uphold the safety contract for `from_mut_ptr_range`. + unsafe { from_raw_parts_mut(range.start, range.end.offset_from_unsigned(range.start)) } +} diff --git a/verifast-proofs/core/slice/mod.rs/original/slice/rotate.rs b/verifast-proofs/core/slice/mod.rs/original/slice/rotate.rs new file mode 100644 index 0000000000000..b3b64422884d5 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/original/slice/rotate.rs @@ -0,0 +1,277 @@ +use crate::mem::{MaybeUninit, SizedTypeProperties}; +use crate::ptr; + +type BufType = [usize; 32]; + +/// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first +/// element. Equivalently, rotates the range `left` elements to the left or `right` elements to the +/// right. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +pub(super) const unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) { + if T::IS_ZST { + return; + } + // abort early if the rotate is a no-op + if (left == 0) || (right == 0) { + return; + } + // `T` is not a zero-sized type, so it's okay to divide by its size. + if !cfg!(feature = "optimize_for_size") + // FIXME(const-hack): Use cmp::min when available in const + && const_min(left, right) <= size_of::() / size_of::() + { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_memmove(left, mid, right) }; + } else if !cfg!(feature = "optimize_for_size") + && ((left + right < 24) || (size_of::() > size_of::<[usize; 4]>())) + { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_gcd(left, mid, right) } + } else { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_swap(left, mid, right) } + } +} + +/// Algorithm 1 is used if `min(left, right)` is small enough to fit onto a stack buffer. The +/// `min(left, right)` elements are copied onto the buffer, `memmove` is applied to the others, and +/// the ones on the buffer are moved back into the hole on the opposite side of where they +/// originated. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +const unsafe fn ptr_rotate_memmove(left: usize, mid: *mut T, right: usize) { + // The `[T; 0]` here is to ensure this is appropriately aligned for T + let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); + let buf = rawarray.as_mut_ptr() as *mut T; + // SAFETY: `mid-left <= mid-left+right < mid+right` + let dim = unsafe { mid.sub(left).add(right) }; + if left <= right { + // SAFETY: + // + // 1) The `if` condition about the sizes ensures `[mid-left; left]` will fit in + // `buf` without overflow and `buf` was created just above and so cannot be + // overlapped with any value of `[mid-left; left]` + // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care + // about overlaps here. + // 3) The `if` condition about `left <= right` ensures writing `left` elements to + // `dim = mid-left+right` is valid because: + // - `buf` is valid and `left` elements were written in it in 1) + // - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)` + unsafe { + // 1) + ptr::copy_nonoverlapping(mid.sub(left), buf, left); + // 2) + ptr::copy(mid, mid.sub(left), right); + // 3) + ptr::copy_nonoverlapping(buf, dim, left); + } + } else { + // SAFETY: same reasoning as above but with `left` and `right` reversed + unsafe { + ptr::copy_nonoverlapping(mid, buf, right); + ptr::copy(mid.sub(left), dim, left); + ptr::copy_nonoverlapping(buf, mid.sub(left), right); + } + } +} + +/// Algorithm 2 is used for small values of `left + right` or for large `T`. The elements +/// are moved into their final positions one at a time starting at `mid - left` and advancing by +/// `right` steps modulo `left + right`, such that only one temporary is needed. Eventually, we +/// arrive back at `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps +/// skipped over elements. For example: +/// ```text +/// left = 10, right = 6 +/// the `^` indicates an element in its final place +/// 6 7 8 9 10 11 12 13 14 15 . 0 1 2 3 4 5 +/// after using one step of the above algorithm (The X will be overwritten at the end of the round, +/// and 12 is stored in a temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 2 3 4 5 +/// ^ +/// after using another step (now 2 is in the temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ +/// after the third step (the steps wrap around, and 8 is in the temporary): +/// X 7 2 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ ^ +/// after 7 more steps, the round ends with the temporary 0 getting put in the X: +/// 0 7 2 9 4 11 6 13 8 15 . 10 1 12 3 14 5 +/// ^ ^ ^ ^ ^ ^ ^ ^ +/// ``` +/// Fortunately, the number of skipped over elements between finalized elements is always equal, so +/// we can just offset our starting position and do more rounds (the total number of rounds is the +/// `gcd(left + right, right)` value). The end result is that all elements are finalized once and +/// only once. +/// +/// Algorithm 2 can be vectorized by chunking and performing many rounds at once, but there are too +/// few rounds on average until `left + right` is enormous, and the worst case of a single +/// round is always there. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +const unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) { + // Algorithm 2 + // Microbenchmarks indicate that the average performance for random shifts is better all + // the way until about `left + right == 32`, but the worst case performance breaks even + // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 + // `usize`s, this algorithm also outperforms other algorithms. + // SAFETY: callers must ensure `mid - left` is valid for reading and writing. + let x = unsafe { mid.sub(left) }; + // beginning of first round + // SAFETY: see previous comment. + let mut tmp: T = unsafe { x.read() }; + let mut i = right; + // `gcd` can be found before hand by calculating `gcd(left + right, right)`, + // but it is faster to do one loop which calculates the gcd as a side effect, then + // doing the rest of the chunk + let mut gcd = right; + // benchmarks reveal that it is faster to swap temporaries all the way through instead + // of reading one temporary once, copying backwards, and then writing that temporary at + // the very end. This is possibly due to the fact that swapping or replacing temporaries + // uses only one memory address in the loop instead of needing to manage two. + loop { + // [long-safety-expl] + // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and + // writing. + // + // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right` + // - `i <= left+right-1` is always true + // - if `i < left`, `right` is added so `i < left+right` and on the next + // iteration `left` is removed from `i` so it doesn't go further + // - if `i >= left`, `left` is removed immediately and so it doesn't go further. + // - overflows cannot happen for `i` since the function's safety contract ask for + // `mid+right-1 = x+left+right` to be valid for writing + // - underflows cannot happen because `i` must be bigger or equal to `left` for + // a subtraction of `left` to happen. + // + // So `x+i` is valid for reading and writing if the caller respected the contract + tmp = unsafe { x.add(i).replace(tmp) }; + // instead of incrementing `i` and then checking if it is outside the bounds, we + // check if `i` will go outside the bounds on the next increment. This prevents + // any wrapping of pointers or `usize`. + if i >= left { + i -= left; + if i == 0 { + // end of first round + // SAFETY: tmp has been read from a valid source and x is valid for writing + // according to the caller. + unsafe { x.write(tmp) }; + break; + } + // this conditional must be here if `left + right >= 15` + if i < gcd { + gcd = i; + } + } else { + i += right; + } + } + // finish the chunk with more rounds + // FIXME(const-hack): Use `for start in 1..gcd` when available in const + let mut start = 1; + while start < gcd { + // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for + // reading and writing as per the function's safety contract, see [long-safety-expl] + // above + tmp = unsafe { x.add(start).read() }; + // [safety-expl-addition] + // + // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the + // greatest common divisor of `(left+right, right)` means that `left = right` so + // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing + // according to the function's safety contract. + i = start + right; + loop { + // SAFETY: see [long-safety-expl] and [safety-expl-addition] + tmp = unsafe { x.add(i).replace(tmp) }; + if i >= left { + i -= left; + if i == start { + // SAFETY: see [long-safety-expl] and [safety-expl-addition] + unsafe { x.add(start).write(tmp) }; + break; + } + } else { + i += right; + } + } + + start += 1; + } +} + +/// Algorithm 3 utilizes repeated swapping of `min(left, right)` elements. +/// +/// /// +/// ```text +/// left = 11, right = 4 +/// [4 5 6 7 8 9 10 11 12 13 14 . 0 1 2 3] +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping the right most elements with elements to the left +/// [4 5 6 7 8 9 10 . 0 1 2 3] 11 12 13 14 +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping these +/// [4 5 6 . 0 1 2 3] 7 8 9 10 11 12 13 14 +/// we cannot swap any more, but a smaller rotation problem is left to solve +/// ``` +/// when `left < right` the swapping happens from the left instead. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +const unsafe fn ptr_rotate_swap(mut left: usize, mut mid: *mut T, mut right: usize) { + loop { + if left >= right { + // Algorithm 3 + // There is an alternate way of swapping that involves finding where the last swap + // of this algorithm would be, and swapping using that last chunk instead of swapping + // adjacent chunks like this algorithm is doing, but this way is still faster. + loop { + // SAFETY: + // `left >= right` so `[mid-right, mid+right)` is valid for reading and writing + // Subtracting `right` from `mid` each turn is counterbalanced by the addition and + // check after it. + unsafe { + ptr::swap_nonoverlapping(mid.sub(right), mid, right); + mid = mid.sub(right); + } + left -= right; + if left < right { + break; + } + } + } else { + // Algorithm 3, `left < right` + loop { + // SAFETY: `[mid-left, mid+left)` is valid for reading and writing because + // `left < right` so `mid+left < mid+right`. + // Adding `left` to `mid` each turn is counterbalanced by the subtraction and check + // after it. + unsafe { + ptr::swap_nonoverlapping(mid.sub(left), mid, left); + mid = mid.add(left); + } + right -= left; + if right < left { + break; + } + } + } + if (right == 0) || (left == 0) { + return; + } + } +} + +// FIXME(const-hack): Use cmp::min when available in const +const fn const_min(left: usize, right: usize) -> usize { + if right < left { right } else { left } +} diff --git a/verifast-proofs/core/slice/mod.rs/original/slice/sort.rs b/verifast-proofs/core/slice/mod.rs/original/slice/sort.rs new file mode 100644 index 0000000000000..bb060c9c9b963 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/original/slice/sort.rs @@ -0,0 +1,11 @@ + +pub mod select { + pub fn partition_at_index(_v: &mut [T], _index: usize, _is_less: F) -> (&mut [T], &mut T, &mut [T]) + where F: FnMut(&T, &T) -> bool { loop {} } +} +pub mod unstable { + pub fn sort(_v: &mut [T], _is_less: &mut F) + where F: FnMut(&T, &T) -> bool { loop {} } + pub fn partial_sort(_v: &mut [T], _range: R, _is_less: F) + where R: core::ops::RangeBounds, F: FnMut(&T, &T) -> bool { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs/original/slice/specialize.rs b/verifast-proofs/core/slice/mod.rs/original/slice/specialize.rs new file mode 100644 index 0000000000000..9bf035047a4ed --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/original/slice/specialize.rs @@ -0,0 +1,7 @@ + +pub trait SpecFill { + fn spec_fill(&mut self, val: T); +} +impl SpecFill for [T] { + fn spec_fill(&mut self, _val: T) { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs/update.sh b/verifast-proofs/core/slice/mod.rs/update.sh new file mode 100644 index 0000000000000..f63c7e7f3ee4d --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/update.sh @@ -0,0 +1,16 @@ +set -x -e + +if ! git diff --quiet .; then + echo "Working directory not clean. Please stash your changes and try again" + false +else + UPSTREAM_MOD=../../../../library/core/src/slice/mod.rs + UPSTREAM_RAW=../../../../library/core/src/slice/raw.rs + UPSTREAM_ROTATE=../../../../library/core/src/slice/rotate.rs + git merge-file --diff3 verified/slice.rs original/slice.rs $UPSTREAM_MOD + cp $UPSTREAM_MOD original/slice.rs + git merge-file --diff3 verified/slice/raw.rs original/slice/raw.rs $UPSTREAM_RAW + cp $UPSTREAM_RAW original/slice/raw.rs + git merge-file --diff3 verified/slice/rotate.rs original/slice/rotate.rs $UPSTREAM_ROTATE + cp $UPSTREAM_ROTATE original/slice/rotate.rs +fi diff --git a/verifast-proofs/core/slice/mod.rs/verified/lib.rs b/verifast-proofs/core/slice/mod.rs/verified/lib.rs new file mode 100644 index 0000000000000..92b20dca28be4 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/verified/lib.rs @@ -0,0 +1,417 @@ +#![feature(const_result_trait_fn, const_iter)] +#![feature(one_sided_range, portable_simd, slice_index_methods, const_index, slice_range, const_clone, trivial_clone, slice_from_ptr_range, const_default, u8_split_ascii_whitespace, str_internals, slice_pattern)] +#![feature(slice_ptr_get, raw_slice_split, ptr_cast_array, array_into_iter_constructors, exact_size_is_empty, iter_advance_by, iter_next_chunk, iter_collect_into, trusted_len, trusted_random_access, trusted_fused, inplace_iteration, sized_type_properties, nonnull_provenance, ptr_metadata, slice_internals, const_option_ops, deref_pure_trait, try_trait_v2, never_type, specialization)] +//! # The Rust Core Library +//! +//! The Rust Core Library is the dependency-free[^free] foundation of [The +//! Rust Standard Library](../std/index.html). It is the portable glue +//! between the language and its libraries, defining the intrinsic and +//! primitive building blocks of all Rust code. It links to no +//! upstream libraries, no system libraries, and no libc. +//! +//! [^free]: Strictly speaking, there are some symbols which are needed but +//! they aren't always necessary. +//! +//! The core library is *minimal*: it isn't even aware of heap allocation, +//! nor does it provide concurrency or I/O. These things require +//! platform integration, and this library is platform-agnostic. +//! +//! # How to use the core library +//! +//! Please note that all of these details are currently not considered stable. +//! +// FIXME: Fill me in with more detail when the interface settles +//! This library is built on the assumption of a few existing symbols: +//! +//! * `memcpy`, `memmove`, `memset`, `memcmp`, `bcmp`, `strlen` - These are core memory routines +//! which are generated by Rust codegen backends. Additionally, this library can make explicit +//! calls to `strlen`. Their signatures are the same as found in C, but there are extra +//! assumptions about their semantics: For `memcpy`, `memmove`, `memset`, `memcmp`, and `bcmp`, if +//! the `n` parameter is 0, the function is assumed to not be UB, even if the pointers are NULL or +//! dangling. (Note that making extra assumptions about these functions is common among compilers: +//! [clang](https://reviews.llvm.org/D86993) and [GCC](https://gcc.gnu.org/onlinedocs/gcc/Standards.html#C-Language) do the same.) +//! These functions are often provided by the system libc, but can also be provided by the +//! [compiler-builtins crate](https://crates.io/crates/compiler_builtins). +//! Note that the library does not guarantee that it will always make these assumptions, so Rust +//! user code directly calling the C functions should follow the C specification! The advice for +//! Rust user code is to call the functions provided by this library instead (such as +//! `ptr::copy`). +//! +//! * Panic handler - This function takes one argument, a `&panic::PanicInfo`. It is up to consumers of this core +//! library to define this panic function; it is only required to never +//! return. You should mark your implementation using `#[panic_handler]`. +//! +//! * `rust_eh_personality` - is used by the failure mechanisms of the +//! compiler. This is often mapped to GCC's personality function, but crates +//! which do not trigger a panic can be assured that this function is never +//! called. The `lang` attribute is called `eh_personality`. + +#![stable(feature = "core", since = "1.6.0")] +#![doc( + html_playground_url = "https://play.rust-lang.org/", + issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", + test(no_crate_inject, attr(deny(warnings))), + test(attr(allow(dead_code, deprecated, unused_variables, unused_mut, duplicate_features))) +)] +#![doc(rust_logo)] +#![doc(auto_cfg( + hide(no_fp_fmt_parse), + hide(target_pointer_width, values("16", "32", "64")), + hide( + target_has_atomic, + target_has_atomic_primitive_alignment, + target_has_atomic_load_store, + values("8", "16", "32", "64", "ptr"), + ), +))] +#![rustc_coherence_is_core] +#![rustc_preserve_ub_checks] +// +// Lints: +#![deny(rust_2021_incompatible_or_patterns)] +#![deny(unsafe_op_in_unsafe_fn)] +#![deny(implicit_provenance_casts)] +#![warn(deprecated_in_future)] +#![warn(missing_debug_implementations)] +#![warn(missing_docs)] +#![allow(explicit_outlives_requirements)] +#![allow(incomplete_features)] +#![warn(multiple_supertrait_upcastable)] +#![allow(internal_features)] +#![allow(unused_features)] +#![deny(ffi_unwind_calls)] +#![warn(unreachable_pub)] +// Do not check link redundancy on bootstrapping phase +#![allow(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::unescaped_backticks)] +// +// Library features: +// tidy-alphabetical-start +#![feature(asm_experimental_arch)] +#![feature(bstr_internals)] +#![feature(cfg_target_has_reliable_f16_f128)] +#![feature(const_carrying_mul_add)] +#![feature(const_cmp)] +#![feature(const_destruct)] +#![feature(const_eval_select)] +#![feature(const_select_unpredictable)] +#![feature(core_intrinsics)] +#![feature(coverage_attribute)] +#![feature(disjoint_bitor)] +#![feature(io_const_error)] +#![feature(offset_of_enum)] +#![feature(panic_internals)] +#![feature(pattern_type_macro)] +#![feature(ub_checks)] +// tidy-alphabetical-end +// +// Language features: +// tidy-alphabetical-start +#![feature(adt_const_params)] +#![feature(allow_internal_unsafe)] +#![feature(allow_internal_unstable)] +#![feature(arbitrary_self_types_pointers)] +#![feature(auto_traits)] +#![feature(cfg_sanitize)] +#![feature(cfg_target_has_atomic)] +#![feature(cfg_ub_checks)] +#![feature(const_closures)] +#![feature(const_precise_live_drops)] +#![feature(const_trait_impl)] +#![feature(decl_macro)] +#![feature(deprecated_suggestion)] +#![feature(derive_const)] +#![feature(diagnostic_on_const)] +#![feature(diagnostic_on_unmatched_args)] +#![feature(diagnostic_opaque)] +#![feature(doc_cfg)] +#![feature(doc_notable_trait)] +#![feature(extern_types)] +#![feature(f16)] +#![feature(f128)] +#![feature(field_projections)] +#![feature(final_associated_functions)] +#![feature(freeze_impls)] +#![feature(fundamental)] +#![feature(funnel_shifts)] +#![feature(impl_restriction)] +#![feature(intra_doc_pointers)] +#![feature(intrinsics)] +#![feature(lang_items)] +#![feature(link_cfg)] +#![feature(link_llvm_intrinsics)] +#![feature(macro_metavar_expr)] +#![feature(macro_metavar_expr_concat)] +#![feature(marker_trait_attr)] +#![feature(min_specialization)] +#![feature(multiple_supertrait_upcastable)] +#![feature(must_not_suspend)] +#![feature(negative_impls)] +#![feature(no_core)] +#![feature(optimize_attribute)] +#![feature(pattern_types)] +#![feature(pin_macro_internals)] +#![feature(prelude_import)] +#![feature(repr_simd)] +#![feature(rustc_attrs)] +#![feature(rustdoc_internals)] +#![feature(simd_ffi)] +#![feature(splat)] +#![feature(staged_api)] +#![feature(stmt_expr_attributes)] +#![feature(strict_provenance_lints)] +#![feature(trait_alias)] +#![feature(transparent_unions)] +#![feature(try_blocks)] +#![feature(uint_carryless_mul)] +#![feature(unboxed_closures)] +#![feature(unsized_fn_params)] +#![feature(with_negative_coherence)] +// Required for Kani loop contracts, which are annotated as custom stmt attributes. +#![feature(proc_macro_hygiene)] +// tidy-alphabetical-end +// +// Target features: +// tidy-alphabetical-start +#![feature(aarch64_unstable_target_feature)] +#![feature(arm_target_feature)] +#![feature(avx10_target_feature)] +#![feature(clflushopt_target_feature)] +#![feature(hexagon_target_feature)] +#![feature(loongarch_target_feature)] +#![feature(mips_target_feature)] +#![feature(movrs_target_feature)] +#![feature(nvptx_target_feature)] +#![feature(powerpc_target_feature)] +#![feature(riscv_target_feature)] +#![feature(rtm_target_feature)] +#![feature(s390x_target_feature)] +#![feature(wasm_target_feature)] +#![feature(x86_amx_intrinsics)] +// tidy-alphabetical-end + +// tidy-alphabetical-start +#![expect(clippy::partialeq_ne_impl, reason = "we need to implement ne for a lot of core types")] +// tidy-alphabetical-end + +// allow using `core::` in intra-doc links + +#![no_core] +#![allow(unused_imports, unused_variables, dead_code, unused_mut, unreachable_pub, missing_docs, missing_debug_implementations)] + +#[stable(feature = "rust1", since = "1.0.0")] +extern crate core; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::{iter, ascii, char, clone, cmp, convert, default, fmt, hash, hint, marker, mem, num, ops, option, panicking, pin, range, result, simd, str}; +#[stable(feature = "rust1", since = "1.0.0")] +pub mod panic { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::panic::{Location, PanicInfo}; + #[unstable(feature = "panic_internals", issue = "none")] + pub macro const_panic($($t:tt)*) { + loop {} + } +} +#[stable(feature = "rust1", since = "1.0.0")] +pub mod ptr { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::ptr::*; + #[unstable(feature = "ptr_internals", issue = "none")] + pub unsafe fn align_offset(p: *const T, a: usize) -> usize + //@ req pointer_within_limits(p) == true &*& a > 0; + //@ ens 0 <= result &*& result <= usize::MAX &*& (result == usize::MAX || ((p + result) as usize) % a == 0); + //@ on_unwind_ens false; + // https://github.com/verifast/verifast/issues/1056 + //@ assume_correct + { + p.align_offset(a) + } + /*@ + fix mk_slice(data: *T, len: usize) -> *[T]; + + lem_auto(mk_slice::(data, len)) mk_slice_props(data: *T, len: usize) + req true; + ens strip_pointer_metadata(mk_slice::(data, len) as pointer) as *T == data && + mk_slice::(data, len) as *T == data && + (mk_slice::(data, len)).len() == len; + { + assume(false); + } + @*/ + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] + pub const unsafe fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] + //@ req true; + //@ ens result == mk_slice::(data, len); + //@ on_unwind_ens false; + // https://github.com/verifast/verifast/issues/1056 + //@ assume_correct + { + core::ptr::slice_from_raw_parts(data, len) + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")] + pub const unsafe fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] + //@ req true; + //@ ens result == mk_slice::(data, len); + //@ on_unwind_ens false; + // https://github.com/verifast/verifast/issues/1056 + //@ assume_correct + { + core::ptr::slice_from_raw_parts_mut(data, len) + } + /*@ + pred copy_context(base: *T, len: usize, src_idx: usize, dst_idx: usize, count: usize, elems: list) = + base[..len] |-> elems &*& + 0 <= count &*& + 0 <= src_idx &*& src_idx + count <= len &*& + 0 <= dst_idx &*& dst_idx + count <= len; + @*/ + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] + pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) + //@ req copy_context::(?base, ?len, ?src_idx, ?dst_idx, count, ?elems) &*& src == base + src_idx &*& dst == base + dst_idx; + //@ ens base[..len] |-> append(take(dst_idx, elems), append(take(count, drop(src_idx, elems)), drop(dst_idx + count, elems))); + //@ on_unwind_ens false; + //@ assume_correct + { + unsafe { core::ptr::copy(src, dst, count) } + } +} +#[stable(feature = "rust1", since = "1.0.0")] +pub mod intrinsics { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::intrinsics::{assume, arith_offset, ptr_offset_from, ptr_offset_from_unsigned, transmute, transmute_unchecked, write_bytes, copy, copy_nonoverlapping, compare_bytes, cttz_nonzero, ctlz_nonzero, size_of_val, align_of_val, size_of, align_of, needs_drop, type_id, type_name, caller_location, cold_path, likely, unlikely, select_unpredictable, abort, unreachable, const_eval_select, black_box, unchecked_shl, unchecked_shr}; + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn exact_div(x: usize, y: usize) -> usize + //@ req y != 0 &*& x % y == 0; + //@ ens result == x / y; + //@ on_unwind_ens false; + { + x / y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_sub(x: usize, y: usize) -> usize + //@ req x >= y; + //@ ens result == x - y; + //@ on_unwind_ens false; + { + x - y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_add(x: usize, y: usize) -> usize + //@ req x + y <= usize::MAX; + //@ ens result == x + y; + //@ on_unwind_ens false; + { + x + y + } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const unsafe fn unchecked_mul(x: usize, y: usize) -> usize + //@ req x * y <= usize::MAX; + //@ ens result == x * y; + //@ on_unwind_ens false; + { + //@ mul_mono_l(0, x, y); + x * y + } +} + +#[unstable(feature = "ub_checks", issue = "none")] +pub mod ub_checks { + #[unstable(feature = "ub_checks", issue = "none")] + pub trait Invariant { + fn is_safe(&self) -> bool { true } + } + #[unstable(feature = "ub_checks", issue = "none")] + impl Invariant for &T {} + #[unstable(feature = "ub_checks", issue = "none")] + impl Invariant for &mut T {} + #[macro_export] + macro_rules! assert_unsafe_precondition { + ($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {{}}; + } + #[unstable(feature = "ub_checks", issue = "none")] + pub use assert_unsafe_precondition; + #[unstable(feature = "ub_checks", issue = "none")] + pub const fn check_language_ub() -> bool { false } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn same_allocation(_a: *const T, _b: *const T) -> bool { true } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn can_dereference(_p: *const T) -> bool { true } + #[unstable(feature = "ub_checks", issue = "none")] + pub fn can_write(_p: *mut T) -> bool { true } +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod array { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::array::*; + #[unstable(feature = "iter_next_chunk", issue = "none")] + pub fn iter_next_chunk(_iter: &mut impl crate::iter::Iterator) -> Result<[T; N], core::array::IntoIter> { + loop {} + } +} + + + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::prelude::v1::{ + Copy, Send, Sized, Sync, Unpin, Drop, Fn, FnMut, FnOnce, AsyncFn, AsyncFnMut, AsyncFnOnce, + drop, align_of, align_of_val, size_of, size_of_val, + Clone, PartialEq, PartialOrd, Eq, Ord, AsMut, AsRef, From, Into, + Option, Some, None, Result, Ok, Err, + Debug, Hash, + panic, assert, assert_eq, assert_ne, cfg, column, compile_error, concat, debug_assert, debug_assert_eq, + debug_assert_ne, file, format_args, include, include_bytes, include_str, line, matches, + module_path, option_env, stringify, todo, unimplemented, unreachable, write, writeln, + cfg_select, derive, derive_const, + }; + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::prelude::rust_2024::{TryInto, TryFrom, FromIterator, Future, IntoFuture}; + #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::Default; + #[stable(feature = "rust1", since = "1.0.0")] + pub use core::iter::{Iterator, IntoIterator, DoubleEndedIterator, ExactSizeIterator, Extend}; +} +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +pub const trait Default { + #[stable(feature = "rust1", since = "1.0.0")] + fn default() -> Self; +} +#[prelude_import] +#[stable(feature = "rust1", since = "1.0.0")] +pub use prelude::*; + +#[stable(feature = "rust1", since = "1.0.0")] +#[path = "."] +pub mod std { + pub mod slice; +} +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::std::slice; + +#[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] +const unsafe fn call_binary_search_f__VeriFast_wrapper<'a, 'b, T, F>( + slice: &'a [T], + f: &'b mut F, + index: usize, +) -> core::cmp::Ordering +where + F: [const] FnMut(&'a T) -> core::cmp::Ordering, +//@ req thread_token(?t) &*& [_](<[T]>.share(?k, t, slice)) &*& *f |-> ?f0 &*& (.own)(t, f0) &*& index < slice.len(); +//@ ens thread_token(t) &*& *f |-> ?f1 &*& (.own)(t, f1); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + f(unsafe { slice.get_unchecked(index) }) +}const fn _vf_const_marker() {} + diff --git a/verifast-proofs/core/slice/mod.rs/verified/slice.rs b/verifast-proofs/core/slice/mod.rs/verified/slice.rs new file mode 100644 index 0000000000000..46c6de178106c --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/verified/slice.rs @@ -0,0 +1,8517 @@ +//! Slice management and manipulation. +//! +//! For more details see [`std::slice`]. +//! +//! [`std::slice`]: ../../std/slice/index.html + +#![stable(feature = "rust1", since = "1.0.0")] + +use safety::{ensures, requires}; + +use crate::clone::TrivialClone; +use crate::cmp::Ordering::{self, Equal, Greater, Less}; +use crate::intrinsics::{exact_div, unchecked_sub}; +#[cfg(kani)] +use crate::kani; +use crate::marker::Destruct; +use crate::mem::{self, MaybeUninit, SizedTypeProperties}; +use crate::num::NonZero; +use crate::ops::{OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeInclusive}; +use crate::panic::const_panic; +use crate::simd::{self, Simd}; +use crate::ub_checks::assert_unsafe_precondition; +use crate::{fmt, hint, ptr, range, slice}; + +#[unstable( + feature = "slice_internals", + issue = "none", + reason = "exposed from core to be reused in std; use the memchr crate" +)] +#[doc(hidden)] +/// Pure Rust memchr implementation, taken from rust-memchr +pub mod memchr; + +#[unstable( + feature = "slice_internals", + issue = "none", + reason = "exposed from core to be reused in std;" +)] +#[doc(hidden)] +pub mod sort; + +mod ascii; +mod cmp; +pub(crate) mod index; +mod iter; +mod raw; +mod rotate; +mod specialize; + +#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] +pub use ascii::EscapeAscii; +#[unstable(feature = "u8_split_ascii_whitespace", issue = "147878")] +pub use ascii::SplitAsciiWhitespace; +#[unstable(feature = "str_internals", issue = "none")] +#[doc(hidden)] +pub use ascii::is_ascii_simple; +#[stable(feature = "slice_get_slice", since = "1.28.0")] +pub use index::SliceIndex; +#[unstable(feature = "slice_range", issue = "76393")] +pub use index::{range, try_range}; +#[stable(feature = "array_windows", since = "1.94.0")] +pub use iter::ArrayWindows; +#[stable(feature = "slice_group_by", since = "1.77.0")] +pub use iter::{ChunkBy, ChunkByMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Chunks, ChunksMut, Windows}; +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub use iter::{ChunksExact, ChunksExactMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Iter, IterMut}; +#[stable(feature = "rchunks", since = "1.31.0")] +pub use iter::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; +#[stable(feature = "slice_rsplit", since = "1.27.0")] +pub use iter::{RSplit, RSplitMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut}; +#[stable(feature = "split_inclusive", since = "1.51.0")] +pub use iter::{SplitInclusive, SplitInclusiveMut}; +#[stable(feature = "from_ref", since = "1.28.0")] +pub use raw::{from_mut, from_ref}; +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +pub use raw::{from_mut_ptr_range, from_ptr_range}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::{from_raw_parts, from_raw_parts_mut}; + +/// Calculates the direction and split point of a one-sided range. +/// +/// This is a helper function for `split_off` and `split_off_mut` that returns +/// the direction of the split (front or back) as well as the index at +/// which to split. Returns `None` if the split index would overflow. +#[inline] +fn split_point_of(range: impl OneSidedRange) -> Option<(Direction, usize)> { + use OneSidedRangeBound::{End, EndInclusive, StartInclusive}; + + Some(match range.bound() { + (StartInclusive, i) => (Direction::Back, i), + (End, i) => (Direction::Front, i), + (EndInclusive, i) => (Direction::Front, i.checked_add(1)?), + }) +} + +enum Direction { + Front, + Back, +} + +/*@ +fix update(i: i32, y: t, xs: list) -> list { + match xs { + nil => nil, + cons(x, xs0) => if i == 0 { cons(y, xs0) } else { cons(x, update(i - 1, y, xs0)) } + } +} + +lem_auto(length(update(i, y, xs))) length_update(i: i32, y: t, xs: list) + req true; + ens length(update(i, y, xs)) == length(xs); +{ + match xs { + nil => {} + cons(x, xs0) => { if i != 0 { length_update(i - 1, y, xs0); } } + } +} + +lem update_same(i: i32, xs: list) + req 0 <= i &*& i < length(xs); + ens update(i, nth(i, xs), xs) == xs; +{ + match xs { + nil => {} + cons(x, xs0) => { if i != 0 { update_same(i - 1, xs0); } } + } +} + +lem update_overwrite(i: i32, y1: t, y2: t, xs: list) + req 0 <= i &*& i < length(xs); + ens update(i, y2, update(i, y1, xs)) == update(i, y2, xs); +{ + match xs { + nil => {} + cons(x, xs0) => { if i != 0 { update_overwrite(i - 1, y1, y2, xs0); } } + } +} + +lem append_take_cons_drop_update(xs: list, i: i32, v: t) + req 0 <= i &*& i < length(xs); + ens append(take(i, xs), cons(v, drop(i + 1, xs))) == update(i, v, xs); +{ + match xs { + nil => {} + cons(x, xs0) => { if i != 0 { append_take_cons_drop_update(xs0, i - 1, v); } } + } +} + +lem take_update_lt(i: i32, v: t, b: i32, xs: list) + req 0 <= i &*& i < b &*& b <= length(xs); + ens update(i, v, take(b, xs)) == take(b, update(i, v, xs)) &*& + drop(b + 1, update(i, v, xs)) == drop(b + 1, xs); +{ + match xs { + nil => {} + cons(x, xs0) => { + if i == 0 { + } else { + take_update_lt(i - 1, v, b - 1, xs0); + } + } + } +} + +lem update_comm(i: i32, vi: t, j: i32, vj: t, xs: list) + req 0 <= i &*& 0 <= j &*& i != j; + ens update(j, vj, update(i, vi, xs)) == update(i, vi, update(j, vj, xs)); +{ + match xs { + nil => {} + cons(x, xs0) => { + if i == 0 { + } else if j == 0 { + } else { + update_comm(i - 1, vi, j - 1, vj, xs0); + } + } + } +} + +lem array_extract_elem(ptr: *T, i: usize) + req ptr[..?len] |-> ?elems &*& 0 <= i &*& i < len; + ens ptr[..i] |-> take(i, elems) &*& *(ptr + i) |-> nth(i, elems) &*& (ptr + i + 1)[..len - i - 1] |-> drop(i + 1, elems); +{ + array_split(ptr, i); + drop_n_plus_one(i, elems); + open array(ptr + i, len - i, drop(i, elems)); +} + +lem array_insert_elem(ptr: *T, i: usize, len: usize, elems: list) + req ptr[..i] |-> take(i, elems) &*& *(ptr + i) |-> ?v &*& (ptr + i + 1)[..len - i - 1] |-> drop(i + 1, elems) &*& 0 <= i &*& i < len &*& length(elems) == len; + ens ptr[..len] |-> update(i, v, elems); +{ + close array(ptr + i, len - i, cons(v, drop(i + 1, elems))); + array_join(ptr); + append_take_cons_drop_update(elems, i, v); +} + +lem update_nth_id(i: i32, xs: list) + req 0 <= i &*& i < length(xs); + ens update(i, nth(i, xs), xs) == xs; +{ + match xs { + nil => {} + cons(h, tl) => { + if i == 0 { + } else { + update_nth_id(i - 1, tl); + } + } + } +} + +lem array_extract_elem_frac(ptr: *T, i: usize) + req [?f](ptr[..?len] |-> ?elems) &*& 0 <= i &*& i < len; + ens [f](ptr[..i] |-> take(i, elems)) &*& [f](*(ptr + i) |-> nth(i, elems)) &*& [f]((ptr + i + 1)[..len - i - 1] |-> drop(i + 1, elems)); +{ + array_split(ptr, i); + drop_n_plus_one(i, elems); + open [f]array(ptr + i, len - i, drop(i, elems)); +} + +lem array_insert_elem_frac(ptr: *T, i: usize, len: usize, elems: list) + req [?f](ptr[..i] |-> take(i, elems)) &*& [f](*(ptr + i) |-> nth(i, elems)) &*& [f]((ptr + i + 1)[..len - i - 1] |-> drop(i + 1, elems)) &*& 0 <= i &*& i < len &*& length(elems) == len; + ens [f](ptr[..len] |-> elems); +{ + close [f]array(ptr + i, len - i, cons(nth(i, elems), drop(i + 1, elems))); + array_join(ptr); + append_take_cons_drop_update(elems, i, nth(i, elems)); + update_nth_id(i, elems); +} + +lem close_slice_pair_own<'a, T>(t: thread_id_t, v: (&'a [T], &'a [T])) + req [_](<[T]>.share('a, t, v.0)) &*& [_](<[T]>.share('a, t, v.1)); + ens <(&'a [T], &'a [T])>.own(t, v); +{ + // https://github.com/verifast/verifast/issues/1049 + assume(false); +} + +lem close_mut_slice_pair_own<'a, T>(t: thread_id_t, v: (&'a mut [T], &'a mut [T])) + req full_borrow('a, <[T]>.full_borrow_content(t, v.0)) &*& full_borrow('a, <[T]>.full_borrow_content(t, v.1)); + ens <(&'a mut [T], &'a mut [T])>.own(t, v); +{ + // https://github.com/verifast/verifast/issues/1049 + assume(false); +} + +lem close_Range_own(t: thread_id_t, v: std::ops::Range) + req (.own)(t, v.start) &*& (.own)(t, v.end); + ens >.own(t, v); +{ + // https://github.com/verifast/verifast/issues/1049 + assume(false); +} + +lem close_Result_usize_own(t: thread_id_t, v: std::result::Result) + req true; + ens >.own(t, v); +{ + match v { + Result::Ok(x) => { + close usize_own(t, x); + close >.own(t, v); + } + Result::Err(x) => { + close usize_own(t, x); + close >.own(t, v); + } + } +} + +lem slice_share_inv(k: lifetime_t, t: thread_id_t, s: *[T]) + req [_](<[T]>.share(k, t, s)); + ens s.len() * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits(strip_pointer_metadata(s as pointer) as *T) == true &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *T) + s.len()) == true; +{ + // https://github.com/verifast/verifast/issues/1050 + assume(false); +} + +lem slice_full_borrow_inv(q: real, k: lifetime_t, t: thread_id_t, s: *[T]) + nonghost_callers_only + req [q]lifetime_token(k) &*& full_borrow(k, <[T]>.full_borrow_content(t, s)); + ens [q]lifetime_token(k) &*& full_borrow(k, <[T]>.full_borrow_content(t, s)) &*& + s.len() * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits(strip_pointer_metadata(s as pointer) as *T) == true &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *T) + s.len()) == true; +{ + open_full_borrow(q / 2, k, slice_full_borrow_content::(t, s)); + open slice_full_borrow_content::(t, s)(); + array_inv::(); + close slice_full_borrow_content::(t, s)(); + close_full_borrow(slice_full_borrow_content::(t, s)); +} + +lem open_mut_slice_full_borrow(q: real, k: lifetime_t, t: thread_id_t, s: *[T]) + nonghost_callers_only + req [q]lifetime_token(k) &*& full_borrow(k, <[T]>.full_borrow_content(t, s)); + ens [q / 2]lifetime_token(k) &*& close_full_borrow_token(<[T]>.full_borrow_content(t, s), q / 2, k) &*& + (strip_pointer_metadata(s as pointer) as *T)[..s.len()] |-> ?elems &*& foreach(elems, own::(t)) &*& + s.len() * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits(strip_pointer_metadata(s as pointer) as *T) == true &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *T) + s.len()) == true; +{ + open_full_borrow(q / 2, k, slice_full_borrow_content::(t, s)); + open slice_full_borrow_content::(t, s)(); +} + +lem close_mut_slice_full_borrow(q: real, k: lifetime_t, t: thread_id_t, s: *[T]) + nonghost_callers_only + req [q / 2]lifetime_token(k) &*& close_full_borrow_token(<[T]>.full_borrow_content(t, s), q / 2, k) &*& + (strip_pointer_metadata(s as pointer) as *T)[..s.len()] |-> ?elems &*& foreach(elems, own::(t)); + ens [q]lifetime_token(k); +{ + close slice_full_borrow_content::(t, s)(); + close_full_borrow(slice_full_borrow_content::(t, s)); + leak full_borrow(k, slice_full_borrow_content::(t, s)); +} + +// Caller obligation of `align_to`/`align_to_mut` (see their `# Safety` sections: the middle slice is +// "essentially a `transmute`" of `T`s to `U`s): reinterpreting a correctly aligned, exactly covering +// run of `T` values as `U` values yields valid `U` values. VeriFast's RustBelt model cannot express +// bit-level validity across types, so this is an abstract fact that the caller must establish. +// `as_simd`/`as_simd_mut` carry it as an explicit precondition of their wrappers. +fix valid_slice_transmute() -> bool; + +lem close_slice_triple_own<'a, T, U>(t: thread_id_t, v: (&'a [T], &'a [U], &'a [T])) + req [_](<[T]>.share('a, t, v.0)) &*& [_](<[U]>.share('a, t, v.1)) &*& [_](<[T]>.share('a, t, v.2)); + ens <(&'a [T], &'a [U], &'a [T])>.own(t, v); +{ + // https://github.com/verifast/verifast/issues/1049 + assume(false); +} + +lem close_mut_slice_triple_own<'a, T, U>(t: thread_id_t, v: (&'a mut [T], &'a mut [U], &'a mut [T])) + req full_borrow('a, <[T]>.full_borrow_content(t, v.0)) &*& full_borrow('a, <[U]>.full_borrow_content(t, v.1)) &*& full_borrow('a, <[T]>.full_borrow_content(t, v.2)); + ens <(&'a mut [T], &'a mut [U], &'a mut [T])>.own(t, v); +{ + // https://github.com/verifast/verifast/issues/1049 + assume(false); +} + +// The "transmute" step of `align_to`/`align_to_mut`: a run of `n` `T` values at `p`, aligned for `U` +// and covering exactly `mid.len()` `U` values byte for byte, is reinterpreted as the `[U]` slice `mid`. +// Everything else `align_to` relies on (the prefix/suffix split of `rest`, the byte-exact coverage +// computed by `align_to_offsets`, the alignment produced by `align_offset`) is proved at the call +// sites; only the validity of the `U` values so obtained, `valid_slice_transmute`, is the caller's +// obligation, as `align_to`'s `# Safety` section states. +lem share_transmute_prefix(k: lifetime_t, t: thread_id_t, p: *T, n: usize, mid: *[U]) + req [?f]array_share::(k, t, p, n) &*& valid_slice_transmute::() == true &*& + std::mem::size_of::() > 0 &*& std::mem::size_of::() > 0 &*& + strip_pointer_metadata(mid as pointer) as *U == p as *U &*& + mid.len() * std::mem::size_of::() == n * std::mem::size_of::() &*& + (p as usize) % std::mem::align_of::() == 0; + ens [_](<[U]>.share(k, t, mid)); +{ + assume(false); +} + +lem full_borrow_transmute_prefix(k: lifetime_t, t: thread_id_t, p: *[T], mid: *[U]) + req full_borrow(k, <[T]>.full_borrow_content(t, p)) &*& valid_slice_transmute::() == true &*& + std::mem::size_of::() > 0 &*& std::mem::size_of::() > 0 &*& + strip_pointer_metadata(mid as pointer) as *U == (strip_pointer_metadata(p as pointer) as *T) as *U &*& + mid.len() * std::mem::size_of::() == p.len() * std::mem::size_of::() &*& + ((strip_pointer_metadata(p as pointer) as *T) as usize) % std::mem::align_of::() == 0; + ens full_borrow(k, <[U]>.full_borrow_content(t, mid)); +{ + assume(false); +} + +lem_auto(pointer_metadata_as_usize(m)) pointer_metadata_as_usize_limits(m: pointer_metadata) + req true; + ens 0 <= pointer_metadata_as_usize(m) && pointer_metadata_as_usize(m) <= usize::MAX; +{ + assume(false); +} + +lem array_share_split(k: lifetime_t, t: thread_id_t, l: *T, length: usize, mid: usize) + req [_]array_share::(k, t, l, length) &*& 0 <= mid &*& mid <= length; + ens array_share::(k, t, l, mid) &*& array_share::(k, t, l + mid, length - mid); +{ + if mid == 0 { + close array_share::(k, t, l, 0); + open array_share::(k, t, l, length); + close array_share::(k, t, l, length); + } else { + open array_share::(k, t, l, length); + array_share_split::(k, t, l + 1, length - 1, mid - 1); + leak array_share::(k, t, l + 1, mid - 1); + close array_share::(k, t, l, mid); + } +} + +// Associativity of multiplication. VeriFast's Redux prover handles commutativity and +// distributivity of `*` but not associativity of products of three symbolic factors, and the Rust +// prelude ships no such lemma, so it is stated here as an arithmetic axiom. +lem mul_assoc(a: i32, b: i32, c: i32) + req true; + ens a * (b * c) == (a * b) * c; +{ + // https://github.com/verifast/verifast/issues/1052 + assume(false); +} + +lem ptr_range_split_limits(ptr: *T, len: usize, mid: usize) + req 0 <= mid &*& mid <= len &*& len * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(ptr) == true &*& pointer_within_limits(ptr + len) == true; + ens mid * std::mem::size_of::() <= isize::MAX &*& (len - mid) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(ptr + mid) == true &*& ((ptr + mid) + (len - mid)) == ptr + len &*& ((ptr + len) - (len - mid)) == ptr + mid; +{ + std::alloc::is_valid_layout_size_of_align_of::(); + mul_mono_l(0, mid, std::mem::size_of::()); + mul_mono_l(mid, len, std::mem::size_of::()); + mul_mono_l(0, len - mid, std::mem::size_of::()); + mul_mono_l(len - mid, len, std::mem::size_of::()); +} + +// Splits a mutable slice borrow at `mid` into two contiguous sub-borrows (the ghost core of +// `split_at_mut_unchecked`, usable from other proofs). +lem slice_full_borrow_split(k: lifetime_t, t: thread_id_t, s: *[T], mid: usize) + nonghost_callers_only + req full_borrow(k, <[T]>.full_borrow_content(t, s)) &*& [?q]lifetime_token(k) &*& 0 <= mid &*& mid <= s.len(); + ens [q]lifetime_token(k) &*& + full_borrow(k, <[T]>.full_borrow_content(t, ptr::mk_slice::(strip_pointer_metadata(s as pointer) as *T, mid))) &*& + full_borrow(k, <[T]>.full_borrow_content(t, ptr::mk_slice::((strip_pointer_metadata(s as pointer) as *T) + mid, s.len() - mid))); +{ + let ptr = strip_pointer_metadata(s as pointer) as *T; + let len = s.len(); + open_full_borrow_strong_(k, <[T]>.full_borrow_content(t, s)); + open slice_full_borrow_content::(t, s)(); + assert array::(ptr, len, ?elems) &*& foreach(elems, own::(t)); + ptr_range_split_limits::(ptr, len, mid); + let r0 = ptr::mk_slice::(ptr, mid); + let r1 = ptr::mk_slice::(ptr + mid, len - mid); + array_split(ptr, mid); + foreach_split(elems, own::(t), mid); + close slice_full_borrow_content::(t, r0)(); + close slice_full_borrow_content::(t, r1)(); + close sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1))(); + produce_lem_ptr_chunk restore_full_borrow_(True, sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1)), <[T]>.full_borrow_content(t, s))() { + open True(); + open sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1))(); + open slice_full_borrow_content::(t, r0)(); + open slice_full_borrow_content::(t, r1)(); + assert array::(ptr, mid, ?elems0) &*& array::(ptr + mid, len - mid, ?elems1); + array_join(ptr); + foreach_append(elems0, elems1); + close slice_full_borrow_content::(t, s)(); + } { + close True(); + close_full_borrow_strong_(); + } + full_borrow_split(k, <[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1)); +} + +// `is_Copy::()` is established only through `copy_witness__VeriFast_wrapper::()`, +// whose `T: Copy` bound makes rustc reject any call site where `T` is not `Copy`. +fix is_Copy() -> bool; + +pred shared_slice_read_token(k: lifetime_t, src: *[T], f: real, elems: list); + +lem open_shared_slice_copy(k: lifetime_t, t: thread_id_t, src: *[T]) + req [_](<[T]>.share(k, t, src)) &*& [?q]lifetime_token(k) &*& is_Copy::() == true; + ens [q / 2]lifetime_token(k) &*& [?f](strip_pointer_metadata(src as pointer) as *T)[..src.len()] |-> ?elems &*& + foreach(elems, own::(t)) &*& shared_slice_read_token::(k, src, f, elems); +{ + // https://github.com/verifast/verifast/issues/1051 + assume(false); +} + +lem close_shared_slice_copy(k: lifetime_t, src: *[T]) + req shared_slice_read_token::(k, src, ?f, ?elems) &*& [f](strip_pointer_metadata(src as pointer) as *T)[..src.len()] |-> elems &*& [?q]lifetime_token(k); + ens [2 * q]lifetime_token(k); +{ + // https://github.com/verifast/verifast/issues/1051 + assume(false); +} + +lem copy_elem_own_dup(t: thread_id_t, v: T) + req (.own)(t, v) &*& is_Copy::() == true; + ens (.own)(t, v) &*& (.own)(t, v); +{ + // https://github.com/verifast/verifast/issues/1051 + assume(false); +} + +lem foreach_copy_dup(t: thread_id_t, xs: list) + req foreach(xs, own::(t)) &*& is_Copy::() == true; + ens foreach(xs, own::(t)) &*& foreach(xs, own::(t)); +{ + match xs { + nil => { + close foreach(nil, own::(t)); + } + cons(h, tl) => { + open foreach(xs, own::(t)); + open own::(t)(h); + copy_elem_own_dup::(t, h); + close own::(t)(h); + close own::(t)(h); + foreach_copy_dup::(t, tl); + close foreach(cons(h, tl), own::(t)); + close foreach(cons(h, tl), own::(t)); + } + } +} + +lem drop_drop(m: i32, n: i32, xs: list) + req 0 <= m &*& 0 <= n; + ens drop(m, drop(n, xs)) == drop(m + n, xs); +{ + match xs { + nil => {} + cons(h, tl) => { + if n == 0 { + } else { + drop_drop(m, n - 1, tl); + } + } + } +} + +lem copy_within_foreach_own(t: thread_id_t, elems: list, src_idx: usize, dst_idx: usize, count: usize) + req foreach(elems, own::(t)) &*& is_Copy::() == true &*& 0 <= count &*& 0 <= src_idx &*& src_idx + count <= length(elems) &*& 0 <= dst_idx &*& dst_idx + count <= length(elems); + ens foreach(append(take(dst_idx, elems), append(take(count, drop(src_idx, elems)), drop(dst_idx + count, elems))), own::(t)); +{ + foreach_copy_dup::(t, elems); + foreach_split(elems, own::(t), src_idx); + leak foreach(take(src_idx, elems), own::(t)); + foreach_split(drop(src_idx, elems), own::(t), count); + leak foreach(drop(count, drop(src_idx, elems)), own::(t)); + + foreach_split(elems, own::(t), dst_idx); + foreach_split(drop(dst_idx, elems), own::(t), count); + leak foreach(take(count, drop(dst_idx, elems)), own::(t)); + drop_drop(count, dst_idx, elems); + + foreach_append(take(count, drop(src_idx, elems)), drop(dst_idx + count, elems)); + foreach_append(take(dst_idx, elems), append(take(count, drop(src_idx, elems)), drop(dst_idx + count, elems))); +} + +lem foreach_extract(xs: list, p: pred(t), i: i32) + req foreach(xs, p) &*& 0 <= i &*& i < length(xs); + ens foreach(take(i, xs), p) &*& p(nth(i, xs)) &*& foreach(drop(i + 1, xs), p); +{ + match xs { + nil => {} + cons(h, tl) => { + open foreach(xs, p); + if i == 0 { + close foreach(nil, p); + } else { + foreach_extract(tl, p, i - 1); + close foreach(cons(h, take(i - 1, tl)), p); + } + } + } +} + +lem foreach_insert(xs: list, p: pred(t), i: i32, v: t) + req foreach(take(i, xs), p) &*& p(v) &*& foreach(drop(i + 1, xs), p) &*& 0 <= i &*& i < length(xs); + ens foreach(update(i, v, xs), p); +{ + match xs { + nil => {} + cons(h, tl) => { + open foreach(take(i, xs), p); + if i == 0 { + close foreach(update(0, v, xs), p); + } else { + foreach_insert(tl, p, i - 1, v); + close foreach(update(i, v, xs), p); + } + } + } +} + +lem swap_foreach_own(t: thread_id_t, xs: list, i: usize, ys: list, j: usize) + req foreach(xs, own::(t)) &*& foreach(ys, own::(t)) &*& 0 <= i &*& i < length(xs) &*& 0 <= j &*& j < length(ys); + ens foreach(update(i, nth(j, ys), xs), own::(t)) &*& foreach(update(j, nth(i, xs), ys), own::(t)); +{ + foreach_extract(xs, own::(t), i); + foreach_extract(ys, own::(t), j); + foreach_insert(xs, own::(t), i, nth(j, ys)); + foreach_insert(ys, own::(t), j, nth(i, xs)); +} + +lem array_swap_elems(t: thread_id_t, pa: *T, i: usize, pb: *T, j: usize, n: usize) + req pa[..n] |-> ?elems_a &*& foreach(elems_a, own::(t)) &*& pb[..n] |-> ?elems_b &*& foreach(elems_b, own::(t)) &*& 0 <= i &*& i < n &*& 0 <= j &*& j < n; + ens pa[..i] |-> take(i, elems_a) &*& *(pa + i) |-> nth(i, elems_a) &*& (pa + i + 1)[..n - i - 1] |-> drop(i + 1, elems_a) &*& + pb[..j] |-> take(j, elems_b) &*& *(pb + j) |-> nth(j, elems_b) &*& (pb + j + 1)[..n - j - 1] |-> drop(j + 1, elems_b) &*& + foreach(take(i, elems_a), own::(t)) &*& own::(t)(nth(i, elems_a)) &*& foreach(drop(i + 1, elems_a), own::(t)) &*& + foreach(take(j, elems_b), own::(t)) &*& own::(t)(nth(j, elems_b)) &*& foreach(drop(j + 1, elems_b), own::(t)) &*& + length(elems_a) == n &*& length(elems_b) == n; +{ + array_extract_elem(pa, i); + foreach_split(elems_a, own::(t), i); + drop_n_plus_one(i, elems_a); + open foreach(drop(i, elems_a), own::(t)); + array_extract_elem(pb, j); + foreach_split(elems_b, own::(t), j); + drop_n_plus_one(j, elems_b); + open foreach(drop(j, elems_b), own::(t)); +} + +lem array_unswap_elems(t: thread_id_t, pa: *T, i: usize, pb: *T, j: usize, n: usize, elems_a: list, elems_b: list) + req pa[..i] |-> take(i, elems_a) &*& *(pa + i) |-> ?va &*& (pa + i + 1)[..n - i - 1] |-> drop(i + 1, elems_a) &*& + pb[..j] |-> take(j, elems_b) &*& *(pb + j) |-> ?vb &*& (pb + j + 1)[..n - j - 1] |-> drop(j + 1, elems_b) &*& + foreach(take(i, elems_a), own::(t)) &*& own::(t)(va) &*& foreach(drop(i + 1, elems_a), own::(t)) &*& + foreach(take(j, elems_b), own::(t)) &*& own::(t)(vb) &*& foreach(drop(j + 1, elems_b), own::(t)) &*& + 0 <= i &*& i < n &*& 0 <= j &*& j < n &*& length(elems_a) == n &*& length(elems_b) == n; + ens pa[..n] |-> update(i, va, elems_a) &*& foreach(update(i, va, elems_a), own::(t)) &*& + pb[..n] |-> update(j, vb, elems_b) &*& foreach(update(j, vb, elems_b), own::(t)); +{ + array_insert_elem(pa, i, n, elems_a); + close foreach(cons(va, drop(i + 1, elems_a)), own::(t)); + foreach_append(take(i, elems_a), cons(va, drop(i + 1, elems_a))); + append_take_cons_drop_update(elems_a, i, va); + array_insert_elem(pb, j, n, elems_b); + close foreach(cons(vb, drop(j + 1, elems_b)), own::(t)); + foreach_append(take(j, elems_b), cons(vb, drop(j + 1, elems_b))); + append_take_cons_drop_update(elems_b, j, vb); +} + +pred array_two_extracted(t: thread_id_t, ptr: *T, i: usize, j: usize, len: usize) = + exists(?elems) &*& length(elems) == len &*& + ptr[..i] |-> take(i, take(j, elems)) &*& + (ptr + i + 1)[..j - i - 1] |-> drop(i + 1, take(j, elems)) &*& + (ptr + j + 1)[..len - j - 1] |-> drop(j + 1, elems) &*& + foreach(take(i, take(j, elems)), own::(t)) &*& + foreach(drop(i + 1, take(j, elems)), own::(t)) &*& + foreach(drop(j + 1, elems), own::(t)); + +lem array_extract_two_own(t: thread_id_t, ptr: *T, i: usize, j: usize, len: usize) + req ptr[..len] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 <= i &*& i < j &*& j < len; + ens *(ptr + i) |-> ?vi &*& (.own)(t, vi) &*& *(ptr + j) |-> ?vj &*& (.own)(t, vj) &*& array_two_extracted::(t, ptr, i, j, len); +{ + array_extract_elem(ptr, j); + array_extract_elem(ptr, i); + foreach_extract(elems, own::(t), j); + open own::(t)(nth(j, elems)); + foreach_extract(take(j, elems), own::(t), i); + open own::(t)(nth(i, take(j, elems))); + close exists(elems); + close array_two_extracted::(t, ptr, i, j, len); +} + +lem array_insert_two_own(t: thread_id_t, ptr: *T, i: usize, j: usize, len: usize) + req array_two_extracted::(t, ptr, i, j, len) &*& *(ptr + i) |-> ?vi &*& (.own)(t, vi) &*& *(ptr + j) |-> ?vj &*& (.own)(t, vj) &*& 0 <= i &*& i < j &*& j < len; + ens ptr[..len] |-> ?elems1 &*& foreach(elems1, own::(t)); +{ + open array_two_extracted::(t, ptr, i, j, len); + open exists(?elems); + close own::(t)(vi); + close own::(t)(vj); + foreach_insert(take(j, elems), own::(t), i, vi); + array_insert_elem(ptr, i, j, take(j, elems)); + close array(ptr + j, len - j, cons(vj, drop(j + 1, elems))); + array_join(ptr); + close foreach(cons(vj, drop(j + 1, elems)), own::(t)); + foreach_append(update(i, vi, take(j, elems)), cons(vj, drop(j + 1, elems))); +} + +// `Chunk` is `[T; n]`, or a type with the same layout *and* validity invariant as `[T; n]` +// (`Simd`, `#[repr(simd)]` over `[T; n]`). Abstract on purpose: a type that merely has the +// layout of `[T; n]` (say, a `bool` for `[u8; 1]`) must not satisfy it, because the chunk lemmas below +// reinterpret ownership of `n` `T`s as ownership of a `Chunk`. It is established only at the +// (const-generic, transcribed) call sites, where `Chunk` is literally `[T; N]` or `Simd`. +fix is_array_of(n: usize) -> bool; + +lem is_array_of_layout(n: usize) + req is_array_of::(n) == true; + ens 0 <= n &*& std::mem::size_of::() == n * std::mem::size_of::() &*& std::mem::align_of::() == std::mem::align_of::(); +{ + // Layout of `[T; n]` (and of `#[repr(simd)]` `Simd`), see the Rust reference. + assume(false); +} + + +lem share_slice_prefix_as_chunk(k: lifetime_t, t: thread_id_t, s: *[T], n: usize) + req [_](<[T]>.share(k, t, s)) &*& is_array_of::(n) == true &*& n <= s.len(); + ens [_](.share(k, t, (strip_pointer_metadata(s as pointer) as *T) as *Chunk)); +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem full_borrow_slice_prefix_as_chunk(k: lifetime_t, t: thread_id_t, s: *[T], n: usize) + req full_borrow(k, <[T]>.full_borrow_content(t, s)) &*& is_array_of::(n) == true &*& n <= s.len(); + ens full_borrow(k, .full_borrow_content(t, (strip_pointer_metadata(s as pointer) as *T) as *Chunk)); +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem share_slice_as_chunks(k: lifetime_t, t: thread_id_t, s: *[T], n: usize, new_len: usize) + req [_](<[T]>.share(k, t, s)) &*& is_array_of::(n) == true &*& n > 0 &*& s.len() == new_len * n; + ens [_](<[Chunk]>.share(k, t, ptr::mk_slice::((strip_pointer_metadata(s as pointer) as *T) as *Chunk, new_len))) &*& + new_len * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *T) as *Chunk) == true &*& + pointer_within_limits(((strip_pointer_metadata(s as pointer) as *T) as *Chunk) + new_len) == true; +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem full_borrow_slice_as_chunks(k: lifetime_t, t: thread_id_t, s: *[T], n: usize, new_len: usize) + req full_borrow(k, <[T]>.full_borrow_content(t, s)) &*& is_array_of::(n) == true &*& n > 0 &*& s.len() == new_len * n; + ens full_borrow(k, <[Chunk]>.full_borrow_content(t, ptr::mk_slice::((strip_pointer_metadata(s as pointer) as *T) as *Chunk, new_len))) &*& + new_len * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *T) as *Chunk) == true &*& + pointer_within_limits(((strip_pointer_metadata(s as pointer) as *T) as *Chunk) + new_len) == true; +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem share_chunks_as_flattened(k: lifetime_t, t: thread_id_t, s: *[Chunk], n: usize, len: usize) + req [_](<[Chunk]>.share(k, t, s)) &*& is_array_of::(n) == true &*& len == s.len() * n &*& len <= usize::MAX; + ens [_](<[Elem]>.share(k, t, ptr::mk_slice::((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem, len))) &*& + len * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem) == true &*& + pointer_within_limits(((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem) + len) == true; +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem full_borrow_chunks_as_flattened(k: lifetime_t, t: thread_id_t, s: *[Chunk], n: usize, len: usize) + req full_borrow(k, <[Chunk]>.full_borrow_content(t, s)) &*& is_array_of::(n) == true &*& len == s.len() * n &*& len <= usize::MAX; + ens full_borrow(k, <[Elem]>.full_borrow_content(t, ptr::mk_slice::((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem, len))) &*& + len * std::mem::size_of::() <= isize::MAX &*& + pointer_within_limits((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem) == true &*& + pointer_within_limits(((strip_pointer_metadata(s as pointer) as *Chunk) as *Elem) + len) == true; +{ + // https://github.com/verifast/verifast/pull/1048 + assume(false); +} + +lem flatten_non_zst_no_overflow(k: lifetime_t, t: thread_id_t, s: *[Chunk], n: usize) + req is_array_of::(n) == true &*& std::mem::size_of::() > 0 &*& s.len() * std::mem::size_of::() <= isize::MAX; + ens s.len() * n <= usize::MAX; +{ + is_array_of_layout::(n); + mul_mono_l(1, std::mem::size_of::(), n); + mul_mono_l(n, std::mem::size_of::(), s.len()); +} + +lem chunk_round_down_facts(len: usize, n: usize) + req 0 <= len &*& n > 0; + ens 0 <= (len / n) * n &*& (len / n) * n <= len &*& ((len / n) * n) % n == 0 &*& ((len / n) * n) / n == len / n &*& len - (len / n) * n == len % n &*& len % n < n; +{ + div_rem_nonneg(len, n); + mul_mono_l(0, len / n, n); + div_rem_nonneg_unique((len / n) * n, n, len / n, 0); +} +@*/ + +/// Ties the ghost fact `is_Copy::()` to the real `T: Copy` bound: this function can only be +/// called where rustc can prove `T: Copy`. Its body is empty, so the refinement checker inlines +/// it to nothing. +const unsafe fn copy_witness__VeriFast_wrapper() +//@ req true; +//@ ens is_Copy::() == true; +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1051 +//@ assume_correct +{ +} + +const unsafe fn revswap_proof__VeriFast_wrapper(a: &mut [T], b: &mut [T], n: usize) +/*@ +req thread_token(?t) &*& + (strip_pointer_metadata(a as pointer) as *T)[..n] |-> ?elems_a &*& foreach(elems_a, own::(t)) &*& a.len() == n &*& + (strip_pointer_metadata(b as pointer) as *T)[..n] |-> ?elems_b &*& foreach(elems_b, own::(t)) &*& b.len() == n; +@*/ +/*@ +ens thread_token(t) &*& + (strip_pointer_metadata(a as pointer) as *T)[..n] |-> ?elems_a1 &*& foreach(elems_a1, own::(t)) &*& + (strip_pointer_metadata(b as pointer) as *T)[..n] |-> ?elems_b1 &*& foreach(elems_b1, own::(t)); +@*/ +//@ on_unwind_ens false; +{ + //@ let ptr_a = strip_pointer_metadata(a as pointer) as *T; + //@ let ptr_b = strip_pointer_metadata(b as pointer) as *T; + // The two `debug_assert!(a.len() == n)` / `debug_assert!(b.len() == n)` of `revswap` are omitted here: + // `cfg!(debug_assertions)` is false in this build, so their bodies are dead code to VeriFast + // (the only `-allow_dead_code` reports of the proof); `a.len() == n` and `b.len() == n` are preconditions. + + //@ let k = begin_lifetime(); + //@ close slice_full_borrow_content::(t, a)(); + //@ borrow(k, <[T]>.full_borrow_content(t, a)); + //@ close slice_full_borrow_content::(t, b)(); + //@ borrow(k, <[T]>.full_borrow_content(t, b)); + let (a1, _) = a.split_at_mut(n); + //@ assert std_tuple_2__0(?tup1_addr, ?a1_val); + let (b1, _) = b.split_at_mut(n); + //@ assert std_tuple_2__0(tup1_addr, a1_val) &*& std_tuple_2__0(?tup2_addr, ?b1_val); + + let mut i = 0; + //@ end_lifetime(k); + //@ borrow_end(k, <[T]>.full_borrow_content(t, a)); + //@ open slice_full_borrow_content::(t, a)(); + //@ borrow_end(k, <[T]>.full_borrow_content(t, b)); + //@ open slice_full_borrow_content::(t, b)(); + //@ leak full_borrow(_, _); + //@ leak full_borrow(_, _); + //@ leak full_borrow(_, _); + //@ leak full_borrow(_, _); + #[safety::loop_invariant(i <= n)] + #[cfg_attr(kani, + kani::loop_modifies( + unsafe {slice::from_raw_parts_mut(a1.as_mut_ptr(), n)}, + unsafe {slice::from_raw_parts_mut(b1.as_mut_ptr(), n)}, + &i) + )] + while i < n { + /*@ + inv thread_token(t) &*& lifetime_token(func_lft) &*& + std_tuple_2__0(tup1_addr, a1_val) &*& std_tuple_2__1(tup1_addr, _) &*& struct_std_tuple_2__padding(tup1_addr) &*& + std_tuple_2__0(tup2_addr, b1_val) &*& std_tuple_2__1(tup2_addr, _) &*& struct_std_tuple_2__padding(tup2_addr) &*& + 0 <= i &*& i < n &*& + a1.len() == n &*& b1.len() == n &*& + a1_val.len() == n &*& b1_val.len() == n &*& + strip_pointer_metadata(a1 as pointer) as *T == ptr_a &*& + strip_pointer_metadata(b1 as pointer) as *T == ptr_b &*& + strip_pointer_metadata(a1_val as pointer) as *T == ptr_a &*& + strip_pointer_metadata(b1_val as pointer) as *T == ptr_b &*& + ptr_a[..n] |-> ?cur_a &*& foreach(cur_a, own::(t)) &*& + ptr_b[..n] |-> ?cur_b &*& foreach(cur_b, own::(t)); + @*/ + // `&mut a[i]` / `&mut b[n - 1 - i]` of `revswap`, as element pointers into the two arrays (the bounds + // `i < n`, `n - 1 - i < n` are the loop invariant; `revswap`'s index operations are panicking checks). + //@ ptr_range_split_limits::(ptr_a, n, i); + //@ ptr_range_split_limits::(ptr_b, n, n - 1 - i); + let pa: *mut T = unsafe { a1.as_mut_ptr().add(i) }; + let pb: *mut T = unsafe { b1.as_mut_ptr().add(n - 1 - i) }; + //@ array_swap_elems(t, ptr_a, i, ptr_b, n - 1 - i, n); + mem::swap(unsafe { &mut *pa }, unsafe { &mut *pb }); + //@ array_unswap_elems(t, ptr_a, i, ptr_b, n - 1 - i, n, cur_a, cur_b); + i += 1; + } +} + +unsafe fn slice_range__VeriFast_wrapper>(src: R, len: usize) -> Range +//@ req thread_token(?t) &*& (.own)(t, src); +//@ ens thread_token(t) &*& 0 <= result.start &*& result.start <= result.end &*& result.end <= len; +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + slice::range(src, ..len) +} + +unsafe fn empty_slice__VeriFast_wrapper<'a, T>(s: &'a [T; 0]) -> &'a [T] +where + 'a: 'a, +//@ req thread_token(?t) &*& [?q]lifetime_token(?a); +//@ ens thread_token(t) &*& [q]lifetime_token(a) &*& [_](<[T]>.share(a, t, result)); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + s +} + +unsafe fn empty_mut_slice_arg__VeriFast_wrapper<'a, T>(s: &'a mut [T; 0]) -> &'a mut [T] +where + 'a: 'a, +//@ req thread_token(?t) &*& [?q]lifetime_token(?a); +//@ ens thread_token(t) &*& [q]lifetime_token(a) &*& full_borrow(a, <[T]>.full_borrow_content(t, result)); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + return s; +} + +unsafe fn call_same_bucket__VeriFast_wrapper<'a, 'b, 'c, T, F>( + x: &'b mut T, + p: &'c mut T, + same_bucket: &'a mut F, +) -> bool +where + F: FnMut(&mut T, &mut T) -> bool, +//@ req thread_token(?t) &*& *same_bucket |-> ?sb0 &*& (.own)(t, sb0) &*& *x |-> ?vx &*& (.own)(t, vx) &*& *p |-> ?vp &*& (.own)(t, vp); +//@ ens thread_token(t) &*& *same_bucket |-> ?sb1 &*& (.own)(t, sb1) &*& *x |-> ?vx1 &*& (.own)(t, vx1) &*& *p |-> ?vp1 &*& (.own)(t, vp1); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + same_bucket(x, p) +} + +const unsafe fn exact_div_usize__VeriFast_wrapper(x: usize, y: usize) -> usize +//@ req y != 0 &*& x % y == 0; +//@ ens result == x / y; +//@ on_unwind_ens false; +{ + unsafe { exact_div(x, y) } +} + +impl [T] { + /// Returns the number of elements in the slice. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert_eq!(a.len(), 3); + /// ``` + #[lang = "slice_len_fn"] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + pub const fn len(&self) -> usize + //@ req true; + //@ ens result == self.len() &*& 0 <= result &*& result <= usize::MAX; + //@ on_unwind_ens false; + { + ptr::metadata(self) + } + + /// Returns `true` if the slice has a length of 0. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert!(!a.is_empty()); + /// + /// let b: &[i32] = &[]; + /// assert!(b.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.39.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + pub const fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&10), v.first()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.first()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn first(&self) -> Option<&T> { + if let [first, ..] = self { Some(first) } else { None } + } + + /// Returns a mutable reference to the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(first) = x.first_mut() { + /// *first = 5; + /// } + /// assert_eq!(x, &[5, 1, 2]); + /// + /// let y: &mut [i32] = &mut []; + /// assert_eq!(None, y.first_mut()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn first_mut(&mut self) -> Option<&mut T> { + if let [first, ..] = self { Some(first) } else { None } + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first() { + /// assert_eq!(first, &0); + /// assert_eq!(elements, &[1, 2]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn split_first(&self) -> Option<(&T, &[T])> { + if let [first, tail @ ..] = self { Some((first, tail)) } else { None } + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_mut() { + /// *first = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[3, 4, 5]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if let [first, tail @ ..] = self { Some((first, tail)) } else { None } + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last() { + /// assert_eq!(last, &2); + /// assert_eq!(elements, &[0, 1]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn split_last(&self) -> Option<(&T, &[T])> { + if let [init @ .., last] = self { Some((last, init)) } else { None } + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last_mut() { + /// *last = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[4, 5, 3]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if let [init @ .., last] = self { Some((last, init)) } else { None } + } + + /// Returns the last element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&30), v.last()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.last()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] + #[inline] + #[must_use] + pub const fn last(&self) -> Option<&T> { + if let [.., last] = self { Some(last) } else { None } + } + + /// Returns a mutable reference to the last item in the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(last) = x.last_mut() { + /// *last = 10; + /// } + /// assert_eq!(x, &[0, 1, 10]); + /// + /// let y: &mut [i32] = &mut []; + /// assert_eq!(None, y.last_mut()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_first_last", since = "1.83.0")] + #[inline] + #[must_use] + pub const fn last_mut(&mut self) -> Option<&mut T> { + if let [.., last] = self { Some(last) } else { None } + } + + /// Returns an array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let u = [10, 40, 30]; + /// assert_eq!(Some(&[10, 40]), u.first_chunk::<2>()); + /// + /// let v: &[i32] = &[10]; + /// assert_eq!(None, v.first_chunk::<2>()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(Some(&[]), w.first_chunk::<0>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn first_chunk(&self) -> Option<&[T; N]> { + if self.len() < N { + None + } else { + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the reference outlive the slice. + Some(unsafe { &*(self.as_ptr().cast_array()) }) + } + } + + /// Returns a mutable array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(first) = x.first_chunk_mut::<2>() { + /// first[0] = 5; + /// first[1] = 4; + /// } + /// assert_eq!(x, &[5, 4, 2]); + /// + /// assert_eq!(None, x.first_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn first_chunk_mut(&mut self) -> Option<&mut [T; N]> { + if self.len() < N { + None + } else { + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and require exclusive access to the entire slice to mutate the chunk. + Some(unsafe { &mut *(self.as_mut_ptr().cast_array()) }) + } + } + + /// Returns an array reference to the first `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_chunk::<2>() { + /// assert_eq!(first, &[0, 1]); + /// assert_eq!(elements, &[2]); + /// } + /// + /// assert_eq!(None, x.split_first_chunk::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_first_chunk(&self) -> Option<(&[T; N], &[T])> { + let Some((first, tail)) = self.split_at_checked(N) else { return None }; + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some((unsafe { &*(first.as_ptr().cast_array()) }, tail)) + } + + /// Returns a mutable array reference to the first `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_chunk_mut::<2>() { + /// first[0] = 3; + /// first[1] = 4; + /// elements[0] = 5; + /// } + /// assert_eq!(x, &[3, 4, 5]); + /// + /// assert_eq!(None, x.split_first_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_first_chunk_mut( + &mut self, + ) -> Option<(&mut [T; N], &mut [T])> { + let Some((first, tail)) = self.split_at_mut_checked(N) else { return None }; + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and enforce exclusive mutability of the chunk by the split. + Some((unsafe { &mut *(first.as_mut_ptr().cast_array()) }, tail)) + } + + /// Returns an array reference to the last `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((elements, last)) = x.split_last_chunk::<2>() { + /// assert_eq!(elements, &[0]); + /// assert_eq!(last, &[1, 2]); + /// } + /// + /// assert_eq!(None, x.split_last_chunk::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_last_chunk(&self) -> Option<(&[T], &[T; N])> { + let Some(index) = self.len().checked_sub(N) else { return None }; + let (init, last) = self.split_at(index); + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some((init, unsafe { &*(last.as_ptr().cast_array()) })) + } + + /// Returns a mutable array reference to the last `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((elements, last)) = x.split_last_chunk_mut::<2>() { + /// last[0] = 3; + /// last[1] = 4; + /// elements[0] = 5; + /// } + /// assert_eq!(x, &[5, 3, 4]); + /// + /// assert_eq!(None, x.split_last_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_last_chunk_mut( + &mut self, + ) -> Option<(&mut [T], &mut [T; N])> { + let Some(index) = self.len().checked_sub(N) else { return None }; + let (init, last) = self.split_at_mut(index); + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and enforce exclusive mutability of the chunk by the split. + Some((init, unsafe { &mut *(last.as_mut_ptr().cast_array()) })) + } + + /// Returns an array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let u = [10, 40, 30]; + /// assert_eq!(Some(&[40, 30]), u.last_chunk::<2>()); + /// + /// let v: &[i32] = &[10]; + /// assert_eq!(None, v.last_chunk::<2>()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(Some(&[]), w.last_chunk::<0>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_last_chunk", since = "1.80.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn last_chunk(&self) -> Option<&[T; N]> { + // FIXME(const-hack): Without const traits, we need this instead of `get`. + let Some(index) = self.len().checked_sub(N) else { return None }; + let (_, last) = self.split_at(index); + + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the references outlive the slice. + Some(unsafe { &*(last.as_ptr().cast_array()) }) + } + + /// Returns a mutable array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(last) = x.last_chunk_mut::<2>() { + /// last[0] = 10; + /// last[1] = 20; + /// } + /// assert_eq!(x, &[0, 10, 20]); + /// + /// assert_eq!(None, x.last_chunk_mut::<4>()); + /// ``` + #[inline] + #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "1.83.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn last_chunk_mut(&mut self) -> Option<&mut [T; N]> { + // FIXME(const-hack): Without const traits, we need this instead of `get`. + let Some(index) = self.len().checked_sub(N) else { return None }; + let (_, last) = self.split_at_mut(index); + + // SAFETY: We explicitly check for the correct number of elements, + // do not let the reference outlive the slice, + // and require exclusive access to the entire slice to mutate the chunk. + Some(unsafe { &mut *(last.as_mut_ptr().cast_array()) }) + } + + const unsafe fn first_chunk_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> Option<&'a Chunk> + //@ req [_](<[T]>.share('a, ?t, self)) &*& is_array_of::(n) == true; + //@ ens if self.len() < n { result == std::option::Option::None } else { result == std::option::Option::Some(?r) &*& [_](.share('a, t, r)) &*& r == (strip_pointer_metadata(self as pointer) as *T) as *Chunk }; + //@ on_unwind_ens false; + { + if self.len() < n { + None + } else { + //@ share_slice_prefix_as_chunk::('a, t, self, n); + Some(unsafe { &*(self.as_ptr() as *const Chunk) }) //~ignore_ref_creation + } + } + + const unsafe fn first_chunk_mut_proof__VeriFast_wrapper<'a, Chunk>(&'a mut self, n: usize) -> Option<&'a mut Chunk> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& if self.len() < n { result == std::option::Option::None &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) } else { result == std::option::Option::Some(?r) &*& full_borrow('a, .full_borrow_content(t, r)) &*& r == (strip_pointer_metadata(self as pointer) as *T) as *Chunk }; + //@ on_unwind_ens false; + { + if self.len() < n { + None + } else { + //@ full_borrow_slice_prefix_as_chunk::('a, t, self, n); + let ptr = self.as_mut_ptr(); + Some(unsafe { &mut *(ptr as *mut Chunk) }) + } + } + + const unsafe fn split_first_chunk_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> Option<(&'a Chunk, &'a [T])> + //@ req [_](<[T]>.share('a, ?t, self)) &*& is_array_of::(n) == true; + //@ ens if self.len() < n { result == std::option::Option::None } else { result == std::option::Option::Some(?p) &*& [_](.share('a, t, p.0)) &*& [_](<[T]>.share('a, t, p.1)) &*& p.1.len() == self.len() - n }; + //@ on_unwind_ens false; + { + let Some((first, tail)) = self.split_at_checked(n) else { return None }; + //@ share_slice_prefix_as_chunk::('a, t, first, n); + Some((unsafe { &*(first.as_ptr() as *const Chunk) }, tail)) //~ignore_ref_creation + } + + const unsafe fn split_first_chunk_mut_proof__VeriFast_wrapper<'a, Chunk>( + &'a mut self, + n: usize, + ) -> Option<(&'a mut Chunk, &'a mut [T])> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& if self.len() < n { result == std::option::Option::None &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) } else { result == std::option::Option::Some(?p) &*& full_borrow('a, .full_borrow_content(t, p.0)) &*& full_borrow('a, <[T]>.full_borrow_content(t, p.1)) &*& p.1.len() == self.len() - n }; + //@ on_unwind_ens false; + { + let Some((first, tail)) = self.split_at_mut_checked(n) else { return None }; + //@ full_borrow_slice_prefix_as_chunk::('a, t, first, n); + let ptr = first.as_mut_ptr(); + Some((unsafe { &mut *(ptr as *mut Chunk) }, tail)) + } + + const unsafe fn split_last_chunk_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> Option<(&'a [T], &'a Chunk)> + //@ req thread_token(?t) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& if self.len() < n { result == std::option::Option::None } else { result == std::option::Option::Some(?p) &*& [_](<[T]>.share('a, t, p.0)) &*& [_](.share('a, t, p.1)) &*& p.0.len() == self.len() - n }; + //@ on_unwind_ens false; + { + let Some(index) = self.len().checked_sub(n) else { return None }; + let (init, last) = self.split_at(index); + //@ share_slice_prefix_as_chunk::('a, t, last, n); + Some((init, unsafe { &*(last.as_ptr() as *const Chunk) })) //~ignore_ref_creation + } + + const unsafe fn split_last_chunk_mut_proof__VeriFast_wrapper<'a, Chunk>( + &'a mut self, + n: usize, + ) -> Option<(&'a mut [T], &'a mut Chunk)> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& if self.len() < n { result == std::option::Option::None &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) } else { result == std::option::Option::Some(?p) &*& full_borrow('a, <[T]>.full_borrow_content(t, p.0)) &*& full_borrow('a, .full_borrow_content(t, p.1)) &*& p.0.len() == self.len() - n }; + //@ on_unwind_ens false; + { + let Some(index) = self.len().checked_sub(n) else { return None }; + let (init, last) = self.split_at_mut(index); + //@ full_borrow_slice_prefix_as_chunk::('a, t, last, n); + let ptr = last.as_mut_ptr(); + Some((init, unsafe { &mut *(ptr as *mut Chunk) })) + } + + const unsafe fn last_chunk_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> Option<&'a Chunk> + //@ req thread_token(?t) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& if self.len() < n { result == std::option::Option::None } else { result == std::option::Option::Some(?r) &*& [_](.share('a, t, r)) &*& r == ((strip_pointer_metadata(self as pointer) as *T) + (self.len() - n)) as *Chunk }; + //@ on_unwind_ens false; + { + let Some(index) = self.len().checked_sub(n) else { return None }; + let (_, last) = self.split_at(index); + //@ share_slice_prefix_as_chunk::('a, t, last, n); + Some(unsafe { &*(last.as_ptr() as *const Chunk) }) //~ignore_ref_creation + } + + const unsafe fn last_chunk_mut_proof__VeriFast_wrapper<'a, Chunk>(&'a mut self, n: usize) -> Option<&'a mut Chunk> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& if self.len() < n { result == std::option::Option::None &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) } else { result == std::option::Option::Some(?r) &*& full_borrow('a, .full_borrow_content(t, r)) &*& r == ((strip_pointer_metadata(self as pointer) as *T) + (self.len() - n)) as *Chunk }; + //@ on_unwind_ens false; + { + let Some(index) = self.len().checked_sub(n) else { return None }; + let (_, last) = self.split_at_mut(index); + //@ leak full_borrow('a, _); + //@ full_borrow_slice_prefix_as_chunk::('a, t, last, n); + let ptr = last.as_mut_ptr(); + Some(unsafe { &mut *(ptr as *mut Chunk) }) + } + + /// Returns a reference to an element or subslice depending on the type of + /// index. + /// + /// - If given a position, returns a reference to the element at that + /// position or `None` if out of bounds. + /// - If given a range, returns the subslice corresponding to that range, + /// or `None` if out of bounds. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&40), v.get(1)); + /// assert_eq!(Some(&[10, 40][..]), v.get(0..2)); + /// assert_eq!(None, v.get(3)); + /// assert_eq!(None, v.get(0..4)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get(&self, index: I) -> Option<&I::Output> + where + I: [const] SliceIndex, + { + index.get(self) + } + + /// Returns a mutable reference to an element or subslice depending on the + /// type of index (see [`get`]) or `None` if the index is out of bounds. + /// + /// [`get`]: slice::get + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(elem) = x.get_mut(1) { + /// *elem = 42; + /// } + /// assert_eq!(x, &[0, 42, 2]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[rustc_no_writable] + pub const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where + I: [const] SliceIndex, + { + index.get_mut(self) + } + + /// Returns a reference to an element or subslice, without doing bounds + /// checking. + /// + /// For a safe alternative see [`get`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. + /// + /// You can think of this like `.get(index).unwrap_unchecked()`. It's UB + /// to call `.get_unchecked(len)`, even if you immediately convert to a + /// pointer. And it's UB to call `.get_unchecked(..len + 1)`, + /// `.get_unchecked(..=len)`, or similar. + /// + /// [`get`]: slice::get + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// + /// unsafe { + /// assert_eq!(x.get_unchecked(1), &2); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[track_caller] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, index)))] + pub const unsafe fn get_unchecked(&self, index: I) -> &I::Output + where + I: [const] SliceIndex, + //@ req thread_token(?t) &*& [_](<[T]>.share(?k, t, self)) &*& std::slice::SliceIndex_in_bounds::(index, self); + //@ ens thread_token(t) &*& [_](< >::Output>.share(k, t, result)); + //@ on_unwind_ens false; + { + // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`; + // the slice is dereferenceable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &*index.get_unchecked(self) } //~ignore_ref_creation + } + + /// Returns a mutable reference to an element or subslice, without doing + /// bounds checking. + /// + /// For a safe alternative see [`get_mut`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. + /// + /// You can think of this like `.get_mut(index).unwrap_unchecked()`. It's + /// UB to call `.get_unchecked_mut(len)`, even if you immediately convert + /// to a pointer. And it's UB to call `.get_unchecked_mut(..len + 1)`, + /// `.get_unchecked_mut(..=len)`, or similar. + /// + /// [`get_mut`]: slice::get_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// + /// unsafe { + /// let elem = x.get_unchecked_mut(1); + /// *elem = 13; + /// } + /// assert_eq!(x, &[1, 13, 4]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_no_implicit_autorefs] + #[inline] + #[must_use] + #[track_caller] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, index)))] + #[rustc_no_writable] + pub const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + where + I: [const] SliceIndex, + //@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, self)) &*& std::slice::SliceIndex_in_bounds::(index, self); + //@ ens thread_token(t) &*& full_borrow(k, < >::Output>.full_borrow_content(t, result)); + //@ on_unwind_ens false; + { + // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`; + // the slice is dereferenceable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &mut *index.get_unchecked_mut(self) } + } + + /// Returns a raw pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up dangling. + /// + /// The caller must also ensure that the memory the pointer (non-transitively) points to + /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer + /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`]. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let x_ptr = x.as_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// assert_eq!(x.get_unchecked(i), &*x_ptr.add(i)); + /// } + /// } + /// ``` + /// + /// [`as_mut_ptr`]: slice::as_mut_ptr + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] + #[rustc_never_returns_null_ptr] + #[rustc_as_ptr] + #[inline(always)] + #[must_use] + pub const fn as_ptr(&self) -> *const T + //@ req true; + //@ ens result == strip_pointer_metadata(self as pointer) as *T &*& result == self as *T; + //@ on_unwind_ens false; + { + self as *const [T] as *const T + } + + /// Returns an unsafe mutable pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up dangling. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// let x_ptr = x.as_mut_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// *x_ptr.add(i) += 2; + /// } + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[rustc_never_returns_null_ptr] + #[rustc_as_ptr] + #[inline(always)] + #[must_use] + #[rustc_no_writable] + pub const fn as_mut_ptr(&mut self) -> *mut T + //@ req true; + //@ ens result == strip_pointer_metadata(self as pointer) as *T &*& result == self as *T; + //@ on_unwind_ens false; + { + self as *mut [T] as *mut T + } + + /// Returns the two raw pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the slice. + /// + /// See [`as_ptr`] for warnings on using these pointers. The end pointer + /// requires extra caution, as it does not point to a valid element in the + /// slice. + /// + /// This function is useful for interacting with foreign interfaces which + /// use two pointers to refer to a range of elements in memory, as is + /// common in C++. + /// + /// It can also be useful to check if a pointer to an element refers to an + /// element of this slice: + /// + /// ``` + /// let a = [1, 2, 3]; + /// let x = &a[1] as *const _; + /// let y = &5 as *const _; + /// + /// assert!(a.as_ptr_range().contains(&x)); + /// assert!(!a.as_ptr_range().contains(&y)); + /// ``` + /// + /// [`as_ptr`]: slice::as_ptr + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[inline] + #[must_use] + pub const fn as_ptr_range(&self) -> Range<*const T> { + let start = self.as_ptr(); + // SAFETY: The `add` here is safe, because: + // + // - Both pointers are part of the same object, as pointing directly + // past the object also counts. + // + // - The size of the slice is never larger than `isize::MAX` bytes, as + // noted here: + // - https://github.com/rust-lang/unsafe-code-guidelines/issues/102#issuecomment-473340447 + // - https://doc.rust-lang.org/reference/behavior-considered-undefined.html + // - https://doc.rust-lang.org/core/slice/fn.from_raw_parts.html#safety + // (This doesn't seem normative yet, but the very same assumption is + // made in many places, including the Index implementation of slices.) + // + // - There is no wrapping around involved, as slices do not wrap past + // the end of the address space. + // + // See the documentation of [`pointer::add`]. + let end = unsafe { start.add(self.len()) }; + start..end + } + + /// Returns the two unsafe mutable pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the slice. + /// + /// See [`as_mut_ptr`] for warnings on using these pointers. The end + /// pointer requires extra caution, as it does not point to a valid element + /// in the slice. + /// + /// This function is useful for interacting with foreign interfaces which + /// use two pointers to refer to a range of elements in memory, as is + /// common in C++. + /// + /// [`as_mut_ptr`]: slice::as_mut_ptr + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[inline] + #[must_use] + pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> + //@ req self.len() * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(strip_pointer_metadata(self as pointer) as *T) == true &*& pointer_within_limits((strip_pointer_metadata(self as pointer) as *T) + self.len()) == true; + //@ ens result == std::ops::Range::<*T> { start: strip_pointer_metadata(self as pointer) as *T, end: (strip_pointer_metadata(self as pointer) as *T) + self.len() } &*& result.start == strip_pointer_metadata(self as pointer) as *T &*& result.start == self as *T &*& result.end == (strip_pointer_metadata(self as pointer) as *T) + self.len(); + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + close raw_ptr_own::()(_t, result.start); + close raw_ptr_own::()(_t, result.end); + close_Range_own::<*T>(_t, result); + } + @*/ + { + let start = self.as_mut_ptr(); + // SAFETY: See as_ptr_range() above for why `add` here is safe. + let end = unsafe { start.add(self.len()) }; + start..end + } + + /// Gets a reference to the underlying array. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] + #[inline] + #[must_use] + pub const fn as_array(&self) -> Option<&[T; N]> { + if self.len() == N { + let ptr = self.as_ptr().cast_array(); + + // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. + let me = unsafe { &*ptr }; + Some(me) + } else { + None + } + } + + /// Gets a mutable reference to the slice's underlying array. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[stable(feature = "core_slice_as_array", since = "1.93.0")] + #[rustc_const_stable(feature = "core_slice_as_array", since = "1.93.0")] + #[inline] + #[must_use] + pub const fn as_mut_array(&mut self) -> Option<&mut [T; N]> { + if self.len() == N { + let ptr = self.as_mut_ptr().cast_array(); + + // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. + let me = unsafe { &mut *ptr }; + Some(me) + } else { + None + } + } + + /// Swaps two elements in the slice. + /// + /// If `a` equals `b`, it's guaranteed that elements won't change value. + /// + /// # Arguments + /// + /// * a - The index of the first element + /// * b - The index of the second element + /// + /// # Panics + /// + /// Panics if `a` or `b` are out of bounds. + /// + /// # Examples + /// + /// ``` + /// let mut v = ["a", "b", "c", "d", "e"]; + /// v.swap(2, 4); + /// assert!(v == ["a", "b", "e", "d", "c"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_swap", since = "1.85.0")] + #[inline] + #[track_caller] + pub const fn swap(&mut self, a: usize, b: usize) { + // Bounds checks that panic exactly like indexing would. + let _ = &self[a]; + let _ = &self[b]; + // SAFETY: `a` and `b` were checked to be in bounds above. + unsafe { + self.swap_unchecked(a, b); + } + } + + /// Swaps two elements in the slice, without doing bounds checking. + /// + /// For a safe alternative see [`swap`]. + /// + /// # Arguments + /// + /// * a - The index of the first element + /// * b - The index of the second element + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]*. + /// The caller has to ensure that `a < self.len()` and `b < self.len()`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_swap_unchecked)] + /// + /// let mut v = ["a", "b", "c", "d"]; + /// // SAFETY: we know that 1 and 3 are both indices of the slice + /// unsafe { v.swap_unchecked(1, 3) }; + /// assert!(v == ["a", "d", "c", "b"]); + /// ``` + /// + /// [`swap`]: slice::swap + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_swap_unchecked", issue = "88539")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(a, "[0,self.len())")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(b, "[0,self.len())")))] + pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) + //@ req (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems &*& a < self.len() &*& b < self.len(); + //@ ens (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> update(a, nth(b, elems), update(b, nth(a, elems), elems)); + //@ on_unwind_ens false; + { + assert_unsafe_precondition!( + check_library_ub, + "slice::swap_unchecked requires that the indices are within the slice", + ( + len: usize = self.len(), + a: usize = a, + b: usize = b, + ) => a < len && b < len, + ); + + let ptr = self.as_mut_ptr(); + //@ let len = self.len(); + //@ ptr_range_split_limits::(ptr, len, a); + //@ ptr_range_split_limits::(ptr, len, b); + /*@ + if a == b { + array_extract_elem(ptr, a); + close std::ptr::opt_pointsto::(true, ptr + a, ptr + b, nth(a, elems), _); + } else if a < b { + array_extract_elem(ptr, b); + array_extract_elem(ptr, a); + close std::ptr::opt_pointsto::(false, ptr + a, ptr + b, nth(a, elems), _); + } else { + array_extract_elem(ptr, a); + array_extract_elem(ptr, b); + close std::ptr::opt_pointsto::(false, ptr + a, ptr + b, nth(a, elems), _); + } + @*/ + // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()` + unsafe { + ptr::swap(ptr.add(a), ptr.add(b)); + } + /*@ + if a == b { + array_insert_elem(ptr, a, len, elems); + update_overwrite(a, nth(a, elems), nth(a, elems), elems); + } else if a < b { + array_insert_elem(ptr, a, b, take(b, elems)); + take_update_lt(a, nth(b, elems), b, elems); + array_insert_elem(ptr, b, len, update(a, nth(b, elems), elems)); + update_comm(a, nth(b, elems), b, nth(a, elems), elems); + } else { + array_insert_elem(ptr, b, a, take(a, elems)); + take_update_lt(b, nth(a, elems), a, elems); + array_insert_elem(ptr, a, len, update(b, nth(a, elems), elems)); + } + @*/ + } + + /// Reverses the order of elements in the slice, in place. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 2, 3]; + /// v.reverse(); + /// assert!(v == [3, 2, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_reverse", since = "1.90.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub const fn reverse<'a>(&'a mut self) + //@ req thread_token(?t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems &*& foreach(elems, own::(t)); + //@ ens thread_token(t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems1 &*& foreach(elems1, own::(t)); + //@ on_unwind_ens false; + /*@ + safety_proof { + open_full_borrow(_q_a, 'a, slice_full_borrow_content::(_t, self)); + open slice_full_borrow_content::(_t, self)(); + call(); + close slice_full_borrow_content::(_t, self)(); + close_full_borrow(slice_full_borrow_content::(_t, self)); + leak full_borrow('a, slice_full_borrow_content::(_t, self)); + } + @*/ + { + //@ let ptr = strip_pointer_metadata(self as pointer) as *T; + //@ let len = self.len(); + let half_len = self.len() / 2; + //@ div_rem_nonneg(len, 2); + //@ ptr_range_split_limits::(ptr, len, half_len); + //@ ptr_range_split_limits::(ptr + half_len, len - half_len, len - 2 * half_len); + let Range { start, end } = self.as_mut_ptr_range(); + + // These slices will skip the middle item for an odd length, + // since that one doesn't need to move. + let (front_half, back_half) = + // SAFETY: Both are subparts of the original slice, so the memory + // range is valid, and they don't overlap because they're each only + // half (or less) of the original slice. + unsafe { + ( + slice::from_raw_parts_mut(start, half_len), + slice::from_raw_parts_mut(end.sub(half_len), half_len), + ) + }; + + // Introducing a function boundary here means that the two halves + // get `noalias` markers, allowing better optimization as LLVM + // knows that they're disjoint, unlike in the original slice. + //@ array_split(ptr, half_len); + //@ foreach_split(elems, own::(t), half_len); + //@ array_split(ptr + half_len, len - 2 * half_len); + //@ foreach_split(drop(half_len, elems), own::(t), len - 2 * half_len); + //@ assert (ptr + half_len)[..len - 2 * half_len] |-> ?elems_mid; + macro_rules! vf_revswap { + ($ghost:stmt; $a:ident, $b:ident, $n:ident) => {{ + $ghost + unsafe { revswap_proof__VeriFast_wrapper($a, $b, $n); } + }}; + ($a:ident, $b:ident, $n:ident) => { + revswap($a, $b, $n); + }; + } + vf_revswap!(/*@ assert true; @*/ front_half, back_half, half_len); + //@ assert ptr[..half_len] |-> ?elems_a1 &*& (ptr + len - half_len)[..half_len] |-> ?elems_b1; + //@ array_join(ptr + half_len); + //@ foreach_append(elems_mid, elems_b1); + //@ array_join(ptr); + //@ foreach_append(elems_a1, append(elems_mid, elems_b1)); + + #[inline] + const fn revswap(a: &mut [T], b: &mut [T], n: usize) { + debug_assert!(a.len() == n); + debug_assert!(b.len() == n); + + // Because this function is first compiled in isolation, + // this check tells LLVM that the indexing below is + // in-bounds. Then after inlining -- once the actual + // lengths of the slices are known -- it's removed. + // FIXME(const_trait_impl) replace with let (a, b) = (&mut a[..n], &mut b[..n]); + let (a, _) = a.split_at_mut(n); + let (b, _) = b.split_at_mut(n); + + let mut i = 0; + #[safety::loop_invariant(i <= n)] + #[cfg_attr(kani, + kani::loop_modifies( + unsafe {slice::from_raw_parts_mut(a.as_mut_ptr(), n)}, + unsafe {slice::from_raw_parts_mut(b.as_mut_ptr(), n)}, + &i) + )] + while i < n { + mem::swap(&mut a[i], &mut b[n - 1 - i]); + i += 1; + } + } + } + + /// Returns an iterator over the slice. + /// + /// The iterator yields all items from start to end. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let mut iterator = x.iter(); + /// + /// assert_eq!(iterator.next(), Some(&1)); + /// assert_eq!(iterator.next(), Some(&2)); + /// assert_eq!(iterator.next(), Some(&4)); + /// assert_eq!(iterator.next(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[rustc_diagnostic_item = "slice_iter"] + pub const fn iter(&self) -> Iter<'_, T> { + Iter::new(self) + } + + /// Returns an iterator that allows modifying each value. + /// + /// The iterator yields all items from start to end. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// for elem in x.iter_mut() { + /// *elem += 2; + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut::new(self) + } + + /// Returns an iterator over all contiguous windows of length + /// `size`. The windows overlap. If the slice is shorter than + /// `size`, the iterator returns no values. + /// + /// # Panics + /// + /// Panics if `size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.windows(3); + /// assert_eq!(iter.next().unwrap(), &['l', 'o', 'r']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e', 'm']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the slice is shorter than `size`: + /// + /// ``` + /// let slice = ['f', 'o', 'o']; + /// let mut iter = slice.windows(4); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// Because the [Iterator] trait cannot represent the required lifetimes, + /// there is no `windows_mut` analog to `windows`; + /// `[0,1,2].windows_mut(2).collect()` would violate [the rules of references] + /// (though a [LendingIterator] analog is possible). You can sometimes use + /// [`Cell::as_slice_of_cells`](crate::cell::Cell::as_slice_of_cells) in + /// conjunction with `windows` instead: + /// + /// [the rules of references]: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references + /// [LendingIterator]: https://blog.rust-lang.org/2022/10/28/gats-stabilization.html + /// ``` + /// use std::cell::Cell; + /// + /// let mut array = ['R', 'u', 's', 't', ' ', '2', '0', '1', '5']; + /// let slice = &mut array[..]; + /// let slice_of_cells: &[Cell] = Cell::from_mut(slice).as_slice_of_cells(); + /// for w in slice_of_cells.windows(3) { + /// Cell::swap(&w[0], &w[2]); + /// } + /// assert_eq!(array, ['s', 't', ' ', '2', '0', '1', '5', 'u', 'R']); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn windows(&self, size: usize) -> Windows<'_, T> { + let size = NonZero::new(size).expect("window size must be non-zero"); + Windows::new(self, size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`chunks_exact`] for a variant of this iterator that returns chunks of always exactly + /// `chunk_size` elements, and [`rchunks`] for the same iterator but starting at the end of the + /// slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['m']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`chunks_exact`]: slice::chunks_exact + /// [`rchunks`]: slice::rchunks + /// [`as_chunks`]: slice::as_chunks + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + Chunks::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`chunks_exact_mut`] for a variant of this iterator that returns chunks of always + /// exactly `chunk_size` elements, and [`rchunks_mut`] for the same iterator but starting at + /// the end of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.chunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 3]); + /// ``` + /// + /// [`chunks_exact_mut`]: slice::chunks_exact_mut + /// [`rchunks_mut`]: slice::rchunks_mut + /// [`as_chunks_mut`]: slice::as_chunks_mut + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksMut::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved + /// from the `remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks`]. + /// + /// See [`chunks`] for a variant of this iterator that also returns the remainder as a smaller + /// chunk, and [`rchunks_exact`] for the same iterator but starting at the end of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks_exact(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert!(iter.next().is_none()); + /// assert_eq!(iter.remainder(), &['m']); + /// ``` + /// + /// [`chunks`]: slice::chunks + /// [`rchunks_exact`]: slice::rchunks_exact + /// [`as_chunks`]: slice::as_chunks + #[stable(feature = "chunks_exact", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksExact::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be + /// retrieved from the `into_remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks_mut`]. + /// + /// See [`chunks_mut`] for a variant of this iterator that also returns the remainder as a + /// smaller chunk, and [`rchunks_exact_mut`] for the same iterator but starting at the end of + /// the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_chunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.chunks_exact_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 0]); + /// ``` + /// + /// [`chunks_mut`]: slice::chunks_mut + /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut + /// [`as_chunks_mut`]: slice::as_chunks_mut + #[stable(feature = "chunks_exact", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + ChunksExactMut::new(self, chunk_size) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// assuming that there's no remainder. + /// + /// This is the inverse operation to [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// As this is `unsafe`, consider whether you could use [`as_chunks`] or + /// [`as_rchunks`] instead, perhaps via something like + /// `if let (chunks, []) = slice.as_chunks()` or + /// `let (chunks, []) = slice.as_chunks() else { unreachable!() };`. + /// + /// [`as_chunks`]: slice::as_chunks + /// [`as_rchunks`]: slice::as_rchunks + /// + /// # Safety + /// + /// This may only be called when + /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). + /// - `N != 0`. + /// + /// # Examples + /// + /// ``` + /// let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!']; + /// let chunks: &[[char; 1]] = + /// // SAFETY: 1-element chunks never have remainder + /// unsafe { slice.as_chunks_unchecked() }; + /// assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]); + /// let chunks: &[[char; 3]] = + /// // SAFETY: The slice length (6) is a multiple of 3 + /// unsafe { slice.as_chunks_unchecked() }; + /// assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]); + /// + /// // These would be unsound: + /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5 + /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(N, "[1,)")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(len(self) % N == 0)))] + // Safety precondition from the documentation: `N != 0` and the length is a multiple of `N`. + #[requires(N != 0 && self.len().is_multiple_of(N))] + #[ensures(|chunks: &&[[T; N]]| chunks.len() == self.len() / N && chunks.as_ptr() as *const T == self.as_ptr())] + pub const unsafe fn as_chunks_unchecked<#[rustc_panics_when_zero] const N: usize>( + &self, + ) -> &[[T; N]] { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n), + ); + // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length + let new_len = unsafe { exact_div(self.len(), N) }; + // SAFETY: We cast a slice of `new_len * N` elements into + // a slice of `new_len` many `N` elements chunks. + unsafe { from_raw_parts(self.as_ptr().cast(), new_len) } + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the beginning of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (chunks, remainder) = slice.as_chunks()`, then: + /// - `chunks.len()` equals `slice.len() / N`, + /// - `remainder.len()` equals `slice.len() % N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let (chunks, remainder) = slice.as_chunks(); + /// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]); + /// assert_eq!(remainder, &['m']); + /// ``` + /// + /// If you expect the slice to be an exact multiple, you can combine + /// `let`-`else` with an empty slice pattern: + /// ``` + /// let slice = ['R', 'u', 's', 't']; + /// let (chunks, []) = slice.as_chunks::<2>() else { + /// panic!("slice didn't have even length") + /// }; + /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_chunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[[T; N]], &[T]) { + assert!(N != 0, "chunk size must be non-zero"); + let len_rounded_down = self.len() / N * N; + // SAFETY: The rounded-down value is always the same or smaller than the + // original length, and thus must be in-bounds of the slice. + let (multiple_of_n, remainder) = unsafe { self.split_at_unchecked(len_rounded_down) }; + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() }; + (array_slice, remainder) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the end of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (remainder, chunks) = slice.as_rchunks()`, then: + /// - `remainder.len()` equals `slice.len() % N`, + /// - `chunks.len()` equals `slice.len() / N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened`]. + /// + /// [`as_flattened`]: slice::as_flattened + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let (remainder, chunks) = slice.as_rchunks(); + /// assert_eq!(remainder, &['l']); + /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_rchunks<#[rustc_panics_when_zero] const N: usize>(&self) -> (&[T], &[[T; N]]) { + assert!(N != 0, "chunk size must be non-zero"); + let len = self.len() / N; + let (remainder, multiple_of_n) = self.split_at(self.len() - len * N); + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() }; + (remainder, array_slice) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// assuming that there's no remainder. + /// + /// This is the inverse operation to [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// As this is `unsafe`, consider whether you could use [`as_chunks_mut`] or + /// [`as_rchunks_mut`] instead, perhaps via something like + /// `if let (chunks, []) = slice.as_chunks_mut()` or + /// `let (chunks, []) = slice.as_chunks_mut() else { unreachable!() };`. + /// + /// [`as_chunks_mut`]: slice::as_chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + /// + /// # Safety + /// + /// This may only be called when + /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`). + /// - `N != 0`. + /// + /// # Examples + /// + /// ``` + /// let slice: &mut [char] = &mut ['l', 'o', 'r', 'e', 'm', '!']; + /// let chunks: &mut [[char; 1]] = + /// // SAFETY: 1-element chunks never have remainder + /// unsafe { slice.as_chunks_unchecked_mut() }; + /// chunks[0] = ['L']; + /// assert_eq!(chunks, &[['L'], ['o'], ['r'], ['e'], ['m'], ['!']]); + /// let chunks: &mut [[char; 3]] = + /// // SAFETY: The slice length (6) is a multiple of 3 + /// unsafe { slice.as_chunks_unchecked_mut() }; + /// chunks[1] = ['a', 'x', '?']; + /// assert_eq!(slice, &['L', 'o', 'r', 'a', 'x', '?']); + /// + /// // These would be unsound: + /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_mut() // The slice length is not a multiple of 5 + /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(N, "[1,)")))] + #[cfg_attr(rapx, rapx::requires(ValidNum(len(self) % N == 0)))] + // Safety precondition from the documentation: `N != 0` and the length is a multiple of `N`. + #[requires(N != 0 && self.len().is_multiple_of(N))] + #[ensures(|chunks: &&mut [[T; N]]| chunks.len() == old(self.len()) / N)] + pub const unsafe fn as_chunks_unchecked_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> &mut [[T; N]] { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n) + ); + // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length + let new_len = unsafe { exact_div(self.len(), N) }; + // SAFETY: We cast a slice of `new_len * N` elements into + // a slice of `new_len` many `N` elements chunks. + unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), new_len) } + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the beginning of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (chunks, remainder) = slice.as_chunks_mut()`, then: + /// - `chunks.len()` equals `slice.len() / N`, + /// - `remainder.len()` equals `slice.len() % N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// let (chunks, remainder) = v.as_chunks_mut(); + /// remainder[0] = 9; + /// for chunk in chunks { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 9]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn as_chunks_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> (&mut [[T; N]], &mut [T]) { + assert!(N != 0, "chunk size must be non-zero"); + let len_rounded_down = self.len() / N * N; + // SAFETY: The rounded-down value is always the same or smaller than the + // original length, and thus must be in-bounds of the slice. + let (multiple_of_n, remainder) = unsafe { self.split_at_mut_unchecked(len_rounded_down) }; + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() }; + (array_slice, remainder) + } + + const unsafe fn as_chunks_unchecked_proof__VeriFast_wrapper( + &self, + n: usize, + ) -> &[Chunk] + //@ req [_](<[T]>.share(?k, ?t, self)) &*& is_array_of::(n) == true &*& n != 0 &*& self.len() % n == 0; + //@ ens [_](<[Chunk]>.share(k, t, result)) &*& result.len() == self.len() / n; + //@ on_unwind_ens false; + { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = n, len: usize = self.len()) => n != 0 && len.is_multiple_of(n), + ); + //@ div_rem_nonneg(self.len(), n); + let new_len = unsafe { exact_div_usize__VeriFast_wrapper(self.len(), n) }; + //@ share_slice_as_chunks::(k, t, self, n, new_len); + unsafe { from_raw_parts(self.as_ptr() as *const Chunk, new_len) } + } + + const unsafe fn as_chunks_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> (&'a [Chunk], &'a [T]) + //@ req thread_token(?t) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& n != 0 &*& [_](<[Chunk]>.share('a, t, result.0)) &*& [_](<[T]>.share('a, t, result.1)) &*& result.0.len() == self.len() / n &*& result.1.len() == self.len() % n; + //@ on_unwind_ens false; + { + assert!(n != 0, "chunk size must be non-zero"); + //@ chunk_round_down_facts(self.len(), n); + let len_rounded_down = self.len() / n * n; + let (multiple_of_n, remainder) = unsafe { self.split_at_unchecked(len_rounded_down) }; + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_proof__VeriFast_wrapper::(n) }; + (array_slice, remainder) + } + + const unsafe fn as_rchunks_proof__VeriFast_wrapper<'a, Chunk>(&'a self, n: usize) -> (&'a [T], &'a [Chunk]) + //@ req thread_token(?t) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& n != 0 &*& [_](<[T]>.share('a, t, result.0)) &*& [_](<[Chunk]>.share('a, t, result.1)) &*& result.0.len() == self.len() % n &*& result.1.len() == self.len() / n; + //@ on_unwind_ens false; + { + assert!(n != 0, "chunk size must be non-zero"); + //@ chunk_round_down_facts(self.len(), n); + let len = self.len() / n; + let (remainder, multiple_of_n) = self.split_at(self.len() - len * n); + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_proof__VeriFast_wrapper::(n) }; + (remainder, array_slice) + } + + const unsafe fn as_chunks_unchecked_mut_proof__VeriFast_wrapper( + &mut self, + n: usize, + ) -> &mut [Chunk] + //@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, self)) &*& [?q]lifetime_token(k) &*& is_array_of::(n) == true &*& n != 0 &*& self.len() % n == 0; + //@ ens thread_token(t) &*& [q]lifetime_token(k) &*& full_borrow(k, <[Chunk]>.full_borrow_content(t, result)) &*& result.len() == self.len() / n; + //@ on_unwind_ens false; + { + assert_unsafe_precondition!( + check_language_ub, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + (n: usize = n, len: usize = self.len()) => n != 0 && len.is_multiple_of(n) + ); + let self_len = self.len(); + //@ div_rem_nonneg(self_len, n); + let new_len = unsafe { exact_div_usize__VeriFast_wrapper(self_len, n) }; + let ptr = self.as_mut_ptr(); + //@ full_borrow_slice_as_chunks::(k, t, self, n, new_len); + unsafe { from_raw_parts_mut(ptr as *mut Chunk, new_len) } + } + + const unsafe fn as_chunks_mut_proof__VeriFast_wrapper<'a, Chunk>( + &'a mut self, + n: usize, + ) -> (&'a mut [Chunk], &'a mut [T]) + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& n != 0 &*& full_borrow('a, <[Chunk]>.full_borrow_content(t, result.0)) &*& full_borrow('a, <[T]>.full_borrow_content(t, result.1)) &*& result.0.len() == self.len() / n &*& result.1.len() == self.len() % n; + //@ on_unwind_ens false; + { + assert!(n != 0, "chunk size must be non-zero"); + let self_len = self.len(); + //@ chunk_round_down_facts(self_len, n); + let len_rounded_down = self_len / n * n; + let (multiple_of_n, remainder) = unsafe { self.split_at_mut_unchecked(len_rounded_down) }; + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut_proof__VeriFast_wrapper::(n) }; + (array_slice, remainder) + } + + /// Splits the slice into a slice of `N`-element arrays, + /// starting at the end of the slice, + /// and a remainder slice with length strictly less than `N`. + /// + /// The remainder is meaningful in the division sense. Given + /// `let (remainder, chunks) = slice.as_rchunks_mut()`, then: + /// - `remainder.len()` equals `slice.len() % N`, + /// - `chunks.len()` equals `slice.len() / N`, and + /// - `slice.len()` equals `chunks.len() * N + remainder.len()`. + /// + /// You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`]. + /// + /// [`as_flattened_mut`]: slice::as_flattened_mut + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// let (remainder, chunks) = v.as_rchunks_mut(); + /// remainder[0] = 9; + /// for chunk in chunks { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[9, 1, 1, 2, 2]); + /// ``` + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] + #[inline] + #[track_caller] + #[must_use] + pub const fn as_rchunks_mut<#[rustc_panics_when_zero] const N: usize>( + &mut self, + ) -> (&mut [T], &mut [[T; N]]) { + assert!(N != 0, "chunk size must be non-zero"); + let len = self.len() / N; + let (remainder, multiple_of_n) = self.split_at_mut(self.len() - len * N); + // SAFETY: We already panicked for zero, and ensured by construction + // that the length of the subslice is a multiple of N. + let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() }; + (remainder, array_slice) + } + + /// Returns an iterator over overlapping windows of `N` elements of a slice, + /// starting at the beginning of the slice. + /// + /// This is the const generic equivalent of [`windows`]. + /// + /// If `N` is greater than the size of the slice, it will return no windows. + /// + /// # Panics + /// + /// Panics if `N` is zero. + /// + /// Note that this check is against a const generic parameter, not a runtime + /// value, and thus a particular monomorphization will either always panic + /// or it will never panic. + /// + /// # Examples + /// + /// ``` + /// let slice = [0, 1, 2, 3]; + /// let mut iter = slice.array_windows(); + /// assert_eq!(iter.next().unwrap(), &[0, 1]); + /// assert_eq!(iter.next().unwrap(), &[1, 2]); + /// assert_eq!(iter.next().unwrap(), &[2, 3]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`windows`]: slice::windows + #[stable(feature = "array_windows", since = "1.94.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn array_windows<#[rustc_panics_when_zero] const N: usize>( + &self, + ) -> ArrayWindows<'_, T, N> { + assert!(N != 0, "window size must be non-zero"); + ArrayWindows::new(self) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`rchunks_exact`] for a variant of this iterator that returns chunks of always exactly + /// `chunk_size` elements, and [`chunks`] for the same iterator but starting at the beginning + /// of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.rchunks(2); + /// assert_eq!(iter.next().unwrap(), &['e', 'm']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r']); + /// assert_eq!(iter.next().unwrap(), &['l']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`rchunks_exact`]: slice::rchunks_exact + /// [`chunks`]: slice::chunks + /// [`as_rchunks`]: slice::as_rchunks + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunks::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`rchunks_exact_mut`] for a variant of this iterator that returns chunks of always + /// exactly `chunk_size` elements, and [`chunks_mut`] for the same iterator but starting at the + /// beginning of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.rchunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[3, 2, 2, 1, 1]); + /// ``` + /// + /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut + /// [`chunks_mut`]: slice::chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksMut::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// end of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved + /// from the `remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`rchunks`]. + /// + /// See [`rchunks`] for a variant of this iterator that also returns the remainder as a smaller + /// chunk, and [`chunks_exact`] for the same iterator but starting at the beginning of the + /// slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.rchunks_exact(2); + /// assert_eq!(iter.next().unwrap(), &['e', 'm']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r']); + /// assert!(iter.next().is_none()); + /// assert_eq!(iter.remainder(), &['l']); + /// ``` + /// + /// [`chunks`]: slice::chunks + /// [`rchunks`]: slice::rchunks + /// [`chunks_exact`]: slice::chunks_exact + /// [`as_rchunks`]: slice::as_rchunks + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksExact::new(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be + /// retrieved from the `into_remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks_mut`]. + /// + /// See [`rchunks_mut`] for a variant of this iterator that also returns the remainder as a + /// smaller chunk, and [`chunks_exact_mut`] for the same iterator but starting at the beginning + /// of the slice. + /// + /// If your `chunk_size` is a constant, consider using [`as_rchunks_mut`] instead, which will + /// give references to arrays of exactly that length, rather than slices. + /// + /// # Panics + /// + /// Panics if `chunk_size` is zero. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.rchunks_exact_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[0, 2, 2, 1, 1]); + /// ``` + /// + /// [`chunks_mut`]: slice::chunks_mut + /// [`rchunks_mut`]: slice::rchunks_mut + /// [`chunks_exact_mut`]: slice::chunks_exact_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + #[stable(feature = "rchunks", since = "1.31.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + #[track_caller] + pub const fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> { + assert!(chunk_size != 0, "chunk size must be non-zero"); + RChunksExactMut::new(self, chunk_size) + } + + /// Returns an iterator over the slice producing non-overlapping runs + /// of elements using the predicate to separate them. + /// + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. + /// + /// # Examples + /// + /// ``` + /// let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; + /// + /// let mut iter = slice.chunk_by(|a, b| a == b); + /// + /// assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + /// assert_eq!(iter.next(), Some(&[3, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// This method can be used to extract the sorted subslices: + /// + /// ``` + /// let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4]; + /// + /// let mut iter = slice.chunk_by(|a, b| a <= b); + /// + /// assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 3][..])); + /// assert_eq!(iter.next(), Some(&[2, 3, 4][..])); + /// assert_eq!(iter.next(), None); + /// ``` + #[stable(feature = "slice_group_by", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + pub const fn chunk_by(&self, pred: F) -> ChunkBy<'_, T, F> + where + F: FnMut(&T, &T) -> bool, + { + ChunkBy::new(self, pred) + } + + /// Returns an iterator over the slice producing non-overlapping mutable + /// runs of elements using the predicate to separate them. + /// + /// The predicate is called for every pair of consecutive elements, + /// meaning that it is called on `slice[0]` and `slice[1]`, + /// followed by `slice[1]` and `slice[2]`, and so on. + /// + /// # Examples + /// + /// ``` + /// let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2]; + /// + /// let mut iter = slice.chunk_by_mut(|a, b| a == b); + /// + /// assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); + /// assert_eq!(iter.next(), Some(&mut [3, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// This method can be used to extract the sorted subslices: + /// + /// ``` + /// let slice = &mut [1, 1, 2, 3, 2, 3, 2, 3, 4]; + /// + /// let mut iter = slice.chunk_by_mut(|a, b| a <= b); + /// + /// assert_eq!(iter.next(), Some(&mut [1, 1, 2, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 3][..])); + /// assert_eq!(iter.next(), Some(&mut [2, 3, 4][..])); + /// assert_eq!(iter.next(), None); + /// ``` + #[stable(feature = "slice_group_by", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")] + #[inline] + pub const fn chunk_by_mut(&mut self, pred: F) -> ChunkByMut<'_, T, F> + where + F: FnMut(&T, &T) -> bool, + { + ChunkByMut::new(self, pred) + } + + /// Divides one slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. For a non-panicking alternative see + /// [`split_at_checked`](slice::split_at_checked). + /// + /// # Examples + /// + /// ``` + /// let v = ['a', 'b', 'c']; + /// + /// { + /// let (left, right) = v.split_at(0); + /// assert_eq!(left, []); + /// assert_eq!(right, ['a', 'b', 'c']); + /// } + /// + /// { + /// let (left, right) = v.split_at(2); + /// assert_eq!(left, ['a', 'b']); + /// assert_eq!(right, ['c']); + /// } + /// + /// { + /// let (left, right) = v.split_at(3); + /// assert_eq!(left, ['a', 'b', 'c']); + /// assert_eq!(right, []); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "1.71.0")] + #[inline] + #[track_caller] + #[must_use] + pub const fn split_at<'a>(&'a self, mid: usize) -> (&'a [T], &'a [T]) + //@ req thread_token(?t) &*& [_](<[T]>.share(?k, t, self)); + //@ ens thread_token(t) &*& mid <= self.len() &*& [_](<[T]>.share(k, t, result.0)) &*& [_](<[T]>.share(k, t, result.1)) &*& strip_pointer_metadata(result.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& result.0 as *T == self as *T &*& result.0.len() == mid &*& strip_pointer_metadata(result.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& result.1.len() == self.len() - mid; + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + close_slice_pair_own::<'a, T>(_t, result); + } + @*/ + { + match self.split_at_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), + } + } + + /// Divides one mutable slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. For a non-panicking alternative see + /// [`split_at_mut_checked`](slice::split_at_mut_checked). + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// let (left, right) = v.split_at_mut(2); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[track_caller] + #[must_use] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + pub const fn split_at_mut<'a>(&'a mut self, mid: usize) -> (&'a mut [T], &'a mut [T]) + //@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, self)) &*& [?q]lifetime_token(k); + //@ ens thread_token(t) &*& [q]lifetime_token(k) &*& mid <= self.len() &*& full_borrow(k, <[T]>.full_borrow_content(t, result.0)) &*& full_borrow(k, <[T]>.full_borrow_content(t, result.1)) &*& result.0 == ptr::mk_slice::(strip_pointer_metadata(self as pointer) as *T, mid) &*& strip_pointer_metadata(result.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& result.0 as *T == self as *T &*& result.0.len() == mid &*& strip_pointer_metadata(result.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& result.1.len() == self.len() - mid; + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + close_mut_slice_pair_own::<'a, T>(_t, result); + } + @*/ + { + match self.split_at_mut_checked(mid) { + Some(pair) => pair, + None => panic!("mid > len"), + } + } + + /// Divides one slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at`]: slice::split_at + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let v = ['a', 'b', 'c']; + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(0); + /// assert_eq!(left, []); + /// assert_eq!(right, ['a', 'b', 'c']); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(2); + /// assert_eq!(left, ['a', 'b']); + /// assert_eq!(right, ['c']); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(3); + /// assert_eq!(left, ['a', 'b', 'c']); + /// assert_eq!(right, []); + /// } + /// ``` + #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_split_at_unchecked", since = "1.77.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(mid, [0,self.len()])))] + pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) + //@ req [_](<[T]>.share(?k, ?t, self)) &*& mid <= self.len(); + //@ ens [_](<[T]>.share(k, t, result.0)) &*& [_](<[T]>.share(k, t, result.1)) &*& strip_pointer_metadata(result.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& result.0 as *T == self as *T &*& result.0.len() == mid &*& strip_pointer_metadata(result.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& result.1.len() == self.len() - mid; + //@ on_unwind_ens false; + { + // FIXME(const-hack): the const function `from_raw_parts` is used to make this + // function const; previously the implementation used + // `(self.get_unchecked(..mid), self.get_unchecked(mid..))` + + let len = self.len(); + let ptr = self.as_ptr(); + + assert_unsafe_precondition!( + check_library_ub, + "slice::split_at_unchecked requires the index to be within the slice", + (mid: usize = mid, len: usize = len) => mid <= len, + ); + + //@ slice_share_inv::(k, t, self); + //@ open slice_share::()(k, t, self); + //@ array_share_split::(k, t, ptr, len, mid); + //@ ptr_range_split_limits::(ptr, len, mid); + //@ let r0 = ptr::mk_slice::(ptr, mid); + //@ let r1 = ptr::mk_slice::(ptr + mid, len - mid); + //@ close slice_share::()(k, t, r0); + //@ leak slice_share::()(k, t, r0); + //@ close slice_share::()(k, t, r1); + //@ leak slice_share::()(k, t, r1); + // SAFETY: Caller has to check that `0 <= mid <= self.len()` + unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), unchecked_sub(len, mid))) } + } + + /// Divides one mutable slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at_mut`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at_mut`]: slice::split_at_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// // scoped to restrict the lifetime of the borrows + /// unsafe { + /// let (left, right) = v.split_at_mut_unchecked(2); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + #[inline] + #[must_use] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidNum(mid, [0,self.len()])))] + pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) + //@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, self)) &*& [?q]lifetime_token(k) &*& mid <= self.len(); + //@ ens thread_token(t) &*& [q]lifetime_token(k) &*& full_borrow(k, <[T]>.full_borrow_content(t, result.0)) &*& full_borrow(k, <[T]>.full_borrow_content(t, result.1)) &*& result.0 == ptr::mk_slice::(strip_pointer_metadata(self as pointer) as *T, mid) &*& strip_pointer_metadata(result.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& result.0 as *T == self as *T &*& result.0.len() == mid &*& strip_pointer_metadata(result.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& result.1.len() == self.len() - mid; + //@ on_unwind_ens false; + { + let len = self.len(); + let ptr = self.as_mut_ptr(); + + assert_unsafe_precondition!( + check_library_ub, + "slice::split_at_mut_unchecked requires the index to be within the slice", + (mid: usize = mid, len: usize = len) => mid <= len, + ); + + //@ open_full_borrow_strong_(k, <[T]>.full_borrow_content(t, self)); + //@ open slice_full_borrow_content::(t, self)(); + //@ assert array::(ptr, len, ?elems) &*& foreach(elems, own::(t)); + //@ ptr_range_split_limits::(ptr, len, mid); + /*@ + { + let r0 = ptr::mk_slice::(ptr, mid); + let r1 = ptr::mk_slice::(ptr + mid, len - mid); + array_split(ptr, mid); + foreach_split(elems, own::(t), mid); + close slice_full_borrow_content::(t, r0)(); + close slice_full_borrow_content::(t, r1)(); + close sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1))(); + produce_lem_ptr_chunk restore_full_borrow_(True, sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1)), <[T]>.full_borrow_content(t, self))() { + open True(); + open sep(<[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1))(); + open slice_full_borrow_content::(t, r0)(); + open slice_full_borrow_content::(t, r1)(); + assert array::(ptr, mid, ?elems0) &*& array::(ptr + mid, len - mid, ?elems1); + array_join(ptr); + foreach_append(elems0, elems1); + close slice_full_borrow_content::(t, self)(); + } { + close True(); + close_full_borrow_strong_(); + } + full_borrow_split(k, <[T]>.full_borrow_content(t, r0), <[T]>.full_borrow_content(t, r1)); + } + @*/ + // SAFETY: Caller has to check that `0 <= mid <= self.len()`. + // + // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference + // is fine. + unsafe { + ( + from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.add(mid), unchecked_sub(len, mid)), + ) + } + } + + /// Divides one slice into two at an index, returning `None` if the slice is + /// too short. + /// + /// If `mid ≤ len`, returns a pair of slices where the first will contain all + /// indices from `[0, mid)` (excluding the index `mid` itself) and the + /// second will contain all indices from `[mid, len)` (excluding the index + /// `len` itself). + /// + /// Otherwise, if `mid > len`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = [1, -2, 3, -4, 5, -6]; + /// + /// { + /// let (left, right) = v.split_at_checked(0).unwrap(); + /// assert_eq!(left, []); + /// assert_eq!(right, [1, -2, 3, -4, 5, -6]); + /// } + /// + /// { + /// let (left, right) = v.split_at_checked(2).unwrap(); + /// assert_eq!(left, [1, -2]); + /// assert_eq!(right, [3, -4, 5, -6]); + /// } + /// + /// { + /// let (left, right) = v.split_at_checked(6).unwrap(); + /// assert_eq!(left, [1, -2, 3, -4, 5, -6]); + /// assert_eq!(right, []); + /// } + /// + /// assert_eq!(None, v.split_at_checked(7)); + /// ``` + #[stable(feature = "split_at_checked", since = "1.80.0")] + #[rustc_const_stable(feature = "split_at_checked", since = "1.80.0")] + #[inline] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_at_checked<'a>(&'a self, mid: usize) -> Option<(&'a [T], &'a [T])> + //@ req [_](<[T]>.share(?k, ?t, self)); + //@ ens if mid <= self.len() { result == std::option::Option::Some(?p) &*& [_](<[T]>.share(k, t, p.0)) &*& [_](<[T]>.share(k, t, p.1)) &*& strip_pointer_metadata(p.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& p.0 as *T == self as *T &*& p.0.len() == mid &*& strip_pointer_metadata(p.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& p.1.len() == self.len() - mid } else { result == std::option::Option::None }; + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + if mid <= self.len() { + assert result == std::option::Option::Some(?p); + close_slice_pair_own::<'a, T>(_t, p); + } + close >.own(_t, result); + } + @*/ + { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. + Some(unsafe { self.split_at_unchecked(mid) }) + } else { + None + } + } + + /// Divides one mutable slice into two at an index, returning `None` if the + /// slice is too short. + /// + /// If `mid ≤ len`, returns a pair of slices where the first will contain all + /// indices from `[0, mid)` (excluding the index `mid` itself) and the + /// second will contain all indices from `[mid, len)` (excluding the index + /// `len` itself). + /// + /// Otherwise, if `mid > len`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// + /// if let Some((left, right)) = v.split_at_mut_checked(2) { + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// + /// assert_eq!(None, v.split_at_mut_checked(7)); + /// ``` + #[stable(feature = "split_at_checked", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] + #[inline] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub const fn split_at_mut_checked<'a>(&'a mut self, mid: usize) -> Option<(&'a mut [T], &'a mut [T])> + //@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, self)) &*& [?q]lifetime_token(k); + //@ ens thread_token(t) &*& [q]lifetime_token(k) &*& if mid <= self.len() { result == std::option::Option::Some(?p) &*& full_borrow(k, <[T]>.full_borrow_content(t, p.0)) &*& full_borrow(k, <[T]>.full_borrow_content(t, p.1)) &*& p.0 == ptr::mk_slice::(strip_pointer_metadata(self as pointer) as *T, mid) &*& strip_pointer_metadata(p.0 as pointer) as *T == strip_pointer_metadata(self as pointer) as *T &*& p.0 as *T == self as *T &*& p.0.len() == mid &*& strip_pointer_metadata(p.1 as pointer) as *T == (strip_pointer_metadata(self as pointer) as *T) + mid &*& p.1.len() == self.len() - mid } else { result == std::option::Option::None &*& full_borrow(k, <[T]>.full_borrow_content(t, self)) }; + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + if mid <= self.len() { + assert result == std::option::Option::Some(?p); + close_mut_slice_pair_own::<'a, T>(_t, p); + } else { + leak full_borrow('a, _); + } + close >.own(_t, result); + } + @*/ + { + if mid <= self.len() { + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `split_at_unchecked`. + Some(unsafe { self.split_at_mut_unchecked(mid) }) + } else { + None + } + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the first element is matched, an empty slice will be the first item + /// returned by the iterator. Similarly, if the last element in the slice + /// is matched, an empty slice will be the last item returned by the + /// iterator: + /// + /// ``` + /// let slice = [10, 40, 33]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If two matched elements are directly adjacent, an empty slice will be + /// present between them: + /// + /// ``` + /// let slice = [10, 6, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split(&self, pred: F) -> Split<'_, T, F> + where + F: FnMut(&T) -> bool, + { + Split::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_mut(|num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_mut(&mut self, pred: F) -> SplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is contained in the end of the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the last element of the slice is matched, + /// that element will be considered the terminator of the preceding slice. + /// That slice will be the last item returned by the iterator. + /// + /// ``` + /// let slice = [3, 10, 40, 33]; + /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[3]); + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[inline] + pub fn split_inclusive(&self, pred: F) -> SplitInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitInclusive::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is contained in the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_inclusive_mut(|num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; + /// } + /// assert_eq!(v, [10, 40, 1, 20, 1, 1]); + /// ``` + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[inline] + pub fn split_inclusive_mut(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitInclusiveMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, starting at the end of the slice and working backwards. + /// The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let mut iter = slice.rsplit(|num| *num == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[44, 55]); + /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// As with `split()`, if the first or last element is matched, an empty + /// slice will be the first (or last) item returned by the iterator. + /// + /// ``` + /// let v = &[0, 1, 1, 2, 3, 5, 8]; + /// let mut it = v.rsplit(|n| *n % 2 == 0); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next().unwrap(), &[3, 5]); + /// assert_eq!(it.next().unwrap(), &[1, 1]); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next(), None); + /// ``` + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplit::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, starting at the end of the slice and working + /// backwards. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [100, 400, 300, 200, 600, 500]; + /// + /// let mut count = 0; + /// for group in v.rsplit_mut(|num| *num % 3 == 0) { + /// count += 1; + /// group[0] = count; + /// } + /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); + /// ``` + /// + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once by numbers divisible by 3 (i.e., `[10, 40]`, + /// `[20, 60, 50]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn(2, |num| *num % 3 == 0) { + /// println!("{group:?}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn(&self, n: usize, pred: F) -> SplitN<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitN::new(self.split(pred), n) + } + + /// Returns an iterator over mutable subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 50]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitNMut::new(self.split_mut(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once, starting from the end, by numbers divisible + /// by 3 (i.e., `[50]`, `[10, 40, 30, 20]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplitn(2, |num| *num % 3 == 0) { + /// println!("{group:?}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitN::new(self.rsplit(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut s = [10, 40, 30, 20, 60, 50]; + /// + /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(s, [1, 40, 30, 20, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitNMut::new(self.rsplit_mut(pred), n) + } + + /// Splits the slice on the first element that matches the specified + /// predicate. + /// + /// If any matching elements are present in the slice, returns the prefix + /// before the match and suffix after. The matching element itself is not + /// included. If no elements match, returns `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_split_once)] + /// let s = [1, 2, 3, 2, 4]; + /// assert_eq!(s.split_once(|&x| x == 2), Some(( + /// &[1][..], + /// &[3, 2, 4][..] + /// ))); + /// assert_eq!(s.split_once(|&x| x == 0), None); + /// ``` + #[unstable(feature = "slice_split_once", issue = "112811")] + #[inline] + pub fn split_once(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { + let index = self.iter().position(pred)?; + // Slice bounds checks optimized are away (as of June 2026) + Some((&self[..index], &self[index + 1..])) + } + + /// Splits the slice on the last element that matches the specified + /// predicate. + /// + /// If any matching elements are present in the slice, returns the prefix + /// before the match and suffix after. The matching element itself is not + /// included. If no elements match, returns `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_split_once)] + /// let s = [1, 2, 3, 2, 4]; + /// assert_eq!(s.rsplit_once(|&x| x == 2), Some(( + /// &[1, 2, 3][..], + /// &[4][..] + /// ))); + /// assert_eq!(s.rsplit_once(|&x| x == 0), None); + /// ``` + #[unstable(feature = "slice_split_once", issue = "112811")] + #[inline] + pub fn rsplit_once(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { + let index = self.iter().rposition(pred)?; + // Slice bounds checks optimized are away (as of June 2026) + Some((&self[..index], &self[index + 1..])) + } + + /// Returns `true` if the slice contains an element with the given value. + /// + /// This operation is *O*(*n*). + /// + /// Note that if you have a sorted slice, [`binary_search`] may be faster. + /// + /// [`binary_search`]: slice::binary_search + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.contains(&30)); + /// assert!(!v.contains(&50)); + /// ``` + /// + /// If you do not have a `&T`, but some other value that you can compare + /// with one (for example, `String` implements `PartialEq`), you can + /// use `iter().any`: + /// + /// ``` + /// let v = [String::from("hello"), String::from("world")]; // slice of `String` + /// assert!(v.iter().any(|e| e == "hello")); // search with `&str` + /// assert!(!v.iter().any(|e| e == "hi")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[must_use] + pub fn contains(&self, x: &T) -> bool + where + T: PartialEq, + { + cmp::SliceContains::slice_contains(x, self) + } + + /// Returns `true` if `needle` is a prefix of the slice or equal to the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.starts_with(&[10])); + /// assert!(v.starts_with(&[10, 40])); + /// assert!(v.starts_with(&v)); + /// assert!(!v.starts_with(&[50])); + /// assert!(!v.starts_with(&[10, 50])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.starts_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.starts_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + pub fn starts_with(&self, needle: &[T]) -> bool + where + T: PartialEq, + { + let n = needle.len(); + self.len() >= n && needle == &self[..n] + } + + /// Returns `true` if `needle` is a suffix of the slice or equal to the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.ends_with(&[30])); + /// assert!(v.ends_with(&[40, 30])); + /// assert!(v.ends_with(&v)); + /// assert!(!v.ends_with(&[50])); + /// assert!(!v.ends_with(&[50, 30])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.ends_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.ends_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + pub fn ends_with(&self, needle: &[T]) -> bool + where + T: PartialEq, + { + let (m, n) = (self.len(), needle.len()); + m >= n && needle == &self[m - n..] + } + + /// Returns a subslice with the prefix removed. + /// + /// If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`. + /// If `prefix` is empty, simply returns the original slice. If `prefix` is equal to the + /// original slice, returns an empty slice. + /// + /// If the slice does not start with `prefix`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..])); + /// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..])); + /// assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_prefix(&[50]), None); + /// assert_eq!(v.strip_prefix(&[10, 50]), None); + /// + /// let prefix : &str = "he"; + /// assert_eq!(b"hello".strip_prefix(prefix.as_bytes()), + /// Some(b"llo".as_ref())); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "slice_strip", since = "1.51.0")] + pub fn strip_prefix + ?Sized>(&self, prefix: &P) -> Option<&[T]> + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let prefix = prefix.as_slice(); + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return Some(tail); + } + } + None + } + + /// Returns a subslice with the suffix removed. + /// + /// If the slice ends with `suffix`, returns the subslice before the suffix, wrapped in `Some`. + /// If `suffix` is empty, simply returns the original slice. If `suffix` is equal to the + /// original slice, returns an empty slice. + /// + /// If the slice does not end with `suffix`, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..])); + /// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..])); + /// assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_suffix(&[50]), None); + /// assert_eq!(v.strip_suffix(&[50, 30]), None); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "slice_strip", since = "1.51.0")] + pub fn strip_suffix + ?Sized>(&self, suffix: &P) -> Option<&[T]> + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let suffix = suffix.as_slice(); + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return Some(head); + } + } + None + } + + /// Returns a subslice with the prefix and suffix removed. + /// + /// If the slice starts with `prefix`, ends with `suffix`, and + /// the prefix and suffix don't overlap, returns the subslice after + /// the prefix and before the suffix, wrapped in `Some`. + /// + /// If the slice does not start with `prefix`, does not end with `suffix`, + /// or the prefix and suffix overlap in the slice, returns `None`. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 50, 40, 30]; + /// assert_eq!(v.strip_circumfix(&[10], &[30]), Some(&[50, 40][..])); + /// assert_eq!(v.strip_circumfix(&[10], &[40, 30]), Some(&[50][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50], &[40, 30]), Some(&[][..])); + /// assert_eq!(v.strip_circumfix(&[50], &[30]), None); + /// assert_eq!(v.strip_circumfix(&[10], &[40]), None); + /// assert_eq!(v.strip_circumfix(&[], &[40, 30]), Some(&[10, 50][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50], &[]), Some(&[40, 30][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50, 40], &[50, 40, 30]), None); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "strip_circumfix", since = "1.98.0")] + pub fn strip_circumfix(&self, prefix: &P, suffix: &S) -> Option<&[T]> + where + T: PartialEq, + S: SlicePattern + ?Sized, + P: SlicePattern + ?Sized, + { + self.strip_prefix(prefix)?.strip_suffix(suffix) + } + + /// Returns a subslice with the optional prefix removed. + /// + /// If the slice starts with `prefix`, returns the subslice after the prefix. If `prefix` + /// is empty or the slice does not start with `prefix`, simply returns the original slice. + /// If `prefix` is equal to the original slice, returns an empty slice. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// + /// // Prefix present - removes it + /// assert_eq!(v.trim_prefix(&[10]), &[40, 30][..]); + /// assert_eq!(v.trim_prefix(&[10, 40]), &[30][..]); + /// assert_eq!(v.trim_prefix(&[10, 40, 30]), &[][..]); + /// + /// // Prefix absent - returns original slice + /// assert_eq!(v.trim_prefix(&[50]), &[10, 40, 30][..]); + /// assert_eq!(v.trim_prefix(&[10, 50]), &[10, 40, 30][..]); + /// + /// let prefix : &str = "he"; + /// assert_eq!(b"hello".trim_prefix(prefix.as_bytes()), b"llo".as_ref()); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "trim_prefix_suffix", since = "1.100.0")] + pub fn trim_prefix + ?Sized>(&self, prefix: &P) -> &[T] + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let prefix = prefix.as_slice(); + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return tail; + } + } + self + } + + /// Returns a subslice with the optional suffix removed. + /// + /// If the slice ends with `suffix`, returns the subslice before the suffix. If `suffix` + /// is empty or the slice does not end with `suffix`, simply returns the original slice. + /// If `suffix` is equal to the original slice, returns an empty slice. + /// + /// # Examples + /// + /// ``` + /// let v = &[10, 40, 30]; + /// + /// // Suffix present - removes it + /// assert_eq!(v.trim_suffix(&[30]), &[10, 40][..]); + /// assert_eq!(v.trim_suffix(&[40, 30]), &[10][..]); + /// assert_eq!(v.trim_suffix(&[10, 40, 30]), &[][..]); + /// + /// // Suffix absent - returns original slice + /// assert_eq!(v.trim_suffix(&[50]), &[10, 40, 30][..]); + /// assert_eq!(v.trim_suffix(&[50, 30]), &[10, 40, 30][..]); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[stable(feature = "trim_prefix_suffix", since = "1.100.0")] + pub fn trim_suffix + ?Sized>(&self, suffix: &P) -> &[T] + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let suffix = suffix.as_slice(); + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return head; + } + } + self + } + + /// Binary searches this slice for a given element. + /// If the slice is not sorted, the returned result is unspecified and + /// meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`]. + /// + /// [`binary_search_by`]: slice::binary_search_by + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// assert_eq!(s.binary_search(&13), Ok(9)); + /// assert_eq!(s.binary_search(&4), Err(7)); + /// assert_eq!(s.binary_search(&100), Err(13)); + /// let r = s.binary_search(&1); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + /// + /// If you want to find that whole *range* of matching items, rather than + /// an arbitrary matching one, that can be done using [`partition_point`]: + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// let low = s.partition_point(|x| x < &1); + /// assert_eq!(low, 1); + /// let high = s.partition_point(|x| x <= &1); + /// assert_eq!(high, 5); + /// let r = s.binary_search(&1); + /// assert!((low..high).contains(&r.unwrap())); + /// + /// assert!(s[..low].iter().all(|&x| x < 1)); + /// assert!(s[low..high].iter().all(|&x| x == 1)); + /// assert!(s[high..].iter().all(|&x| x > 1)); + /// + /// // For something not found, the "range" of equal items is empty + /// assert_eq!(s.partition_point(|x| x < &11), 9); + /// assert_eq!(s.partition_point(|x| x <= &11), 9); + /// assert_eq!(s.binary_search(&11), Err(9)); + /// ``` + /// + /// If you want to insert an item to a sorted vector, while maintaining + /// sort order, consider using [`partition_point`]: + /// + /// ``` + /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let num = 42; + /// let idx = s.partition_point(|&x| x <= num); + /// // If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to + /// // `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` will allow `insert` + /// // to shift less elements. + /// s.insert(idx, num); + /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "rust1", since = "1.0.0")] + pub const fn binary_search(&self, x: &T) -> Result + where + T: [const] Ord, + { + self.binary_search_by(const |p| p.cmp(x)) + } + + /// Binary searches this slice with a comparator function. + /// + /// The comparator function should return an order code that indicates + /// whether its argument is `Less`, `Equal` or `Greater` the desired + /// target. + /// If the slice is not sorted or if the comparator function does not + /// implement an order consistent with the sort order of the underlying + /// slice, the returned result is unspecified and meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`]. + /// + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// let seek = 13; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9)); + /// let seek = 4; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7)); + /// let seek = 100; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); + /// let seek = 1; + /// let r = s.binary_search_by(|probe| probe.cmp(&seek)); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub const fn binary_search_by<'a, F>(&'a self, /*@~mut@*/ mut f: F) -> Result + where + F: [const] FnMut(&'a T) -> Ordering + [const] Destruct, + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& [_](<[T]>.share('a, t, self)) &*& (.own)(t, f); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& >.own(t, result); + //@ on_unwind_ens false; + { + //@ slice_share_inv::('a, t, self); + let mut size = self.len(); + if size == 0 { + //@ close_Result_usize_own(t, std::result::Result::Err::(0)); + return Err(0); + } + let mut base = 0usize; + + // This loop intentionally doesn't have an early exit if the comparison + // returns Equal. We want the number of loop iterations to depend *only* + // on the size of the input slice so that the CPU can reliably predict + // the loop count. + while size > 1 { + //@ inv thread_token(t) &*& [q]lifetime_token('a) &*& [_](<[T]>.share('a, t, self)) &*& lifetime_token(func_lft) &*& f |-> ?f_cur &*& (.own)(t, f_cur) &*& [1/2]points_to_::(&cmp, _) &*& [1/2]points_to_::(&cmp_1, _) &*& 1 <= size &*& 0 <= base &*& base + size <= self.len(); + let half = size / 2; + //@ div_rem_nonneg(size, 2); + let mid = base + half; + + // SAFETY: the call is made safe by the following invariants: + // - `mid >= 0`: by definition + // - `mid < size`: `mid = size / 2 + size / 4 + size / 8 ...` + let f_ref = &mut f; + let cmp = unsafe { crate::call_binary_search_f__VeriFast_wrapper(self, f_ref, mid) }; + + // Binary search interacts poorly with branch prediction, so force + // the compiler to use conditional moves if supported by the target + // architecture. + base = hint::select_unpredictable(cmp == Greater, base, mid); //~ignore_ref_creation + + // This is imprecise in the case where `size` is odd and the + // comparison returns Greater: the mid element still gets included + // by `size` even though it's known to be larger than the element + // being searched for. + // + // This is fine though: we gain more performance by keeping the + // loop iteration count invariant (and thus predictable) than we + // lose from considering one additional element. + size -= half; + } + + // SAFETY: base is always in [0, size) because base <= mid. + let f_ref = &mut f; + let cmp = unsafe { crate::call_binary_search_f__VeriFast_wrapper(self, f_ref, base) }; + if cmp == Equal { //~ignore_ref_creation + // SAFETY: same as the `get_unchecked` above. + unsafe { hint::assert_unchecked(base < self.len()) }; + //@ close_Result_usize_own(t, std::result::Result::Ok::(base)); + Ok(base) + } else { + let result = base + (cmp == Less) as usize; //~ignore_ref_creation + // SAFETY: same as the `get_unchecked` above. + // Note that this is `<=`, unlike the assume in the `Ok` path. + unsafe { hint::assert_unchecked(result <= self.len()) }; + //@ close_Result_usize_own(t, std::result::Result::Err::(result)); + Err(result) + } + } + + /// Binary searches this slice with a key extraction function. + /// + /// Assumes that the slice is sorted by the key, for instance with + /// [`sort_by_key`] using the same key extraction function. + /// If the slice is not sorted by the key, the returned result is + /// unspecified and meaningless. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. + /// + /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`]. + /// + /// [`sort_by_key`]: slice::sort_by_key + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by`]: slice::binary_search_by + /// [`partition_point`]: slice::partition_point + /// + /// # Examples + /// + /// Looks up a series of four elements in a slice of pairs sorted by + /// their second elements. The first is found, with a uniquely + /// determined position; the second and third are not found; the + /// fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), + /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), + /// (1, 21), (2, 34), (4, 55)]; + /// + /// assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b), Ok(9)); + /// assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b), Err(7)); + /// assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13)); + /// let r = s.binary_search_by_key(&1, |&(a, b)| b); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); + /// ``` + // Lint rustdoc::broken_intra_doc_links is allowed as `slice::sort_by_key` is + // in crate `alloc`, and as such doesn't exists yet when building `core`: #74481. + // This breaks links when slice is displayed in core, but changing it to use relative links + // would break when the item is re-exported. So allow the core links to be broken for now. + #[allow(rustdoc::broken_intra_doc_links)] + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] + #[inline] + pub const fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result + where + F: [const] FnMut(&'a T) -> B + [const] Destruct, + B: [const] Ord + [const] Destruct, + { + self.binary_search_by(const |k| f(k).cmp(b)) + } + + /// Sorts the slice in ascending order **without** preserving the initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `T` panics. + /// + /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require + /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the + /// reflexivity requirement of [`Ord`]. By using an alternative comparison function with + /// `slice::sort_unstable_by` such as [`f32::total_cmp`] or [`f64::total_cmp`] that defines a + /// [total order] users can sort slices containing floating-point values. Alternatively, if all + /// values in the slice are guaranteed to be in a subset for which [`PartialOrd::partial_cmp`] + /// forms a [total order], it's possible to sort the slice with `sort_unstable_by(|a, b| + /// a.partial_cmp(b).unwrap())`. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if + /// the [`Ord`] implementation panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// v.sort_unstable(); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable(&mut self) + where + T: Ord, + { + sort::unstable::sort(self, &mut T::lt); + } + + /// Sorts the slice in ascending order with a comparison function, **without** preserving the + /// initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the comparison function `compare` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if `compare` panics. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the `compare` does not implement a [total order], or if + /// the `compare` itself panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4, -5, 1, -3, 2]; + /// v.sort_unstable_by(|a, b| a.cmp(b)); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// + /// // reverse sorting + /// v.sort_unstable_by(|a, b| b.cmp(a)); + /// assert_eq!(v, [4, 2, 1, -3, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by(&mut self, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + { + sort::unstable::sort(self, &mut |a, b| compare(a, b) == Ordering::Less); + } + + /// Sorts the slice in ascending order with a key extraction function, **without** preserving + /// the initial order of equal elements. + /// + /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not + /// allocate), and *O*(*n* \* log(*n*)) worst-case. + /// + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `K` panics. + /// + /// # Current implementation + /// + /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which + /// combines the fast average case of quicksort with the fast worst case of heapsort, achieving + /// linear time on fully sorted and reversed inputs. On inputs with k distinct elements, the + /// expected time to sort the data is *O*(*n* \* log(*k*)). + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g., when the + /// slice is partially sorted. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation panics. + /// + /// # Examples + /// + /// ``` + /// let mut v = [4i32, -5, 1, -3, 2]; + /// + /// v.sort_unstable_by_key(|k| k.abs()); + /// assert_eq!(v, [1, 2, -3, 4, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by_key(&mut self, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, + { + sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b))); + } + + /// Partially sorts the slice in ascending order **without** preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable(0..0); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable(2..2); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable(2..3); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable(1..4); + /// assert_eq!(&v[1..4], [-3, 1, 2]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable(..); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [`sort_unstable`]: slice::sort_unstable + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable(&mut self, range: R) + where + T: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, T::lt); + } + + /// Partially sorts the slice in ascending order with a comparison function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the `compare` does not implement a total order, or if + /// the `compare` itself panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by(0..0, |a, b| b.cmp(a)); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by(2..2, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by(2..3, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by(1..4, |a, b| b.cmp(a)); + /// assert_eq!(&v[1..4], [2, 1, -3]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by(.., |a, b| b.cmp(a)); + /// assert_eq!(v, [4, 2, 1, -3, -5]); + /// ``` + /// + /// [`sort_unstable_by`]: slice::sort_unstable_by + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by(&mut self, range: R, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| compare(a, b) == Less); + } + + /// Partially sorts the slice in ascending order with a key extraction function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by_key`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `K` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4i32, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by_key(0..0, |k| k.abs()); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by_key(2..2, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by_key(2..3, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by_key(1..4, |k| k.abs()); + /// assert_eq!(&v[1..4], [2, -3, 4]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by_key(.., |k| k.abs()); + /// assert_eq!(v, [1, 2, -3, 4, -5]); + /// ``` + /// + /// [`sort_unstable_by_key`]: slice::sort_unstable_by_key + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by_key(&mut self, range: R, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| f(a).lt(&f(b))); + } + + /// Reorders the slice such that the element at `index` is at a sort-order position. All + /// elements before `index` will be `<=` to this value, and all elements after will be `>=` to + /// it. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple that partitions the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy `x <= self[index]`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy `x >= self[index]`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, and so always panics on empty slices. + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order]. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 2, -3, 1]; + /// + /// // Find the items `<=` to the median, the median itself, and the items `>=` to it. + /// let (lesser, median, greater) = v.select_nth_unstable(2); + /// + /// assert!(lesser == [-3, -5] || lesser == [-5, -3]); + /// assert_eq!(median, &mut 1); + /// assert!(greater == [4, 2] || greater == [2, 4]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [-3, -5, 1, 2, 4] || + /// v == [-5, -3, 1, 2, 4] || + /// v == [-3, -5, 1, 4, 2] || + /// v == [-5, -3, 1, 4, 2]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + where + T: Ord, + { + sort::select::partition_at_index(self, index, T::lt) + } + + /// Reorders the slice with a comparator function such that the element at `index` is at a + /// sort-order position. All elements before `index` will be `<=` to this value, and all + /// elements after will be `>=` to it, according to the comparator function. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy + /// `compare(x, self[index]).is_le()`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy + /// `compare(x, self[index]).is_ge()`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, and so always panics on empty slices. + /// + /// May panic if `compare` does not implement a [total order]. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 2, -3, 1]; + /// + /// // Find the items `>=` to the median, the median itself, and the items `<=` to it, by using + /// // a reversed comparator. + /// let (before, median, after) = v.select_nth_unstable_by(2, |a, b| b.cmp(a)); + /// + /// assert!(before == [4, 2] || before == [2, 4]); + /// assert_eq!(median, &mut 1); + /// assert!(after == [-3, -5] || after == [-5, -3]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [2, 4, 1, -5, -3] || + /// v == [2, 4, 1, -3, -5] || + /// v == [4, 2, 1, -5, -3] || + /// v == [4, 2, 1, -3, -5]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable_by( + &mut self, + index: usize, + mut compare: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T, &T) -> Ordering, + { + sort::select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less) + } + + /// Reorders the slice with a key extraction function such that the element at `index` is at a + /// sort-order position. All elements before `index` will have keys `<=` to the key at `index`, + /// and all elements after will have keys `>=` to it. + /// + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy `f(x) <= f(self[index])`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy `f(x) >= f(self[index])`. + /// + /// # Current implementation + /// + /// The current algorithm is an introselect implementation based on [ipnsort] by Lukas Bergdoll + /// and Orson Peters, which is also the basis for [`sort_unstable`]. The fallback algorithm is + /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime + /// for all inputs. + /// + /// [`sort_unstable`]: slice::sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// May panic if `K: Ord` does not implement a total order. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Find the items `<=` to the absolute median, the absolute median itself, and the items + /// // `>=` to it. + /// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs()); + /// + /// assert!(lesser == [1, 2] || lesser == [2, 1]); + /// assert_eq!(median, &mut -3); + /// assert!(greater == [4, -5] || greater == [-5, 4]); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [1, 2, -3, 4, -5] || + /// v == [1, 2, -3, -5, 4] || + /// v == [2, 1, -3, 4, -5] || + /// v == [2, 1, -3, -5, 4]); + /// ``` + /// + /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort + /// [total order]: https://en.wikipedia.org/wiki/Total_order + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] + #[inline] + pub fn select_nth_unstable_by_key( + &mut self, + index: usize, + mut f: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T) -> K, + K: Ord, + { + sort::select::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b))) + } + + /// Moves all consecutive repeated elements to the end of the slice according to the + /// [`PartialEq`] trait implementation. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = [1, 2, 2, 3, 3, 2, 1, 1]; + /// + /// let (dedup, duplicates) = slice.partition_dedup(); + /// + /// assert_eq!(dedup, [1, 2, 3, 2, 1]); + /// assert_eq!(duplicates, [2, 3, 1]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + pub fn partition_dedup(&mut self) -> (&mut [T], &mut [T]) + where + T: PartialEq, + { + self.partition_dedup_by(|a, b| a == b) + } + + /// Moves all but the first of consecutive elements to the end of the slice that are + /// "equal" according to the given predicate function. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// The predicate `same_bucket(x, p)` is passed references to two elements from + /// the slice and must determine if the elements compare equal. The element `p` occurs + /// *before* `x` in the slice (`[.., p, .., x, ..]`), so `same_bucket(x, p)` + /// is receiving them in reversed order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. For more + /// complicated predicates however, the order (ascending vs. descending) can matter. + /// + /// Both references passed to `same_bucket` are mutable. + /// This allows merged elements in the first slice by mutating `p` and returning `true`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"]; + /// + /// let (dedup, duplicates) = slice.partition_dedup_by(|x, p| x.eq_ignore_ascii_case(p)); + /// + /// assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]); + /// assert_eq!(duplicates, ["bar", "Foo", "BAZ"]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub fn partition_dedup_by<'a, F>(&'a mut self, /*@~mut@*/ mut same_bucket: F) -> (&'a mut [T], &'a mut [T]) + where + F: FnMut(&mut T, &mut T) -> bool, + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& (.own)(t, same_bucket); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, result.0)) &*& full_borrow('a, <[T]>.full_borrow_content(t, result.1)); + //@ on_unwind_ens false; + /*@ + safety_proof { + let result = call(); + close_mut_slice_pair_own::<'a, T>(_t, result); + } + @*/ + { + // Although we have a mutable reference to `self`, we cannot make + // *arbitrary* changes. The `same_bucket` calls could panic, so we + // must ensure that the slice is in a valid state at all times. + // + // The way that we handle this is by using swaps; we iterate + // over all the elements, swapping as we go so that at the end + // the elements we wish to keep are in the front, and those we + // wish to reject are at the back. We can then split the slice. + // This operation is still `O(n)`. + // + // Example: We start in this state, where `r` represents "next + // read" and `w` represents "next_write". + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, so + // we swap self[r] and self[w] (no effect as r==w) and then increment both + // r and w, leaving us with: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this value is a duplicate, + // so we increment `r` but leave everything else unchanged: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, + // so swap self[r] and self[w] and advance r and w: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 1 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Not a duplicate, repeat: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 3 | 1 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Duplicate, advance r. End of slice. Split at w. + + let len = self.len(); + if len <= 1 { + return (self, unsafe { empty_mut_slice_arg__VeriFast_wrapper(&mut []) }); + } + + let ptr = self.as_mut_ptr(); + let mut next_read: usize = 1; + let mut next_write: usize = 1; + + //@ open_full_borrow(q, 'a, <[T]>.full_borrow_content(t, self)); + //@ open slice_full_borrow_content::(t, self)(); + //@ assert std_tuple_2__0_::<&'a mut [T], &'a mut [T]>(?r_addr, _); + + // SAFETY: the `while` condition guarantees `next_read` and `next_write` + // are less than `len`, thus are inside `self`. `prev_ptr_write` points to + // one element before `ptr_write`, but `next_write` starts at 1, so + // `prev_ptr_write` is never less than 0 and is inside the slice. + // This fulfills the requirements for dereferencing `ptr_read`, `prev_ptr_write` + // and `ptr_write`, and for using `ptr.add(next_read)`, `ptr.add(next_write - 1)` + // and `prev_ptr_write.offset(1)`. + // + // `next_write` is also incremented at most once per loop at most meaning + // no element is skipped when it may need to be swapped. + // + // `ptr_read` and `prev_ptr_write` never point to the same element. This + // is required for `&mut *ptr_read`, `&mut *prev_ptr_write` to be safe. + // The explanation is simply that `next_read >= next_write` is always true, + // thus `next_read > next_write - 1` is too. + unsafe { + // Avoid bounds checks by using raw pointers. + while next_read < len { + //@ inv thread_token(t) &*& lifetime_token(func_lft) &*& close_full_borrow_token(<[T]>.full_borrow_content(t, self), q, 'a) &*& points_to_::<(&'a mut [T], &'a mut [T])>(r_addr, _) &*& same_bucket |-> ?sb_cur &*& (.own)(t, sb_cur) &*& ptr[..len] |-> ?elems &*& foreach(elems, own::(t)) &*& 1 <= next_write &*& next_write <= next_read &*& next_read < len &*& len == self.len() &*& len * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(ptr) == true &*& pointer_within_limits(ptr + len) == true; + //@ ptr_range_split_limits::(ptr, len, next_read); + let ptr_read = ptr.add(next_read); + //@ ptr_range_split_limits::(ptr, len, next_write - 1); + let prev_ptr_write = ptr.add(next_write - 1); + //@ array_extract_two_own::(t, ptr, next_write - 1, next_read, len); + let sb_ref = &mut same_bucket; + if !call_same_bucket__VeriFast_wrapper(&mut *ptr_read, &mut *prev_ptr_write, sb_ref) { + //@ array_insert_two_own::(t, ptr, next_write - 1, next_read, len); + if next_read != next_write { + //@ ptr_range_split_limits::(prev_ptr_write, len - (next_write - 1), 1); + let ptr_write = prev_ptr_write.add(1); + //@ array_extract_two_own::(t, ptr, next_write, next_read, len); + mem::swap(&mut *ptr_read, &mut *ptr_write); + //@ array_insert_two_own::(t, ptr, next_write, next_read, len); + } + next_write += 1; + } else { + //@ array_insert_two_own::(t, ptr, next_write - 1, next_read, len); + } + next_read += 1; + } + } + + //@ close slice_full_borrow_content::(t, self)(); + //@ close_full_borrow(<[T]>.full_borrow_content(t, self)); + + self.split_at_mut(next_write) + } + + /// Moves all but the first of consecutive elements to the end of the slice that resolve + /// to the same key. + /// + /// Returns two slices. The first contains no consecutive repeated elements. + /// The second contains all the duplicates in no specified order. + /// + /// If the slice is sorted, the first returned slice contains no duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_dedup)] + /// + /// let mut slice = [10, 20, 21, 30, 30, 20, 11, 13]; + /// + /// let (dedup, duplicates) = slice.partition_dedup_by_key(|i| *i / 10); + /// + /// assert_eq!(dedup, [10, 20, 30, 20, 11]); + /// assert_eq!(duplicates, [21, 30, 13]); + /// ``` + #[unstable(feature = "slice_partition_dedup", issue = "54279")] + #[inline] + pub fn partition_dedup_by_key(&mut self, mut key: F) -> (&mut [T], &mut [T]) + where + F: FnMut(&mut T) -> K, + K: PartialEq, + { + self.partition_dedup_by(|a, b| key(a) == key(b)) + } + + /// Rotates the slice in-place such that the first `mid` elements of the + /// slice move to the end while the last `self.len() - mid` elements move to + /// the front. + /// + /// After calling `rotate_left`, the element previously at index `mid` will + /// become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `mid` is greater than the length of the + /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_left(2); + /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']); + /// ``` + /// + /// Rotating a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_left(1); + /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn rotate_left(&mut self, mid: usize) + //@ req thread_token(?t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems &*& foreach(elems, own::(t)); + //@ ens thread_token(t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems1 &*& foreach(elems1, own::(t)); + //@ on_unwind_ens false; + { + assert!(mid <= self.len()); + let k = self.len() - mid; + let p = self.as_mut_ptr(); + + // SAFETY: The range `[p.add(mid) - mid, p.add(mid) + k)` is trivially + // valid for reading and writing, as required by `ptr_rotate`. + unsafe { + //@ ptr_range_split_limits::(p, self.len(), mid); + rotate::ptr_rotate(mid, p.add(mid), k); + } + } + + /// Rotates the slice in-place such that the first `self.len() - k` + /// elements of the slice move to the end while the last `k` elements move + /// to the front. + /// + /// After calling `rotate_right`, the element previously at index + /// `self.len() - k` will become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `k` is greater than the length of the + /// slice. Note that `k == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_right(2); + /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']); + /// ``` + /// + /// Rotating a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_right(1); + /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] + #[cfg_attr(rapx, rapx::verify)] + pub const fn rotate_right(&mut self, k: usize) + //@ req thread_token(?t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems &*& foreach(elems, own::(t)); + //@ ens thread_token(t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems1 &*& foreach(elems1, own::(t)); + //@ on_unwind_ens false; + { + assert!(k <= self.len()); + let mid = self.len() - k; + let p = self.as_mut_ptr(); + + // SAFETY: The range `[p.add(mid) - mid, p.add(mid) + k)` is trivially + // valid for reading and writing, as required by `ptr_rotate`. + unsafe { + //@ ptr_range_split_limits::(p, self.len(), mid); + rotate::ptr_rotate(mid, p.add(mid), k); + } + } + + /// Moves the elements of this slice `N` places to the left, returning the ones + /// that "fall off" the front, and putting `inserted` at the end. + /// + /// Equivalently, you can think of concatenating `self` and `inserted` into one + /// long sequence, then returning the left-most `N` items and the rest into `self`: + /// + /// ```text + /// self (before) inserted + /// vvvvvvvvvvvvvvv vvv + /// [1, 2, 3, 4, 5] [9] + /// ↙ ↙ ↙ ↙ ↙ ↙ + /// [1] [2, 3, 4, 5, 9] + /// ^^^ ^^^^^^^^^^^^^^^ + /// returned self (after) + /// ``` + /// + /// See also [`Self::shift_right`] and compare [`Self::rotate_left`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_shift)] + /// + /// // Same as the diagram above + /// let mut a = [1, 2, 3, 4, 5]; + /// let inserted = [9]; + /// let returned = a.shift_left(inserted); + /// assert_eq!(returned, [1]); + /// assert_eq!(a, [2, 3, 4, 5, 9]); + /// + /// // You can shift multiple items at a time + /// let mut a = *b"Hello world"; + /// assert_eq!(a.shift_left(*b" peace"), *b"Hello "); + /// assert_eq!(a, *b"world peace"); + /// + /// // The name comes from this operation's similarity to bitshifts + /// let mut a: u8 = 0b10010110; + /// a <<= 3; + /// assert_eq!(a, 0b10110000_u8); + /// let mut a: [_; 8] = [1, 0, 0, 1, 0, 1, 1, 0]; + /// a.shift_left([0; 3]); + /// assert_eq!(a, [1, 0, 1, 1, 0, 0, 0, 0]); + /// + /// // Remember you can sub-slice to affect less that the whole slice. + /// // For example, this is similar to `.remove(1)` + `.insert(4, 'Z')` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// assert_eq!(a[1..=4].shift_left(['Z']), ['b']); + /// assert_eq!(a, ['a', 'c', 'd', 'e', 'Z', 'f']); + /// + /// // If the size matches it's equivalent to `mem::replace` + /// let mut a = [1, 2, 3]; + /// assert_eq!(a.shift_left([7, 8, 9]), [1, 2, 3]); + /// assert_eq!(a, [7, 8, 9]); + /// + /// // Some of the "inserted" elements end up returned if the slice is too short + /// let mut a = []; + /// assert_eq!(a.shift_left([1, 2, 3]), [1, 2, 3]); + /// let mut a = [9]; + /// assert_eq!(a.shift_left([1, 2, 3]), [9, 1, 2]); + /// assert_eq!(a, [3]); + /// ``` + #[unstable(feature = "slice_shift", issue = "151772")] + pub const fn shift_left(&mut self, inserted: [T; N]) -> [T; N] { + if let Some(shift) = self.len().checked_sub(N) { + // SAFETY: Having just checked that the inserted/returned arrays are + // shorter than (or the same length as) the slice: + // 1. The read for the items to return is in-bounds + // 2. We can `memmove` the slice over to cover the items we're returning + // to ensure those aren't double-dropped + // 3. Then we write (in-bounds for the same reason as the read) the + // inserted items atop the items of the slice that we just duplicated + // + // And none of this can panic, so there's no risk of intermediate unwinds. + unsafe { + let ptr = self.as_mut_ptr(); + let returned = ptr.cast_array::().read(); + ptr.copy_from(ptr.add(N), shift); + ptr.add(shift).cast_array::().write(inserted); + returned + } + } else { + // SAFETY: Having checked that the slice is strictly shorter than the + // inserted/returned arrays, it means we'll be copying the whole slice + // into the returned array, but that's not enough on its own. We also + // need to copy some of the inserted array into the returned array, + // with the rest going into the slice. Because `&mut` is exclusive + // and we own both `inserted` and `returned`, they're all disjoint + // allocations from each other as we can use `nonoverlapping` copies. + // + // We avoid double-frees by `ManuallyDrop`ing the inserted items, + // since we always copy them to other locations that will drop them + // instead. Plus nothing in here can panic -- it's just memcpy three + // times -- so there's no intermediate unwinds to worry about. + unsafe { + let len = self.len(); + let slice = self.as_mut_ptr(); + let inserted = mem::ManuallyDrop::new(inserted); + let inserted = (&raw const inserted).cast::(); + + let mut returned = MaybeUninit::<[T; N]>::uninit(); + let ptr = returned.as_mut_ptr().cast::(); + ptr.copy_from_nonoverlapping(slice, len); + ptr.add(len).copy_from_nonoverlapping(inserted, N - len); + slice.copy_from_nonoverlapping(inserted.add(N - len), len); + returned.assume_init() + } + } + } + + /// Moves the elements of this slice `N` places to the right, returning the ones + /// that "fall off" the back, and putting `inserted` at the beginning. + /// + /// Equivalently, you can think of concatenating `inserted` and `self` into one + /// long sequence, then returning the right-most `N` items and the rest into `self`: + /// + /// ```text + /// inserted self (before) + /// vvv vvvvvvvvvvvvvvv + /// [0] [5, 6, 7, 8, 9] + /// ↘ ↘ ↘ ↘ ↘ ↘ + /// [0, 5, 6, 7, 8] [9] + /// ^^^^^^^^^^^^^^^ ^^^ + /// self (after) returned + /// ``` + /// + /// See also [`Self::shift_left`] and compare [`Self::rotate_right`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_shift)] + /// + /// // Same as the diagram above + /// let mut a = [5, 6, 7, 8, 9]; + /// let inserted = [0]; + /// let returned = a.shift_right(inserted); + /// assert_eq!(returned, [9]); + /// assert_eq!(a, [0, 5, 6, 7, 8]); + /// + /// // The name comes from this operation's similarity to bitshifts + /// let mut a: u8 = 0b10010110; + /// a >>= 3; + /// assert_eq!(a, 0b00010010_u8); + /// let mut a: [_; 8] = [1, 0, 0, 1, 0, 1, 1, 0]; + /// a.shift_right([0; 3]); + /// assert_eq!(a, [0, 0, 0, 1, 0, 0, 1, 0]); + /// + /// // Remember you can sub-slice to affect less that the whole slice. + /// // For example, this is similar to `.remove(4)` + `.insert(1, 'Z')` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// assert_eq!(a[1..=4].shift_right(['Z']), ['e']); + /// assert_eq!(a, ['a', 'Z', 'b', 'c', 'd', 'f']); + /// + /// // If the size matches it's equivalent to `mem::replace` + /// let mut a = [1, 2, 3]; + /// assert_eq!(a.shift_right([7, 8, 9]), [1, 2, 3]); + /// assert_eq!(a, [7, 8, 9]); + /// + /// // Some of the "inserted" elements end up returned if the slice is too short + /// let mut a = []; + /// assert_eq!(a.shift_right([1, 2, 3]), [1, 2, 3]); + /// let mut a = [9]; + /// assert_eq!(a.shift_right([1, 2, 3]), [2, 3, 9]); + /// assert_eq!(a, [1]); + /// ``` + #[unstable(feature = "slice_shift", issue = "151772")] + pub const fn shift_right(&mut self, inserted: [T; N]) -> [T; N] { + if let Some(shift) = self.len().checked_sub(N) { + // SAFETY: Having just checked that the inserted/returned arrays are + // shorter than (or the same length as) the slice: + // 1. The read for the items to return is in-bounds + // 2. We can `memmove` the slice over to cover the items we're returning + // to ensure those aren't double-dropped + // 3. Then we write (in-bounds for the same reason as the read) the + // inserted items atop the items of the slice that we just duplicated + // + // And none of this can panic, so there's no risk of intermediate unwinds. + unsafe { + let ptr = self.as_mut_ptr(); + let returned = ptr.add(shift).cast_array::().read(); + ptr.add(N).copy_from(ptr, shift); + ptr.cast_array::().write(inserted); + returned + } + } else { + // SAFETY: Having checked that the slice is strictly shorter than the + // inserted/returned arrays, it means we'll be copying the whole slice + // into the returned array, but that's not enough on its own. We also + // need to copy some of the inserted array into the returned array, + // with the rest going into the slice. Because `&mut` is exclusive + // and we own both `inserted` and `returned`, they're all disjoint + // allocations from each other as we can use `nonoverlapping` copies. + // + // We avoid double-frees by `ManuallyDrop`ing the inserted items, + // since we always copy them to other locations that will drop them + // instead. Plus nothing in here can panic -- it's just memcpy three + // times -- so there's no intermediate unwinds to worry about. + unsafe { + let len = self.len(); + let slice = self.as_mut_ptr(); + let inserted = mem::ManuallyDrop::new(inserted); + let inserted = (&raw const inserted).cast::(); + + let mut returned = MaybeUninit::<[T; N]>::uninit(); + let ptr = returned.as_mut_ptr().cast::(); + ptr.add(N - len).copy_from_nonoverlapping(slice, len); + ptr.copy_from_nonoverlapping(inserted.add(len), N - len); + slice.copy_from_nonoverlapping(inserted, len); + returned.assume_init() + } + } + } + + /// Fills `self` with elements by cloning `value`. + /// + /// # Examples + /// + /// ``` + /// let mut buf = vec![0; 10]; + /// buf.fill(1); + /// assert_eq!(buf, vec![1; 10]); + /// ``` + #[doc(alias = "memset")] + #[stable(feature = "slice_fill", since = "1.50.0")] + pub fn fill(&mut self, value: T) + where + T: Clone, + { + specialize::SpecFill::spec_fill(self, value); + } + + /// Fills `self` with elements returned by calling a closure repeatedly. + /// + /// This method uses a closure to create new values. If you'd rather + /// [`Clone`] a given value, use [`fill`]. If you want to use the [`Default`] + /// trait to generate values, you can pass [`Default::default`] as the + /// argument. + /// + /// [`fill`]: slice::fill + /// + /// # Examples + /// + /// ``` + /// let mut buf = vec![1; 10]; + /// buf.fill_with(Default::default); + /// assert_eq!(buf, vec![0; 10]); + /// ``` + #[stable(feature = "slice_fill_with", since = "1.51.0")] + pub fn fill_with(&mut self, mut f: F) + where + F: FnMut() -> T, + { + for el in self { + *el = f(); + } + } + + /// Copies the elements from `src` into `self`. + /// + /// The length of `src` must be the same as `self`. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Cloning two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. + /// dst.clone_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `clone_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].clone_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.clone_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`copy_from_slice`]: slice::copy_from_slice + /// [`split_at_mut`]: slice::split_at_mut + #[stable(feature = "clone_from_slice", since = "1.7.0")] + #[track_caller] + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + pub const fn clone_from_slice(&mut self, src: &[T]) + where + T: [const] Clone + [const] Destruct, + { + self.spec_clone_from(src); + } + + /// Copies all elements from `src` into `self`, using a memcpy. + /// + /// The length of `src` must be the same as `self`. + /// + /// If `T` does not implement `Copy`, use [`clone_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Copying two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. + /// dst.copy_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `copy_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].copy_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.copy_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`clone_from_slice`]: slice::clone_from_slice + /// [`split_at_mut`]: slice::split_at_mut + #[doc(alias = "memcpy")] + #[inline] + #[stable(feature = "copy_from_slice", since = "1.9.0")] + #[rustc_const_stable(feature = "const_copy_from_slice", since = "1.87.0")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub const fn copy_from_slice(&mut self, src: &[T]) + where + T: Copy, + //@ req thread_token(?t) &*& [_](<[T]>.share(?k, t, src)) &*& [?q]lifetime_token(k) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems_dest &*& foreach(elems_dest, own::(t)); + //@ ens thread_token(t) &*& [q]lifetime_token(k) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems_src &*& foreach(elems_src, own::(t)) &*& self.len() == src.len(); + //@ on_unwind_ens false; + { + unsafe { copy_witness__VeriFast_wrapper::() }; + // SAFETY: `T` implements `Copy`. + unsafe { copy_from_slice_impl(self, src) } + } + + /// Copies elements from one part of the slice to another part of itself, + /// using a memmove. + /// + /// `src` is the range within `self` to copy from. `dest` is the starting + /// index of the range within `self` to copy to, which will have the same + /// length as `src`. The two ranges may overlap. The ends of the two ranges + /// must be less than or equal to `self.len()`. + /// + /// # Panics + /// + /// This function will panic if either range exceeds the end of the slice, + /// or if the end of `src` is before the start. + /// + /// # Examples + /// + /// Copying four bytes within a slice: + /// + /// ``` + /// let mut bytes = *b"Hello, World!"; + /// + /// bytes.copy_within(1..5, 8); + /// + /// assert_eq!(&bytes, b"Hello, Wello!"); + /// ``` + #[inline] + #[stable(feature = "copy_within", since = "1.37.0")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub fn copy_within>(&mut self, src: R, dest: usize) + where + T: Copy, + //@ req thread_token(?t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems &*& foreach(elems, own::(t)) &*& (.own)(t, src); + //@ ens thread_token(t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems1 &*& foreach(elems1, own::(t)); + //@ on_unwind_ens false; + { + let Range { start: src_start, end: src_end } = unsafe { slice_range__VeriFast_wrapper(src, self.len()) }; + let count = src_end - src_start; + assert!(dest <= self.len() - count, "dest is out of bounds"); + // SAFETY: the conditions for `ptr::copy` have all been checked above, + // as have those for `ptr::add`. + unsafe { + // Derive both `src_ptr` and `dest_ptr` from the same loan + let ptr = self.as_mut_ptr(); + //@ let len = self.len(); + //@ ptr_range_split_limits::(ptr, len, src_start); + //@ ptr_range_split_limits::(ptr, len, dest); + let src_ptr = ptr.add(src_start); + let dest_ptr = ptr.add(dest); + //@ close ptr::copy_context::(ptr, len, src_start, dest, count, elems); + ptr::copy(src_ptr, dest_ptr, count); + copy_witness__VeriFast_wrapper::(); + //@ copy_within_foreach_own::(t, elems, src_start, dest, count); + } + } + + /// Swaps all elements in `self` with those in `other`. + /// + /// The length of `other` must be the same as `self`. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Example + /// + /// Swapping two elements across slices: + /// + /// ``` + /// let mut slice1 = [0, 0]; + /// let mut slice2 = [1, 2, 3, 4]; + /// + /// slice1.swap_with_slice(&mut slice2[2..]); + /// + /// assert_eq!(slice1, [3, 4]); + /// assert_eq!(slice2, [1, 2, 0, 0]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference to a + /// particular piece of data in a particular scope. Because of this, + /// attempting to use `swap_with_slice` on a single slice will result in + /// a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// mutable sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.swap_with_slice(&mut right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 1, 2]); + /// ``` + /// + /// [`split_at_mut`]: slice::split_at_mut + #[stable(feature = "swap_with_slice", since = "1.27.0")] + #[rustc_const_unstable(feature = "const_swap_with_slice", issue = "142204")] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + pub const fn swap_with_slice(&mut self, other: &mut [T]) + //@ req thread_token(?t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> ?elems1 &*& foreach(elems1, own::(t)) &*& (strip_pointer_metadata(other as pointer) as *T)[..other.len()] |-> ?elems2 &*& foreach(elems2, own::(t)); + //@ ens thread_token(t) &*& (strip_pointer_metadata(self as pointer) as *T)[..self.len()] |-> elems2 &*& foreach(elems2, own::(t)) &*& (strip_pointer_metadata(other as pointer) as *T)[..other.len()] |-> elems1 &*& foreach(elems1, own::(t)) &*& self.len() == other.len(); + //@ on_unwind_ens false; + { + assert!(self.len() == other.len(), "destination and source slices have different lengths"); + // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was + // checked to have the same length. The slices cannot overlap because + // mutable references are exclusive. + unsafe { + ptr::swap_nonoverlapping(self.as_mut_ptr(), other.as_mut_ptr(), self.len()); + } + } + + /// Function to calculate lengths of the middle and trailing slice for `align_to{,_mut}`. + fn align_to_offsets(&self) -> (usize, usize) + //@ req thread_token(?t); + //@ ens thread_token(t) &*& <(usize, usize)>.own(t, result) &*& 0 <= result.0 &*& 0 <= result.1 &*& result.1 <= self.len() &*& if self.len() * std::mem::size_of::() <= isize::MAX && pointer_within_limits(strip_pointer_metadata(self as pointer) as *T) && pointer_within_limits((strip_pointer_metadata(self as pointer) as *T) + self.len()) && std::mem::size_of::() > 0 && std::mem::size_of::() > 0 { result.0 * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits((strip_pointer_metadata(self as pointer) as *U) + result.0) == true &*& result.0 * std::mem::size_of::() == (self.len() - result.1) * std::mem::size_of::() } else { true }; + //@ on_unwind_ens false; + //@ assume_correct + { + // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a + // lowest number of `T`s. And how many `T`s we need for each such "multiple". + // + // Consider for example T=u8 U=u16. Then we can put 1 U in 2 Ts. Simple. Now, consider + // for example a case where size_of:: = 16, size_of:: = 24. We can put 2 Us in + // place of every 3 Ts in the `rest` slice. A bit more complicated. + // + // Formula to calculate this is: + // + // Us = lcm(size_of::, size_of::) / size_of:: + // Ts = lcm(size_of::, size_of::) / size_of:: + // + // Expanded and simplified: + // + // Us = size_of:: / gcd(size_of::, size_of::) + // Ts = size_of:: / gcd(size_of::, size_of::) + // + // Luckily since all this is constant-evaluated... performance here matters not! + const fn gcd(a: usize, b: usize) -> usize { + if b == 0 { a } else { gcd(b, a % b) } + } + + // Explicitly wrap the function call in a const block so it gets + // constant-evaluated even in debug mode. + let gcd: usize = const { gcd(size_of::(), size_of::()) }; + let ts: usize = size_of::() / gcd; + let us: usize = size_of::() / gcd; + + // Armed with this knowledge, we can find how many `U`s we can fit! + let us_len = self.len() / ts * us; + // And how many `T`s will be in the trailing slice! + let ts_len = self.len() % ts; + (us_len, ts_len) + } + + const unsafe fn gcd_proof__VeriFast_wrapper(a: usize, b: usize) -> usize + //@ req a > 0 &*& b >= 0; + //@ ens result > 0 &*& result <= a &*& (b == 0 || result <= b) &*& a % result == 0 &*& b % result == 0; + //@ on_unwind_ens false; + { + if b == 0 { + //@ div_rem_nonneg_unique(a, a, 1, 0); + //@ div_rem_nonneg_unique(0, a, 0, 0); + a + } else { + //@ div_rem_nonneg(a, b); + //@ mul_mono_l(0, a / b, b); + //@ if a % b == 0 { mul_mono_l(1, a / b, b); } + let g = unsafe { Self::gcd_proof__VeriFast_wrapper(b, a % b) }; + // g | b and g | a % b imply g | a: a == g * ((a / b) * (b / g) + (a % b) / g). + //@ div_rem_nonneg(b, g); + //@ div_rem_nonneg(a % b, g); + //@ mul_assoc(a / b, b / g, g); + //@ div_rem_nonneg_unique(a, g, (a / b) * (b / g) + (a % b) / g, 0); + g + } + } + + unsafe fn align_to_offsets_proof__VeriFast_wrapper(&self) -> (usize, usize) + //@ req self.len() * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(strip_pointer_metadata(self as pointer) as *T) == true &*& pointer_within_limits((strip_pointer_metadata(self as pointer) as *T) + self.len()) == true &*& std::mem::size_of::() > 0 &*& std::mem::size_of::() > 0; + //@ ens 0 <= result.0 &*& result.0 <= isize::MAX &*& 0 <= result.1 &*& result.1 <= self.len() &*& result.0 * std::mem::size_of::() == (self.len() - result.1) * std::mem::size_of::() &*& result.0 * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits((strip_pointer_metadata(self as pointer) as *U) + result.0) == true; + //@ on_unwind_ens false; + { + let gcd: usize = unsafe { Self::gcd_proof__VeriFast_wrapper(size_of::(), size_of::()) }; + //@ div_rem_nonneg(std::mem::size_of::(), gcd); + let ts: usize = size_of::() / gcd; + //@ div_rem_nonneg(std::mem::size_of::(), gcd); + //@ mul_mono_l(1, gcd, std::mem::size_of::() / gcd); + let us: usize = size_of::() / gcd; + + //@ div_rem_nonneg(self.len(), ts); + //@ mul_mono_l(0, self.len() / ts, ts); + //@ mul_mono_l(1, ts, self.len() / ts); + //@ mul_mono_l(0, self.len() / ts, us); + //@ mul_mono_l(self.len() / ts, self.len(), us); + //@ mul_mono_l(us, std::mem::size_of::(), self.len()); + let us_len = self.len() / ts * us; + let ts_len = self.len() % ts; + // us_len * size_of::() == (len - ts_len) * size_of::(): both sides equal + // ((len / ts) * us) * (gcd * ts) == ((len / ts) * ts) * (gcd * us), using gcd | size_of::() + // and gcd | size_of::() (so size_of::() == gcd * ts and size_of::() == gcd * us). + //@ let q = self.len() / ts; + //@ mul_assoc(q, us, std::mem::size_of::()); + //@ mul_assoc(q, ts, std::mem::size_of::()); + //@ mul_assoc(us, gcd, ts); + //@ mul_assoc(ts, gcd, us); + //@ mul_assoc(q * us, gcd, ts); + //@ mul_assoc(q * ts, gcd, us); + //@ mul_assoc(q, us, gcd); + //@ mul_assoc(q, ts, gcd); + //@ mul_assoc(q * us, ts, gcd); + //@ mul_assoc(q * ts, us, gcd); + //@ mul_assoc(us, q, ts); + //@ mul_assoc(ts, q, us); + // us_len * size_of::() == (len - ts_len) * size_of::() <= len * size_of::() <= isize::MAX, + // and the end of the middle run, `self as *U + us_len`, is the same address as `self as *T + (len - ts_len)`, + // which `ptr_range_split_limits` places within limits. + //@ mul_mono_l(self.len() - ts_len, self.len(), std::mem::size_of::()); + //@ ptr_range_split_limits::(strip_pointer_metadata(self as pointer) as *T, self.len(), self.len() - ts_len); + (us_len, ts_len) + } + + /// Transmutes the slice to a slice of another type, ensuring alignment of the types is + /// maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle part will be as big as possible under + /// the given alignment constraint and element size. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Safety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// unsafe { + /// let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[stable(feature = "slice_align_to", since = "1.30.0")] + #[must_use] + //Checks if the part that will be transmuted from type T to U is valid for type U + //reuses most function logic up to use of from_raw_parts, + //where the potentially unsafe transmute occurs + #[requires( + U::IS_ZST || T::IS_ZST || { + let ptr = self.as_ptr(); + let offset = crate::ptr::align_offset(ptr, align_of::()); + offset > self.len() || { + let (_, rest) = self.split_at(offset); + let (us_len, _) = rest.align_to_offsets::(); + let middle = crate::ptr::slice_from_raw_parts(rest.as_ptr() as *const U, us_len); + crate::ub_checks::can_dereference(middle) + } + } + )] + //The following clause guarantees that middle is of maximum size within self + //If U or T are ZSTs, then middle has size zero, so we adapt the check in that case + #[ensures(|(prefix, _, suffix): &(&[T], &[U], &[T])| + ((U::IS_ZST || T::IS_ZST) && prefix.len() == self.len()) || ( + (prefix.len() * size_of::() < align_of::()) && + (suffix.len() * size_of::() < size_of::()) + ) + )] + //Either align_to just returns self in the prefix, or the 3 returned slices + //should be sequential, contiguous, and have same total length as self + #[ensures(|(prefix, middle, suffix): &(&[T], &[U], &[T])| + prefix.as_ptr() == self.as_ptr() && + (prefix.len() == self.len() || ( + ((prefix.as_ptr()).add(prefix.len()) as *const u8 == middle.as_ptr() as *const u8) && + ((middle.as_ptr()).add(middle.len()) as *const u8 == suffix.as_ptr() as *const u8) && + ((suffix.as_ptr()).add(suffix.len()) == (self.as_ptr()).add(self.len())) ) + ) + )] + #[cfg_attr(rapx, rapx::requires(ValidTransmute(T, U)))] + #[cfg_attr(rapx, rapx::verify)] + pub unsafe fn align_to<'a, U>(&'a self) -> (&'a [T], &'a [U], &'a [T]) + //@ req thread_token(?t) &*& [?q]lifetime_token(?a) &*& [_](<[T]>.share(a, t, self)) &*& valid_slice_transmute::() == true; + //@ ens thread_token(t) &*& [q]lifetime_token(a) &*& [_](<[T]>.share(a, t, result.0)) &*& [_](<[U]>.share(a, t, result.1)) &*& [_](<[T]>.share(a, t, result.2)); + //@ on_unwind_ens false; + { + // Note that most of this function will be constant-evaluated, + if U::IS_ZST || T::IS_ZST { + // handle ZSTs specially, which is – don't handle them at all. + return unsafe { (self, empty_slice__VeriFast_wrapper::<'a, U>(&[]), empty_slice__VeriFast_wrapper::<'a, T>(&[])) }; //~ignore_ref_creation + } + //@ std::alloc::is_valid_layout_size_of_align_of::(); + //@ std::alloc::is_valid_layout_size_of_align_of::(); + //@ slice_share_inv::(a, t, self); + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. + let ptr = self.as_ptr(); + // SAFETY: See the `align_to_mut` method for the detailed safety comment. + let offset = unsafe { crate::ptr::align_offset(ptr, align_of::()) }; + if offset > self.len() { + unsafe { (self, empty_slice__VeriFast_wrapper::<'a, U>(&[]), empty_slice__VeriFast_wrapper::<'a, T>(&[])) } //~ignore_ref_creation + } else { + let (left, rest) = self.split_at(offset); + //@ slice_share_inv::(a, t, rest); + let (us_len, ts_len) = rest.align_to_offsets::(); + //@ leak <(usize, usize)>.own(_, _); + //@ let rest_ptr = strip_pointer_metadata(rest as pointer) as *T; + //@ ptr_range_split_limits::(rest_ptr, rest.len(), rest.len() - ts_len); + // `offset <= self.len() < usize::MAX`, so `align_offset` did not fail and `rest_ptr == ptr + offset` is aligned for `U`. + //@ mul_mono_l(1, std::mem::size_of::(), self.len()); + //@ open slice_share::()(a, t, rest); + //@ array_share_split::(a, t, rest_ptr, rest.len(), rest.len() - ts_len); + //@ close slice_share::()(a, t, ptr::mk_slice::(rest_ptr + (rest.len() - ts_len), ts_len)); + //@ leak slice_share::()(a, t, ptr::mk_slice::(rest_ptr + (rest.len() - ts_len), ts_len)); + //@ share_transmute_prefix::(a, t, rest_ptr, rest.len() - ts_len, ptr::mk_slice::(rest_ptr as *U, us_len)); + // Inform Miri that we want to consider the "middle" pointer to be suitably aligned. + #[cfg(miri)] + crate::intrinsics::miri_promise_symbolic_alignment( + rest.as_ptr().cast(), + align_of::(), + ); + // SAFETY: now `rest` is definitely aligned, so `from_raw_parts` below is okay, + // since the caller guarantees that we can transmute `T` to `U` safely. + unsafe { + ( + left, + from_raw_parts(rest.as_ptr() as *const U, us_len), + from_raw_parts(rest.as_ptr().add(rest.len() - ts_len), ts_len), + ) + } + } + } + + + /// Transmutes the mutable slice to a mutable slice of another type, ensuring alignment of the + /// types is maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle part will be as big as possible under + /// the given alignment constraint and element size. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Safety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// unsafe { + /// let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to_mut::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[stable(feature = "slice_align_to", since = "1.30.0")] + #[must_use] + //Checks if the part that will be transmuted from type T to U is valid for type U + //reuses most function logic up to use of from_raw_parts, + //where the potentially unsafe transmute occurs + #[requires( + U::IS_ZST || T::IS_ZST || { + let ptr = self.as_ptr(); + let offset = crate::ptr::align_offset(ptr, align_of::()); + offset > self.len() || { + let (_, rest) = self.split_at(offset); + let (us_len, _) = rest.align_to_offsets::(); + let middle = crate::ptr::slice_from_raw_parts(rest.as_ptr() as *const U, us_len); + crate::ub_checks::can_dereference(middle) + } + } + )] + //The following clause guarantees that middle is of maximum size within self + //If U or T are ZSTs, then middle has size zero, so we adapt the check in that case + #[ensures(|(prefix, _, suffix): &(&mut [T], &mut [U], &mut [T])| + ((U::IS_ZST || T::IS_ZST) && prefix.len() == old(self.len())) || ( + (prefix.len() * size_of::() < align_of::()) && + (suffix.len() * size_of::() < size_of::()) + ) + )] + //Either align_to just returns self in the prefix, or the 3 returned slices + //should be sequential, contiguous, and have same total length as self + #[ensures(|(prefix, middle, suffix): &(&mut [T], &mut [U], &mut [T])| + prefix.as_ptr() == old(self.as_ptr()) && + (prefix.len() == old(self.len()) || ( + ((prefix.as_ptr()).add(prefix.len()) as *const u8 == middle.as_ptr() as *const u8) && + ((middle.as_ptr()).add(middle.len()) as *const u8 == suffix.as_ptr() as *const u8) && + ((suffix.as_ptr()).add(suffix.len()) == old((self.as_ptr()).add(self.len()))) + )) + )] + #[cfg_attr(rapx, rapx::requires(ValidTransmute(T, U)))] + #[cfg_attr(rapx, rapx::verify)] + pub unsafe fn align_to_mut<'a, U>(&'a mut self) -> (&'a mut [T], &'a mut [U], &'a mut [T]) + //@ req thread_token(?t) &*& [?q]lifetime_token(?a) &*& full_borrow(a, <[T]>.full_borrow_content(t, self)) &*& valid_slice_transmute::() == true; + //@ ens thread_token(t) &*& [q]lifetime_token(a) &*& full_borrow(a, <[T]>.full_borrow_content(t, result.0)) &*& full_borrow(a, <[U]>.full_borrow_content(t, result.1)) &*& full_borrow(a, <[T]>.full_borrow_content(t, result.2)); + //@ on_unwind_ens false; + { + // Note that most of this function will be constant-evaluated, + if U::IS_ZST || T::IS_ZST { + // handle ZSTs specially, which is – don't handle them at all. + unsafe { + let res = (&mut *self, empty_mut_slice_arg__VeriFast_wrapper::<'a, U>(&mut []), empty_mut_slice_arg__VeriFast_wrapper::<'a, T>(&mut [])); + return res; + } + } + //@ std::alloc::is_valid_layout_size_of_align_of::(); + //@ std::alloc::is_valid_layout_size_of_align_of::(); + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. + let ptr = self.as_ptr(); + // SAFETY: Here we are ensuring we will use aligned pointers for U for the + // rest of the method. This is done by passing a pointer to &[T] with an + // alignment targeted for U. + // `crate::ptr::align_offset` is called with a correctly aligned and + // valid pointer `ptr` (it comes from a reference to `self`) and with + // a size that is a power of two (since it comes from the alignment for U), + // satisfying its safety constraints. + let offset = unsafe { crate::ptr::align_offset(ptr, align_of::()) }; + if offset > self.len() { + unsafe { + let res = (&mut *self, empty_mut_slice_arg__VeriFast_wrapper::<'a, U>(&mut []), empty_mut_slice_arg__VeriFast_wrapper::<'a, T>(&mut [])); + res + } + } else { + let (left, rest) = self.split_at_mut(offset); + //@ slice_full_borrow_inv::(q, a, t, rest); + let (us_len, ts_len) = rest.align_to_offsets::(); + //@ leak <(usize, usize)>.own(_, _); + let rest_len = rest.len(); + let mut_ptr = rest.as_mut_ptr(); + //@ ptr_range_split_limits::(mut_ptr, rest_len, rest_len - ts_len); + // `offset == left.len() <= isize::MAX < usize::MAX`, so `align_offset` did not fail and `mut_ptr == ptr + offset` is aligned for `U`. + //@ slice_full_borrow_inv::(q, a, t, left); + //@ mul_mono_l(1, std::mem::size_of::(), left.len()); + //@ slice_full_borrow_split::(a, t, rest, rest_len - ts_len); + //@ full_borrow_transmute_prefix::(a, t, ptr::mk_slice::(mut_ptr, rest_len - ts_len), ptr::mk_slice::(mut_ptr as *U, us_len)); + // Inform Miri that we want to consider the "middle" pointer to be suitably aligned. + #[cfg(miri)] + crate::intrinsics::miri_promise_symbolic_alignment( + mut_ptr.cast() as *const (), + align_of::(), + ); + // We can't use `rest` again after this, that would invalidate its alias `mut_ptr`! + // SAFETY: see comments for `align_to`. + unsafe { + ( + left, + from_raw_parts_mut(mut_ptr as *mut U, us_len), + from_raw_parts_mut(mut_ptr.add(rest_len - ts_len), ts_len), + ) + } + } + } + + /// Splits a slice into a prefix, a middle of aligned SIMD types, and a suffix. + /// + /// This is a safe wrapper around [`slice::align_to`], so inherits the same + /// guarantees as that method. + /// + /// # Panics + /// + /// This will panic if the size of the SIMD type is different from + /// `LANES` times that of the scalar. + /// + /// At the time of writing, the trait restrictions on `Simd` keeps + /// that from ever happening, as only power-of-two numbers of lanes are + /// supported. It's possible that, in the future, those restrictions might + /// be lifted in a way that would make it possible to see panics from this + /// method for something like `LANES == 3`. + /// + /// # Examples + /// + /// ``` + /// #![feature(portable_simd)] + /// use core::simd::prelude::*; + /// + /// let short = &[1, 2, 3]; + /// let (prefix, middle, suffix) = short.as_simd::<4>(); + /// assert_eq!(middle, []); // Not enough elements for anything in the middle + /// + /// // They might be split in any possible way between prefix and suffix + /// let it = prefix.iter().chain(suffix).copied(); + /// assert_eq!(it.collect::>(), vec![1, 2, 3]); + /// + /// fn basic_simd_sum(x: &[f32]) -> f32 { + /// use std::ops::Add; + /// let (prefix, middle, suffix) = x.as_simd(); + /// let sums = f32x4::from_array([ + /// prefix.iter().copied().sum(), + /// 0.0, + /// 0.0, + /// suffix.iter().copied().sum(), + /// ]); + /// let sums = middle.iter().copied().fold(sums, f32x4::add); + /// sums.reduce_sum() + /// } + /// + /// let numbers: Vec = (1..101).map(|x| x as _).collect(); + /// assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0); + /// ``` + #[unstable(feature = "portable_simd", issue = "86656")] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub fn as_simd(&self) -> (&[T], &[Simd], &[T]) + where + Simd: AsRef<[T; LANES]>, + T: simd::SimdElement, + { + // These are expected to always match, as vector types are laid out like + // arrays per , but we + // might as well double-check since it'll optimize away anyhow. + assert_eq!(size_of::>(), size_of::<[T; LANES]>()); + + // SAFETY: The simd types have the same layout as arrays, just with + // potentially-higher alignment, so the de-facto transmutes are sound. + unsafe { self.align_to() } + } + + /// Splits a mutable slice into a mutable prefix, a middle of aligned SIMD types, + /// and a mutable suffix. + /// + /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same + /// guarantees as that method. + /// + /// This is the mutable version of [`slice::as_simd`]; see that for examples. + /// + /// # Panics + /// + /// This will panic if the size of the SIMD type is different from + /// `LANES` times that of the scalar. + /// + /// At the time of writing, the trait restrictions on `Simd` keeps + /// that from ever happening, as only power-of-two numbers of lanes are + /// supported. It's possible that, in the future, those restrictions might + /// be lifted in a way that would make it possible to see panics from this + /// method for something like `LANES == 3`. + #[unstable(feature = "portable_simd", issue = "86656")] + #[must_use] + #[cfg_attr(rapx, rapx::verify)] + pub fn as_simd_mut(&mut self) -> (&mut [T], &mut [Simd], &mut [T]) + where + Simd: AsMut<[T; LANES]>, + T: simd::SimdElement, + { + // These are expected to always match, as vector types are laid out like + // arrays per , but we + // might as well double-check since it'll optimize away anyhow. + assert_eq!(size_of::>(), size_of::<[T; LANES]>()); + + // SAFETY: The simd types have the same layout as arrays, just with + // potentially-higher alignment, so the de-facto transmutes are sound. + unsafe { self.align_to_mut() } + } + + // Transcription of `as_simd::` with `SimdVec = Simd`, `Chunk = [T; N]`, `lanes = N`. + // The two layout facts in the precondition are the `#[repr(simd)]` guarantees `as_simd` relies on + // (`Simd` has the size of `[T; N]`, element type `T`, and a possibly larger alignment that + // `align_to` accounts for); they are the caller's obligation, exactly like `is_array_of` is for the + // other const-generic wrappers, and are not assumed inside verified code. + unsafe fn as_simd_proof__VeriFast_wrapper<'a, SimdVec, Chunk>(&'a self, lanes: usize) -> (&'a [T], &'a [SimdVec], &'a [T]) + where + SimdVec: AsRef, + T: simd::SimdElement, + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(lanes) == true &*& valid_slice_transmute::() == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& [_](<[T]>.share('a, t, result.0)) &*& [_](<[SimdVec]>.share('a, t, result.1)) &*& [_](<[T]>.share('a, t, result.2)); + //@ on_unwind_ens false; + { + //@ is_array_of_layout::(lanes); + assert!(size_of::() == size_of::()); + unsafe { self.align_to() } + } + + // See `as_simd_proof__VeriFast_wrapper`. + unsafe fn as_simd_mut_proof__VeriFast_wrapper<'a, SimdVec, Chunk>(&'a mut self, lanes: usize) -> (&'a mut [T], &'a mut [SimdVec], &'a mut [T]) + where + SimdVec: AsMut, + T: simd::SimdElement, + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(lanes) == true &*& valid_slice_transmute::() == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, result.0)) &*& full_borrow('a, <[SimdVec]>.full_borrow_content(t, result.1)) &*& full_borrow('a, <[T]>.full_borrow_content(t, result.2)); + //@ on_unwind_ens false; + { + //@ is_array_of_layout::(lanes); + assert!(size_of::() == size_of::()); + unsafe { self.align_to_mut() } + } + + /// Checks if the elements of this slice are sorted. + /// + /// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the + /// slice yields exactly zero or one element, `true` is returned. + /// + /// Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition + /// implies that this function returns `false` if any two consecutive items are not + /// comparable. + /// + /// # Examples + /// + /// ``` + /// let empty: [i32; 0] = []; + /// + /// assert!([1, 2, 2, 9].is_sorted()); + /// assert!(![1, 3, 2, 4].is_sorted()); + /// assert!([0].is_sorted()); + /// assert!(empty.is_sorted()); + /// assert!(![0.0, 1.0, f32::NAN].is_sorted()); + /// ``` + #[inline] + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted(&self) -> bool + where + T: PartialOrd, + { + // This odd number works the best. 32 + 1 extra due to overlapping chunk boundaries. + const CHUNK_SIZE: usize = 33; + if self.len() < CHUNK_SIZE { + return self.windows(2).all(|w| w[0] <= w[1]); + } + let mut i = 0; + // Check in chunks for autovectorization. + while i < self.len() - CHUNK_SIZE { + let chunk = &self[i..i + CHUNK_SIZE]; + if !chunk.windows(2).fold(true, |acc, w| acc & (w[0] <= w[1])) { + return false; + } + // We need to ensure that chunk boundaries are also sorted. + // Overlap the next chunk with the last element of our last chunk. + i += CHUNK_SIZE - 1; + } + self[i..].windows(2).all(|w| w[0] <= w[1]) + } + + /// Checks if the elements of this slice are sorted using the given comparator function. + /// + /// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare` + /// function to determine whether two elements are to be considered in sorted order. + /// + /// # Examples + /// + /// ``` + /// assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b)); + /// assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b)); + /// + /// assert!([0].is_sorted_by(|a, b| true)); + /// assert!([0].is_sorted_by(|a, b| false)); + /// + /// let empty: [i32; 0] = []; + /// assert!(empty.is_sorted_by(|a, b| false)); + /// assert!(empty.is_sorted_by(|a, b| true)); + /// ``` + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted_by<'a, F>(&'a self, mut compare: F) -> bool + where + F: FnMut(&'a T, &'a T) -> bool, + { + self.array_windows().all(|[a, b]| compare(a, b)) + } + + /// Checks if the elements of this slice are sorted using the given key extraction function. + /// + /// Instead of comparing the slice's elements directly, this function compares the keys of the + /// elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see its + /// documentation for more information. + /// + /// [`is_sorted`]: slice::is_sorted + /// + /// # Examples + /// + /// ``` + /// assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); + /// assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); + /// ``` + #[inline] + #[stable(feature = "is_sorted", since = "1.82.0")] + #[must_use] + pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool + where + F: FnMut(&'a T) -> K, + K: PartialOrd, + { + self.iter().is_sorted_by_key(f) + } + + /// Returns the index of the partition point according to the given predicate + /// (the index of the first element of the second partition). + /// + /// The slice is assumed to be partitioned according to the given predicate. + /// This means that all elements for which the predicate returns true are at the start of the slice + /// and all elements for which the predicate returns false are at the end. + /// For example, `[7, 15, 3, 5, 4, 12, 6]` is partitioned under the predicate `x % 2 != 0` + /// (all odd numbers are at the start, all even at the end). + /// + /// If this slice is not partitioned, the returned result is unspecified and meaningless, + /// as this method performs a kind of binary search. + /// + /// See also [`binary_search`], [`binary_search_by`], and [`binary_search_by_key`]. + /// + /// [`binary_search`]: slice::binary_search + /// [`binary_search_by`]: slice::binary_search_by + /// [`binary_search_by_key`]: slice::binary_search_by_key + /// + /// # Examples + /// + /// ``` + /// let v = [1, 2, 3, 3, 5, 6, 7]; + /// let i = v.partition_point(|&x| x < 5); + /// + /// assert_eq!(i, 4); + /// assert!(v[..i].iter().all(|&x| x < 5)); + /// assert!(v[i..].iter().all(|&x| !(x < 5))); + /// ``` + /// + /// If all elements of the slice match the predicate, including if the slice + /// is empty, then the length of the slice will be returned: + /// + /// ``` + /// let a = [2, 4, 8]; + /// assert_eq!(a.partition_point(|x| x < &100), a.len()); + /// let a: [i32; 0] = []; + /// assert_eq!(a.partition_point(|x| x < &100), 0); + /// ``` + /// + /// If you want to insert an item to a sorted vector, while maintaining + /// sort order: + /// + /// ``` + /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// let num = 42; + /// let idx = s.partition_point(|&x| x <= num); + /// s.insert(idx, num); + /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` + #[rustc_const_unstable(feature = "const_binary_search", issue = "159532")] + #[stable(feature = "partition_point", since = "1.52.0")] + #[must_use] + pub const fn partition_point

(&self, mut pred: P) -> usize + where + P: [const] FnMut(&T) -> bool + [const] Destruct, + { + self.binary_search_by(const |x| if pred(x) { Less } else { Greater }) + .unwrap_or_else(const |i| i) + } + + /// Removes the subslice corresponding to the given range + /// and returns a reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Splitting off the first three elements of a slice: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut first_three = slice.split_off(..3).unwrap(); + /// + /// assert_eq!(slice, &['d']); + /// assert_eq!(first_three, &['a', 'b', 'c']); + /// ``` + /// + /// Splitting off a slice starting with the third element: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut tail = slice.split_off(2..).unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(tail, &['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.split_off(5..)); + /// assert_eq!(None, slice.split_off(..5)); + /// assert_eq!(None, slice.split_off(..=4)); + /// let expected: &[char] = &['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.split_off(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[stable(feature = "slice_take", since = "1.87.0")] + pub fn split_off<'a, R: OneSidedRange>( + self: &mut &'a Self, + range: R, + ) -> Option<&'a Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = self.split_at(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the subslice corresponding to the given range + /// and returns a mutable reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Splitting off the first three elements of a slice: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut first_three = slice.split_off_mut(..3).unwrap(); + /// + /// assert_eq!(slice, &mut ['d']); + /// assert_eq!(first_three, &mut ['a', 'b', 'c']); + /// ``` + /// + /// Splitting off a slice starting with the third element: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut tail = slice.split_off_mut(2..).unwrap(); + /// + /// assert_eq!(slice, &mut ['a', 'b']); + /// assert_eq!(tail, &mut ['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.split_off_mut(5..)); + /// assert_eq!(None, slice.split_off_mut(..5)); + /// assert_eq!(None, slice.split_off_mut(..=4)); + /// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.split_off_mut(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[stable(feature = "slice_take", since = "1.87.0")] + pub fn split_off_mut<'a, R: OneSidedRange>( + self: &mut &'a mut Self, + range: R, + ) -> Option<&'a mut Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = mem::take(self).split_at_mut(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the first element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let first = slice.split_off_first().unwrap(); + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'a'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((first, rem)) = self.split_first() else { return None }; + *self = rem; + Some(first) + } + + /// Removes the first element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let first = slice.split_off_first_mut().unwrap(); + /// *first = 'd'; + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'d'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_first_mut()?` + let Some((first, rem)) = mem::replace(self, &mut []).split_first_mut() else { return None }; + *self = rem; + Some(first) + } + + /// Removes the last element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let last = slice.split_off_last().unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'c'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((last, rem)) = self.split_last() else { return None }; + *self = rem; + Some(last) + } + + /// Removes the last element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let last = slice.split_off_last_mut().unwrap(); + /// *last = 'd'; + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'d'); + /// ``` + #[inline] + #[stable(feature = "slice_take", since = "1.87.0")] + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_last_mut()?` + let Some((last, rem)) = mem::replace(self, &mut []).split_last_mut() else { return None }; + *self = rem; + Some(last) + } + + /// Returns mutable references to many indices at once, without doing any checks. + /// + /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note + /// that this method takes an array, so all indices must be of the same type. + /// If passed an array of `usize`s this method gives back an array of mutable references + /// to single elements, while if passed an array of ranges it gives back an array of + /// mutable references to slices. + /// + /// For a safe alternative see [`get_disjoint_mut`]. + /// + /// # Safety + /// + /// Calling this method with overlapping or out-of-bounds indices is *[undefined behavior]* + /// even if the resulting references are not used. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([0, 2]); + /// *a *= 10; + /// *b *= 100; + /// } + /// assert_eq!(x, &[10, 2, 400]); + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([0..1, 1..3]); + /// a[0] = 8; + /// b[0] = 88; + /// b[1] = 888; + /// } + /// assert_eq!(x, &[8, 88, 888]); + /// + /// unsafe { + /// let [a, b] = x.get_disjoint_unchecked_mut([1..=2, 0..=0]); + /// a[0] = 11; + /// a[1] = 111; + /// b[0] = 1; + /// } + /// assert_eq!(x, &[1, 11, 111]); + /// ``` + /// + /// [`get_disjoint_mut`]: slice::get_disjoint_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[stable(feature = "get_many_mut", since = "1.86.0")] + #[inline] + #[track_caller] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(InBound(self, indices)))] + #[cfg_attr(rapx, rapx::requires(NonOverlap(indices)))] + // Safety precondition from the documentation: all indices in bounds and pairwise disjoint, + // i.e. exactly what `get_disjoint_mut` checks before calling this function. + #[requires(get_disjoint_check_valid(&indices, self.len()).is_ok())] + pub unsafe fn get_disjoint_unchecked_mut( + &mut self, + indices: [I; N], + ) -> [&mut I::Output; N] + where + I: GetDisjointMutIndex + SliceIndex, + { + // NB: This implementation is written as it is because any variation of + // `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy, + // or generate worse code otherwise. This is also why we need to go + // through a raw pointer here. + let slice: *mut [T] = self; + let mut arr: MaybeUninit<[&mut I::Output; N]> = MaybeUninit::uninit(); + let arr_ptr = arr.as_mut_ptr(); + + // SAFETY: We expect `indices` to contain disjunct values that are + // in bounds of `self`. + unsafe { + for i in 0..N { + let idx = indices.get_unchecked(i).clone(); + arr_ptr.cast::<&mut I::Output>().add(i).write(&mut *slice.get_unchecked_mut(idx)); + } + arr.assume_init() + } + } + + /// Returns mutable references to many indices at once. + /// + /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note + /// that this method takes an array, so all indices must be of the same type. + /// If passed an array of `usize`s this method gives back an array of mutable references + /// to single elements, while if passed an array of ranges it gives back an array of + /// mutable references to slices. + /// + /// Returns an error if any index is out-of-bounds, or if there are overlapping indices. + /// An empty range is not considered to overlap if it is located at the beginning or at + /// the end of another range, but is considered to overlap if it is located in the middle. + /// + /// This method does a O(n^2) check to check that there are no overlapping indices, so be careful + /// when passing many indices. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [1, 2, 3]; + /// if let Ok([a, b]) = v.get_disjoint_mut([0, 2]) { + /// *a = 413; + /// *b = 612; + /// } + /// assert_eq!(v, &[413, 2, 612]); + /// + /// if let Ok([a, b]) = v.get_disjoint_mut([0..1, 1..3]) { + /// a[0] = 8; + /// b[0] = 88; + /// b[1] = 888; + /// } + /// assert_eq!(v, &[8, 88, 888]); + /// + /// if let Ok([a, b]) = v.get_disjoint_mut([1..=2, 0..=0]) { + /// a[0] = 11; + /// a[1] = 111; + /// b[0] = 1; + /// } + /// assert_eq!(v, &[1, 11, 111]); + /// ``` + #[stable(feature = "get_many_mut", since = "1.86.0")] + #[inline] + #[cfg_attr(rapx, rapx::verify)] + pub fn get_disjoint_mut( + &mut self, + indices: [I; N], + ) -> Result<[&mut I::Output; N], GetDisjointMutError> + where + I: GetDisjointMutIndex + SliceIndex, + { + get_disjoint_check_valid(&indices, self.len())?; + // SAFETY: The `get_disjoint_check_valid()` call checked that all indices + // are disjunct and in bounds. + unsafe { Ok(self.get_disjoint_unchecked_mut(indices)) } + } + + /// Returns the index that an element reference points to. + /// + /// Returns `None` if `element` does not point to the start of an element within the slice. + /// + /// This method is useful for extending slice iterators like [`slice::split`]. + /// + /// Note that this uses pointer arithmetic and **does not compare elements**. + /// To find the index of an element via comparison, use + /// [`.iter().position()`](crate::iter::Iterator::position) instead. + /// + /// # Panics + /// Panics if `T` is zero-sized. + /// + /// # Examples + /// Basic usage: + /// ``` + /// let nums: &[u32] = &[1, 7, 1, 1]; + /// let num = &nums[2]; + /// + /// assert_eq!(num, &1); + /// assert_eq!(nums.element_offset(num), Some(2)); + /// ``` + /// Returning `None` with an unaligned element: + /// ``` + /// let arr: &[[u32; 2]] = &[[0, 1], [2, 3]]; + /// let flat_arr: &[u32] = arr.as_flattened(); + /// + /// let ok_elm: &[u32; 2] = flat_arr[0..2].try_into().unwrap(); + /// let weird_elm: &[u32; 2] = flat_arr[1..3].try_into().unwrap(); + /// + /// assert_eq!(ok_elm, &[0, 1]); + /// assert_eq!(weird_elm, &[1, 2]); + /// + /// assert_eq!(arr.element_offset(ok_elm), Some(0)); // Points to element 0 + /// assert_eq!(arr.element_offset(weird_elm), None); // Points between element 0 and 1 + /// ``` + #[must_use] + #[stable(feature = "element_offset", since = "1.94.0")] + pub fn element_offset(&self, element: &T) -> Option { + if T::IS_ZST { + panic!("elements are zero-sized"); + } + + let self_start = self.as_ptr().addr(); + let elem_start = ptr::from_ref(element).addr(); + + let byte_offset = elem_start.wrapping_sub(self_start); + + if !byte_offset.is_multiple_of(size_of::()) { + return None; + } + + let offset = byte_offset / size_of::(); + + if offset < self.len() { Some(offset) } else { None } + } + + /// Returns the range of indices that a subslice points to. + /// + /// Returns `None` if `subslice` does not point within the slice or if it is not aligned with the + /// elements in the slice. + /// + /// This method **does not compare elements**. Instead, this method finds the location in the slice that + /// `subslice` was obtained from. To find the index of a subslice via comparison, instead use + /// [`.windows()`](slice::windows)[`.position()`](crate::iter::Iterator::position). + /// + /// This method is useful for extending slice iterators like [`slice::split`]. + /// + /// Note that this may return a false positive (either `Some(0..0)` or `Some(self.len()..self.len())`) + /// if `subslice` has a length of zero and points to the beginning or end of another, separate, slice. + /// + /// # Panics + /// Panics if `T` is zero-sized. + /// + /// # Examples + /// Basic usage: + /// ``` + /// use core::range::Range; + /// + /// let nums = &[0, 5, 10, 0, 0, 5]; + /// + /// let mut iter = nums + /// .split(|t| *t == 0) + /// .map(|n| nums.subslice_range(n).unwrap()); + /// + /// assert_eq!(iter.next(), Some(Range { start: 0, end: 0 })); + /// assert_eq!(iter.next(), Some(Range { start: 1, end: 3 })); + /// assert_eq!(iter.next(), Some(Range { start: 4, end: 4 })); + /// assert_eq!(iter.next(), Some(Range { start: 5, end: 6 })); + /// ``` + #[must_use] + #[stable(feature = "substr_range", since = "1.98.0")] + pub fn subslice_range(&self, subslice: &[T]) -> Option> { + if T::IS_ZST { + panic!("elements are zero-sized"); + } + + let self_start = self.as_ptr().addr(); + let subslice_start = subslice.as_ptr().addr(); + + let byte_start = subslice_start.wrapping_sub(self_start); + + if !byte_start.is_multiple_of(size_of::()) { + return None; + } + + let start = byte_start / size_of::(); + let end = start.wrapping_add(subslice.len()); + + if start <= self.len() && end <= self.len() { + Some(core::range::Range { start, end }) + } else { + None + } + } + + /// Returns the same slice `&[T]`. + /// + /// This method is redundant when used directly on `&[T]`, but + /// it helps dereferencing other "container" types to slices, + /// for example `Box<[T]>` or `Arc<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_slice(&self) -> &[T] { + self + } + + /// Returns the same slice `&mut [T]`. + /// + /// This method is redundant when used directly on `&mut [T]`, but + /// it helps dereferencing other "container" types to slices, + /// for example `Box<[T]>` or `MutexGuard<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_mut_slice(&mut self) -> &mut [T] { + self + } + + const unsafe fn as_flattened_proof__VeriFast_wrapper<'a, Elem>(&'a self, n: usize) -> &'a [Elem] + //@ req thread_token(?t) &*& [_](<[T]>.share('a, t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [_](<[Elem]>.share('a, t, result)) &*& result.len() == self.len() * n; + //@ on_unwind_ens false; + { + //@ slice_share_inv::('a, t, self); + let len = if Elem::IS_ZST { + unsafe { checked_mul_or_panic__VeriFast_wrapper(self.len(), n) } + } else { + //@ std::alloc::is_valid_layout_size_of_align_of::(); + //@ flatten_non_zst_no_overflow::('a, t, self, n); + unsafe { self.len().unchecked_mul(n) } + }; + //@ share_chunks_as_flattened::('a, t, self, n, len); + unsafe { from_raw_parts(self.as_ptr() as *const Elem, len) } + } + + const unsafe fn as_flattened_mut_proof__VeriFast_wrapper<'a, Elem>(&'a mut self, n: usize) -> &'a mut [Elem] + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, self)) &*& is_array_of::(n) == true; + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& full_borrow('a, <[Elem]>.full_borrow_content(t, result)) &*& result.len() == self.len() * n; + //@ on_unwind_ens false; + { + //@ slice_full_borrow_inv::(q, 'a, t, self); + let self_len = self.len(); + let len = if Elem::IS_ZST { + unsafe { checked_mul_or_panic__VeriFast_wrapper(self_len, n) } + } else { + //@ std::alloc::is_valid_layout_size_of_align_of::(); + //@ flatten_non_zst_no_overflow::('a, t, self, n); + unsafe { self_len.unchecked_mul(n) } + }; + let ptr = self.as_mut_ptr(); + //@ full_borrow_chunks_as_flattened::('a, t, self, n, len); + unsafe { from_raw_parts_mut(ptr as *mut Elem, len) } + } +} + +const unsafe fn checked_mul_or_panic__VeriFast_wrapper(a: usize, b: usize) -> usize +//@ req true; +//@ ens result == a * b &*& a * b <= usize::MAX; +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + match a.checked_mul(b) { + Some(v) => v, + None => panic!("slice len overflow"), + } +} + +impl [MaybeUninit] { + /// Transmutes the mutable uninitialized slice to a mutable uninitialized slice of + /// another type, ensuring alignment of the types is maintained. + /// + /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same + /// guarantees as that method. + /// + /// # Examples + /// + /// ``` + /// #![feature(align_to_uninit_mut)] + /// use std::mem::MaybeUninit; + /// + /// pub struct BumpAllocator<'scope> { + /// memory: &'scope mut [MaybeUninit], + /// } + /// + /// impl<'scope> BumpAllocator<'scope> { + /// pub fn new(memory: &'scope mut [MaybeUninit]) -> Self { + /// Self { memory } + /// } + /// pub fn try_alloc_uninit(&mut self) -> Option<&'scope mut MaybeUninit> { + /// let first_end = self.memory.as_ptr().align_offset(align_of::()) + size_of::(); + /// let prefix = self.memory.split_off_mut(..first_end)?; + /// Some(&mut prefix.align_to_uninit_mut::().1[0]) + /// } + /// pub fn try_alloc_u32(&mut self, value: u32) -> Option<&'scope mut u32> { + /// let uninit = self.try_alloc_uninit()?; + /// Some(uninit.write(value)) + /// } + /// } + /// + /// let mut memory = [MaybeUninit::::uninit(); 10]; + /// let mut allocator = BumpAllocator::new(&mut memory); + /// let v = allocator.try_alloc_u32(42); + /// assert_eq!(v, Some(&mut 42)); + /// ``` + #[unstable(feature = "align_to_uninit_mut", issue = "139062")] + #[inline] + #[must_use] + pub fn align_to_uninit_mut(&mut self) -> (&mut Self, &mut [MaybeUninit], &mut Self) { + // SAFETY: `MaybeUninit` is transparent. Correct size and alignment are guaranteed by + // `align_to_mut` itself. Therefore the only thing that we have to ensure for a safe + // `transmute` is that the values are valid for the types involved. But for `MaybeUninit` + // any values are valid, so this operation is safe. + unsafe { self.align_to_mut() } + } +} + +impl [[T; N]] { + /// Takes a `&[[T; N]]`, and flattens it to a `&[T]`. + /// + /// For the opposite operation, see [`as_chunks`] and [`as_rchunks`]. + /// + /// [`as_chunks`]: slice::as_chunks + /// [`as_rchunks`]: slice::as_rchunks + /// + /// # Panics + /// + /// This panics if the length of the resulting slice would overflow a `usize`. + /// + /// This is only possible when flattening a slice of arrays of zero-sized + /// types, and thus tends to be irrelevant in practice. If + /// `size_of::() > 0`, this will never panic. + /// + /// # Examples + /// + /// ``` + /// assert_eq!([[1, 2, 3], [4, 5, 6]].as_flattened(), &[1, 2, 3, 4, 5, 6]); + /// + /// assert_eq!( + /// [[1, 2, 3], [4, 5, 6]].as_flattened(), + /// [[1, 2], [3, 4], [5, 6]].as_flattened(), + /// ); + /// + /// let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []]; + /// assert!(slice_of_empty_arrays.as_flattened().is_empty()); + /// + /// let empty_slice_of_arrays: &[[u32; 10]] = &[]; + /// assert!(empty_slice_of_arrays.as_flattened().is_empty()); + /// ``` + #[stable(feature = "slice_flatten", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidTransmute([T; N], T)))] + pub const fn as_flattened(&self) -> &[T] { + let len = if T::IS_ZST { + self.len().checked_mul(N).expect("slice len overflow") + } else { + // SAFETY: `self.len() * N` cannot overflow because `self` is + // already in the address space. + unsafe { self.len().unchecked_mul(N) } + }; + // SAFETY: `[T]` is layout-identical to `[T; N]` + unsafe { from_raw_parts(self.as_ptr().cast(), len) } + } + + /// Takes a `&mut [[T; N]]`, and flattens it to a `&mut [T]`. + /// + /// For the opposite operation, see [`as_chunks_mut`] and [`as_rchunks_mut`]. + /// + /// [`as_chunks_mut`]: slice::as_chunks_mut + /// [`as_rchunks_mut`]: slice::as_rchunks_mut + /// + /// # Panics + /// + /// This panics if the length of the resulting slice would overflow a `usize`. + /// + /// This is only possible when flattening a slice of arrays of zero-sized + /// types, and thus tends to be irrelevant in practice. If + /// `size_of::() > 0`, this will never panic. + /// + /// # Examples + /// + /// ``` + /// fn add_5_to_all(slice: &mut [i32]) { + /// for i in slice { + /// *i += 5; + /// } + /// } + /// + /// let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; + /// add_5_to_all(array.as_flattened_mut()); + /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]); + /// ``` + #[stable(feature = "slice_flatten", since = "1.80.0")] + #[rustc_const_stable(feature = "const_slice_flatten", since = "1.87.0")] + #[cfg_attr(rapx, rapx::verify)] + #[cfg_attr(rapx, rapx::requires(ValidTransmute([T; N], T)))] + pub const fn as_flattened_mut(&mut self) -> &mut [T] { + let len = if T::IS_ZST { + self.len().checked_mul(N).expect("slice len overflow") + } else { + // SAFETY: `self.len() * N` cannot overflow because `self` is + // already in the address space. + unsafe { self.len().unchecked_mul(N) } + }; + // SAFETY: `[T]` is layout-identical to `[T; N]` + unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), len) } + } +} + +impl [f32] { + /// Sorts the slice of floats. + /// + /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses + /// the ordering defined by [`f32::total_cmp`]. + /// + /// # Current implementation + /// + /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by). + /// + /// # Examples + /// + /// ``` + /// #![feature(sort_floats)] + /// let mut v = [2.6, -5e-8, f32::NAN, 8.29, f32::INFINITY, -1.0, 0.0, -f32::INFINITY, -0.0]; + /// + /// v.sort_floats(); + /// let sorted = [-f32::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f32::INFINITY, f32::NAN]; + /// assert_eq!(&v[..8], &sorted[..8]); + /// assert!(v[8].is_nan()); + /// ``` + #[unstable(feature = "sort_floats", issue = "93396")] + #[inline] + pub fn sort_floats(&mut self) { + self.sort_unstable_by(f32::total_cmp); + } +} + +impl [f64] { + /// Sorts the slice of floats. + /// + /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses + /// the ordering defined by [`f64::total_cmp`]. + /// + /// # Current implementation + /// + /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by). + /// + /// # Examples + /// + /// ``` + /// #![feature(sort_floats)] + /// let mut v = [2.6, -5e-8, f64::NAN, 8.29, f64::INFINITY, -1.0, 0.0, -f64::INFINITY, -0.0]; + /// + /// v.sort_floats(); + /// let sorted = [-f64::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f64::INFINITY, f64::NAN]; + /// assert_eq!(&v[..8], &sorted[..8]); + /// assert!(v[8].is_nan()); + /// ``` + #[unstable(feature = "sort_floats", issue = "93396")] + #[inline] + pub fn sort_floats(&mut self) { + self.sort_unstable_by(f64::total_cmp); + } +} + +/// Copies `src` to `dest`. +/// +/// # Safety +/// `T` must implement one of `Copy` or `TrivialClone`. +#[track_caller] +#[cfg_attr(rapx, rapx::verify)] +#[cfg_attr(rapx, rapx::requires(any(Trait(T, Copy), Trait(T, TrivialClone))))] +const unsafe fn copy_from_slice_impl(dest: &mut [T], src: &[T]) +//@ req thread_token(?t) &*& [_](<[T]>.share(?k, t, src)) &*& [?q]lifetime_token(k) &*& (strip_pointer_metadata(dest as pointer) as *T)[..dest.len()] |-> ?elems_dest &*& foreach(elems_dest, own::(t)) &*& is_Copy::() == true; +//@ ens thread_token(t) &*& [q]lifetime_token(k) &*& (strip_pointer_metadata(dest as pointer) as *T)[..dest.len()] |-> ?elems_src &*& foreach(elems_src, own::(t)) &*& dest.len() == src.len(); +//@ on_unwind_ens false; +{ + // The panic code path was put into a cold function to not bloat the + // call site. + #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] + #[cfg_attr(panic = "immediate-abort", inline)] + #[track_caller] + const fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! { + const_panic!( + "copy_from_slice: source slice length does not match destination slice length", + "copy_from_slice: source slice length ({src_len}) does not match destination slice length ({dst_len})", + src_len: usize, + dst_len: usize, + ) + } + + if dest.len() != src.len() { + len_mismatch_fail(dest.len(), src.len()); //~allow_dead_code + } + + // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was + // checked to have the same length. The slices cannot overlap because + // mutable references are exclusive. + unsafe { + //@ leak foreach(elems_dest, own::(t)); + //@ array_to_array_(strip_pointer_metadata(dest as pointer) as *T); + //@ open_shared_slice_copy::(k, t, src); + ptr::copy_nonoverlapping(src.as_ptr(), dest.as_mut_ptr(), dest.len()); + //@ close_shared_slice_copy::(k, src); + } +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const trait CloneFromSpec { + fn spec_clone_from(&mut self, src: &[T]) + where + T: [const] Destruct; +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const impl CloneFromSpec for [T] +where + T: [const] Clone + [const] Destruct, +{ + #[track_caller] + default fn spec_clone_from(&mut self, src: &[T]) { + assert!(self.len() == src.len(), "destination and source slices have different lengths"); + // NOTE: We need to explicitly slice them to the same length + // to make it easier for the optimizer to elide bounds checking. + // But since it can't be relied on we also have an explicit specialization for T: Copy. + let len = self.len(); + let src = &src[..len]; + for i in 0..len { + self[i].clone_from(&src[i]); + } + } +} + +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const impl CloneFromSpec for [T] +where + T: [const] TrivialClone + [const] Destruct, +{ + #[track_caller] + fn spec_clone_from(&mut self, src: &[T]) { + // SAFETY: `T` implements `TrivialClone`. + unsafe { + copy_from_slice_impl(self, src); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +const impl Default for &[T] { + /// Creates an empty slice. + fn default() -> Self { + &[] + } +} + +#[stable(feature = "mut_slice_default", since = "1.5.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +const impl Default for &mut [T] { + /// Creates a mutable empty slice. + fn default() -> Self { + &mut [] + } +} + +#[unstable(feature = "slice_pattern", reason = "stopgap trait for slice patterns", issue = "56345")] +/// Patterns in slices - currently, only used by `strip_prefix` and `strip_suffix`. At a future +/// point, we hope to generalise `core::str::Pattern` (which at the time of writing is limited to +/// `str`) to slices, and then this trait will be replaced or abolished. +pub trait SlicePattern { + /// The element type of the slice being matched on. + type Item; + + /// Currently, the consumers of `SlicePattern` need a slice. + fn as_slice(&self) -> &[Self::Item]; +} + +#[stable(feature = "slice_strip", since = "1.51.0")] +impl SlicePattern for [T] { + type Item = T; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } +} + +#[stable(feature = "slice_strip", since = "1.51.0")] +impl SlicePattern for [T; N] { + type Item = T; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } +} + +/// This checks every index against each other, and against `len`. +/// +/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..` +/// comparison operations. +#[inline] +#[cfg_attr(rapx, rapx::verify)] +fn get_disjoint_check_valid( + indices: &[I; N], + len: usize, +) -> Result<(), GetDisjointMutError> { + // NB: The optimizer should inline the loops into a sequence + // of instructions without additional branching. + for (i, idx) in indices.iter().enumerate() { + if !idx.is_in_bounds(len) { + return Err(GetDisjointMutError::IndexOutOfBounds); + } + for idx2 in &indices[..i] { + if idx.is_overlapping(idx2) { + return Err(GetDisjointMutError::OverlappingIndices); + } + } + } + Ok(()) +} + +/// The error type returned by [`get_disjoint_mut`][`slice::get_disjoint_mut`]. +/// +/// It indicates one of two possible errors: +/// - An index is out-of-bounds. +/// - The same index appeared multiple times in the array +/// (or different but overlapping indices when ranges are provided). +/// +/// # Examples +/// +/// ``` +/// use std::slice::GetDisjointMutError; +/// +/// let v = &mut [1, 2, 3]; +/// assert_eq!(v.get_disjoint_mut([0, 999]), Err(GetDisjointMutError::IndexOutOfBounds)); +/// assert_eq!(v.get_disjoint_mut([1, 1]), Err(GetDisjointMutError::OverlappingIndices)); +/// ``` +#[stable(feature = "get_many_mut", since = "1.86.0")] +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum GetDisjointMutError { + /// An index provided was out-of-bounds for the slice. + IndexOutOfBounds, + /// Two indices provided were overlapping. + OverlappingIndices, +} + +#[stable(feature = "get_many_mut", since = "1.86.0")] +impl fmt::Display for GetDisjointMutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let msg = match self { + GetDisjointMutError::IndexOutOfBounds => "an index is out of bounds", + GetDisjointMutError::OverlappingIndices => "there were overlapping indices", + }; + fmt::Display::fmt(msg, f) + } +} + +/*@ +fix all_in_bounds(xs: list, len: usize) -> bool { + match xs { + nil => true, + cons(x, xs0) => std::slice::GetDisjointMutIndex_in_bounds::(x, len) && all_in_bounds::(xs0, len), + } +} + +fix none_overlapping_with(x: I, xs: list) -> bool { + match xs { + nil => true, + cons(y, xs0) => !std::slice::GetDisjointMutIndex_overlapping::(x, y) && none_overlapping_with::(x, xs0), + } +} + +fix none_overlapping_after(y: I, xs: list) -> bool { + match xs { + nil => true, + cons(x, xs0) => !std::slice::GetDisjointMutIndex_overlapping::(x, y) && none_overlapping_after::(y, xs0), + } +} + +fix all_pairwise_disjoint(xs: list) -> bool { + match xs { + nil => true, + cons(y, xs0) => none_overlapping_after::(y, xs0) && all_pairwise_disjoint::(xs0), + } +} + +lem all_in_bounds_nth(xs: list, i: i32, len: usize) + req all_in_bounds::(xs, len) == true &*& 0 <= i &*& i < length(xs); + ens std::slice::GetDisjointMutIndex_in_bounds::(nth(i, xs), len) == true; +{ + match xs { + nil => {} + cons(h, tl) => { + if i == 0 { + } else { + all_in_bounds_nth::(tl, i - 1, len); + } + } + } +} + +// Safety precondition of the sealed `SliceIndex<[T]>::get_unchecked{,_mut}` impl for `Range`, as +// documented on `get_unchecked` ("the index must be within the bounds of the slice"), so that the +// contracts of `get_unchecked` / `get_unchecked_mut` are usable at that index type as well as at +// `usize` (`core.rsspec`). The other index types (`RangeTo`, `RangeFrom`, `RangeFull`, +// `RangeInclusive`, `core::range::*`) cannot be named in VeriFast 26.10's ghost language, so the +// contract is not usable at those types from within this proof. +lem Range_SliceIndex_in_bounds(r: std::ops::Range, slice: *[T]) + req 0 <= r.start &*& r.start <= r.end &*& r.end <= slice.len(); + ens std::slice::SliceIndex_in_bounds::, [T]>(r, slice); +{ + assume(false); +} + +lem all_in_bounds_snoc(xs: list, i: i32, len: usize) + req 0 <= i &*& i < length(xs) &*& all_in_bounds::(take(i, xs), len) == true &*& std::slice::GetDisjointMutIndex_in_bounds::(nth(i, xs), len) == true; + ens all_in_bounds::(take(i + 1, xs), len) == true; +{ + match xs { + nil => {} + cons(h, tl) => { + if i == 0 { + } else { + all_in_bounds_snoc::(tl, i - 1, len); + } + } + } +} + +lem none_overlapping_with_snoc(x: I, xs: list, j: i32) + req 0 <= j &*& j < length(xs) &*& none_overlapping_with::(x, take(j, xs)) == true &*& !std::slice::GetDisjointMutIndex_overlapping::(x, nth(j, xs)); + ens none_overlapping_with::(x, take(j + 1, xs)) == true; +{ + match xs { + nil => {} + cons(h, tl) => { + if j == 0 { + } else { + none_overlapping_with_snoc::(x, tl, j - 1); + } + } + } +} + +lem none_overlapping_after_snoc(y: I, tl: list, k: i32) + req 0 <= k &*& k < length(tl) &*& none_overlapping_after::(y, take(k, tl)) == true &*& !std::slice::GetDisjointMutIndex_overlapping::(nth(k, tl), y); + ens none_overlapping_after::(y, take(k + 1, tl)) == true; +{ + match tl { + nil => {} + cons(h, tl0) => { + if k == 0 { + } else { + none_overlapping_after_snoc::(y, tl0, k - 1); + } + } + } +} + +lem all_pairwise_disjoint_snoc(xs: list, i: i32) + req 0 <= i &*& i < length(xs) &*& all_pairwise_disjoint::(take(i, xs)) == true &*& none_overlapping_with::(nth(i, xs), take(i, xs)) == true; + ens all_pairwise_disjoint::(take(i + 1, xs)) == true; +{ + match xs { + nil => {} + cons(h, tl) => { + if i == 0 { + } else { + none_overlapping_after_snoc::(h, tl, i - 1); + all_pairwise_disjoint_snoc::(tl, i - 1); + } + } + } +} + +// Region model of the sealed `GetDisjointMutIndex` + `SliceIndex<[T]>` implementations (`usize`, +// `Range`, `RangeInclusive`, `range::Range`, `range::RangeInclusive`): +// an index `idx` denotes the contiguous element range +// `[region_start(idx), region_start(idx) + region_len(idx))`; `is_in_bounds` means that range lies +// inside the slice, `is_overlapping` means the two ranges intersect, and `get_unchecked_mut` returns +// a reference to the range (`region_ptr`: an element reference for `usize`, a sub-slice reference +// for the ranges). These are exactly the facts the `SAFETY` comments of `get_disjoint_mut` and +// `get_disjoint_unchecked_mut` rely on. +fix region_start(idx: I) -> usize; +fix region_len(idx: I) -> usize; +fix region_ptr(p: *T, idx: I) -> P; +// `P` is the type of the output slots (a mutable reference to `O` at the const-generic, hence +// transcribed, call sites); `ref_target` is the pointer such a reference denotes. Lifetimes cannot +// be parameters of VeriFast predicates, hence the indirection. +fix ref_target(r: P) -> *O; + +lem GetDisjointMutIndex_in_bounds_region(idx: I, len: usize) + req std::slice::GetDisjointMutIndex_in_bounds::(idx, len) == true; + ens 0 <= region_start::(idx) &*& 0 <= region_len::(idx) &*& region_start::(idx) + region_len::(idx) <= len; +{ + assume(false); +} + +lem GetDisjointMutIndex_not_overlapping_disjoint(a: I, b: I) + req std::slice::GetDisjointMutIndex_overlapping::(a, b) == false; + ens region_start::(a) + region_len::(a) <= region_start::(b) || region_start::(b) + region_len::(b) <= region_start::(a); +{ + assume(false); +} + +// Definition of the region model at each concrete index type. These are the meaning of the abstract +// fixpoints `region_start`, `region_len`, `GetDisjointMutIndex_in_bounds`, `GetDisjointMutIndex_overlapping` +// at `usize` and `Range` (VeriFast 26.10's ghost language has no declaration of `RangeInclusive` or of `core::range::*`, so those impls stay specless); the two generic axioms above are checked +// against them (`in_bounds_region_*`, `not_overlapping_disjoint_*`), and the `is_in_bounds` / +// `is_overlapping` implementations below are verified against `GetDisjointMutIndex_in_bounds` / +// `GetDisjointMutIndex_overlapping` through them. An empty region is normalized to `[0, 0)` so that +// disjointness of non-overlapping ranges holds without an in-bounds hypothesis. +lem usize_region_model(i: usize, len: usize, j: usize) + req true; + ens region_start::(i) == i &*& region_len::(i) == 1 &*& + std::slice::GetDisjointMutIndex_in_bounds::(i, len) == (0 <= i && i < len) &*& + std::slice::GetDisjointMutIndex_overlapping::(i, j) == (i == j); +{ + assume(false); +} + +lem Range_region_model(r: std::ops::Range, len: usize, r2: std::ops::Range) + req true; + ens region_start::>(r) == (if r.end <= r.start { 0 } else { r.start }) &*& + region_len::>(r) == (if r.end <= r.start { 0 } else { r.end - r.start }) &*& + std::slice::GetDisjointMutIndex_in_bounds::>(r, len) == (0 <= r.start && r.start <= r.end && r.end <= len) &*& + std::slice::GetDisjointMutIndex_overlapping::>(r, r2) == (r.start < r2.end && r2.start < r.end); +{ + assume(false); +} + +// The two generic region axioms hold at each defined type. +lem in_bounds_region_usize(i: usize, len: usize) + req std::slice::GetDisjointMutIndex_in_bounds::(i, len) == true; + ens 0 <= region_start::(i) &*& 0 <= region_len::(i) &*& region_start::(i) + region_len::(i) <= len; +{ + usize_region_model(i, len, i); +} + +lem not_overlapping_disjoint_usize(a: usize, b: usize) + req std::slice::GetDisjointMutIndex_overlapping::(a, b) == false; + ens region_start::(a) + region_len::(a) <= region_start::(b) || region_start::(b) + region_len::(b) <= region_start::(a); +{ + usize_region_model(a, 0, b); + usize_region_model(b, 0, a); +} + +lem in_bounds_region_Range(r: std::ops::Range, len: usize) + req std::slice::GetDisjointMutIndex_in_bounds::>(r, len) == true; + ens 0 <= region_start::>(r) &*& 0 <= region_len::>(r) &*& region_start::>(r) + region_len::>(r) <= len; +{ + Range_region_model(r, len, r); +} + +// (`0 <= a.start`, `0 <= b.start`: the fields are `usize` values; VeriFast's ghost integers do not carry +// that bound, so it is a hypothesis here.) +lem not_overlapping_disjoint_Range(a: std::ops::Range, b: std::ops::Range) + req std::slice::GetDisjointMutIndex_overlapping::>(a, b) == false &*& 0 <= a.start &*& 0 <= b.start; + ens region_start::>(a) + region_len::>(a) <= region_start::>(b) || region_start::>(b) + region_len::>(b) <= region_start::>(a); +{ + Range_region_model(a, 0, b); + Range_region_model(b, 0, a); +} + +// Ownership of the element regions denoted by `idxs`, in list order. +pred regions_owned(t: thread_id_t, p: *T, idxs: list) = + match idxs { + nil => true, + cons(idx, idxs0) => (p + region_start::(idx))[..region_len::(idx)] |-> ?es &*& foreach(es, own::(t)) &*& regions_owned::(t, p, idxs0) + }; + +// `i` lies in one of the regions of `idxs`. +fix in_some_region(i: usize, idxs: list) -> bool { + match idxs { + nil => false, + cons(idx, idxs0) => (region_start::(idx) <= i && i < region_start::(idx) + region_len::(idx)) || in_some_region::(i, idxs0), + } +} + +// The elements `p[i..len]` that lie outside the regions of `idxs`, one by one. +pred rest_elems(t: thread_id_t, p: *T, len: usize, idxs: list, i: usize) = + pointer_within_limits(p + i) == true &*& + if len <= i { + true + } else { + (if in_some_region::(i, idxs) { true } else { *(p + i) |-> ?v &*& own::(t)(v) }) &*& + rest_elems::(t, p, len, idxs, i + 1) + }; + +// The rest-elements, together with the facts that justify putting the regions back (they are pure, +// so keeping them here saves the callers of `uncarve_regions` from re-establishing them). +pred slice_rest_owned(t: thread_id_t, p: *T, len: usize, idxs: list) = + rest_elems::(t, p, len, idxs, 0) &*& 0 <= len &*& all_in_bounds::(idxs, len) == true &*& all_pairwise_disjoint::(idxs) == true; + +lem array_to_rest_elems(t: thread_id_t, p: *T, len: usize, i: usize) + req (p + i)[..len - i] |-> ?es &*& foreach(es, own::(t)) &*& 0 <= i &*& i <= len; + ens rest_elems::(t, p, len, nil, i); +{ + open array(p + i, len - i, es); + if len <= i { + open foreach(es, own::(t)); + close rest_elems::(t, p, len, nil, i); + } else { + open foreach(es, own::(t)); + array_to_rest_elems::(t, p, len, i + 1); + close rest_elems::(t, p, len, nil, i); + } +} + +lem rest_elems_to_array(t: thread_id_t, p: *T, len: usize, i: usize) + req rest_elems::(t, p, len, nil, i) &*& 0 <= i &*& i <= len; + ens (p + i)[..len - i] |-> ?es &*& foreach(es, own::(t)); +{ + open rest_elems::(t, p, len, nil, i); + if len <= i { + close array(p + i, 0, nil); + close foreach(nil, own::(t)); + } else { + rest_elems_to_array::(t, p, len, i + 1); + assert (p + i + 1)[..len - i - 1] |-> ?es0; + assert *(p + i) |-> ?v; + close array(p + i, len - i, cons(v, es0)); + close foreach(cons(v, es0), own::(t)); + } +} + +// An index of `h`'s region lies in no region of a list that `h` does not overlap. +lem not_in_regions_of_disjoint(h: I, tl: list, j: usize) + req none_overlapping_after::(h, tl) == true &*& region_start::(h) <= j &*& j < region_start::(h) + region_len::(h); + ens in_some_region::(j, tl) == false; +{ + match tl { + nil => {} + cons(x, tl0) => { + GetDisjointMutIndex_not_overlapping_disjoint::(x, h); + not_in_regions_of_disjoint::(h, tl0, j); + } + } +} + +// Beyond the end of `h`'s region, adding `h` to the hole list changes nothing. +lem rest_elems_cons_outside(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, tl, i) &*& region_start::(h) + region_len::(h) <= i; + ens rest_elems::(t, p, len, cons(h, tl), i); +{ + open rest_elems::(t, p, len, tl, i); + if len <= i { + } else { + rest_elems_cons_outside::(t, p, len, tl, h, i + 1); + } + close rest_elems::(t, p, len, cons(h, tl), i); +} + +lem rest_elems_uncons_outside(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, cons(h, tl), i) &*& region_start::(h) + region_len::(h) <= i; + ens rest_elems::(t, p, len, tl, i); +{ + open rest_elems::(t, p, len, cons(h, tl), i); + if len <= i { + } else { + rest_elems_uncons_outside::(t, p, len, tl, h, i + 1); + } + close rest_elems::(t, p, len, tl, i); +} + +// Carve the part of `h`'s region at or after `i` (with `start <= i <= end`) out of the +// rest-elements of `tl`. +lem carve_one_in(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, tl, i) &*& none_overlapping_after::(h, tl) == true &*& + region_start::(h) <= i &*& i <= region_start::(h) + region_len::(h) &*& region_start::(h) + region_len::(h) <= len; + ens rest_elems::(t, p, len, cons(h, tl), i) &*& + (p + i)[..region_start::(h) + region_len::(h) - i] |-> ?es &*& foreach(es, own::(t)); +{ + let s = region_start::(h); + let e = s + region_len::(h); + if i == e { + open rest_elems::(t, p, len, tl, i); + close rest_elems::(t, p, len, tl, i); + rest_elems_cons_outside::(t, p, len, tl, h, i); + close array(p + i, 0, nil); + close foreach(nil, own::(t)); + } else { + open rest_elems::(t, p, len, tl, i); + not_in_regions_of_disjoint::(h, tl, i); + carve_one_in::(t, p, len, tl, h, i + 1); + assert *(p + i) |-> ?v; + assert (p + i + 1)[..e - i - 1] |-> ?es0; + close array(p + i, e - i, cons(v, es0)); + close foreach(cons(v, es0), own::(t)); + close rest_elems::(t, p, len, cons(h, tl), i); + } +} + +// Same, starting before the region (`i <= start`). +lem carve_one(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, tl, i) &*& none_overlapping_after::(h, tl) == true &*& + 0 <= i &*& i <= region_start::(h) &*& 0 <= region_len::(h) &*& region_start::(h) + region_len::(h) <= len; + ens rest_elems::(t, p, len, cons(h, tl), i) &*& + (p + region_start::(h))[..region_len::(h)] |-> ?es &*& foreach(es, own::(t)); +{ + let s = region_start::(h); + if i == s { + carve_one_in::(t, p, len, tl, h, i); + } else { + open rest_elems::(t, p, len, tl, i); + carve_one::(t, p, len, tl, h, i + 1); + close rest_elems::(t, p, len, cons(h, tl), i); + } +} + +// Put the part of `h`'s region at or after `i` (`start <= i <= end`) back. Elements that another +// region of `tl` also claims, or that lie beyond `len`, are surplus and are leaked. +lem uncarve_one_in(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, cons(h, tl), i) &*& region_start::(h) <= i &*& i <= region_start::(h) + region_len::(h) &*& + (p + i)[..region_start::(h) + region_len::(h) - i] |-> ?es &*& foreach(es, own::(t)); + ens rest_elems::(t, p, len, tl, i); +{ + let s = region_start::(h); + let e = s + region_len::(h); + if i == e { + leak array(_, _, _); + leak foreach(_, _); + rest_elems_uncons_outside::(t, p, len, tl, h, i); + } else { + open rest_elems::(t, p, len, cons(h, tl), i); + if len <= i { + leak array(_, _, _); + leak foreach(_, _); + close rest_elems::(t, p, len, tl, i); + } else { + open array(p + i, e - i, es); + open foreach(es, own::(t)); + if in_some_region::(i, tl) { + leak *(p + i) |-> _; + leak own::(t)(_); + } + uncarve_one_in::(t, p, len, tl, h, i + 1); + close rest_elems::(t, p, len, tl, i); + } + } +} + +// Same, starting before the region (`i <= start`). +lem uncarve_one(t: thread_id_t, p: *T, len: usize, tl: list, h: I, i: usize) + req rest_elems::(t, p, len, cons(h, tl), i) &*& 0 <= i &*& i <= region_start::(h) &*& + (p + region_start::(h))[..region_len::(h)] |-> ?es &*& foreach(es, own::(t)); + ens rest_elems::(t, p, len, tl, i); +{ + let s = region_start::(h); + if i == s { + uncarve_one_in::(t, p, len, tl, h, i); + } else { + open rest_elems::(t, p, len, cons(h, tl), i); + if len <= i { + leak array(_, _, _); + leak foreach(_, _); + close rest_elems::(t, p, len, tl, i); + } else { + uncarve_one::(t, p, len, tl, h, i + 1); + close rest_elems::(t, p, len, tl, i); + } + } +} + +lem carve_regions(t: thread_id_t, p: *T, len: usize, idxs: list) + req p[..len] |-> ?es &*& foreach(es, own::(t)) &*& all_in_bounds::(idxs, len) == true &*& all_pairwise_disjoint::(idxs) == true; + ens regions_owned::(t, p, idxs) &*& slice_rest_owned::(t, p, len, idxs); +{ + match idxs { + nil => { + array_to_rest_elems::(t, p, len, 0); + close regions_owned::(t, p, nil); + close slice_rest_owned::(t, p, len, nil); + } + cons(h, tl) => { + carve_regions::(t, p, len, tl); + open slice_rest_owned::(t, p, len, tl); + GetDisjointMutIndex_in_bounds_region::(h, len); + carve_one::(t, p, len, tl, h, 0); + close regions_owned::(t, p, cons(h, tl)); + close slice_rest_owned::(t, p, len, cons(h, tl)); + } + } +} + +lem uncarve_regions(t: thread_id_t, p: *T, len: usize, idxs: list) + req regions_owned::(t, p, idxs) &*& slice_rest_owned::(t, p, len, idxs); + ens p[..len] |-> ?es &*& foreach(es, own::(t)); +{ + open regions_owned::(t, p, idxs); + open slice_rest_owned::(t, p, len, idxs); + match idxs { + nil => { + rest_elems_to_array::(t, p, len, 0); + } + cons(h, tl) => { + GetDisjointMutIndex_in_bounds_region::(h, len); + uncarve_one::(t, p, len, tl, h, 0); + close slice_rest_owned::(t, p, len, tl); + uncarve_regions::(t, p, len, tl); + } + } +} + +// `.full_borrow_content` of the reference `get_unchecked_mut` returns for `idx` is exactly +// the ownership of `idx`'s region: `*r |-> v &*& own(v)` for `usize`, `slice_full_borrow_content` for +// the ranges. +lem region_to_output_fbc(t: thread_id_t, p: *T, idx: I) + req (p + region_start::(idx))[..region_len::(idx)] |-> ?es &*& foreach(es, own::(t)); + ens (.full_borrow_content(t, ref_target::(region_ptr::(p, idx))))(); +{ + assume(false); +} + +lem output_fbc_to_region(t: thread_id_t, p: *T, idx: I) + req (.full_borrow_content(t, ref_target::(region_ptr::(p, idx))))(); + ens (p + region_start::(idx))[..region_len::(idx)] |-> ?es &*& foreach(es, own::(t)); +{ + assume(false); +} + +// Content of one lifetime-`k` borrow covering everything the output references point to. +pred_ctor outputs_fbc(t: thread_id_t, p: *T, idxs: list)() = + match idxs { + nil => true, + cons(idx, idxs0) => (.full_borrow_content(t, ref_target::(region_ptr::(p, idx))))() &*& outputs_fbc::(t, p, idxs0)() + }; + +lem regions_to_outputs_fbc(t: thread_id_t, p: *T, idxs: list) + req regions_owned::(t, p, idxs); + ens outputs_fbc::(t, p, idxs)(); +{ + open regions_owned::(t, p, idxs); + match idxs { + nil => { + } + cons(idx, idxs0) => { + region_to_output_fbc::(t, p, idx); + regions_to_outputs_fbc::(t, p, idxs0); + } + } + close outputs_fbc::(t, p, idxs)(); +} + +lem outputs_fbc_to_regions(t: thread_id_t, p: *T, idxs: list) + req outputs_fbc::(t, p, idxs)(); + ens regions_owned::(t, p, idxs); +{ + open outputs_fbc::(t, p, idxs)(); + match idxs { + nil => { + } + cons(idx, idxs0) => { + output_fbc_to_region::(t, p, idx); + outputs_fbc_to_regions::(t, p, idxs0); + } + } + close regions_owned::(t, p, idxs); +} + +pred_ctor slice_rest_owned_ctor(t: thread_id_t, p: *T, len: usize, idxs: list)() = slice_rest_owned::(t, p, len, idxs); + +// The references `get_disjoint_unchecked_mut` stores, in index order. +fix refs_of(p: *T, idxs: list) -> list

{ + match idxs { + nil => nil, + cons(idx, idxs0) => cons(region_ptr::(p, idx), refs_of::(p, idxs0)) + } +} + +lem refs_of_snoc(p: *T, idxs: list, idx: I) + req true; + ens refs_of::(p, append(idxs, cons(idx, nil))) == append(refs_of::(p, idxs), cons(region_ptr::(p, idx), nil)); +{ + match idxs { + nil => {} + cons(idx0, idxs0) => { + refs_of_snoc::(p, idxs0, idx); + } + } +} + +// Result of `get_disjoint_unchecked_mut`: the output references, and one lifetime-`k` borrow of +// everything they point to. `disjoint_mut_borrows_peel` turns it into the usual per-reference borrows. +pred disjoint_mut_borrows(k: lifetime_t, t: thread_id_t, out_ptr: *P, p: *T, idxs: list) = + out_ptr[..length(idxs)] |-> refs_of::(p, idxs) &*& full_borrow(k, outputs_fbc::(t, p, idxs)); + +lem disjoint_mut_borrows_peel(k: lifetime_t, t: thread_id_t, out_ptr: *P, p: *T, idx: I, idxs0: list) + nonghost_callers_only + req disjoint_mut_borrows::(k, t, out_ptr, p, cons(idx, idxs0)); + ens *out_ptr |-> region_ptr::(p, idx) &*& full_borrow(k, .full_borrow_content(t, ref_target::(region_ptr::(p, idx)))) &*& disjoint_mut_borrows::(k, t, out_ptr + 1, p, idxs0); +{ + open disjoint_mut_borrows::(k, t, out_ptr, p, cons(idx, idxs0)); + open array(out_ptr, _, _); + produce_lem_ptr_chunk implies(outputs_fbc::(t, p, cons(idx, idxs0)), sep(.full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0)))() { + open outputs_fbc::(t, p, cons(idx, idxs0))(); + close sep(.full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0))(); + } { + produce_lem_ptr_chunk implies(sep(.full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0)), outputs_fbc::(t, p, cons(idx, idxs0)))() { + open sep(.full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0))(); + close outputs_fbc::(t, p, cons(idx, idxs0))(); + } { + full_borrow_implies(k, outputs_fbc::(t, p, cons(idx, idxs0)), sep(.full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0))); + } + } + full_borrow_split(k, .full_borrow_content(t, ref_target::(region_ptr::(p, idx))), outputs_fbc::(t, p, idxs0)); + close disjoint_mut_borrows::(k, t, out_ptr + 1, p, idxs0); +} + +lem take_plus_one(n: i32, xs: list) + req 0 <= n &*& n < length(xs); + ens take(n + 1, xs) == append(take(n, xs), cons(nth(n, xs), nil)); +{ + match xs { + nil => {} + cons(h, tl) => { + if n > 0 { + take_plus_one(n - 1, tl); + } + } + } +} +@*/ + +// `GetDisjointMutIndex` is sealed (`impl(self)`): its only implementors are `usize`, `Range`, +// `RangeInclusive`, `range::Range` and `range::RangeInclusive`, all of which derive +// `Clone` field-wise, so `clone` is the identity on values and `result == nth(i, elems)` is exact for +// every type this wrapper can be instantiated with (a foreign `I` cannot implement the trait). +unsafe fn clone_disjoint_index__VeriFast_wrapper(s: &[I], i: usize) -> I +//@ req thread_token(?t) &*& [?f]((strip_pointer_metadata(s as pointer) as *I)[..s.len()] |-> ?elems) &*& 0 <= i &*& i < s.len(); +//@ ens thread_token(t) &*& [f]((strip_pointer_metadata(s as pointer) as *I)[..s.len()] |-> elems) &*& result == nth(i, elems); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + unsafe { s.get_unchecked(i).clone() } +} + +unsafe fn write_disjoint_mut_elem__VeriFast_wrapper( + slice: *mut [T], + idx: I, + out_ptr: *mut P, + i: usize, +) +where + I: GetDisjointMutIndex + SliceIndex<[T], Output = O>, +// Raw-pointer semantics of the sealed `SliceIndex::get_unchecked_mut` impls: the reference written to +// slot `i` points at `idx`'s region. No ownership of the slice is needed to compute and store it; the +// ownership transfer to the returned references happens in `get_disjoint_unchecked_mut`'s proof. +//@ req *(out_ptr + i) |-> _ &*& 0 <= i &*& std::slice::GetDisjointMutIndex_in_bounds::(idx, slice.len()) == true; +//@ ens *(out_ptr + i) |-> region_ptr::(strip_pointer_metadata(slice as pointer) as *T, idx); +//@ on_unwind_ens false; +//@ assume_correct +{ + unsafe { + let elem = &mut *slice.get_unchecked_mut(idx); + out_ptr.cast::<&mut I::Output>().add(i).write(elem); + } +} + +unsafe fn get_disjoint_check_valid_proof__VeriFast_wrapper( + indices: &[I], + len: usize, +) -> Result<(), GetDisjointMutError> +//@ req thread_token(?t) &*& [?f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> ?elems); +//@ ens thread_token(t) &*& [f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> elems) &*& match result { Result::Ok(u) => all_in_bounds::(elems, len) == true &*& all_pairwise_disjoint::(elems) == true, Result::Err(e) => true }; +//@ on_unwind_ens false; +{ + let n = indices.len(); + let base: *const I = indices.as_ptr(); + //@ let p = strip_pointer_metadata(indices as pointer) as *I; + let mut i = 0; + loop { + //@ inv thread_token(t) &*& [f](p[..n] |-> elems) &*& 0 <= i &*& i <= n &*& length(elems) == n &*& all_in_bounds::(take(i, elems), len) == true &*& all_pairwise_disjoint::(take(i, elems)) == true; + if !(i < n) { + break; + } + // `indices[i]` as a reference created from the raw element address under the aliasing protocol + // (`precreate_ref` / `init_ref_readonly` / `end_ref_readonly`), instead of a trusted indexing wrapper. + //@ array_extract_elem_frac::(p, i); + //@ points_to_limits::(p + i); + let idx_ptr = unsafe { base.add(i) }; + //@ let idx_ref = precreate_ref(idx_ptr); + //@ init_ref_readonly(idx_ref, 1/2); + let in_bounds = GetDisjointMutIndex::is_in_bounds(unsafe { &*idx_ptr }, len); + //@ end_ref_readonly(idx_ref); + //@ array_insert_elem_frac::(p, i, n, elems); + if !in_bounds { + return Err(GetDisjointMutError::IndexOutOfBounds); + } + let mut j = 0; + loop { + //@ inv thread_token(t) &*& [f](p[..n] |-> elems) &*& 0 <= j &*& j <= i &*& i < n &*& length(elems) == n &*& none_overlapping_with::(nth(i, elems), take(j, elems)) == true; + if !(j < i) { + break; + } + //@ array_extract_elem_frac::(p, i); + //@ array_extract_elem_frac::(p, j); + //@ points_to_limits::(p + i); + //@ points_to_limits::(p + j); + let idx_i_ptr = unsafe { base.add(i) }; + let idx_j_ptr = unsafe { base.add(j) }; + //@ let idx_i_ref = precreate_ref(idx_i_ptr); + //@ init_ref_readonly(idx_i_ref, 1/2); + //@ let idx_j_ref = precreate_ref(idx_j_ptr); + //@ init_ref_readonly(idx_j_ref, 1/2); + let ov = GetDisjointMutIndex::is_overlapping(unsafe { &*idx_i_ptr }, unsafe { &*idx_j_ptr }); + //@ end_ref_readonly(idx_j_ref); + //@ end_ref_readonly(idx_i_ref); + //@ array_insert_elem_frac::(p, j, i, take(i, elems)); + //@ array_insert_elem_frac::(p, i, n, elems); + if ov { + return Err(GetDisjointMutError::OverlappingIndices); + } + //@ none_overlapping_with_snoc::(nth(i, elems), elems, j); + j += 1; + } + //@ all_in_bounds_snoc::(elems, i, len); + //@ all_pairwise_disjoint_snoc::(elems, i); + i += 1; + } + Ok(()) +} + +unsafe fn get_disjoint_unchecked_mut_proof__VeriFast_wrapper<'a, T, I, O, P>( + slice_ref: &'a mut [T], + indices: &[I], + out_ptr: *mut P, +) +where + I: GetDisjointMutIndex + SliceIndex<[T], Output = O>, +//@ req thread_token(?t) &*& full_borrow(?k, <[T]>.full_borrow_content(t, slice_ref)) &*& [?q]lifetime_token(k) &*& [?f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> ?elems) &*& all_in_bounds::(elems, slice_ref.len()) == true &*& all_pairwise_disjoint::(elems) == true &*& out_ptr[..indices.len()] |-> _; +//@ ens thread_token(t) &*& [q]lifetime_token(k) &*& [f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> elems) &*& disjoint_mut_borrows::(k, t, out_ptr, strip_pointer_metadata(slice_ref as pointer) as *T, elems); +//@ on_unwind_ens false; +{ + let n = indices.len(); + let slice: *mut [T] = slice_ref; + //@ let p = strip_pointer_metadata(indices as pointer) as *I; + //@ let sp = strip_pointer_metadata(slice_ref as pointer) as *T; + //@ let len = slice_ref.len(); + //@ open_full_borrow_strong_(k, <[T]>.full_borrow_content(t, slice_ref)); + //@ open slice_full_borrow_content::(t, slice_ref)(); + //@ carve_regions::(t, sp, len, elems); + //@ close array(out_ptr, 0, nil); + let mut i = 0; + loop { + //@ inv thread_token(t) &*& [f](p[..n] |-> elems) &*& 0 <= i &*& i <= n &*& length(elems) == n &*& out_ptr[..i] |-> refs_of::(sp, take(i, elems)) &*& (out_ptr + i)[..n - i] |-> _ &*& regions_owned::(t, sp, elems) &*& slice_rest_owned::(t, sp, len, elems) &*& close_full_borrow_token_strong_(k, <[T]>.full_borrow_content(t, slice_ref), q); + if !(i < n) { + break; + } + let idx = unsafe { clone_disjoint_index__VeriFast_wrapper(indices, i) }; + //@ open array_(out_ptr + i, n - i, _); + //@ all_in_bounds_nth::(elems, i, len); + unsafe { + write_disjoint_mut_elem__VeriFast_wrapper::(slice, idx, out_ptr, i); + } + //@ close array(out_ptr + i + 1, 0, nil); + //@ close array(out_ptr + i, 1, cons(region_ptr::(sp, idx), nil)); + //@ array_join(out_ptr); + //@ take_plus_one(i, elems); + //@ refs_of_snoc::(sp, take(i, elems), nth(i, elems)); + i += 1; + } + //@ open array_(out_ptr + n, 0, _); + //@ regions_to_outputs_fbc::(t, sp, elems); + //@ close slice_rest_owned_ctor::(t, sp, len, elems)(); + //@ close sep(outputs_fbc::(t, sp, elems), slice_rest_owned_ctor::(t, sp, len, elems))(); + /*@ + produce_lem_ptr_chunk restore_full_borrow_(True, sep(outputs_fbc::(t, sp, elems), slice_rest_owned_ctor::(t, sp, len, elems)), <[T]>.full_borrow_content(t, slice_ref))() { + open True(); + open sep(outputs_fbc::(t, sp, elems), slice_rest_owned_ctor::(t, sp, len, elems))(); + open slice_rest_owned_ctor::(t, sp, len, elems)(); + outputs_fbc_to_regions::(t, sp, elems); + uncarve_regions::(t, sp, len, elems); + close slice_full_borrow_content::(t, slice_ref)(); + } { + close True(); + close_full_borrow_strong_(); + } + @*/ + //@ full_borrow_split(k, outputs_fbc::(t, sp, elems), slice_rest_owned_ctor::(t, sp, len, elems)); + //@ leak full_borrow(k, slice_rest_owned_ctor::(t, sp, len, elems)); + //@ close disjoint_mut_borrows::(k, t, out_ptr, sp, elems); +} + +unsafe fn get_disjoint_mut_proof__VeriFast_wrapper<'a, T, I, O, P>( + slice_ref: &'a mut [T], + indices: &[I], + out_ptr: *mut P, +) -> Result<(), GetDisjointMutError> +where + I: GetDisjointMutIndex + SliceIndex<[T], Output = O>, +//@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, <[T]>.full_borrow_content(t, slice_ref)) &*& [?f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> ?elems) &*& out_ptr[..indices.len()] |-> _; +//@ ens thread_token(t) &*& [q]lifetime_token('a) &*& [f]((strip_pointer_metadata(indices as pointer) as *I)[..indices.len()] |-> elems) &*& match result { Result::Ok(u) => disjoint_mut_borrows::('a, t, out_ptr, strip_pointer_metadata(slice_ref as pointer) as *T, elems), Result::Err(e) => full_borrow('a, <[T]>.full_borrow_content(t, slice_ref)) &*& out_ptr[..indices.len()] |-> _ }; +//@ on_unwind_ens false; +{ + let len = slice_ref.len(); + let check = unsafe { get_disjoint_check_valid_proof__VeriFast_wrapper(indices, len) }; + match check { + Ok(()) => { + unsafe { + get_disjoint_unchecked_mut_proof__VeriFast_wrapper::(slice_ref, indices, out_ptr); + } + Ok(()) + } + Err(e) => Err(e), + } +} + +/// A helper trait for `<[T]>::get_disjoint_mut()`. +/// +/// # Safety +/// +/// If `is_in_bounds()` returns `true` and `is_overlapping()` returns `false`, +/// it must be safe to index the slice with the indices. +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +pub impl(self) unsafe trait GetDisjointMutIndex: Clone { + /// Returns `true` if `self` is in bounds for `len` slice elements. + #[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] + fn is_in_bounds(&self, len: usize) -> bool; + + /// Returns `true` if `self` overlaps with `other`. + /// + /// Note that we don't consider zero-length ranges to overlap at the beginning or the end, + /// but do consider them to overlap in the middle. + #[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] + fn is_overlapping(&self, other: &Self) -> bool; +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for usize { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool + //@ req [?f](*self |-> ?v); + //@ ens [f](*self |-> v) &*& result == std::slice::GetDisjointMutIndex_in_bounds::(v, len); + //@ on_unwind_ens false; + /*@ + safety_proof { + assert [?q]lifetime_token(?k); + open_frac_borrow(k, usize_full_borrow_content(_t, self), q); + open [?f]usize_full_borrow_content(_t, self)(); + call(); + close [f]usize_full_borrow_content(_t, self)(); + close_frac_borrow(f, usize_full_borrow_content(_t, self)); + } + @*/ + { + //@ usize_region_model(v, len, v); + *self < len + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool + //@ req [?f1](*self |-> ?v1) &*& [?f2](*other |-> ?v2); + //@ ens [f1](*self |-> v1) &*& [f2](*other |-> v2) &*& result == std::slice::GetDisjointMutIndex_overlapping::(v1, v2); + //@ on_unwind_ens false; + /*@ + safety_proof { + assert [_]frac_borrow(?k1, usize_full_borrow_content(_t, self)) &*& [?q1]lifetime_token(k1); + assert [_]frac_borrow(?k2, usize_full_borrow_content(_t, other)) &*& [?q2]lifetime_token(k2); + open_frac_borrow(k1, usize_full_borrow_content(_t, self), q1); + open [?f1]usize_full_borrow_content(_t, self)(); + open_frac_borrow(k2, usize_full_borrow_content(_t, other), q2); + open [?f2]usize_full_borrow_content(_t, other)(); + call(); + close [f2]usize_full_borrow_content(_t, other)(); + close_frac_borrow(f2, usize_full_borrow_content(_t, other)); + close [f1]usize_full_borrow_content(_t, self)(); + close_frac_borrow(f1, usize_full_borrow_content(_t, self)); + } + @*/ + { + //@ usize_region_model(v1, 0, v2); + *self == *other + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for Range { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + (self.start <= self.end) & (self.end <= len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + (self.start < other.end) & (other.start < self.end) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for RangeInclusive { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + (self.start <= self.end) & (self.end < len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + (self.start <= other.end) & (other.start <= self.end) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for range::Range { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + Range::from(*self).is_in_bounds(len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + Range::from(*self).is_overlapping(&Range::from(*other)) + } +} + +#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")] +// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly. +unsafe impl GetDisjointMutIndex for range::RangeInclusive { + #[inline] + fn is_in_bounds(&self, len: usize) -> bool { + RangeInclusive::from(*self).is_in_bounds(len) + } + + #[inline] + fn is_overlapping(&self, other: &Self) -> bool { + RangeInclusive::from(*self).is_overlapping(&RangeInclusive::from(*other)) + } +} + +#[cfg(kani)] +#[unstable(feature = "kani", issue = "none")] +mod verify { + use super::*; + + //generates proof_of_contract harness for align_to given the T (src) and U (dst) types + macro_rules! proof_of_contract_for_align_to { + ($harness:ident, $src:ty, $dst:ty) => { + #[kani::proof_for_contract(<[$src]>::align_to)] + fn $harness() { + const ARR_SIZE: usize = 100; + let src_arr: [$src; ARR_SIZE] = kani::any(); + let src_slice = kani::slice::any_slice_of_array(&src_arr); + let dst_slice = unsafe { src_slice.align_to::<$dst>() }; + } + }; + } + + //generates harnesses for align_to where T is a given src type and U is one of the main primitives + macro_rules! gen_align_to_harnesses { + ($mod_name:ident, $src_type:ty) => { + mod $mod_name { + use super::*; + + proof_of_contract_for_align_to!(align_to_u8, $src_type, u8); + proof_of_contract_for_align_to!(align_to_u16, $src_type, u16); + proof_of_contract_for_align_to!(align_to_u32, $src_type, u32); + proof_of_contract_for_align_to!(align_to_u64, $src_type, u64); + proof_of_contract_for_align_to!(align_to_u128, $src_type, u128); + proof_of_contract_for_align_to!(align_to_bool, $src_type, bool); + proof_of_contract_for_align_to!(align_to_char, $src_type, char); + proof_of_contract_for_align_to!(align_to_unit, $src_type, ()); + } + }; + } + + gen_align_to_harnesses!(align_to_from_u8, u8); + gen_align_to_harnesses!(align_to_from_u16, u16); + gen_align_to_harnesses!(align_to_from_u32, u32); + gen_align_to_harnesses!(align_to_from_u64, u64); + gen_align_to_harnesses!(align_to_from_u128, u128); + gen_align_to_harnesses!(align_to_from_bool, bool); + gen_align_to_harnesses!(align_to_from_char, char); + gen_align_to_harnesses!(align_to_from_unit, ()); + + //generates proof_of_contract harness for align_to_mut given the T (src) and U (dst) types + macro_rules! proof_of_contract_for_align_to_mut { + ($harness:ident, $src:ty, $dst:ty) => { + #[kani::proof_for_contract(<[$src]>::align_to_mut)] + fn $harness() { + const ARR_SIZE: usize = 100; + let mut src_arr: [$src; ARR_SIZE] = kani::any(); + let src_slice = kani::slice::any_slice_of_array_mut(&mut src_arr); + let dst_slice = unsafe { src_slice.align_to_mut::<$dst>() }; + } + }; + } + + //generates harnesses between a given src type and all the main primitives + macro_rules! gen_align_to_mut_harnesses { + ($mod_name:ident, $src_type:ty) => { + mod $mod_name { + use super::*; + + proof_of_contract_for_align_to_mut!(align_to_mut_u8, $src_type, u8); + proof_of_contract_for_align_to_mut!(align_to_mut_u16, $src_type, u16); + proof_of_contract_for_align_to_mut!(align_to_mut_u32, $src_type, u32); + proof_of_contract_for_align_to_mut!(align_to_mut_u64, $src_type, u64); + proof_of_contract_for_align_to_mut!(align_to_mut_u128, $src_type, u128); + proof_of_contract_for_align_to_mut!(align_to_mut_bool, $src_type, bool); + proof_of_contract_for_align_to_mut!(align_to_mut_char, $src_type, char); + proof_of_contract_for_align_to_mut!(align_to_mut_unit, $src_type, ()); + } + }; + } + + gen_align_to_mut_harnesses!(align_to_mut_from_u8, u8); + gen_align_to_mut_harnesses!(align_to_mut_from_u16, u16); + gen_align_to_mut_harnesses!(align_to_mut_from_u32, u32); + gen_align_to_mut_harnesses!(align_to_mut_from_u64, u64); + gen_align_to_mut_harnesses!(align_to_mut_from_u128, u128); + gen_align_to_mut_harnesses!(align_to_mut_from_bool, bool); + gen_align_to_mut_harnesses!(align_to_mut_from_char, char); + gen_align_to_mut_harnesses!(align_to_mut_from_unit, ()); + + #[kani::proof] + fn check_reverse() { + let mut a: [u8; 100] = kani::any(); + a.reverse(); + } + + // Const-generic functions. The VeriFast proof in verifast-proofs/core/slice verifies these + // through runtime-`n` transcriptions (VeriFast cannot yet attach specifications to + // `` functions); the harnesses below run the exact shipped bodies, bounded in slice + // length and monomorphized over a few element types and chunk sizes. + + const CG_ARR_SIZE: usize = 12; + + macro_rules! proof_of_contract_for_as_chunks_unchecked { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof_for_contract(<[$t]>::as_chunks_unchecked)] + fn $harness() { + let arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let chunks = unsafe { s.as_chunks_unchecked::<$n>() }; + assert_eq!(chunks.len(), s.len() / $n); + } + }; + } + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u8_1, u8, 1); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u8_3, u8, 3); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_u32_2, u32, 2); + proof_of_contract_for_as_chunks_unchecked!(check_as_chunks_unchecked_unit_4, (), 4); + + macro_rules! proof_of_contract_for_as_chunks_unchecked_mut { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof_for_contract(<[$t]>::as_chunks_unchecked_mut)] + fn $harness() { + let mut arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let chunks = unsafe { s.as_chunks_unchecked_mut::<$n>() }; + assert_eq!(chunks.len(), len / $n); + } + }; + } + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u8_1, u8, 1); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u8_3, u8, 3); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_u32_2, u32, 2); + proof_of_contract_for_as_chunks_unchecked_mut!(check_as_chunks_unchecked_mut_unit_4, (), 4); + + #[kani::proof_for_contract(<[u8]>::get_disjoint_unchecked_mut)] + fn check_get_disjoint_unchecked_mut_usize() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let indices: [usize; 3] = kani::any(); + let [a, b, c] = unsafe { s.get_disjoint_unchecked_mut(indices) }; + *a = 1; + *b = 2; + *c = 3; + } + + #[kani::proof_for_contract(<[u32]>::get_disjoint_unchecked_mut)] + fn check_get_disjoint_unchecked_mut_range() { + let mut arr: [u32; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let indices: [Range; 2] = [kani::any()..kani::any(), kani::any()..kani::any()]; + let [a, b] = unsafe { s.get_disjoint_unchecked_mut(indices) }; + if let Some(x) = a.first_mut() { + *x = 1; + } + if let Some(y) = b.first_mut() { + *y = 2; + } + } + + macro_rules! check_chunk_accessors { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof] + fn $harness() { + let mut arr: [$t; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let len = s.len(); + match s.first_chunk::<$n>() { + Some(c) => assert!(len >= $n && c.as_ptr() == s.as_ptr()), + None => assert!(len < $n), + } + match s.last_chunk::<$n>() { + Some(c) => { + assert!(len >= $n && c.as_ptr() == unsafe { s.as_ptr().add(len - $n) }) + } + None => assert!(len < $n), + } + match s.split_first_chunk::<$n>() { + Some((c, rest)) => assert!(c.len() + rest.len() == len), + None => assert!(len < $n), + } + match s.split_last_chunk::<$n>() { + Some((rest, c)) => assert!(rest.len() + c.len() == len), + None => assert!(len < $n), + } + let (chunks, rem) = s.as_chunks::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + let (rem, chunks) = s.as_rchunks::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + match s.first_chunk_mut::<$n>() { + Some(c) => assert!(len >= $n && c.len() == $n), + None => assert!(len < $n), + } + match s.last_chunk_mut::<$n>() { + Some(c) => assert!(len >= $n && c.len() == $n), + None => assert!(len < $n), + } + match s.split_first_chunk_mut::<$n>() { + Some((c, rest)) => assert!(c.len() + rest.len() == len), + None => assert!(len < $n), + } + match s.split_last_chunk_mut::<$n>() { + Some((rest, c)) => assert!(rest.len() + c.len() == len), + None => assert!(len < $n), + } + let (chunks, rem) = s.as_chunks_mut::<$n>(); + assert!(chunks.len() == len / $n && rem.len() == len % $n); + } + }; + } + check_chunk_accessors!(check_chunk_accessors_u8_1, u8, 1); + check_chunk_accessors!(check_chunk_accessors_u8_3, u8, 3); + check_chunk_accessors!(check_chunk_accessors_u32_2, u32, 2); + check_chunk_accessors!(check_chunk_accessors_unit_5, (), 5); + + macro_rules! check_as_flattened { + ($harness:ident, $t:ty, $n:expr) => { + #[kani::proof] + fn $harness() { + let mut arr: [[$t; $n]; 4] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let flat = s.as_flattened(); + assert!(flat.len() == s.len() * $n); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let flat = s.as_flattened_mut(); + assert!(flat.len() == len * $n); + } + }; + } + check_as_flattened!(check_as_flattened_u8_3, u8, 3); + check_as_flattened!(check_as_flattened_u32_2, u32, 2); + check_as_flattened!(check_as_flattened_u8_0, u8, 0); + + #[kani::proof] + fn check_as_simd_u8_4() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array(&arr); + let (prefix, middle, suffix) = s.as_simd::<4>(); + assert!(prefix.len() + middle.len() * 4 + suffix.len() == s.len()); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let (prefix, middle, suffix) = s.as_simd_mut::<4>(); + assert!(prefix.len() + middle.len() * 4 + suffix.len() == len); + } + + #[kani::proof] + fn check_get_disjoint_mut_usize() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let indices: [usize; 3] = kani::any(); + let valid = get_disjoint_check_valid(&indices, len).is_ok(); + match s.get_disjoint_mut(indices) { + Ok([a, b, c]) => { + assert!(valid); + *a = 1; + *b = 2; + *c = 3; + } + Err(_) => assert!(!valid), + } + } + + #[kani::proof] + fn check_get_disjoint_mut_range() { + let mut arr: [u8; CG_ARR_SIZE] = kani::any(); + let s = kani::slice::any_slice_of_array_mut(&mut arr); + let len = s.len(); + let indices: [Range; 2] = [kani::any()..kani::any(), kani::any()..kani::any()]; + let valid = get_disjoint_check_valid(&indices, len).is_ok(); + match s.get_disjoint_mut(indices) { + Ok([a, b]) => { + assert!(valid); + assert!(a.len() + b.len() <= len); + } + Err(_) => assert!(!valid), + } + } + + #[kani::proof] + fn check_get_disjoint_check_valid() { + let len: usize = kani::any(); + kani::assume(len <= CG_ARR_SIZE); + let indices: [usize; 3] = kani::any(); + let r = get_disjoint_check_valid(&indices, len); + let in_bounds = indices.iter().all(|i| *i < len); + let disjoint = + indices[0] != indices[1] && indices[0] != indices[2] && indices[1] != indices[2]; + assert!(r.is_ok() == (in_bounds && disjoint)); + } +} diff --git a/verifast-proofs/core/slice/mod.rs/verified/slice/ascii.rs b/verifast-proofs/core/slice/mod.rs/verified/slice/ascii.rs new file mode 100644 index 0000000000000..bf427f448fe55 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/verified/slice/ascii.rs @@ -0,0 +1,4 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{EscapeAscii, SplitAsciiWhitespace, is_ascii_simple}; diff --git a/verifast-proofs/core/slice/mod.rs/verified/slice/cmp.rs b/verifast-proofs/core/slice/mod.rs/verified/slice/cmp.rs new file mode 100644 index 0000000000000..76f6305d79eb4 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/verified/slice/cmp.rs @@ -0,0 +1,7 @@ + +pub trait SliceContains { + fn slice_contains(&self, x: &[T]) -> bool; +} +impl SliceContains for T { + fn slice_contains(&self, _x: &[T]) -> bool { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs/verified/slice/index.rs b/verifast-proofs/core/slice/mod.rs/verified/slice/index.rs new file mode 100644 index 0000000000000..9fc403d41a778 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/verified/slice/index.rs @@ -0,0 +1,4 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{SliceIndex, range, try_range}; diff --git a/verifast-proofs/core/slice/mod.rs/verified/slice/iter.rs b/verifast-proofs/core/slice/mod.rs/verified/slice/iter.rs new file mode 100644 index 0000000000000..107231ba4b021 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/verified/slice/iter.rs @@ -0,0 +1,10 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{ + ArrayWindows, ChunkBy, ChunkByMut, Chunks, ChunksMut, Windows, + ChunksExact, ChunksExactMut, Iter, IterMut, + RChunks, RChunksExact, RChunksExactMut, RChunksMut, + RSplit, RSplitMut, RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut, + SplitInclusive, SplitInclusiveMut, +}; diff --git a/verifast-proofs/core/slice/mod.rs/verified/slice/memchr.rs b/verifast-proofs/core/slice/mod.rs/verified/slice/memchr.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/verifast-proofs/core/slice/mod.rs/verified/slice/raw.rs b/verifast-proofs/core/slice/mod.rs/verified/slice/raw.rs new file mode 100644 index 0000000000000..b5fff9064c46f --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/verified/slice/raw.rs @@ -0,0 +1,372 @@ +//! Free functions to create `&[T]` and `&mut [T]`. + +use crate::ops::Range; +use crate::{array, ptr, ub_checks}; + +/// Forms a slice from a pointer and a length. +/// +/// The `len` argument is the number of **elements**, not the number of bytes. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be non-null, [valid] for reads for `len * size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. See [below](#incorrect-usage) +/// for an example incorrectly not taking this into account. +/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total size `len * size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// use std::slice; +/// +/// // manifest a slice for a single element +/// let x = 42; +/// let ptr = &x as *const _; +/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; +/// assert_eq!(slice[0], 42); +/// ``` +/// +/// ### Incorrect usage +/// +/// The following `join_slices` function is **unsound** ⚠️ +/// +/// ```rust,no_run +/// use std::slice; +/// +/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { +/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); +/// let snd_start = snd.as_ptr(); +/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); +/// unsafe { +/// // The assertion above ensures `fst` and `snd` are contiguous, but they might +/// // still be contained within _different allocations_, in which case +/// // creating this slice is undefined behavior. +/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) +/// } +/// } +/// +/// fn main() { +/// // `a` and `b` are different allocations... +/// let a = 42; +/// let b = 27; +/// // ... which may nevertheless be laid out contiguously in memory: | a | b | +/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB +/// } +/// ``` +/// +/// ### FFI: Handling null pointers +/// +/// In languages such as C++, pointers to empty collections are not guaranteed to be non-null. +/// When accepting such pointers, they have to be checked for null-ness to avoid undefined +/// behavior. +/// +/// ``` +/// use std::slice; +/// +/// /// Sum the elements of an FFI slice. +/// /// +/// /// # Safety +/// /// +/// /// If ptr is not NULL, it must be correctly aligned and +/// /// point to `len` initialized items of type `f32`. +/// unsafe extern "C" fn sum_slice(ptr: *const f32, len: usize) -> f32 { +/// let data = if ptr.is_null() { +/// // `len` is assumed to be 0. +/// &[] +/// } else { +/// // SAFETY: see function docstring. +/// unsafe { slice::from_raw_parts(ptr, len) } +/// }; +/// data.into_iter().sum() +/// } +/// +/// // This could be the result of C++'s std::vector::data(): +/// let ptr = std::ptr::null(); +/// // And this could be std::vector::size(): +/// let len = 0; +/// assert_eq!(unsafe { sum_slice(ptr, len) }, 0.0); +/// ``` +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] +#[must_use] +#[rustc_diagnostic_item = "slice_from_raw_parts"] +#[track_caller] +#[cfg_attr(rapx, rapx::requires(NonNull(data)))] +#[cfg_attr(rapx, rapx::requires(ValidPtr(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Init(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Alive(data, 'a)))] +#[cfg_attr(rapx, rapx::requires(Alias(data)))] +#[cfg_attr(rapx, rapx::requires(Align(data, T)))] +#[cfg_attr(rapx, rapx::requires(ValidNum(size_of(T) * len <= isize::MAX)))] +pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] +//@ req len * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(data) == true &*& pointer_within_limits(data + len) == true; +//@ ens result == ptr::mk_slice::(data, len) &*& strip_pointer_metadata(result as pointer) as *T == data &*& result as *T == data &*& result.len() == len; +//@ on_unwind_ens false; +{ + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`", + ( + data: *mut () = data as *mut (), + size: usize = size_of::(), + align: usize = align_of::(), + len: usize = len, + ) => + ub_checks::maybe_is_aligned_and_not_null(data, align, false) + && ub_checks::is_valid_allocation_size(size, len) + ); + &*ptr::slice_from_raw_parts(data, len) + } +} + +/// Performs the same functionality as [`from_raw_parts`], except that a +/// mutable slice is returned. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be non-null, [valid] for both reads and writes for `len * size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// * `data` must be non-null and aligned even for zero-length slices or slices of ZSTs. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total size `len * size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")] +#[must_use] +#[rustc_diagnostic_item = "slice_from_raw_parts_mut"] +#[track_caller] +#[cfg_attr(rapx, rapx::requires(NonNull(data)))] +#[cfg_attr(rapx, rapx::requires(ValidPtr(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Init(data, T, len)))] +#[cfg_attr(rapx, rapx::requires(Alive(data, 'a)))] +#[cfg_attr(rapx, rapx::requires(Alias(data)))] +#[cfg_attr(rapx, rapx::requires(Align(data, T)))] +#[cfg_attr(rapx, rapx::requires(ValidNum(size_of(T) * len <= isize::MAX)))] +pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] +//@ req len * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(data) == true &*& pointer_within_limits(data + len) == true; +//@ ens result == ptr::mk_slice::(data, len) &*& strip_pointer_metadata(result as pointer) as *T == data &*& result as *T == data &*& result.len() == len; +//@ on_unwind_ens false; +{ + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`", + ( + data: *mut () = data as *mut (), + size: usize = size_of::(), + align: usize = align_of::(), + len: usize = len, + ) => + ub_checks::maybe_is_aligned_and_not_null(data, align, false) + && ub_checks::is_valid_allocation_size(size, len) + ); + &mut *ptr::slice_from_raw_parts_mut(data, len) + } +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +#[rustc_const_stable(feature = "const_slice_from_ref_shared", since = "1.63.0")] +#[rustc_diagnostic_item = "slice_from_ref"] +#[must_use] +pub const fn from_ref(s: &T) -> &[T] { + array::from_ref(s) +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +#[rustc_const_stable(feature = "const_slice_from_ref", since = "1.83.0")] +#[must_use] +pub const fn from_mut(s: &mut T) -> &mut [T] { + array::from_mut(s) +} + +/// Forms a slice from a pointer range. +/// +/// This function is useful for interacting with foreign interfaces which +/// use two pointers to refer to a range of elements in memory, as is +/// common in C++. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * The `start` pointer of the range must be a non-null, [valid] and properly aligned pointer +/// to the first element of a slice. +/// +/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* +/// the last element, such that the offset from the end to the start pointer is +/// the length of the slice. +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// +/// * The range must contain `N` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `start` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements. +/// +/// # Panics +/// +/// This function panics if `T` is a Zero-Sized Type (“ZST”). +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_from_ptr_range)] +/// +/// use core::slice; +/// +/// let x = [1, 2, 3]; +/// let range = x.as_ptr_range(); +/// +/// unsafe { +/// assert_eq!(slice::from_ptr_range(range), &x); +/// } +/// ``` +/// +/// [valid]: ptr#safety +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +#[rustc_const_unstable(feature = "const_slice_from_ptr_range", issue = "89792")] +#[track_caller] +pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { + // SAFETY: the caller must uphold the safety contract for `from_ptr_range`. + unsafe { from_raw_parts(range.start, range.end.offset_from_unsigned(range.start)) } +} + +/// Forms a mutable slice from a pointer range. +/// +/// This is the same functionality as [`from_ptr_range`], except that a +/// mutable slice is returned. +/// +/// This function is useful for interacting with foreign interfaces which +/// use two pointers to refer to a range of elements in memory, as is +/// common in C++. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * The `start` pointer of the range must be a non-null, [valid] and properly aligned pointer +/// to the first element of a slice. +/// +/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* +/// the last element, such that the offset from the end to the start pointer is +/// the length of the slice. +/// +/// * The entire memory range of this slice must be contained within a single allocation! +/// Slices can never span across multiple allocations. +/// +/// * The range must contain `N` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `start` must not "wrap around" the address space. +/// See the safety documentation of [`pointer::offset`]. +/// +/// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements. +/// +/// # Panics +/// +/// This function panics if `T` is a Zero-Sized Type (“ZST”). +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_from_ptr_range)] +/// +/// use core::slice; +/// +/// let mut x = [1, 2, 3]; +/// let range = x.as_mut_ptr_range(); +/// +/// unsafe { +/// assert_eq!(slice::from_mut_ptr_range(range), &mut [1, 2, 3]); +/// } +/// ``` +/// +/// [valid]: ptr#safety +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +#[rustc_const_unstable(feature = "const_slice_from_mut_ptr_range", issue = "89792")] +pub const unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] { + // SAFETY: the caller must uphold the safety contract for `from_mut_ptr_range`. + unsafe { from_raw_parts_mut(range.start, range.end.offset_from_unsigned(range.start)) } +} diff --git a/verifast-proofs/core/slice/mod.rs/verified/slice/rotate.rs b/verifast-proofs/core/slice/mod.rs/verified/slice/rotate.rs new file mode 100644 index 0000000000000..e688d40f8435c --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/verified/slice/rotate.rs @@ -0,0 +1,619 @@ +use crate::mem::{MaybeUninit, SizedTypeProperties}; +use crate::ptr; + +type BufType = [usize; 32]; + +const unsafe fn uninit_buf__VeriFast_wrapper() -> MaybeUninit<(BufType, [T; 0])> +//@ req true; +//@ ens true; +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + MaybeUninit::<(BufType, [T; 0])>::uninit() +} + +const unsafe fn uninit_buf_as_mut_ptr__VeriFast_wrapper( + rawarray: &mut MaybeUninit<(BufType, [T; 0])>, +) -> *mut (BufType, [T; 0]) +//@ req *rawarray |-> ?v; +//@ ens *rawarray |-> v &*& result == rawarray as *mut (BufType, [T; 0]); +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + rawarray.as_mut_ptr() +} + +const unsafe fn ptr_replace__VeriFast_wrapper(dst: *mut T, src: T) -> T +//@ req *dst |-> ?v; +//@ ens *dst |-> src &*& result == v; +//@ on_unwind_ens false; +// https://github.com/verifast/verifast/issues/1056 +//@ assume_correct +{ + unsafe { dst.replace(src) } +} + +/*@ +lem rotate_ptr_limits(ptr: *T, len: usize, mid: usize) + req 0 <= mid &*& mid <= len &*& 0 < std::mem::size_of::() &*& len * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(ptr) == true &*& pointer_within_limits(ptr + len) == true; + ens mid <= isize::MAX &*& len - mid <= isize::MAX &*& len <= isize::MAX &*& mid * std::mem::size_of::() <= isize::MAX &*& (len - mid) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(ptr + mid) == true &*& ((ptr + mid) + (len - mid)) == ptr + len &*& ((ptr + len) - (len - mid)) == ptr + mid; +{ + mul_mono_l(1, std::mem::size_of::(), len); + mul_mono_l(0, mid, std::mem::size_of::()); + mul_mono_l(mid, len, std::mem::size_of::()); + mul_mono_l(0, len - mid, std::mem::size_of::()); + mul_mono_l(len - mid, len, std::mem::size_of::()); +} + +// Reinterpretation of the uninitialized stack buffer `MaybeUninit<(BufType, [T; 0])>` (whose size is +// `size_of::()`, as `[T; 0]` is a ZST) as `k` uninitialized `T` slots, and back. VeriFast's +// prelude has `u8s__to_array_` only for `u8` reinterpretation, so this is axiomatized, with the +// buffer type fixed to the one `ptr_rotate_memmove` uses and the bound stated in bytes. +pred rawarray_rest(rawarray: *std::mem::MaybeUninit<([usize; 32], [T; 0])>, k: usize); + +lem rawarray_to_buf(rawarray: *std::mem::MaybeUninit<([usize; 32], [T; 0])>, buf: *T, k: usize) + req *rawarray |-> ?_ &*& buf == rawarray as *T &*& 0 <= k &*& 0 < std::mem::size_of::() &*& k * std::mem::size_of::() <= std::mem::size_of(typeid([usize; 32])); + ens buf[..k] |-> _ &*& rawarray_rest::(rawarray, k); +{ + // https://github.com/verifast/verifast/issues/1053 + assume(false); +} + +lem buf_to_rawarray(rawarray: *std::mem::MaybeUninit<([usize; 32], [T; 0])>, buf: *T, k: usize) + req buf[..k] |-> _ &*& rawarray_rest::(rawarray, k); + ens *rawarray |-> ?_; +{ + // https://github.com/verifast/verifast/issues/1053 + assume(false); +} +@*/ + +/// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first +/// element. Equivalently, rotates the range `left` elements to the left or `right` elements to the +/// right. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +pub(super) const unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) +//@ req thread_token(?t) &*& (mid - left)[..left + right] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 <= left &*& 0 <= right &*& left + right <= usize::MAX &*& (left + right) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(mid - left) == true &*& pointer_within_limits(mid + right) == true; +//@ ens thread_token(t) &*& (mid - left)[..left + right] |-> ?elems1 &*& foreach(elems1, own::(t)); +//@ on_unwind_ens false; +{ + if T::IS_ZST { + return; + } + // abort early if the rotate is a no-op + if (left == 0) || (right == 0) { + return; + } + // `T` is not a zero-sized type, so it's okay to divide by its size. + //@ std::alloc::is_valid_layout_size_of_align_of::(); + if !cfg!(feature = "optimize_for_size") + // FIXME(const-hack): Use cmp::min when available in const + && const_min(left, right) <= size_of::() / size_of::() + { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_memmove(left, mid, right) }; + } else if !cfg!(feature = "optimize_for_size") + && ((left + right < 24) || (size_of::() > size_of::<[usize; 4]>())) + { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_gcd(left, mid, right) } + } else { + // SAFETY: guaranteed by the caller + unsafe { ptr_rotate_swap(left, mid, right) } + } +} + +/// Algorithm 1 is used if `min(left, right)` is small enough to fit onto a stack buffer. The +/// `min(left, right)` elements are copied onto the buffer, `memmove` is applied to the others, and +/// the ones on the buffer are moved back into the hole on the opposite side of where they +/// originated. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +const unsafe fn ptr_rotate_memmove(left: usize, mid: *mut T, right: usize) +//@ req thread_token(?t) &*& (mid - left)[..left + right] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 < left &*& 0 < right &*& (left + right) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(mid - left) == true &*& pointer_within_limits(mid + right) == true &*& 0 < std::mem::size_of::() &*& (if right < left { right } else { left }) <= std::mem::size_of(typeid([usize; 32])) / std::mem::size_of::(); +//@ ens thread_token(t) &*& (mid - left)[..left + right] |-> ?elems1 &*& foreach(elems1, own::(t)); +//@ on_unwind_ens false; +{ + //@ let p_start = mid - left; + //@ let n_total = left + right; + //@ rotate_ptr_limits::(p_start, n_total, left); + //@ rotate_ptr_limits::(p_start, n_total, right); + // The `[T; 0]` here is to ensure this is appropriately aligned for T + let mut rawarray = unsafe { uninit_buf__VeriFast_wrapper::() }; + let buf = unsafe { uninit_buf_as_mut_ptr__VeriFast_wrapper::(&mut rawarray) } as *mut T; + // SAFETY: `mid-left <= mid-left+right < mid+right` + let dim = unsafe { mid.sub(left).add(right) }; + if left <= right { + // SAFETY: + // + // 1) The `if` condition about the sizes ensures `[mid-left; left]` will fit in + // `buf` without overflow and `buf` was created just above and so cannot be + // overlapped with any value of `[mid-left; left]` + // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care + // about overlaps here. + // 3) The `if` condition about `left <= right` ensures writing `left` elements to + // `dim = mid-left+right` is valid because: + // - `buf` is valid and `left` elements were written in it in 1) + // - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)` + unsafe { + //@ std::alloc::is_valid_layout_size_of_align_of::<[usize; 32]>(); + //@ div_rem_nonneg(std::mem::size_of(typeid([usize; 32])), std::mem::size_of::()); + //@ mul_mono_l(left, std::mem::size_of(typeid([usize; 32])) / std::mem::size_of::(), std::mem::size_of::()); + //@ rawarray_to_buf(&rawarray, buf, left); + //@ array_split(p_start, left); + //@ foreach_split(elems, own::(t), left); + // 1) + ptr::copy_nonoverlapping(mid.sub(left), buf, left); + //@ array_join(p_start); + //@ close ptr::copy_context::(p_start, n_total, left, 0, right, elems); + // 2) + ptr::copy(mid, mid.sub(left), right); + //@ take_append_l(right, drop(left, elems), drop(right, elems)); + //@ array_split(p_start, right); + //@ array_to_array_(p_start + right); + // 3) + ptr::copy_nonoverlapping(buf, dim, left); + //@ array_join(p_start); + //@ foreach_append(drop(left, elems), take(left, elems)); + //@ array_to_array_(buf); + //@ buf_to_rawarray(&rawarray, buf, left); + } + } else { + // SAFETY: same reasoning as above but with `left` and `right` reversed + unsafe { + //@ std::alloc::is_valid_layout_size_of_align_of::<[usize; 32]>(); + //@ div_rem_nonneg(std::mem::size_of(typeid([usize; 32])), std::mem::size_of::()); + //@ mul_mono_l(right, std::mem::size_of(typeid([usize; 32])) / std::mem::size_of::(), std::mem::size_of::()); + //@ rawarray_to_buf(&rawarray, buf, right); + //@ array_split(p_start, left); + //@ foreach_split(elems, own::(t), left); + ptr::copy_nonoverlapping(mid, buf, right); + //@ array_join(p_start); + //@ close ptr::copy_context::(p_start, n_total, 0, right, left, elems); + ptr::copy(mid.sub(left), dim, left); + //@ take_append_l(right, take(right, elems), take(left, elems)); + //@ drop_append(right, take(right, elems), take(left, elems)); + //@ array_split(p_start, right); + //@ array_to_array_(p_start); + ptr::copy_nonoverlapping(buf, mid.sub(left), right); + //@ array_join(p_start); + //@ foreach_append(drop(left, elems), take(left, elems)); + //@ array_to_array_(buf); + //@ buf_to_rawarray(&rawarray, buf, right); + } + } +} + +/*@ +pred rotate_gcd_hole(t: thread_id_t, x: *T, n_total: usize, hole: usize) = + 0 <= hole &*& hole < n_total &*& + x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> _ &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)); + +pred rotate_gcd_step_ctxt(t: thread_id_t, x: *T, n_total: usize, hole: usize, i: usize) = + 0 <= hole &*& hole < n_total &*& 0 <= i &*& i < n_total &*& i != hole &*& + if i < hole { + x[..i] |-> ?p1 &*& foreach(p1, own::(t)) &*& + (x + i + 1)[..hole - i - 1] |-> ?p2 &*& foreach(p2, own::(t)) &*& + *(x + hole) |-> _ &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)) + } else { + x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> _ &*& + (x + hole + 1)[..i - hole - 1] |-> ?s1 &*& foreach(s1, own::(t)) &*& + (x + i + 1)[..n_total - i - 1] |-> ?s2 &*& foreach(s2, own::(t)) + }; + +lem rotate_gcd_open_hole(t: thread_id_t, x: *T, n_total: usize, hole: usize) + req x[..n_total] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 <= hole &*& hole < n_total; + ens x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> ?v &*& (.own)(t, v) &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)); +{ + array_split(x, hole); + foreach_split(elems, own::(t), hole); + let rest = drop(hole, elems); + open array(x + hole, n_total - hole, rest); + open foreach(rest, own::(t)); + assert *(x + hole) |-> ?v; + open own::(t)(v); +} + +lem rotate_gcd_finish_open_hole(t: thread_id_t, x: *T, n_total: usize, hole: usize) + req 0 <= hole &*& hole < n_total &*& + x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> ?v &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)); + ens rotate_gcd_hole::(t, x, n_total, hole); +{ + open points_to(x + hole, v); + close rotate_gcd_hole::(t, x, n_total, hole); +} + +lem rotate_gcd_extract_i(t: thread_id_t, x: *T, n_total: usize, hole: usize, i: usize) + req rotate_gcd_hole::(t, x, n_total, hole) &*& 0 <= i &*& i < n_total &*& i != hole; + ens rotate_gcd_step_ctxt::(t, x, n_total, hole, i) &*& *(x + i) |-> ?vi &*& (.own)(t, vi); +{ + open rotate_gcd_hole::(t, x, n_total, hole); + assert x[..hole] |-> ?prefix; + assert (x + hole + 1)[..n_total - hole - 1] |-> ?suffix; + if i < hole { + array_split(x, i); + foreach_split(prefix, own::(t), i); + let rest = drop(i, prefix); + open array(x + i, hole - i, rest); + open foreach(rest, own::(t)); + assert *(x + i) |-> ?vi; + open own::(t)(vi); + close rotate_gcd_step_ctxt::(t, x, n_total, hole, i); + } else { + let k = i - hole - 1; + array_split(x + hole + 1, k); + foreach_split(suffix, own::(t), k); + let rest = drop(k, suffix); + open array(x + i, n_total - i, rest); + open foreach(rest, own::(t)); + assert *(x + i) |-> ?vi; + open own::(t)(vi); + close rotate_gcd_step_ctxt::(t, x, n_total, hole, i); + } +} + +lem rotate_gcd_restore_i(t: thread_id_t, x: *T, n_total: usize, hole: usize, i: usize, v_new: T) + req rotate_gcd_step_ctxt::(t, x, n_total, hole, i) &*& *(x + i) |-> v_new &*& (.own)(t, v_new); + ens rotate_gcd_hole::(t, x, n_total, hole); +{ + open rotate_gcd_step_ctxt::(t, x, n_total, hole, i); + points_to_limits(x + i); + close own::(t)(v_new); + if i < hole { + assert x[..i] |-> ?p1; + assert (x + i + 1)[..hole - i - 1] |-> ?p2; + close foreach(cons(v_new, p2), own::(t)); + close array(x + i, hole - i, cons(v_new, p2)); + array_join(x); + foreach_append(p1, cons(v_new, p2)); + close rotate_gcd_hole::(t, x, n_total, hole); + } else { + assert (x + hole + 1)[..i - hole - 1] |-> ?s1; + assert (x + i + 1)[..n_total - i - 1] |-> ?s2; + close foreach(cons(v_new, s2), own::(t)); + close array(x + i, n_total - i, cons(v_new, s2)); + array_join(x + hole + 1); + foreach_append(s1, cons(v_new, s2)); + close rotate_gcd_hole::(t, x, n_total, hole); + } +} + +lem rotate_gcd_prep_close_hole(t: thread_id_t, x: *T, n_total: usize, hole: usize) + req rotate_gcd_hole::(t, x, n_total, hole); + ens 0 <= hole &*& hole < n_total &*& + x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> _ &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)); +{ + open rotate_gcd_hole::(t, x, n_total, hole); +} + +lem rotate_gcd_finish_close_hole(t: thread_id_t, x: *T, n_total: usize, hole: usize, v_final: T) + req 0 <= hole &*& hole < n_total &*& + x[..hole] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + *(x + hole) |-> v_final &*& (.own)(t, v_final) &*& + (x + hole + 1)[..n_total - hole - 1] |-> ?suffix &*& foreach(suffix, own::(t)); + ens x[..n_total] |-> ?elems1 &*& foreach(elems1, own::(t)); +{ + points_to_limits(x + hole); + close own::(t)(v_final); + close foreach(cons(v_final, suffix), own::(t)); + close array(x + hole, n_total - hole, cons(v_final, suffix)); + array_join(x); + foreach_append(prefix, cons(v_final, suffix)); +} +@*/ + +/// Algorithm 2 is used for small values of `left + right` or for large `T`. The elements +/// are moved into their final positions one at a time starting at `mid - left` and advancing by +/// `right` steps modulo `left + right`, such that only one temporary is needed. Eventually, we +/// arrive back at `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps +/// skipped over elements. For example: +/// ```text +/// left = 10, right = 6 +/// the `^` indicates an element in its final place +/// 6 7 8 9 10 11 12 13 14 15 . 0 1 2 3 4 5 +/// after using one step of the above algorithm (The X will be overwritten at the end of the round, +/// and 12 is stored in a temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 2 3 4 5 +/// ^ +/// after using another step (now 2 is in the temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ +/// after the third step (the steps wrap around, and 8 is in the temporary): +/// X 7 2 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ ^ +/// after 7 more steps, the round ends with the temporary 0 getting put in the X: +/// 0 7 2 9 4 11 6 13 8 15 . 10 1 12 3 14 5 +/// ^ ^ ^ ^ ^ ^ ^ ^ +/// ``` +/// Fortunately, the number of skipped over elements between finalized elements is always equal, so +/// we can just offset our starting position and do more rounds (the total number of rounds is the +/// `gcd(left + right, right)` value). The end result is that all elements are finalized once and +/// only once. +/// +/// Algorithm 2 can be vectorized by chunking and performing many rounds at once, but there are too +/// few rounds on average until `left + right` is enormous, and the worst case of a single +/// round is always there. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +#[inline] +const unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) +//@ req thread_token(?t) &*& (mid - left)[..left + right] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 < left &*& 0 < right &*& 0 < std::mem::size_of::() &*& (left + right) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(mid - left) == true &*& pointer_within_limits(mid + right) == true; +//@ ens thread_token(t) &*& (mid - left)[..left + right] |-> ?elems1 &*& foreach(elems1, own::(t)); +//@ on_unwind_ens false; +{ + //@ let n_total = left + right; + //@ rotate_ptr_limits::(mid - left, n_total, left); + // Algorithm 2 + // Microbenchmarks indicate that the average performance for random shifts is better all + // the way until about `left + right == 32`, but the worst case performance breaks even + // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 + // `usize`s, this algorithm also outperforms other algorithms. + // SAFETY: callers must ensure `mid - left` is valid for reading and writing. + let x = unsafe { mid.sub(left) }; + // beginning of first round + // SAFETY: see previous comment. + //@ rotate_gcd_open_hole::(t, x, n_total, 0); + let mut tmp: T = unsafe { x.read() }; + //@ rotate_gcd_finish_open_hole::(t, x, n_total, 0); + let mut i = right; + // `gcd` can be found before hand by calculating `gcd(left + right, right)`, + // but it is faster to do one loop which calculates the gcd as a side effect, then + // doing the rest of the chunk + let mut gcd = right; + // benchmarks reveal that it is faster to swap temporaries all the way through instead + // of reading one temporary once, copying backwards, and then writing that temporary at + // the very end. This is possibly due to the fact that swapping or replacing temporaries + // uses only one memory address in the loop instead of needing to manage two. + loop { + //@ inv thread_token(t) &*& rotate_gcd_hole::(t, x, n_total, 0) &*& (.own)(t, tmp) &*& 1 <= gcd &*& gcd <= right &*& gcd <= i &*& 1 <= i &*& i < n_total &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(x) == true &*& pointer_within_limits(x + n_total) == true; + // [long-safety-expl] + // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and + // writing. + // + // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right` + // - `i <= left+right-1` is always true + // - if `i < left`, `right` is added so `i < left+right` and on the next + // iteration `left` is removed from `i` so it doesn't go further + // - if `i >= left`, `left` is removed immediately and so it doesn't go further. + // - overflows cannot happen for `i` since the function's safety contract ask for + // `mid+right-1 = x+left+right` to be valid for writing + // - underflows cannot happen because `i` must be bigger or equal to `left` for + // a subtraction of `left` to happen. + // + // So `x+i` is valid for reading and writing if the caller respected the contract + //@ rotate_ptr_limits::(x, n_total, i); + //@ rotate_gcd_extract_i::(t, x, n_total, 0, i); + //@ let old_tmp = tmp; + tmp = unsafe { ptr_replace__VeriFast_wrapper(x.add(i), tmp) }; + //@ rotate_gcd_restore_i::(t, x, n_total, 0, i, old_tmp); + // instead of incrementing `i` and then checking if it is outside the bounds, we + // check if `i` will go outside the bounds on the next increment. This prevents + // any wrapping of pointers or `usize`. + if i >= left { + i -= left; + if i == 0 { + // end of first round + // SAFETY: tmp has been read from a valid source and x is valid for writing + // according to the caller. + //@ rotate_gcd_prep_close_hole::(t, x, n_total, 0); + unsafe { x.write(tmp) }; + //@ rotate_gcd_finish_close_hole::(t, x, n_total, 0, tmp); + break; + } + // this conditional must be here if `left + right >= 15` + if i < gcd { + gcd = i; + } + } else { + i += right; + } + } + // finish the chunk with more rounds + // FIXME(const-hack): Use `for start in 1..gcd` when available in const + let mut start = 1; + loop { + //@ inv thread_token(t) &*& lifetime_token(func_lft) &*& x[..n_total] |-> ?cur_elems &*& foreach(cur_elems, own::(t)) &*& 1 <= start &*& 1 <= gcd &*& gcd <= left &*& gcd <= right &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(x) == true &*& pointer_within_limits(x + n_total) == true; + if start < gcd { + // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for + // reading and writing as per the function's safety contract, see [long-safety-expl] + // above + //@ rotate_ptr_limits::(x, n_total, start); + //@ rotate_gcd_open_hole::(t, x, n_total, start); + tmp = unsafe { x.add(start).read() }; + //@ rotate_gcd_finish_open_hole::(t, x, n_total, start); + // [safety-expl-addition] + // + // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the + // greatest common divisor of `(left+right, right)` means that `left = right` so + // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing + // according to the function's safety contract. + i = start + right; + loop { + //@ inv thread_token(t) &*& rotate_gcd_hole::(t, x, n_total, start) &*& (.own)(t, tmp) &*& 1 <= start &*& start < gcd &*& gcd <= left &*& gcd <= right &*& 0 <= i &*& i < n_total &*& i != start &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(x) == true &*& pointer_within_limits(x + n_total) == true; + // SAFETY: see [long-safety-expl] and [safety-expl-addition] + //@ rotate_ptr_limits::(x, n_total, i); + //@ rotate_gcd_extract_i::(t, x, n_total, start, i); + //@ let old_tmp2 = tmp; + tmp = unsafe { ptr_replace__VeriFast_wrapper(x.add(i), tmp) }; + //@ rotate_gcd_restore_i::(t, x, n_total, start, i, old_tmp2); + if i >= left { + i -= left; + if i == start { + // SAFETY: see [long-safety-expl] and [safety-expl-addition] + //@ rotate_ptr_limits::(x, n_total, start); + //@ rotate_gcd_prep_close_hole::(t, x, n_total, start); + unsafe { x.add(start).write(tmp) }; + //@ rotate_gcd_finish_close_hole::(t, x, n_total, start, tmp); + break; + } + } else { + i += right; + } + } + + start += 1; + } else { + break; + } + } +} + +/// Algorithm 3 utilizes repeated swapping of `min(left, right)` elements. +/// +/// /// +/// ```text +/// left = 11, right = 4 +/// [4 5 6 7 8 9 10 11 12 13 14 . 0 1 2 3] +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping the right most elements with elements to the left +/// [4 5 6 7 8 9 10 . 0 1 2 3] 11 12 13 14 +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping these +/// [4 5 6 . 0 1 2 3] 7 8 9 10 11 12 13 14 +/// we cannot swap any more, but a smaller rotation problem is left to solve +/// ``` +/// when `left < right` the swapping happens from the left instead. +/// +/// # Safety +/// +/// The specified range must be valid for reading and writing. +/*@ +pred rotate_swap_ctxt(t: thread_id_t, p_start: *T, n_total: usize, idx: usize, k: usize, vs1: list, vs2: list) = + 0 <= idx &*& 0 <= k &*& idx + 2 * k <= n_total &*& + p_start[..idx] |-> ?prefix &*& foreach(prefix, own::(t)) &*& + (p_start + idx + 2 * k)[..n_total - idx - 2 * k] |-> ?suffix &*& foreach(suffix, own::(t)) &*& + foreach(vs1, own::(t)) &*& foreach(vs2, own::(t)); + +lem rotate_swap_extract(t: thread_id_t, p_start: *T, n_total: usize, idx: usize, k: usize) + req p_start[..n_total] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 <= idx &*& 0 <= k &*& idx + 2 * k <= n_total; + ens (p_start + idx)[..k] |-> ?vs1 &*& (p_start + idx + k)[..k] |-> ?vs2 &*& + rotate_swap_ctxt::(t, p_start, n_total, idx, k, vs1, vs2); +{ + array_split(p_start, idx); + foreach_split(elems, own::(t), idx); + let rest1 = drop(idx, elems); + array_split(p_start + idx, k); + foreach_split(rest1, own::(t), k); + let rest2 = drop(k, rest1); + array_split(p_start + idx + k, k); + foreach_split(rest2, own::(t), k); + close rotate_swap_ctxt::(t, p_start, n_total, idx, k, take(k, rest1), take(k, rest2)); +} + +lem rotate_swap_restore(t: thread_id_t, p_start: *T, n_total: usize, idx: usize, k: usize) + req rotate_swap_ctxt::(t, p_start, n_total, idx, k, ?vs1, ?vs2) &*& + (p_start + idx)[..k] |-> vs2 &*& (p_start + idx + k)[..k] |-> vs1; + ens p_start[..n_total] |-> ?elems1 &*& foreach(elems1, own::(t)); +{ + open rotate_swap_ctxt::(t, p_start, n_total, idx, k, vs1, vs2); + assert p_start[..idx] |-> ?prefix; + assert (p_start + idx + 2 * k)[..n_total - idx - 2 * k] |-> ?suffix; + array_join(p_start + idx + k); + foreach_append(vs1, suffix); + array_join(p_start + idx); + foreach_append(vs2, append(vs1, suffix)); + array_join(p_start); + foreach_append(prefix, append(vs2, append(vs1, suffix))); +} + +pred rotate_swap_state(p_start: *T, n_total: usize, left: usize, mid: *T, right: usize, offset: usize) = + 0 <= offset &*& offset + left + right <= n_total &*& mid == p_start + (offset + left); +@*/ + +#[inline] +const unsafe fn ptr_rotate_swap(mut left: usize, mut mid: *mut T, mut right: usize) +//@ req thread_token(?t) &*& (mid - left)[..left + right] |-> ?elems &*& foreach(elems, own::(t)) &*& 0 < left &*& 0 < right &*& 0 < std::mem::size_of::() &*& (left + right) * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(mid - left) == true &*& pointer_within_limits(mid + right) == true; +//@ ens thread_token(t) &*& (mid - left)[..left + right] |-> ?elems1 &*& foreach(elems1, own::(t)); +//@ on_unwind_ens false; +{ + //@ let p_start = mid - left; + //@ let n_total = left + right; + //@ close rotate_swap_state::(p_start, n_total, left, mid, right, 0); + loop { + //@ inv thread_token(t) &*& p_start[..n_total] |-> ?cur_elems &*& foreach(cur_elems, own::(t)) &*& rotate_swap_state::(p_start, n_total, left, mid, right, ?offset) &*& 0 < left &*& 0 < right &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(p_start) == true &*& pointer_within_limits(p_start + n_total) == true; + if left >= right { + // Algorithm 3 + // There is an alternate way of swapping that involves finding where the last swap + // of this algorithm would be, and swapping using that last chunk instead of swapping + // adjacent chunks like this algorithm is doing, but this way is still faster. + loop { + //@ inv thread_token(t) &*& p_start[..n_total] |-> ?cur_elems1 &*& foreach(cur_elems1, own::(t)) &*& rotate_swap_state::(p_start, n_total, left, mid, right, ?offset1) &*& left >= right &*& 0 < right &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(p_start) == true &*& pointer_within_limits(p_start + n_total) == true; + // SAFETY: + // `left >= right` so `[mid-right, mid+right)` is valid for reading and writing + // Subtracting `right` from `mid` each turn is counterbalanced by the addition and + // check after it. + unsafe { + //@ open rotate_swap_state::(p_start, n_total, left, mid, right, offset1); + //@ let idx = offset1 + left - right; + //@ rotate_swap_extract::(t, p_start, n_total, idx, right); + //@ rotate_ptr_limits::(p_start, n_total, offset1 + left); + //@ rotate_ptr_limits::(p_start, offset1 + left, idx); + ptr::swap_nonoverlapping(mid.sub(right), mid, right); + //@ rotate_swap_restore::(t, p_start, n_total, idx, right); + mid = mid.sub(right); + } + left -= right; + //@ close rotate_swap_state::(p_start, n_total, left, mid, right, offset1); + if left < right { + break; + } + } + } else { + // Algorithm 3, `left < right` + loop { + //@ inv thread_token(t) &*& p_start[..n_total] |-> ?cur_elems1 &*& foreach(cur_elems1, own::(t)) &*& rotate_swap_state::(p_start, n_total, left, mid, right, ?offset1) &*& right >= left &*& 0 < left &*& 0 < std::mem::size_of::() &*& n_total * std::mem::size_of::() <= isize::MAX &*& pointer_within_limits(p_start) == true &*& pointer_within_limits(p_start + n_total) == true; + // SAFETY: `[mid-left, mid+left)` is valid for reading and writing because + // `left < right` so `mid+left < mid+right`. + // Adding `left` to `mid` each turn is counterbalanced by the subtraction and check + // after it. + unsafe { + //@ open rotate_swap_state::(p_start, n_total, left, mid, right, offset1); + //@ rotate_swap_extract::(t, p_start, n_total, offset1, left); + //@ rotate_ptr_limits::(p_start, n_total, offset1 + left); + //@ rotate_ptr_limits::(p_start, offset1 + left, offset1); + //@ rotate_ptr_limits::(p_start, n_total, offset1 + 2 * left); + ptr::swap_nonoverlapping(mid.sub(left), mid, left); + //@ rotate_swap_restore::(t, p_start, n_total, offset1, left); + mid = mid.add(left); + } + right -= left; + //@ close rotate_swap_state::(p_start, n_total, left, mid, right, offset1 + left); + if right < left { + break; + } + } + } + if (right == 0) || (left == 0) { + //@ open rotate_swap_state::(p_start, n_total, left, mid, right, _); + return; + } + } +} + +// FIXME(const-hack): Use cmp::min when available in const +const fn const_min(left: usize, right: usize) -> usize +//@ req true; +//@ ens result == if right < left { right } else { left }; +//@ on_unwind_ens false; +{ + if right < left { right } else { left } +} diff --git a/verifast-proofs/core/slice/mod.rs/verified/slice/sort.rs b/verifast-proofs/core/slice/mod.rs/verified/slice/sort.rs new file mode 100644 index 0000000000000..bb060c9c9b963 --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/verified/slice/sort.rs @@ -0,0 +1,11 @@ + +pub mod select { + pub fn partition_at_index(_v: &mut [T], _index: usize, _is_less: F) -> (&mut [T], &mut T, &mut [T]) + where F: FnMut(&T, &T) -> bool { loop {} } +} +pub mod unstable { + pub fn sort(_v: &mut [T], _is_less: &mut F) + where F: FnMut(&T, &T) -> bool { loop {} } + pub fn partial_sort(_v: &mut [T], _range: R, _is_less: F) + where R: core::ops::RangeBounds, F: FnMut(&T, &T) -> bool { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs/verified/slice/specialize.rs b/verifast-proofs/core/slice/mod.rs/verified/slice/specialize.rs new file mode 100644 index 0000000000000..9bf035047a4ed --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/verified/slice/specialize.rs @@ -0,0 +1,7 @@ + +pub trait SpecFill { + fn spec_fill(&mut self, val: T); +} +impl SpecFill for [T] { + fn spec_fill(&mut self, _val: T) { loop {} } +} diff --git a/verifast-proofs/core/slice/mod.rs/verify.sh b/verifast-proofs/core/slice/mod.rs/verify.sh new file mode 100755 index 0000000000000..70e8df9ca35cc --- /dev/null +++ b/verifast-proofs/core/slice/mod.rs/verify.sh @@ -0,0 +1,80 @@ +#!/bin/bash +set -e -x + +export VFVERSION=26.10 +if [ -f ../../../setup-verifast-home ]; then + . ../../../setup-verifast-home +fi +if ! command -v verifast >/dev/null 2>&1 && [ -d "$VERIFAST_HOME/bin" ]; then + export PATH="$VERIFAST_HOME/bin:$PATH" +fi + +# VeriFast 26.10 is built against rustc nightly-2026-09-25 (see setup-verifast-home). +# The `core` sysroot below must be compiled by that exact rustc, so it is built from the +# `rust-src` component of that toolchain rather than from the repository's `library/core` +# subtree, which tracks a newer nightly whose intrinsics and feature gates that rustc +# does not know. +VF_RUST_TOOLCHAIN=nightly-2026-09-25 +RUSTC="$(rustup which --toolchain $VF_RUST_TOOLCHAIN rustc 2>/dev/null || rustup which rustc 2>/dev/null || which rustc)" +CARGO="$(rustup which --toolchain $VF_RUST_TOOLCHAIN cargo 2>/dev/null || rustup which cargo 2>/dev/null || which cargo)" +HOST_TRIPLE="$("$RUSTC" -vV | sed -n 's/^host: //p')" +if [[ "$HOST_TRIPLE" == *"apple-darwin"* ]]; then + DYLIB_EXT="dylib" +else + DYLIB_EXT="so" +fi + +SYSROOT_REL="../../../../library/target/vf_sysroot" +SYSROOT_LIB_REL="$SYSROOT_REL/lib/rustlib/$HOST_TRIPLE/lib" + +if [ ! -f "$SYSROOT_LIB_REL/libcore_noslice.rlib" ] || [ ! -f "$SYSROOT_LIB_REL/libsafety.$DYLIB_EXT" ]; then + mkdir -p "$SYSROOT_LIB_REL" + RUSTC_SYSROOT="$("$RUSTC" --print sysroot)" + cp -n "$RUSTC_SYSROOT/lib/rustlib/$HOST_TRIPLE/lib/"* "$SYSROOT_LIB_REL/" || true + if [ -d ../../../../library/contracts/safety ]; then + (cd ../../../../library/contracts/safety && RUSTC="$RUSTC" "$CARGO" build --release) + cp "../../../../library/target/release/libsafety.$DYLIB_EXT" "$SYSROOT_LIB_REL/" + elif [ -d ../../../../deps/safety ]; then + (cd ../../../../deps/safety && RUSTC="$RUSTC" "$CARGO" build --release) + cp "../../../../deps/safety/target/release/libsafety.$DYLIB_EXT" "$SYSROOT_LIB_REL/" + fi + RUST_SRC="$RUSTC_SYSROOT/lib/rustlib/src/rust/library" + if [ ! -d "$RUST_SRC/core/src" ]; then + rustup component add rust-src --toolchain "$VF_RUST_TOOLCHAIN" + fi + CORE_SRC_TMP="$SYSROOT_REL/core_src/core" + rm -rf "$SYSROOT_REL/core_src" + mkdir -p "$CORE_SRC_TMP" + ln -s "$RUST_SRC/stdarch" "$SYSROOT_REL/core_src/stdarch" + ln -s "$RUST_SRC/portable-simd" "$SYSROOT_REL/core_src/portable-simd" + cp -R "$RUST_SRC/core/src" "$CORE_SRC_TMP/src" + # The four visibility/attribute edits that let the slice sources compile as a separate + # crate against this `core` (listed in README.md, "Sysroot"). + patch -p1 -d "$CORE_SRC_TMP/src" < core-sysroot.patch + "$RUSTC" --crate-name core --edition=2024 "$CORE_SRC_TMP/src/lib.rs" --crate-type lib \ + -C embed-bitcode=no -Z force-unstable-if-unmarked -A warnings \ + -L dependency="$SYSROOT_LIB_REL" \ + --extern "safety=$SYSROOT_LIB_REL/libsafety.$DYLIB_EXT" \ + -o "$SYSROOT_LIB_REL/libcore_noslice.rlib" + rm -rf "$SYSROOT_REL/core_src" +fi + +SYSROOT="$(cd "$SYSROOT_REL" && pwd)" +SYSROOT_LIB="$SYSROOT/lib/rustlib/$HOST_TRIPLE/lib" +RUSTC_ARGS="--crate-type lib --edition=2024 --extern core=$SYSROOT_LIB/libcore_noslice.rlib --extern safety=$SYSROOT_LIB/libsafety.$DYLIB_EXT -L dependency=$SYSROOT_LIB -Z force-unstable-if-unmarked -A warnings" + +verifast -rustc_args "$RUSTC_ARGS" -extern_spec std=core.rsspec -skip_specless_fns -ignore_unwind_paths -allow_assume -allow_ignore_ref_creation verified/lib.rs +refinement-checker --rustc-args "$RUSTC_ARGS" original/lib.rs verified/lib.rs > /dev/null +if ! diff original/slice.rs ../../../../library/core/src/slice/mod.rs; then + echo "::error title=Please run verifast-proofs/patch-verifast-proofs.sh::Some VeriFast proofs are out of date; please chdir to verifast-proofs and run patch-verifast-proofs.sh to update them." + false +fi +if ! diff original/slice/raw.rs ../../../../library/core/src/slice/raw.rs; then + echo "::error title=Please run verifast-proofs/patch-verifast-proofs.sh::Some VeriFast proofs are out of date; please chdir to verifast-proofs and run patch-verifast-proofs.sh to update them." + false +fi +if ! diff original/slice/rotate.rs ../../../../library/core/src/slice/rotate.rs; then + echo "::error title=Please run verifast-proofs/patch-verifast-proofs.sh::Some VeriFast proofs are out of date; please chdir to verifast-proofs and run patch-verifast-proofs.sh to update them." + false +fi + diff --git a/verifast-proofs/patch-verifast-proofs.sh b/verifast-proofs/patch-verifast-proofs.sh index 802b68ba7b68a..de04f294b2f43 100755 --- a/verifast-proofs/patch-verifast-proofs.sh +++ b/verifast-proofs/patch-verifast-proofs.sh @@ -22,3 +22,9 @@ popd pushd alloc/raw_vec/mod.rs patch_proof popd +pushd core/slice/mod.rs + patch_proof +popd +pushd core/slice/mod.rs-negative + patch_proof +popd