From e0b75776c3265fdb9dead021e565c2fda906ed88 Mon Sep 17 00:00:00 2001 From: Rémy Rakic Date: Wed, 26 Feb 2025 15:45:36 +0000 Subject: linux x64: default to `-znostart-stop-gc` This will help stabilization of lld. --- compiler/rustc_codegen_ssa/src/back/link.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index a170b2e3b6a..3407117a06e 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3382,6 +3382,35 @@ fn add_lld_args( // this, `wasm-component-ld`, which is overridden if this option is passed. if !sess.target.is_like_wasm { cmd.cc_arg("-fuse-ld=lld"); + + // On ELF platforms like at least x64 linux, GNU ld and LLD have opposite defaults on some + // section garbage-collection features. For example, the somewhat popular `linkme` crate and + // its dependents rely in practice on this difference: when using lld, they need `-z + // nostart-stop-gc` to prevent encapsulation symbols and sections from being + // garbage-collected. + // + // More information about all this can be found in: + // - https://maskray.me/blog/2021-01-31-metadata-sections-comdat-and-shf-link-order + // - https://lld.llvm.org/ELF/start-stop-gc + // + // So when using lld, we restore, for now, the traditional behavior to help migration, but + // will remove it in the future. + // Since this only disables an optimization, it shouldn't create issues, but is in theory + // slightly suboptimal. However, it: + // - doesn't have any visible impact on our benchmarks + // - reduces the need to disable lld for the crates that depend on this + // + // Note that lld can detect some cases where this difference is relied on, and emits a + // dedicated error to add this link arg. We could make use of this error to emit an FCW. As + // of writing this, we don't do it, because lld is already enabled by default on nightly + // without this mitigation: no working project would see the FCW, so we do this to help + // stabilization. + // + // FIXME: emit an FCW if linking fails due its absence, and then remove this link-arg in the + // future. + if sess.target.llvm_target == "x86_64-unknown-linux-gnu" { + cmd.link_arg("-znostart-stop-gc"); + } } if !flavor.is_gnu() { -- cgit 1.4.1-3-g733a5 From 0dfe2ae3fb72c50ea369286131c73daede13d7e5 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 24 Feb 2025 03:48:12 +0000 Subject: Windows: Use MoveFileEx by default in `fs:rename` --- library/std/src/sys/pal/windows/fs.rs | 179 +++++++++++----------------------- 1 file changed, 56 insertions(+), 123 deletions(-) diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 17dc3e5c257..34108e44d58 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1,10 +1,10 @@ use super::api::{self, WinError, set_file_information_by_handle}; use super::{IoResult, to_u16s}; -use crate::alloc::{alloc, handle_alloc_error}; +use crate::alloc::{Layout, alloc, dealloc, handle_alloc_error}; use crate::borrow::Cow; use crate::ffi::{OsStr, OsString, c_void}; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; -use crate::mem::{self, MaybeUninit}; +use crate::mem::{self, MaybeUninit, offset_of}; use crate::os::windows::io::{AsHandle, BorrowedHandle}; use crate::os::windows::prelude::*; use crate::path::{Path, PathBuf}; @@ -1241,139 +1241,72 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { let old = maybe_verbatim(old)?; let new = maybe_verbatim(new)?; - let new_len_without_nul_in_bytes = (new.len() - 1).try_into().unwrap(); - - // The last field of FILE_RENAME_INFO, the file name, is unsized, - // and FILE_RENAME_INFO has two padding bytes. - // Therefore we need to make sure to not allocate less than - // size_of::() bytes, which would be the case with - // 0 or 1 character paths + a null byte. - let struct_size = size_of::() - .max(mem::offset_of!(c::FILE_RENAME_INFO, FileName) + new.len() * size_of::()); - - let struct_size: u32 = struct_size.try_into().unwrap(); - - let create_file = |extra_access, extra_flags| { - let handle = unsafe { - HandleOrInvalid::from_raw_handle(c::CreateFileW( - old.as_ptr(), - c::SYNCHRONIZE | c::DELETE | extra_access, - c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE, - ptr::null(), - c::OPEN_EXISTING, - c::FILE_ATTRIBUTE_NORMAL | c::FILE_FLAG_BACKUP_SEMANTICS | extra_flags, - ptr::null_mut(), - )) - }; - - OwnedHandle::try_from(handle).map_err(|_| io::Error::last_os_error()) - }; - - // The following code replicates `MoveFileEx`'s behavior as reverse-engineered from its disassembly. - // If `old` refers to a mount point, we move it instead of the target. - let handle = match create_file(c::FILE_READ_ATTRIBUTES, c::FILE_FLAG_OPEN_REPARSE_POINT) { - Ok(handle) => { - let mut file_attribute_tag_info: MaybeUninit = - MaybeUninit::uninit(); - - let result = unsafe { - cvt(c::GetFileInformationByHandleEx( - handle.as_raw_handle(), - c::FileAttributeTagInfo, - file_attribute_tag_info.as_mut_ptr().cast(), - size_of::().try_into().unwrap(), - )) + if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 { + let err = api::get_last_error(); + // if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move + // the file while ignoring the readonly attribute. + // This is accomplished by calling `SetFileInformationByHandle` with `FileRenameInfoEx`. + if err == WinError::ACCESS_DENIED { + let mut opts = OpenOptions::new(); + opts.access_mode(c::DELETE); + opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); + let Ok(f) = File::open_native(&old, &opts) else { return Err(err).io_result() }; + + // Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation` + // This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size. + let Ok(new_len_without_nul_in_bytes): Result = ((new.len() - 1) * 2).try_into() + else { + return Err(err).io_result(); }; - - if let Err(err) = result { - if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) - || err.raw_os_error() == Some(c::ERROR_INVALID_FUNCTION as _) - { - // `GetFileInformationByHandleEx` documents that not all underlying drivers support all file information classes. - // Since we know we passed the correct arguments, this means the underlying driver didn't understand our request; - // `MoveFileEx` proceeds by reopening the file without inhibiting reparse point behavior. - None - } else { - Some(Err(err)) + let offset: u32 = offset_of!(c::FILE_RENAME_INFO, FileName).try_into().unwrap(); + let struct_size = offset + new_len_without_nul_in_bytes + 2; + let layout = + Layout::from_size_align(struct_size as usize, align_of::()) + .unwrap(); + + // SAFETY: We allocate enough memory for a full FILE_RENAME_INFO struct and a filename. + let file_rename_info; + unsafe { + file_rename_info = alloc(layout).cast::(); + if file_rename_info.is_null() { + handle_alloc_error(layout); } - } else { - // SAFETY: The struct has been initialized by GetFileInformationByHandleEx - let file_attribute_tag_info = unsafe { file_attribute_tag_info.assume_init() }; - let file_type = FileType::new( - file_attribute_tag_info.FileAttributes, - file_attribute_tag_info.ReparseTag, - ); - if file_type.is_symlink() { - // The file is a mount point, junction point or symlink so - // don't reopen the file so that the link gets renamed. - Some(Ok(handle)) - } else { - // Otherwise reopen the file without inhibiting reparse point behavior. - None - } - } - } - // The underlying driver may not support `FILE_FLAG_OPEN_REPARSE_POINT`: Retry without it. - Err(err) if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) => None, - Err(err) => Some(Err(err)), - } - .unwrap_or_else(|| create_file(0, 0))?; - - let layout = - core::alloc::Layout::from_size_align(struct_size as _, align_of::()) - .unwrap(); - - let file_rename_info = unsafe { alloc(layout) } as *mut c::FILE_RENAME_INFO; - - if file_rename_info.is_null() { - handle_alloc_error(layout); - } - - // SAFETY: file_rename_info is a non-null pointer pointing to memory allocated by the global allocator. - let mut file_rename_info = unsafe { Box::from_raw(file_rename_info) }; - - // SAFETY: We have allocated enough memory for a full FILE_RENAME_INFO struct and a filename. - unsafe { - (&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 { - Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS | c::FILE_RENAME_FLAG_POSIX_SEMANTICS, - }); + (&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 { + Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS + | c::FILE_RENAME_FLAG_POSIX_SEMANTICS, + }); - (&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut()); - (&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes); - - new.as_ptr() - .copy_to_nonoverlapping((&raw mut (*file_rename_info).FileName) as *mut u16, new.len()); - } - - // We don't use `set_file_information_by_handle` here as `FILE_RENAME_INFO` is used for both `FileRenameInfo` and `FileRenameInfoEx`. - let result = unsafe { - cvt(c::SetFileInformationByHandle( - handle.as_raw_handle(), - c::FileRenameInfoEx, - (&raw const *file_rename_info).cast::(), - struct_size, - )) - }; + (&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut()); + // Don't include the NULL in the size + (&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes); - if let Err(err) = result { - if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) { - // FileRenameInfoEx and FILE_RENAME_FLAG_POSIX_SEMANTICS were added in Windows 10 1607; retry with FileRenameInfo. - file_rename_info.Anonymous.ReplaceIfExists = true; + new.as_ptr().copy_to_nonoverlapping( + (&raw mut (*file_rename_info).FileName).cast::(), + new.len(), + ); + } - cvt(unsafe { + let result = unsafe { c::SetFileInformationByHandle( - handle.as_raw_handle(), - c::FileRenameInfo, - (&raw const *file_rename_info).cast::(), + f.as_raw_handle(), + c::FileRenameInfoEx, + file_rename_info.cast::(), struct_size, ) - })?; + }; + unsafe { dealloc(file_rename_info.cast::(), layout) }; + if result == 0 { + if api::get_last_error() == WinError::DIR_NOT_EMPTY { + return Err(WinError::DIR_NOT_EMPTY).io_result(); + } else { + return Err(err).io_result(); + } + } } else { - return Err(err); + return Err(err).io_result(); } } - Ok(()) } -- cgit 1.4.1-3-g733a5 From 3cb53df1feaba73b84344c8c0e3dc4120ad8c95b Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 6 Mar 2025 14:18:18 +0000 Subject: Return OutOfMemoryError and update docs --- library/std/src/fs.rs | 2 +- library/std/src/sys/pal/windows/fs.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 4314c8a0b18..46b5860123f 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2446,7 +2446,7 @@ pub fn symlink_metadata>(path: P) -> io::Result { /// # Platform-specific behavior /// /// This function currently corresponds to the `rename` function on Unix -/// and the `SetFileInformationByHandle` function on Windows. +/// and the `MoveFileExW` or `SetFileInformationByHandle` function on Windows. /// /// Because of this, the behavior when both `from` and `to` exist differs. On /// Unix, if `from` is a directory, `to` must also be an (empty) directory. If diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 34108e44d58..8fce0496d80 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1,6 +1,6 @@ use super::api::{self, WinError, set_file_information_by_handle}; use super::{IoResult, to_u16s}; -use crate::alloc::{Layout, alloc, dealloc, handle_alloc_error}; +use crate::alloc::{Layout, alloc, dealloc}; use crate::borrow::Cow; use crate::ffi::{OsStr, OsString, c_void}; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; @@ -1269,7 +1269,7 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { unsafe { file_rename_info = alloc(layout).cast::(); if file_rename_info.is_null() { - handle_alloc_error(layout); + return Err(io::ErrorKind::OutOfMemory.into()); } (&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 { -- cgit 1.4.1-3-g733a5 From d975bd3a67e4f18c02f57d8d66a9d32daa295a47 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Thu, 27 Feb 2025 21:09:45 +0000 Subject: Remove highlighting of spans on `-Zteach` `-Zteach` is perma-unstable, barely used, the highlighting logic buggy and the flag being passed around is tech-debt. We should likely remove `-Zteach` in its entirely. --- compiler/rustc_errors/src/emitter.rs | 11 ----------- compiler/rustc_session/src/session.rs | 1 - src/librustdoc/core.rs | 1 - 3 files changed, 13 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index f7f84239308..18846a6dbe1 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -616,7 +616,6 @@ pub struct HumanEmitter { #[setters(skip)] fallback_bundle: LazyFallbackBundle, short_message: bool, - teach: bool, ui_testing: bool, ignored_directories_in_source_blocks: Vec, diagnostic_width: Option, @@ -642,7 +641,6 @@ impl HumanEmitter { fluent_bundle: None, fallback_bundle, short_message: false, - teach: false, ui_testing: false, ignored_directories_in_source_blocks: Vec::new(), diagnostic_width: None, @@ -1044,15 +1042,6 @@ impl HumanEmitter { underline.style, ); } - _ if self.teach => { - buffer.set_style_range( - line_offset, - (code_offset + annotation.start_col.display).saturating_sub(left), - (code_offset + annotation.end_col.display).saturating_sub(left), - underline.style, - annotation.is_primary, - ); - } _ => {} } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index aa1e9762f39..bcd9a73d9d3 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -930,7 +930,6 @@ fn default_emitter( .fluent_bundle(bundle) .sm(source_map) .short_message(short) - .teach(sopts.unstable_opts.teach) .diagnostic_width(sopts.diagnostic_width) .macro_backtrace(macro_backtrace) .track_diagnostics(track_diagnostics) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index f95ae380fa8..719f1f978fe 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -160,7 +160,6 @@ pub(crate) fn new_dcx( HumanEmitter::new(stderr_destination(color_config), fallback_bundle) .sm(source_map.map(|sm| sm as _)) .short_message(short) - .teach(unstable_opts.teach) .diagnostic_width(diagnostic_width) .track_diagnostics(unstable_opts.track_diagnostics) .theme(if let HumanReadableErrorType::Unicode = kind { -- cgit 1.4.1-3-g733a5 From 72326bfe4033fe51c5cb0f31614bbf6e66ec77f9 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Thu, 27 Feb 2025 21:11:22 +0000 Subject: On long spans, trim the middle of them to make them fit in the terminal width When encountering a single line span that is wider than the terminal, we keep context at the start and end of the span but otherwise remove the code from the middle. This is somewhat independent from whether the left and right margins of the output have been trimmed as well. ``` error[E0308]: mismatched types --> $DIR/long-span.rs:6:15 | LL | ... = [0, 0, 0, 0, ..., 0, 0]; | ^^^^^^^^^^^^^...^^^^^^^ expected `u8`, found `[{integer}; 1681]` ``` Address part of #137680 (missing handling of the long suggestion). Fix #125581. --- compiler/rustc_errors/src/emitter.rs | 27 ++++++++++++++++++++++ compiler/rustc_errors/src/styled_buffer.rs | 10 ++++++++ tests/ui/diagnostic-width/long-span.long.stderr | 9 ++++++++ tests/ui/diagnostic-width/long-span.longest.stderr | 9 ++++++++ tests/ui/diagnostic-width/long-span.rs | 9 ++++++++ tests/ui/diagnostic-width/long-span.short.stderr | 9 ++++++++ .../ui/diagnostic-width/long-span.shortest.stderr | 9 ++++++++ tests/ui/parser/raw/too-many-hash.stderr | 4 ++-- tests/ui/rust-2024/reserved-guarded-strings.stderr | 4 ++-- 9 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 tests/ui/diagnostic-width/long-span.long.stderr create mode 100644 tests/ui/diagnostic-width/long-span.longest.stderr create mode 100644 tests/ui/diagnostic-width/long-span.rs create mode 100644 tests/ui/diagnostic-width/long-span.short.stderr create mode 100644 tests/ui/diagnostic-width/long-span.shortest.stderr diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 18846a6dbe1..9277bae94ec 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1238,6 +1238,33 @@ impl HumanEmitter { ); } } + + // We look for individual *long* spans, and we trim the *middle*, so that we render + // LL | ...= [0, 0, 0, ..., 0, 0]; + // | ^^^^^^^^^^...^^^^^^^ expected `&[u8]`, found `[{integer}; 1680]` + for &(pos, annotation) in &annotations_position { + let AnnotationType::Singleline = annotation.annotation_type else { continue }; + let width = annotation.end_col.display - annotation.start_col.display; + if pos == 0 && width > margin.column_width && width > 10 { + // If the terminal is *too* small, we keep at least a tiny bit of the span for + // display. + let pad = max(margin.column_width / 2, 5); + // Code line + buffer.replace( + line_offset, + annotation.start_col.file + pad, + annotation.end_col.file - pad, + self.margin(), + ); + // Underline line + buffer.replace( + line_offset + 1, + annotation.start_col.file + pad, + annotation.end_col.file - pad, + self.margin(), + ); + } + } annotations_position .iter() .filter_map(|&(_, annotation)| match annotation.annotation_type { diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs index 5ca9e9b18f3..b0f4ec84a89 100644 --- a/compiler/rustc_errors/src/styled_buffer.rs +++ b/compiler/rustc_errors/src/styled_buffer.rs @@ -89,6 +89,16 @@ impl StyledBuffer { } } + pub(crate) fn replace(&mut self, line: usize, start: usize, end: usize, string: &str) { + if start == end { + return; + } + let _ = self.lines[line].drain(start..(end - string.chars().count())); + for (i, c) in string.chars().enumerate() { + self.lines[line][start + i] = StyledChar::new(c, Style::LineNumber); + } + } + /// For given `line` inserts `string` with `style` before old content of that line, /// adding lines if needed pub(crate) fn prepend(&mut self, line: usize, string: &str, style: Style) { diff --git a/tests/ui/diagnostic-width/long-span.long.stderr b/tests/ui/diagnostic-width/long-span.long.stderr new file mode 100644 index 00000000000..81edde85b33 --- /dev/null +++ b/tests/ui/diagnostic-width/long-span.long.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + ╭▸ $DIR/long-span.rs:7:15 + │ +LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]… + ╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━…━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostic-width/long-span.longest.stderr b/tests/ui/diagnostic-width/long-span.longest.stderr new file mode 100644 index 00000000000..77aafc5f426 --- /dev/null +++ b/tests/ui/diagnostic-width/long-span.longest.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/long-span.rs:7:15 + | +LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostic-width/long-span.rs b/tests/ui/diagnostic-width/long-span.rs new file mode 100644 index 00000000000..2feacdd9604 --- /dev/null +++ b/tests/ui/diagnostic-width/long-span.rs @@ -0,0 +1,9 @@ +//@ revisions: shortest short long longest +//@[shortest] compile-flags: --diagnostic-width=4 +//@[short] compile-flags: --diagnostic-width=12 -Zunstable-options --json=diagnostic-unicode +//@[long] compile-flags: --diagnostic-width=80 -Zunstable-options --json=diagnostic-unicode +//@[longest] compile-flags: --diagnostic-width=120 +// ignore-tidy-linelength +const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; +//~^ ERROR E0308 +fn main() {} diff --git a/tests/ui/diagnostic-width/long-span.short.stderr b/tests/ui/diagnostic-width/long-span.short.stderr new file mode 100644 index 00000000000..8e62acc936c --- /dev/null +++ b/tests/ui/diagnostic-width/long-span.short.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + ╭▸ $DIR/long-span.rs:7:15 + │ +LL │ …u8 = [0, 0, 0…0]… + ╰╴ ━━━━━━━━…━━ expected `u8`, found `[{integer}; 1680]` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostic-width/long-span.shortest.stderr b/tests/ui/diagnostic-width/long-span.shortest.stderr new file mode 100644 index 00000000000..d9cec96ad8f --- /dev/null +++ b/tests/ui/diagnostic-width/long-span.shortest.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/long-span.rs:7:15 + | +LL | ... = [0, 0, 0...... + | ^^^^^^^^...^^ expected `u8`, found `[{integer}; 1680]` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/raw/too-many-hash.stderr b/tests/ui/parser/raw/too-many-hash.stderr index 1c46b5385cd..61fcbcee159 100644 --- a/tests/ui/parser/raw/too-many-hash.stderr +++ b/tests/ui/parser/raw/too-many-hash.stderr @@ -1,8 +1,8 @@ error: too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 256 --> $DIR/too-many-hash.rs:4:19 | -LL | ... = r################################################################################################################################################################################################################################################################"very raw"##############################################################################################################################################################################################################################################################... - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... = r############################################################################...#############################################################... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/rust-2024/reserved-guarded-strings.stderr b/tests/ui/rust-2024/reserved-guarded-strings.stderr index 0f3b06147c4..5c0f5064546 100644 --- a/tests/ui/rust-2024/reserved-guarded-strings.stderr +++ b/tests/ui/rust-2024/reserved-guarded-strings.stderr @@ -241,8 +241,8 @@ LL | demo2!(#"foo"## #); error: invalid string literal --> $DIR/reserved-guarded-strings.rs:71:12 | -LL | ...n!(####################################################################################################################################################################################################################################################################"foo... - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ...n!(######################################################################...#################################################################"foo... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: unprefixed guarded string literals are reserved for future use since Rust 2024 help: consider inserting whitespace here -- cgit 1.4.1-3-g733a5 From f1c751bc1a08e3439a9d0c482cbb0ea0fc8f644f Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Thu, 27 Feb 2025 21:12:58 +0000 Subject: Refactor `emitter` to better account for unicode chars when trimming Change the way that underline positions are calculated by delaying using the "visual" column position until the last possible moment, instead using the "file"/byte position in the file, and then calculating visual positioning as late as possible. This should make the underlines more resilient to non-1-width unicode chars. Unfortunately, as part of this change (which fixes some visual bugs) comes with the loss of some eager tab codepoint handling, but the output remains legible despite some minor regression on the "margin trimming" logic. --- compiler/rustc_errors/src/emitter.rs | 177 +++++---- tests/ui/codemap_tests/tab_2.stderr | 2 +- tests/ui/diagnostic-width/long-span.long.stderr | 2 +- tests/ui/diagnostic-width/long-span.longest.stderr | 2 +- tests/ui/diagnostic-width/long-span.short.stderr | 2 +- .../ui/diagnostic-width/long-span.shortest.stderr | 2 +- ...on-1-width-unicode-multiline-label.ascii.stderr | 59 ++- .../non-1-width-unicode-multiline-label.rs | 6 + ...-1-width-unicode-multiline-label.unicode.stderr | 59 ++- .../non-whitespace-trimming-unicode.stderr | 8 +- tests/ui/diagnostic-width/tabs-trimming.stderr | 20 +- .../error-emitter/multiline-removal-suggestion.svg | 436 +++++++++++---------- tests/ui/issues/issue-44078.stderr | 2 +- tests/ui/lexer/unterminated-nested-comment.stderr | 2 +- tests/ui/macros/not-utf8.stderr | 2 +- tests/ui/macros/same-sequence-span.stderr | 2 +- tests/ui/parser/byte-string-literals.stderr | 2 +- tests/ui/parser/raw/too-many-hash.stderr | 2 +- tests/ui/parser/unbalanced-doublequote.stderr | 2 +- tests/ui/rust-2024/reserved-guarded-strings.stderr | 2 +- 20 files changed, 462 insertions(+), 329 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 9277bae94ec..9a3c96776b9 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -113,24 +113,11 @@ impl Margin { self.computed_left > 0 } - fn was_cut_right(&self, line_len: usize) -> bool { - let right = - if self.computed_right == self.span_right || self.computed_right == self.label_right { - // FIXME: This comment refers to the only callsite of this method. - // Rephrase it or refactor it, so it can stand on its own. - // Account for the "..." padding given above. Otherwise we end up with code lines - // that do fit but end in "..." as if they were trimmed. - // FIXME: Don't hard-code this offset. Is this meant to represent - // `2 * str_width(self.margin())`? - self.computed_right - 6 - } else { - self.computed_right - }; - right < line_len && self.computed_left + self.column_width < line_len - } - fn compute(&mut self, max_line_len: usize) { // When there's a lot of whitespace (>20), we want to trim it as it is useless. + // FIXME: this doesn't account for '\t', but to do so correctly we need to perform that + // calculation later, right before printing in order to be accurate with both unicode + // handling and trimming of long lines. self.computed_left = if self.whitespace_left > 20 { self.whitespace_left - 16 // We want some padding. } else { @@ -668,43 +655,43 @@ impl HumanEmitter { width_offset: usize, code_offset: usize, margin: Margin, - ) { - // Tabs are assumed to have been replaced by spaces in calling code. - debug_assert!(!source_string.contains('\t')); + ) -> usize { let line_len = source_string.len(); // Create the source line we will highlight. let left = margin.left(line_len); let right = margin.right(line_len); // FIXME: The following code looks fishy. See #132860. // On long lines, we strip the source line, accounting for unicode. - let mut taken = 0; let code: String = source_string .chars() - .skip(left) - .take_while(|ch| { - // Make sure that the trimming on the right will fall within the terminal width. - let next = char_width(*ch); - if taken + next > right - left { - return false; - } - taken += next; - true - }) + .enumerate() + .skip_while(|(i, _)| *i < left) + .take_while(|(i, _)| *i < right) + .map(|(_, c)| c) .collect(); + let code = normalize_whitespace(&code); + let was_cut_right = + source_string.chars().enumerate().skip_while(|(i, _)| *i < right).next().is_some(); buffer.puts(line_offset, code_offset, &code, Style::Quotation); let placeholder = self.margin(); if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. buffer.puts(line_offset, code_offset, placeholder, Style::LineNumber); } - if margin.was_cut_right(line_len) { + if was_cut_right { let padding = str_width(placeholder); // We have stripped some code after the rightmost span end, make it clear we did so. - buffer.puts(line_offset, code_offset + taken - padding, placeholder, Style::LineNumber); + buffer.puts( + line_offset, + code_offset + str_width(&code) - padding, + placeholder, + Style::LineNumber, + ); } buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2); + left } #[instrument(level = "trace", skip(self), ret)] @@ -736,22 +723,16 @@ impl HumanEmitter { return Vec::new(); } - let source_string = match file.get_line(line.line_index - 1) { - Some(s) => normalize_whitespace(&s), - None => return Vec::new(), + let Some(source_string) = file.get_line(line.line_index - 1) else { + return Vec::new(); }; trace!(?source_string); let line_offset = buffer.num_lines(); - // Left trim - let left = margin.left(source_string.len()); - + // Left trim. // FIXME: This looks fishy. See #132860. - // Account for unicode characters of width !=0 that were removed. - let left = source_string.chars().take(left).map(|ch| char_width(ch)).sum(); - - self.draw_line( + let left = self.draw_line( buffer, &source_string, line.line_index, @@ -1033,12 +1014,18 @@ impl HumanEmitter { let pos = pos + 1; match annotation.annotation_type { AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { + let pre: usize = source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum(); self.draw_range( buffer, underline.multiline_horizontal, line_offset + pos, width_offset + depth, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset + pre, underline.style, ); } @@ -1061,11 +1048,18 @@ impl HumanEmitter { let underline = self.underline(annotation.is_primary); let pos = pos + 1; + let code_offset = code_offset + + source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum::(); if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { buffer.putc( p, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, match annotation.annotation_type { AnnotationType::MultilineLine(_) => underline.multiline_vertical, _ => underline.vertical_text_line, @@ -1076,7 +1070,7 @@ impl HumanEmitter { if let AnnotationType::MultilineStart(_) = annotation.annotation_type { buffer.putc( line_offset + pos, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, underline.bottom_right, underline.style, ); @@ -1086,7 +1080,7 @@ impl HumanEmitter { { buffer.putc( line_offset + pos, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, underline.multiline_bottom_right_with_text, underline.style, ); @@ -1144,13 +1138,30 @@ impl HumanEmitter { let style = if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - if annotation.end_col.display == 0 { - (pos + 1, (annotation.end_col.display + 2).saturating_sub(left)) + let pre: usize = source_string + .chars() + .take(annotation.end_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum(); + if annotation.end_col.file == 0 { + (pos + 1, (pre + 2)) } else { - (pos + 1, (annotation.end_col.display + 1).saturating_sub(left)) + let pad = if annotation.end_col.file - annotation.start_col.file == 0 { + 2 + } else { + 1 + }; + (pos + 1, (pre + pad)) } } else { - (pos + 2, annotation.start_col.display.saturating_sub(left)) + let pre: usize = source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum(); + (pos + 2, pre) }; if let Some(ref label) = annotation.label { buffer.puts(line_offset + pos, code_offset + col, label, style); @@ -1183,14 +1194,35 @@ impl HumanEmitter { // | _^ test for &(pos, annotation) in &annotations_position { let uline = self.underline(annotation.is_primary); - for p in annotation.start_col.display..annotation.end_col.display { + let width = annotation.end_col.file - annotation.start_col.file; + let previous: String = + source_string.chars().take(annotation.start_col.file).skip(left).collect(); + let underlined: String = + source_string.chars().skip(annotation.start_col.file).take(width).collect(); + debug!(?previous, ?underlined); + let code_offset = code_offset + + source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum::(); + let ann_width: usize = source_string + .chars() + .skip(annotation.start_col.file) + .take(width) + .map(|c| char_width(c)) + .sum(); + let ann_width = if ann_width == 0 + && matches!(annotation.annotation_type, AnnotationType::Singleline) + { + 1 + } else { + ann_width + }; + for p in 0..ann_width { // The default span label underline. - buffer.putc( - line_offset + 1, - (code_offset + p).saturating_sub(left), - uline.underline, - uline.style, - ); + buffer.putc(line_offset + 1, code_offset + p, uline.underline, uline.style); } if pos == 0 @@ -1202,7 +1234,7 @@ impl HumanEmitter { // The beginning of a multiline span with its leftward moving line on the same line. buffer.putc( line_offset + 1, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, match annotation.annotation_type { AnnotationType::MultilineStart(_) => uline.top_right_flat, AnnotationType::MultilineEnd(_) => uline.multiline_end_same_line, @@ -1220,7 +1252,7 @@ impl HumanEmitter { // so we start going down first. buffer.putc( line_offset + 1, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, match annotation.annotation_type { AnnotationType::MultilineStart(_) => uline.multiline_start_down, AnnotationType::MultilineEnd(_) => uline.multiline_end_up, @@ -1230,12 +1262,7 @@ impl HumanEmitter { ); } else if pos != 0 && annotation.has_label() { // The beginning of a span label with an actual label, we'll point down. - buffer.putc( - line_offset + 1, - (code_offset + annotation.start_col.display).saturating_sub(left), - uline.label_start, - uline.style, - ); + buffer.putc(line_offset + 1, code_offset, uline.label_start, uline.style); } } @@ -1718,17 +1745,11 @@ impl HumanEmitter { // non-rustc_lexer::is_whitespace() chars are reported as an // error (ex. no-break-spaces \u{a0}), and thus can't be considered // for removal during error reporting. + // FIXME: doesn't account for '\t' properly. let leading_whitespace = source_string .chars() .take_while(|c| rustc_lexer::is_whitespace(*c)) - .map(|c| { - match c { - // Tabs are displayed as 4 spaces - '\t' => 4, - _ => 1, - } - }) - .sum(); + .count(); if source_string.chars().any(|c| !rustc_lexer::is_whitespace(c)) { whitespace_margin = min(whitespace_margin, leading_whitespace); } @@ -1742,8 +1763,8 @@ impl HumanEmitter { let mut span_left_margin = usize::MAX; for line in &annotated_file.lines { for ann in &line.annotations { - span_left_margin = min(span_left_margin, ann.start_col.display); - span_left_margin = min(span_left_margin, ann.end_col.display); + span_left_margin = min(span_left_margin, ann.start_col.file); + span_left_margin = min(span_left_margin, ann.end_col.file); } } if span_left_margin == usize::MAX { @@ -1763,12 +1784,12 @@ impl HumanEmitter { .map_or(0, |s| s.len()), ); for ann in &line.annotations { - span_right_margin = max(span_right_margin, ann.start_col.display); - span_right_margin = max(span_right_margin, ann.end_col.display); + span_right_margin = max(span_right_margin, ann.start_col.file); + span_right_margin = max(span_right_margin, ann.end_col.file); // FIXME: account for labels not in the same line let label_right = ann.label.as_ref().map_or(0, |l| l.len() + 1); label_right_margin = - max(label_right_margin, ann.end_col.display + label_right); + max(label_right_margin, ann.end_col.file + label_right); } } diff --git a/tests/ui/codemap_tests/tab_2.stderr b/tests/ui/codemap_tests/tab_2.stderr index b22c7b42665..4f9a937155d 100644 --- a/tests/ui/codemap_tests/tab_2.stderr +++ b/tests/ui/codemap_tests/tab_2.stderr @@ -4,7 +4,7 @@ error[E0765]: unterminated double quote string LL | """; | ___________________^ LL | | } - | |_^ + | |__^ error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/long-span.long.stderr b/tests/ui/diagnostic-width/long-span.long.stderr index 81edde85b33..e39f4000d3c 100644 --- a/tests/ui/diagnostic-width/long-span.long.stderr +++ b/tests/ui/diagnostic-width/long-span.long.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types ╭▸ $DIR/long-span.rs:7:15 │ -LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]… +LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; ╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━…━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/long-span.longest.stderr b/tests/ui/diagnostic-width/long-span.longest.stderr index 77aafc5f426..8e2bad93692 100644 --- a/tests/ui/diagnostic-width/long-span.longest.stderr +++ b/tests/ui/diagnostic-width/long-span.longest.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/long-span.rs:7:15 | -LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... +LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/long-span.short.stderr b/tests/ui/diagnostic-width/long-span.short.stderr index 8e62acc936c..73ee895a89b 100644 --- a/tests/ui/diagnostic-width/long-span.short.stderr +++ b/tests/ui/diagnostic-width/long-span.short.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types ╭▸ $DIR/long-span.rs:7:15 │ -LL │ …u8 = [0, 0, 0…0]… +LL │ …u8 = [0, 0, 0…0]; ╰╴ ━━━━━━━━…━━ expected `u8`, found `[{integer}; 1680]` error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/long-span.shortest.stderr b/tests/ui/diagnostic-width/long-span.shortest.stderr index d9cec96ad8f..2b485e75541 100644 --- a/tests/ui/diagnostic-width/long-span.shortest.stderr +++ b/tests/ui/diagnostic-width/long-span.shortest.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/long-span.rs:7:15 | -LL | ... = [0, 0, 0...... +LL | ... = [0, 0, 0...0]; | ^^^^^^^^...^^ expected `u8`, found `[{integer}; 1680]` error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr index 4d8afb6f3ad..60ce0d9a148 100644 --- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr @@ -1,11 +1,41 @@ error[E0369]: cannot add `&str` to `&str` - --> $DIR/non-1-width-unicode-multiline-label.rs:7:260 + --> $DIR/non-1-width-unicode-multiline-label.rs:7:237 | -LL | ...ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇...࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; - | -------------- ^ -------------- &str - | | | - | | `+` cannot be used to concatenate two `&str` strings - | &str +LL | ...👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!"; + | -------------- ^ -------------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str + | + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + | +LL | let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!"; + | +++++++++++ + +error[E0369]: cannot add `&str` to `&str` + --> $DIR/non-1-width-unicode-multiline-label.rs:9:384 + | +LL | ...👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!"; + | -------------- ^ -------------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str + | + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + | +LL | let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!"; + | +++++++++++ + +error[E0369]: cannot add `&str` to `&str` + --> $DIR/non-1-width-unicode-multiline-label.rs:11:260 + | +LL | ...࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; + | -------------- ^ -------------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str | = note: string concatenation requires an owned `String` on the left help: create an owned `String` from a string reference @@ -13,6 +43,21 @@ help: create an owned `String` from a string reference LL | let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!"; | +++++++++++ -error: aborting due to 1 previous error +error[E0369]: cannot add `&str` to `&str` + --> $DIR/non-1-width-unicode-multiline-label.rs:13:219 + | +LL | ...xxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!"; + | -------------- ^ -------------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str + | + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + | +LL | let _ = "xxxxxxx👨👩👧👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun.to_owned() + " really fun!"; + | +++++++++++ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs index e630db8ba42..6b9b27f6297 100644 --- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs @@ -4,6 +4,12 @@ fn main() { let unicode_is_fun = "؁‱ஹ௸௵꧄.ဪ꧅⸻𒈙𒐫﷽𒌄𒈟𒍼𒁎𒀱𒌧𒅃 𒈓𒍙𒊎𒄡𒅌𒁏𒀰𒐪𒐩𒈙𒐫𪚥"; + let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!"; + //[ascii]~^ ERROR cannot add `&str` to `&str` + let _ = "👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦"; let _a = unicode_is_fun + " really fun!"; + //[ascii]~^ ERROR cannot add `&str` to `&str` let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; //[ascii]~^ ERROR cannot add `&str` to `&str` + let _ = "xxxxxxx👨‍👩‍👧‍👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!"; + //[ascii]~^ ERROR cannot add `&str` to `&str` } diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr index ed8ce770bb7..15b5dd9d7e2 100644 --- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr @@ -1,11 +1,41 @@ error[E0369]: cannot add `&str` to `&str` - ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:260 + ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:237 │ -LL │ …ཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉…࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; - │ ┬───────────── ┯ ────────────── &str - │ │ │ - │ │ `+` cannot be used to concatenate two `&str` strings - │ &str +LL │ …👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str + │ + ╰ note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + ╭╴ +LL │ let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!"; + ╰╴ +++++++++++ + +error[E0369]: cannot add `&str` to `&str` + ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:9:384 + │ +LL │ …👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str + │ + ╰ note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + ╭╴ +LL │ let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!"; + ╰╴ +++++++++++ + +error[E0369]: cannot add `&str` to `&str` + ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:11:260 + │ +LL │ …࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str │ ╰ note: string concatenation requires an owned `String` on the left help: create an owned `String` from a string reference @@ -13,6 +43,21 @@ help: create an owned `String` from a string reference LL │ let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!"; ╰╴ +++++++++++ -error: aborting due to 1 previous error +error[E0369]: cannot add `&str` to `&str` + ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:13:219 + │ +LL │ …xxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str + │ + ╰ note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + ╭╴ +LL │ let _ = "xxxxxxx👨👩👧👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun.to_owned() + " really fun!"; + ╰╴ +++++++++++ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr b/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr index da3d8d31892..5408825d8cd 100644 --- a/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr +++ b/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr @@ -1,10 +1,10 @@ error[E0308]: mismatched types --> $DIR/non-whitespace-trimming-unicode.rs:4:415 | -LL | ...♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄... - | -- ^^ expected `()`, found integer - | | - | expected due to this +LL | ...♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼... + | -- ^^ expected `()`, found integer + | | + | expected due to this error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/tabs-trimming.stderr b/tests/ui/diagnostic-width/tabs-trimming.stderr index 85103fbf6f5..a896345bd70 100644 --- a/tests/ui/diagnostic-width/tabs-trimming.stderr +++ b/tests/ui/diagnostic-width/tabs-trimming.stderr @@ -1,20 +1,20 @@ error[E0408]: variable `v` is not bound in all patterns --> $DIR/tabs-trimming.rs:9:16 | -LL | ... v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT... - | - ^ ^ pattern doesn't bind `v` - | | | - | | pattern doesn't bind `v` - | variable not in all patterns +LL | ... v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT... + | - ^ ^ pattern doesn't bind `v` + | | | + | | pattern doesn't bind `v` + | variable not in all patterns error[E0381]: used binding `v` is possibly-uninitialized --> $DIR/tabs-trimming.rs:9:67 | -LL | ... v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT... - | - ^ `v` used here but it is possibly-uninitialized - | | - | binding initialized here in some conditions - | binding declared here but left uninitialized +LL | ... v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT... + | - ^ `v` used here but it is possibly-uninitialized + | | + | binding initialized here in some conditions + | binding declared here but left uninitialized | = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/error-emitter/multiline-removal-suggestion.svg b/tests/ui/error-emitter/multiline-removal-suggestion.svg index 95c7740f699..0820baaff09 100644 --- a/tests/ui/error-emitter/multiline-removal-suggestion.svg +++ b/tests/ui/error-emitter/multiline-removal-suggestion.svg @@ -1,4 +1,4 @@ - + { - input.into_iter().map(|e| unsafe { std::mem::transmute_copy(&e) }).collect() -} - -#[bench] -fn bench_transmute(b: &mut Bencher) { - let mut vec = vec![10u32; 100]; - b.bytes = 800; // 2 casts x 4 bytes x 100 - b.iter(|| { - let v = std::mem::take(&mut vec); - let v = black_box(vec_cast::(v)); - let v = black_box(vec_cast::(v)); - vec = v; - }); -} - -#[derive(Clone)] -struct Droppable(usize); - -impl Drop for Droppable { - fn drop(&mut self) { - black_box(self); - } -} - -#[bench] -fn bench_in_place_collect_droppable(b: &mut Bencher) { - let v: Vec = std::iter::repeat_with(|| Droppable(0)).take(1000).collect(); - b.iter(|| { - v.clone() - .into_iter() - .skip(100) - .enumerate() - .map(|(i, e)| Droppable(i ^ e.0)) - .collect::>() - }) -} - -// node.js gives out of memory error to use with length 1_100_000 -#[cfg(target_os = "emscripten")] -const LEN: usize = 4096; - -#[cfg(not(target_os = "emscripten"))] -const LEN: usize = 16384; - -#[bench] -fn bench_chain_collect(b: &mut Bencher) { - let data = black_box([0; LEN]); - b.iter(|| data.iter().cloned().chain([1]).collect::>()); -} - -#[bench] -fn bench_chain_chain_collect(b: &mut Bencher) { - let data = black_box([0; LEN]); - b.iter(|| data.iter().cloned().chain([1]).chain([2]).collect::>()); -} - -#[bench] -fn bench_nest_chain_chain_collect(b: &mut Bencher) { - let data = black_box([0; LEN]); - b.iter(|| { - data.iter().cloned().chain([1].iter().chain([2].iter()).cloned()).collect::>() - }); -} - -#[bench] -fn bench_range_map_collect(b: &mut Bencher) { - b.iter(|| (0..LEN).map(|_| u32::default()).collect::>()); -} - -#[bench] -fn bench_chain_extend_ref(b: &mut Bencher) { - let data = black_box([0; LEN]); - b.iter(|| { - let mut v = Vec::::with_capacity(data.len() + 1); - v.extend(data.iter().chain([1].iter())); - v - }); -} - -#[bench] -fn bench_chain_extend_value(b: &mut Bencher) { - let data = black_box([0; LEN]); - b.iter(|| { - let mut v = Vec::::with_capacity(data.len() + 1); - v.extend(data.iter().cloned().chain(Some(1))); - v - }); -} - -#[bench] -fn bench_rev_1(b: &mut Bencher) { - let data = black_box([0; LEN]); - b.iter(|| { - let mut v = Vec::::new(); - v.extend(data.iter().rev()); - v - }); -} - -#[bench] -fn bench_rev_2(b: &mut Bencher) { - let data = black_box([0; LEN]); - b.iter(|| { - let mut v = Vec::::with_capacity(data.len()); - v.extend(data.iter().rev()); - v - }); -} - -#[bench] -fn bench_map_regular(b: &mut Bencher) { - let data = black_box([(0, 0); LEN]); - b.iter(|| { - let mut v = Vec::::new(); - v.extend(data.iter().map(|t| t.1)); - v - }); -} - -#[bench] -fn bench_map_fast(b: &mut Bencher) { - let data = black_box([(0, 0); LEN]); - b.iter(|| { - let mut result: Vec = Vec::with_capacity(data.len()); - for i in 0..data.len() { - unsafe { - *result.as_mut_ptr().add(i) = data[i].0; - result.set_len(i); - } - } - result - }); -} - -fn random_sorted_fill(mut seed: u32, buf: &mut [u32]) { - let mask = if buf.len() < 8192 { - 0xFF - } else if buf.len() < 200_000 { - 0xFFFF - } else { - 0xFFFF_FFFF - }; - - for item in buf.iter_mut() { - seed ^= seed << 13; - seed ^= seed >> 17; - seed ^= seed << 5; - - *item = seed & mask; - } - - buf.sort(); -} - -// Measures performance of slice dedup impl. -// This was used to justify separate implementation of dedup for Vec. -// This algorithm was used for Vecs prior to Rust 1.52. -fn bench_dedup_slice_truncate(b: &mut Bencher, sz: usize) { - let mut template = vec![0u32; sz]; - b.bytes = size_of_val(template.as_slice()) as u64; - random_sorted_fill(0x43, &mut template); - - let mut vec = template.clone(); - b.iter(|| { - let vec = black_box(&mut vec); - let len = { - let (dedup, _) = vec.partition_dedup(); - dedup.len() - }; - vec.truncate(len); - - black_box(vec.first()); - let vec = black_box(vec); - vec.clear(); - vec.extend_from_slice(&template); - }); -} - -// Measures performance of Vec::dedup on random data. -fn bench_vec_dedup_random(b: &mut Bencher, sz: usize) { - let mut template = vec![0u32; sz]; - b.bytes = size_of_val(template.as_slice()) as u64; - random_sorted_fill(0x43, &mut template); - - let mut vec = template.clone(); - b.iter(|| { - let vec = black_box(&mut vec); - vec.dedup(); - black_box(vec.first()); - let vec = black_box(vec); - vec.clear(); - vec.extend_from_slice(&template); - }); -} - -// Measures performance of Vec::dedup when there is no items removed -fn bench_vec_dedup_none(b: &mut Bencher, sz: usize) { - let mut template = vec![0u32; sz]; - b.bytes = size_of_val(template.as_slice()) as u64; - template.chunks_exact_mut(2).for_each(|w| { - w[0] = black_box(0); - w[1] = black_box(5); - }); - - let mut vec = template.clone(); - b.iter(|| { - let vec = black_box(&mut vec); - vec.dedup(); - black_box(vec.first()); - // Unlike other benches of `dedup` - // this doesn't reinitialize vec - // because we measure how efficient dedup is - // when no memory written - }); -} - -// Measures performance of Vec::dedup when there is all items removed -fn bench_vec_dedup_all(b: &mut Bencher, sz: usize) { - let mut template = vec![0u32; sz]; - b.bytes = size_of_val(template.as_slice()) as u64; - template.iter_mut().for_each(|w| { - *w = black_box(0); - }); - - let mut vec = template.clone(); - b.iter(|| { - let vec = black_box(&mut vec); - vec.dedup(); - black_box(vec.first()); - let vec = black_box(vec); - vec.clear(); - vec.extend_from_slice(&template); - }); -} - -#[bench] -fn bench_dedup_slice_truncate_100(b: &mut Bencher) { - bench_dedup_slice_truncate(b, 100); -} -#[bench] -fn bench_dedup_random_100(b: &mut Bencher) { - bench_vec_dedup_random(b, 100); -} - -#[bench] -fn bench_dedup_none_100(b: &mut Bencher) { - bench_vec_dedup_none(b, 100); -} - -#[bench] -fn bench_dedup_all_100(b: &mut Bencher) { - bench_vec_dedup_all(b, 100); -} - -#[bench] -fn bench_dedup_slice_truncate_1000(b: &mut Bencher) { - bench_dedup_slice_truncate(b, 1000); -} -#[bench] -fn bench_dedup_random_1000(b: &mut Bencher) { - bench_vec_dedup_random(b, 1000); -} - -#[bench] -fn bench_dedup_none_1000(b: &mut Bencher) { - bench_vec_dedup_none(b, 1000); -} - -#[bench] -fn bench_dedup_all_1000(b: &mut Bencher) { - bench_vec_dedup_all(b, 1000); -} - -#[bench] -fn bench_dedup_slice_truncate_10000(b: &mut Bencher) { - bench_dedup_slice_truncate(b, 10000); -} -#[bench] -fn bench_dedup_random_10000(b: &mut Bencher) { - bench_vec_dedup_random(b, 10000); -} - -#[bench] -fn bench_dedup_none_10000(b: &mut Bencher) { - bench_vec_dedup_none(b, 10000); -} - -#[bench] -fn bench_dedup_all_10000(b: &mut Bencher) { - bench_vec_dedup_all(b, 10000); -} - -#[bench] -fn bench_dedup_slice_truncate_100000(b: &mut Bencher) { - bench_dedup_slice_truncate(b, 100000); -} -#[bench] -fn bench_dedup_random_100000(b: &mut Bencher) { - bench_vec_dedup_random(b, 100000); -} - -#[bench] -fn bench_dedup_none_100000(b: &mut Bencher) { - bench_vec_dedup_none(b, 100000); -} - -#[bench] -fn bench_dedup_all_100000(b: &mut Bencher) { - bench_vec_dedup_all(b, 100000); -} - -#[bench] -fn bench_flat_map_collect(b: &mut Bencher) { - let v = vec![777u32; 500000]; - b.iter(|| v.iter().flat_map(|color| color.rotate_left(8).to_be_bytes()).collect::>()); -} - -/// Reference benchmark that `retain` has to compete with. -#[bench] -fn bench_retain_iter_100000(b: &mut Bencher) { - let mut v = Vec::with_capacity(100000); - - b.iter(|| { - let mut tmp = std::mem::take(&mut v); - tmp.clear(); - tmp.extend(black_box(1..=100000)); - v = tmp.into_iter().filter(|x| x & 1 == 0).collect(); - }); -} - -#[bench] -fn bench_retain_100000(b: &mut Bencher) { - let mut v = Vec::with_capacity(100000); - - b.iter(|| { - v.clear(); - v.extend(black_box(1..=100000)); - v.retain(|x| x & 1 == 0) - }); -} - -#[bench] -fn bench_retain_whole_100000(b: &mut Bencher) { - let mut v = black_box(vec![826u32; 100000]); - b.iter(|| v.retain(|x| *x == 826u32)); -} - -#[bench] -fn bench_next_chunk(b: &mut Bencher) { - let v = vec![13u8; 2048]; - - b.iter(|| { - const CHUNK: usize = 8; - - let mut sum = [0u32; CHUNK]; - let mut iter = black_box(v.clone()).into_iter(); - - while let Ok(chunk) = iter.next_chunk::() { - for i in 0..CHUNK { - sum[i] += chunk[i] as u32; - } - } - - sum - }) -} diff --git a/library/alloc/benches/vec_deque.rs b/library/alloc/benches/vec_deque.rs deleted file mode 100644 index a56f8496963..00000000000 --- a/library/alloc/benches/vec_deque.rs +++ /dev/null @@ -1,267 +0,0 @@ -use std::collections::{VecDeque, vec_deque}; -use std::mem; - -use test::{Bencher, black_box}; - -#[bench] -fn bench_new(b: &mut Bencher) { - b.iter(|| { - let ring: VecDeque = VecDeque::new(); - black_box(ring); - }) -} - -#[bench] -fn bench_grow_1025(b: &mut Bencher) { - b.iter(|| { - let mut deq = VecDeque::new(); - for i in 0..1025 { - deq.push_front(i); - } - black_box(deq); - }) -} - -#[bench] -fn bench_iter_1000(b: &mut Bencher) { - let ring: VecDeque<_> = (0..1000).collect(); - - b.iter(|| { - let mut sum = 0; - for &i in &ring { - sum += i; - } - black_box(sum); - }) -} - -#[bench] -fn bench_mut_iter_1000(b: &mut Bencher) { - let mut ring: VecDeque<_> = (0..1000).collect(); - - b.iter(|| { - let mut sum = 0; - for i in &mut ring { - sum += *i; - } - black_box(sum); - }) -} - -#[bench] -fn bench_try_fold(b: &mut Bencher) { - let ring: VecDeque<_> = (0..1000).collect(); - - b.iter(|| black_box(ring.iter().try_fold(0, |a, b| Some(a + b)))) -} - -/// does the memory bookkeeping to reuse the buffer of the Vec between iterations. -/// `setup` must not modify its argument's length or capacity. `g` must not move out of its argument. -fn into_iter_helper< - T: Copy, - F: FnOnce(&mut VecDeque), - G: FnOnce(&mut vec_deque::IntoIter), ->( - v: &mut Vec, - setup: F, - g: G, -) { - let ptr = v.as_mut_ptr(); - let len = v.len(); - // ensure that the vec is full, to make sure that any wrapping from the deque doesn't - // access uninitialized memory. - assert_eq!(v.len(), v.capacity()); - - let mut deque = VecDeque::from(mem::take(v)); - setup(&mut deque); - - let mut it = deque.into_iter(); - g(&mut it); - - mem::forget(it); - - // SAFETY: the provided functions are not allowed to modify the allocation, so the buffer is still alive. - // len and capacity are accurate due to the above assertion. - // All the elements in the buffer are still valid, because of `T: Copy` which implies `T: !Drop`. - mem::forget(mem::replace(v, unsafe { Vec::from_raw_parts(ptr, len, len) })); -} - -#[bench] -fn bench_into_iter(b: &mut Bencher) { - let len = 1024; - // we reuse this allocation for every run - let mut vec: Vec = (0..len).collect(); - vec.shrink_to_fit(); - - b.iter(|| { - let mut sum = 0; - into_iter_helper( - &mut vec, - |_| {}, - |it| { - for i in it { - sum += i; - } - }, - ); - black_box(sum); - - let mut sum = 0; - // rotating a full deque doesn't move any memory. - into_iter_helper( - &mut vec, - |d| d.rotate_left(len / 2), - |it| { - for i in it { - sum += i; - } - }, - ); - black_box(sum); - }); -} - -#[bench] -fn bench_into_iter_fold(b: &mut Bencher) { - let len = 1024; - - // because `fold` takes ownership of the iterator, - // we can't prevent it from dropping the memory, - // so we have to bite the bullet and reallocate - // for every iteration. - b.iter(|| { - let deque: VecDeque = (0..len).collect(); - assert_eq!(deque.len(), deque.capacity()); - let sum = deque.into_iter().fold(0, |a, b| a + b); - black_box(sum); - - // rotating a full deque doesn't move any memory. - let mut deque: VecDeque = (0..len).collect(); - assert_eq!(deque.len(), deque.capacity()); - deque.rotate_left(len / 2); - let sum = deque.into_iter().fold(0, |a, b| a + b); - black_box(sum); - }); -} - -#[bench] -fn bench_into_iter_try_fold(b: &mut Bencher) { - let len = 1024; - // we reuse this allocation for every run - let mut vec: Vec = (0..len).collect(); - vec.shrink_to_fit(); - - // Iterator::any uses Iterator::try_fold under the hood - b.iter(|| { - let mut b = false; - into_iter_helper(&mut vec, |_| {}, |it| b = it.any(|i| i == len - 1)); - black_box(b); - - into_iter_helper(&mut vec, |d| d.rotate_left(len / 2), |it| b = it.any(|i| i == len - 1)); - black_box(b); - }); -} - -#[bench] -fn bench_into_iter_next_chunk(b: &mut Bencher) { - let len = 1024; - // we reuse this allocation for every run - let mut vec: Vec = (0..len).collect(); - vec.shrink_to_fit(); - - b.iter(|| { - let mut buf = [0; 64]; - into_iter_helper( - &mut vec, - |_| {}, - |it| { - while let Ok(a) = it.next_chunk() { - buf = a; - } - }, - ); - black_box(buf); - - into_iter_helper( - &mut vec, - |d| d.rotate_left(len / 2), - |it| { - while let Ok(a) = it.next_chunk() { - buf = a; - } - }, - ); - black_box(buf); - }); -} - -#[bench] -fn bench_from_array_1000(b: &mut Bencher) { - const N: usize = 1000; - let mut array: [usize; N] = [0; N]; - - for i in 0..N { - array[i] = i; - } - - b.iter(|| { - let deq: VecDeque<_> = array.into(); - black_box(deq); - }) -} - -#[bench] -fn bench_extend_bytes(b: &mut Bencher) { - let mut ring: VecDeque = VecDeque::with_capacity(1000); - let input: &[u8] = &[128; 512]; - - b.iter(|| { - ring.clear(); - ring.extend(black_box(input)); - }); -} - -#[bench] -fn bench_extend_vec(b: &mut Bencher) { - let mut ring: VecDeque = VecDeque::with_capacity(1000); - let input = vec![128; 512]; - - b.iter(|| { - ring.clear(); - - let input = input.clone(); - ring.extend(black_box(input)); - }); -} - -#[bench] -fn bench_extend_trustedlen(b: &mut Bencher) { - let mut ring: VecDeque = VecDeque::with_capacity(1000); - - b.iter(|| { - ring.clear(); - ring.extend(black_box(0..512)); - }); -} - -#[bench] -fn bench_extend_chained_trustedlen(b: &mut Bencher) { - let mut ring: VecDeque = VecDeque::with_capacity(1000); - - b.iter(|| { - ring.clear(); - ring.extend(black_box((0..256).chain(768..1024))); - }); -} - -#[bench] -fn bench_extend_chained_bytes(b: &mut Bencher) { - let mut ring: VecDeque = VecDeque::with_capacity(1000); - let input1: &[u16] = &[128; 256]; - let input2: &[u16] = &[255; 256]; - - b.iter(|| { - ring.clear(); - ring.extend(black_box(input1.iter().chain(input2.iter()))); - }); -} diff --git a/library/alloc/benches/vec_deque_append.rs b/library/alloc/benches/vec_deque_append.rs deleted file mode 100644 index 7c805da9737..00000000000 --- a/library/alloc/benches/vec_deque_append.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::collections::VecDeque; -use std::time::Instant; - -const VECDEQUE_LEN: i32 = 100000; -const WARMUP_N: usize = 100; -const BENCH_N: usize = 1000; - -fn main() { - if cfg!(miri) { - // Don't benchmark Miri... - // (Due to bootstrap quirks, this gets picked up by `x.py miri library/alloc --no-doc`.) - return; - } - let a: VecDeque = (0..VECDEQUE_LEN).collect(); - let b: VecDeque = (0..VECDEQUE_LEN).collect(); - - for _ in 0..WARMUP_N { - let mut c = a.clone(); - let mut d = b.clone(); - c.append(&mut d); - } - - let mut durations = Vec::with_capacity(BENCH_N); - - for _ in 0..BENCH_N { - let mut c = a.clone(); - let mut d = b.clone(); - let before = Instant::now(); - c.append(&mut d); - let after = Instant::now(); - durations.push(after.duration_since(before)); - } - - let l = durations.len(); - durations.sort(); - - assert!(BENCH_N % 2 == 0); - let median = (durations[(l / 2) - 1] + durations[l / 2]) / 2; - println!("\ncustom-bench vec_deque_append {:?} ns/iter\n", median.as_nanos()); -} diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs deleted file mode 100644 index 70f32fbaab4..00000000000 --- a/library/alloc/src/raw_vec.rs +++ /dev/null @@ -1,818 +0,0 @@ -#![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")] - -use core::marker::PhantomData; -use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; -use core::ptr::{self, NonNull, Unique}; -use core::{cmp, hint}; - -#[cfg(not(no_global_oom_handling))] -use crate::alloc::handle_alloc_error; -use crate::alloc::{Allocator, Global, Layout}; -use crate::boxed::Box; -use crate::collections::TryReserveError; -use crate::collections::TryReserveErrorKind::*; - -#[cfg(test)] -mod tests; - -// One central function responsible for reporting capacity overflows. This'll -// ensure that the code generation related to these panics is minimal as there's -// only one location which panics rather than a bunch throughout the module. -#[cfg(not(no_global_oom_handling))] -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -#[track_caller] -fn capacity_overflow() -> ! { - panic!("capacity overflow"); -} - -enum AllocInit { - /// The contents of the new memory are uninitialized. - Uninitialized, - #[cfg(not(no_global_oom_handling))] - /// The new memory is guaranteed to be zeroed. - Zeroed, -} - -type Cap = core::num::niche_types::UsizeNoHighBit; - -const ZERO_CAP: Cap = unsafe { Cap::new_unchecked(0) }; - -/// `Cap(cap)`, except if `T` is a ZST then `Cap::ZERO`. -/// -/// # Safety: cap must be <= `isize::MAX`. -unsafe fn new_cap(cap: usize) -> Cap { - if T::IS_ZST { ZERO_CAP } else { unsafe { Cap::new_unchecked(cap) } } -} - -/// A low-level utility for more ergonomically allocating, reallocating, and deallocating -/// a buffer of memory on the heap without having to worry about all the corner cases -/// involved. This type is excellent for building your own data structures like Vec and VecDeque. -/// In particular: -/// -/// * Produces `Unique::dangling()` on zero-sized types. -/// * Produces `Unique::dangling()` on zero-length allocations. -/// * Avoids freeing `Unique::dangling()`. -/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics). -/// * Guards against 32-bit systems allocating more than `isize::MAX` bytes. -/// * Guards against overflowing your length. -/// * Calls `handle_alloc_error` for fallible allocations. -/// * Contains a `ptr::Unique` and thus endows the user with all related benefits. -/// * Uses the excess returned from the allocator to use the largest available capacity. -/// -/// This type does not in anyway inspect the memory that it manages. When dropped it *will* -/// free its memory, but it *won't* try to drop its contents. It is up to the user of `RawVec` -/// to handle the actual things *stored* inside of a `RawVec`. -/// -/// Note that the excess of a zero-sized types is always infinite, so `capacity()` always returns -/// `usize::MAX`. This means that you need to be careful when round-tripping this type with a -/// `Box<[T]>`, since `capacity()` won't yield the length. -#[allow(missing_debug_implementations)] -pub(crate) struct RawVec { - inner: RawVecInner, - _marker: PhantomData, -} - -/// Like a `RawVec`, but only generic over the allocator, not the type. -/// -/// As such, all the methods need the layout passed-in as a parameter. -/// -/// Having this separation reduces the amount of code we need to monomorphize, -/// as most operations don't need the actual type, just its layout. -#[allow(missing_debug_implementations)] -struct RawVecInner { - ptr: Unique, - /// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case. - /// - /// # Safety - /// - /// `cap` must be in the `0..=isize::MAX` range. - cap: Cap, - alloc: A, -} - -impl RawVec { - /// Creates the biggest possible `RawVec` (on the system heap) - /// without allocating. If `T` has positive size, then this makes a - /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a - /// `RawVec` with capacity `usize::MAX`. Useful for implementing - /// delayed allocation. - #[must_use] - pub(crate) const fn new() -> Self { - Self::new_in(Global) - } - - /// Creates a `RawVec` (on the system heap) with exactly the - /// capacity and alignment requirements for a `[T; capacity]`. This is - /// equivalent to calling `RawVec::new` when `capacity` is `0` or `T` is - /// zero-sized. Note that if `T` is zero-sized this means you will - /// *not* get a `RawVec` with the requested capacity. - /// - /// Non-fallible version of `try_with_capacity` - /// - /// # Panics - /// - /// Panics if the requested capacity exceeds `isize::MAX` bytes. - /// - /// # Aborts - /// - /// Aborts on OOM. - #[cfg(not(any(no_global_oom_handling, test)))] - #[must_use] - #[inline] - #[track_caller] - pub(crate) fn with_capacity(capacity: usize) -> Self { - Self { inner: RawVecInner::with_capacity(capacity, T::LAYOUT), _marker: PhantomData } - } - - /// Like `with_capacity`, but guarantees the buffer is zeroed. - #[cfg(not(any(no_global_oom_handling, test)))] - #[must_use] - #[inline] - #[track_caller] - pub(crate) fn with_capacity_zeroed(capacity: usize) -> Self { - Self { - inner: RawVecInner::with_capacity_zeroed_in(capacity, Global, T::LAYOUT), - _marker: PhantomData, - } - } -} - -impl RawVecInner { - #[cfg(not(any(no_global_oom_handling, test)))] - #[must_use] - #[inline] - #[track_caller] - fn with_capacity(capacity: usize, elem_layout: Layout) -> Self { - match Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global, elem_layout) { - Ok(res) => res, - Err(err) => handle_error(err), - } - } -} - -// Tiny Vecs are dumb. Skip to: -// - 8 if the element size is 1, because any heap allocators is likely -// to round up a request of less than 8 bytes to at least 8 bytes. -// - 4 if elements are moderate-sized (<= 1 KiB). -// - 1 otherwise, to avoid wasting too much space for very short Vecs. -const fn min_non_zero_cap(size: usize) -> usize { - if size == 1 { - 8 - } else if size <= 1024 { - 4 - } else { - 1 - } -} - -impl RawVec { - #[cfg(not(no_global_oom_handling))] - pub(crate) const MIN_NON_ZERO_CAP: usize = min_non_zero_cap(size_of::()); - - /// Like `new`, but parameterized over the choice of allocator for - /// the returned `RawVec`. - #[inline] - pub(crate) const fn new_in(alloc: A) -> Self { - Self { inner: RawVecInner::new_in(alloc, align_of::()), _marker: PhantomData } - } - - /// Like `with_capacity`, but parameterized over the choice of - /// allocator for the returned `RawVec`. - #[cfg(not(no_global_oom_handling))] - #[inline] - #[track_caller] - pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self { - Self { - inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), - _marker: PhantomData, - } - } - - /// Like `try_with_capacity`, but parameterized over the choice of - /// allocator for the returned `RawVec`. - #[inline] - pub(crate) fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { - match RawVecInner::try_with_capacity_in(capacity, alloc, T::LAYOUT) { - Ok(inner) => Ok(Self { inner, _marker: PhantomData }), - Err(e) => Err(e), - } - } - - /// Like `with_capacity_zeroed`, but parameterized over the choice - /// of allocator for the returned `RawVec`. - #[cfg(not(no_global_oom_handling))] - #[inline] - #[track_caller] - pub(crate) fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { - Self { - inner: RawVecInner::with_capacity_zeroed_in(capacity, alloc, T::LAYOUT), - _marker: PhantomData, - } - } - - /// Converts the entire buffer into `Box<[MaybeUninit]>` with the specified `len`. - /// - /// Note that this will correctly reconstitute any `cap` changes - /// that may have been performed. (See description of type for details.) - /// - /// # Safety - /// - /// * `len` must be greater than or equal to the most recently requested capacity, and - /// * `len` must be less than or equal to `self.capacity()`. - /// - /// Note, that the requested capacity and `self.capacity()` could differ, as - /// an allocator could overallocate and return a greater memory block than requested. - pub(crate) unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit], A> { - // Sanity-check one half of the safety requirement (we cannot check the other half). - debug_assert!( - len <= self.capacity(), - "`len` must be smaller than or equal to `self.capacity()`" - ); - - let me = ManuallyDrop::new(self); - unsafe { - let slice = ptr::slice_from_raw_parts_mut(me.ptr() as *mut MaybeUninit, len); - Box::from_raw_in(slice, ptr::read(&me.inner.alloc)) - } - } - - /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator. - /// - /// # Safety - /// - /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given - /// `capacity`. - /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit - /// systems). For ZSTs capacity is ignored. - /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is - /// guaranteed. - #[inline] - pub(crate) unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self { - // SAFETY: Precondition passed to the caller - unsafe { - let ptr = ptr.cast(); - let capacity = new_cap::(capacity); - Self { - inner: RawVecInner::from_raw_parts_in(ptr, capacity, alloc), - _marker: PhantomData, - } - } - } - - /// A convenience method for hoisting the non-null precondition out of [`RawVec::from_raw_parts_in`]. - /// - /// # Safety - /// - /// See [`RawVec::from_raw_parts_in`]. - #[inline] - pub(crate) unsafe fn from_nonnull_in(ptr: NonNull, capacity: usize, alloc: A) -> Self { - // SAFETY: Precondition passed to the caller - unsafe { - let ptr = ptr.cast(); - let capacity = new_cap::(capacity); - Self { inner: RawVecInner::from_nonnull_in(ptr, capacity, alloc), _marker: PhantomData } - } - } - - /// Gets a raw pointer to the start of the allocation. Note that this is - /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must - /// be careful. - #[inline] - pub(crate) const fn ptr(&self) -> *mut T { - self.inner.ptr() - } - - #[inline] - pub(crate) fn non_null(&self) -> NonNull { - self.inner.non_null() - } - - /// Gets the capacity of the allocation. - /// - /// This will always be `usize::MAX` if `T` is zero-sized. - #[inline] - pub(crate) const fn capacity(&self) -> usize { - self.inner.capacity(size_of::()) - } - - /// Returns a shared reference to the allocator backing this `RawVec`. - #[inline] - pub(crate) fn allocator(&self) -> &A { - self.inner.allocator() - } - - /// Ensures that the buffer contains at least enough space to hold `len + - /// additional` elements. If it doesn't already have enough capacity, will - /// reallocate enough space plus comfortable slack space to get amortized - /// *O*(1) behavior. Will limit this behavior if it would needlessly cause - /// itself to panic. - /// - /// If `len` exceeds `self.capacity()`, this may fail to actually allocate - /// the requested space. This is not really unsafe, but the unsafe - /// code *you* write that relies on the behavior of this function may break. - /// - /// This is ideal for implementing a bulk-push operation like `extend`. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds `isize::MAX` _bytes_. - /// - /// # Aborts - /// - /// Aborts on OOM. - #[cfg(not(no_global_oom_handling))] - #[inline] - #[track_caller] - pub(crate) fn reserve(&mut self, len: usize, additional: usize) { - self.inner.reserve(len, additional, T::LAYOUT) - } - - /// A specialized version of `self.reserve(len, 1)` which requires the - /// caller to ensure `len == self.capacity()`. - #[cfg(not(no_global_oom_handling))] - #[inline(never)] - #[track_caller] - pub(crate) fn grow_one(&mut self) { - self.inner.grow_one(T::LAYOUT) - } - - /// The same as `reserve`, but returns on errors instead of panicking or aborting. - pub(crate) fn try_reserve( - &mut self, - len: usize, - additional: usize, - ) -> Result<(), TryReserveError> { - self.inner.try_reserve(len, additional, T::LAYOUT) - } - - /// Ensures that the buffer contains at least enough space to hold `len + - /// additional` elements. If it doesn't already, will reallocate the - /// minimum possible amount of memory necessary. Generally this will be - /// exactly the amount of memory necessary, but in principle the allocator - /// is free to give back more than we asked for. - /// - /// If `len` exceeds `self.capacity()`, this may fail to actually allocate - /// the requested space. This is not really unsafe, but the unsafe code - /// *you* write that relies on the behavior of this function may break. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds `isize::MAX` _bytes_. - /// - /// # Aborts - /// - /// Aborts on OOM. - #[cfg(not(no_global_oom_handling))] - #[track_caller] - pub(crate) fn reserve_exact(&mut self, len: usize, additional: usize) { - self.inner.reserve_exact(len, additional, T::LAYOUT) - } - - /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. - pub(crate) fn try_reserve_exact( - &mut self, - len: usize, - additional: usize, - ) -> Result<(), TryReserveError> { - self.inner.try_reserve_exact(len, additional, T::LAYOUT) - } - - /// Shrinks the buffer down to the specified capacity. If the given amount - /// is 0, actually completely deallocates. - /// - /// # Panics - /// - /// Panics if the given amount is *larger* than the current capacity. - /// - /// # Aborts - /// - /// Aborts on OOM. - #[cfg(not(no_global_oom_handling))] - #[track_caller] - #[inline] - pub(crate) fn shrink_to_fit(&mut self, cap: usize) { - self.inner.shrink_to_fit(cap, T::LAYOUT) - } -} - -unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { - /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. - fn drop(&mut self) { - // SAFETY: We are in a Drop impl, self.inner will not be used again. - unsafe { self.inner.deallocate(T::LAYOUT) } - } -} - -impl RawVecInner { - #[inline] - const fn new_in(alloc: A, align: usize) -> Self { - let ptr = unsafe { core::mem::transmute(align) }; - // `cap: 0` means "unallocated". zero-sized types are ignored. - Self { ptr, cap: ZERO_CAP, alloc } - } - - #[cfg(not(no_global_oom_handling))] - #[inline] - #[track_caller] - fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { - match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { - Ok(this) => { - unsafe { - // Make it more obvious that a subsequent Vec::reserve(capacity) will not allocate. - hint::assert_unchecked(!this.needs_to_grow(0, capacity, elem_layout)); - } - this - } - Err(err) => handle_error(err), - } - } - - #[inline] - fn try_with_capacity_in( - capacity: usize, - alloc: A, - elem_layout: Layout, - ) -> Result { - Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) - } - - #[cfg(not(no_global_oom_handling))] - #[inline] - #[track_caller] - fn with_capacity_zeroed_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { - match Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc, elem_layout) { - Ok(res) => res, - Err(err) => handle_error(err), - } - } - - fn try_allocate_in( - capacity: usize, - init: AllocInit, - alloc: A, - elem_layout: Layout, - ) -> Result { - // We avoid `unwrap_or_else` here because it bloats the amount of - // LLVM IR generated. - let layout = match layout_array(capacity, elem_layout) { - Ok(layout) => layout, - Err(_) => return Err(CapacityOverflow.into()), - }; - - // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. - if layout.size() == 0 { - return Ok(Self::new_in(alloc, elem_layout.align())); - } - - if let Err(err) = alloc_guard(layout.size()) { - return Err(err); - } - - let result = match init { - AllocInit::Uninitialized => alloc.allocate(layout), - #[cfg(not(no_global_oom_handling))] - AllocInit::Zeroed => alloc.allocate_zeroed(layout), - }; - let ptr = match result { - Ok(ptr) => ptr, - Err(_) => return Err(AllocError { layout, non_exhaustive: () }.into()), - }; - - // Allocators currently return a `NonNull<[u8]>` whose length - // matches the size requested. If that ever changes, the capacity - // here should change to `ptr.len() / size_of::()`. - Ok(Self { - ptr: Unique::from(ptr.cast()), - cap: unsafe { Cap::new_unchecked(capacity) }, - alloc, - }) - } - - #[inline] - unsafe fn from_raw_parts_in(ptr: *mut u8, cap: Cap, alloc: A) -> Self { - Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap, alloc } - } - - #[inline] - unsafe fn from_nonnull_in(ptr: NonNull, cap: Cap, alloc: A) -> Self { - Self { ptr: Unique::from(ptr), cap, alloc } - } - - #[inline] - const fn ptr(&self) -> *mut T { - self.non_null::().as_ptr() - } - - #[inline] - const fn non_null(&self) -> NonNull { - self.ptr.cast().as_non_null_ptr() - } - - #[inline] - const fn capacity(&self, elem_size: usize) -> usize { - if elem_size == 0 { usize::MAX } else { self.cap.as_inner() } - } - - #[inline] - fn allocator(&self) -> &A { - &self.alloc - } - - #[inline] - fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull, Layout)> { - if elem_layout.size() == 0 || self.cap.as_inner() == 0 { - None - } else { - // We could use Layout::array here which ensures the absence of isize and usize overflows - // and could hypothetically handle differences between stride and size, but this memory - // has already been allocated so we know it can't overflow and currently Rust does not - // support such types. So we can do better by skipping some checks and avoid an unwrap. - unsafe { - let alloc_size = elem_layout.size().unchecked_mul(self.cap.as_inner()); - let layout = Layout::from_size_align_unchecked(alloc_size, elem_layout.align()); - Some((self.ptr.into(), layout)) - } - } - } - - #[cfg(not(no_global_oom_handling))] - #[inline] - #[track_caller] - fn reserve(&mut self, len: usize, additional: usize, elem_layout: Layout) { - // Callers expect this function to be very cheap when there is already sufficient capacity. - // Therefore, we move all the resizing and error-handling logic from grow_amortized and - // handle_reserve behind a call, while making sure that this function is likely to be - // inlined as just a comparison and a call if the comparison fails. - #[cold] - fn do_reserve_and_handle( - slf: &mut RawVecInner, - len: usize, - additional: usize, - elem_layout: Layout, - ) { - if let Err(err) = slf.grow_amortized(len, additional, elem_layout) { - handle_error(err); - } - } - - if self.needs_to_grow(len, additional, elem_layout) { - do_reserve_and_handle(self, len, additional, elem_layout); - } - } - - #[cfg(not(no_global_oom_handling))] - #[inline] - #[track_caller] - fn grow_one(&mut self, elem_layout: Layout) { - if let Err(err) = self.grow_amortized(self.cap.as_inner(), 1, elem_layout) { - handle_error(err); - } - } - - fn try_reserve( - &mut self, - len: usize, - additional: usize, - elem_layout: Layout, - ) -> Result<(), TryReserveError> { - if self.needs_to_grow(len, additional, elem_layout) { - self.grow_amortized(len, additional, elem_layout)?; - } - unsafe { - // Inform the optimizer that the reservation has succeeded or wasn't needed - hint::assert_unchecked(!self.needs_to_grow(len, additional, elem_layout)); - } - Ok(()) - } - - #[cfg(not(no_global_oom_handling))] - #[track_caller] - fn reserve_exact(&mut self, len: usize, additional: usize, elem_layout: Layout) { - if let Err(err) = self.try_reserve_exact(len, additional, elem_layout) { - handle_error(err); - } - } - - fn try_reserve_exact( - &mut self, - len: usize, - additional: usize, - elem_layout: Layout, - ) -> Result<(), TryReserveError> { - if self.needs_to_grow(len, additional, elem_layout) { - self.grow_exact(len, additional, elem_layout)?; - } - unsafe { - // Inform the optimizer that the reservation has succeeded or wasn't needed - hint::assert_unchecked(!self.needs_to_grow(len, additional, elem_layout)); - } - Ok(()) - } - - #[cfg(not(no_global_oom_handling))] - #[inline] - #[track_caller] - fn shrink_to_fit(&mut self, cap: usize, elem_layout: Layout) { - if let Err(err) = self.shrink(cap, elem_layout) { - handle_error(err); - } - } - - #[inline] - fn needs_to_grow(&self, len: usize, additional: usize, elem_layout: Layout) -> bool { - additional > self.capacity(elem_layout.size()).wrapping_sub(len) - } - - #[inline] - unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) { - // Allocators currently return a `NonNull<[u8]>` whose length matches - // the size requested. If that ever changes, the capacity here should - // change to `ptr.len() / size_of::()`. - self.ptr = Unique::from(ptr.cast()); - self.cap = unsafe { Cap::new_unchecked(cap) }; - } - - fn grow_amortized( - &mut self, - len: usize, - additional: usize, - elem_layout: Layout, - ) -> Result<(), TryReserveError> { - // This is ensured by the calling contexts. - debug_assert!(additional > 0); - - if elem_layout.size() == 0 { - // Since we return a capacity of `usize::MAX` when `elem_size` is - // 0, getting to here necessarily means the `RawVec` is overfull. - return Err(CapacityOverflow.into()); - } - - // Nothing we can really do about these checks, sadly. - let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?; - - // This guarantees exponential growth. The doubling cannot overflow - // because `cap <= isize::MAX` and the type of `cap` is `usize`. - let cap = cmp::max(self.cap.as_inner() * 2, required_cap); - let cap = cmp::max(min_non_zero_cap(elem_layout.size()), cap); - - let new_layout = layout_array(cap, elem_layout)?; - - let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?; - // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items - - unsafe { self.set_ptr_and_cap(ptr, cap) }; - Ok(()) - } - - fn grow_exact( - &mut self, - len: usize, - additional: usize, - elem_layout: Layout, - ) -> Result<(), TryReserveError> { - if elem_layout.size() == 0 { - // Since we return a capacity of `usize::MAX` when the type size is - // 0, getting to here necessarily means the `RawVec` is overfull. - return Err(CapacityOverflow.into()); - } - - let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; - let new_layout = layout_array(cap, elem_layout)?; - - let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?; - // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items - unsafe { - self.set_ptr_and_cap(ptr, cap); - } - Ok(()) - } - - #[cfg(not(no_global_oom_handling))] - #[inline] - fn shrink(&mut self, cap: usize, elem_layout: Layout) -> Result<(), TryReserveError> { - assert!(cap <= self.capacity(elem_layout.size()), "Tried to shrink to a larger capacity"); - // SAFETY: Just checked this isn't trying to grow - unsafe { self.shrink_unchecked(cap, elem_layout) } - } - - /// `shrink`, but without the capacity check. - /// - /// This is split out so that `shrink` can inline the check, since it - /// optimizes out in things like `shrink_to_fit`, without needing to - /// also inline all this code, as doing that ends up failing the - /// `vec-shrink-panic` codegen test when `shrink_to_fit` ends up being too - /// big for LLVM to be willing to inline. - /// - /// # Safety - /// `cap <= self.capacity()` - #[cfg(not(no_global_oom_handling))] - unsafe fn shrink_unchecked( - &mut self, - cap: usize, - elem_layout: Layout, - ) -> Result<(), TryReserveError> { - let (ptr, layout) = - if let Some(mem) = self.current_memory(elem_layout) { mem } else { return Ok(()) }; - - // If shrinking to 0, deallocate the buffer. We don't reach this point - // for the T::IS_ZST case since current_memory() will have returned - // None. - if cap == 0 { - unsafe { self.alloc.deallocate(ptr, layout) }; - self.ptr = - unsafe { Unique::new_unchecked(ptr::without_provenance_mut(elem_layout.align())) }; - self.cap = ZERO_CAP; - } else { - let ptr = unsafe { - // Layout cannot overflow here because it would have - // overflowed earlier when capacity was larger. - let new_size = elem_layout.size().unchecked_mul(cap); - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc - .shrink(ptr, layout, new_layout) - .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? - }; - // SAFETY: if the allocation is valid, then the capacity is too - unsafe { - self.set_ptr_and_cap(ptr, cap); - } - } - Ok(()) - } - - /// # Safety - /// - /// This function deallocates the owned allocation, but does not update `ptr` or `cap` to - /// prevent double-free or use-after-free. Essentially, do not do anything with the caller - /// after this function returns. - /// Ideally this function would take `self` by move, but it cannot because it exists to be - /// called from a `Drop` impl. - unsafe fn deallocate(&mut self, elem_layout: Layout) { - if let Some((ptr, layout)) = self.current_memory(elem_layout) { - unsafe { - self.alloc.deallocate(ptr, layout); - } - } - } -} - -// not marked inline(never) since we want optimizers to be able to observe the specifics of this -// function, see tests/codegen/vec-reserve-extend.rs. -#[cold] -fn finish_grow( - new_layout: Layout, - current_memory: Option<(NonNull, Layout)>, - alloc: &mut A, -) -> Result, TryReserveError> -where - A: Allocator, -{ - alloc_guard(new_layout.size())?; - - let memory = if let Some((ptr, old_layout)) = current_memory { - debug_assert_eq!(old_layout.align(), new_layout.align()); - unsafe { - // The allocator checks for alignment equality - hint::assert_unchecked(old_layout.align() == new_layout.align()); - alloc.grow(ptr, old_layout, new_layout) - } - } else { - alloc.allocate(new_layout) - }; - - memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into()) -} - -// Central function for reserve error handling. -#[cfg(not(no_global_oom_handling))] -#[cold] -#[optimize(size)] -#[track_caller] -fn handle_error(e: TryReserveError) -> ! { - match e.kind() { - CapacityOverflow => capacity_overflow(), - AllocError { layout, .. } => handle_alloc_error(layout), - } -} - -// We need to guarantee the following: -// * We don't ever allocate `> isize::MAX` byte-size objects. -// * We don't overflow `usize::MAX` and actually allocate too little. -// -// On 64-bit we just need to check for overflow since trying to allocate -// `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add -// an extra guard for this in case we're running on a platform which can use -// all 4GB in user-space, e.g., PAE or x32. -#[inline] -fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { - if usize::BITS < 64 && alloc_size > isize::MAX as usize { - Err(CapacityOverflow.into()) - } else { - Ok(()) - } -} - -#[inline] -fn layout_array(cap: usize, elem_layout: Layout) -> Result { - elem_layout.repeat(cap).map(|(layout, _pad)| layout).map_err(|_| CapacityOverflow.into()) -} diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs new file mode 100644 index 00000000000..70f32fbaab4 --- /dev/null +++ b/library/alloc/src/raw_vec/mod.rs @@ -0,0 +1,818 @@ +#![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")] + +use core::marker::PhantomData; +use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; +use core::ptr::{self, NonNull, Unique}; +use core::{cmp, hint}; + +#[cfg(not(no_global_oom_handling))] +use crate::alloc::handle_alloc_error; +use crate::alloc::{Allocator, Global, Layout}; +use crate::boxed::Box; +use crate::collections::TryReserveError; +use crate::collections::TryReserveErrorKind::*; + +#[cfg(test)] +mod tests; + +// One central function responsible for reporting capacity overflows. This'll +// ensure that the code generation related to these panics is minimal as there's +// only one location which panics rather than a bunch throughout the module. +#[cfg(not(no_global_oom_handling))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[track_caller] +fn capacity_overflow() -> ! { + panic!("capacity overflow"); +} + +enum AllocInit { + /// The contents of the new memory are uninitialized. + Uninitialized, + #[cfg(not(no_global_oom_handling))] + /// The new memory is guaranteed to be zeroed. + Zeroed, +} + +type Cap = core::num::niche_types::UsizeNoHighBit; + +const ZERO_CAP: Cap = unsafe { Cap::new_unchecked(0) }; + +/// `Cap(cap)`, except if `T` is a ZST then `Cap::ZERO`. +/// +/// # Safety: cap must be <= `isize::MAX`. +unsafe fn new_cap(cap: usize) -> Cap { + if T::IS_ZST { ZERO_CAP } else { unsafe { Cap::new_unchecked(cap) } } +} + +/// A low-level utility for more ergonomically allocating, reallocating, and deallocating +/// a buffer of memory on the heap without having to worry about all the corner cases +/// involved. This type is excellent for building your own data structures like Vec and VecDeque. +/// In particular: +/// +/// * Produces `Unique::dangling()` on zero-sized types. +/// * Produces `Unique::dangling()` on zero-length allocations. +/// * Avoids freeing `Unique::dangling()`. +/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics). +/// * Guards against 32-bit systems allocating more than `isize::MAX` bytes. +/// * Guards against overflowing your length. +/// * Calls `handle_alloc_error` for fallible allocations. +/// * Contains a `ptr::Unique` and thus endows the user with all related benefits. +/// * Uses the excess returned from the allocator to use the largest available capacity. +/// +/// This type does not in anyway inspect the memory that it manages. When dropped it *will* +/// free its memory, but it *won't* try to drop its contents. It is up to the user of `RawVec` +/// to handle the actual things *stored* inside of a `RawVec`. +/// +/// Note that the excess of a zero-sized types is always infinite, so `capacity()` always returns +/// `usize::MAX`. This means that you need to be careful when round-tripping this type with a +/// `Box<[T]>`, since `capacity()` won't yield the length. +#[allow(missing_debug_implementations)] +pub(crate) struct RawVec { + inner: RawVecInner, + _marker: PhantomData, +} + +/// Like a `RawVec`, but only generic over the allocator, not the type. +/// +/// As such, all the methods need the layout passed-in as a parameter. +/// +/// Having this separation reduces the amount of code we need to monomorphize, +/// as most operations don't need the actual type, just its layout. +#[allow(missing_debug_implementations)] +struct RawVecInner { + ptr: Unique, + /// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case. + /// + /// # Safety + /// + /// `cap` must be in the `0..=isize::MAX` range. + cap: Cap, + alloc: A, +} + +impl RawVec { + /// Creates the biggest possible `RawVec` (on the system heap) + /// without allocating. If `T` has positive size, then this makes a + /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a + /// `RawVec` with capacity `usize::MAX`. Useful for implementing + /// delayed allocation. + #[must_use] + pub(crate) const fn new() -> Self { + Self::new_in(Global) + } + + /// Creates a `RawVec` (on the system heap) with exactly the + /// capacity and alignment requirements for a `[T; capacity]`. This is + /// equivalent to calling `RawVec::new` when `capacity` is `0` or `T` is + /// zero-sized. Note that if `T` is zero-sized this means you will + /// *not* get a `RawVec` with the requested capacity. + /// + /// Non-fallible version of `try_with_capacity` + /// + /// # Panics + /// + /// Panics if the requested capacity exceeds `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM. + #[cfg(not(any(no_global_oom_handling, test)))] + #[must_use] + #[inline] + #[track_caller] + pub(crate) fn with_capacity(capacity: usize) -> Self { + Self { inner: RawVecInner::with_capacity(capacity, T::LAYOUT), _marker: PhantomData } + } + + /// Like `with_capacity`, but guarantees the buffer is zeroed. + #[cfg(not(any(no_global_oom_handling, test)))] + #[must_use] + #[inline] + #[track_caller] + pub(crate) fn with_capacity_zeroed(capacity: usize) -> Self { + Self { + inner: RawVecInner::with_capacity_zeroed_in(capacity, Global, T::LAYOUT), + _marker: PhantomData, + } + } +} + +impl RawVecInner { + #[cfg(not(any(no_global_oom_handling, test)))] + #[must_use] + #[inline] + #[track_caller] + fn with_capacity(capacity: usize, elem_layout: Layout) -> Self { + match Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global, elem_layout) { + Ok(res) => res, + Err(err) => handle_error(err), + } + } +} + +// Tiny Vecs are dumb. Skip to: +// - 8 if the element size is 1, because any heap allocators is likely +// to round up a request of less than 8 bytes to at least 8 bytes. +// - 4 if elements are moderate-sized (<= 1 KiB). +// - 1 otherwise, to avoid wasting too much space for very short Vecs. +const fn min_non_zero_cap(size: usize) -> usize { + if size == 1 { + 8 + } else if size <= 1024 { + 4 + } else { + 1 + } +} + +impl RawVec { + #[cfg(not(no_global_oom_handling))] + pub(crate) const MIN_NON_ZERO_CAP: usize = min_non_zero_cap(size_of::()); + + /// Like `new`, but parameterized over the choice of allocator for + /// the returned `RawVec`. + #[inline] + pub(crate) const fn new_in(alloc: A) -> Self { + Self { inner: RawVecInner::new_in(alloc, align_of::()), _marker: PhantomData } + } + + /// Like `with_capacity`, but parameterized over the choice of + /// allocator for the returned `RawVec`. + #[cfg(not(no_global_oom_handling))] + #[inline] + #[track_caller] + pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), + _marker: PhantomData, + } + } + + /// Like `try_with_capacity`, but parameterized over the choice of + /// allocator for the returned `RawVec`. + #[inline] + pub(crate) fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + match RawVecInner::try_with_capacity_in(capacity, alloc, T::LAYOUT) { + Ok(inner) => Ok(Self { inner, _marker: PhantomData }), + Err(e) => Err(e), + } + } + + /// Like `with_capacity_zeroed`, but parameterized over the choice + /// of allocator for the returned `RawVec`. + #[cfg(not(no_global_oom_handling))] + #[inline] + #[track_caller] + pub(crate) fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { + Self { + inner: RawVecInner::with_capacity_zeroed_in(capacity, alloc, T::LAYOUT), + _marker: PhantomData, + } + } + + /// Converts the entire buffer into `Box<[MaybeUninit]>` with the specified `len`. + /// + /// Note that this will correctly reconstitute any `cap` changes + /// that may have been performed. (See description of type for details.) + /// + /// # Safety + /// + /// * `len` must be greater than or equal to the most recently requested capacity, and + /// * `len` must be less than or equal to `self.capacity()`. + /// + /// Note, that the requested capacity and `self.capacity()` could differ, as + /// an allocator could overallocate and return a greater memory block than requested. + pub(crate) unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit], A> { + // Sanity-check one half of the safety requirement (we cannot check the other half). + debug_assert!( + len <= self.capacity(), + "`len` must be smaller than or equal to `self.capacity()`" + ); + + let me = ManuallyDrop::new(self); + unsafe { + let slice = ptr::slice_from_raw_parts_mut(me.ptr() as *mut MaybeUninit, len); + Box::from_raw_in(slice, ptr::read(&me.inner.alloc)) + } + } + + /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator. + /// + /// # Safety + /// + /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given + /// `capacity`. + /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit + /// systems). For ZSTs capacity is ignored. + /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is + /// guaranteed. + #[inline] + pub(crate) unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self { + // SAFETY: Precondition passed to the caller + unsafe { + let ptr = ptr.cast(); + let capacity = new_cap::(capacity); + Self { + inner: RawVecInner::from_raw_parts_in(ptr, capacity, alloc), + _marker: PhantomData, + } + } + } + + /// A convenience method for hoisting the non-null precondition out of [`RawVec::from_raw_parts_in`]. + /// + /// # Safety + /// + /// See [`RawVec::from_raw_parts_in`]. + #[inline] + pub(crate) unsafe fn from_nonnull_in(ptr: NonNull, capacity: usize, alloc: A) -> Self { + // SAFETY: Precondition passed to the caller + unsafe { + let ptr = ptr.cast(); + let capacity = new_cap::(capacity); + Self { inner: RawVecInner::from_nonnull_in(ptr, capacity, alloc), _marker: PhantomData } + } + } + + /// Gets a raw pointer to the start of the allocation. Note that this is + /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must + /// be careful. + #[inline] + pub(crate) const fn ptr(&self) -> *mut T { + self.inner.ptr() + } + + #[inline] + pub(crate) fn non_null(&self) -> NonNull { + self.inner.non_null() + } + + /// Gets the capacity of the allocation. + /// + /// This will always be `usize::MAX` if `T` is zero-sized. + #[inline] + pub(crate) const fn capacity(&self) -> usize { + self.inner.capacity(size_of::()) + } + + /// Returns a shared reference to the allocator backing this `RawVec`. + #[inline] + pub(crate) fn allocator(&self) -> &A { + self.inner.allocator() + } + + /// Ensures that the buffer contains at least enough space to hold `len + + /// additional` elements. If it doesn't already have enough capacity, will + /// reallocate enough space plus comfortable slack space to get amortized + /// *O*(1) behavior. Will limit this behavior if it would needlessly cause + /// itself to panic. + /// + /// If `len` exceeds `self.capacity()`, this may fail to actually allocate + /// the requested space. This is not really unsafe, but the unsafe + /// code *you* write that relies on the behavior of this function may break. + /// + /// This is ideal for implementing a bulk-push operation like `extend`. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// + /// # Aborts + /// + /// Aborts on OOM. + #[cfg(not(no_global_oom_handling))] + #[inline] + #[track_caller] + pub(crate) fn reserve(&mut self, len: usize, additional: usize) { + self.inner.reserve(len, additional, T::LAYOUT) + } + + /// A specialized version of `self.reserve(len, 1)` which requires the + /// caller to ensure `len == self.capacity()`. + #[cfg(not(no_global_oom_handling))] + #[inline(never)] + #[track_caller] + pub(crate) fn grow_one(&mut self) { + self.inner.grow_one(T::LAYOUT) + } + + /// The same as `reserve`, but returns on errors instead of panicking or aborting. + pub(crate) fn try_reserve( + &mut self, + len: usize, + additional: usize, + ) -> Result<(), TryReserveError> { + self.inner.try_reserve(len, additional, T::LAYOUT) + } + + /// Ensures that the buffer contains at least enough space to hold `len + + /// additional` elements. If it doesn't already, will reallocate the + /// minimum possible amount of memory necessary. Generally this will be + /// exactly the amount of memory necessary, but in principle the allocator + /// is free to give back more than we asked for. + /// + /// If `len` exceeds `self.capacity()`, this may fail to actually allocate + /// the requested space. This is not really unsafe, but the unsafe code + /// *you* write that relies on the behavior of this function may break. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// + /// # Aborts + /// + /// Aborts on OOM. + #[cfg(not(no_global_oom_handling))] + #[track_caller] + pub(crate) fn reserve_exact(&mut self, len: usize, additional: usize) { + self.inner.reserve_exact(len, additional, T::LAYOUT) + } + + /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. + pub(crate) fn try_reserve_exact( + &mut self, + len: usize, + additional: usize, + ) -> Result<(), TryReserveError> { + self.inner.try_reserve_exact(len, additional, T::LAYOUT) + } + + /// Shrinks the buffer down to the specified capacity. If the given amount + /// is 0, actually completely deallocates. + /// + /// # Panics + /// + /// Panics if the given amount is *larger* than the current capacity. + /// + /// # Aborts + /// + /// Aborts on OOM. + #[cfg(not(no_global_oom_handling))] + #[track_caller] + #[inline] + pub(crate) fn shrink_to_fit(&mut self, cap: usize) { + self.inner.shrink_to_fit(cap, T::LAYOUT) + } +} + +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { + /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. + fn drop(&mut self) { + // SAFETY: We are in a Drop impl, self.inner will not be used again. + unsafe { self.inner.deallocate(T::LAYOUT) } + } +} + +impl RawVecInner { + #[inline] + const fn new_in(alloc: A, align: usize) -> Self { + let ptr = unsafe { core::mem::transmute(align) }; + // `cap: 0` means "unallocated". zero-sized types are ignored. + Self { ptr, cap: ZERO_CAP, alloc } + } + + #[cfg(not(no_global_oom_handling))] + #[inline] + #[track_caller] + fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { + match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { + Ok(this) => { + unsafe { + // Make it more obvious that a subsequent Vec::reserve(capacity) will not allocate. + hint::assert_unchecked(!this.needs_to_grow(0, capacity, elem_layout)); + } + this + } + Err(err) => handle_error(err), + } + } + + #[inline] + fn try_with_capacity_in( + capacity: usize, + alloc: A, + elem_layout: Layout, + ) -> Result { + Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) + } + + #[cfg(not(no_global_oom_handling))] + #[inline] + #[track_caller] + fn with_capacity_zeroed_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { + match Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc, elem_layout) { + Ok(res) => res, + Err(err) => handle_error(err), + } + } + + fn try_allocate_in( + capacity: usize, + init: AllocInit, + alloc: A, + elem_layout: Layout, + ) -> Result { + // We avoid `unwrap_or_else` here because it bloats the amount of + // LLVM IR generated. + let layout = match layout_array(capacity, elem_layout) { + Ok(layout) => layout, + Err(_) => return Err(CapacityOverflow.into()), + }; + + // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. + if layout.size() == 0 { + return Ok(Self::new_in(alloc, elem_layout.align())); + } + + if let Err(err) = alloc_guard(layout.size()) { + return Err(err); + } + + let result = match init { + AllocInit::Uninitialized => alloc.allocate(layout), + #[cfg(not(no_global_oom_handling))] + AllocInit::Zeroed => alloc.allocate_zeroed(layout), + }; + let ptr = match result { + Ok(ptr) => ptr, + Err(_) => return Err(AllocError { layout, non_exhaustive: () }.into()), + }; + + // Allocators currently return a `NonNull<[u8]>` whose length + // matches the size requested. If that ever changes, the capacity + // here should change to `ptr.len() / size_of::()`. + Ok(Self { + ptr: Unique::from(ptr.cast()), + cap: unsafe { Cap::new_unchecked(capacity) }, + alloc, + }) + } + + #[inline] + unsafe fn from_raw_parts_in(ptr: *mut u8, cap: Cap, alloc: A) -> Self { + Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap, alloc } + } + + #[inline] + unsafe fn from_nonnull_in(ptr: NonNull, cap: Cap, alloc: A) -> Self { + Self { ptr: Unique::from(ptr), cap, alloc } + } + + #[inline] + const fn ptr(&self) -> *mut T { + self.non_null::().as_ptr() + } + + #[inline] + const fn non_null(&self) -> NonNull { + self.ptr.cast().as_non_null_ptr() + } + + #[inline] + const fn capacity(&self, elem_size: usize) -> usize { + if elem_size == 0 { usize::MAX } else { self.cap.as_inner() } + } + + #[inline] + fn allocator(&self) -> &A { + &self.alloc + } + + #[inline] + fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull, Layout)> { + if elem_layout.size() == 0 || self.cap.as_inner() == 0 { + None + } else { + // We could use Layout::array here which ensures the absence of isize and usize overflows + // and could hypothetically handle differences between stride and size, but this memory + // has already been allocated so we know it can't overflow and currently Rust does not + // support such types. So we can do better by skipping some checks and avoid an unwrap. + unsafe { + let alloc_size = elem_layout.size().unchecked_mul(self.cap.as_inner()); + let layout = Layout::from_size_align_unchecked(alloc_size, elem_layout.align()); + Some((self.ptr.into(), layout)) + } + } + } + + #[cfg(not(no_global_oom_handling))] + #[inline] + #[track_caller] + fn reserve(&mut self, len: usize, additional: usize, elem_layout: Layout) { + // Callers expect this function to be very cheap when there is already sufficient capacity. + // Therefore, we move all the resizing and error-handling logic from grow_amortized and + // handle_reserve behind a call, while making sure that this function is likely to be + // inlined as just a comparison and a call if the comparison fails. + #[cold] + fn do_reserve_and_handle( + slf: &mut RawVecInner, + len: usize, + additional: usize, + elem_layout: Layout, + ) { + if let Err(err) = slf.grow_amortized(len, additional, elem_layout) { + handle_error(err); + } + } + + if self.needs_to_grow(len, additional, elem_layout) { + do_reserve_and_handle(self, len, additional, elem_layout); + } + } + + #[cfg(not(no_global_oom_handling))] + #[inline] + #[track_caller] + fn grow_one(&mut self, elem_layout: Layout) { + if let Err(err) = self.grow_amortized(self.cap.as_inner(), 1, elem_layout) { + handle_error(err); + } + } + + fn try_reserve( + &mut self, + len: usize, + additional: usize, + elem_layout: Layout, + ) -> Result<(), TryReserveError> { + if self.needs_to_grow(len, additional, elem_layout) { + self.grow_amortized(len, additional, elem_layout)?; + } + unsafe { + // Inform the optimizer that the reservation has succeeded or wasn't needed + hint::assert_unchecked(!self.needs_to_grow(len, additional, elem_layout)); + } + Ok(()) + } + + #[cfg(not(no_global_oom_handling))] + #[track_caller] + fn reserve_exact(&mut self, len: usize, additional: usize, elem_layout: Layout) { + if let Err(err) = self.try_reserve_exact(len, additional, elem_layout) { + handle_error(err); + } + } + + fn try_reserve_exact( + &mut self, + len: usize, + additional: usize, + elem_layout: Layout, + ) -> Result<(), TryReserveError> { + if self.needs_to_grow(len, additional, elem_layout) { + self.grow_exact(len, additional, elem_layout)?; + } + unsafe { + // Inform the optimizer that the reservation has succeeded or wasn't needed + hint::assert_unchecked(!self.needs_to_grow(len, additional, elem_layout)); + } + Ok(()) + } + + #[cfg(not(no_global_oom_handling))] + #[inline] + #[track_caller] + fn shrink_to_fit(&mut self, cap: usize, elem_layout: Layout) { + if let Err(err) = self.shrink(cap, elem_layout) { + handle_error(err); + } + } + + #[inline] + fn needs_to_grow(&self, len: usize, additional: usize, elem_layout: Layout) -> bool { + additional > self.capacity(elem_layout.size()).wrapping_sub(len) + } + + #[inline] + unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) { + // Allocators currently return a `NonNull<[u8]>` whose length matches + // the size requested. If that ever changes, the capacity here should + // change to `ptr.len() / size_of::()`. + self.ptr = Unique::from(ptr.cast()); + self.cap = unsafe { Cap::new_unchecked(cap) }; + } + + fn grow_amortized( + &mut self, + len: usize, + additional: usize, + elem_layout: Layout, + ) -> Result<(), TryReserveError> { + // This is ensured by the calling contexts. + debug_assert!(additional > 0); + + if elem_layout.size() == 0 { + // Since we return a capacity of `usize::MAX` when `elem_size` is + // 0, getting to here necessarily means the `RawVec` is overfull. + return Err(CapacityOverflow.into()); + } + + // Nothing we can really do about these checks, sadly. + let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?; + + // This guarantees exponential growth. The doubling cannot overflow + // because `cap <= isize::MAX` and the type of `cap` is `usize`. + let cap = cmp::max(self.cap.as_inner() * 2, required_cap); + let cap = cmp::max(min_non_zero_cap(elem_layout.size()), cap); + + let new_layout = layout_array(cap, elem_layout)?; + + let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?; + // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items + + unsafe { self.set_ptr_and_cap(ptr, cap) }; + Ok(()) + } + + fn grow_exact( + &mut self, + len: usize, + additional: usize, + elem_layout: Layout, + ) -> Result<(), TryReserveError> { + if elem_layout.size() == 0 { + // Since we return a capacity of `usize::MAX` when the type size is + // 0, getting to here necessarily means the `RawVec` is overfull. + return Err(CapacityOverflow.into()); + } + + let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; + let new_layout = layout_array(cap, elem_layout)?; + + let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?; + // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items + unsafe { + self.set_ptr_and_cap(ptr, cap); + } + Ok(()) + } + + #[cfg(not(no_global_oom_handling))] + #[inline] + fn shrink(&mut self, cap: usize, elem_layout: Layout) -> Result<(), TryReserveError> { + assert!(cap <= self.capacity(elem_layout.size()), "Tried to shrink to a larger capacity"); + // SAFETY: Just checked this isn't trying to grow + unsafe { self.shrink_unchecked(cap, elem_layout) } + } + + /// `shrink`, but without the capacity check. + /// + /// This is split out so that `shrink` can inline the check, since it + /// optimizes out in things like `shrink_to_fit`, without needing to + /// also inline all this code, as doing that ends up failing the + /// `vec-shrink-panic` codegen test when `shrink_to_fit` ends up being too + /// big for LLVM to be willing to inline. + /// + /// # Safety + /// `cap <= self.capacity()` + #[cfg(not(no_global_oom_handling))] + unsafe fn shrink_unchecked( + &mut self, + cap: usize, + elem_layout: Layout, + ) -> Result<(), TryReserveError> { + let (ptr, layout) = + if let Some(mem) = self.current_memory(elem_layout) { mem } else { return Ok(()) }; + + // If shrinking to 0, deallocate the buffer. We don't reach this point + // for the T::IS_ZST case since current_memory() will have returned + // None. + if cap == 0 { + unsafe { self.alloc.deallocate(ptr, layout) }; + self.ptr = + unsafe { Unique::new_unchecked(ptr::without_provenance_mut(elem_layout.align())) }; + self.cap = ZERO_CAP; + } else { + let ptr = unsafe { + // Layout cannot overflow here because it would have + // overflowed earlier when capacity was larger. + let new_size = elem_layout.size().unchecked_mul(cap); + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + self.alloc + .shrink(ptr, layout, new_layout) + .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? + }; + // SAFETY: if the allocation is valid, then the capacity is too + unsafe { + self.set_ptr_and_cap(ptr, cap); + } + } + Ok(()) + } + + /// # Safety + /// + /// This function deallocates the owned allocation, but does not update `ptr` or `cap` to + /// prevent double-free or use-after-free. Essentially, do not do anything with the caller + /// after this function returns. + /// Ideally this function would take `self` by move, but it cannot because it exists to be + /// called from a `Drop` impl. + unsafe fn deallocate(&mut self, elem_layout: Layout) { + if let Some((ptr, layout)) = self.current_memory(elem_layout) { + unsafe { + self.alloc.deallocate(ptr, layout); + } + } + } +} + +// not marked inline(never) since we want optimizers to be able to observe the specifics of this +// function, see tests/codegen/vec-reserve-extend.rs. +#[cold] +fn finish_grow( + new_layout: Layout, + current_memory: Option<(NonNull, Layout)>, + alloc: &mut A, +) -> Result, TryReserveError> +where + A: Allocator, +{ + alloc_guard(new_layout.size())?; + + let memory = if let Some((ptr, old_layout)) = current_memory { + debug_assert_eq!(old_layout.align(), new_layout.align()); + unsafe { + // The allocator checks for alignment equality + hint::assert_unchecked(old_layout.align() == new_layout.align()); + alloc.grow(ptr, old_layout, new_layout) + } + } else { + alloc.allocate(new_layout) + }; + + memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into()) +} + +// Central function for reserve error handling. +#[cfg(not(no_global_oom_handling))] +#[cold] +#[optimize(size)] +#[track_caller] +fn handle_error(e: TryReserveError) -> ! { + match e.kind() { + CapacityOverflow => capacity_overflow(), + AllocError { layout, .. } => handle_alloc_error(layout), + } +} + +// We need to guarantee the following: +// * We don't ever allocate `> isize::MAX` byte-size objects. +// * We don't overflow `usize::MAX` and actually allocate too little. +// +// On 64-bit we just need to check for overflow since trying to allocate +// `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add +// an extra guard for this in case we're running on a platform which can use +// all 4GB in user-space, e.g., PAE or x32. +#[inline] +fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { + if usize::BITS < 64 && alloc_size > isize::MAX as usize { + Err(CapacityOverflow.into()) + } else { + Ok(()) + } +} + +#[inline] +fn layout_array(cap: usize, elem_layout: Layout) -> Result { + elem_layout.repeat(cap).map(|(layout, _pad)| layout).map_err(|_| CapacityOverflow.into()) +} diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs deleted file mode 100644 index 09206c2f8b2..00000000000 --- a/library/alloc/src/rc.rs +++ /dev/null @@ -1,4148 +0,0 @@ -//! Single-threaded reference-counting pointers. 'Rc' stands for 'Reference -//! Counted'. -//! -//! The type [`Rc`][`Rc`] provides shared ownership of a value of type `T`, -//! allocated in the heap. Invoking [`clone`][clone] on [`Rc`] produces a new -//! pointer to the same allocation in the heap. When the last [`Rc`] pointer to a -//! given allocation is destroyed, the value stored in that allocation (often -//! referred to as "inner value") is also dropped. -//! -//! Shared references in Rust disallow mutation by default, and [`Rc`] -//! is no exception: you cannot generally obtain a mutable reference to -//! something inside an [`Rc`]. If you need mutability, put a [`Cell`] -//! or [`RefCell`] inside the [`Rc`]; see [an example of mutability -//! inside an `Rc`][mutability]. -//! -//! [`Rc`] uses non-atomic reference counting. This means that overhead is very -//! low, but an [`Rc`] cannot be sent between threads, and consequently [`Rc`] -//! does not implement [`Send`]. As a result, the Rust compiler -//! will check *at compile time* that you are not sending [`Rc`]s between -//! threads. If you need multi-threaded, atomic reference counting, use -//! [`sync::Arc`][arc]. -//! -//! The [`downgrade`][downgrade] method can be used to create a non-owning -//! [`Weak`] pointer. A [`Weak`] pointer can be [`upgrade`][upgrade]d -//! to an [`Rc`], but this will return [`None`] if the value stored in the allocation has -//! already been dropped. In other words, `Weak` pointers do not keep the value -//! inside the allocation alive; however, they *do* keep the allocation -//! (the backing store for the inner value) alive. -//! -//! A cycle between [`Rc`] pointers will never be deallocated. For this reason, -//! [`Weak`] is used to break cycles. For example, a tree could have strong -//! [`Rc`] pointers from parent nodes to children, and [`Weak`] pointers from -//! children back to their parents. -//! -//! `Rc` automatically dereferences to `T` (via the [`Deref`] trait), -//! so you can call `T`'s methods on a value of type [`Rc`][`Rc`]. To avoid name -//! clashes with `T`'s methods, the methods of [`Rc`][`Rc`] itself are associated -//! functions, called using [fully qualified syntax]: -//! -//! ``` -//! use std::rc::Rc; -//! -//! let my_rc = Rc::new(()); -//! let my_weak = Rc::downgrade(&my_rc); -//! ``` -//! -//! `Rc`'s implementations of traits like `Clone` may also be called using -//! fully qualified syntax. Some people prefer to use fully qualified syntax, -//! while others prefer using method-call syntax. -//! -//! ``` -//! use std::rc::Rc; -//! -//! let rc = Rc::new(()); -//! // Method-call syntax -//! let rc2 = rc.clone(); -//! // Fully qualified syntax -//! let rc3 = Rc::clone(&rc); -//! ``` -//! -//! [`Weak`][`Weak`] does not auto-dereference to `T`, because the inner value may have -//! already been dropped. -//! -//! # Cloning references -//! -//! Creating a new reference to the same allocation as an existing reference counted pointer -//! is done using the `Clone` trait implemented for [`Rc`][`Rc`] and [`Weak`][`Weak`]. -//! -//! ``` -//! use std::rc::Rc; -//! -//! let foo = Rc::new(vec![1.0, 2.0, 3.0]); -//! // The two syntaxes below are equivalent. -//! let a = foo.clone(); -//! let b = Rc::clone(&foo); -//! // a and b both point to the same memory location as foo. -//! ``` -//! -//! The `Rc::clone(&from)` syntax is the most idiomatic because it conveys more explicitly -//! the meaning of the code. In the example above, this syntax makes it easier to see that -//! this code is creating a new reference rather than copying the whole content of foo. -//! -//! # Examples -//! -//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. -//! We want to have our `Gadget`s point to their `Owner`. We can't do this with -//! unique ownership, because more than one gadget may belong to the same -//! `Owner`. [`Rc`] allows us to share an `Owner` between multiple `Gadget`s, -//! and have the `Owner` remain allocated as long as any `Gadget` points at it. -//! -//! ``` -//! use std::rc::Rc; -//! -//! struct Owner { -//! name: String, -//! // ...other fields -//! } -//! -//! struct Gadget { -//! id: i32, -//! owner: Rc, -//! // ...other fields -//! } -//! -//! fn main() { -//! // Create a reference-counted `Owner`. -//! let gadget_owner: Rc = Rc::new( -//! Owner { -//! name: "Gadget Man".to_string(), -//! } -//! ); -//! -//! // Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc` -//! // gives us a new pointer to the same `Owner` allocation, incrementing -//! // the reference count in the process. -//! let gadget1 = Gadget { -//! id: 1, -//! owner: Rc::clone(&gadget_owner), -//! }; -//! let gadget2 = Gadget { -//! id: 2, -//! owner: Rc::clone(&gadget_owner), -//! }; -//! -//! // Dispose of our local variable `gadget_owner`. -//! drop(gadget_owner); -//! -//! // Despite dropping `gadget_owner`, we're still able to print out the name -//! // of the `Owner` of the `Gadget`s. This is because we've only dropped a -//! // single `Rc`, not the `Owner` it points to. As long as there are -//! // other `Rc` pointing at the same `Owner` allocation, it will remain -//! // live. The field projection `gadget1.owner.name` works because -//! // `Rc` automatically dereferences to `Owner`. -//! println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name); -//! println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name); -//! -//! // At the end of the function, `gadget1` and `gadget2` are destroyed, and -//! // with them the last counted references to our `Owner`. Gadget Man now -//! // gets destroyed as well. -//! } -//! ``` -//! -//! If our requirements change, and we also need to be able to traverse from -//! `Owner` to `Gadget`, we will run into problems. An [`Rc`] pointer from `Owner` -//! to `Gadget` introduces a cycle. This means that their -//! reference counts can never reach 0, and the allocation will never be destroyed: -//! a memory leak. In order to get around this, we can use [`Weak`] -//! pointers. -//! -//! Rust actually makes it somewhat difficult to produce this loop in the first -//! place. In order to end up with two values that point at each other, one of -//! them needs to be mutable. This is difficult because [`Rc`] enforces -//! memory safety by only giving out shared references to the value it wraps, -//! and these don't allow direct mutation. We need to wrap the part of the -//! value we wish to mutate in a [`RefCell`], which provides *interior -//! mutability*: a method to achieve mutability through a shared reference. -//! [`RefCell`] enforces Rust's borrowing rules at runtime. -//! -//! ``` -//! use std::rc::Rc; -//! use std::rc::Weak; -//! use std::cell::RefCell; -//! -//! struct Owner { -//! name: String, -//! gadgets: RefCell>>, -//! // ...other fields -//! } -//! -//! struct Gadget { -//! id: i32, -//! owner: Rc, -//! // ...other fields -//! } -//! -//! fn main() { -//! // Create a reference-counted `Owner`. Note that we've put the `Owner`'s -//! // vector of `Gadget`s inside a `RefCell` so that we can mutate it through -//! // a shared reference. -//! let gadget_owner: Rc = Rc::new( -//! Owner { -//! name: "Gadget Man".to_string(), -//! gadgets: RefCell::new(vec![]), -//! } -//! ); -//! -//! // Create `Gadget`s belonging to `gadget_owner`, as before. -//! let gadget1 = Rc::new( -//! Gadget { -//! id: 1, -//! owner: Rc::clone(&gadget_owner), -//! } -//! ); -//! let gadget2 = Rc::new( -//! Gadget { -//! id: 2, -//! owner: Rc::clone(&gadget_owner), -//! } -//! ); -//! -//! // Add the `Gadget`s to their `Owner`. -//! { -//! let mut gadgets = gadget_owner.gadgets.borrow_mut(); -//! gadgets.push(Rc::downgrade(&gadget1)); -//! gadgets.push(Rc::downgrade(&gadget2)); -//! -//! // `RefCell` dynamic borrow ends here. -//! } -//! -//! // Iterate over our `Gadget`s, printing their details out. -//! for gadget_weak in gadget_owner.gadgets.borrow().iter() { -//! -//! // `gadget_weak` is a `Weak`. Since `Weak` pointers can't -//! // guarantee the allocation still exists, we need to call -//! // `upgrade`, which returns an `Option>`. -//! // -//! // In this case we know the allocation still exists, so we simply -//! // `unwrap` the `Option`. In a more complicated program, you might -//! // need graceful error handling for a `None` result. -//! -//! let gadget = gadget_weak.upgrade().unwrap(); -//! println!("Gadget {} owned by {}", gadget.id, gadget.owner.name); -//! } -//! -//! // At the end of the function, `gadget_owner`, `gadget1`, and `gadget2` -//! // are destroyed. There are now no strong (`Rc`) pointers to the -//! // gadgets, so they are destroyed. This zeroes the reference count on -//! // Gadget Man, so he gets destroyed as well. -//! } -//! ``` -//! -//! [clone]: Clone::clone -//! [`Cell`]: core::cell::Cell -//! [`RefCell`]: core::cell::RefCell -//! [arc]: crate::sync::Arc -//! [`Deref`]: core::ops::Deref -//! [downgrade]: Rc::downgrade -//! [upgrade]: Weak::upgrade -//! [mutability]: core::cell#introducing-mutability-inside-of-something-immutable -//! [fully qualified syntax]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name - -#![stable(feature = "rust1", since = "1.0.0")] - -use core::any::Any; -use core::cell::Cell; -#[cfg(not(no_global_oom_handling))] -use core::clone::CloneToUninit; -use core::cmp::Ordering; -use core::hash::{Hash, Hasher}; -use core::intrinsics::abort; -#[cfg(not(no_global_oom_handling))] -use core::iter; -use core::marker::{PhantomData, Unsize}; -use core::mem::{self, ManuallyDrop, align_of_val_raw}; -use core::num::NonZeroUsize; -use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; -use core::panic::{RefUnwindSafe, UnwindSafe}; -#[cfg(not(no_global_oom_handling))] -use core::pin::Pin; -use core::pin::PinCoerceUnsized; -use core::ptr::{self, NonNull, drop_in_place}; -#[cfg(not(no_global_oom_handling))] -use core::slice::from_raw_parts_mut; -use core::{borrow, fmt, hint}; -#[cfg(test)] -use std::boxed::Box; - -#[cfg(not(no_global_oom_handling))] -use crate::alloc::handle_alloc_error; -use crate::alloc::{AllocError, Allocator, Global, Layout}; -use crate::borrow::{Cow, ToOwned}; -#[cfg(not(test))] -use crate::boxed::Box; -#[cfg(not(no_global_oom_handling))] -use crate::string::String; -#[cfg(not(no_global_oom_handling))] -use crate::vec::Vec; - -#[cfg(test)] -mod tests; - -// This is repr(C) to future-proof against possible field-reordering, which -// would interfere with otherwise safe [into|from]_raw() of transmutable -// inner types. -#[repr(C)] -struct RcInner { - strong: Cell, - weak: Cell, - value: T, -} - -/// Calculate layout for `RcInner` using the inner value's layout -fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout { - // Calculate layout using the given value layout. - // Previously, layout was calculated on the expression - // `&*(ptr as *const RcInner)`, but this created a misaligned - // reference (see #54908). - Layout::new::>().extend(layout).unwrap().0.pad_to_align() -} - -/// A single-threaded reference-counting pointer. 'Rc' stands for 'Reference -/// Counted'. -/// -/// See the [module-level documentation](./index.html) for more details. -/// -/// The inherent methods of `Rc` are all associated functions, which means -/// that you have to call them as e.g., [`Rc::get_mut(&mut value)`][get_mut] instead of -/// `value.get_mut()`. This avoids conflicts with methods of the inner type `T`. -/// -/// [get_mut]: Rc::get_mut -#[doc(search_unbox)] -#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_insignificant_dtor] -pub struct Rc< - T: ?Sized, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> { - ptr: NonNull>, - phantom: PhantomData>, - alloc: A, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl !Send for Rc {} - -// Note that this negative impl isn't strictly necessary for correctness, -// as `Rc` transitively contains a `Cell`, which is itself `!Sync`. -// However, given how important `Rc`'s `!Sync`-ness is, -// having an explicit negative impl is nice for documentation purposes -// and results in nicer error messages. -#[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for Rc {} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for Rc {} -#[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")] -impl RefUnwindSafe for Rc {} - -#[unstable(feature = "coerce_unsized", issue = "18598")] -impl, U: ?Sized, A: Allocator> CoerceUnsized> for Rc {} - -#[unstable(feature = "dispatch_from_dyn", issue = "none")] -impl, U: ?Sized> DispatchFromDyn> for Rc {} - -impl Rc { - #[inline] - unsafe fn from_inner(ptr: NonNull>) -> Self { - unsafe { Self::from_inner_in(ptr, Global) } - } - - #[inline] - unsafe fn from_ptr(ptr: *mut RcInner) -> Self { - unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) } - } -} - -impl Rc { - #[inline(always)] - fn inner(&self) -> &RcInner { - // This unsafety is ok because while this Rc is alive we're guaranteed - // that the inner pointer is valid. - unsafe { self.ptr.as_ref() } - } - - #[inline] - fn into_inner_with_allocator(this: Self) -> (NonNull>, A) { - let this = mem::ManuallyDrop::new(this); - (this.ptr, unsafe { ptr::read(&this.alloc) }) - } - - #[inline] - unsafe fn from_inner_in(ptr: NonNull>, alloc: A) -> Self { - Self { ptr, phantom: PhantomData, alloc } - } - - #[inline] - unsafe fn from_ptr_in(ptr: *mut RcInner, alloc: A) -> Self { - unsafe { Self::from_inner_in(NonNull::new_unchecked(ptr), alloc) } - } - - // Non-inlined part of `drop`. - #[inline(never)] - unsafe fn drop_slow(&mut self) { - // Reconstruct the "strong weak" pointer and drop it when this - // variable goes out of scope. This ensures that the memory is - // deallocated even if the destructor of `T` panics. - let _weak = Weak { ptr: self.ptr, alloc: &self.alloc }; - - // Destroy the contained object. - // We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed. - unsafe { - ptr::drop_in_place(&mut (*self.ptr.as_ptr()).value); - } - } -} - -impl Rc { - /// Constructs a new `Rc`. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// ``` - #[cfg(not(no_global_oom_handling))] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(value: T) -> Rc { - // There is an implicit weak pointer owned by all the strong - // pointers, which ensures that the weak destructor never frees - // the allocation while the strong destructor is running, even - // if the weak pointer is stored inside the strong one. - unsafe { - Self::from_inner( - Box::leak(Box::new(RcInner { strong: Cell::new(1), weak: Cell::new(1), value })) - .into(), - ) - } - } - - /// Constructs a new `Rc` while giving you a `Weak` to the allocation, - /// to allow you to construct a `T` which holds a weak pointer to itself. - /// - /// Generally, a structure circularly referencing itself, either directly or - /// indirectly, should not hold a strong reference to itself to prevent a memory leak. - /// Using this function, you get access to the weak pointer during the - /// initialization of `T`, before the `Rc` is created, such that you can - /// clone and store it inside the `T`. - /// - /// `new_cyclic` first allocates the managed allocation for the `Rc`, - /// then calls your closure, giving it a `Weak` to this allocation, - /// and only afterwards completes the construction of the `Rc` by placing - /// the `T` returned from your closure into the allocation. - /// - /// Since the new `Rc` is not fully-constructed until `Rc::new_cyclic` - /// returns, calling [`upgrade`] on the weak reference inside your closure will - /// fail and result in a `None` value. - /// - /// # Panics - /// - /// If `data_fn` panics, the panic is propagated to the caller, and the - /// temporary [`Weak`] is dropped normally. - /// - /// # Examples - /// - /// ``` - /// # #![allow(dead_code)] - /// use std::rc::{Rc, Weak}; - /// - /// struct Gadget { - /// me: Weak, - /// } - /// - /// impl Gadget { - /// /// Constructs a reference counted Gadget. - /// fn new() -> Rc { - /// // `me` is a `Weak` pointing at the new allocation of the - /// // `Rc` we're constructing. - /// Rc::new_cyclic(|me| { - /// // Create the actual struct here. - /// Gadget { me: me.clone() } - /// }) - /// } - /// - /// /// Returns a reference counted pointer to Self. - /// fn me(&self) -> Rc { - /// self.me.upgrade().unwrap() - /// } - /// } - /// ``` - /// [`upgrade`]: Weak::upgrade - #[cfg(not(no_global_oom_handling))] - #[stable(feature = "arc_new_cyclic", since = "1.60.0")] - pub fn new_cyclic(data_fn: F) -> Rc - where - F: FnOnce(&Weak) -> T, - { - Self::new_cyclic_in(data_fn, Global) - } - - /// Constructs a new `Rc` with uninitialized contents. - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut five = Rc::::new_uninit(); - /// - /// // Deferred initialization: - /// Rc::get_mut(&mut five).unwrap().write(5); - /// - /// let five = unsafe { five.assume_init() }; - /// - /// assert_eq!(*five, 5) - /// ``` - #[cfg(not(no_global_oom_handling))] - #[stable(feature = "new_uninit", since = "1.82.0")] - #[must_use] - pub fn new_uninit() -> Rc> { - unsafe { - Rc::from_ptr(Rc::allocate_for_layout( - Layout::new::(), - |layout| Global.allocate(layout), - <*mut u8>::cast, - )) - } - } - - /// Constructs a new `Rc` with uninitialized contents, with the memory - /// being filled with `0` bytes. - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(new_zeroed_alloc)] - /// - /// use std::rc::Rc; - /// - /// let zero = Rc::::new_zeroed(); - /// let zero = unsafe { zero.assume_init() }; - /// - /// assert_eq!(*zero, 0) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "new_zeroed_alloc", issue = "129396")] - #[must_use] - pub fn new_zeroed() -> Rc> { - unsafe { - Rc::from_ptr(Rc::allocate_for_layout( - Layout::new::(), - |layout| Global.allocate_zeroed(layout), - <*mut u8>::cast, - )) - } - } - - /// Constructs a new `Rc`, returning an error if the allocation fails - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// use std::rc::Rc; - /// - /// let five = Rc::try_new(5); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn try_new(value: T) -> Result, AllocError> { - // There is an implicit weak pointer owned by all the strong - // pointers, which ensures that the weak destructor never frees - // the allocation while the strong destructor is running, even - // if the weak pointer is stored inside the strong one. - unsafe { - Ok(Self::from_inner( - Box::leak(Box::try_new(RcInner { - strong: Cell::new(1), - weak: Cell::new(1), - value, - })?) - .into(), - )) - } - } - - /// Constructs a new `Rc` with uninitialized contents, returning an error if the allocation fails - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut five = Rc::::try_new_uninit()?; - /// - /// // Deferred initialization: - /// Rc::get_mut(&mut five).unwrap().write(5); - /// - /// let five = unsafe { five.assume_init() }; - /// - /// assert_eq!(*five, 5); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - pub fn try_new_uninit() -> Result>, AllocError> { - unsafe { - Ok(Rc::from_ptr(Rc::try_allocate_for_layout( - Layout::new::(), - |layout| Global.allocate(layout), - <*mut u8>::cast, - )?)) - } - } - - /// Constructs a new `Rc` with uninitialized contents, with the memory - /// being filled with `0` bytes, returning an error if the allocation fails - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// - /// let zero = Rc::::try_new_zeroed()?; - /// let zero = unsafe { zero.assume_init() }; - /// - /// assert_eq!(*zero, 0); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[unstable(feature = "allocator_api", issue = "32838")] - //#[unstable(feature = "new_uninit", issue = "63291")] - pub fn try_new_zeroed() -> Result>, AllocError> { - unsafe { - Ok(Rc::from_ptr(Rc::try_allocate_for_layout( - Layout::new::(), - |layout| Global.allocate_zeroed(layout), - <*mut u8>::cast, - )?)) - } - } - /// Constructs a new `Pin>`. If `T` does not implement `Unpin`, then - /// `value` will be pinned in memory and unable to be moved. - #[cfg(not(no_global_oom_handling))] - #[stable(feature = "pin", since = "1.33.0")] - #[must_use] - pub fn pin(value: T) -> Pin> { - unsafe { Pin::new_unchecked(Rc::new(value)) } - } -} - -impl Rc { - /// Constructs a new `Rc` in the provided allocator. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let five = Rc::new_in(5, System); - /// ``` - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub fn new_in(value: T, alloc: A) -> Rc { - // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. - // That would make code size bigger. - match Self::try_new_in(value, alloc) { - Ok(m) => m, - Err(_) => handle_alloc_error(Layout::new::>()), - } - } - - /// Constructs a new `Rc` with uninitialized contents in the provided allocator. - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let mut five = Rc::::new_uninit_in(System); - /// - /// let five = unsafe { - /// // Deferred initialization: - /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); - /// - /// five.assume_init() - /// }; - /// - /// assert_eq!(*five, 5) - /// ``` - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn new_uninit_in(alloc: A) -> Rc, A> { - unsafe { - Rc::from_ptr_in( - Rc::allocate_for_layout( - Layout::new::(), - |layout| alloc.allocate(layout), - <*mut u8>::cast, - ), - alloc, - ) - } - } - - /// Constructs a new `Rc` with uninitialized contents, with the memory - /// being filled with `0` bytes, in the provided allocator. - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let zero = Rc::::new_zeroed_in(System); - /// let zero = unsafe { zero.assume_init() }; - /// - /// assert_eq!(*zero, 0) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn new_zeroed_in(alloc: A) -> Rc, A> { - unsafe { - Rc::from_ptr_in( - Rc::allocate_for_layout( - Layout::new::(), - |layout| alloc.allocate_zeroed(layout), - <*mut u8>::cast, - ), - alloc, - ) - } - } - - /// Constructs a new `Rc` in the given allocator while giving you a `Weak` to the allocation, - /// to allow you to construct a `T` which holds a weak pointer to itself. - /// - /// Generally, a structure circularly referencing itself, either directly or - /// indirectly, should not hold a strong reference to itself to prevent a memory leak. - /// Using this function, you get access to the weak pointer during the - /// initialization of `T`, before the `Rc` is created, such that you can - /// clone and store it inside the `T`. - /// - /// `new_cyclic_in` first allocates the managed allocation for the `Rc`, - /// then calls your closure, giving it a `Weak` to this allocation, - /// and only afterwards completes the construction of the `Rc` by placing - /// the `T` returned from your closure into the allocation. - /// - /// Since the new `Rc` is not fully-constructed until `Rc::new_cyclic_in` - /// returns, calling [`upgrade`] on the weak reference inside your closure will - /// fail and result in a `None` value. - /// - /// # Panics - /// - /// If `data_fn` panics, the panic is propagated to the caller, and the - /// temporary [`Weak`] is dropped normally. - /// - /// # Examples - /// - /// See [`new_cyclic`]. - /// - /// [`new_cyclic`]: Rc::new_cyclic - /// [`upgrade`]: Weak::upgrade - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn new_cyclic_in(data_fn: F, alloc: A) -> Rc - where - F: FnOnce(&Weak) -> T, - { - // Construct the inner in the "uninitialized" state with a single - // weak reference. - let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in( - RcInner { - strong: Cell::new(0), - weak: Cell::new(1), - value: mem::MaybeUninit::::uninit(), - }, - alloc, - )); - let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into(); - let init_ptr: NonNull> = uninit_ptr.cast(); - - let weak = Weak { ptr: init_ptr, alloc }; - - // It's important we don't give up ownership of the weak pointer, or - // else the memory might be freed by the time `data_fn` returns. If - // we really wanted to pass ownership, we could create an additional - // weak pointer for ourselves, but this would result in additional - // updates to the weak reference count which might not be necessary - // otherwise. - let data = data_fn(&weak); - - let strong = unsafe { - let inner = init_ptr.as_ptr(); - ptr::write(&raw mut (*inner).value, data); - - let prev_value = (*inner).strong.get(); - debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); - (*inner).strong.set(1); - - // Strong references should collectively own a shared weak reference, - // so don't run the destructor for our old weak reference. - // Calling into_raw_with_allocator has the double effect of giving us back the allocator, - // and forgetting the weak reference. - let alloc = weak.into_raw_with_allocator().1; - - Rc::from_inner_in(init_ptr, alloc) - }; - - strong - } - - /// Constructs a new `Rc` in the provided allocator, returning an error if the allocation - /// fails - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let five = Rc::try_new_in(5, System); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub fn try_new_in(value: T, alloc: A) -> Result { - // There is an implicit weak pointer owned by all the strong - // pointers, which ensures that the weak destructor never frees - // the allocation while the strong destructor is running, even - // if the weak pointer is stored inside the strong one. - let (ptr, alloc) = Box::into_unique(Box::try_new_in( - RcInner { strong: Cell::new(1), weak: Cell::new(1), value }, - alloc, - )?); - Ok(unsafe { Self::from_inner_in(ptr.into(), alloc) }) - } - - /// Constructs a new `Rc` with uninitialized contents, in the provided allocator, returning an - /// error if the allocation fails - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let mut five = Rc::::try_new_uninit_in(System)?; - /// - /// let five = unsafe { - /// // Deferred initialization: - /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); - /// - /// five.assume_init() - /// }; - /// - /// assert_eq!(*five, 5); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> { - unsafe { - Ok(Rc::from_ptr_in( - Rc::try_allocate_for_layout( - Layout::new::(), - |layout| alloc.allocate(layout), - <*mut u8>::cast, - )?, - alloc, - )) - } - } - - /// Constructs a new `Rc` with uninitialized contents, with the memory - /// being filled with `0` bytes, in the provided allocator, returning an error if the allocation - /// fails - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let zero = Rc::::try_new_zeroed_in(System)?; - /// let zero = unsafe { zero.assume_init() }; - /// - /// assert_eq!(*zero, 0); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[unstable(feature = "allocator_api", issue = "32838")] - //#[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> { - unsafe { - Ok(Rc::from_ptr_in( - Rc::try_allocate_for_layout( - Layout::new::(), - |layout| alloc.allocate_zeroed(layout), - <*mut u8>::cast, - )?, - alloc, - )) - } - } - - /// Constructs a new `Pin>` in the provided allocator. If `T` does not implement `Unpin`, then - /// `value` will be pinned in memory and unable to be moved. - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub fn pin_in(value: T, alloc: A) -> Pin - where - A: 'static, - { - unsafe { Pin::new_unchecked(Rc::new_in(value, alloc)) } - } - - /// Returns the inner value, if the `Rc` has exactly one strong reference. - /// - /// Otherwise, an [`Err`] is returned with the same `Rc` that was - /// passed in. - /// - /// This will succeed even if there are outstanding weak references. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new(3); - /// assert_eq!(Rc::try_unwrap(x), Ok(3)); - /// - /// let x = Rc::new(4); - /// let _y = Rc::clone(&x); - /// assert_eq!(*Rc::try_unwrap(x).unwrap_err(), 4); - /// ``` - #[inline] - #[stable(feature = "rc_unique", since = "1.4.0")] - pub fn try_unwrap(this: Self) -> Result { - if Rc::strong_count(&this) == 1 { - let this = ManuallyDrop::new(this); - - let val: T = unsafe { ptr::read(&**this) }; // copy the contained object - let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator - - // Indicate to Weaks that they can't be promoted by decrementing - // the strong count, and then remove the implicit "strong weak" - // pointer while also handling drop logic by just crafting a - // fake Weak. - this.inner().dec_strong(); - let _weak = Weak { ptr: this.ptr, alloc }; - Ok(val) - } else { - Err(this) - } - } - - /// Returns the inner value, if the `Rc` has exactly one strong reference. - /// - /// Otherwise, [`None`] is returned and the `Rc` is dropped. - /// - /// This will succeed even if there are outstanding weak references. - /// - /// If `Rc::into_inner` is called on every clone of this `Rc`, - /// it is guaranteed that exactly one of the calls returns the inner value. - /// This means in particular that the inner value is not dropped. - /// - /// [`Rc::try_unwrap`] is conceptually similar to `Rc::into_inner`. - /// And while they are meant for different use-cases, `Rc::into_inner(this)` - /// is in fact equivalent to [Rc::try_unwrap]\(this).[ok][Result::ok](). - /// (Note that the same kind of equivalence does **not** hold true for - /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`!) - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new(3); - /// assert_eq!(Rc::into_inner(x), Some(3)); - /// - /// let x = Rc::new(4); - /// let y = Rc::clone(&x); - /// - /// assert_eq!(Rc::into_inner(y), None); - /// assert_eq!(Rc::into_inner(x), Some(4)); - /// ``` - #[inline] - #[stable(feature = "rc_into_inner", since = "1.70.0")] - pub fn into_inner(this: Self) -> Option { - Rc::try_unwrap(this).ok() - } -} - -impl Rc<[T]> { - /// Constructs a new reference-counted slice with uninitialized contents. - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut values = Rc::<[u32]>::new_uninit_slice(3); - /// - /// // Deferred initialization: - /// let data = Rc::get_mut(&mut values).unwrap(); - /// data[0].write(1); - /// data[1].write(2); - /// data[2].write(3); - /// - /// let values = unsafe { values.assume_init() }; - /// - /// assert_eq!(*values, [1, 2, 3]) - /// ``` - #[cfg(not(no_global_oom_handling))] - #[stable(feature = "new_uninit", since = "1.82.0")] - #[must_use] - pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit]> { - unsafe { Rc::from_ptr(Rc::allocate_for_slice(len)) } - } - - /// Constructs a new reference-counted slice with uninitialized contents, with the memory being - /// filled with `0` bytes. - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(new_zeroed_alloc)] - /// - /// use std::rc::Rc; - /// - /// let values = Rc::<[u32]>::new_zeroed_slice(3); - /// let values = unsafe { values.assume_init() }; - /// - /// assert_eq!(*values, [0, 0, 0]) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "new_zeroed_alloc", issue = "129396")] - #[must_use] - pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit]> { - unsafe { - Rc::from_ptr(Rc::allocate_for_layout( - Layout::array::(len).unwrap(), - |layout| Global.allocate_zeroed(layout), - |mem| { - ptr::slice_from_raw_parts_mut(mem.cast::(), len) - as *mut RcInner<[mem::MaybeUninit]> - }, - )) - } - } - - /// Converts the reference-counted slice into a reference-counted array. - /// - /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type. - /// - /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. - #[unstable(feature = "slice_as_array", issue = "133508")] - #[inline] - #[must_use] - pub fn into_array(self) -> Option> { - if self.len() == N { - let ptr = Self::into_raw(self) as *const [T; N]; - - // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length. - let me = unsafe { Rc::from_raw(ptr) }; - Some(me) - } else { - None - } - } -} - -impl Rc<[T], A> { - /// Constructs a new reference-counted slice with uninitialized contents. - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let mut values = Rc::<[u32], _>::new_uninit_slice_in(3, System); - /// - /// let values = unsafe { - /// // Deferred initialization: - /// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); - /// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); - /// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); - /// - /// values.assume_init() - /// }; - /// - /// assert_eq!(*values, [1, 2, 3]) - /// ``` - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn new_uninit_slice_in(len: usize, alloc: A) -> Rc<[mem::MaybeUninit], A> { - unsafe { Rc::from_ptr_in(Rc::allocate_for_slice_in(len, &alloc), alloc) } - } - - /// Constructs a new reference-counted slice with uninitialized contents, with the memory being - /// filled with `0` bytes. - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let values = Rc::<[u32], _>::new_zeroed_slice_in(3, System); - /// let values = unsafe { values.assume_init() }; - /// - /// assert_eq!(*values, [0, 0, 0]) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Rc<[mem::MaybeUninit], A> { - unsafe { - Rc::from_ptr_in( - Rc::allocate_for_layout( - Layout::array::(len).unwrap(), - |layout| alloc.allocate_zeroed(layout), - |mem| { - ptr::slice_from_raw_parts_mut(mem.cast::(), len) - as *mut RcInner<[mem::MaybeUninit]> - }, - ), - alloc, - ) - } - } -} - -impl Rc, A> { - /// Converts to `Rc`. - /// - /// # Safety - /// - /// As with [`MaybeUninit::assume_init`], - /// it is up to the caller to guarantee that the inner value - /// really is in an initialized state. - /// Calling this when the content is not yet fully initialized - /// causes immediate undefined behavior. - /// - /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut five = Rc::::new_uninit(); - /// - /// // Deferred initialization: - /// Rc::get_mut(&mut five).unwrap().write(5); - /// - /// let five = unsafe { five.assume_init() }; - /// - /// assert_eq!(*five, 5) - /// ``` - #[stable(feature = "new_uninit", since = "1.82.0")] - #[inline] - pub unsafe fn assume_init(self) -> Rc { - let (ptr, alloc) = Rc::into_inner_with_allocator(self); - unsafe { Rc::from_inner_in(ptr.cast(), alloc) } - } -} - -impl Rc<[mem::MaybeUninit], A> { - /// Converts to `Rc<[T]>`. - /// - /// # Safety - /// - /// As with [`MaybeUninit::assume_init`], - /// it is up to the caller to guarantee that the inner value - /// really is in an initialized state. - /// Calling this when the content is not yet fully initialized - /// causes immediate undefined behavior. - /// - /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut values = Rc::<[u32]>::new_uninit_slice(3); - /// - /// // Deferred initialization: - /// let data = Rc::get_mut(&mut values).unwrap(); - /// data[0].write(1); - /// data[1].write(2); - /// data[2].write(3); - /// - /// let values = unsafe { values.assume_init() }; - /// - /// assert_eq!(*values, [1, 2, 3]) - /// ``` - #[stable(feature = "new_uninit", since = "1.82.0")] - #[inline] - pub unsafe fn assume_init(self) -> Rc<[T], A> { - let (ptr, alloc) = Rc::into_inner_with_allocator(self); - unsafe { Rc::from_ptr_in(ptr.as_ptr() as _, alloc) } - } -} - -impl Rc { - /// Constructs an `Rc` from a raw pointer. - /// - /// The raw pointer must have been previously returned by a call to - /// [`Rc::into_raw`][into_raw] with the following requirements: - /// - /// * If `U` is sized, it must have the same size and alignment as `T`. This - /// is trivially true if `U` is `T`. - /// * If `U` is unsized, its data pointer must have the same size and - /// alignment as `T`. This is trivially true if `Rc` was constructed - /// through `Rc` and then converted to `Rc` through an [unsized - /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by the global allocator - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. - /// - /// This function is unsafe because improper use may lead to memory unsafety, - /// even if the returned `Rc` is never accessed. - /// - /// [into_raw]: Rc::into_raw - /// [transmute]: core::mem::transmute - /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new("hello".to_owned()); - /// let x_ptr = Rc::into_raw(x); - /// - /// unsafe { - /// // Convert back to an `Rc` to prevent leak. - /// let x = Rc::from_raw(x_ptr); - /// assert_eq!(&*x, "hello"); - /// - /// // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe. - /// } - /// - /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! - /// ``` - /// - /// Convert a slice back into its original array: - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x: Rc<[u32]> = Rc::new([1, 2, 3]); - /// let x_ptr: *const [u32] = Rc::into_raw(x); - /// - /// unsafe { - /// let x: Rc<[u32; 3]> = Rc::from_raw(x_ptr.cast::<[u32; 3]>()); - /// assert_eq!(&*x, &[1, 2, 3]); - /// } - /// ``` - #[inline] - #[stable(feature = "rc_raw", since = "1.17.0")] - pub unsafe fn from_raw(ptr: *const T) -> Self { - unsafe { Self::from_raw_in(ptr, Global) } - } - - /// Increments the strong reference count on the `Rc` associated with the - /// provided pointer by one. - /// - /// # Safety - /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at - /// least 1) for the duration of this method, and `ptr` must point to a block of memory - /// allocated by the global allocator. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// unsafe { - /// let ptr = Rc::into_raw(five); - /// Rc::increment_strong_count(ptr); - /// - /// let five = Rc::from_raw(ptr); - /// assert_eq!(2, Rc::strong_count(&five)); - /// # // Prevent leaks for Miri. - /// # Rc::decrement_strong_count(ptr); - /// } - /// ``` - #[inline] - #[stable(feature = "rc_mutate_strong_count", since = "1.53.0")] - pub unsafe fn increment_strong_count(ptr: *const T) { - unsafe { Self::increment_strong_count_in(ptr, Global) } - } - - /// Decrements the strong reference count on the `Rc` associated with the - /// provided pointer by one. - /// - /// # Safety - /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at - /// least 1) when invoking this method, and `ptr` must point to a block of memory - /// allocated by the global allocator. This method can be used to release the final `Rc` and - /// backing storage, but **should not** be called after the final `Rc` has been released. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// unsafe { - /// let ptr = Rc::into_raw(five); - /// Rc::increment_strong_count(ptr); - /// - /// let five = Rc::from_raw(ptr); - /// assert_eq!(2, Rc::strong_count(&five)); - /// Rc::decrement_strong_count(ptr); - /// assert_eq!(1, Rc::strong_count(&five)); - /// } - /// ``` - #[inline] - #[stable(feature = "rc_mutate_strong_count", since = "1.53.0")] - pub unsafe fn decrement_strong_count(ptr: *const T) { - unsafe { Self::decrement_strong_count_in(ptr, Global) } - } -} - -impl Rc { - /// Returns a reference to the underlying allocator. - /// - /// Note: this is an associated function, which means that you have - /// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This - /// is so that there is no conflict with a method on the inner type. - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn allocator(this: &Self) -> &A { - &this.alloc - } - - /// Consumes the `Rc`, returning the wrapped pointer. - /// - /// To avoid a memory leak the pointer must be converted back to an `Rc` using - /// [`Rc::from_raw`]. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new("hello".to_owned()); - /// let x_ptr = Rc::into_raw(x); - /// assert_eq!(unsafe { &*x_ptr }, "hello"); - /// # // Prevent leaks for Miri. - /// # drop(unsafe { Rc::from_raw(x_ptr) }); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "rc_raw", since = "1.17.0")] - #[rustc_never_returns_null_ptr] - pub fn into_raw(this: Self) -> *const T { - let this = ManuallyDrop::new(this); - Self::as_ptr(&*this) - } - - /// Consumes the `Rc`, returning the wrapped pointer and allocator. - /// - /// To avoid a memory leak the pointer must be converted back to an `Rc` using - /// [`Rc::from_raw_in`]. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let x = Rc::new_in("hello".to_owned(), System); - /// let (ptr, alloc) = Rc::into_raw_with_allocator(x); - /// assert_eq!(unsafe { &*ptr }, "hello"); - /// let x = unsafe { Rc::from_raw_in(ptr, alloc) }; - /// assert_eq!(&*x, "hello"); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn into_raw_with_allocator(this: Self) -> (*const T, A) { - let this = mem::ManuallyDrop::new(this); - let ptr = Self::as_ptr(&this); - // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped - let alloc = unsafe { ptr::read(&this.alloc) }; - (ptr, alloc) - } - - /// Provides a raw pointer to the data. - /// - /// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid - /// for as long as there are strong counts in the `Rc`. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new(0); - /// let y = Rc::clone(&x); - /// let x_ptr = Rc::as_ptr(&x); - /// assert_eq!(x_ptr, Rc::as_ptr(&y)); - /// assert_eq!(unsafe { *x_ptr }, 0); - /// ``` - #[stable(feature = "weak_into_raw", since = "1.45.0")] - #[rustc_never_returns_null_ptr] - pub fn as_ptr(this: &Self) -> *const T { - let ptr: *mut RcInner = NonNull::as_ptr(this.ptr); - - // SAFETY: This cannot go through Deref::deref or Rc::inner because - // this is required to retain raw/mut provenance such that e.g. `get_mut` can - // write through the pointer after the Rc is recovered through `from_raw`. - unsafe { &raw mut (*ptr).value } - } - - /// Constructs an `Rc` from a raw pointer in the provided allocator. - /// - /// The raw pointer must have been previously returned by a call to [`Rc::into_raw`][into_raw] with the following requirements: - /// - /// * If `U` is sized, it must have the same size and alignment as `T`. This - /// is trivially true if `U` is `T`. - /// * If `U` is unsized, its data pointer must have the same size and - /// alignment as `T`. This is trivially true if `Rc` was constructed - /// through `Rc` and then converted to `Rc` through an [unsized - /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by `alloc` - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. - /// - /// This function is unsafe because improper use may lead to memory unsafety, - /// even if the returned `Rc` is never accessed. - /// - /// [into_raw]: Rc::into_raw - /// [transmute]: core::mem::transmute - /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let x = Rc::new_in("hello".to_owned(), System); - /// let x_ptr = Rc::into_raw(x); - /// - /// unsafe { - /// // Convert back to an `Rc` to prevent leak. - /// let x = Rc::from_raw_in(x_ptr, System); - /// assert_eq!(&*x, "hello"); - /// - /// // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe. - /// } - /// - /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! - /// ``` - /// - /// Convert a slice back into its original array: - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let x: Rc<[u32], _> = Rc::new_in([1, 2, 3], System); - /// let x_ptr: *const [u32] = Rc::into_raw(x); - /// - /// unsafe { - /// let x: Rc<[u32; 3], _> = Rc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); - /// assert_eq!(&*x, &[1, 2, 3]); - /// } - /// ``` - #[unstable(feature = "allocator_api", issue = "32838")] - pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { - let offset = unsafe { data_offset(ptr) }; - - // Reverse the offset to find the original RcInner. - let rc_ptr = unsafe { ptr.byte_sub(offset) as *mut RcInner }; - - unsafe { Self::from_ptr_in(rc_ptr, alloc) } - } - - /// Creates a new [`Weak`] pointer to this allocation. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// let weak_five = Rc::downgrade(&five); - /// ``` - #[must_use = "this returns a new `Weak` pointer, \ - without modifying the original `Rc`"] - #[stable(feature = "rc_weak", since = "1.4.0")] - pub fn downgrade(this: &Self) -> Weak - where - A: Clone, - { - this.inner().inc_weak(); - // Make sure we do not create a dangling Weak - debug_assert!(!is_dangling(this.ptr.as_ptr())); - Weak { ptr: this.ptr, alloc: this.alloc.clone() } - } - - /// Gets the number of [`Weak`] pointers to this allocation. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// let _weak_five = Rc::downgrade(&five); - /// - /// assert_eq!(1, Rc::weak_count(&five)); - /// ``` - #[inline] - #[stable(feature = "rc_counts", since = "1.15.0")] - pub fn weak_count(this: &Self) -> usize { - this.inner().weak() - 1 - } - - /// Gets the number of strong (`Rc`) pointers to this allocation. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// let _also_five = Rc::clone(&five); - /// - /// assert_eq!(2, Rc::strong_count(&five)); - /// ``` - #[inline] - #[stable(feature = "rc_counts", since = "1.15.0")] - pub fn strong_count(this: &Self) -> usize { - this.inner().strong() - } - - /// Increments the strong reference count on the `Rc` associated with the - /// provided pointer by one. - /// - /// # Safety - /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at - /// least 1) for the duration of this method, and `ptr` must point to a block of memory - /// allocated by `alloc` - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let five = Rc::new_in(5, System); - /// - /// unsafe { - /// let ptr = Rc::into_raw(five); - /// Rc::increment_strong_count_in(ptr, System); - /// - /// let five = Rc::from_raw_in(ptr, System); - /// assert_eq!(2, Rc::strong_count(&five)); - /// # // Prevent leaks for Miri. - /// # Rc::decrement_strong_count_in(ptr, System); - /// } - /// ``` - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub unsafe fn increment_strong_count_in(ptr: *const T, alloc: A) - where - A: Clone, - { - // Retain Rc, but don't touch refcount by wrapping in ManuallyDrop - let rc = unsafe { mem::ManuallyDrop::new(Rc::::from_raw_in(ptr, alloc)) }; - // Now increase refcount, but don't drop new refcount either - let _rc_clone: mem::ManuallyDrop<_> = rc.clone(); - } - - /// Decrements the strong reference count on the `Rc` associated with the - /// provided pointer by one. - /// - /// # Safety - /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at - /// least 1) when invoking this method, and `ptr` must point to a block of memory - /// allocated by `alloc`. This method can be used to release the final `Rc` and backing storage, - /// but **should not** be called after the final `Rc` has been released. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let five = Rc::new_in(5, System); - /// - /// unsafe { - /// let ptr = Rc::into_raw(five); - /// Rc::increment_strong_count_in(ptr, System); - /// - /// let five = Rc::from_raw_in(ptr, System); - /// assert_eq!(2, Rc::strong_count(&five)); - /// Rc::decrement_strong_count_in(ptr, System); - /// assert_eq!(1, Rc::strong_count(&five)); - /// } - /// ``` - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub unsafe fn decrement_strong_count_in(ptr: *const T, alloc: A) { - unsafe { drop(Rc::from_raw_in(ptr, alloc)) }; - } - - /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to - /// this allocation. - #[inline] - fn is_unique(this: &Self) -> bool { - Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 - } - - /// Returns a mutable reference into the given `Rc`, if there are - /// no other `Rc` or [`Weak`] pointers to the same allocation. - /// - /// Returns [`None`] otherwise, because it is not safe to - /// mutate a shared value. - /// - /// See also [`make_mut`][make_mut], which will [`clone`][clone] - /// the inner value when there are other `Rc` pointers. - /// - /// [make_mut]: Rc::make_mut - /// [clone]: Clone::clone - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let mut x = Rc::new(3); - /// *Rc::get_mut(&mut x).unwrap() = 4; - /// assert_eq!(*x, 4); - /// - /// let _y = Rc::clone(&x); - /// assert!(Rc::get_mut(&mut x).is_none()); - /// ``` - #[inline] - #[stable(feature = "rc_unique", since = "1.4.0")] - pub fn get_mut(this: &mut Self) -> Option<&mut T> { - if Rc::is_unique(this) { unsafe { Some(Rc::get_mut_unchecked(this)) } } else { None } - } - - /// Returns a mutable reference into the given `Rc`, - /// without any check. - /// - /// See also [`get_mut`], which is safe and does appropriate checks. - /// - /// [`get_mut`]: Rc::get_mut - /// - /// # Safety - /// - /// If any other `Rc` or [`Weak`] pointers to the same allocation exist, then - /// they must not be dereferenced or have active borrows for the duration - /// of the returned borrow, and their inner type must be exactly the same as the - /// inner type of this Rc (including lifetimes). This is trivially the case if no - /// such pointers exist, for example immediately after `Rc::new`. - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut x = Rc::new(String::new()); - /// unsafe { - /// Rc::get_mut_unchecked(&mut x).push_str("foo") - /// } - /// assert_eq!(*x, "foo"); - /// ``` - /// Other `Rc` pointers to the same allocation must be to the same type. - /// ```no_run - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let x: Rc = Rc::from("Hello, world!"); - /// let mut y: Rc<[u8]> = x.clone().into(); - /// unsafe { - /// // this is Undefined Behavior, because x's inner type is str, not [u8] - /// Rc::get_mut_unchecked(&mut y).fill(0xff); // 0xff is invalid in UTF-8 - /// } - /// println!("{}", &*x); // Invalid UTF-8 in a str - /// ``` - /// Other `Rc` pointers to the same allocation must be to the exact same type, including lifetimes. - /// ```no_run - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let x: Rc<&str> = Rc::new("Hello, world!"); - /// { - /// let s = String::from("Oh, no!"); - /// let mut y: Rc<&str> = x.clone(); - /// unsafe { - /// // this is Undefined Behavior, because x's inner type - /// // is &'long str, not &'short str - /// *Rc::get_mut_unchecked(&mut y) = &s; - /// } - /// } - /// println!("{}", &*x); // Use-after-free - /// ``` - #[inline] - #[unstable(feature = "get_mut_unchecked", issue = "63292")] - pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { - // We are careful to *not* create a reference covering the "count" fields, as - // this would conflict with accesses to the reference counts (e.g. by `Weak`). - unsafe { &mut (*this.ptr.as_ptr()).value } - } - - #[inline] - #[stable(feature = "ptr_eq", since = "1.17.0")] - /// Returns `true` if the two `Rc`s point to the same allocation in a vein similar to - /// [`ptr::eq`]. This function ignores the metadata of `dyn Trait` pointers. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// let same_five = Rc::clone(&five); - /// let other_five = Rc::new(5); - /// - /// assert!(Rc::ptr_eq(&five, &same_five)); - /// assert!(!Rc::ptr_eq(&five, &other_five)); - /// ``` - pub fn ptr_eq(this: &Self, other: &Self) -> bool { - ptr::addr_eq(this.ptr.as_ptr(), other.ptr.as_ptr()) - } -} - -#[cfg(not(no_global_oom_handling))] -impl Rc { - /// Makes a mutable reference into the given `Rc`. - /// - /// If there are other `Rc` pointers to the same allocation, then `make_mut` will - /// [`clone`] the inner value to a new allocation to ensure unique ownership. This is also - /// referred to as clone-on-write. - /// - /// However, if there are no other `Rc` pointers to this allocation, but some [`Weak`] - /// pointers, then the [`Weak`] pointers will be disassociated and the inner value will not - /// be cloned. - /// - /// See also [`get_mut`], which will fail rather than cloning the inner value - /// or disassociating [`Weak`] pointers. - /// - /// [`clone`]: Clone::clone - /// [`get_mut`]: Rc::get_mut - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let mut data = Rc::new(5); - /// - /// *Rc::make_mut(&mut data) += 1; // Won't clone anything - /// let mut other_data = Rc::clone(&data); // Won't clone inner data - /// *Rc::make_mut(&mut data) += 1; // Clones inner data - /// *Rc::make_mut(&mut data) += 1; // Won't clone anything - /// *Rc::make_mut(&mut other_data) *= 2; // Won't clone anything - /// - /// // Now `data` and `other_data` point to different allocations. - /// assert_eq!(*data, 8); - /// assert_eq!(*other_data, 12); - /// ``` - /// - /// [`Weak`] pointers will be disassociated: - /// - /// ``` - /// use std::rc::Rc; - /// - /// let mut data = Rc::new(75); - /// let weak = Rc::downgrade(&data); - /// - /// assert!(75 == *data); - /// assert!(75 == *weak.upgrade().unwrap()); - /// - /// *Rc::make_mut(&mut data) += 1; - /// - /// assert!(76 == *data); - /// assert!(weak.upgrade().is_none()); - /// ``` - #[inline] - #[stable(feature = "rc_unique", since = "1.4.0")] - pub fn make_mut(this: &mut Self) -> &mut T { - let size_of_val = size_of_val::(&**this); - - if Rc::strong_count(this) != 1 { - // Gotta clone the data, there are other Rcs. - - let this_data_ref: &T = &**this; - // `in_progress` drops the allocation if we panic before finishing initializing it. - let mut in_progress: UniqueRcUninit = - UniqueRcUninit::new(this_data_ref, this.alloc.clone()); - - // Initialize with clone of this. - let initialized_clone = unsafe { - // Clone. If the clone panics, `in_progress` will be dropped and clean up. - this_data_ref.clone_to_uninit(in_progress.data_ptr().cast()); - // Cast type of pointer, now that it is initialized. - in_progress.into_rc() - }; - - // Replace `this` with newly constructed Rc. - *this = initialized_clone; - } else if Rc::weak_count(this) != 0 { - // Can just steal the data, all that's left is Weaks - - // We don't need panic-protection like the above branch does, but we might as well - // use the same mechanism. - let mut in_progress: UniqueRcUninit = - UniqueRcUninit::new(&**this, this.alloc.clone()); - unsafe { - // Initialize `in_progress` with move of **this. - // We have to express this in terms of bytes because `T: ?Sized`; there is no - // operation that just copies a value based on its `size_of_val()`. - ptr::copy_nonoverlapping( - ptr::from_ref(&**this).cast::(), - in_progress.data_ptr().cast::(), - size_of_val, - ); - - this.inner().dec_strong(); - // Remove implicit strong-weak ref (no need to craft a fake - // Weak here -- we know other Weaks can clean up for us) - this.inner().dec_weak(); - // Replace `this` with newly constructed Rc that has the moved data. - ptr::write(this, in_progress.into_rc()); - } - } - // This unsafety is ok because we're guaranteed that the pointer - // returned is the *only* pointer that will ever be returned to T. Our - // reference count is guaranteed to be 1 at this point, and we required - // the `Rc` itself to be `mut`, so we're returning the only possible - // reference to the allocation. - unsafe { &mut this.ptr.as_mut().value } - } -} - -impl Rc { - /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the - /// clone. - /// - /// Assuming `rc_t` is of type `Rc`, this function is functionally equivalent to - /// `(*rc_t).clone()`, but will avoid cloning the inner value where possible. - /// - /// # Examples - /// - /// ``` - /// # use std::{ptr, rc::Rc}; - /// let inner = String::from("test"); - /// let ptr = inner.as_ptr(); - /// - /// let rc = Rc::new(inner); - /// let inner = Rc::unwrap_or_clone(rc); - /// // The inner value was not cloned - /// assert!(ptr::eq(ptr, inner.as_ptr())); - /// - /// let rc = Rc::new(inner); - /// let rc2 = rc.clone(); - /// let inner = Rc::unwrap_or_clone(rc); - /// // Because there were 2 references, we had to clone the inner value. - /// assert!(!ptr::eq(ptr, inner.as_ptr())); - /// // `rc2` is the last reference, so when we unwrap it we get back - /// // the original `String`. - /// let inner = Rc::unwrap_or_clone(rc2); - /// assert!(ptr::eq(ptr, inner.as_ptr())); - /// ``` - #[inline] - #[stable(feature = "arc_unwrap_or_clone", since = "1.76.0")] - pub fn unwrap_or_clone(this: Self) -> T { - Rc::try_unwrap(this).unwrap_or_else(|rc| (*rc).clone()) - } -} - -impl Rc { - /// Attempts to downcast the `Rc` to a concrete type. - /// - /// # Examples - /// - /// ``` - /// use std::any::Any; - /// use std::rc::Rc; - /// - /// fn print_if_string(value: Rc) { - /// if let Ok(string) = value.downcast::() { - /// println!("String ({}): {}", string.len(), string); - /// } - /// } - /// - /// let my_string = "Hello World".to_string(); - /// print_if_string(Rc::new(my_string)); - /// print_if_string(Rc::new(0i8)); - /// ``` - #[inline] - #[stable(feature = "rc_downcast", since = "1.29.0")] - pub fn downcast(self) -> Result, Self> { - if (*self).is::() { - unsafe { - let (ptr, alloc) = Rc::into_inner_with_allocator(self); - Ok(Rc::from_inner_in(ptr.cast(), alloc)) - } - } else { - Err(self) - } - } - - /// Downcasts the `Rc` to a concrete type. - /// - /// For a safe alternative see [`downcast`]. - /// - /// # Examples - /// - /// ``` - /// #![feature(downcast_unchecked)] - /// - /// use std::any::Any; - /// use std::rc::Rc; - /// - /// let x: Rc = Rc::new(1_usize); - /// - /// unsafe { - /// assert_eq!(*x.downcast_unchecked::(), 1); - /// } - /// ``` - /// - /// # Safety - /// - /// The contained value must be of type `T`. Calling this method - /// with the incorrect type is *undefined behavior*. - /// - /// - /// [`downcast`]: Self::downcast - #[inline] - #[unstable(feature = "downcast_unchecked", issue = "90850")] - pub unsafe fn downcast_unchecked(self) -> Rc { - unsafe { - let (ptr, alloc) = Rc::into_inner_with_allocator(self); - Rc::from_inner_in(ptr.cast(), alloc) - } - } -} - -impl Rc { - /// Allocates an `RcInner` with sufficient space for - /// a possibly-unsized inner value where the value has the layout provided. - /// - /// The function `mem_to_rc_inner` is called with the data pointer - /// and must return back a (potentially fat)-pointer for the `RcInner`. - #[cfg(not(no_global_oom_handling))] - unsafe fn allocate_for_layout( - value_layout: Layout, - allocate: impl FnOnce(Layout) -> Result, AllocError>, - mem_to_rc_inner: impl FnOnce(*mut u8) -> *mut RcInner, - ) -> *mut RcInner { - let layout = rc_inner_layout_for_value_layout(value_layout); - unsafe { - Rc::try_allocate_for_layout(value_layout, allocate, mem_to_rc_inner) - .unwrap_or_else(|_| handle_alloc_error(layout)) - } - } - - /// Allocates an `RcInner` with sufficient space for - /// a possibly-unsized inner value where the value has the layout provided, - /// returning an error if allocation fails. - /// - /// The function `mem_to_rc_inner` is called with the data pointer - /// and must return back a (potentially fat)-pointer for the `RcInner`. - #[inline] - unsafe fn try_allocate_for_layout( - value_layout: Layout, - allocate: impl FnOnce(Layout) -> Result, AllocError>, - mem_to_rc_inner: impl FnOnce(*mut u8) -> *mut RcInner, - ) -> Result<*mut RcInner, AllocError> { - let layout = rc_inner_layout_for_value_layout(value_layout); - - // Allocate for the layout. - let ptr = allocate(layout)?; - - // Initialize the RcInner - let inner = mem_to_rc_inner(ptr.as_non_null_ptr().as_ptr()); - unsafe { - debug_assert_eq!(Layout::for_value_raw(inner), layout); - - (&raw mut (*inner).strong).write(Cell::new(1)); - (&raw mut (*inner).weak).write(Cell::new(1)); - } - - Ok(inner) - } -} - -impl Rc { - /// Allocates an `RcInner` with sufficient space for an unsized inner value - #[cfg(not(no_global_oom_handling))] - unsafe fn allocate_for_ptr_in(ptr: *const T, alloc: &A) -> *mut RcInner { - // Allocate for the `RcInner` using the given value. - unsafe { - Rc::::allocate_for_layout( - Layout::for_value_raw(ptr), - |layout| alloc.allocate(layout), - |mem| mem.with_metadata_of(ptr as *const RcInner), - ) - } - } - - #[cfg(not(no_global_oom_handling))] - fn from_box_in(src: Box) -> Rc { - unsafe { - let value_size = size_of_val(&*src); - let ptr = Self::allocate_for_ptr_in(&*src, Box::allocator(&src)); - - // Copy value as bytes - ptr::copy_nonoverlapping( - (&raw const *src) as *const u8, - (&raw mut (*ptr).value) as *mut u8, - value_size, - ); - - // Free the allocation without dropping its contents - let (bptr, alloc) = Box::into_raw_with_allocator(src); - let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, alloc.by_ref()); - drop(src); - - Self::from_ptr_in(ptr, alloc) - } - } -} - -impl Rc<[T]> { - /// Allocates an `RcInner<[T]>` with the given length. - #[cfg(not(no_global_oom_handling))] - unsafe fn allocate_for_slice(len: usize) -> *mut RcInner<[T]> { - unsafe { - Self::allocate_for_layout( - Layout::array::(len).unwrap(), - |layout| Global.allocate(layout), - |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, - ) - } - } - - /// Copy elements from slice into newly allocated `Rc<[T]>` - /// - /// Unsafe because the caller must either take ownership or bind `T: Copy` - #[cfg(not(no_global_oom_handling))] - unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { - unsafe { - let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping(v.as_ptr(), (&raw mut (*ptr).value) as *mut T, v.len()); - Self::from_ptr(ptr) - } - } - - /// Constructs an `Rc<[T]>` from an iterator known to be of a certain size. - /// - /// Behavior is undefined should the size be wrong. - #[cfg(not(no_global_oom_handling))] - unsafe fn from_iter_exact(iter: impl Iterator, len: usize) -> Rc<[T]> { - // Panic guard while cloning T elements. - // In the event of a panic, elements that have been written - // into the new RcInner will be dropped, then the memory freed. - struct Guard { - mem: NonNull, - elems: *mut T, - layout: Layout, - n_elems: usize, - } - - impl Drop for Guard { - fn drop(&mut self) { - unsafe { - let slice = from_raw_parts_mut(self.elems, self.n_elems); - ptr::drop_in_place(slice); - - Global.deallocate(self.mem, self.layout); - } - } - } - - unsafe { - let ptr = Self::allocate_for_slice(len); - - let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value_raw(ptr); - - // Pointer to first element - let elems = (&raw mut (*ptr).value) as *mut T; - - let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; - - for (i, item) in iter.enumerate() { - ptr::write(elems.add(i), item); - guard.n_elems += 1; - } - - // All clear. Forget the guard so it doesn't free the new RcInner. - mem::forget(guard); - - Self::from_ptr(ptr) - } - } -} - -impl Rc<[T], A> { - /// Allocates an `RcInner<[T]>` with the given length. - #[inline] - #[cfg(not(no_global_oom_handling))] - unsafe fn allocate_for_slice_in(len: usize, alloc: &A) -> *mut RcInner<[T]> { - unsafe { - Rc::<[T]>::allocate_for_layout( - Layout::array::(len).unwrap(), - |layout| alloc.allocate(layout), - |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, - ) - } - } -} - -#[cfg(not(no_global_oom_handling))] -/// Specialization trait used for `From<&[T]>`. -trait RcFromSlice { - fn from_slice(slice: &[T]) -> Self; -} - -#[cfg(not(no_global_oom_handling))] -impl RcFromSlice for Rc<[T]> { - #[inline] - default fn from_slice(v: &[T]) -> Self { - unsafe { Self::from_iter_exact(v.iter().cloned(), v.len()) } - } -} - -#[cfg(not(no_global_oom_handling))] -impl RcFromSlice for Rc<[T]> { - #[inline] - fn from_slice(v: &[T]) -> Self { - unsafe { Rc::copy_from_slice(v) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Rc { - type Target = T; - - #[inline(always)] - fn deref(&self) -> &T { - &self.inner().value - } -} - -#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] -unsafe impl PinCoerceUnsized for Rc {} - -//#[unstable(feature = "unique_rc_arc", issue = "112566")] -#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] -unsafe impl PinCoerceUnsized for UniqueRc {} - -#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] -unsafe impl PinCoerceUnsized for Weak {} - -#[unstable(feature = "deref_pure_trait", issue = "87121")] -unsafe impl DerefPure for Rc {} - -//#[unstable(feature = "unique_rc_arc", issue = "112566")] -#[unstable(feature = "deref_pure_trait", issue = "87121")] -unsafe impl DerefPure for UniqueRc {} - -#[unstable(feature = "legacy_receiver_trait", issue = "none")] -impl LegacyReceiver for Rc {} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc { - /// Drops the `Rc`. - /// - /// This will decrement the strong reference count. If the strong reference - /// count reaches zero then the only other references (if any) are - /// [`Weak`], so we `drop` the inner value. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// struct Foo; - /// - /// impl Drop for Foo { - /// fn drop(&mut self) { - /// println!("dropped!"); - /// } - /// } - /// - /// let foo = Rc::new(Foo); - /// let foo2 = Rc::clone(&foo); - /// - /// drop(foo); // Doesn't print anything - /// drop(foo2); // Prints "dropped!" - /// ``` - #[inline] - fn drop(&mut self) { - unsafe { - self.inner().dec_strong(); - if self.inner().strong() == 0 { - self.drop_slow(); - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Rc { - /// Makes a clone of the `Rc` pointer. - /// - /// This creates another pointer to the same allocation, increasing the - /// strong reference count. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// let _ = Rc::clone(&five); - /// ``` - #[inline] - fn clone(&self) -> Self { - unsafe { - self.inner().inc_strong(); - Self::from_inner_in(self.ptr, self.alloc.clone()) - } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for Rc { - /// Creates a new `Rc`, with the `Default` value for `T`. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x: Rc = Default::default(); - /// assert_eq!(*x, 0); - /// ``` - #[inline] - fn default() -> Rc { - unsafe { - Self::from_inner( - Box::leak(Box::write( - Box::new_uninit(), - RcInner { strong: Cell::new(1), weak: Cell::new(1), value: T::default() }, - )) - .into(), - ) - } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "more_rc_default_impls", since = "1.80.0")] -impl Default for Rc { - /// Creates an empty str inside an Rc - /// - /// This may or may not share an allocation with other Rcs on the same thread. - #[inline] - fn default() -> Self { - let rc = Rc::<[u8]>::default(); - // `[u8]` has the same layout as `str`. - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const str) } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "more_rc_default_impls", since = "1.80.0")] -impl Default for Rc<[T]> { - /// Creates an empty `[T]` inside an Rc - /// - /// This may or may not share an allocation with other Rcs on the same thread. - #[inline] - fn default() -> Self { - let arr: [T; 0] = []; - Rc::from(arr) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -trait RcEqIdent { - fn eq(&self, other: &Rc) -> bool; - fn ne(&self, other: &Rc) -> bool; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl RcEqIdent for Rc { - #[inline] - default fn eq(&self, other: &Rc) -> bool { - **self == **other - } - - #[inline] - default fn ne(&self, other: &Rc) -> bool { - **self != **other - } -} - -// Hack to allow specializing on `Eq` even though `Eq` has a method. -#[rustc_unsafe_specialization_marker] -pub(crate) trait MarkerEq: PartialEq {} - -impl MarkerEq for T {} - -/// We're doing this specialization here, and not as a more general optimization on `&T`, because it -/// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to -/// store large values, that are slow to clone, but also heavy to check for equality, causing this -/// cost to pay off more easily. It's also more likely to have two `Rc` clones, that point to -/// the same value, than two `&T`s. -/// -/// We can only do this when `T: Eq` as a `PartialEq` might be deliberately irreflexive. -#[stable(feature = "rust1", since = "1.0.0")] -impl RcEqIdent for Rc { - #[inline] - fn eq(&self, other: &Rc) -> bool { - Rc::ptr_eq(self, other) || **self == **other - } - - #[inline] - fn ne(&self, other: &Rc) -> bool { - !Rc::ptr_eq(self, other) && **self != **other - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Rc { - /// Equality for two `Rc`s. - /// - /// Two `Rc`s are equal if their inner values are equal, even if they are - /// stored in different allocation. - /// - /// If `T` also implements `Eq` (implying reflexivity of equality), - /// two `Rc`s that point to the same allocation are - /// always equal. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five == Rc::new(5)); - /// ``` - #[inline] - fn eq(&self, other: &Rc) -> bool { - RcEqIdent::eq(self, other) - } - - /// Inequality for two `Rc`s. - /// - /// Two `Rc`s are not equal if their inner values are not equal. - /// - /// If `T` also implements `Eq` (implying reflexivity of equality), - /// two `Rc`s that point to the same allocation are - /// always equal. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five != Rc::new(6)); - /// ``` - #[inline] - fn ne(&self, other: &Rc) -> bool { - RcEqIdent::ne(self, other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Rc {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Rc { - /// Partial comparison for two `Rc`s. - /// - /// The two are compared by calling `partial_cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// use std::cmp::Ordering; - /// - /// let five = Rc::new(5); - /// - /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Rc::new(6))); - /// ``` - #[inline(always)] - fn partial_cmp(&self, other: &Rc) -> Option { - (**self).partial_cmp(&**other) - } - - /// Less-than comparison for two `Rc`s. - /// - /// The two are compared by calling `<` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five < Rc::new(6)); - /// ``` - #[inline(always)] - fn lt(&self, other: &Rc) -> bool { - **self < **other - } - - /// 'Less than or equal to' comparison for two `Rc`s. - /// - /// The two are compared by calling `<=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five <= Rc::new(5)); - /// ``` - #[inline(always)] - fn le(&self, other: &Rc) -> bool { - **self <= **other - } - - /// Greater-than comparison for two `Rc`s. - /// - /// The two are compared by calling `>` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five > Rc::new(4)); - /// ``` - #[inline(always)] - fn gt(&self, other: &Rc) -> bool { - **self > **other - } - - /// 'Greater than or equal to' comparison for two `Rc`s. - /// - /// The two are compared by calling `>=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five >= Rc::new(5)); - /// ``` - #[inline(always)] - fn ge(&self, other: &Rc) -> bool { - **self >= **other - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Rc { - /// Comparison for two `Rc`s. - /// - /// The two are compared by calling `cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// use std::cmp::Ordering; - /// - /// let five = Rc::new(5); - /// - /// assert_eq!(Ordering::Less, five.cmp(&Rc::new(6))); - /// ``` - #[inline] - fn cmp(&self, other: &Rc) -> Ordering { - (**self).cmp(&**other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Rc { - fn hash(&self, state: &mut H) { - (**self).hash(state); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Rc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Rc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Pointer for Rc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&(&raw const **self), f) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "from_for_ptrs", since = "1.6.0")] -impl From for Rc { - /// Converts a generic type `T` into an `Rc` - /// - /// The conversion allocates on the heap and moves `t` - /// from the stack into it. - /// - /// # Example - /// ```rust - /// # use std::rc::Rc; - /// let x = 5; - /// let rc = Rc::new(5); - /// - /// assert_eq!(Rc::from(x), rc); - /// ``` - fn from(t: T) -> Self { - Rc::new(t) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_array", since = "1.74.0")] -impl From<[T; N]> for Rc<[T]> { - /// Converts a [`[T; N]`](prim@array) into an `Rc<[T]>`. - /// - /// The conversion moves the array into a newly allocated `Rc`. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let original: [i32; 3] = [1, 2, 3]; - /// let shared: Rc<[i32]> = Rc::from(original); - /// assert_eq!(&[1, 2, 3], &shared[..]); - /// ``` - #[inline] - fn from(v: [T; N]) -> Rc<[T]> { - Rc::<[T; N]>::from(v) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From<&[T]> for Rc<[T]> { - /// Allocates a reference-counted slice and fills it by cloning `v`'s items. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let original: &[i32] = &[1, 2, 3]; - /// let shared: Rc<[i32]> = Rc::from(original); - /// assert_eq!(&[1, 2, 3], &shared[..]); - /// ``` - #[inline] - fn from(v: &[T]) -> Rc<[T]> { - >::from_slice(v) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] -impl From<&mut [T]> for Rc<[T]> { - /// Allocates a reference-counted slice and fills it by cloning `v`'s items. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let mut original = [1, 2, 3]; - /// let original: &mut [i32] = &mut original; - /// let shared: Rc<[i32]> = Rc::from(original); - /// assert_eq!(&[1, 2, 3], &shared[..]); - /// ``` - #[inline] - fn from(v: &mut [T]) -> Rc<[T]> { - Rc::from(&*v) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From<&str> for Rc { - /// Allocates a reference-counted string slice and copies `v` into it. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let shared: Rc = Rc::from("statue"); - /// assert_eq!("statue", &shared[..]); - /// ``` - #[inline] - fn from(v: &str) -> Rc { - let rc = Rc::<[u8]>::from(v.as_bytes()); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const str) } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] -impl From<&mut str> for Rc { - /// Allocates a reference-counted string slice and copies `v` into it. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let mut original = String::from("statue"); - /// let original: &mut str = &mut original; - /// let shared: Rc = Rc::from(original); - /// assert_eq!("statue", &shared[..]); - /// ``` - #[inline] - fn from(v: &mut str) -> Rc { - Rc::from(&*v) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From for Rc { - /// Allocates a reference-counted string slice and copies `v` into it. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let original: String = "statue".to_owned(); - /// let shared: Rc = Rc::from(original); - /// assert_eq!("statue", &shared[..]); - /// ``` - #[inline] - fn from(v: String) -> Rc { - Rc::from(&v[..]) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From> for Rc { - /// Move a boxed object to a new, reference counted, allocation. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let original: Box = Box::new(1); - /// let shared: Rc = Rc::from(original); - /// assert_eq!(1, *shared); - /// ``` - #[inline] - fn from(v: Box) -> Rc { - Rc::from_box_in(v) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From> for Rc<[T], A> { - /// Allocates a reference-counted slice and moves `v`'s items into it. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let unique: Vec = vec![1, 2, 3]; - /// let shared: Rc<[i32]> = Rc::from(unique); - /// assert_eq!(&[1, 2, 3], &shared[..]); - /// ``` - #[inline] - fn from(v: Vec) -> Rc<[T], A> { - unsafe { - let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); - - let rc_ptr = Self::allocate_for_slice_in(len, &alloc); - ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).value) as *mut T, len); - - // Create a `Vec` with length 0, to deallocate the buffer - // without dropping its contents or the allocator - let _ = Vec::from_raw_parts_in(vec_ptr, 0, cap, &alloc); - - Self::from_ptr_in(rc_ptr, alloc) - } - } -} - -#[stable(feature = "shared_from_cow", since = "1.45.0")] -impl<'a, B> From> for Rc -where - B: ToOwned + ?Sized, - Rc: From<&'a B> + From, -{ - /// Creates a reference-counted pointer from a clone-on-write pointer by - /// copying its content. - /// - /// # Example - /// - /// ```rust - /// # use std::rc::Rc; - /// # use std::borrow::Cow; - /// let cow: Cow<'_, str> = Cow::Borrowed("eggplant"); - /// let shared: Rc = Rc::from(cow); - /// assert_eq!("eggplant", &shared[..]); - /// ``` - #[inline] - fn from(cow: Cow<'a, B>) -> Rc { - match cow { - Cow::Borrowed(s) => Rc::from(s), - Cow::Owned(s) => Rc::from(s), - } - } -} - -#[stable(feature = "shared_from_str", since = "1.62.0")] -impl From> for Rc<[u8]> { - /// Converts a reference-counted string slice into a byte slice. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let string: Rc = Rc::from("eggplant"); - /// let bytes: Rc<[u8]> = Rc::from(string); - /// assert_eq!("eggplant".as_bytes(), bytes.as_ref()); - /// ``` - #[inline] - fn from(rc: Rc) -> Self { - // SAFETY: `str` has the same layout as `[u8]`. - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const [u8]) } - } -} - -#[stable(feature = "boxed_slice_try_from", since = "1.43.0")] -impl TryFrom> for Rc<[T; N], A> { - type Error = Rc<[T], A>; - - fn try_from(boxed_slice: Rc<[T], A>) -> Result { - if boxed_slice.len() == N { - let (ptr, alloc) = Rc::into_inner_with_allocator(boxed_slice); - Ok(unsafe { Rc::from_inner_in(ptr.cast(), alloc) }) - } else { - Err(boxed_slice) - } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_iter", since = "1.37.0")] -impl FromIterator for Rc<[T]> { - /// Takes each element in the `Iterator` and collects it into an `Rc<[T]>`. - /// - /// # Performance characteristics - /// - /// ## The general case - /// - /// In the general case, collecting into `Rc<[T]>` is done by first - /// collecting into a `Vec`. That is, when writing the following: - /// - /// ```rust - /// # use std::rc::Rc; - /// let evens: Rc<[u8]> = (0..10).filter(|&x| x % 2 == 0).collect(); - /// # assert_eq!(&*evens, &[0, 2, 4, 6, 8]); - /// ``` - /// - /// this behaves as if we wrote: - /// - /// ```rust - /// # use std::rc::Rc; - /// let evens: Rc<[u8]> = (0..10).filter(|&x| x % 2 == 0) - /// .collect::>() // The first set of allocations happens here. - /// .into(); // A second allocation for `Rc<[T]>` happens here. - /// # assert_eq!(&*evens, &[0, 2, 4, 6, 8]); - /// ``` - /// - /// This will allocate as many times as needed for constructing the `Vec` - /// and then it will allocate once for turning the `Vec` into the `Rc<[T]>`. - /// - /// ## Iterators of known length - /// - /// When your `Iterator` implements `TrustedLen` and is of an exact size, - /// a single allocation will be made for the `Rc<[T]>`. For example: - /// - /// ```rust - /// # use std::rc::Rc; - /// let evens: Rc<[u8]> = (0..10).collect(); // Just a single allocation happens here. - /// # assert_eq!(&*evens, &*(0..10).collect::>()); - /// ``` - fn from_iter>(iter: I) -> Self { - ToRcSlice::to_rc_slice(iter.into_iter()) - } -} - -/// Specialization trait used for collecting into `Rc<[T]>`. -#[cfg(not(no_global_oom_handling))] -trait ToRcSlice: Iterator + Sized { - fn to_rc_slice(self) -> Rc<[T]>; -} - -#[cfg(not(no_global_oom_handling))] -impl> ToRcSlice for I { - default fn to_rc_slice(self) -> Rc<[T]> { - self.collect::>().into() - } -} - -#[cfg(not(no_global_oom_handling))] -impl> ToRcSlice for I { - fn to_rc_slice(self) -> Rc<[T]> { - // This is the case for a `TrustedLen` iterator. - let (low, high) = self.size_hint(); - if let Some(high) = high { - debug_assert_eq!( - low, - high, - "TrustedLen iterator's size hint is not exact: {:?}", - (low, high) - ); - - unsafe { - // SAFETY: We need to ensure that the iterator has an exact length and we have. - Rc::from_iter_exact(self, low) - } - } else { - // TrustedLen contract guarantees that `upper_bound == None` implies an iterator - // length exceeding `usize::MAX`. - // The default implementation would collect into a vec which would panic. - // Thus we panic here immediately without invoking `Vec` code. - panic!("capacity overflow"); - } - } -} - -/// `Weak` is a version of [`Rc`] that holds a non-owning reference to the -/// managed allocation. -/// -/// The allocation is accessed by calling [`upgrade`] on the `Weak` -/// pointer, which returns an [Option]<[Rc]\>. -/// -/// Since a `Weak` reference does not count towards ownership, it will not -/// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no -/// guarantees about the value still being present. Thus it may return [`None`] -/// when [`upgrade`]d. Note however that a `Weak` reference *does* prevent the allocation -/// itself (the backing store) from being deallocated. -/// -/// A `Weak` pointer is useful for keeping a temporary reference to the allocation -/// managed by [`Rc`] without preventing its inner value from being dropped. It is also used to -/// prevent circular references between [`Rc`] pointers, since mutual owning references -/// would never allow either [`Rc`] to be dropped. For example, a tree could -/// have strong [`Rc`] pointers from parent nodes to children, and `Weak` -/// pointers from children back to their parents. -/// -/// The typical way to obtain a `Weak` pointer is to call [`Rc::downgrade`]. -/// -/// [`upgrade`]: Weak::upgrade -#[stable(feature = "rc_weak", since = "1.4.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "RcWeak")] -pub struct Weak< - T: ?Sized, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> { - // This is a `NonNull` to allow optimizing the size of this type in enums, - // but it is not necessarily a valid pointer. - // `Weak::new` sets this to `usize::MAX` so that it doesn’t need - // to allocate space on the heap. That's not a value a real pointer - // will ever have because RcInner has alignment at least 2. - // This is only possible when `T: Sized`; unsized `T` never dangle. - ptr: NonNull>, - alloc: A, -} - -#[stable(feature = "rc_weak", since = "1.4.0")] -impl !Send for Weak {} -#[stable(feature = "rc_weak", since = "1.4.0")] -impl !Sync for Weak {} - -#[unstable(feature = "coerce_unsized", issue = "18598")] -impl, U: ?Sized, A: Allocator> CoerceUnsized> for Weak {} - -#[unstable(feature = "dispatch_from_dyn", issue = "none")] -impl, U: ?Sized> DispatchFromDyn> for Weak {} - -impl Weak { - /// Constructs a new `Weak`, without allocating any memory. - /// Calling [`upgrade`] on the return value always gives [`None`]. - /// - /// [`upgrade`]: Weak::upgrade - /// - /// # Examples - /// - /// ``` - /// use std::rc::Weak; - /// - /// let empty: Weak = Weak::new(); - /// assert!(empty.upgrade().is_none()); - /// ``` - #[inline] - #[stable(feature = "downgraded_weak", since = "1.10.0")] - #[rustc_const_stable(feature = "const_weak_new", since = "1.73.0")] - #[must_use] - pub const fn new() -> Weak { - Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc: Global } - } -} - -impl Weak { - /// Constructs a new `Weak`, without allocating any memory, technically in the provided - /// allocator. - /// Calling [`upgrade`] on the return value always gives [`None`]. - /// - /// [`upgrade`]: Weak::upgrade - /// - /// # Examples - /// - /// ``` - /// use std::rc::Weak; - /// - /// let empty: Weak = Weak::new(); - /// assert!(empty.upgrade().is_none()); - /// ``` - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn new_in(alloc: A) -> Weak { - Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc } - } -} - -pub(crate) fn is_dangling(ptr: *const T) -> bool { - (ptr.cast::<()>()).addr() == usize::MAX -} - -/// Helper type to allow accessing the reference counts without -/// making any assertions about the data field. -struct WeakInner<'a> { - weak: &'a Cell, - strong: &'a Cell, -} - -impl Weak { - /// Converts a raw pointer previously created by [`into_raw`] back into `Weak`. - /// - /// This can be used to safely get a strong reference (by calling [`upgrade`] - /// later) or to deallocate the weak count by dropping the `Weak`. - /// - /// It takes ownership of one weak reference (with the exception of pointers created by [`new`], - /// as these don't own anything; the method still works on them). - /// - /// # Safety - /// - /// The pointer must have originated from the [`into_raw`] and must still own its potential - /// weak reference, and `ptr` must point to a block of memory allocated by the global allocator. - /// - /// It is allowed for the strong count to be 0 at the time of calling this. Nevertheless, this - /// takes ownership of one weak reference currently represented as a raw pointer (the weak - /// count is not modified by this operation) and therefore it must be paired with a previous - /// call to [`into_raw`]. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let strong = Rc::new("hello".to_owned()); - /// - /// let raw_1 = Rc::downgrade(&strong).into_raw(); - /// let raw_2 = Rc::downgrade(&strong).into_raw(); - /// - /// assert_eq!(2, Rc::weak_count(&strong)); - /// - /// assert_eq!("hello", &*unsafe { Weak::from_raw(raw_1) }.upgrade().unwrap()); - /// assert_eq!(1, Rc::weak_count(&strong)); - /// - /// drop(strong); - /// - /// // Decrement the last weak count. - /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none()); - /// ``` - /// - /// [`into_raw`]: Weak::into_raw - /// [`upgrade`]: Weak::upgrade - /// [`new`]: Weak::new - #[inline] - #[stable(feature = "weak_into_raw", since = "1.45.0")] - pub unsafe fn from_raw(ptr: *const T) -> Self { - unsafe { Self::from_raw_in(ptr, Global) } - } -} - -impl Weak { - /// Returns a reference to the underlying allocator. - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn allocator(&self) -> &A { - &self.alloc - } - - /// Returns a raw pointer to the object `T` pointed to by this `Weak`. - /// - /// The pointer is valid only if there are some strong references. The pointer may be dangling, - /// unaligned or even [`null`] otherwise. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// use std::ptr; - /// - /// let strong = Rc::new("hello".to_owned()); - /// let weak = Rc::downgrade(&strong); - /// // Both point to the same object - /// assert!(ptr::eq(&*strong, weak.as_ptr())); - /// // The strong here keeps it alive, so we can still access the object. - /// assert_eq!("hello", unsafe { &*weak.as_ptr() }); - /// - /// drop(strong); - /// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to - /// // undefined behavior. - /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); - /// ``` - /// - /// [`null`]: ptr::null - #[must_use] - #[stable(feature = "rc_as_ptr", since = "1.45.0")] - pub fn as_ptr(&self) -> *const T { - let ptr: *mut RcInner = NonNull::as_ptr(self.ptr); - - if is_dangling(ptr) { - // If the pointer is dangling, we return the sentinel directly. This cannot be - // a valid payload address, as the payload is at least as aligned as RcInner (usize). - ptr as *const T - } else { - // SAFETY: if is_dangling returns false, then the pointer is dereferenceable. - // The payload may be dropped at this point, and we have to maintain provenance, - // so use raw pointer manipulation. - unsafe { &raw mut (*ptr).value } - } - } - - /// Consumes the `Weak` and turns it into a raw pointer. - /// - /// This converts the weak pointer into a raw pointer, while still preserving the ownership of - /// one weak reference (the weak count is not modified by this operation). It can be turned - /// back into the `Weak` with [`from_raw`]. - /// - /// The same restrictions of accessing the target of the pointer as with - /// [`as_ptr`] apply. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let strong = Rc::new("hello".to_owned()); - /// let weak = Rc::downgrade(&strong); - /// let raw = weak.into_raw(); - /// - /// assert_eq!(1, Rc::weak_count(&strong)); - /// assert_eq!("hello", unsafe { &*raw }); - /// - /// drop(unsafe { Weak::from_raw(raw) }); - /// assert_eq!(0, Rc::weak_count(&strong)); - /// ``` - /// - /// [`from_raw`]: Weak::from_raw - /// [`as_ptr`]: Weak::as_ptr - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "weak_into_raw", since = "1.45.0")] - pub fn into_raw(self) -> *const T { - mem::ManuallyDrop::new(self).as_ptr() - } - - /// Consumes the `Weak`, returning the wrapped pointer and allocator. - /// - /// This converts the weak pointer into a raw pointer, while still preserving the ownership of - /// one weak reference (the weak count is not modified by this operation). It can be turned - /// back into the `Weak` with [`from_raw_in`]. - /// - /// The same restrictions of accessing the target of the pointer as with - /// [`as_ptr`] apply. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// use std::rc::{Rc, Weak}; - /// use std::alloc::System; - /// - /// let strong = Rc::new_in("hello".to_owned(), System); - /// let weak = Rc::downgrade(&strong); - /// let (raw, alloc) = weak.into_raw_with_allocator(); - /// - /// assert_eq!(1, Rc::weak_count(&strong)); - /// assert_eq!("hello", unsafe { &*raw }); - /// - /// drop(unsafe { Weak::from_raw_in(raw, alloc) }); - /// assert_eq!(0, Rc::weak_count(&strong)); - /// ``` - /// - /// [`from_raw_in`]: Weak::from_raw_in - /// [`as_ptr`]: Weak::as_ptr - #[must_use = "losing the pointer will leak memory"] - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn into_raw_with_allocator(self) -> (*const T, A) { - let this = mem::ManuallyDrop::new(self); - let result = this.as_ptr(); - // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped - let alloc = unsafe { ptr::read(&this.alloc) }; - (result, alloc) - } - - /// Converts a raw pointer previously created by [`into_raw`] back into `Weak`. - /// - /// This can be used to safely get a strong reference (by calling [`upgrade`] - /// later) or to deallocate the weak count by dropping the `Weak`. - /// - /// It takes ownership of one weak reference (with the exception of pointers created by [`new`], - /// as these don't own anything; the method still works on them). - /// - /// # Safety - /// - /// The pointer must have originated from the [`into_raw`] and must still own its potential - /// weak reference, and `ptr` must point to a block of memory allocated by `alloc`. - /// - /// It is allowed for the strong count to be 0 at the time of calling this. Nevertheless, this - /// takes ownership of one weak reference currently represented as a raw pointer (the weak - /// count is not modified by this operation) and therefore it must be paired with a previous - /// call to [`into_raw`]. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let strong = Rc::new("hello".to_owned()); - /// - /// let raw_1 = Rc::downgrade(&strong).into_raw(); - /// let raw_2 = Rc::downgrade(&strong).into_raw(); - /// - /// assert_eq!(2, Rc::weak_count(&strong)); - /// - /// assert_eq!("hello", &*unsafe { Weak::from_raw(raw_1) }.upgrade().unwrap()); - /// assert_eq!(1, Rc::weak_count(&strong)); - /// - /// drop(strong); - /// - /// // Decrement the last weak count. - /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none()); - /// ``` - /// - /// [`into_raw`]: Weak::into_raw - /// [`upgrade`]: Weak::upgrade - /// [`new`]: Weak::new - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { - // See Weak::as_ptr for context on how the input pointer is derived. - - let ptr = if is_dangling(ptr) { - // This is a dangling Weak. - ptr as *mut RcInner - } else { - // Otherwise, we're guaranteed the pointer came from a nondangling Weak. - // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. - let offset = unsafe { data_offset(ptr) }; - // Thus, we reverse the offset to get the whole RcInner. - // SAFETY: the pointer originated from a Weak, so this offset is safe. - unsafe { ptr.byte_sub(offset) as *mut RcInner } - }; - - // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. - Weak { ptr: unsafe { NonNull::new_unchecked(ptr) }, alloc } - } - - /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying - /// dropping of the inner value if successful. - /// - /// Returns [`None`] if the inner value has since been dropped. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// let weak_five = Rc::downgrade(&five); - /// - /// let strong_five: Option> = weak_five.upgrade(); - /// assert!(strong_five.is_some()); - /// - /// // Destroy all strong pointers. - /// drop(strong_five); - /// drop(five); - /// - /// assert!(weak_five.upgrade().is_none()); - /// ``` - #[must_use = "this returns a new `Rc`, \ - without modifying the original weak pointer"] - #[stable(feature = "rc_weak", since = "1.4.0")] - pub fn upgrade(&self) -> Option> - where - A: Clone, - { - let inner = self.inner()?; - - if inner.strong() == 0 { - None - } else { - unsafe { - inner.inc_strong(); - Some(Rc::from_inner_in(self.ptr, self.alloc.clone())) - } - } - } - - /// Gets the number of strong (`Rc`) pointers pointing to this allocation. - /// - /// If `self` was created using [`Weak::new`], this will return 0. - #[must_use] - #[stable(feature = "weak_counts", since = "1.41.0")] - pub fn strong_count(&self) -> usize { - if let Some(inner) = self.inner() { inner.strong() } else { 0 } - } - - /// Gets the number of `Weak` pointers pointing to this allocation. - /// - /// If no strong pointers remain, this will return zero. - #[must_use] - #[stable(feature = "weak_counts", since = "1.41.0")] - pub fn weak_count(&self) -> usize { - if let Some(inner) = self.inner() { - if inner.strong() > 0 { - inner.weak() - 1 // subtract the implicit weak ptr - } else { - 0 - } - } else { - 0 - } - } - - /// Returns `None` when the pointer is dangling and there is no allocated `RcInner`, - /// (i.e., when this `Weak` was created by `Weak::new`). - #[inline] - fn inner(&self) -> Option> { - if is_dangling(self.ptr.as_ptr()) { - None - } else { - // We are careful to *not* create a reference covering the "data" field, as - // the field may be mutated concurrently (for example, if the last `Rc` - // is dropped, the data field will be dropped in-place). - Some(unsafe { - let ptr = self.ptr.as_ptr(); - WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } - }) - } - } - - /// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if - /// both don't point to any allocation (because they were created with `Weak::new()`). However, - /// this function ignores the metadata of `dyn Trait` pointers. - /// - /// # Notes - /// - /// Since this compares pointers it means that `Weak::new()` will equal each - /// other, even though they don't point to any allocation. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let first_rc = Rc::new(5); - /// let first = Rc::downgrade(&first_rc); - /// let second = Rc::downgrade(&first_rc); - /// - /// assert!(first.ptr_eq(&second)); - /// - /// let third_rc = Rc::new(5); - /// let third = Rc::downgrade(&third_rc); - /// - /// assert!(!first.ptr_eq(&third)); - /// ``` - /// - /// Comparing `Weak::new`. - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let first = Weak::new(); - /// let second = Weak::new(); - /// assert!(first.ptr_eq(&second)); - /// - /// let third_rc = Rc::new(()); - /// let third = Rc::downgrade(&third_rc); - /// assert!(!first.ptr_eq(&third)); - /// ``` - #[inline] - #[must_use] - #[stable(feature = "weak_ptr_eq", since = "1.39.0")] - pub fn ptr_eq(&self, other: &Self) -> bool { - ptr::addr_eq(self.ptr.as_ptr(), other.ptr.as_ptr()) - } -} - -#[stable(feature = "rc_weak", since = "1.4.0")] -unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Weak { - /// Drops the `Weak` pointer. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// struct Foo; - /// - /// impl Drop for Foo { - /// fn drop(&mut self) { - /// println!("dropped!"); - /// } - /// } - /// - /// let foo = Rc::new(Foo); - /// let weak_foo = Rc::downgrade(&foo); - /// let other_weak_foo = Weak::clone(&weak_foo); - /// - /// drop(weak_foo); // Doesn't print anything - /// drop(foo); // Prints "dropped!" - /// - /// assert!(other_weak_foo.upgrade().is_none()); - /// ``` - fn drop(&mut self) { - let inner = if let Some(inner) = self.inner() { inner } else { return }; - - inner.dec_weak(); - // the weak count starts at 1, and will only go to zero if all - // the strong pointers have disappeared. - if inner.weak() == 0 { - unsafe { - self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); - } - } - } -} - -#[stable(feature = "rc_weak", since = "1.4.0")] -impl Clone for Weak { - /// Makes a clone of the `Weak` pointer that points to the same allocation. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let weak_five = Rc::downgrade(&Rc::new(5)); - /// - /// let _ = Weak::clone(&weak_five); - /// ``` - #[inline] - fn clone(&self) -> Weak { - if let Some(inner) = self.inner() { - inner.inc_weak() - } - Weak { ptr: self.ptr, alloc: self.alloc.clone() } - } -} - -#[stable(feature = "rc_weak", since = "1.4.0")] -impl fmt::Debug for Weak { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "(Weak)") - } -} - -#[stable(feature = "downgraded_weak", since = "1.10.0")] -impl Default for Weak { - /// Constructs a new `Weak`, without allocating any memory. - /// Calling [`upgrade`] on the return value always gives [`None`]. - /// - /// [`upgrade`]: Weak::upgrade - /// - /// # Examples - /// - /// ``` - /// use std::rc::Weak; - /// - /// let empty: Weak = Default::default(); - /// assert!(empty.upgrade().is_none()); - /// ``` - fn default() -> Weak { - Weak::new() - } -} - -// NOTE: We checked_add here to deal with mem::forget safely. In particular -// if you mem::forget Rcs (or Weaks), the ref-count can overflow, and then -// you can free the allocation while outstanding Rcs (or Weaks) exist. -// We abort because this is such a degenerate scenario that we don't care about -// what happens -- no real program should ever experience this. -// -// This should have negligible overhead since you don't actually need to -// clone these much in Rust thanks to ownership and move-semantics. - -#[doc(hidden)] -trait RcInnerPtr { - fn weak_ref(&self) -> &Cell; - fn strong_ref(&self) -> &Cell; - - #[inline] - fn strong(&self) -> usize { - self.strong_ref().get() - } - - #[inline] - fn inc_strong(&self) { - let strong = self.strong(); - - // We insert an `assume` here to hint LLVM at an otherwise - // missed optimization. - // SAFETY: The reference count will never be zero when this is - // called. - unsafe { - hint::assert_unchecked(strong != 0); - } - - let strong = strong.wrapping_add(1); - self.strong_ref().set(strong); - - // We want to abort on overflow instead of dropping the value. - // Checking for overflow after the store instead of before - // allows for slightly better code generation. - if core::intrinsics::unlikely(strong == 0) { - abort(); - } - } - - #[inline] - fn dec_strong(&self) { - self.strong_ref().set(self.strong() - 1); - } - - #[inline] - fn weak(&self) -> usize { - self.weak_ref().get() - } - - #[inline] - fn inc_weak(&self) { - let weak = self.weak(); - - // We insert an `assume` here to hint LLVM at an otherwise - // missed optimization. - // SAFETY: The reference count will never be zero when this is - // called. - unsafe { - hint::assert_unchecked(weak != 0); - } - - let weak = weak.wrapping_add(1); - self.weak_ref().set(weak); - - // We want to abort on overflow instead of dropping the value. - // Checking for overflow after the store instead of before - // allows for slightly better code generation. - if core::intrinsics::unlikely(weak == 0) { - abort(); - } - } - - #[inline] - fn dec_weak(&self) { - self.weak_ref().set(self.weak() - 1); - } -} - -impl RcInnerPtr for RcInner { - #[inline(always)] - fn weak_ref(&self) -> &Cell { - &self.weak - } - - #[inline(always)] - fn strong_ref(&self) -> &Cell { - &self.strong - } -} - -impl<'a> RcInnerPtr for WeakInner<'a> { - #[inline(always)] - fn weak_ref(&self) -> &Cell { - self.weak - } - - #[inline(always)] - fn strong_ref(&self) -> &Cell { - self.strong - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl borrow::Borrow for Rc { - fn borrow(&self) -> &T { - &**self - } -} - -#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] -impl AsRef for Rc { - fn as_ref(&self) -> &T { - &**self - } -} - -#[stable(feature = "pin", since = "1.33.0")] -impl Unpin for Rc {} - -/// Gets the offset within an `RcInner` for the payload behind a pointer. -/// -/// # Safety -/// -/// The pointer must point to (and have valid metadata for) a previously -/// valid instance of T, but the T is allowed to be dropped. -unsafe fn data_offset(ptr: *const T) -> usize { - // Align the unsized value to the end of the RcInner. - // Because RcInner is repr(C), it will always be the last field in memory. - // SAFETY: since the only unsized types possible are slices, trait objects, - // and extern types, the input safety requirement is currently enough to - // satisfy the requirements of align_of_val_raw; this is an implementation - // detail of the language that must not be relied upon outside of std. - unsafe { data_offset_align(align_of_val_raw(ptr)) } -} - -#[inline] -fn data_offset_align(align: usize) -> usize { - let layout = Layout::new::>(); - layout.size() + layout.padding_needed_for(align) -} - -/// A uniquely owned [`Rc`]. -/// -/// This represents an `Rc` that is known to be uniquely owned -- that is, have exactly one strong -/// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong -/// references will fail unless the `UniqueRc` they point to has been converted into a regular `Rc`. -/// -/// Because they are uniquely owned, the contents of a `UniqueRc` can be freely mutated. A common -/// use case is to have an object be mutable during its initialization phase but then have it become -/// immutable and converted to a normal `Rc`. -/// -/// This can be used as a flexible way to create cyclic data structures, as in the example below. -/// -/// ``` -/// #![feature(unique_rc_arc)] -/// use std::rc::{Rc, Weak, UniqueRc}; -/// -/// struct Gadget { -/// #[allow(dead_code)] -/// me: Weak, -/// } -/// -/// fn create_gadget() -> Option> { -/// let mut rc = UniqueRc::new(Gadget { -/// me: Weak::new(), -/// }); -/// rc.me = UniqueRc::downgrade(&rc); -/// Some(UniqueRc::into_rc(rc)) -/// } -/// -/// create_gadget().unwrap(); -/// ``` -/// -/// An advantage of using `UniqueRc` over [`Rc::new_cyclic`] to build cyclic data structures is that -/// [`Rc::new_cyclic`]'s `data_fn` parameter cannot be async or return a [`Result`]. As shown in the -/// previous example, `UniqueRc` allows for more flexibility in the construction of cyclic data, -/// including fallible or async constructors. -#[unstable(feature = "unique_rc_arc", issue = "112566")] -pub struct UniqueRc< - T: ?Sized, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> { - ptr: NonNull>, - // Define the ownership of `RcInner` for drop-check - _marker: PhantomData>, - // Invariance is necessary for soundness: once other `Weak` - // references exist, we already have a form of shared mutability! - _marker2: PhantomData<*mut T>, - alloc: A, -} - -// Not necessary for correctness since `UniqueRc` contains `NonNull`, -// but having an explicit negative impl is nice for documentation purposes -// and results in nicer error messages. -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl !Send for UniqueRc {} - -// Not necessary for correctness since `UniqueRc` contains `NonNull`, -// but having an explicit negative impl is nice for documentation purposes -// and results in nicer error messages. -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl !Sync for UniqueRc {} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl, U: ?Sized, A: Allocator> CoerceUnsized> - for UniqueRc -{ -} - -//#[unstable(feature = "unique_rc_arc", issue = "112566")] -#[unstable(feature = "dispatch_from_dyn", issue = "none")] -impl, U: ?Sized> DispatchFromDyn> for UniqueRc {} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl fmt::Display for UniqueRc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl fmt::Debug for UniqueRc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl fmt::Pointer for UniqueRc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&(&raw const **self), f) - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl borrow::Borrow for UniqueRc { - fn borrow(&self) -> &T { - &**self - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl borrow::BorrowMut for UniqueRc { - fn borrow_mut(&mut self) -> &mut T { - &mut **self - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl AsRef for UniqueRc { - fn as_ref(&self) -> &T { - &**self - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl AsMut for UniqueRc { - fn as_mut(&mut self) -> &mut T { - &mut **self - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Unpin for UniqueRc {} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl PartialEq for UniqueRc { - /// Equality for two `UniqueRc`s. - /// - /// Two `UniqueRc`s are equal if their inner values are equal. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five == UniqueRc::new(5)); - /// ``` - #[inline] - fn eq(&self, other: &Self) -> bool { - PartialEq::eq(&**self, &**other) - } - - /// Inequality for two `UniqueRc`s. - /// - /// Two `UniqueRc`s are not equal if their inner values are not equal. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five != UniqueRc::new(6)); - /// ``` - #[inline] - fn ne(&self, other: &Self) -> bool { - PartialEq::ne(&**self, &**other) - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl PartialOrd for UniqueRc { - /// Partial comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `partial_cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// use std::cmp::Ordering; - /// - /// let five = UniqueRc::new(5); - /// - /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&UniqueRc::new(6))); - /// ``` - #[inline(always)] - fn partial_cmp(&self, other: &UniqueRc) -> Option { - (**self).partial_cmp(&**other) - } - - /// Less-than comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `<` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five < UniqueRc::new(6)); - /// ``` - #[inline(always)] - fn lt(&self, other: &UniqueRc) -> bool { - **self < **other - } - - /// 'Less than or equal to' comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `<=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five <= UniqueRc::new(5)); - /// ``` - #[inline(always)] - fn le(&self, other: &UniqueRc) -> bool { - **self <= **other - } - - /// Greater-than comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `>` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five > UniqueRc::new(4)); - /// ``` - #[inline(always)] - fn gt(&self, other: &UniqueRc) -> bool { - **self > **other - } - - /// 'Greater than or equal to' comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `>=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five >= UniqueRc::new(5)); - /// ``` - #[inline(always)] - fn ge(&self, other: &UniqueRc) -> bool { - **self >= **other - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Ord for UniqueRc { - /// Comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// use std::cmp::Ordering; - /// - /// let five = UniqueRc::new(5); - /// - /// assert_eq!(Ordering::Less, five.cmp(&UniqueRc::new(6))); - /// ``` - #[inline] - fn cmp(&self, other: &UniqueRc) -> Ordering { - (**self).cmp(&**other) - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Eq for UniqueRc {} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Hash for UniqueRc { - fn hash(&self, state: &mut H) { - (**self).hash(state); - } -} - -// Depends on A = Global -impl UniqueRc { - /// Creates a new `UniqueRc`. - /// - /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading - /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. - /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will - /// point to the new [`Rc`]. - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn new(value: T) -> Self { - Self::new_in(value, Global) - } -} - -impl UniqueRc { - /// Creates a new `UniqueRc` in the provided allocator. - /// - /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading - /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. - /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will - /// point to the new [`Rc`]. - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn new_in(value: T, alloc: A) -> Self { - let (ptr, alloc) = Box::into_unique(Box::new_in( - RcInner { - strong: Cell::new(0), - // keep one weak reference so if all the weak pointers that are created are dropped - // the UniqueRc still stays valid. - weak: Cell::new(1), - value, - }, - alloc, - )); - Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc } - } -} - -impl UniqueRc { - /// Converts the `UniqueRc` into a regular [`Rc`]. - /// - /// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that - /// is passed to `into_rc`. - /// - /// Any weak references created before this method is called can now be upgraded to strong - /// references. - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn into_rc(this: Self) -> Rc { - let mut this = ManuallyDrop::new(this); - - // Move the allocator out. - // SAFETY: `this.alloc` will not be accessed again, nor dropped because it is in - // a `ManuallyDrop`. - let alloc: A = unsafe { ptr::read(&this.alloc) }; - - // SAFETY: This pointer was allocated at creation time so we know it is valid. - unsafe { - // Convert our weak reference into a strong reference - this.ptr.as_mut().strong.set(1); - Rc::from_inner_in(this.ptr, alloc) - } - } -} - -impl UniqueRc { - /// Creates a new weak reference to the `UniqueRc`. - /// - /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted - /// to a [`Rc`] using [`UniqueRc::into_rc`]. - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn downgrade(this: &Self) -> Weak { - // SAFETY: This pointer was allocated at creation time and we guarantee that we only have - // one strong reference before converting to a regular Rc. - unsafe { - this.ptr.as_ref().inc_weak(); - } - Weak { ptr: this.ptr, alloc: this.alloc.clone() } - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Deref for UniqueRc { - type Target = T; - - fn deref(&self) -> &T { - // SAFETY: This pointer was allocated at creation time so we know it is valid. - unsafe { &self.ptr.as_ref().value } - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl DerefMut for UniqueRc { - fn deref_mut(&mut self) -> &mut T { - // SAFETY: This pointer was allocated at creation time so we know it is valid. We know we - // have unique ownership and therefore it's safe to make a mutable reference because - // `UniqueRc` owns the only strong reference to itself. - unsafe { &mut (*self.ptr.as_ptr()).value } - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc { - fn drop(&mut self) { - unsafe { - // destroy the contained object - drop_in_place(DerefMut::deref_mut(self)); - - // remove the implicit "strong weak" pointer now that we've destroyed the contents. - self.ptr.as_ref().dec_weak(); - - if self.ptr.as_ref().weak() == 0 { - self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); - } - } - } -} - -/// A unique owning pointer to a [`RcInner`] **that does not imply the contents are initialized,** -/// but will deallocate it (without dropping the value) when dropped. -/// -/// This is a helper for [`Rc::make_mut()`] to ensure correct cleanup on panic. -/// It is nearly a duplicate of `UniqueRc, A>` except that it allows `T: !Sized`, -/// which `MaybeUninit` does not. -#[cfg(not(no_global_oom_handling))] -struct UniqueRcUninit { - ptr: NonNull>, - layout_for_value: Layout, - alloc: Option, -} - -#[cfg(not(no_global_oom_handling))] -impl UniqueRcUninit { - /// Allocates a RcInner with layout suitable to contain `for_value` or a clone of it. - fn new(for_value: &T, alloc: A) -> UniqueRcUninit { - let layout = Layout::for_value(for_value); - let ptr = unsafe { - Rc::allocate_for_layout( - layout, - |layout_for_rc_inner| alloc.allocate(layout_for_rc_inner), - |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcInner), - ) - }; - Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) } - } - - /// Returns the pointer to be written into to initialize the [`Rc`]. - fn data_ptr(&mut self) -> *mut T { - let offset = data_offset_align(self.layout_for_value.align()); - unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } - } - - /// Upgrade this into a normal [`Rc`]. - /// - /// # Safety - /// - /// The data must have been initialized (by writing to [`Self::data_ptr()`]). - unsafe fn into_rc(self) -> Rc { - let mut this = ManuallyDrop::new(self); - let ptr = this.ptr; - let alloc = this.alloc.take().unwrap(); - - // SAFETY: The pointer is valid as per `UniqueRcUninit::new`, and the caller is responsible - // for having initialized the data. - unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) } - } -} - -#[cfg(not(no_global_oom_handling))] -impl Drop for UniqueRcUninit { - fn drop(&mut self) { - // SAFETY: - // * new() produced a pointer safe to deallocate. - // * We own the pointer unless into_rc() was called, which forgets us. - unsafe { - self.alloc.take().unwrap().deallocate( - self.ptr.cast(), - rc_inner_layout_for_value_layout(self.layout_for_value), - ); - } - } -} diff --git a/library/alloc/src/rc/mod.rs b/library/alloc/src/rc/mod.rs new file mode 100644 index 00000000000..09206c2f8b2 --- /dev/null +++ b/library/alloc/src/rc/mod.rs @@ -0,0 +1,4148 @@ +//! Single-threaded reference-counting pointers. 'Rc' stands for 'Reference +//! Counted'. +//! +//! The type [`Rc`][`Rc`] provides shared ownership of a value of type `T`, +//! allocated in the heap. Invoking [`clone`][clone] on [`Rc`] produces a new +//! pointer to the same allocation in the heap. When the last [`Rc`] pointer to a +//! given allocation is destroyed, the value stored in that allocation (often +//! referred to as "inner value") is also dropped. +//! +//! Shared references in Rust disallow mutation by default, and [`Rc`] +//! is no exception: you cannot generally obtain a mutable reference to +//! something inside an [`Rc`]. If you need mutability, put a [`Cell`] +//! or [`RefCell`] inside the [`Rc`]; see [an example of mutability +//! inside an `Rc`][mutability]. +//! +//! [`Rc`] uses non-atomic reference counting. This means that overhead is very +//! low, but an [`Rc`] cannot be sent between threads, and consequently [`Rc`] +//! does not implement [`Send`]. As a result, the Rust compiler +//! will check *at compile time* that you are not sending [`Rc`]s between +//! threads. If you need multi-threaded, atomic reference counting, use +//! [`sync::Arc`][arc]. +//! +//! The [`downgrade`][downgrade] method can be used to create a non-owning +//! [`Weak`] pointer. A [`Weak`] pointer can be [`upgrade`][upgrade]d +//! to an [`Rc`], but this will return [`None`] if the value stored in the allocation has +//! already been dropped. In other words, `Weak` pointers do not keep the value +//! inside the allocation alive; however, they *do* keep the allocation +//! (the backing store for the inner value) alive. +//! +//! A cycle between [`Rc`] pointers will never be deallocated. For this reason, +//! [`Weak`] is used to break cycles. For example, a tree could have strong +//! [`Rc`] pointers from parent nodes to children, and [`Weak`] pointers from +//! children back to their parents. +//! +//! `Rc` automatically dereferences to `T` (via the [`Deref`] trait), +//! so you can call `T`'s methods on a value of type [`Rc`][`Rc`]. To avoid name +//! clashes with `T`'s methods, the methods of [`Rc`][`Rc`] itself are associated +//! functions, called using [fully qualified syntax]: +//! +//! ``` +//! use std::rc::Rc; +//! +//! let my_rc = Rc::new(()); +//! let my_weak = Rc::downgrade(&my_rc); +//! ``` +//! +//! `Rc`'s implementations of traits like `Clone` may also be called using +//! fully qualified syntax. Some people prefer to use fully qualified syntax, +//! while others prefer using method-call syntax. +//! +//! ``` +//! use std::rc::Rc; +//! +//! let rc = Rc::new(()); +//! // Method-call syntax +//! let rc2 = rc.clone(); +//! // Fully qualified syntax +//! let rc3 = Rc::clone(&rc); +//! ``` +//! +//! [`Weak`][`Weak`] does not auto-dereference to `T`, because the inner value may have +//! already been dropped. +//! +//! # Cloning references +//! +//! Creating a new reference to the same allocation as an existing reference counted pointer +//! is done using the `Clone` trait implemented for [`Rc`][`Rc`] and [`Weak`][`Weak`]. +//! +//! ``` +//! use std::rc::Rc; +//! +//! let foo = Rc::new(vec![1.0, 2.0, 3.0]); +//! // The two syntaxes below are equivalent. +//! let a = foo.clone(); +//! let b = Rc::clone(&foo); +//! // a and b both point to the same memory location as foo. +//! ``` +//! +//! The `Rc::clone(&from)` syntax is the most idiomatic because it conveys more explicitly +//! the meaning of the code. In the example above, this syntax makes it easier to see that +//! this code is creating a new reference rather than copying the whole content of foo. +//! +//! # Examples +//! +//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. +//! We want to have our `Gadget`s point to their `Owner`. We can't do this with +//! unique ownership, because more than one gadget may belong to the same +//! `Owner`. [`Rc`] allows us to share an `Owner` between multiple `Gadget`s, +//! and have the `Owner` remain allocated as long as any `Gadget` points at it. +//! +//! ``` +//! use std::rc::Rc; +//! +//! struct Owner { +//! name: String, +//! // ...other fields +//! } +//! +//! struct Gadget { +//! id: i32, +//! owner: Rc, +//! // ...other fields +//! } +//! +//! fn main() { +//! // Create a reference-counted `Owner`. +//! let gadget_owner: Rc = Rc::new( +//! Owner { +//! name: "Gadget Man".to_string(), +//! } +//! ); +//! +//! // Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc` +//! // gives us a new pointer to the same `Owner` allocation, incrementing +//! // the reference count in the process. +//! let gadget1 = Gadget { +//! id: 1, +//! owner: Rc::clone(&gadget_owner), +//! }; +//! let gadget2 = Gadget { +//! id: 2, +//! owner: Rc::clone(&gadget_owner), +//! }; +//! +//! // Dispose of our local variable `gadget_owner`. +//! drop(gadget_owner); +//! +//! // Despite dropping `gadget_owner`, we're still able to print out the name +//! // of the `Owner` of the `Gadget`s. This is because we've only dropped a +//! // single `Rc`, not the `Owner` it points to. As long as there are +//! // other `Rc` pointing at the same `Owner` allocation, it will remain +//! // live. The field projection `gadget1.owner.name` works because +//! // `Rc` automatically dereferences to `Owner`. +//! println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name); +//! println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name); +//! +//! // At the end of the function, `gadget1` and `gadget2` are destroyed, and +//! // with them the last counted references to our `Owner`. Gadget Man now +//! // gets destroyed as well. +//! } +//! ``` +//! +//! If our requirements change, and we also need to be able to traverse from +//! `Owner` to `Gadget`, we will run into problems. An [`Rc`] pointer from `Owner` +//! to `Gadget` introduces a cycle. This means that their +//! reference counts can never reach 0, and the allocation will never be destroyed: +//! a memory leak. In order to get around this, we can use [`Weak`] +//! pointers. +//! +//! Rust actually makes it somewhat difficult to produce this loop in the first +//! place. In order to end up with two values that point at each other, one of +//! them needs to be mutable. This is difficult because [`Rc`] enforces +//! memory safety by only giving out shared references to the value it wraps, +//! and these don't allow direct mutation. We need to wrap the part of the +//! value we wish to mutate in a [`RefCell`], which provides *interior +//! mutability*: a method to achieve mutability through a shared reference. +//! [`RefCell`] enforces Rust's borrowing rules at runtime. +//! +//! ``` +//! use std::rc::Rc; +//! use std::rc::Weak; +//! use std::cell::RefCell; +//! +//! struct Owner { +//! name: String, +//! gadgets: RefCell>>, +//! // ...other fields +//! } +//! +//! struct Gadget { +//! id: i32, +//! owner: Rc, +//! // ...other fields +//! } +//! +//! fn main() { +//! // Create a reference-counted `Owner`. Note that we've put the `Owner`'s +//! // vector of `Gadget`s inside a `RefCell` so that we can mutate it through +//! // a shared reference. +//! let gadget_owner: Rc = Rc::new( +//! Owner { +//! name: "Gadget Man".to_string(), +//! gadgets: RefCell::new(vec![]), +//! } +//! ); +//! +//! // Create `Gadget`s belonging to `gadget_owner`, as before. +//! let gadget1 = Rc::new( +//! Gadget { +//! id: 1, +//! owner: Rc::clone(&gadget_owner), +//! } +//! ); +//! let gadget2 = Rc::new( +//! Gadget { +//! id: 2, +//! owner: Rc::clone(&gadget_owner), +//! } +//! ); +//! +//! // Add the `Gadget`s to their `Owner`. +//! { +//! let mut gadgets = gadget_owner.gadgets.borrow_mut(); +//! gadgets.push(Rc::downgrade(&gadget1)); +//! gadgets.push(Rc::downgrade(&gadget2)); +//! +//! // `RefCell` dynamic borrow ends here. +//! } +//! +//! // Iterate over our `Gadget`s, printing their details out. +//! for gadget_weak in gadget_owner.gadgets.borrow().iter() { +//! +//! // `gadget_weak` is a `Weak`. Since `Weak` pointers can't +//! // guarantee the allocation still exists, we need to call +//! // `upgrade`, which returns an `Option>`. +//! // +//! // In this case we know the allocation still exists, so we simply +//! // `unwrap` the `Option`. In a more complicated program, you might +//! // need graceful error handling for a `None` result. +//! +//! let gadget = gadget_weak.upgrade().unwrap(); +//! println!("Gadget {} owned by {}", gadget.id, gadget.owner.name); +//! } +//! +//! // At the end of the function, `gadget_owner`, `gadget1`, and `gadget2` +//! // are destroyed. There are now no strong (`Rc`) pointers to the +//! // gadgets, so they are destroyed. This zeroes the reference count on +//! // Gadget Man, so he gets destroyed as well. +//! } +//! ``` +//! +//! [clone]: Clone::clone +//! [`Cell`]: core::cell::Cell +//! [`RefCell`]: core::cell::RefCell +//! [arc]: crate::sync::Arc +//! [`Deref`]: core::ops::Deref +//! [downgrade]: Rc::downgrade +//! [upgrade]: Weak::upgrade +//! [mutability]: core::cell#introducing-mutability-inside-of-something-immutable +//! [fully qualified syntax]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name + +#![stable(feature = "rust1", since = "1.0.0")] + +use core::any::Any; +use core::cell::Cell; +#[cfg(not(no_global_oom_handling))] +use core::clone::CloneToUninit; +use core::cmp::Ordering; +use core::hash::{Hash, Hasher}; +use core::intrinsics::abort; +#[cfg(not(no_global_oom_handling))] +use core::iter; +use core::marker::{PhantomData, Unsize}; +use core::mem::{self, ManuallyDrop, align_of_val_raw}; +use core::num::NonZeroUsize; +use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; +use core::panic::{RefUnwindSafe, UnwindSafe}; +#[cfg(not(no_global_oom_handling))] +use core::pin::Pin; +use core::pin::PinCoerceUnsized; +use core::ptr::{self, NonNull, drop_in_place}; +#[cfg(not(no_global_oom_handling))] +use core::slice::from_raw_parts_mut; +use core::{borrow, fmt, hint}; +#[cfg(test)] +use std::boxed::Box; + +#[cfg(not(no_global_oom_handling))] +use crate::alloc::handle_alloc_error; +use crate::alloc::{AllocError, Allocator, Global, Layout}; +use crate::borrow::{Cow, ToOwned}; +#[cfg(not(test))] +use crate::boxed::Box; +#[cfg(not(no_global_oom_handling))] +use crate::string::String; +#[cfg(not(no_global_oom_handling))] +use crate::vec::Vec; + +#[cfg(test)] +mod tests; + +// This is repr(C) to future-proof against possible field-reordering, which +// would interfere with otherwise safe [into|from]_raw() of transmutable +// inner types. +#[repr(C)] +struct RcInner { + strong: Cell, + weak: Cell, + value: T, +} + +/// Calculate layout for `RcInner` using the inner value's layout +fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout { + // Calculate layout using the given value layout. + // Previously, layout was calculated on the expression + // `&*(ptr as *const RcInner)`, but this created a misaligned + // reference (see #54908). + Layout::new::>().extend(layout).unwrap().0.pad_to_align() +} + +/// A single-threaded reference-counting pointer. 'Rc' stands for 'Reference +/// Counted'. +/// +/// See the [module-level documentation](./index.html) for more details. +/// +/// The inherent methods of `Rc` are all associated functions, which means +/// that you have to call them as e.g., [`Rc::get_mut(&mut value)`][get_mut] instead of +/// `value.get_mut()`. This avoids conflicts with methods of the inner type `T`. +/// +/// [get_mut]: Rc::get_mut +#[doc(search_unbox)] +#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] +pub struct Rc< + T: ?Sized, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + ptr: NonNull>, + phantom: PhantomData>, + alloc: A, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl !Send for Rc {} + +// Note that this negative impl isn't strictly necessary for correctness, +// as `Rc` transitively contains a `Cell`, which is itself `!Sync`. +// However, given how important `Rc`'s `!Sync`-ness is, +// having an explicit negative impl is nice for documentation purposes +// and results in nicer error messages. +#[stable(feature = "rust1", since = "1.0.0")] +impl !Sync for Rc {} + +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl UnwindSafe for Rc {} +#[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")] +impl RefUnwindSafe for Rc {} + +#[unstable(feature = "coerce_unsized", issue = "18598")] +impl, U: ?Sized, A: Allocator> CoerceUnsized> for Rc {} + +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +impl, U: ?Sized> DispatchFromDyn> for Rc {} + +impl Rc { + #[inline] + unsafe fn from_inner(ptr: NonNull>) -> Self { + unsafe { Self::from_inner_in(ptr, Global) } + } + + #[inline] + unsafe fn from_ptr(ptr: *mut RcInner) -> Self { + unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) } + } +} + +impl Rc { + #[inline(always)] + fn inner(&self) -> &RcInner { + // This unsafety is ok because while this Rc is alive we're guaranteed + // that the inner pointer is valid. + unsafe { self.ptr.as_ref() } + } + + #[inline] + fn into_inner_with_allocator(this: Self) -> (NonNull>, A) { + let this = mem::ManuallyDrop::new(this); + (this.ptr, unsafe { ptr::read(&this.alloc) }) + } + + #[inline] + unsafe fn from_inner_in(ptr: NonNull>, alloc: A) -> Self { + Self { ptr, phantom: PhantomData, alloc } + } + + #[inline] + unsafe fn from_ptr_in(ptr: *mut RcInner, alloc: A) -> Self { + unsafe { Self::from_inner_in(NonNull::new_unchecked(ptr), alloc) } + } + + // Non-inlined part of `drop`. + #[inline(never)] + unsafe fn drop_slow(&mut self) { + // Reconstruct the "strong weak" pointer and drop it when this + // variable goes out of scope. This ensures that the memory is + // deallocated even if the destructor of `T` panics. + let _weak = Weak { ptr: self.ptr, alloc: &self.alloc }; + + // Destroy the contained object. + // We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed. + unsafe { + ptr::drop_in_place(&mut (*self.ptr.as_ptr()).value); + } + } +} + +impl Rc { + /// Constructs a new `Rc`. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(value: T) -> Rc { + // There is an implicit weak pointer owned by all the strong + // pointers, which ensures that the weak destructor never frees + // the allocation while the strong destructor is running, even + // if the weak pointer is stored inside the strong one. + unsafe { + Self::from_inner( + Box::leak(Box::new(RcInner { strong: Cell::new(1), weak: Cell::new(1), value })) + .into(), + ) + } + } + + /// Constructs a new `Rc` while giving you a `Weak` to the allocation, + /// to allow you to construct a `T` which holds a weak pointer to itself. + /// + /// Generally, a structure circularly referencing itself, either directly or + /// indirectly, should not hold a strong reference to itself to prevent a memory leak. + /// Using this function, you get access to the weak pointer during the + /// initialization of `T`, before the `Rc` is created, such that you can + /// clone and store it inside the `T`. + /// + /// `new_cyclic` first allocates the managed allocation for the `Rc`, + /// then calls your closure, giving it a `Weak` to this allocation, + /// and only afterwards completes the construction of the `Rc` by placing + /// the `T` returned from your closure into the allocation. + /// + /// Since the new `Rc` is not fully-constructed until `Rc::new_cyclic` + /// returns, calling [`upgrade`] on the weak reference inside your closure will + /// fail and result in a `None` value. + /// + /// # Panics + /// + /// If `data_fn` panics, the panic is propagated to the caller, and the + /// temporary [`Weak`] is dropped normally. + /// + /// # Examples + /// + /// ``` + /// # #![allow(dead_code)] + /// use std::rc::{Rc, Weak}; + /// + /// struct Gadget { + /// me: Weak, + /// } + /// + /// impl Gadget { + /// /// Constructs a reference counted Gadget. + /// fn new() -> Rc { + /// // `me` is a `Weak` pointing at the new allocation of the + /// // `Rc` we're constructing. + /// Rc::new_cyclic(|me| { + /// // Create the actual struct here. + /// Gadget { me: me.clone() } + /// }) + /// } + /// + /// /// Returns a reference counted pointer to Self. + /// fn me(&self) -> Rc { + /// self.me.upgrade().unwrap() + /// } + /// } + /// ``` + /// [`upgrade`]: Weak::upgrade + #[cfg(not(no_global_oom_handling))] + #[stable(feature = "arc_new_cyclic", since = "1.60.0")] + pub fn new_cyclic(data_fn: F) -> Rc + where + F: FnOnce(&Weak) -> T, + { + Self::new_cyclic_in(data_fn, Global) + } + + /// Constructs a new `Rc` with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut five = Rc::::new_uninit(); + /// + /// // Deferred initialization: + /// Rc::get_mut(&mut five).unwrap().write(5); + /// + /// let five = unsafe { five.assume_init() }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[stable(feature = "new_uninit", since = "1.82.0")] + #[must_use] + pub fn new_uninit() -> Rc> { + unsafe { + Rc::from_ptr(Rc::allocate_for_layout( + Layout::new::(), + |layout| Global.allocate(layout), + <*mut u8>::cast, + )) + } + } + + /// Constructs a new `Rc` with uninitialized contents, with the memory + /// being filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_zeroed_alloc)] + /// + /// use std::rc::Rc; + /// + /// let zero = Rc::::new_zeroed(); + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "new_zeroed_alloc", issue = "129396")] + #[must_use] + pub fn new_zeroed() -> Rc> { + unsafe { + Rc::from_ptr(Rc::allocate_for_layout( + Layout::new::(), + |layout| Global.allocate_zeroed(layout), + <*mut u8>::cast, + )) + } + } + + /// Constructs a new `Rc`, returning an error if the allocation fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// use std::rc::Rc; + /// + /// let five = Rc::try_new(5); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn try_new(value: T) -> Result, AllocError> { + // There is an implicit weak pointer owned by all the strong + // pointers, which ensures that the weak destructor never frees + // the allocation while the strong destructor is running, even + // if the weak pointer is stored inside the strong one. + unsafe { + Ok(Self::from_inner( + Box::leak(Box::try_new(RcInner { + strong: Cell::new(1), + weak: Cell::new(1), + value, + })?) + .into(), + )) + } + } + + /// Constructs a new `Rc` with uninitialized contents, returning an error if the allocation fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut five = Rc::::try_new_uninit()?; + /// + /// // Deferred initialization: + /// Rc::get_mut(&mut five).unwrap().write(5); + /// + /// let five = unsafe { five.assume_init() }; + /// + /// assert_eq!(*five, 5); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + pub fn try_new_uninit() -> Result>, AllocError> { + unsafe { + Ok(Rc::from_ptr(Rc::try_allocate_for_layout( + Layout::new::(), + |layout| Global.allocate(layout), + <*mut u8>::cast, + )?)) + } + } + + /// Constructs a new `Rc` with uninitialized contents, with the memory + /// being filled with `0` bytes, returning an error if the allocation fails + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// + /// let zero = Rc::::try_new_zeroed()?; + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[unstable(feature = "allocator_api", issue = "32838")] + //#[unstable(feature = "new_uninit", issue = "63291")] + pub fn try_new_zeroed() -> Result>, AllocError> { + unsafe { + Ok(Rc::from_ptr(Rc::try_allocate_for_layout( + Layout::new::(), + |layout| Global.allocate_zeroed(layout), + <*mut u8>::cast, + )?)) + } + } + /// Constructs a new `Pin>`. If `T` does not implement `Unpin`, then + /// `value` will be pinned in memory and unable to be moved. + #[cfg(not(no_global_oom_handling))] + #[stable(feature = "pin", since = "1.33.0")] + #[must_use] + pub fn pin(value: T) -> Pin> { + unsafe { Pin::new_unchecked(Rc::new(value)) } + } +} + +impl Rc { + /// Constructs a new `Rc` in the provided allocator. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let five = Rc::new_in(5, System); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn new_in(value: T, alloc: A) -> Rc { + // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. + // That would make code size bigger. + match Self::try_new_in(value, alloc) { + Ok(m) => m, + Err(_) => handle_alloc_error(Layout::new::>()), + } + } + + /// Constructs a new `Rc` with uninitialized contents in the provided allocator. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let mut five = Rc::::new_uninit_in(System); + /// + /// let five = unsafe { + /// // Deferred initialization: + /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn new_uninit_in(alloc: A) -> Rc, A> { + unsafe { + Rc::from_ptr_in( + Rc::allocate_for_layout( + Layout::new::(), + |layout| alloc.allocate(layout), + <*mut u8>::cast, + ), + alloc, + ) + } + } + + /// Constructs a new `Rc` with uninitialized contents, with the memory + /// being filled with `0` bytes, in the provided allocator. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let zero = Rc::::new_zeroed_in(System); + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn new_zeroed_in(alloc: A) -> Rc, A> { + unsafe { + Rc::from_ptr_in( + Rc::allocate_for_layout( + Layout::new::(), + |layout| alloc.allocate_zeroed(layout), + <*mut u8>::cast, + ), + alloc, + ) + } + } + + /// Constructs a new `Rc` in the given allocator while giving you a `Weak` to the allocation, + /// to allow you to construct a `T` which holds a weak pointer to itself. + /// + /// Generally, a structure circularly referencing itself, either directly or + /// indirectly, should not hold a strong reference to itself to prevent a memory leak. + /// Using this function, you get access to the weak pointer during the + /// initialization of `T`, before the `Rc` is created, such that you can + /// clone and store it inside the `T`. + /// + /// `new_cyclic_in` first allocates the managed allocation for the `Rc`, + /// then calls your closure, giving it a `Weak` to this allocation, + /// and only afterwards completes the construction of the `Rc` by placing + /// the `T` returned from your closure into the allocation. + /// + /// Since the new `Rc` is not fully-constructed until `Rc::new_cyclic_in` + /// returns, calling [`upgrade`] on the weak reference inside your closure will + /// fail and result in a `None` value. + /// + /// # Panics + /// + /// If `data_fn` panics, the panic is propagated to the caller, and the + /// temporary [`Weak`] is dropped normally. + /// + /// # Examples + /// + /// See [`new_cyclic`]. + /// + /// [`new_cyclic`]: Rc::new_cyclic + /// [`upgrade`]: Weak::upgrade + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_cyclic_in(data_fn: F, alloc: A) -> Rc + where + F: FnOnce(&Weak) -> T, + { + // Construct the inner in the "uninitialized" state with a single + // weak reference. + let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in( + RcInner { + strong: Cell::new(0), + weak: Cell::new(1), + value: mem::MaybeUninit::::uninit(), + }, + alloc, + )); + let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into(); + let init_ptr: NonNull> = uninit_ptr.cast(); + + let weak = Weak { ptr: init_ptr, alloc }; + + // It's important we don't give up ownership of the weak pointer, or + // else the memory might be freed by the time `data_fn` returns. If + // we really wanted to pass ownership, we could create an additional + // weak pointer for ourselves, but this would result in additional + // updates to the weak reference count which might not be necessary + // otherwise. + let data = data_fn(&weak); + + let strong = unsafe { + let inner = init_ptr.as_ptr(); + ptr::write(&raw mut (*inner).value, data); + + let prev_value = (*inner).strong.get(); + debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); + (*inner).strong.set(1); + + // Strong references should collectively own a shared weak reference, + // so don't run the destructor for our old weak reference. + // Calling into_raw_with_allocator has the double effect of giving us back the allocator, + // and forgetting the weak reference. + let alloc = weak.into_raw_with_allocator().1; + + Rc::from_inner_in(init_ptr, alloc) + }; + + strong + } + + /// Constructs a new `Rc` in the provided allocator, returning an error if the allocation + /// fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let five = Rc::try_new_in(5, System); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn try_new_in(value: T, alloc: A) -> Result { + // There is an implicit weak pointer owned by all the strong + // pointers, which ensures that the weak destructor never frees + // the allocation while the strong destructor is running, even + // if the weak pointer is stored inside the strong one. + let (ptr, alloc) = Box::into_unique(Box::try_new_in( + RcInner { strong: Cell::new(1), weak: Cell::new(1), value }, + alloc, + )?); + Ok(unsafe { Self::from_inner_in(ptr.into(), alloc) }) + } + + /// Constructs a new `Rc` with uninitialized contents, in the provided allocator, returning an + /// error if the allocation fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let mut five = Rc::::try_new_uninit_in(System)?; + /// + /// let five = unsafe { + /// // Deferred initialization: + /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> { + unsafe { + Ok(Rc::from_ptr_in( + Rc::try_allocate_for_layout( + Layout::new::(), + |layout| alloc.allocate(layout), + <*mut u8>::cast, + )?, + alloc, + )) + } + } + + /// Constructs a new `Rc` with uninitialized contents, with the memory + /// being filled with `0` bytes, in the provided allocator, returning an error if the allocation + /// fails + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let zero = Rc::::try_new_zeroed_in(System)?; + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[unstable(feature = "allocator_api", issue = "32838")] + //#[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> { + unsafe { + Ok(Rc::from_ptr_in( + Rc::try_allocate_for_layout( + Layout::new::(), + |layout| alloc.allocate_zeroed(layout), + <*mut u8>::cast, + )?, + alloc, + )) + } + } + + /// Constructs a new `Pin>` in the provided allocator. If `T` does not implement `Unpin`, then + /// `value` will be pinned in memory and unable to be moved. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn pin_in(value: T, alloc: A) -> Pin + where + A: 'static, + { + unsafe { Pin::new_unchecked(Rc::new_in(value, alloc)) } + } + + /// Returns the inner value, if the `Rc` has exactly one strong reference. + /// + /// Otherwise, an [`Err`] is returned with the same `Rc` that was + /// passed in. + /// + /// This will succeed even if there are outstanding weak references. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new(3); + /// assert_eq!(Rc::try_unwrap(x), Ok(3)); + /// + /// let x = Rc::new(4); + /// let _y = Rc::clone(&x); + /// assert_eq!(*Rc::try_unwrap(x).unwrap_err(), 4); + /// ``` + #[inline] + #[stable(feature = "rc_unique", since = "1.4.0")] + pub fn try_unwrap(this: Self) -> Result { + if Rc::strong_count(&this) == 1 { + let this = ManuallyDrop::new(this); + + let val: T = unsafe { ptr::read(&**this) }; // copy the contained object + let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator + + // Indicate to Weaks that they can't be promoted by decrementing + // the strong count, and then remove the implicit "strong weak" + // pointer while also handling drop logic by just crafting a + // fake Weak. + this.inner().dec_strong(); + let _weak = Weak { ptr: this.ptr, alloc }; + Ok(val) + } else { + Err(this) + } + } + + /// Returns the inner value, if the `Rc` has exactly one strong reference. + /// + /// Otherwise, [`None`] is returned and the `Rc` is dropped. + /// + /// This will succeed even if there are outstanding weak references. + /// + /// If `Rc::into_inner` is called on every clone of this `Rc`, + /// it is guaranteed that exactly one of the calls returns the inner value. + /// This means in particular that the inner value is not dropped. + /// + /// [`Rc::try_unwrap`] is conceptually similar to `Rc::into_inner`. + /// And while they are meant for different use-cases, `Rc::into_inner(this)` + /// is in fact equivalent to [Rc::try_unwrap]\(this).[ok][Result::ok](). + /// (Note that the same kind of equivalence does **not** hold true for + /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`!) + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new(3); + /// assert_eq!(Rc::into_inner(x), Some(3)); + /// + /// let x = Rc::new(4); + /// let y = Rc::clone(&x); + /// + /// assert_eq!(Rc::into_inner(y), None); + /// assert_eq!(Rc::into_inner(x), Some(4)); + /// ``` + #[inline] + #[stable(feature = "rc_into_inner", since = "1.70.0")] + pub fn into_inner(this: Self) -> Option { + Rc::try_unwrap(this).ok() + } +} + +impl Rc<[T]> { + /// Constructs a new reference-counted slice with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut values = Rc::<[u32]>::new_uninit_slice(3); + /// + /// // Deferred initialization: + /// let data = Rc::get_mut(&mut values).unwrap(); + /// data[0].write(1); + /// data[1].write(2); + /// data[2].write(3); + /// + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[stable(feature = "new_uninit", since = "1.82.0")] + #[must_use] + pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit]> { + unsafe { Rc::from_ptr(Rc::allocate_for_slice(len)) } + } + + /// Constructs a new reference-counted slice with uninitialized contents, with the memory being + /// filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_zeroed_alloc)] + /// + /// use std::rc::Rc; + /// + /// let values = Rc::<[u32]>::new_zeroed_slice(3); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "new_zeroed_alloc", issue = "129396")] + #[must_use] + pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit]> { + unsafe { + Rc::from_ptr(Rc::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| Global.allocate_zeroed(layout), + |mem| { + ptr::slice_from_raw_parts_mut(mem.cast::(), len) + as *mut RcInner<[mem::MaybeUninit]> + }, + )) + } + } + + /// Converts the reference-counted slice into a reference-counted array. + /// + /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[unstable(feature = "slice_as_array", issue = "133508")] + #[inline] + #[must_use] + pub fn into_array(self) -> Option> { + if self.len() == N { + let ptr = Self::into_raw(self) as *const [T; N]; + + // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length. + let me = unsafe { Rc::from_raw(ptr) }; + Some(me) + } else { + None + } + } +} + +impl Rc<[T], A> { + /// Constructs a new reference-counted slice with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let mut values = Rc::<[u32], _>::new_uninit_slice_in(3, System); + /// + /// let values = unsafe { + /// // Deferred initialization: + /// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); + /// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); + /// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); + /// + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn new_uninit_slice_in(len: usize, alloc: A) -> Rc<[mem::MaybeUninit], A> { + unsafe { Rc::from_ptr_in(Rc::allocate_for_slice_in(len, &alloc), alloc) } + } + + /// Constructs a new reference-counted slice with uninitialized contents, with the memory being + /// filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let values = Rc::<[u32], _>::new_zeroed_slice_in(3, System); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Rc<[mem::MaybeUninit], A> { + unsafe { + Rc::from_ptr_in( + Rc::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| alloc.allocate_zeroed(layout), + |mem| { + ptr::slice_from_raw_parts_mut(mem.cast::(), len) + as *mut RcInner<[mem::MaybeUninit]> + }, + ), + alloc, + ) + } + } +} + +impl Rc, A> { + /// Converts to `Rc`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the inner value + /// really is in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut five = Rc::::new_uninit(); + /// + /// // Deferred initialization: + /// Rc::get_mut(&mut five).unwrap().write(5); + /// + /// let five = unsafe { five.assume_init() }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[stable(feature = "new_uninit", since = "1.82.0")] + #[inline] + pub unsafe fn assume_init(self) -> Rc { + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + unsafe { Rc::from_inner_in(ptr.cast(), alloc) } + } +} + +impl Rc<[mem::MaybeUninit], A> { + /// Converts to `Rc<[T]>`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the inner value + /// really is in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut values = Rc::<[u32]>::new_uninit_slice(3); + /// + /// // Deferred initialization: + /// let data = Rc::get_mut(&mut values).unwrap(); + /// data[0].write(1); + /// data[1].write(2); + /// data[2].write(3); + /// + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[stable(feature = "new_uninit", since = "1.82.0")] + #[inline] + pub unsafe fn assume_init(self) -> Rc<[T], A> { + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + unsafe { Rc::from_ptr_in(ptr.as_ptr() as _, alloc) } + } +} + +impl Rc { + /// Constructs an `Rc` from a raw pointer. + /// + /// The raw pointer must have been previously returned by a call to + /// [`Rc::into_raw`][into_raw] with the following requirements: + /// + /// * If `U` is sized, it must have the same size and alignment as `T`. This + /// is trivially true if `U` is `T`. + /// * If `U` is unsized, its data pointer must have the same size and + /// alignment as `T`. This is trivially true if `Rc` was constructed + /// through `Rc` and then converted to `Rc` through an [unsized + /// coercion]. + /// + /// Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// + /// The raw pointer must point to a block of memory allocated by the global allocator + /// + /// The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. + /// + /// This function is unsafe because improper use may lead to memory unsafety, + /// even if the returned `Rc` is never accessed. + /// + /// [into_raw]: Rc::into_raw + /// [transmute]: core::mem::transmute + /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new("hello".to_owned()); + /// let x_ptr = Rc::into_raw(x); + /// + /// unsafe { + /// // Convert back to an `Rc` to prevent leak. + /// let x = Rc::from_raw(x_ptr); + /// assert_eq!(&*x, "hello"); + /// + /// // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// ``` + /// + /// Convert a slice back into its original array: + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x: Rc<[u32]> = Rc::new([1, 2, 3]); + /// let x_ptr: *const [u32] = Rc::into_raw(x); + /// + /// unsafe { + /// let x: Rc<[u32; 3]> = Rc::from_raw(x_ptr.cast::<[u32; 3]>()); + /// assert_eq!(&*x, &[1, 2, 3]); + /// } + /// ``` + #[inline] + #[stable(feature = "rc_raw", since = "1.17.0")] + pub unsafe fn from_raw(ptr: *const T) -> Self { + unsafe { Self::from_raw_in(ptr, Global) } + } + + /// Increments the strong reference count on the `Rc` associated with the + /// provided pointer by one. + /// + /// # Safety + /// + /// The pointer must have been obtained through `Rc::into_raw`, the + /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// least 1) for the duration of this method, and `ptr` must point to a block of memory + /// allocated by the global allocator. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// unsafe { + /// let ptr = Rc::into_raw(five); + /// Rc::increment_strong_count(ptr); + /// + /// let five = Rc::from_raw(ptr); + /// assert_eq!(2, Rc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Rc::decrement_strong_count(ptr); + /// } + /// ``` + #[inline] + #[stable(feature = "rc_mutate_strong_count", since = "1.53.0")] + pub unsafe fn increment_strong_count(ptr: *const T) { + unsafe { Self::increment_strong_count_in(ptr, Global) } + } + + /// Decrements the strong reference count on the `Rc` associated with the + /// provided pointer by one. + /// + /// # Safety + /// + /// The pointer must have been obtained through `Rc::into_raw`, the + /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// least 1) when invoking this method, and `ptr` must point to a block of memory + /// allocated by the global allocator. This method can be used to release the final `Rc` and + /// backing storage, but **should not** be called after the final `Rc` has been released. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// unsafe { + /// let ptr = Rc::into_raw(five); + /// Rc::increment_strong_count(ptr); + /// + /// let five = Rc::from_raw(ptr); + /// assert_eq!(2, Rc::strong_count(&five)); + /// Rc::decrement_strong_count(ptr); + /// assert_eq!(1, Rc::strong_count(&five)); + /// } + /// ``` + #[inline] + #[stable(feature = "rc_mutate_strong_count", since = "1.53.0")] + pub unsafe fn decrement_strong_count(ptr: *const T) { + unsafe { Self::decrement_strong_count_in(ptr, Global) } + } +} + +impl Rc { + /// Returns a reference to the underlying allocator. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This + /// is so that there is no conflict with a method on the inner type. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(this: &Self) -> &A { + &this.alloc + } + + /// Consumes the `Rc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Rc` using + /// [`Rc::from_raw`]. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new("hello".to_owned()); + /// let x_ptr = Rc::into_raw(x); + /// assert_eq!(unsafe { &*x_ptr }, "hello"); + /// # // Prevent leaks for Miri. + /// # drop(unsafe { Rc::from_raw(x_ptr) }); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "rc_raw", since = "1.17.0")] + #[rustc_never_returns_null_ptr] + pub fn into_raw(this: Self) -> *const T { + let this = ManuallyDrop::new(this); + Self::as_ptr(&*this) + } + + /// Consumes the `Rc`, returning the wrapped pointer and allocator. + /// + /// To avoid a memory leak the pointer must be converted back to an `Rc` using + /// [`Rc::from_raw_in`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let x = Rc::new_in("hello".to_owned(), System); + /// let (ptr, alloc) = Rc::into_raw_with_allocator(x); + /// assert_eq!(unsafe { &*ptr }, "hello"); + /// let x = unsafe { Rc::from_raw_in(ptr, alloc) }; + /// assert_eq!(&*x, "hello"); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn into_raw_with_allocator(this: Self) -> (*const T, A) { + let this = mem::ManuallyDrop::new(this); + let ptr = Self::as_ptr(&this); + // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped + let alloc = unsafe { ptr::read(&this.alloc) }; + (ptr, alloc) + } + + /// Provides a raw pointer to the data. + /// + /// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid + /// for as long as there are strong counts in the `Rc`. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new(0); + /// let y = Rc::clone(&x); + /// let x_ptr = Rc::as_ptr(&x); + /// assert_eq!(x_ptr, Rc::as_ptr(&y)); + /// assert_eq!(unsafe { *x_ptr }, 0); + /// ``` + #[stable(feature = "weak_into_raw", since = "1.45.0")] + #[rustc_never_returns_null_ptr] + pub fn as_ptr(this: &Self) -> *const T { + let ptr: *mut RcInner = NonNull::as_ptr(this.ptr); + + // SAFETY: This cannot go through Deref::deref or Rc::inner because + // this is required to retain raw/mut provenance such that e.g. `get_mut` can + // write through the pointer after the Rc is recovered through `from_raw`. + unsafe { &raw mut (*ptr).value } + } + + /// Constructs an `Rc` from a raw pointer in the provided allocator. + /// + /// The raw pointer must have been previously returned by a call to [`Rc::into_raw`][into_raw] with the following requirements: + /// + /// * If `U` is sized, it must have the same size and alignment as `T`. This + /// is trivially true if `U` is `T`. + /// * If `U` is unsized, its data pointer must have the same size and + /// alignment as `T`. This is trivially true if `Rc` was constructed + /// through `Rc` and then converted to `Rc` through an [unsized + /// coercion]. + /// + /// Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// + /// The raw pointer must point to a block of memory allocated by `alloc` + /// + /// The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. + /// + /// This function is unsafe because improper use may lead to memory unsafety, + /// even if the returned `Rc` is never accessed. + /// + /// [into_raw]: Rc::into_raw + /// [transmute]: core::mem::transmute + /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let x = Rc::new_in("hello".to_owned(), System); + /// let x_ptr = Rc::into_raw(x); + /// + /// unsafe { + /// // Convert back to an `Rc` to prevent leak. + /// let x = Rc::from_raw_in(x_ptr, System); + /// assert_eq!(&*x, "hello"); + /// + /// // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// ``` + /// + /// Convert a slice back into its original array: + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let x: Rc<[u32], _> = Rc::new_in([1, 2, 3], System); + /// let x_ptr: *const [u32] = Rc::into_raw(x); + /// + /// unsafe { + /// let x: Rc<[u32; 3], _> = Rc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); + /// assert_eq!(&*x, &[1, 2, 3]); + /// } + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { + let offset = unsafe { data_offset(ptr) }; + + // Reverse the offset to find the original RcInner. + let rc_ptr = unsafe { ptr.byte_sub(offset) as *mut RcInner }; + + unsafe { Self::from_ptr_in(rc_ptr, alloc) } + } + + /// Creates a new [`Weak`] pointer to this allocation. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let weak_five = Rc::downgrade(&five); + /// ``` + #[must_use = "this returns a new `Weak` pointer, \ + without modifying the original `Rc`"] + #[stable(feature = "rc_weak", since = "1.4.0")] + pub fn downgrade(this: &Self) -> Weak + where + A: Clone, + { + this.inner().inc_weak(); + // Make sure we do not create a dangling Weak + debug_assert!(!is_dangling(this.ptr.as_ptr())); + Weak { ptr: this.ptr, alloc: this.alloc.clone() } + } + + /// Gets the number of [`Weak`] pointers to this allocation. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// let _weak_five = Rc::downgrade(&five); + /// + /// assert_eq!(1, Rc::weak_count(&five)); + /// ``` + #[inline] + #[stable(feature = "rc_counts", since = "1.15.0")] + pub fn weak_count(this: &Self) -> usize { + this.inner().weak() - 1 + } + + /// Gets the number of strong (`Rc`) pointers to this allocation. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// let _also_five = Rc::clone(&five); + /// + /// assert_eq!(2, Rc::strong_count(&five)); + /// ``` + #[inline] + #[stable(feature = "rc_counts", since = "1.15.0")] + pub fn strong_count(this: &Self) -> usize { + this.inner().strong() + } + + /// Increments the strong reference count on the `Rc` associated with the + /// provided pointer by one. + /// + /// # Safety + /// + /// The pointer must have been obtained through `Rc::into_raw`, the + /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// least 1) for the duration of this method, and `ptr` must point to a block of memory + /// allocated by `alloc` + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let five = Rc::new_in(5, System); + /// + /// unsafe { + /// let ptr = Rc::into_raw(five); + /// Rc::increment_strong_count_in(ptr, System); + /// + /// let five = Rc::from_raw_in(ptr, System); + /// assert_eq!(2, Rc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Rc::decrement_strong_count_in(ptr, System); + /// } + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub unsafe fn increment_strong_count_in(ptr: *const T, alloc: A) + where + A: Clone, + { + // Retain Rc, but don't touch refcount by wrapping in ManuallyDrop + let rc = unsafe { mem::ManuallyDrop::new(Rc::::from_raw_in(ptr, alloc)) }; + // Now increase refcount, but don't drop new refcount either + let _rc_clone: mem::ManuallyDrop<_> = rc.clone(); + } + + /// Decrements the strong reference count on the `Rc` associated with the + /// provided pointer by one. + /// + /// # Safety + /// + /// The pointer must have been obtained through `Rc::into_raw`, the + /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// least 1) when invoking this method, and `ptr` must point to a block of memory + /// allocated by `alloc`. This method can be used to release the final `Rc` and backing storage, + /// but **should not** be called after the final `Rc` has been released. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let five = Rc::new_in(5, System); + /// + /// unsafe { + /// let ptr = Rc::into_raw(five); + /// Rc::increment_strong_count_in(ptr, System); + /// + /// let five = Rc::from_raw_in(ptr, System); + /// assert_eq!(2, Rc::strong_count(&five)); + /// Rc::decrement_strong_count_in(ptr, System); + /// assert_eq!(1, Rc::strong_count(&five)); + /// } + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub unsafe fn decrement_strong_count_in(ptr: *const T, alloc: A) { + unsafe { drop(Rc::from_raw_in(ptr, alloc)) }; + } + + /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to + /// this allocation. + #[inline] + fn is_unique(this: &Self) -> bool { + Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 + } + + /// Returns a mutable reference into the given `Rc`, if there are + /// no other `Rc` or [`Weak`] pointers to the same allocation. + /// + /// Returns [`None`] otherwise, because it is not safe to + /// mutate a shared value. + /// + /// See also [`make_mut`][make_mut], which will [`clone`][clone] + /// the inner value when there are other `Rc` pointers. + /// + /// [make_mut]: Rc::make_mut + /// [clone]: Clone::clone + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let mut x = Rc::new(3); + /// *Rc::get_mut(&mut x).unwrap() = 4; + /// assert_eq!(*x, 4); + /// + /// let _y = Rc::clone(&x); + /// assert!(Rc::get_mut(&mut x).is_none()); + /// ``` + #[inline] + #[stable(feature = "rc_unique", since = "1.4.0")] + pub fn get_mut(this: &mut Self) -> Option<&mut T> { + if Rc::is_unique(this) { unsafe { Some(Rc::get_mut_unchecked(this)) } } else { None } + } + + /// Returns a mutable reference into the given `Rc`, + /// without any check. + /// + /// See also [`get_mut`], which is safe and does appropriate checks. + /// + /// [`get_mut`]: Rc::get_mut + /// + /// # Safety + /// + /// If any other `Rc` or [`Weak`] pointers to the same allocation exist, then + /// they must not be dereferenced or have active borrows for the duration + /// of the returned borrow, and their inner type must be exactly the same as the + /// inner type of this Rc (including lifetimes). This is trivially the case if no + /// such pointers exist, for example immediately after `Rc::new`. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut x = Rc::new(String::new()); + /// unsafe { + /// Rc::get_mut_unchecked(&mut x).push_str("foo") + /// } + /// assert_eq!(*x, "foo"); + /// ``` + /// Other `Rc` pointers to the same allocation must be to the same type. + /// ```no_run + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let x: Rc = Rc::from("Hello, world!"); + /// let mut y: Rc<[u8]> = x.clone().into(); + /// unsafe { + /// // this is Undefined Behavior, because x's inner type is str, not [u8] + /// Rc::get_mut_unchecked(&mut y).fill(0xff); // 0xff is invalid in UTF-8 + /// } + /// println!("{}", &*x); // Invalid UTF-8 in a str + /// ``` + /// Other `Rc` pointers to the same allocation must be to the exact same type, including lifetimes. + /// ```no_run + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let x: Rc<&str> = Rc::new("Hello, world!"); + /// { + /// let s = String::from("Oh, no!"); + /// let mut y: Rc<&str> = x.clone(); + /// unsafe { + /// // this is Undefined Behavior, because x's inner type + /// // is &'long str, not &'short str + /// *Rc::get_mut_unchecked(&mut y) = &s; + /// } + /// } + /// println!("{}", &*x); // Use-after-free + /// ``` + #[inline] + #[unstable(feature = "get_mut_unchecked", issue = "63292")] + pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { + // We are careful to *not* create a reference covering the "count" fields, as + // this would conflict with accesses to the reference counts (e.g. by `Weak`). + unsafe { &mut (*this.ptr.as_ptr()).value } + } + + #[inline] + #[stable(feature = "ptr_eq", since = "1.17.0")] + /// Returns `true` if the two `Rc`s point to the same allocation in a vein similar to + /// [`ptr::eq`]. This function ignores the metadata of `dyn Trait` pointers. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// let same_five = Rc::clone(&five); + /// let other_five = Rc::new(5); + /// + /// assert!(Rc::ptr_eq(&five, &same_five)); + /// assert!(!Rc::ptr_eq(&five, &other_five)); + /// ``` + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + ptr::addr_eq(this.ptr.as_ptr(), other.ptr.as_ptr()) + } +} + +#[cfg(not(no_global_oom_handling))] +impl Rc { + /// Makes a mutable reference into the given `Rc`. + /// + /// If there are other `Rc` pointers to the same allocation, then `make_mut` will + /// [`clone`] the inner value to a new allocation to ensure unique ownership. This is also + /// referred to as clone-on-write. + /// + /// However, if there are no other `Rc` pointers to this allocation, but some [`Weak`] + /// pointers, then the [`Weak`] pointers will be disassociated and the inner value will not + /// be cloned. + /// + /// See also [`get_mut`], which will fail rather than cloning the inner value + /// or disassociating [`Weak`] pointers. + /// + /// [`clone`]: Clone::clone + /// [`get_mut`]: Rc::get_mut + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let mut data = Rc::new(5); + /// + /// *Rc::make_mut(&mut data) += 1; // Won't clone anything + /// let mut other_data = Rc::clone(&data); // Won't clone inner data + /// *Rc::make_mut(&mut data) += 1; // Clones inner data + /// *Rc::make_mut(&mut data) += 1; // Won't clone anything + /// *Rc::make_mut(&mut other_data) *= 2; // Won't clone anything + /// + /// // Now `data` and `other_data` point to different allocations. + /// assert_eq!(*data, 8); + /// assert_eq!(*other_data, 12); + /// ``` + /// + /// [`Weak`] pointers will be disassociated: + /// + /// ``` + /// use std::rc::Rc; + /// + /// let mut data = Rc::new(75); + /// let weak = Rc::downgrade(&data); + /// + /// assert!(75 == *data); + /// assert!(75 == *weak.upgrade().unwrap()); + /// + /// *Rc::make_mut(&mut data) += 1; + /// + /// assert!(76 == *data); + /// assert!(weak.upgrade().is_none()); + /// ``` + #[inline] + #[stable(feature = "rc_unique", since = "1.4.0")] + pub fn make_mut(this: &mut Self) -> &mut T { + let size_of_val = size_of_val::(&**this); + + if Rc::strong_count(this) != 1 { + // Gotta clone the data, there are other Rcs. + + let this_data_ref: &T = &**this; + // `in_progress` drops the allocation if we panic before finishing initializing it. + let mut in_progress: UniqueRcUninit = + UniqueRcUninit::new(this_data_ref, this.alloc.clone()); + + // Initialize with clone of this. + let initialized_clone = unsafe { + // Clone. If the clone panics, `in_progress` will be dropped and clean up. + this_data_ref.clone_to_uninit(in_progress.data_ptr().cast()); + // Cast type of pointer, now that it is initialized. + in_progress.into_rc() + }; + + // Replace `this` with newly constructed Rc. + *this = initialized_clone; + } else if Rc::weak_count(this) != 0 { + // Can just steal the data, all that's left is Weaks + + // We don't need panic-protection like the above branch does, but we might as well + // use the same mechanism. + let mut in_progress: UniqueRcUninit = + UniqueRcUninit::new(&**this, this.alloc.clone()); + unsafe { + // Initialize `in_progress` with move of **this. + // We have to express this in terms of bytes because `T: ?Sized`; there is no + // operation that just copies a value based on its `size_of_val()`. + ptr::copy_nonoverlapping( + ptr::from_ref(&**this).cast::(), + in_progress.data_ptr().cast::(), + size_of_val, + ); + + this.inner().dec_strong(); + // Remove implicit strong-weak ref (no need to craft a fake + // Weak here -- we know other Weaks can clean up for us) + this.inner().dec_weak(); + // Replace `this` with newly constructed Rc that has the moved data. + ptr::write(this, in_progress.into_rc()); + } + } + // This unsafety is ok because we're guaranteed that the pointer + // returned is the *only* pointer that will ever be returned to T. Our + // reference count is guaranteed to be 1 at this point, and we required + // the `Rc` itself to be `mut`, so we're returning the only possible + // reference to the allocation. + unsafe { &mut this.ptr.as_mut().value } + } +} + +impl Rc { + /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the + /// clone. + /// + /// Assuming `rc_t` is of type `Rc`, this function is functionally equivalent to + /// `(*rc_t).clone()`, but will avoid cloning the inner value where possible. + /// + /// # Examples + /// + /// ``` + /// # use std::{ptr, rc::Rc}; + /// let inner = String::from("test"); + /// let ptr = inner.as_ptr(); + /// + /// let rc = Rc::new(inner); + /// let inner = Rc::unwrap_or_clone(rc); + /// // The inner value was not cloned + /// assert!(ptr::eq(ptr, inner.as_ptr())); + /// + /// let rc = Rc::new(inner); + /// let rc2 = rc.clone(); + /// let inner = Rc::unwrap_or_clone(rc); + /// // Because there were 2 references, we had to clone the inner value. + /// assert!(!ptr::eq(ptr, inner.as_ptr())); + /// // `rc2` is the last reference, so when we unwrap it we get back + /// // the original `String`. + /// let inner = Rc::unwrap_or_clone(rc2); + /// assert!(ptr::eq(ptr, inner.as_ptr())); + /// ``` + #[inline] + #[stable(feature = "arc_unwrap_or_clone", since = "1.76.0")] + pub fn unwrap_or_clone(this: Self) -> T { + Rc::try_unwrap(this).unwrap_or_else(|rc| (*rc).clone()) + } +} + +impl Rc { + /// Attempts to downcast the `Rc` to a concrete type. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// use std::rc::Rc; + /// + /// fn print_if_string(value: Rc) { + /// if let Ok(string) = value.downcast::() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// let my_string = "Hello World".to_string(); + /// print_if_string(Rc::new(my_string)); + /// print_if_string(Rc::new(0i8)); + /// ``` + #[inline] + #[stable(feature = "rc_downcast", since = "1.29.0")] + pub fn downcast(self) -> Result, Self> { + if (*self).is::() { + unsafe { + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + Ok(Rc::from_inner_in(ptr.cast(), alloc)) + } + } else { + Err(self) + } + } + + /// Downcasts the `Rc` to a concrete type. + /// + /// For a safe alternative see [`downcast`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// use std::rc::Rc; + /// + /// let x: Rc = Rc::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + /// + /// + /// [`downcast`]: Self::downcast + #[inline] + #[unstable(feature = "downcast_unchecked", issue = "90850")] + pub unsafe fn downcast_unchecked(self) -> Rc { + unsafe { + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + Rc::from_inner_in(ptr.cast(), alloc) + } + } +} + +impl Rc { + /// Allocates an `RcInner` with sufficient space for + /// a possibly-unsized inner value where the value has the layout provided. + /// + /// The function `mem_to_rc_inner` is called with the data pointer + /// and must return back a (potentially fat)-pointer for the `RcInner`. + #[cfg(not(no_global_oom_handling))] + unsafe fn allocate_for_layout( + value_layout: Layout, + allocate: impl FnOnce(Layout) -> Result, AllocError>, + mem_to_rc_inner: impl FnOnce(*mut u8) -> *mut RcInner, + ) -> *mut RcInner { + let layout = rc_inner_layout_for_value_layout(value_layout); + unsafe { + Rc::try_allocate_for_layout(value_layout, allocate, mem_to_rc_inner) + .unwrap_or_else(|_| handle_alloc_error(layout)) + } + } + + /// Allocates an `RcInner` with sufficient space for + /// a possibly-unsized inner value where the value has the layout provided, + /// returning an error if allocation fails. + /// + /// The function `mem_to_rc_inner` is called with the data pointer + /// and must return back a (potentially fat)-pointer for the `RcInner`. + #[inline] + unsafe fn try_allocate_for_layout( + value_layout: Layout, + allocate: impl FnOnce(Layout) -> Result, AllocError>, + mem_to_rc_inner: impl FnOnce(*mut u8) -> *mut RcInner, + ) -> Result<*mut RcInner, AllocError> { + let layout = rc_inner_layout_for_value_layout(value_layout); + + // Allocate for the layout. + let ptr = allocate(layout)?; + + // Initialize the RcInner + let inner = mem_to_rc_inner(ptr.as_non_null_ptr().as_ptr()); + unsafe { + debug_assert_eq!(Layout::for_value_raw(inner), layout); + + (&raw mut (*inner).strong).write(Cell::new(1)); + (&raw mut (*inner).weak).write(Cell::new(1)); + } + + Ok(inner) + } +} + +impl Rc { + /// Allocates an `RcInner` with sufficient space for an unsized inner value + #[cfg(not(no_global_oom_handling))] + unsafe fn allocate_for_ptr_in(ptr: *const T, alloc: &A) -> *mut RcInner { + // Allocate for the `RcInner` using the given value. + unsafe { + Rc::::allocate_for_layout( + Layout::for_value_raw(ptr), + |layout| alloc.allocate(layout), + |mem| mem.with_metadata_of(ptr as *const RcInner), + ) + } + } + + #[cfg(not(no_global_oom_handling))] + fn from_box_in(src: Box) -> Rc { + unsafe { + let value_size = size_of_val(&*src); + let ptr = Self::allocate_for_ptr_in(&*src, Box::allocator(&src)); + + // Copy value as bytes + ptr::copy_nonoverlapping( + (&raw const *src) as *const u8, + (&raw mut (*ptr).value) as *mut u8, + value_size, + ); + + // Free the allocation without dropping its contents + let (bptr, alloc) = Box::into_raw_with_allocator(src); + let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, alloc.by_ref()); + drop(src); + + Self::from_ptr_in(ptr, alloc) + } + } +} + +impl Rc<[T]> { + /// Allocates an `RcInner<[T]>` with the given length. + #[cfg(not(no_global_oom_handling))] + unsafe fn allocate_for_slice(len: usize) -> *mut RcInner<[T]> { + unsafe { + Self::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| Global.allocate(layout), + |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, + ) + } + } + + /// Copy elements from slice into newly allocated `Rc<[T]>` + /// + /// Unsafe because the caller must either take ownership or bind `T: Copy` + #[cfg(not(no_global_oom_handling))] + unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { + unsafe { + let ptr = Self::allocate_for_slice(v.len()); + ptr::copy_nonoverlapping(v.as_ptr(), (&raw mut (*ptr).value) as *mut T, v.len()); + Self::from_ptr(ptr) + } + } + + /// Constructs an `Rc<[T]>` from an iterator known to be of a certain size. + /// + /// Behavior is undefined should the size be wrong. + #[cfg(not(no_global_oom_handling))] + unsafe fn from_iter_exact(iter: impl Iterator, len: usize) -> Rc<[T]> { + // Panic guard while cloning T elements. + // In the event of a panic, elements that have been written + // into the new RcInner will be dropped, then the memory freed. + struct Guard { + mem: NonNull, + elems: *mut T, + layout: Layout, + n_elems: usize, + } + + impl Drop for Guard { + fn drop(&mut self) { + unsafe { + let slice = from_raw_parts_mut(self.elems, self.n_elems); + ptr::drop_in_place(slice); + + Global.deallocate(self.mem, self.layout); + } + } + } + + unsafe { + let ptr = Self::allocate_for_slice(len); + + let mem = ptr as *mut _ as *mut u8; + let layout = Layout::for_value_raw(ptr); + + // Pointer to first element + let elems = (&raw mut (*ptr).value) as *mut T; + + let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; + + for (i, item) in iter.enumerate() { + ptr::write(elems.add(i), item); + guard.n_elems += 1; + } + + // All clear. Forget the guard so it doesn't free the new RcInner. + mem::forget(guard); + + Self::from_ptr(ptr) + } + } +} + +impl Rc<[T], A> { + /// Allocates an `RcInner<[T]>` with the given length. + #[inline] + #[cfg(not(no_global_oom_handling))] + unsafe fn allocate_for_slice_in(len: usize, alloc: &A) -> *mut RcInner<[T]> { + unsafe { + Rc::<[T]>::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| alloc.allocate(layout), + |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, + ) + } + } +} + +#[cfg(not(no_global_oom_handling))] +/// Specialization trait used for `From<&[T]>`. +trait RcFromSlice { + fn from_slice(slice: &[T]) -> Self; +} + +#[cfg(not(no_global_oom_handling))] +impl RcFromSlice for Rc<[T]> { + #[inline] + default fn from_slice(v: &[T]) -> Self { + unsafe { Self::from_iter_exact(v.iter().cloned(), v.len()) } + } +} + +#[cfg(not(no_global_oom_handling))] +impl RcFromSlice for Rc<[T]> { + #[inline] + fn from_slice(v: &[T]) -> Self { + unsafe { Rc::copy_from_slice(v) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Deref for Rc { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + &self.inner().value + } +} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for Rc {} + +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for UniqueRc {} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for Weak {} + +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for Rc {} + +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for UniqueRc {} + +#[unstable(feature = "legacy_receiver_trait", issue = "none")] +impl LegacyReceiver for Rc {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc { + /// Drops the `Rc`. + /// + /// This will decrement the strong reference count. If the strong reference + /// count reaches zero then the only other references (if any) are + /// [`Weak`], so we `drop` the inner value. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// struct Foo; + /// + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } + /// } + /// + /// let foo = Rc::new(Foo); + /// let foo2 = Rc::clone(&foo); + /// + /// drop(foo); // Doesn't print anything + /// drop(foo2); // Prints "dropped!" + /// ``` + #[inline] + fn drop(&mut self) { + unsafe { + self.inner().dec_strong(); + if self.inner().strong() == 0 { + self.drop_slow(); + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Rc { + /// Makes a clone of the `Rc` pointer. + /// + /// This creates another pointer to the same allocation, increasing the + /// strong reference count. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let _ = Rc::clone(&five); + /// ``` + #[inline] + fn clone(&self) -> Self { + unsafe { + self.inner().inc_strong(); + Self::from_inner_in(self.ptr, self.alloc.clone()) + } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Default for Rc { + /// Creates a new `Rc`, with the `Default` value for `T`. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x: Rc = Default::default(); + /// assert_eq!(*x, 0); + /// ``` + #[inline] + fn default() -> Rc { + unsafe { + Self::from_inner( + Box::leak(Box::write( + Box::new_uninit(), + RcInner { strong: Cell::new(1), weak: Cell::new(1), value: T::default() }, + )) + .into(), + ) + } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "more_rc_default_impls", since = "1.80.0")] +impl Default for Rc { + /// Creates an empty str inside an Rc + /// + /// This may or may not share an allocation with other Rcs on the same thread. + #[inline] + fn default() -> Self { + let rc = Rc::<[u8]>::default(); + // `[u8]` has the same layout as `str`. + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const str) } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "more_rc_default_impls", since = "1.80.0")] +impl Default for Rc<[T]> { + /// Creates an empty `[T]` inside an Rc + /// + /// This may or may not share an allocation with other Rcs on the same thread. + #[inline] + fn default() -> Self { + let arr: [T; 0] = []; + Rc::from(arr) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +trait RcEqIdent { + fn eq(&self, other: &Rc) -> bool; + fn ne(&self, other: &Rc) -> bool; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl RcEqIdent for Rc { + #[inline] + default fn eq(&self, other: &Rc) -> bool { + **self == **other + } + + #[inline] + default fn ne(&self, other: &Rc) -> bool { + **self != **other + } +} + +// Hack to allow specializing on `Eq` even though `Eq` has a method. +#[rustc_unsafe_specialization_marker] +pub(crate) trait MarkerEq: PartialEq {} + +impl MarkerEq for T {} + +/// We're doing this specialization here, and not as a more general optimization on `&T`, because it +/// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to +/// store large values, that are slow to clone, but also heavy to check for equality, causing this +/// cost to pay off more easily. It's also more likely to have two `Rc` clones, that point to +/// the same value, than two `&T`s. +/// +/// We can only do this when `T: Eq` as a `PartialEq` might be deliberately irreflexive. +#[stable(feature = "rust1", since = "1.0.0")] +impl RcEqIdent for Rc { + #[inline] + fn eq(&self, other: &Rc) -> bool { + Rc::ptr_eq(self, other) || **self == **other + } + + #[inline] + fn ne(&self, other: &Rc) -> bool { + !Rc::ptr_eq(self, other) && **self != **other + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for Rc { + /// Equality for two `Rc`s. + /// + /// Two `Rc`s are equal if their inner values are equal, even if they are + /// stored in different allocation. + /// + /// If `T` also implements `Eq` (implying reflexivity of equality), + /// two `Rc`s that point to the same allocation are + /// always equal. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five == Rc::new(5)); + /// ``` + #[inline] + fn eq(&self, other: &Rc) -> bool { + RcEqIdent::eq(self, other) + } + + /// Inequality for two `Rc`s. + /// + /// Two `Rc`s are not equal if their inner values are not equal. + /// + /// If `T` also implements `Eq` (implying reflexivity of equality), + /// two `Rc`s that point to the same allocation are + /// always equal. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five != Rc::new(6)); + /// ``` + #[inline] + fn ne(&self, other: &Rc) -> bool { + RcEqIdent::ne(self, other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for Rc {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for Rc { + /// Partial comparison for two `Rc`s. + /// + /// The two are compared by calling `partial_cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// use std::cmp::Ordering; + /// + /// let five = Rc::new(5); + /// + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Rc::new(6))); + /// ``` + #[inline(always)] + fn partial_cmp(&self, other: &Rc) -> Option { + (**self).partial_cmp(&**other) + } + + /// Less-than comparison for two `Rc`s. + /// + /// The two are compared by calling `<` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five < Rc::new(6)); + /// ``` + #[inline(always)] + fn lt(&self, other: &Rc) -> bool { + **self < **other + } + + /// 'Less than or equal to' comparison for two `Rc`s. + /// + /// The two are compared by calling `<=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five <= Rc::new(5)); + /// ``` + #[inline(always)] + fn le(&self, other: &Rc) -> bool { + **self <= **other + } + + /// Greater-than comparison for two `Rc`s. + /// + /// The two are compared by calling `>` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five > Rc::new(4)); + /// ``` + #[inline(always)] + fn gt(&self, other: &Rc) -> bool { + **self > **other + } + + /// 'Greater than or equal to' comparison for two `Rc`s. + /// + /// The two are compared by calling `>=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five >= Rc::new(5)); + /// ``` + #[inline(always)] + fn ge(&self, other: &Rc) -> bool { + **self >= **other + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for Rc { + /// Comparison for two `Rc`s. + /// + /// The two are compared by calling `cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// use std::cmp::Ordering; + /// + /// let five = Rc::new(5); + /// + /// assert_eq!(Ordering::Less, five.cmp(&Rc::new(6))); + /// ``` + #[inline] + fn cmp(&self, other: &Rc) -> Ordering { + (**self).cmp(&**other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for Rc { + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Rc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Rc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Rc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&(&raw const **self), f) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "from_for_ptrs", since = "1.6.0")] +impl From for Rc { + /// Converts a generic type `T` into an `Rc` + /// + /// The conversion allocates on the heap and moves `t` + /// from the stack into it. + /// + /// # Example + /// ```rust + /// # use std::rc::Rc; + /// let x = 5; + /// let rc = Rc::new(5); + /// + /// assert_eq!(Rc::from(x), rc); + /// ``` + fn from(t: T) -> Self { + Rc::new(t) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_array", since = "1.74.0")] +impl From<[T; N]> for Rc<[T]> { + /// Converts a [`[T; N]`](prim@array) into an `Rc<[T]>`. + /// + /// The conversion moves the array into a newly allocated `Rc`. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let original: [i32; 3] = [1, 2, 3]; + /// let shared: Rc<[i32]> = Rc::from(original); + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// ``` + #[inline] + fn from(v: [T; N]) -> Rc<[T]> { + Rc::<[T; N]>::from(v) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From<&[T]> for Rc<[T]> { + /// Allocates a reference-counted slice and fills it by cloning `v`'s items. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let original: &[i32] = &[1, 2, 3]; + /// let shared: Rc<[i32]> = Rc::from(original); + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// ``` + #[inline] + fn from(v: &[T]) -> Rc<[T]> { + >::from_slice(v) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] +impl From<&mut [T]> for Rc<[T]> { + /// Allocates a reference-counted slice and fills it by cloning `v`'s items. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let mut original = [1, 2, 3]; + /// let original: &mut [i32] = &mut original; + /// let shared: Rc<[i32]> = Rc::from(original); + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// ``` + #[inline] + fn from(v: &mut [T]) -> Rc<[T]> { + Rc::from(&*v) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From<&str> for Rc { + /// Allocates a reference-counted string slice and copies `v` into it. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let shared: Rc = Rc::from("statue"); + /// assert_eq!("statue", &shared[..]); + /// ``` + #[inline] + fn from(v: &str) -> Rc { + let rc = Rc::<[u8]>::from(v.as_bytes()); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const str) } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] +impl From<&mut str> for Rc { + /// Allocates a reference-counted string slice and copies `v` into it. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let mut original = String::from("statue"); + /// let original: &mut str = &mut original; + /// let shared: Rc = Rc::from(original); + /// assert_eq!("statue", &shared[..]); + /// ``` + #[inline] + fn from(v: &mut str) -> Rc { + Rc::from(&*v) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From for Rc { + /// Allocates a reference-counted string slice and copies `v` into it. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let original: String = "statue".to_owned(); + /// let shared: Rc = Rc::from(original); + /// assert_eq!("statue", &shared[..]); + /// ``` + #[inline] + fn from(v: String) -> Rc { + Rc::from(&v[..]) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From> for Rc { + /// Move a boxed object to a new, reference counted, allocation. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let original: Box = Box::new(1); + /// let shared: Rc = Rc::from(original); + /// assert_eq!(1, *shared); + /// ``` + #[inline] + fn from(v: Box) -> Rc { + Rc::from_box_in(v) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From> for Rc<[T], A> { + /// Allocates a reference-counted slice and moves `v`'s items into it. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let unique: Vec = vec![1, 2, 3]; + /// let shared: Rc<[i32]> = Rc::from(unique); + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// ``` + #[inline] + fn from(v: Vec) -> Rc<[T], A> { + unsafe { + let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); + + let rc_ptr = Self::allocate_for_slice_in(len, &alloc); + ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).value) as *mut T, len); + + // Create a `Vec` with length 0, to deallocate the buffer + // without dropping its contents or the allocator + let _ = Vec::from_raw_parts_in(vec_ptr, 0, cap, &alloc); + + Self::from_ptr_in(rc_ptr, alloc) + } + } +} + +#[stable(feature = "shared_from_cow", since = "1.45.0")] +impl<'a, B> From> for Rc +where + B: ToOwned + ?Sized, + Rc: From<&'a B> + From, +{ + /// Creates a reference-counted pointer from a clone-on-write pointer by + /// copying its content. + /// + /// # Example + /// + /// ```rust + /// # use std::rc::Rc; + /// # use std::borrow::Cow; + /// let cow: Cow<'_, str> = Cow::Borrowed("eggplant"); + /// let shared: Rc = Rc::from(cow); + /// assert_eq!("eggplant", &shared[..]); + /// ``` + #[inline] + fn from(cow: Cow<'a, B>) -> Rc { + match cow { + Cow::Borrowed(s) => Rc::from(s), + Cow::Owned(s) => Rc::from(s), + } + } +} + +#[stable(feature = "shared_from_str", since = "1.62.0")] +impl From> for Rc<[u8]> { + /// Converts a reference-counted string slice into a byte slice. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let string: Rc = Rc::from("eggplant"); + /// let bytes: Rc<[u8]> = Rc::from(string); + /// assert_eq!("eggplant".as_bytes(), bytes.as_ref()); + /// ``` + #[inline] + fn from(rc: Rc) -> Self { + // SAFETY: `str` has the same layout as `[u8]`. + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const [u8]) } + } +} + +#[stable(feature = "boxed_slice_try_from", since = "1.43.0")] +impl TryFrom> for Rc<[T; N], A> { + type Error = Rc<[T], A>; + + fn try_from(boxed_slice: Rc<[T], A>) -> Result { + if boxed_slice.len() == N { + let (ptr, alloc) = Rc::into_inner_with_allocator(boxed_slice); + Ok(unsafe { Rc::from_inner_in(ptr.cast(), alloc) }) + } else { + Err(boxed_slice) + } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_iter", since = "1.37.0")] +impl FromIterator for Rc<[T]> { + /// Takes each element in the `Iterator` and collects it into an `Rc<[T]>`. + /// + /// # Performance characteristics + /// + /// ## The general case + /// + /// In the general case, collecting into `Rc<[T]>` is done by first + /// collecting into a `Vec`. That is, when writing the following: + /// + /// ```rust + /// # use std::rc::Rc; + /// let evens: Rc<[u8]> = (0..10).filter(|&x| x % 2 == 0).collect(); + /// # assert_eq!(&*evens, &[0, 2, 4, 6, 8]); + /// ``` + /// + /// this behaves as if we wrote: + /// + /// ```rust + /// # use std::rc::Rc; + /// let evens: Rc<[u8]> = (0..10).filter(|&x| x % 2 == 0) + /// .collect::>() // The first set of allocations happens here. + /// .into(); // A second allocation for `Rc<[T]>` happens here. + /// # assert_eq!(&*evens, &[0, 2, 4, 6, 8]); + /// ``` + /// + /// This will allocate as many times as needed for constructing the `Vec` + /// and then it will allocate once for turning the `Vec` into the `Rc<[T]>`. + /// + /// ## Iterators of known length + /// + /// When your `Iterator` implements `TrustedLen` and is of an exact size, + /// a single allocation will be made for the `Rc<[T]>`. For example: + /// + /// ```rust + /// # use std::rc::Rc; + /// let evens: Rc<[u8]> = (0..10).collect(); // Just a single allocation happens here. + /// # assert_eq!(&*evens, &*(0..10).collect::>()); + /// ``` + fn from_iter>(iter: I) -> Self { + ToRcSlice::to_rc_slice(iter.into_iter()) + } +} + +/// Specialization trait used for collecting into `Rc<[T]>`. +#[cfg(not(no_global_oom_handling))] +trait ToRcSlice: Iterator + Sized { + fn to_rc_slice(self) -> Rc<[T]>; +} + +#[cfg(not(no_global_oom_handling))] +impl> ToRcSlice for I { + default fn to_rc_slice(self) -> Rc<[T]> { + self.collect::>().into() + } +} + +#[cfg(not(no_global_oom_handling))] +impl> ToRcSlice for I { + fn to_rc_slice(self) -> Rc<[T]> { + // This is the case for a `TrustedLen` iterator. + let (low, high) = self.size_hint(); + if let Some(high) = high { + debug_assert_eq!( + low, + high, + "TrustedLen iterator's size hint is not exact: {:?}", + (low, high) + ); + + unsafe { + // SAFETY: We need to ensure that the iterator has an exact length and we have. + Rc::from_iter_exact(self, low) + } + } else { + // TrustedLen contract guarantees that `upper_bound == None` implies an iterator + // length exceeding `usize::MAX`. + // The default implementation would collect into a vec which would panic. + // Thus we panic here immediately without invoking `Vec` code. + panic!("capacity overflow"); + } + } +} + +/// `Weak` is a version of [`Rc`] that holds a non-owning reference to the +/// managed allocation. +/// +/// The allocation is accessed by calling [`upgrade`] on the `Weak` +/// pointer, which returns an [Option]<[Rc]\>. +/// +/// Since a `Weak` reference does not count towards ownership, it will not +/// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no +/// guarantees about the value still being present. Thus it may return [`None`] +/// when [`upgrade`]d. Note however that a `Weak` reference *does* prevent the allocation +/// itself (the backing store) from being deallocated. +/// +/// A `Weak` pointer is useful for keeping a temporary reference to the allocation +/// managed by [`Rc`] without preventing its inner value from being dropped. It is also used to +/// prevent circular references between [`Rc`] pointers, since mutual owning references +/// would never allow either [`Rc`] to be dropped. For example, a tree could +/// have strong [`Rc`] pointers from parent nodes to children, and `Weak` +/// pointers from children back to their parents. +/// +/// The typical way to obtain a `Weak` pointer is to call [`Rc::downgrade`]. +/// +/// [`upgrade`]: Weak::upgrade +#[stable(feature = "rc_weak", since = "1.4.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "RcWeak")] +pub struct Weak< + T: ?Sized, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + // This is a `NonNull` to allow optimizing the size of this type in enums, + // but it is not necessarily a valid pointer. + // `Weak::new` sets this to `usize::MAX` so that it doesn’t need + // to allocate space on the heap. That's not a value a real pointer + // will ever have because RcInner has alignment at least 2. + // This is only possible when `T: Sized`; unsized `T` never dangle. + ptr: NonNull>, + alloc: A, +} + +#[stable(feature = "rc_weak", since = "1.4.0")] +impl !Send for Weak {} +#[stable(feature = "rc_weak", since = "1.4.0")] +impl !Sync for Weak {} + +#[unstable(feature = "coerce_unsized", issue = "18598")] +impl, U: ?Sized, A: Allocator> CoerceUnsized> for Weak {} + +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +impl, U: ?Sized> DispatchFromDyn> for Weak {} + +impl Weak { + /// Constructs a new `Weak`, without allocating any memory. + /// Calling [`upgrade`] on the return value always gives [`None`]. + /// + /// [`upgrade`]: Weak::upgrade + /// + /// # Examples + /// + /// ``` + /// use std::rc::Weak; + /// + /// let empty: Weak = Weak::new(); + /// assert!(empty.upgrade().is_none()); + /// ``` + #[inline] + #[stable(feature = "downgraded_weak", since = "1.10.0")] + #[rustc_const_stable(feature = "const_weak_new", since = "1.73.0")] + #[must_use] + pub const fn new() -> Weak { + Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc: Global } + } +} + +impl Weak { + /// Constructs a new `Weak`, without allocating any memory, technically in the provided + /// allocator. + /// Calling [`upgrade`] on the return value always gives [`None`]. + /// + /// [`upgrade`]: Weak::upgrade + /// + /// # Examples + /// + /// ``` + /// use std::rc::Weak; + /// + /// let empty: Weak = Weak::new(); + /// assert!(empty.upgrade().is_none()); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_in(alloc: A) -> Weak { + Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc } + } +} + +pub(crate) fn is_dangling(ptr: *const T) -> bool { + (ptr.cast::<()>()).addr() == usize::MAX +} + +/// Helper type to allow accessing the reference counts without +/// making any assertions about the data field. +struct WeakInner<'a> { + weak: &'a Cell, + strong: &'a Cell, +} + +impl Weak { + /// Converts a raw pointer previously created by [`into_raw`] back into `Weak`. + /// + /// This can be used to safely get a strong reference (by calling [`upgrade`] + /// later) or to deallocate the weak count by dropping the `Weak`. + /// + /// It takes ownership of one weak reference (with the exception of pointers created by [`new`], + /// as these don't own anything; the method still works on them). + /// + /// # Safety + /// + /// The pointer must have originated from the [`into_raw`] and must still own its potential + /// weak reference, and `ptr` must point to a block of memory allocated by the global allocator. + /// + /// It is allowed for the strong count to be 0 at the time of calling this. Nevertheless, this + /// takes ownership of one weak reference currently represented as a raw pointer (the weak + /// count is not modified by this operation) and therefore it must be paired with a previous + /// call to [`into_raw`]. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let strong = Rc::new("hello".to_owned()); + /// + /// let raw_1 = Rc::downgrade(&strong).into_raw(); + /// let raw_2 = Rc::downgrade(&strong).into_raw(); + /// + /// assert_eq!(2, Rc::weak_count(&strong)); + /// + /// assert_eq!("hello", &*unsafe { Weak::from_raw(raw_1) }.upgrade().unwrap()); + /// assert_eq!(1, Rc::weak_count(&strong)); + /// + /// drop(strong); + /// + /// // Decrement the last weak count. + /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none()); + /// ``` + /// + /// [`into_raw`]: Weak::into_raw + /// [`upgrade`]: Weak::upgrade + /// [`new`]: Weak::new + #[inline] + #[stable(feature = "weak_into_raw", since = "1.45.0")] + pub unsafe fn from_raw(ptr: *const T) -> Self { + unsafe { Self::from_raw_in(ptr, Global) } + } +} + +impl Weak { + /// Returns a reference to the underlying allocator. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(&self) -> &A { + &self.alloc + } + + /// Returns a raw pointer to the object `T` pointed to by this `Weak`. + /// + /// The pointer is valid only if there are some strong references. The pointer may be dangling, + /// unaligned or even [`null`] otherwise. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// use std::ptr; + /// + /// let strong = Rc::new("hello".to_owned()); + /// let weak = Rc::downgrade(&strong); + /// // Both point to the same object + /// assert!(ptr::eq(&*strong, weak.as_ptr())); + /// // The strong here keeps it alive, so we can still access the object. + /// assert_eq!("hello", unsafe { &*weak.as_ptr() }); + /// + /// drop(strong); + /// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to + /// // undefined behavior. + /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); + /// ``` + /// + /// [`null`]: ptr::null + #[must_use] + #[stable(feature = "rc_as_ptr", since = "1.45.0")] + pub fn as_ptr(&self) -> *const T { + let ptr: *mut RcInner = NonNull::as_ptr(self.ptr); + + if is_dangling(ptr) { + // If the pointer is dangling, we return the sentinel directly. This cannot be + // a valid payload address, as the payload is at least as aligned as RcInner (usize). + ptr as *const T + } else { + // SAFETY: if is_dangling returns false, then the pointer is dereferenceable. + // The payload may be dropped at this point, and we have to maintain provenance, + // so use raw pointer manipulation. + unsafe { &raw mut (*ptr).value } + } + } + + /// Consumes the `Weak` and turns it into a raw pointer. + /// + /// This converts the weak pointer into a raw pointer, while still preserving the ownership of + /// one weak reference (the weak count is not modified by this operation). It can be turned + /// back into the `Weak` with [`from_raw`]. + /// + /// The same restrictions of accessing the target of the pointer as with + /// [`as_ptr`] apply. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let strong = Rc::new("hello".to_owned()); + /// let weak = Rc::downgrade(&strong); + /// let raw = weak.into_raw(); + /// + /// assert_eq!(1, Rc::weak_count(&strong)); + /// assert_eq!("hello", unsafe { &*raw }); + /// + /// drop(unsafe { Weak::from_raw(raw) }); + /// assert_eq!(0, Rc::weak_count(&strong)); + /// ``` + /// + /// [`from_raw`]: Weak::from_raw + /// [`as_ptr`]: Weak::as_ptr + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "weak_into_raw", since = "1.45.0")] + pub fn into_raw(self) -> *const T { + mem::ManuallyDrop::new(self).as_ptr() + } + + /// Consumes the `Weak`, returning the wrapped pointer and allocator. + /// + /// This converts the weak pointer into a raw pointer, while still preserving the ownership of + /// one weak reference (the weak count is not modified by this operation). It can be turned + /// back into the `Weak` with [`from_raw_in`]. + /// + /// The same restrictions of accessing the target of the pointer as with + /// [`as_ptr`] apply. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// use std::rc::{Rc, Weak}; + /// use std::alloc::System; + /// + /// let strong = Rc::new_in("hello".to_owned(), System); + /// let weak = Rc::downgrade(&strong); + /// let (raw, alloc) = weak.into_raw_with_allocator(); + /// + /// assert_eq!(1, Rc::weak_count(&strong)); + /// assert_eq!("hello", unsafe { &*raw }); + /// + /// drop(unsafe { Weak::from_raw_in(raw, alloc) }); + /// assert_eq!(0, Rc::weak_count(&strong)); + /// ``` + /// + /// [`from_raw_in`]: Weak::from_raw_in + /// [`as_ptr`]: Weak::as_ptr + #[must_use = "losing the pointer will leak memory"] + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn into_raw_with_allocator(self) -> (*const T, A) { + let this = mem::ManuallyDrop::new(self); + let result = this.as_ptr(); + // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped + let alloc = unsafe { ptr::read(&this.alloc) }; + (result, alloc) + } + + /// Converts a raw pointer previously created by [`into_raw`] back into `Weak`. + /// + /// This can be used to safely get a strong reference (by calling [`upgrade`] + /// later) or to deallocate the weak count by dropping the `Weak`. + /// + /// It takes ownership of one weak reference (with the exception of pointers created by [`new`], + /// as these don't own anything; the method still works on them). + /// + /// # Safety + /// + /// The pointer must have originated from the [`into_raw`] and must still own its potential + /// weak reference, and `ptr` must point to a block of memory allocated by `alloc`. + /// + /// It is allowed for the strong count to be 0 at the time of calling this. Nevertheless, this + /// takes ownership of one weak reference currently represented as a raw pointer (the weak + /// count is not modified by this operation) and therefore it must be paired with a previous + /// call to [`into_raw`]. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let strong = Rc::new("hello".to_owned()); + /// + /// let raw_1 = Rc::downgrade(&strong).into_raw(); + /// let raw_2 = Rc::downgrade(&strong).into_raw(); + /// + /// assert_eq!(2, Rc::weak_count(&strong)); + /// + /// assert_eq!("hello", &*unsafe { Weak::from_raw(raw_1) }.upgrade().unwrap()); + /// assert_eq!(1, Rc::weak_count(&strong)); + /// + /// drop(strong); + /// + /// // Decrement the last weak count. + /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none()); + /// ``` + /// + /// [`into_raw`]: Weak::into_raw + /// [`upgrade`]: Weak::upgrade + /// [`new`]: Weak::new + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { + // See Weak::as_ptr for context on how the input pointer is derived. + + let ptr = if is_dangling(ptr) { + // This is a dangling Weak. + ptr as *mut RcInner + } else { + // Otherwise, we're guaranteed the pointer came from a nondangling Weak. + // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. + let offset = unsafe { data_offset(ptr) }; + // Thus, we reverse the offset to get the whole RcInner. + // SAFETY: the pointer originated from a Weak, so this offset is safe. + unsafe { ptr.byte_sub(offset) as *mut RcInner } + }; + + // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. + Weak { ptr: unsafe { NonNull::new_unchecked(ptr) }, alloc } + } + + /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying + /// dropping of the inner value if successful. + /// + /// Returns [`None`] if the inner value has since been dropped. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let weak_five = Rc::downgrade(&five); + /// + /// let strong_five: Option> = weak_five.upgrade(); + /// assert!(strong_five.is_some()); + /// + /// // Destroy all strong pointers. + /// drop(strong_five); + /// drop(five); + /// + /// assert!(weak_five.upgrade().is_none()); + /// ``` + #[must_use = "this returns a new `Rc`, \ + without modifying the original weak pointer"] + #[stable(feature = "rc_weak", since = "1.4.0")] + pub fn upgrade(&self) -> Option> + where + A: Clone, + { + let inner = self.inner()?; + + if inner.strong() == 0 { + None + } else { + unsafe { + inner.inc_strong(); + Some(Rc::from_inner_in(self.ptr, self.alloc.clone())) + } + } + } + + /// Gets the number of strong (`Rc`) pointers pointing to this allocation. + /// + /// If `self` was created using [`Weak::new`], this will return 0. + #[must_use] + #[stable(feature = "weak_counts", since = "1.41.0")] + pub fn strong_count(&self) -> usize { + if let Some(inner) = self.inner() { inner.strong() } else { 0 } + } + + /// Gets the number of `Weak` pointers pointing to this allocation. + /// + /// If no strong pointers remain, this will return zero. + #[must_use] + #[stable(feature = "weak_counts", since = "1.41.0")] + pub fn weak_count(&self) -> usize { + if let Some(inner) = self.inner() { + if inner.strong() > 0 { + inner.weak() - 1 // subtract the implicit weak ptr + } else { + 0 + } + } else { + 0 + } + } + + /// Returns `None` when the pointer is dangling and there is no allocated `RcInner`, + /// (i.e., when this `Weak` was created by `Weak::new`). + #[inline] + fn inner(&self) -> Option> { + if is_dangling(self.ptr.as_ptr()) { + None + } else { + // We are careful to *not* create a reference covering the "data" field, as + // the field may be mutated concurrently (for example, if the last `Rc` + // is dropped, the data field will be dropped in-place). + Some(unsafe { + let ptr = self.ptr.as_ptr(); + WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } + }) + } + } + + /// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if + /// both don't point to any allocation (because they were created with `Weak::new()`). However, + /// this function ignores the metadata of `dyn Trait` pointers. + /// + /// # Notes + /// + /// Since this compares pointers it means that `Weak::new()` will equal each + /// other, even though they don't point to any allocation. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let first_rc = Rc::new(5); + /// let first = Rc::downgrade(&first_rc); + /// let second = Rc::downgrade(&first_rc); + /// + /// assert!(first.ptr_eq(&second)); + /// + /// let third_rc = Rc::new(5); + /// let third = Rc::downgrade(&third_rc); + /// + /// assert!(!first.ptr_eq(&third)); + /// ``` + /// + /// Comparing `Weak::new`. + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let first = Weak::new(); + /// let second = Weak::new(); + /// assert!(first.ptr_eq(&second)); + /// + /// let third_rc = Rc::new(()); + /// let third = Rc::downgrade(&third_rc); + /// assert!(!first.ptr_eq(&third)); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "weak_ptr_eq", since = "1.39.0")] + pub fn ptr_eq(&self, other: &Self) -> bool { + ptr::addr_eq(self.ptr.as_ptr(), other.ptr.as_ptr()) + } +} + +#[stable(feature = "rc_weak", since = "1.4.0")] +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Weak { + /// Drops the `Weak` pointer. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// struct Foo; + /// + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } + /// } + /// + /// let foo = Rc::new(Foo); + /// let weak_foo = Rc::downgrade(&foo); + /// let other_weak_foo = Weak::clone(&weak_foo); + /// + /// drop(weak_foo); // Doesn't print anything + /// drop(foo); // Prints "dropped!" + /// + /// assert!(other_weak_foo.upgrade().is_none()); + /// ``` + fn drop(&mut self) { + let inner = if let Some(inner) = self.inner() { inner } else { return }; + + inner.dec_weak(); + // the weak count starts at 1, and will only go to zero if all + // the strong pointers have disappeared. + if inner.weak() == 0 { + unsafe { + self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); + } + } + } +} + +#[stable(feature = "rc_weak", since = "1.4.0")] +impl Clone for Weak { + /// Makes a clone of the `Weak` pointer that points to the same allocation. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let weak_five = Rc::downgrade(&Rc::new(5)); + /// + /// let _ = Weak::clone(&weak_five); + /// ``` + #[inline] + fn clone(&self) -> Weak { + if let Some(inner) = self.inner() { + inner.inc_weak() + } + Weak { ptr: self.ptr, alloc: self.alloc.clone() } + } +} + +#[stable(feature = "rc_weak", since = "1.4.0")] +impl fmt::Debug for Weak { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(Weak)") + } +} + +#[stable(feature = "downgraded_weak", since = "1.10.0")] +impl Default for Weak { + /// Constructs a new `Weak`, without allocating any memory. + /// Calling [`upgrade`] on the return value always gives [`None`]. + /// + /// [`upgrade`]: Weak::upgrade + /// + /// # Examples + /// + /// ``` + /// use std::rc::Weak; + /// + /// let empty: Weak = Default::default(); + /// assert!(empty.upgrade().is_none()); + /// ``` + fn default() -> Weak { + Weak::new() + } +} + +// NOTE: We checked_add here to deal with mem::forget safely. In particular +// if you mem::forget Rcs (or Weaks), the ref-count can overflow, and then +// you can free the allocation while outstanding Rcs (or Weaks) exist. +// We abort because this is such a degenerate scenario that we don't care about +// what happens -- no real program should ever experience this. +// +// This should have negligible overhead since you don't actually need to +// clone these much in Rust thanks to ownership and move-semantics. + +#[doc(hidden)] +trait RcInnerPtr { + fn weak_ref(&self) -> &Cell; + fn strong_ref(&self) -> &Cell; + + #[inline] + fn strong(&self) -> usize { + self.strong_ref().get() + } + + #[inline] + fn inc_strong(&self) { + let strong = self.strong(); + + // We insert an `assume` here to hint LLVM at an otherwise + // missed optimization. + // SAFETY: The reference count will never be zero when this is + // called. + unsafe { + hint::assert_unchecked(strong != 0); + } + + let strong = strong.wrapping_add(1); + self.strong_ref().set(strong); + + // We want to abort on overflow instead of dropping the value. + // Checking for overflow after the store instead of before + // allows for slightly better code generation. + if core::intrinsics::unlikely(strong == 0) { + abort(); + } + } + + #[inline] + fn dec_strong(&self) { + self.strong_ref().set(self.strong() - 1); + } + + #[inline] + fn weak(&self) -> usize { + self.weak_ref().get() + } + + #[inline] + fn inc_weak(&self) { + let weak = self.weak(); + + // We insert an `assume` here to hint LLVM at an otherwise + // missed optimization. + // SAFETY: The reference count will never be zero when this is + // called. + unsafe { + hint::assert_unchecked(weak != 0); + } + + let weak = weak.wrapping_add(1); + self.weak_ref().set(weak); + + // We want to abort on overflow instead of dropping the value. + // Checking for overflow after the store instead of before + // allows for slightly better code generation. + if core::intrinsics::unlikely(weak == 0) { + abort(); + } + } + + #[inline] + fn dec_weak(&self) { + self.weak_ref().set(self.weak() - 1); + } +} + +impl RcInnerPtr for RcInner { + #[inline(always)] + fn weak_ref(&self) -> &Cell { + &self.weak + } + + #[inline(always)] + fn strong_ref(&self) -> &Cell { + &self.strong + } +} + +impl<'a> RcInnerPtr for WeakInner<'a> { + #[inline(always)] + fn weak_ref(&self) -> &Cell { + self.weak + } + + #[inline(always)] + fn strong_ref(&self) -> &Cell { + self.strong + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl borrow::Borrow for Rc { + fn borrow(&self) -> &T { + &**self + } +} + +#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] +impl AsRef for Rc { + fn as_ref(&self) -> &T { + &**self + } +} + +#[stable(feature = "pin", since = "1.33.0")] +impl Unpin for Rc {} + +/// Gets the offset within an `RcInner` for the payload behind a pointer. +/// +/// # Safety +/// +/// The pointer must point to (and have valid metadata for) a previously +/// valid instance of T, but the T is allowed to be dropped. +unsafe fn data_offset(ptr: *const T) -> usize { + // Align the unsized value to the end of the RcInner. + // Because RcInner is repr(C), it will always be the last field in memory. + // SAFETY: since the only unsized types possible are slices, trait objects, + // and extern types, the input safety requirement is currently enough to + // satisfy the requirements of align_of_val_raw; this is an implementation + // detail of the language that must not be relied upon outside of std. + unsafe { data_offset_align(align_of_val_raw(ptr)) } +} + +#[inline] +fn data_offset_align(align: usize) -> usize { + let layout = Layout::new::>(); + layout.size() + layout.padding_needed_for(align) +} + +/// A uniquely owned [`Rc`]. +/// +/// This represents an `Rc` that is known to be uniquely owned -- that is, have exactly one strong +/// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong +/// references will fail unless the `UniqueRc` they point to has been converted into a regular `Rc`. +/// +/// Because they are uniquely owned, the contents of a `UniqueRc` can be freely mutated. A common +/// use case is to have an object be mutable during its initialization phase but then have it become +/// immutable and converted to a normal `Rc`. +/// +/// This can be used as a flexible way to create cyclic data structures, as in the example below. +/// +/// ``` +/// #![feature(unique_rc_arc)] +/// use std::rc::{Rc, Weak, UniqueRc}; +/// +/// struct Gadget { +/// #[allow(dead_code)] +/// me: Weak, +/// } +/// +/// fn create_gadget() -> Option> { +/// let mut rc = UniqueRc::new(Gadget { +/// me: Weak::new(), +/// }); +/// rc.me = UniqueRc::downgrade(&rc); +/// Some(UniqueRc::into_rc(rc)) +/// } +/// +/// create_gadget().unwrap(); +/// ``` +/// +/// An advantage of using `UniqueRc` over [`Rc::new_cyclic`] to build cyclic data structures is that +/// [`Rc::new_cyclic`]'s `data_fn` parameter cannot be async or return a [`Result`]. As shown in the +/// previous example, `UniqueRc` allows for more flexibility in the construction of cyclic data, +/// including fallible or async constructors. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +pub struct UniqueRc< + T: ?Sized, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + ptr: NonNull>, + // Define the ownership of `RcInner` for drop-check + _marker: PhantomData>, + // Invariance is necessary for soundness: once other `Weak` + // references exist, we already have a form of shared mutability! + _marker2: PhantomData<*mut T>, + alloc: A, +} + +// Not necessary for correctness since `UniqueRc` contains `NonNull`, +// but having an explicit negative impl is nice for documentation purposes +// and results in nicer error messages. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl !Send for UniqueRc {} + +// Not necessary for correctness since `UniqueRc` contains `NonNull`, +// but having an explicit negative impl is nice for documentation purposes +// and results in nicer error messages. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl !Sync for UniqueRc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl, U: ?Sized, A: Allocator> CoerceUnsized> + for UniqueRc +{ +} + +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +impl, U: ?Sized> DispatchFromDyn> for UniqueRc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Display for UniqueRc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Debug for UniqueRc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Pointer for UniqueRc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&(&raw const **self), f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl borrow::Borrow for UniqueRc { + fn borrow(&self) -> &T { + &**self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl borrow::BorrowMut for UniqueRc { + fn borrow_mut(&mut self) -> &mut T { + &mut **self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsRef for UniqueRc { + fn as_ref(&self) -> &T { + &**self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsMut for UniqueRc { + fn as_mut(&mut self) -> &mut T { + &mut **self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Unpin for UniqueRc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl PartialEq for UniqueRc { + /// Equality for two `UniqueRc`s. + /// + /// Two `UniqueRc`s are equal if their inner values are equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five == UniqueRc::new(5)); + /// ``` + #[inline] + fn eq(&self, other: &Self) -> bool { + PartialEq::eq(&**self, &**other) + } + + /// Inequality for two `UniqueRc`s. + /// + /// Two `UniqueRc`s are not equal if their inner values are not equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five != UniqueRc::new(6)); + /// ``` + #[inline] + fn ne(&self, other: &Self) -> bool { + PartialEq::ne(&**self, &**other) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl PartialOrd for UniqueRc { + /// Partial comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `partial_cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// use std::cmp::Ordering; + /// + /// let five = UniqueRc::new(5); + /// + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&UniqueRc::new(6))); + /// ``` + #[inline(always)] + fn partial_cmp(&self, other: &UniqueRc) -> Option { + (**self).partial_cmp(&**other) + } + + /// Less-than comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `<` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five < UniqueRc::new(6)); + /// ``` + #[inline(always)] + fn lt(&self, other: &UniqueRc) -> bool { + **self < **other + } + + /// 'Less than or equal to' comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `<=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five <= UniqueRc::new(5)); + /// ``` + #[inline(always)] + fn le(&self, other: &UniqueRc) -> bool { + **self <= **other + } + + /// Greater-than comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `>` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five > UniqueRc::new(4)); + /// ``` + #[inline(always)] + fn gt(&self, other: &UniqueRc) -> bool { + **self > **other + } + + /// 'Greater than or equal to' comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `>=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five >= UniqueRc::new(5)); + /// ``` + #[inline(always)] + fn ge(&self, other: &UniqueRc) -> bool { + **self >= **other + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Ord for UniqueRc { + /// Comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// use std::cmp::Ordering; + /// + /// let five = UniqueRc::new(5); + /// + /// assert_eq!(Ordering::Less, five.cmp(&UniqueRc::new(6))); + /// ``` + #[inline] + fn cmp(&self, other: &UniqueRc) -> Ordering { + (**self).cmp(&**other) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Eq for UniqueRc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Hash for UniqueRc { + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} + +// Depends on A = Global +impl UniqueRc { + /// Creates a new `UniqueRc`. + /// + /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. + /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will + /// point to the new [`Rc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new(value: T) -> Self { + Self::new_in(value, Global) + } +} + +impl UniqueRc { + /// Creates a new `UniqueRc` in the provided allocator. + /// + /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. + /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will + /// point to the new [`Rc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new_in(value: T, alloc: A) -> Self { + let (ptr, alloc) = Box::into_unique(Box::new_in( + RcInner { + strong: Cell::new(0), + // keep one weak reference so if all the weak pointers that are created are dropped + // the UniqueRc still stays valid. + weak: Cell::new(1), + value, + }, + alloc, + )); + Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc } + } +} + +impl UniqueRc { + /// Converts the `UniqueRc` into a regular [`Rc`]. + /// + /// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that + /// is passed to `into_rc`. + /// + /// Any weak references created before this method is called can now be upgraded to strong + /// references. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn into_rc(this: Self) -> Rc { + let mut this = ManuallyDrop::new(this); + + // Move the allocator out. + // SAFETY: `this.alloc` will not be accessed again, nor dropped because it is in + // a `ManuallyDrop`. + let alloc: A = unsafe { ptr::read(&this.alloc) }; + + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { + // Convert our weak reference into a strong reference + this.ptr.as_mut().strong.set(1); + Rc::from_inner_in(this.ptr, alloc) + } + } +} + +impl UniqueRc { + /// Creates a new weak reference to the `UniqueRc`. + /// + /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted + /// to a [`Rc`] using [`UniqueRc::into_rc`]. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn downgrade(this: &Self) -> Weak { + // SAFETY: This pointer was allocated at creation time and we guarantee that we only have + // one strong reference before converting to a regular Rc. + unsafe { + this.ptr.as_ref().inc_weak(); + } + Weak { ptr: this.ptr, alloc: this.alloc.clone() } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Deref for UniqueRc { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { &self.ptr.as_ref().value } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl DerefMut for UniqueRc { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. We know we + // have unique ownership and therefore it's safe to make a mutable reference because + // `UniqueRc` owns the only strong reference to itself. + unsafe { &mut (*self.ptr.as_ptr()).value } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc { + fn drop(&mut self) { + unsafe { + // destroy the contained object + drop_in_place(DerefMut::deref_mut(self)); + + // remove the implicit "strong weak" pointer now that we've destroyed the contents. + self.ptr.as_ref().dec_weak(); + + if self.ptr.as_ref().weak() == 0 { + self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); + } + } + } +} + +/// A unique owning pointer to a [`RcInner`] **that does not imply the contents are initialized,** +/// but will deallocate it (without dropping the value) when dropped. +/// +/// This is a helper for [`Rc::make_mut()`] to ensure correct cleanup on panic. +/// It is nearly a duplicate of `UniqueRc, A>` except that it allows `T: !Sized`, +/// which `MaybeUninit` does not. +#[cfg(not(no_global_oom_handling))] +struct UniqueRcUninit { + ptr: NonNull>, + layout_for_value: Layout, + alloc: Option, +} + +#[cfg(not(no_global_oom_handling))] +impl UniqueRcUninit { + /// Allocates a RcInner with layout suitable to contain `for_value` or a clone of it. + fn new(for_value: &T, alloc: A) -> UniqueRcUninit { + let layout = Layout::for_value(for_value); + let ptr = unsafe { + Rc::allocate_for_layout( + layout, + |layout_for_rc_inner| alloc.allocate(layout_for_rc_inner), + |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcInner), + ) + }; + Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) } + } + + /// Returns the pointer to be written into to initialize the [`Rc`]. + fn data_ptr(&mut self) -> *mut T { + let offset = data_offset_align(self.layout_for_value.align()); + unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } + } + + /// Upgrade this into a normal [`Rc`]. + /// + /// # Safety + /// + /// The data must have been initialized (by writing to [`Self::data_ptr()`]). + unsafe fn into_rc(self) -> Rc { + let mut this = ManuallyDrop::new(self); + let ptr = this.ptr; + let alloc = this.alloc.take().unwrap(); + + // SAFETY: The pointer is valid as per `UniqueRcUninit::new`, and the caller is responsible + // for having initialized the data. + unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) } + } +} + +#[cfg(not(no_global_oom_handling))] +impl Drop for UniqueRcUninit { + fn drop(&mut self) { + // SAFETY: + // * new() produced a pointer safe to deallocate. + // * We own the pointer unless into_rc() was called, which forgets us. + unsafe { + self.alloc.take().unwrap().deallocate( + self.ptr.cast(), + rc_inner_layout_for_value_layout(self.layout_for_value), + ); + } + } +} diff --git a/library/alloc/tests/alloc.rs b/library/alloc/tests/alloc.rs deleted file mode 100644 index 1e722d66795..00000000000 --- a/library/alloc/tests/alloc.rs +++ /dev/null @@ -1,29 +0,0 @@ -use alloc::alloc::*; -use alloc::boxed::Box; - -extern crate test; -use test::Bencher; - -#[test] -fn allocate_zeroed() { - unsafe { - let layout = Layout::from_size_align(1024, 1).unwrap(); - let ptr = - Global.allocate_zeroed(layout.clone()).unwrap_or_else(|_| handle_alloc_error(layout)); - - let mut i = ptr.as_non_null_ptr().as_ptr(); - let end = i.add(layout.size()); - while i < end { - assert_eq!(*i, 0); - i = i.add(1); - } - Global.deallocate(ptr.as_non_null_ptr(), layout); - } -} - -#[bench] -fn alloc_owned_small(b: &mut Bencher) { - b.iter(|| { - let _: Box<_> = Box::new(10); - }) -} diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs deleted file mode 100644 index 0baa50f439b..00000000000 --- a/library/alloc/tests/arc.rs +++ /dev/null @@ -1,278 +0,0 @@ -use std::any::Any; -use std::cell::{Cell, RefCell}; -use std::iter::TrustedLen; -use std::sync::{Arc, Weak}; - -#[test] -fn uninhabited() { - enum Void {} - let mut a = Weak::::new(); - a = a.clone(); - assert!(a.upgrade().is_none()); - - let mut a: Weak = a; // Unsizing - a = a.clone(); - assert!(a.upgrade().is_none()); -} - -#[test] -fn slice() { - let a: Arc<[u32; 3]> = Arc::new([3, 2, 1]); - let a: Arc<[u32]> = a; // Unsizing - let b: Arc<[u32]> = Arc::from(&[3, 2, 1][..]); // Conversion - assert_eq!(a, b); - - // Exercise is_dangling() with a DST - let mut a = Arc::downgrade(&a); - a = a.clone(); - assert!(a.upgrade().is_some()); -} - -#[test] -fn trait_object() { - let a: Arc = Arc::new(4); - let a: Arc = a; // Unsizing - - // Exercise is_dangling() with a DST - let mut a = Arc::downgrade(&a); - a = a.clone(); - assert!(a.upgrade().is_some()); - - let mut b = Weak::::new(); - b = b.clone(); - assert!(b.upgrade().is_none()); - let mut b: Weak = b; // Unsizing - b = b.clone(); - assert!(b.upgrade().is_none()); -} - -#[test] -fn float_nan_ne() { - let x = Arc::new(f32::NAN); - assert!(x != x); - assert!(!(x == x)); -} - -#[test] -fn partial_eq() { - struct TestPEq(RefCell); - impl PartialEq for TestPEq { - fn eq(&self, other: &TestPEq) -> bool { - *self.0.borrow_mut() += 1; - *other.0.borrow_mut() += 1; - true - } - } - let x = Arc::new(TestPEq(RefCell::new(0))); - assert!(x == x); - assert!(!(x != x)); - assert_eq!(*x.0.borrow(), 4); -} - -#[test] -fn eq() { - #[derive(Eq)] - struct TestEq(RefCell); - impl PartialEq for TestEq { - fn eq(&self, other: &TestEq) -> bool { - *self.0.borrow_mut() += 1; - *other.0.borrow_mut() += 1; - true - } - } - let x = Arc::new(TestEq(RefCell::new(0))); - assert!(x == x); - assert!(!(x != x)); - assert_eq!(*x.0.borrow(), 0); -} - -// The test code below is identical to that in `rc.rs`. -// For better maintainability we therefore define this type alias. -type Rc = Arc; - -const SHARED_ITER_MAX: u16 = 100; - -fn assert_trusted_len(_: &I) {} - -#[test] -fn shared_from_iter_normal() { - // Exercise the base implementation for non-`TrustedLen` iterators. - { - // `Filter` is never `TrustedLen` since we don't - // know statically how many elements will be kept: - let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new); - - // Collecting into a `Vec` or `Rc<[T]>` should make no difference: - let vec = iter.clone().collect::>(); - let rc = iter.collect::>(); - assert_eq!(&*vec, &*rc); - - // Clone a bit and let these get dropped. - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } // Drop what hasn't been here. -} - -#[test] -fn shared_from_iter_trustedlen_normal() { - // Exercise the `TrustedLen` implementation under normal circumstances - // where `size_hint()` matches `(_, Some(exact_len))`. - { - let iter = (0..SHARED_ITER_MAX).map(Box::new); - assert_trusted_len(&iter); - - // Collecting into a `Vec` or `Rc<[T]>` should make no difference: - let vec = iter.clone().collect::>(); - let rc = iter.collect::>(); - assert_eq!(&*vec, &*rc); - assert_eq!(size_of::>() * SHARED_ITER_MAX as usize, size_of_val(&*rc)); - - // Clone a bit and let these get dropped. - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } // Drop what hasn't been here. - - // Try a ZST to make sure it is handled well. - { - let iter = (0..SHARED_ITER_MAX).map(drop); - let vec = iter.clone().collect::>(); - let rc = iter.collect::>(); - assert_eq!(&*vec, &*rc); - assert_eq!(0, size_of_val(&*rc)); - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } -} - -#[test] -#[should_panic = "I've almost got 99 problems."] -fn shared_from_iter_trustedlen_panic() { - // Exercise the `TrustedLen` implementation when `size_hint()` matches - // `(_, Some(exact_len))` but where `.next()` drops before the last iteration. - let iter = (0..SHARED_ITER_MAX).map(|val| match val { - 98 => panic!("I've almost got 99 problems."), - _ => Box::new(val), - }); - assert_trusted_len(&iter); - let _ = iter.collect::>(); - - panic!("I am unreachable."); -} - -#[test] -fn shared_from_iter_trustedlen_no_fuse() { - // Exercise the `TrustedLen` implementation when `size_hint()` matches - // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner. - struct Iter(std::vec::IntoIter>>); - - unsafe impl TrustedLen for Iter {} - - impl Iterator for Iter { - fn size_hint(&self) -> (usize, Option) { - (2, Some(2)) - } - - type Item = Box; - - fn next(&mut self) -> Option { - self.0.next().flatten() - } - } - - let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))]; - let iter = Iter(vec.into_iter()); - assert_trusted_len(&iter); - assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::>()); -} - -#[test] -fn weak_may_dangle() { - fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> { - val.clone() - } - - // Without #[may_dangle] we get: - let mut val = Weak::new(); - hmm(&mut val); - // ~~~~~~~~ borrowed value does not live long enough - // - // `val` dropped here while still borrowed - // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak` -} - -/// Test that a panic from a destructor does not leak the allocation. -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn panic_no_leak() { - use std::alloc::{AllocError, Allocator, Global, Layout}; - use std::panic::{AssertUnwindSafe, catch_unwind}; - use std::ptr::NonNull; - - struct AllocCount(Cell); - unsafe impl Allocator for AllocCount { - fn allocate(&self, layout: Layout) -> Result, AllocError> { - self.0.set(self.0.get() + 1); - Global.allocate(layout) - } - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - self.0.set(self.0.get() - 1); - unsafe { Global.deallocate(ptr, layout) } - } - } - - struct PanicOnDrop; - impl Drop for PanicOnDrop { - fn drop(&mut self) { - panic!("PanicOnDrop"); - } - } - - let alloc = AllocCount(Cell::new(0)); - let rc = Rc::new_in(PanicOnDrop, &alloc); - assert_eq!(alloc.0.get(), 1); - - let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); - assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); - assert_eq!(alloc.0.get(), 0); -} - -/// This is similar to the doc-test for `Arc::make_mut()`, but on an unsized type (slice). -#[test] -fn make_mut_unsized() { - use alloc::sync::Arc; - - let mut data: Arc<[i32]> = Arc::new([10, 20, 30]); - - Arc::make_mut(&mut data)[0] += 1; // Won't clone anything - let mut other_data = Arc::clone(&data); // Won't clone inner data - Arc::make_mut(&mut data)[1] += 1; // Clones inner data - Arc::make_mut(&mut data)[2] += 1; // Won't clone anything - Arc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything - - // Now `data` and `other_data` point to different allocations. - assert_eq!(*data, [11, 21, 31]); - assert_eq!(*other_data, [110, 20, 30]); -} - -#[allow(unused)] -mod pin_coerce_unsized { - use alloc::sync::Arc; - use core::pin::Pin; - - pub trait MyTrait {} - impl MyTrait for String {} - - // Pin coercion should work for Arc - pub fn pin_arc(arg: Pin>) -> Pin> { - arg - } -} diff --git a/library/alloc/tests/autotraits.rs b/library/alloc/tests/autotraits.rs deleted file mode 100644 index 6b82deeac8a..00000000000 --- a/library/alloc/tests/autotraits.rs +++ /dev/null @@ -1,288 +0,0 @@ -fn require_sync(_: T) {} -fn require_send_sync(_: T) {} - -struct NotSend(#[allow(dead_code)] *const ()); -unsafe impl Sync for NotSend {} - -#[test] -fn test_btree_map() { - // Tests of this form are prone to https://github.com/rust-lang/rust/issues/64552. - // - // In theory the async block's future would be Send if the value we hold - // across the await point is Send, and Sync if the value we hold across the - // await point is Sync. - // - // We test autotraits in this convoluted way, instead of a straightforward - // `require_send_sync::()`, because the interaction with - // coroutines exposes some current limitations in rustc's ability to prove a - // lifetime bound on the erased coroutine witness types. See the above link. - // - // A typical way this would surface in real code is: - // - // fn spawn(_: T) {} - // - // async fn f() { - // let map = BTreeMap::>::new(); - // for _ in &map { - // async {}.await; - // } - // } - // - // fn main() { - // spawn(f()); - // } - // - // where with some unintentionally overconstrained Send impls in alloc's - // internals, the future might incorrectly not be Send even though every - // single type involved in the program is Send and Sync. - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - // Testing like this would not catch all issues that the above form catches. - require_send_sync(None::>); - - require_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::< - alloc::collections::btree_map::ExtractIf<'_, &u32, &u32, fn(&&u32, &mut &u32) -> bool>, - >; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); -} - -#[test] -fn test_btree_set() { - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None:: bool>>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); -} - -#[test] -fn test_binary_heap() { - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); -} - -#[test] -fn test_linked_list() { - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - // FIXME - /* - require_send_sync(async { - let _v = - None:: bool>>; - async {}.await; - }); - */ - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); -} - -#[test] -fn test_vec_deque() { - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); - - require_send_sync(async { - let _v = None::>; - async {}.await; - }); -} diff --git a/library/alloc/tests/borrow.rs b/library/alloc/tests/borrow.rs deleted file mode 100644 index af7efb7d782..00000000000 --- a/library/alloc/tests/borrow.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::borrow::Cow; -use std::ffi::{CStr, OsStr}; -use std::path::Path; -use std::rc::Rc; -use std::sync::Arc; - -macro_rules! test_from_cow { - ($value:ident => $($ty:ty),+) => {$( - let borrowed = <$ty>::from(Cow::Borrowed($value)); - let owned = <$ty>::from(Cow::Owned($value.to_owned())); - assert_eq!($value, &*borrowed); - assert_eq!($value, &*owned); - )+}; - ($value:ident : & $ty:ty) => { - test_from_cow!($value => Box<$ty>, Rc<$ty>, Arc<$ty>); - } -} - -#[test] -fn test_from_cow_slice() { - let slice: &[i32] = &[1, 2, 3]; - test_from_cow!(slice: &[i32]); -} - -#[test] -fn test_from_cow_str() { - let string = "hello"; - test_from_cow!(string: &str); -} - -#[test] -fn test_from_cow_c_str() { - let string = CStr::from_bytes_with_nul(b"hello\0").unwrap(); - test_from_cow!(string: &CStr); -} - -#[test] -fn test_from_cow_os_str() { - let string = OsStr::new("hello"); - test_from_cow!(string: &OsStr); -} - -#[test] -fn test_from_cow_path() { - let path = Path::new("hello"); - test_from_cow!(path: &Path); -} - -#[test] -fn cow_const() { - // test that the methods of `Cow` are usable in a const context - - const COW: Cow<'_, str> = Cow::Borrowed("moo"); - - const IS_BORROWED: bool = COW.is_borrowed(); - assert!(IS_BORROWED); - - const IS_OWNED: bool = COW.is_owned(); - assert!(!IS_OWNED); -} diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs deleted file mode 100644 index 94389cf2de9..00000000000 --- a/library/alloc/tests/boxed.rs +++ /dev/null @@ -1,258 +0,0 @@ -use core::alloc::{AllocError, Allocator, Layout}; -use core::cell::Cell; -use core::mem::MaybeUninit; -use core::ptr::NonNull; - -#[test] -#[expect(dangling_pointers_from_temporaries)] -fn uninitialized_zero_size_box() { - assert_eq!( - &*Box::<()>::new_uninit() as *const _, - NonNull::>::dangling().as_ptr(), - ); - assert_eq!( - Box::<[()]>::new_uninit_slice(4).as_ptr(), - NonNull::>::dangling().as_ptr(), - ); - assert_eq!( - Box::<[String]>::new_uninit_slice(0).as_ptr(), - NonNull::>::dangling().as_ptr(), - ); -} - -#[derive(Clone, PartialEq, Eq, Debug)] -struct Dummy { - _data: u8, -} - -#[test] -fn box_clone_and_clone_from_equivalence() { - for size in (0..8).map(|i| 2usize.pow(i)) { - let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); - let clone = control.clone(); - let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); - copy.clone_from(&control); - assert_eq!(control, clone); - assert_eq!(control, copy); - } -} - -/// This test might give a false positive in case the box reallocates, -/// but the allocator keeps the original pointer. -/// -/// On the other hand, it won't give a false negative: If it fails, then the -/// memory was definitely not reused. -#[test] -fn box_clone_from_ptr_stability() { - for size in (0..8).map(|i| 2usize.pow(i)) { - let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); - let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); - let copy_raw = copy.as_ptr() as usize; - copy.clone_from(&control); - assert_eq!(copy.as_ptr() as usize, copy_raw); - } -} - -#[test] -fn box_deref_lval() { - let x = Box::new(Cell::new(5)); - x.set(1000); - assert_eq!(x.get(), 1000); -} - -/// Test that a panic from a destructor does not leak the allocation. -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn panic_no_leak() { - use std::alloc::{AllocError, Allocator, Global, Layout}; - use std::panic::{AssertUnwindSafe, catch_unwind}; - use std::ptr::NonNull; - - struct AllocCount(Cell); - unsafe impl Allocator for AllocCount { - fn allocate(&self, layout: Layout) -> Result, AllocError> { - self.0.set(self.0.get() + 1); - Global.allocate(layout) - } - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - self.0.set(self.0.get() - 1); - unsafe { Global.deallocate(ptr, layout) } - } - } - - struct PanicOnDrop { - _data: u8, - } - impl Drop for PanicOnDrop { - fn drop(&mut self) { - panic!("PanicOnDrop"); - } - } - - let alloc = AllocCount(Cell::new(0)); - let b = Box::new_in(PanicOnDrop { _data: 42 }, &alloc); - assert_eq!(alloc.0.get(), 1); - - let panic_message = catch_unwind(AssertUnwindSafe(|| drop(b))).unwrap_err(); - assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); - assert_eq!(alloc.0.get(), 0); -} - -#[allow(unused)] -pub struct ConstAllocator; - -unsafe impl Allocator for ConstAllocator { - fn allocate(&self, layout: Layout) -> Result, AllocError> { - match layout.size() { - 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), - _ => unsafe { - let ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); - Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8])) - }, - } - } - - unsafe fn deallocate(&self, _ptr: NonNull, layout: Layout) { - match layout.size() { - 0 => { /* do nothing */ } - _ => { /* do nothing too */ } - } - } - - fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { - let ptr = self.allocate(layout)?; - if layout.size() > 0 { - unsafe { - ptr.as_mut_ptr().write_bytes(0, layout.size()); - } - } - Ok(ptr) - } - - unsafe fn grow( - &self, - ptr: NonNull, - old_layout: Layout, - new_layout: Layout, - ) -> Result, AllocError> { - debug_assert!( - new_layout.size() >= old_layout.size(), - "`new_layout.size()` must be greater than or equal to `old_layout.size()`" - ); - - let new_ptr = self.allocate(new_layout)?; - if new_layout.size() > 0 { - // Safety: `new_ptr` is valid for writes and `ptr` for reads of - // `old_layout.size()`, because `new_layout.size() >= - // old_layout.size()` (which is an invariant that must be upheld by - // callers). - unsafe { - new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size()); - } - // Safety: `ptr` is never used again is also an invariant which must - // be upheld by callers. - unsafe { - self.deallocate(ptr, old_layout); - } - } - Ok(new_ptr) - } - - unsafe fn grow_zeroed( - &self, - ptr: NonNull, - old_layout: Layout, - new_layout: Layout, - ) -> Result, AllocError> { - // Safety: Invariants of `grow_zeroed` and `grow` are the same, and must - // be enforced by callers. - let new_ptr = unsafe { self.grow(ptr, old_layout, new_layout)? }; - if new_layout.size() > 0 { - let old_size = old_layout.size(); - let new_size = new_layout.size(); - let raw_ptr = new_ptr.as_mut_ptr(); - // Safety: - // - `grow` returned Ok, so the returned pointer must be valid for - // `new_size` bytes - // - `new_size` must be larger than `old_size`, which is an - // invariant which must be upheld by callers. - unsafe { - raw_ptr.add(old_size).write_bytes(0, new_size - old_size); - } - } - Ok(new_ptr) - } - - unsafe fn shrink( - &self, - ptr: NonNull, - old_layout: Layout, - new_layout: Layout, - ) -> Result, AllocError> { - debug_assert!( - new_layout.size() <= old_layout.size(), - "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" - ); - - let new_ptr = self.allocate(new_layout)?; - if new_layout.size() > 0 { - // Safety: `new_ptr` and `ptr` are valid for reads/writes of - // `new_layout.size()` because of the invariants of shrink, which - // include `new_layout.size()` being smaller than (or equal to) - // `old_layout.size()`. - unsafe { - new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), new_layout.size()); - } - // Safety: `ptr` is never used again is also an invariant which must - // be upheld by callers. - unsafe { - self.deallocate(ptr, old_layout); - } - } - Ok(new_ptr) - } - - fn by_ref(&self) -> &Self - where - Self: Sized, - { - self - } -} - -#[allow(unused)] -mod pin_coerce_unsized { - use alloc::boxed::Box; - use core::pin::Pin; - - trait MyTrait { - fn action(&self) -> &str; - } - impl MyTrait for String { - fn action(&self) -> &str { - &*self - } - } - struct MyStruct; - impl MyTrait for MyStruct { - fn action(&self) -> &str { - "MyStruct" - } - } - - // Pin coercion should work for Box - fn pin_box(arg: Pin>) -> Pin> { - arg - } - - #[test] - fn pin_coerce_unsized_box() { - let my_string = "my string"; - let a_string = Box::pin(String::from(my_string)); - let pin_box_str = pin_box(a_string); - assert_eq!(pin_box_str.as_ref().action(), my_string); - let a_struct = Box::pin(MyStruct); - let pin_box_struct = pin_box(a_struct); - assert_eq!(pin_box_struct.as_ref().action(), "MyStruct"); - } -} diff --git a/library/alloc/tests/btree_set_hash.rs b/library/alloc/tests/btree_set_hash.rs deleted file mode 100644 index 71a3a143209..00000000000 --- a/library/alloc/tests/btree_set_hash.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::collections::BTreeSet; - -use crate::hash; - -#[test] -fn test_hash() { - let mut x = BTreeSet::new(); - let mut y = BTreeSet::new(); - - x.insert(1); - x.insert(2); - x.insert(3); - - y.insert(3); - y.insert(2); - y.insert(1); - - assert_eq!(hash(&x), hash(&y)); -} - -#[test] -fn test_prefix_free() { - let x = BTreeSet::from([1, 2, 3]); - let y = BTreeSet::::new(); - - // If hashed by iteration alone, `(x, y)` and `(y, x)` would visit the same - // order of elements, resulting in the same hash. But now that we also hash - // the length, they get distinct sequences of hashed data. - assert_ne!(hash(&(&x, &y)), hash(&(&y, &x))); -} diff --git a/library/alloc/tests/c_str.rs b/library/alloc/tests/c_str.rs deleted file mode 100644 index 4a581793956..00000000000 --- a/library/alloc/tests/c_str.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::borrow::Cow::{Borrowed, Owned}; -use std::ffi::CStr; -use std::os::raw::c_char; - -#[test] -fn to_str() { - let data = b"123\xE2\x80\xA6\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…")); - assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…")); - } - let data = b"123\xE2\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert!(CStr::from_ptr(ptr).to_str().is_err()); - assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::(format!("123\u{FFFD}"))); - } -} diff --git a/library/alloc/tests/c_str2.rs b/library/alloc/tests/c_str2.rs deleted file mode 100644 index 0f4c27fa123..00000000000 --- a/library/alloc/tests/c_str2.rs +++ /dev/null @@ -1,227 +0,0 @@ -use alloc::ffi::CString; -use alloc::rc::Rc; -use alloc::sync::Arc; -use core::assert_matches::assert_matches; -use core::ffi::{CStr, FromBytesUntilNulError, c_char}; -#[allow(deprecated)] -use core::hash::SipHasher13 as DefaultHasher; -use core::hash::{Hash, Hasher}; - -#[test] -fn c_to_rust() { - let data = b"123\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123"); - assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0"); - } -} - -#[test] -fn simple() { - let s = CString::new("1234").unwrap(); - assert_eq!(s.as_bytes(), b"1234"); - assert_eq!(s.as_bytes_with_nul(), b"1234\0"); -} - -#[test] -fn build_with_zero1() { - assert!(CString::new(&b"\0"[..]).is_err()); -} -#[test] -fn build_with_zero2() { - assert!(CString::new(vec![0]).is_err()); -} - -#[test] -fn formatted() { - let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); - assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); -} - -#[test] -fn borrowed() { - unsafe { - let s = CStr::from_ptr(b"12\0".as_ptr() as *const _); - assert_eq!(s.to_bytes(), b"12"); - assert_eq!(s.to_bytes_with_nul(), b"12\0"); - } -} - -#[test] -fn to_owned() { - let data = b"123\0"; - let ptr = data.as_ptr() as *const c_char; - - let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; - assert_eq!(owned.as_bytes_with_nul(), data); -} - -#[test] -fn equal_hash() { - let data = b"123\xE2\xFA\xA6\0"; - let ptr = data.as_ptr() as *const c_char; - let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; - - #[allow(deprecated)] - let mut s = DefaultHasher::new(); - cstr.hash(&mut s); - let cstr_hash = s.finish(); - #[allow(deprecated)] - let mut s = DefaultHasher::new(); - CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s); - let cstring_hash = s.finish(); - - assert_eq!(cstr_hash, cstring_hash); -} - -#[test] -fn from_bytes_with_nul() { - let data = b"123\0"; - let cstr = CStr::from_bytes_with_nul(data); - assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..])); - let cstr = CStr::from_bytes_with_nul(data); - assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..])); - - unsafe { - let cstr = CStr::from_bytes_with_nul(data); - let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data); - assert_eq!(cstr, Ok(cstr_unchecked)); - } -} - -#[test] -fn from_bytes_with_nul_unterminated() { - let data = b"123"; - let cstr = CStr::from_bytes_with_nul(data); - assert!(cstr.is_err()); -} - -#[test] -fn from_bytes_with_nul_interior() { - let data = b"1\023\0"; - let cstr = CStr::from_bytes_with_nul(data); - assert!(cstr.is_err()); -} - -#[test] -fn cstr_from_bytes_until_nul() { - // Test an empty slice. This should fail because it - // does not contain a nul byte. - let b = b""; - assert_matches!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError { .. })); - - // Test a non-empty slice, that does not contain a nul byte. - let b = b"hello"; - assert_matches!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError { .. })); - - // Test an empty nul-terminated string - let b = b"\0"; - let r = CStr::from_bytes_until_nul(&b[..]).unwrap(); - assert_eq!(r.to_bytes(), b""); - - // Test a slice with the nul byte in the middle - let b = b"hello\0world!"; - let r = CStr::from_bytes_until_nul(&b[..]).unwrap(); - assert_eq!(r.to_bytes(), b"hello"); - - // Test a slice with the nul byte at the end - let b = b"hello\0"; - let r = CStr::from_bytes_until_nul(&b[..]).unwrap(); - assert_eq!(r.to_bytes(), b"hello"); - - // Test a slice with two nul bytes at the end - let b = b"hello\0\0"; - let r = CStr::from_bytes_until_nul(&b[..]).unwrap(); - assert_eq!(r.to_bytes(), b"hello"); - - // Test a slice containing lots of nul bytes - let b = b"\0\0\0\0"; - let r = CStr::from_bytes_until_nul(&b[..]).unwrap(); - assert_eq!(r.to_bytes(), b""); -} - -#[test] -fn into_boxed() { - let orig: &[u8] = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(orig).unwrap(); - let boxed: Box = Box::from(cstr); - let cstring = cstr.to_owned().into_boxed_c_str().into_c_string(); - assert_eq!(cstr, &*boxed); - assert_eq!(&*boxed, &*cstring); - assert_eq!(&*cstring, cstr); -} - -#[test] -fn boxed_default() { - let boxed = >::default(); - assert_eq!(boxed.to_bytes_with_nul(), &[0]); -} - -#[test] -fn test_c_str_clone_into() { - let mut c_string = c"lorem".to_owned(); - let c_ptr = c_string.as_ptr(); - let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap(); - c_str.clone_into(&mut c_string); - assert_eq!(c_str, c_string.as_c_str()); - // The exact same size shouldn't have needed to move its allocation - assert_eq!(c_ptr, c_string.as_ptr()); -} - -#[test] -fn into_rc() { - let orig: &[u8] = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(orig).unwrap(); - let rc: Rc = Rc::from(cstr); - let arc: Arc = Arc::from(cstr); - - assert_eq!(&*rc, cstr); - assert_eq!(&*arc, cstr); - - let rc2: Rc = Rc::from(cstr.to_owned()); - let arc2: Arc = Arc::from(cstr.to_owned()); - - assert_eq!(&*rc2, cstr); - assert_eq!(&*arc2, cstr); -} - -#[test] -fn cstr_const_constructor() { - const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") }; - - assert_eq!(CSTR.to_str().unwrap(), "Hello, world!"); -} - -#[test] -fn cstr_index_from() { - let original = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(original).unwrap(); - let result = CStr::from_bytes_with_nul(&original[7..]).unwrap(); - - assert_eq!(&cstr[7..], result); -} - -#[test] -#[should_panic] -fn cstr_index_from_empty() { - let original = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(original).unwrap(); - let _ = &cstr[original.len()..]; -} - -#[test] -fn c_string_from_empty_string() { - let original = ""; - let cstring = CString::new(original).unwrap(); - assert_eq!(original.as_bytes(), cstring.as_bytes()); - assert_eq!([b'\0'], cstring.as_bytes_with_nul()); -} - -#[test] -fn c_str_from_empty_string() { - let original = b"\0"; - let cstr = CStr::from_bytes_with_nul(original).unwrap(); - assert_eq!([] as [u8; 0], cstr.to_bytes()); - assert_eq!([b'\0'], cstr.to_bytes_with_nul()); -} diff --git a/library/alloc/tests/collections/binary_heap.rs b/library/alloc/tests/collections/binary_heap.rs deleted file mode 100644 index 95f4c3e614f..00000000000 --- a/library/alloc/tests/collections/binary_heap.rs +++ /dev/null @@ -1,580 +0,0 @@ -use alloc::boxed::Box; -use alloc::collections::binary_heap::*; -use std::iter::TrustedLen; -use std::mem; -use std::panic::{AssertUnwindSafe, catch_unwind}; - -use crate::testing::crash_test::{CrashTestDummy, Panic}; - -#[test] -fn test_iterator() { - let data = vec![5, 9, 3]; - let iterout = [9, 5, 3]; - let heap = BinaryHeap::from(data); - let mut i = 0; - for el in &heap { - assert_eq!(*el, iterout[i]); - i += 1; - } -} - -#[test] -fn test_iter_rev_cloned_collect() { - let data = vec![5, 9, 3]; - let iterout = vec![3, 5, 9]; - let pq = BinaryHeap::from(data); - - let v: Vec<_> = pq.iter().rev().cloned().collect(); - assert_eq!(v, iterout); -} - -#[test] -fn test_into_iter_collect() { - let data = vec![5, 9, 3]; - let iterout = vec![9, 5, 3]; - let pq = BinaryHeap::from(data); - - let v: Vec<_> = pq.into_iter().collect(); - assert_eq!(v, iterout); -} - -#[test] -fn test_into_iter_size_hint() { - let data = vec![5, 9]; - let pq = BinaryHeap::from(data); - - let mut it = pq.into_iter(); - - assert_eq!(it.size_hint(), (2, Some(2))); - assert_eq!(it.next(), Some(9)); - - assert_eq!(it.size_hint(), (1, Some(1))); - assert_eq!(it.next(), Some(5)); - - assert_eq!(it.size_hint(), (0, Some(0))); - assert_eq!(it.next(), None); -} - -#[test] -fn test_into_iter_rev_collect() { - let data = vec![5, 9, 3]; - let iterout = vec![3, 5, 9]; - let pq = BinaryHeap::from(data); - - let v: Vec<_> = pq.into_iter().rev().collect(); - assert_eq!(v, iterout); -} - -#[test] -fn test_into_iter_sorted_collect() { - let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); - let it = heap.into_iter_sorted(); - let sorted = it.collect::>(); - assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]); -} - -#[test] -fn test_drain_sorted_collect() { - let mut heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); - let it = heap.drain_sorted(); - let sorted = it.collect::>(); - assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]); -} - -fn check_exact_size_iterator(len: usize, it: I) { - let mut it = it; - - for i in 0..it.len() { - let (lower, upper) = it.size_hint(); - assert_eq!(Some(lower), upper); - assert_eq!(lower, len - i); - assert_eq!(it.len(), len - i); - it.next(); - } - assert_eq!(it.len(), 0); - assert!(it.is_empty()); -} - -#[test] -fn test_exact_size_iterator() { - let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); - check_exact_size_iterator(heap.len(), heap.iter()); - check_exact_size_iterator(heap.len(), heap.clone().into_iter()); - check_exact_size_iterator(heap.len(), heap.clone().into_iter_sorted()); - check_exact_size_iterator(heap.len(), heap.clone().drain()); - check_exact_size_iterator(heap.len(), heap.clone().drain_sorted()); -} - -fn check_trusted_len(len: usize, it: I) { - let mut it = it; - for i in 0..len { - let (lower, upper) = it.size_hint(); - if upper.is_some() { - assert_eq!(Some(lower), upper); - assert_eq!(lower, len - i); - } - it.next(); - } -} - -#[test] -fn test_trusted_len() { - let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); - check_trusted_len(heap.len(), heap.clone().into_iter_sorted()); - check_trusted_len(heap.len(), heap.clone().drain_sorted()); -} - -#[test] -fn test_peek_and_pop() { - let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; - let mut sorted = data.clone(); - sorted.sort(); - let mut heap = BinaryHeap::from(data); - while !heap.is_empty() { - assert_eq!(heap.peek().unwrap(), sorted.last().unwrap()); - assert_eq!(heap.pop().unwrap(), sorted.pop().unwrap()); - } -} - -#[test] -fn test_peek_mut() { - let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; - let mut heap = BinaryHeap::from(data); - assert_eq!(heap.peek(), Some(&10)); - { - let mut top = heap.peek_mut().unwrap(); - *top -= 2; - } - assert_eq!(heap.peek(), Some(&9)); -} - -#[test] -fn test_peek_mut_leek() { - let data = vec![4, 2, 7]; - let mut heap = BinaryHeap::from(data); - let mut max = heap.peek_mut().unwrap(); - *max = -1; - - // The PeekMut object's Drop impl would have been responsible for moving the - // -1 out of the max position of the BinaryHeap, but we don't run it. - mem::forget(max); - - // Absent some mitigation like leak amplification, the -1 would incorrectly - // end up in the last position of the returned Vec, with the rest of the - // heap's original contents in front of it in sorted order. - let sorted_vec = heap.into_sorted_vec(); - assert!(sorted_vec.is_sorted(), "{:?}", sorted_vec); -} - -#[test] -fn test_peek_mut_pop() { - let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; - let mut heap = BinaryHeap::from(data); - assert_eq!(heap.peek(), Some(&10)); - { - let mut top = heap.peek_mut().unwrap(); - *top -= 2; - assert_eq!(PeekMut::pop(top), 8); - } - assert_eq!(heap.peek(), Some(&9)); -} - -#[test] -fn test_push() { - let mut heap = BinaryHeap::from(vec![2, 4, 9]); - assert_eq!(heap.len(), 3); - assert!(*heap.peek().unwrap() == 9); - heap.push(11); - assert_eq!(heap.len(), 4); - assert!(*heap.peek().unwrap() == 11); - heap.push(5); - assert_eq!(heap.len(), 5); - assert!(*heap.peek().unwrap() == 11); - heap.push(27); - assert_eq!(heap.len(), 6); - assert!(*heap.peek().unwrap() == 27); - heap.push(3); - assert_eq!(heap.len(), 7); - assert!(*heap.peek().unwrap() == 27); - heap.push(103); - assert_eq!(heap.len(), 8); - assert!(*heap.peek().unwrap() == 103); -} - -#[test] -fn test_push_unique() { - let mut heap = BinaryHeap::>::from(vec![Box::new(2), Box::new(4), Box::new(9)]); - assert_eq!(heap.len(), 3); - assert!(**heap.peek().unwrap() == 9); - heap.push(Box::new(11)); - assert_eq!(heap.len(), 4); - assert!(**heap.peek().unwrap() == 11); - heap.push(Box::new(5)); - assert_eq!(heap.len(), 5); - assert!(**heap.peek().unwrap() == 11); - heap.push(Box::new(27)); - assert_eq!(heap.len(), 6); - assert!(**heap.peek().unwrap() == 27); - heap.push(Box::new(3)); - assert_eq!(heap.len(), 7); - assert!(**heap.peek().unwrap() == 27); - heap.push(Box::new(103)); - assert_eq!(heap.len(), 8); - assert!(**heap.peek().unwrap() == 103); -} - -fn check_to_vec(mut data: Vec) { - let heap = BinaryHeap::from(data.clone()); - let mut v = heap.clone().into_vec(); - v.sort(); - data.sort(); - - assert_eq!(v, data); - assert_eq!(heap.into_sorted_vec(), data); -} - -#[test] -fn test_to_vec() { - check_to_vec(vec![]); - check_to_vec(vec![5]); - check_to_vec(vec![3, 2]); - check_to_vec(vec![2, 3]); - check_to_vec(vec![5, 1, 2]); - check_to_vec(vec![1, 100, 2, 3]); - check_to_vec(vec![1, 3, 5, 7, 9, 2, 4, 6, 8, 0]); - check_to_vec(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); - check_to_vec(vec![9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]); - check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - check_to_vec(vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]); - check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]); - check_to_vec(vec![5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]); -} - -#[test] -fn test_in_place_iterator_specialization() { - let src: Vec = vec![1, 2, 3]; - let src_ptr = src.as_ptr(); - let heap: BinaryHeap<_> = src.into_iter().map(std::convert::identity).collect(); - let heap_ptr = heap.iter().next().unwrap() as *const usize; - assert_eq!(src_ptr, heap_ptr); - let sink: Vec<_> = heap.into_iter().map(std::convert::identity).collect(); - let sink_ptr = sink.as_ptr(); - assert_eq!(heap_ptr, sink_ptr); -} - -#[test] -fn test_empty_pop() { - let mut heap = BinaryHeap::::new(); - assert!(heap.pop().is_none()); -} - -#[test] -fn test_empty_peek() { - let empty = BinaryHeap::::new(); - assert!(empty.peek().is_none()); -} - -#[test] -fn test_empty_peek_mut() { - let mut empty = BinaryHeap::::new(); - assert!(empty.peek_mut().is_none()); -} - -#[test] -fn test_from_iter() { - let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1]; - - let mut q: BinaryHeap<_> = xs.iter().rev().cloned().collect(); - - for &x in &xs { - assert_eq!(q.pop().unwrap(), x); - } -} - -#[test] -fn test_drain() { - let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect(); - - assert_eq!(q.drain().take(5).count(), 5); - - assert!(q.is_empty()); -} - -#[test] -fn test_drain_sorted() { - let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect(); - - assert_eq!(q.drain_sorted().take(5).collect::>(), vec![9, 8, 7, 6, 5]); - - assert!(q.is_empty()); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_drain_sorted_leak() { - let d0 = CrashTestDummy::new(0); - let d1 = CrashTestDummy::new(1); - let d2 = CrashTestDummy::new(2); - let d3 = CrashTestDummy::new(3); - let d4 = CrashTestDummy::new(4); - let d5 = CrashTestDummy::new(5); - let mut q = BinaryHeap::from(vec![ - d0.spawn(Panic::Never), - d1.spawn(Panic::Never), - d2.spawn(Panic::Never), - d3.spawn(Panic::InDrop), - d4.spawn(Panic::Never), - d5.spawn(Panic::Never), - ]); - - catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).unwrap_err(); - - assert_eq!(d0.dropped(), 1); - assert_eq!(d1.dropped(), 1); - assert_eq!(d2.dropped(), 1); - assert_eq!(d3.dropped(), 1); - assert_eq!(d4.dropped(), 1); - assert_eq!(d5.dropped(), 1); - assert!(q.is_empty()); -} - -#[test] -fn test_drain_forget() { - let a = CrashTestDummy::new(0); - let b = CrashTestDummy::new(1); - let c = CrashTestDummy::new(2); - let mut q = - BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]); - - catch_unwind(AssertUnwindSafe(|| { - let mut it = q.drain(); - it.next(); - mem::forget(it); - })) - .unwrap(); - // Behavior after leaking is explicitly unspecified and order is arbitrary, - // so it's fine if these start failing, but probably worth knowing. - assert!(q.is_empty()); - assert_eq!(a.dropped() + b.dropped() + c.dropped(), 1); - assert_eq!(a.dropped(), 0); - assert_eq!(b.dropped(), 0); - assert_eq!(c.dropped(), 1); - drop(q); - assert_eq!(a.dropped(), 0); - assert_eq!(b.dropped(), 0); - assert_eq!(c.dropped(), 1); -} - -#[test] -fn test_drain_sorted_forget() { - let a = CrashTestDummy::new(0); - let b = CrashTestDummy::new(1); - let c = CrashTestDummy::new(2); - let mut q = - BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]); - - catch_unwind(AssertUnwindSafe(|| { - let mut it = q.drain_sorted(); - it.next(); - mem::forget(it); - })) - .unwrap(); - // Behavior after leaking is explicitly unspecified, - // so it's fine if these start failing, but probably worth knowing. - assert_eq!(q.len(), 2); - assert_eq!(a.dropped(), 0); - assert_eq!(b.dropped(), 0); - assert_eq!(c.dropped(), 1); - drop(q); - assert_eq!(a.dropped(), 1); - assert_eq!(b.dropped(), 1); - assert_eq!(c.dropped(), 1); -} - -#[test] -fn test_extend_ref() { - let mut a = BinaryHeap::new(); - a.push(1); - a.push(2); - - a.extend(&[3, 4, 5]); - - assert_eq!(a.len(), 5); - assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]); - - let mut a = BinaryHeap::new(); - a.push(1); - a.push(2); - let mut b = BinaryHeap::new(); - b.push(3); - b.push(4); - b.push(5); - - a.extend(&b); - - assert_eq!(a.len(), 5); - assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]); -} - -#[test] -fn test_append() { - let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]); - let mut b = BinaryHeap::from(vec![-20, 5, 43]); - - a.append(&mut b); - - assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]); - assert!(b.is_empty()); -} - -#[test] -fn test_append_to_empty() { - let mut a = BinaryHeap::new(); - let mut b = BinaryHeap::from(vec![-20, 5, 43]); - - a.append(&mut b); - - assert_eq!(a.into_sorted_vec(), [-20, 5, 43]); - assert!(b.is_empty()); -} - -#[test] -fn test_extend_specialization() { - let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]); - let b = BinaryHeap::from(vec![-20, 5, 43]); - - a.extend(b); - - assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]); -} - -#[allow(dead_code)] -fn assert_covariance() { - fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { - d - } -} - -#[test] -fn test_retain() { - let mut a = BinaryHeap::from(vec![100, 10, 50, 1, 2, 20, 30]); - a.retain(|&x| x != 2); - - // Check that 20 moved into 10's place. - assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]); - - a.retain(|_| true); - - assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]); - - a.retain(|&x| x < 50); - - assert_eq!(a.clone().into_vec(), [30, 20, 10, 1]); - - a.retain(|_| false); - - assert!(a.is_empty()); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_retain_catch_unwind() { - let mut heap = BinaryHeap::from(vec![3, 1, 2]); - - // Removes the 3, then unwinds out of retain. - let _ = catch_unwind(AssertUnwindSafe(|| { - heap.retain(|e| { - if *e == 1 { - panic!(); - } - false - }); - })); - - // Naively this would be [1, 2] (an invalid heap) if BinaryHeap delegates to - // Vec's retain impl and then does not rebuild the heap after that unwinds. - assert_eq!(heap.into_vec(), [2, 1]); -} - -// old binaryheap failed this test -// -// Integrity means that all elements are present after a comparison panics, -// even if the order might not be correct. -// -// Destructors must be called exactly once per element. -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn panic_safe() { - use std::cmp; - use std::panic::{self, AssertUnwindSafe}; - use std::sync::atomic::{AtomicUsize, Ordering}; - - use rand::seq::SliceRandom; - - static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); - - #[derive(Eq, PartialEq, Ord, Clone, Debug)] - struct PanicOrd(T, bool); - - impl Drop for PanicOrd { - fn drop(&mut self) { - // update global drop count - DROP_COUNTER.fetch_add(1, Ordering::SeqCst); - } - } - - impl PartialOrd for PanicOrd { - fn partial_cmp(&self, other: &Self) -> Option { - if self.1 || other.1 { - panic!("Panicking comparison"); - } - self.0.partial_cmp(&other.0) - } - } - let mut rng = crate::test_rng(); - const DATASZ: usize = 32; - // Miri is too slow - let ntest = if cfg!(miri) { 1 } else { 10 }; - - // don't use 0 in the data -- we want to catch the zeroed-out case. - let data = (1..=DATASZ).collect::>(); - - // since it's a fuzzy test, run several tries. - for _ in 0..ntest { - for i in 1..=DATASZ { - DROP_COUNTER.store(0, Ordering::SeqCst); - - let mut panic_ords: Vec<_> = - data.iter().filter(|&&x| x != i).map(|&x| PanicOrd(x, false)).collect(); - let panic_item = PanicOrd(i, true); - - // heapify the sane items - panic_ords.shuffle(&mut rng); - let mut heap = BinaryHeap::from(panic_ords); - let inner_data; - - { - // push the panicking item to the heap and catch the panic - let thread_result = { - let mut heap_ref = AssertUnwindSafe(&mut heap); - panic::catch_unwind(move || { - heap_ref.push(panic_item); - }) - }; - assert!(thread_result.is_err()); - - // Assert no elements were dropped - let drops = DROP_COUNTER.load(Ordering::SeqCst); - assert!(drops == 0, "Must not drop items. drops={}", drops); - inner_data = heap.clone().into_vec(); - drop(heap); - } - let drops = DROP_COUNTER.load(Ordering::SeqCst); - assert_eq!(drops, DATASZ); - - let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::>(); - data_sorted.sort(); - assert_eq!(data_sorted, data); - } - } -} diff --git a/library/alloc/tests/collections/mod.rs b/library/alloc/tests/collections/mod.rs deleted file mode 100644 index e73f3aaef8c..00000000000 --- a/library/alloc/tests/collections/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod binary_heap; diff --git a/library/alloc/tests/const_fns.rs b/library/alloc/tests/const_fns.rs deleted file mode 100644 index 4e7d7fc833e..00000000000 --- a/library/alloc/tests/const_fns.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Test const functions in the library - -pub const MY_VEC: Vec = Vec::new(); - -// FIXME(#110395) -// pub const MY_VEC2: Vec = Default::default(); - -pub const MY_STRING: String = String::new(); - -// pub const MY_STRING2: String = Default::default(); - -// pub const MY_BOXED_SLICE: Box<[usize]> = Default::default(); -// pub const MY_BOXED_STR: Box = Default::default(); - -use std::collections::{BTreeMap, BTreeSet}; - -pub const MY_BTREEMAP: BTreeMap = BTreeMap::new(); -pub const MAP: &'static BTreeMap = &MY_BTREEMAP; -pub const MAP_LEN: usize = MAP.len(); -pub const MAP_IS_EMPTY: bool = MAP.is_empty(); - -pub const MY_BTREESET: BTreeSet = BTreeSet::new(); -pub const SET: &'static BTreeSet = &MY_BTREESET; -pub const SET_LEN: usize = SET.len(); -pub const SET_IS_EMPTY: bool = SET.is_empty(); - -#[test] -fn test_const() { - assert_eq!(MY_VEC, /* MY_VEC */ vec![]); - assert_eq!(MY_STRING, /* MY_STRING2 */ String::default()); - - // assert_eq!(MY_VEC, *MY_BOXED_SLICE); - // assert_eq!(MY_STRING, *MY_BOXED_STR); - - assert_eq!(MAP_LEN, 0); - assert_eq!(SET_LEN, 0); - assert!(MAP_IS_EMPTY && SET_IS_EMPTY); -} diff --git a/library/alloc/tests/cow_str.rs b/library/alloc/tests/cow_str.rs deleted file mode 100644 index 62a5c245a54..00000000000 --- a/library/alloc/tests/cow_str.rs +++ /dev/null @@ -1,144 +0,0 @@ -use std::borrow::Cow; - -// check that Cow<'a, str> implements addition -#[test] -fn check_cow_add_cow() { - let borrowed1 = Cow::Borrowed("Hello, "); - let borrowed2 = Cow::Borrowed("World!"); - let borrow_empty = Cow::Borrowed(""); - - let owned1: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); - let owned2: Cow<'_, str> = Cow::Owned(String::from("Rustaceans!")); - let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); - - assert_eq!("Hello, World!", borrowed1.clone() + borrowed2.clone()); - assert_eq!("Hello, Rustaceans!", borrowed1.clone() + owned2.clone()); - - assert_eq!("Hi, World!", owned1.clone() + borrowed2.clone()); - assert_eq!("Hi, Rustaceans!", owned1.clone() + owned2.clone()); - - if let Cow::Owned(_) = borrowed1.clone() + borrow_empty.clone() { - panic!("Adding empty strings to a borrow should note allocate"); - } - if let Cow::Owned(_) = borrow_empty.clone() + borrowed1.clone() { - panic!("Adding empty strings to a borrow should note allocate"); - } - if let Cow::Owned(_) = borrowed1.clone() + owned_empty.clone() { - panic!("Adding empty strings to a borrow should note allocate"); - } - if let Cow::Owned(_) = owned_empty.clone() + borrowed1.clone() { - panic!("Adding empty strings to a borrow should note allocate"); - } -} - -#[test] -fn check_cow_add_str() { - let borrowed = Cow::Borrowed("Hello, "); - let borrow_empty = Cow::Borrowed(""); - - let owned: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); - let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); - - assert_eq!("Hello, World!", borrowed.clone() + "World!"); - - assert_eq!("Hi, World!", owned.clone() + "World!"); - - if let Cow::Owned(_) = borrowed.clone() + "" { - panic!("Adding empty strings to a borrow should note allocate"); - } - if let Cow::Owned(_) = borrow_empty.clone() + "Hello, " { - panic!("Adding empty strings to a borrow should note allocate"); - } - if let Cow::Owned(_) = owned_empty.clone() + "Hello, " { - panic!("Adding empty strings to a borrow should note allocate"); - } -} - -#[test] -fn check_cow_add_assign_cow() { - let mut borrowed1 = Cow::Borrowed("Hello, "); - let borrowed2 = Cow::Borrowed("World!"); - let borrow_empty = Cow::Borrowed(""); - - let mut owned1: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); - let owned2: Cow<'_, str> = Cow::Owned(String::from("Rustaceans!")); - let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); - - let mut s = borrowed1.clone(); - s += borrow_empty.clone(); - assert_eq!("Hello, ", s); - if let Cow::Owned(_) = s { - panic!("Adding empty strings to a borrow should note allocate"); - } - let mut s = borrow_empty.clone(); - s += borrowed1.clone(); - assert_eq!("Hello, ", s); - if let Cow::Owned(_) = s { - panic!("Adding empty strings to a borrow should note allocate"); - } - let mut s = borrowed1.clone(); - s += owned_empty.clone(); - assert_eq!("Hello, ", s); - if let Cow::Owned(_) = s { - panic!("Adding empty strings to a borrow should note allocate"); - } - let mut s = owned_empty.clone(); - s += borrowed1.clone(); - assert_eq!("Hello, ", s); - if let Cow::Owned(_) = s { - panic!("Adding empty strings to a borrow should note allocate"); - } - - owned1 += borrowed2; - borrowed1 += owned2; - - assert_eq!("Hi, World!", owned1); - assert_eq!("Hello, Rustaceans!", borrowed1); -} - -#[test] -fn check_cow_add_assign_str() { - let mut borrowed = Cow::Borrowed("Hello, "); - let borrow_empty = Cow::Borrowed(""); - - let mut owned: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); - let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); - - let mut s = borrowed.clone(); - s += ""; - assert_eq!("Hello, ", s); - if let Cow::Owned(_) = s { - panic!("Adding empty strings to a borrow should note allocate"); - } - let mut s = borrow_empty.clone(); - s += "World!"; - assert_eq!("World!", s); - if let Cow::Owned(_) = s { - panic!("Adding empty strings to a borrow should note allocate"); - } - let mut s = owned_empty.clone(); - s += "World!"; - assert_eq!("World!", s); - if let Cow::Owned(_) = s { - panic!("Adding empty strings to a borrow should note allocate"); - } - - owned += "World!"; - borrowed += "World!"; - - assert_eq!("Hi, World!", owned); - assert_eq!("Hello, World!", borrowed); -} - -#[test] -fn check_cow_clone_from() { - let mut c1: Cow<'_, str> = Cow::Owned(String::with_capacity(25)); - let s: String = "hi".to_string(); - assert!(s.capacity() < 25); - let c2: Cow<'_, str> = Cow::Owned(s); - c1.clone_from(&c2); - assert!(c1.into_owned().capacity() >= 25); - let mut c3: Cow<'_, str> = Cow::Borrowed("bye"); - c3.clone_from(&c2); - assert_eq!(c2, c3); -} diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs deleted file mode 100644 index c13074c53b7..00000000000 --- a/library/alloc/tests/fmt.rs +++ /dev/null @@ -1,326 +0,0 @@ -#![deny(warnings)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#![allow(static_mut_refs)] - -use std::cell::RefCell; -use std::fmt::{self, Write}; -use std::ptr; - -#[test] -fn test_format() { - let s = fmt::format(format_args!("Hello, {}!", "world")); - assert_eq!(s, "Hello, world!"); -} - -struct A; -struct B; -struct C; -struct D; - -impl fmt::LowerHex for A { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("aloha") - } -} -impl fmt::UpperHex for B { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("adios") - } -} -impl fmt::Display for C { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad_integral(true, "☃", "123") - } -} -impl fmt::Binary for D { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("aa")?; - f.write_char('☃')?; - f.write_str("bb") - } -} - -macro_rules! t { - ($a:expr, $b:expr) => { - assert_eq!($a, $b) - }; -} - -#[test] -fn test_format_macro_interface() { - // Various edge cases without formats - t!(format!(""), ""); - t!(format!("hello"), "hello"); - t!(format!("hello {{"), "hello {"); - - // default formatters should work - t!(format!("{}", 1.0f32), "1"); - t!(format!("{}", 1.0f64), "1"); - t!(format!("{}", "a"), "a"); - t!(format!("{}", "a".to_string()), "a"); - t!(format!("{}", false), "false"); - t!(format!("{}", 'a'), "a"); - - // At least exercise all the formats - t!(format!("{}", true), "true"); - t!(format!("{}", '☃'), "☃"); - t!(format!("{}", 10), "10"); - t!(format!("{}", 10_usize), "10"); - t!(format!("{:?}", '☃'), "'☃'"); - t!(format!("{:?}", 10), "10"); - t!(format!("{:?}", 10_usize), "10"); - t!(format!("{:?}", "true"), "\"true\""); - t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\""); - t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), r#""foo\n\"bar\"\r\n'baz'\t\\qux\\""#); - t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), r#""foo\0bar\u{1}baz\u{7f}qux""#); - t!(format!("{:o}", 10_usize), "12"); - t!(format!("{:x}", 10_usize), "a"); - t!(format!("{:X}", 10_usize), "A"); - t!(format!("{}", "foo"), "foo"); - t!(format!("{}", "foo".to_string()), "foo"); - if cfg!(target_pointer_width = "32") { - t!(format!("{:#p}", ptr::without_provenance::(0x1234)), "0x00001234"); - t!(format!("{:#p}", ptr::without_provenance_mut::(0x1234)), "0x00001234"); - } else { - t!(format!("{:#p}", ptr::without_provenance::(0x1234)), "0x0000000000001234"); - t!(format!("{:#p}", ptr::without_provenance_mut::(0x1234)), "0x0000000000001234"); - } - t!(format!("{:p}", ptr::without_provenance::(0x1234)), "0x1234"); - t!(format!("{:p}", ptr::without_provenance_mut::(0x1234)), "0x1234"); - t!(format!("{A:x}"), "aloha"); - t!(format!("{B:X}"), "adios"); - t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); - t!(format!("{1} {0}", 0, 1), "1 0"); - t!(format!("{foo} {bar}", foo = 0, bar = 1), "0 1"); - t!(format!("{foo} {1} {bar} {0}", 0, 1, foo = 2, bar = 3), "2 1 3 0"); - t!(format!("{} {0}", "a"), "a a"); - t!(format!("{_foo}", _foo = 6usize), "6"); - t!(format!("{foo_bar}", foo_bar = 1), "1"); - t!(format!("{}", 5 + 5), "10"); - t!(format!("{C:#4}"), "☃123"); - t!(format!("{D:b}"), "aa☃bb"); - - let a: &dyn fmt::Debug = &1; - t!(format!("{a:?}"), "1"); - - // Formatting strings and their arguments - t!(format!("{}", "a"), "a"); - t!(format!("{:4}", "a"), "a "); - t!(format!("{:4}", "☃"), "☃ "); - t!(format!("{:>4}", "a"), " a"); - t!(format!("{:<4}", "a"), "a "); - t!(format!("{:^5}", "a"), " a "); - t!(format!("{:^5}", "aa"), " aa "); - t!(format!("{:^4}", "a"), " a "); - t!(format!("{:^4}", "aa"), " aa "); - t!(format!("{:.4}", "a"), "a"); - t!(format!("{:4.4}", "a"), "a "); - t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), " aaaa"); - t!(format!("{:2.4}", "aaaaa"), "aaaa"); - t!(format!("{:2.4}", "aaaa"), "aaaa"); - t!(format!("{:2.4}", "aaa"), "aaa"); - t!(format!("{:2.4}", "aa"), "aa"); - t!(format!("{:2.4}", "a"), "a "); - t!(format!("{:0>2}", "a"), "0a"); - t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); - t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4), "aaaa"); - t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4), "aaaa"); - t!(format!("{:1$}", "a", 4), "a "); - t!(format!("{1:0$}", 4, "a"), "a "); - t!(format!("{:a$}", "a", a = 4), "a "); - t!(format!("{:-#}", "a"), "a"); - t!(format!("{:+#}", "a"), "a"); - t!(format!("{:/^10.8}", "1234567890"), "/12345678/"); - - // Some float stuff - t!(format!("{:}", 1.0f32), "1"); - t!(format!("{:}", 1.0f64), "1"); - t!(format!("{:.3}", 1.0f64), "1.000"); - t!(format!("{:10.3}", 1.0f64), " 1.000"); - t!(format!("{:+10.3}", 1.0f64), " +1.000"); - t!(format!("{:+10.3}", -1.0f64), " -1.000"); - - t!(format!("{:e}", 1.2345e6f32), "1.2345e6"); - t!(format!("{:e}", 1.2345e6f64), "1.2345e6"); - t!(format!("{:E}", 1.2345e6f64), "1.2345E6"); - t!(format!("{:.3e}", 1.2345e6f64), "1.234e6"); - t!(format!("{:10.3e}", 1.2345e6f64), " 1.234e6"); - t!(format!("{:+10.3e}", 1.2345e6f64), " +1.234e6"); - t!(format!("{:+10.3e}", -1.2345e6f64), " -1.234e6"); - - // Float edge cases - t!(format!("{}", -0.0), "-0"); - t!(format!("{:?}", 0.0), "0.0"); - - // sign aware zero padding - t!(format!("{:<3}", 1), "1 "); - t!(format!("{:>3}", 1), " 1"); - t!(format!("{:^3}", 1), " 1 "); - t!(format!("{:03}", 1), "001"); - t!(format!("{:<03}", 1), "001"); - t!(format!("{:>03}", 1), "001"); - t!(format!("{:^03}", 1), "001"); - t!(format!("{:+03}", 1), "+01"); - t!(format!("{:<+03}", 1), "+01"); - t!(format!("{:>+03}", 1), "+01"); - t!(format!("{:^+03}", 1), "+01"); - t!(format!("{:#05x}", 1), "0x001"); - t!(format!("{:<#05x}", 1), "0x001"); - t!(format!("{:>#05x}", 1), "0x001"); - t!(format!("{:^#05x}", 1), "0x001"); - t!(format!("{:05}", 1.2), "001.2"); - t!(format!("{:<05}", 1.2), "001.2"); - t!(format!("{:>05}", 1.2), "001.2"); - t!(format!("{:^05}", 1.2), "001.2"); - t!(format!("{:05}", -1.2), "-01.2"); - t!(format!("{:<05}", -1.2), "-01.2"); - t!(format!("{:>05}", -1.2), "-01.2"); - t!(format!("{:^05}", -1.2), "-01.2"); - t!(format!("{:+05}", 1.2), "+01.2"); - t!(format!("{:<+05}", 1.2), "+01.2"); - t!(format!("{:>+05}", 1.2), "+01.2"); - t!(format!("{:^+05}", 1.2), "+01.2"); - - // Ergonomic format_args! - t!(format!("{0:x} {0:X}", 15), "f F"); - t!(format!("{0:x} {0:X} {}", 15), "f F 15"); - t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a = 15), "dDfEeF"); - t!(format!("{a:x} {a:X}", a = 15), "f F"); - - // And its edge cases - t!( - format!( - "{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}", - 4, - a = "abcdefg", - b = "hijklmn", - c = 3 - ), - "abcd hijk 4\nabc hij 3" - ); - t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a = "abcdef"), "abcd 4 efg"); - t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a = 2), "aa 2 0x2"); - - // Test that pointers don't get truncated. - { - let val = usize::MAX; - let exp = format!("{val:#x}"); - t!(format!("{:p}", std::ptr::without_provenance::(val)), exp); - } - - // Escaping - t!(format!("{{"), "{"); - t!(format!("}}"), "}"); - - // make sure that format! doesn't move out of local variables - let a = Box::new(3); - let _ = format!("{a}"); - let _ = format!("{a}"); - - // make sure that format! doesn't cause spurious unused-unsafe warnings when - // it's inside of an outer unsafe block - unsafe { - let a: isize = ::std::mem::transmute(3_usize); - let _ = format!("{a}"); - } - - // test that trailing commas are acceptable - let _ = format!("{}", "test",); - let _ = format!("{foo}", foo = "test",); -} - -// Basic test to make sure that we can invoke the `write!` macro with an -// fmt::Write instance. -#[test] -fn test_write() { - let mut buf = String::new(); - let _ = write!(&mut buf, "{}", 3); - { - let w = &mut buf; - let _ = write!(w, "{foo}", foo = 4); - let _ = write!(w, "{}", "hello"); - let _ = writeln!(w, "{}", "line"); - let _ = writeln!(w, "{foo}", foo = "bar"); - let _ = w.write_char('☃'); - let _ = w.write_str("str"); - } - - t!(buf, "34helloline\nbar\n☃str"); -} - -// Just make sure that the macros are defined, there's not really a lot that we -// can do with them just yet (to test the output) -#[test] -fn test_print() { - print!("hi"); - print!("{:?}", vec![0u8]); - println!("hello"); - println!("this is a {}", "test"); - println!("{foo}", foo = "bar"); -} - -// Just make sure that the macros are defined, there's not really a lot that we -// can do with them just yet (to test the output) -#[test] -fn test_format_args() { - let mut buf = String::new(); - { - let w = &mut buf; - let _ = write!(w, "{}", format_args!("{}", 1)); - let _ = write!(w, "{}", format_args!("test")); - let _ = write!(w, "{}", format_args!("{test}", test = 3)); - } - let s = buf; - t!(s, "1test3"); - - let s = fmt::format(format_args!("hello {}", "world")); - t!(s, "hello world"); - let s = format!("{}: {}", "args were", format_args!("hello {}", "world")); - t!(s, "args were: hello world"); -} - -#[test] -fn test_order() { - // Make sure format!() arguments are always evaluated in a left-to-right - // ordering - fn foo() -> isize { - static mut FOO: isize = 0; - unsafe { - FOO += 1; - FOO - } - } - assert_eq!( - format!("{} {} {a} {b} {} {c}", foo(), foo(), foo(), a = foo(), b = foo(), c = foo()), - "1 2 4 5 3 6".to_string() - ); -} - -#[test] -fn test_once() { - // Make sure each argument are evaluated only once even though it may be - // formatted multiple times - fn foo() -> isize { - static mut FOO: isize = 0; - unsafe { - FOO += 1; - FOO - } - } - assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a = foo()), "1 1 1 2 2 2".to_string()); -} - -#[test] -fn test_refcell() { - let refcell = RefCell::new(5); - assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }"); - let borrow = refcell.borrow_mut(); - assert_eq!(format!("{refcell:?}"), "RefCell { value: }"); - drop(borrow); - assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }"); -} diff --git a/library/alloc/tests/heap.rs b/library/alloc/tests/heap.rs deleted file mode 100644 index 246b341eeb3..00000000000 --- a/library/alloc/tests/heap.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::alloc::{Allocator, Global, Layout, System}; - -/// Issue #45955 and #62251. -#[test] -fn alloc_system_overaligned_request() { - check_overalign_requests(System) -} - -#[test] -fn std_heap_overaligned_request() { - check_overalign_requests(Global) -} - -fn check_overalign_requests(allocator: T) { - for &align in &[4, 8, 16, 32] { - // less than and bigger than `MIN_ALIGN` - for &size in &[align / 2, align - 1] { - // size less than alignment - let iterations = 128; - unsafe { - let pointers: Vec<_> = (0..iterations) - .map(|_| { - allocator.allocate(Layout::from_size_align(size, align).unwrap()).unwrap() - }) - .collect(); - for &ptr in &pointers { - assert_eq!( - (ptr.as_non_null_ptr().as_ptr() as usize) % align, - 0, - "Got a pointer less aligned than requested" - ) - } - - // Clean up - for &ptr in &pointers { - allocator.deallocate( - ptr.as_non_null_ptr(), - Layout::from_size_align(size, align).unwrap(), - ) - } - } - } - } -} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs deleted file mode 100644 index 785070fb2bb..00000000000 --- a/library/alloc/tests/lib.rs +++ /dev/null @@ -1,106 +0,0 @@ -#![feature(allocator_api)] -#![feature(alloc_layout_extra)] -#![feature(iter_array_chunks)] -#![feature(assert_matches)] -#![feature(btree_extract_if)] -#![feature(char_max_len)] -#![feature(cow_is_borrowed)] -#![feature(core_intrinsics)] -#![feature(downcast_unchecked)] -#![feature(exact_size_is_empty)] -#![feature(hashmap_internals)] -#![feature(linked_list_cursors)] -#![feature(map_try_insert)] -#![feature(pattern)] -#![feature(trusted_len)] -#![feature(try_reserve_kind)] -#![feature(try_with_capacity)] -#![feature(unboxed_closures)] -#![feature(binary_heap_into_iter_sorted)] -#![feature(binary_heap_drain_sorted)] -#![feature(slice_ptr_get)] -#![feature(inplace_iteration)] -#![feature(iter_advance_by)] -#![feature(iter_next_chunk)] -#![feature(round_char_boundary)] -#![feature(slice_partition_dedup)] -#![feature(string_from_utf8_lossy_owned)] -#![feature(string_remove_matches)] -#![feature(const_btree_len)] -#![feature(const_trait_impl)] -#![feature(panic_update_hook)] -#![feature(pointer_is_aligned_to)] -#![feature(test)] -#![feature(thin_box)] -#![feature(drain_keep_rest)] -#![feature(local_waker)] -#![feature(str_as_str)] -#![feature(strict_provenance_lints)] -#![feature(vec_deque_pop_if)] -#![feature(unique_rc_arc)] -#![feature(macro_metavar_expr_concat)] -#![allow(internal_features)] -#![deny(fuzzy_provenance_casts)] -#![deny(unsafe_op_in_unsafe_fn)] - -extern crate test; - -use std::hash::{DefaultHasher, Hash, Hasher}; - -mod alloc; -mod arc; -mod autotraits; -mod borrow; -mod boxed; -mod btree_set_hash; -mod c_str; -mod c_str2; -mod collections; -mod const_fns; -mod cow_str; -mod fmt; -mod heap; -mod linked_list; -mod misc_tests; -mod rc; -mod slice; -mod sort; -mod str; -mod string; -mod sync; -mod task; -mod testing; -mod thin_box; -mod vec; -mod vec_deque; - -fn hash(t: &T) -> u64 { - let mut s = DefaultHasher::new(); - t.hash(&mut s); - s.finish() -} - -/// Copied from `std::test_helpers::test_rng`, since these tests rely on the -/// seed not being the same for every RNG invocation too. -fn test_rng() -> rand_xorshift::XorShiftRng { - use std::hash::{BuildHasher, Hash, Hasher}; - let mut hasher = std::hash::RandomState::new().build_hasher(); - std::panic::Location::caller().hash(&mut hasher); - let hc64 = hasher.finish(); - let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); - let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); - rand::SeedableRng::from_seed(seed) -} - -#[test] -fn test_boxed_hasher() { - let ordinary_hash = hash(&5u32); - - let mut hasher_1 = Box::new(DefaultHasher::new()); - 5u32.hash(&mut hasher_1); - assert_eq!(ordinary_hash, hasher_1.finish()); - - let mut hasher_2 = Box::new(DefaultHasher::new()) as Box; - 5u32.hash(&mut hasher_2); - assert_eq!(ordinary_hash, hasher_2.finish()); -} diff --git a/library/alloc/tests/linked_list.rs b/library/alloc/tests/linked_list.rs deleted file mode 100644 index 65b09cb00c4..00000000000 --- a/library/alloc/tests/linked_list.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::collections::LinkedList; - -#[test] -fn test_hash() { - use crate::hash; - - let mut x = LinkedList::new(); - let mut y = LinkedList::new(); - - assert!(hash(&x) == hash(&y)); - - x.push_back(1); - x.push_back(2); - x.push_back(3); - - y.push_front(3); - y.push_front(2); - y.push_front(1); - - assert!(hash(&x) == hash(&y)); -} diff --git a/library/alloc/tests/misc_tests.rs b/library/alloc/tests/misc_tests.rs deleted file mode 100644 index b95d11cb07e..00000000000 --- a/library/alloc/tests/misc_tests.rs +++ /dev/null @@ -1,140 +0,0 @@ -//! Test for `boxed` mod. - -use core::any::Any; -use core::ops::Deref; -use std::boxed::Box; - -#[test] -fn test_owned_clone() { - let a = Box::new(5); - let b: Box = a.clone(); - assert!(a == b); -} - -#[derive(Debug, PartialEq, Eq)] -struct Test; - -#[test] -fn any_move() { - let a = Box::new(8) as Box; - let b = Box::new(Test) as Box; - - let a: Box = a.downcast::().unwrap(); - assert_eq!(*a, 8); - - let b: Box = b.downcast::().unwrap(); - assert_eq!(*b, Test); - - let a = Box::new(8) as Box; - let b = Box::new(Test) as Box; - - assert!(a.downcast::>().is_err()); - assert!(b.downcast::>().is_err()); -} - -#[test] -fn test_show() { - let a = Box::new(8) as Box; - let b = Box::new(Test) as Box; - let a_str = format!("{a:?}"); - let b_str = format!("{b:?}"); - assert_eq!(a_str, "Any { .. }"); - assert_eq!(b_str, "Any { .. }"); - - static EIGHT: usize = 8; - static TEST: Test = Test; - let a = &EIGHT as &dyn Any; - let b = &TEST as &dyn Any; - let s = format!("{a:?}"); - assert_eq!(s, "Any { .. }"); - let s = format!("{b:?}"); - assert_eq!(s, "Any { .. }"); -} - -#[test] -fn deref() { - fn homura>(_: T) {} - homura(Box::new(765)); -} - -#[test] -fn raw_sized() { - let x = Box::new(17); - let p = Box::into_raw(x); - unsafe { - assert_eq!(17, *p); - *p = 19; - let y = Box::from_raw(p); - assert_eq!(19, *y); - } -} - -#[test] -fn raw_trait() { - trait Foo { - fn get(&self) -> u32; - fn set(&mut self, value: u32); - } - - struct Bar(u32); - - impl Foo for Bar { - fn get(&self) -> u32 { - self.0 - } - - fn set(&mut self, value: u32) { - self.0 = value; - } - } - - let x: Box = Box::new(Bar(17)); - let p = Box::into_raw(x); - unsafe { - assert_eq!(17, (*p).get()); - (*p).set(19); - let y: Box = Box::from_raw(p); - assert_eq!(19, y.get()); - } -} - -#[test] -fn f64_slice() { - let slice: &[f64] = &[-1.0, 0.0, 1.0, f64::INFINITY]; - let boxed: Box<[f64]> = Box::from(slice); - assert_eq!(&*boxed, slice) -} - -#[test] -fn i64_slice() { - let slice: &[i64] = &[i64::MIN, -2, -1, 0, 1, 2, i64::MAX]; - let boxed: Box<[i64]> = Box::from(slice); - assert_eq!(&*boxed, slice) -} - -#[test] -fn str_slice() { - let s = "Hello, world!"; - let boxed: Box = Box::from(s); - assert_eq!(&*boxed, s) -} - -#[test] -fn boxed_slice_from_iter() { - let iter = 0..100; - let boxed: Box<[u32]> = iter.collect(); - assert_eq!(boxed.len(), 100); - assert_eq!(boxed[7], 7); -} - -#[test] -fn test_array_from_slice() { - let v = vec![1, 2, 3]; - let r: Box<[u32]> = v.into_boxed_slice(); - - let a: Result, _> = r.clone().try_into(); - assert!(a.is_ok()); - - let a: Result, _> = r.clone().try_into(); - assert!(a.is_err()); -} diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs deleted file mode 100644 index 9d82a7621a2..00000000000 --- a/library/alloc/tests/rc.rs +++ /dev/null @@ -1,259 +0,0 @@ -use std::any::Any; -use std::cell::{Cell, RefCell}; -use std::iter::TrustedLen; -use std::rc::{Rc, Weak}; - -#[test] -fn uninhabited() { - enum Void {} - let mut a = Weak::::new(); - a = a.clone(); - assert!(a.upgrade().is_none()); - - let mut a: Weak = a; // Unsizing - a = a.clone(); - assert!(a.upgrade().is_none()); -} - -#[test] -fn slice() { - let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]); - let a: Rc<[u32]> = a; // Unsizing - let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion - assert_eq!(a, b); - - // Exercise is_dangling() with a DST - let mut a = Rc::downgrade(&a); - a = a.clone(); - assert!(a.upgrade().is_some()); -} - -#[test] -fn trait_object() { - let a: Rc = Rc::new(4); - let a: Rc = a; // Unsizing - - // Exercise is_dangling() with a DST - let mut a = Rc::downgrade(&a); - a = a.clone(); - assert!(a.upgrade().is_some()); - - let mut b = Weak::::new(); - b = b.clone(); - assert!(b.upgrade().is_none()); - let mut b: Weak = b; // Unsizing - b = b.clone(); - assert!(b.upgrade().is_none()); -} - -#[test] -fn float_nan_ne() { - let x = Rc::new(f32::NAN); - assert!(x != x); - assert!(!(x == x)); -} - -#[test] -fn partial_eq() { - struct TestPEq(RefCell); - impl PartialEq for TestPEq { - fn eq(&self, other: &TestPEq) -> bool { - *self.0.borrow_mut() += 1; - *other.0.borrow_mut() += 1; - true - } - } - let x = Rc::new(TestPEq(RefCell::new(0))); - assert!(x == x); - assert!(!(x != x)); - assert_eq!(*x.0.borrow(), 4); -} - -#[test] -fn eq() { - #[derive(Eq)] - struct TestEq(RefCell); - impl PartialEq for TestEq { - fn eq(&self, other: &TestEq) -> bool { - *self.0.borrow_mut() += 1; - *other.0.borrow_mut() += 1; - true - } - } - let x = Rc::new(TestEq(RefCell::new(0))); - assert!(x == x); - assert!(!(x != x)); - assert_eq!(*x.0.borrow(), 0); -} - -const SHARED_ITER_MAX: u16 = 100; - -fn assert_trusted_len(_: &I) {} - -#[test] -fn shared_from_iter_normal() { - // Exercise the base implementation for non-`TrustedLen` iterators. - { - // `Filter` is never `TrustedLen` since we don't - // know statically how many elements will be kept: - let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new); - - // Collecting into a `Vec` or `Rc<[T]>` should make no difference: - let vec = iter.clone().collect::>(); - let rc = iter.collect::>(); - assert_eq!(&*vec, &*rc); - - // Clone a bit and let these get dropped. - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } // Drop what hasn't been here. -} - -#[test] -fn shared_from_iter_trustedlen_normal() { - // Exercise the `TrustedLen` implementation under normal circumstances - // where `size_hint()` matches `(_, Some(exact_len))`. - { - let iter = (0..SHARED_ITER_MAX).map(Box::new); - assert_trusted_len(&iter); - - // Collecting into a `Vec` or `Rc<[T]>` should make no difference: - let vec = iter.clone().collect::>(); - let rc = iter.collect::>(); - assert_eq!(&*vec, &*rc); - assert_eq!(size_of::>() * SHARED_ITER_MAX as usize, size_of_val(&*rc)); - - // Clone a bit and let these get dropped. - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } // Drop what hasn't been here. - - // Try a ZST to make sure it is handled well. - { - let iter = (0..SHARED_ITER_MAX).map(drop); - let vec = iter.clone().collect::>(); - let rc = iter.collect::>(); - assert_eq!(&*vec, &*rc); - assert_eq!(0, size_of_val(&*rc)); - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } -} - -#[test] -#[should_panic = "I've almost got 99 problems."] -fn shared_from_iter_trustedlen_panic() { - // Exercise the `TrustedLen` implementation when `size_hint()` matches - // `(_, Some(exact_len))` but where `.next()` drops before the last iteration. - let iter = (0..SHARED_ITER_MAX).map(|val| match val { - 98 => panic!("I've almost got 99 problems."), - _ => Box::new(val), - }); - assert_trusted_len(&iter); - let _ = iter.collect::>(); - - panic!("I am unreachable."); -} - -#[test] -fn shared_from_iter_trustedlen_no_fuse() { - // Exercise the `TrustedLen` implementation when `size_hint()` matches - // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner. - struct Iter(std::vec::IntoIter>>); - - unsafe impl TrustedLen for Iter {} - - impl Iterator for Iter { - fn size_hint(&self) -> (usize, Option) { - (2, Some(2)) - } - - type Item = Box; - - fn next(&mut self) -> Option { - self.0.next().flatten() - } - } - - let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))]; - let iter = Iter(vec.into_iter()); - assert_trusted_len(&iter); - assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::>()); -} - -#[test] -fn weak_may_dangle() { - fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> { - val.clone() - } - - // Without #[may_dangle] we get: - let mut val = Weak::new(); - hmm(&mut val); - // ~~~~~~~~ borrowed value does not live long enough - // - // `val` dropped here while still borrowed - // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak` -} - -/// Test that a panic from a destructor does not leak the allocation. -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn panic_no_leak() { - use std::alloc::{AllocError, Allocator, Global, Layout}; - use std::panic::{AssertUnwindSafe, catch_unwind}; - use std::ptr::NonNull; - - struct AllocCount(Cell); - unsafe impl Allocator for AllocCount { - fn allocate(&self, layout: Layout) -> Result, AllocError> { - self.0.set(self.0.get() + 1); - Global.allocate(layout) - } - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - self.0.set(self.0.get() - 1); - unsafe { Global.deallocate(ptr, layout) } - } - } - - struct PanicOnDrop; - impl Drop for PanicOnDrop { - fn drop(&mut self) { - panic!("PanicOnDrop"); - } - } - - let alloc = AllocCount(Cell::new(0)); - let rc = Rc::new_in(PanicOnDrop, &alloc); - assert_eq!(alloc.0.get(), 1); - - let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); - assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); - assert_eq!(alloc.0.get(), 0); -} - -#[allow(unused)] -mod pin_coerce_unsized { - use alloc::rc::{Rc, UniqueRc}; - use core::pin::Pin; - - pub trait MyTrait {} - impl MyTrait for String {} - - // Pin coercion should work for Rc - pub fn pin_rc(arg: Pin>) -> Pin> { - arg - } - pub fn pin_unique_rc(arg: Pin>) -> Pin> { - arg - } -} diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs deleted file mode 100644 index 2516563187f..00000000000 --- a/library/alloc/tests/slice.rs +++ /dev/null @@ -1,1668 +0,0 @@ -use std::cmp::Ordering::{Equal, Greater, Less}; -use std::convert::identity; -use std::rc::Rc; -use std::{fmt, panic}; - -fn square(n: usize) -> usize { - n * n -} - -fn is_odd(n: &usize) -> bool { - *n % 2 == 1 -} - -#[test] -fn test_from_fn() { - // Test on-stack from_fn. - let mut v: Vec<_> = (0..3).map(square).collect(); - { - let v = v; - assert_eq!(v.len(), 3); - assert_eq!(v[0], 0); - assert_eq!(v[1], 1); - assert_eq!(v[2], 4); - } - - // Test on-heap from_fn. - v = (0..5).map(square).collect(); - { - let v = v; - assert_eq!(v.len(), 5); - assert_eq!(v[0], 0); - assert_eq!(v[1], 1); - assert_eq!(v[2], 4); - assert_eq!(v[3], 9); - assert_eq!(v[4], 16); - } -} - -#[test] -fn test_from_elem() { - // Test on-stack from_elem. - let mut v = vec![10, 10]; - { - let v = v; - assert_eq!(v.len(), 2); - assert_eq!(v[0], 10); - assert_eq!(v[1], 10); - } - - // Test on-heap from_elem. - v = vec![20; 6]; - { - let v = &v[..]; - assert_eq!(v[0], 20); - assert_eq!(v[1], 20); - assert_eq!(v[2], 20); - assert_eq!(v[3], 20); - assert_eq!(v[4], 20); - assert_eq!(v[5], 20); - } -} - -#[test] -fn test_is_empty() { - let xs: [i32; 0] = []; - assert!(xs.is_empty()); - assert!(![0].is_empty()); -} - -#[test] -fn test_len_divzero() { - type Z = [i8; 0]; - let v0: &[Z] = &[]; - let v1: &[Z] = &[[]]; - let v2: &[Z] = &[[], []]; - assert_eq!(size_of::(), 0); - assert_eq!(v0.len(), 0); - assert_eq!(v1.len(), 1); - assert_eq!(v2.len(), 2); -} - -#[test] -fn test_get() { - let mut a = vec![11]; - assert_eq!(a.get(1), None); - a = vec![11, 12]; - assert_eq!(a.get(1).unwrap(), &12); - a = vec![11, 12, 13]; - assert_eq!(a.get(1).unwrap(), &12); -} - -#[test] -fn test_first() { - let mut a = vec![]; - assert_eq!(a.first(), None); - a = vec![11]; - assert_eq!(a.first().unwrap(), &11); - a = vec![11, 12]; - assert_eq!(a.first().unwrap(), &11); -} - -#[test] -fn test_first_mut() { - let mut a = vec![]; - assert_eq!(a.first_mut(), None); - a = vec![11]; - assert_eq!(*a.first_mut().unwrap(), 11); - a = vec![11, 12]; - assert_eq!(*a.first_mut().unwrap(), 11); -} - -#[test] -fn test_split_first() { - let mut a = vec![11]; - let b: &[i32] = &[]; - assert!(b.split_first().is_none()); - assert_eq!(a.split_first(), Some((&11, b))); - a = vec![11, 12]; - let b: &[i32] = &[12]; - assert_eq!(a.split_first(), Some((&11, b))); -} - -#[test] -fn test_split_first_mut() { - let mut a = vec![11]; - let b: &mut [i32] = &mut []; - assert!(b.split_first_mut().is_none()); - assert!(a.split_first_mut() == Some((&mut 11, b))); - a = vec![11, 12]; - let b: &mut [_] = &mut [12]; - assert!(a.split_first_mut() == Some((&mut 11, b))); -} - -#[test] -fn test_split_last() { - let mut a = vec![11]; - let b: &[i32] = &[]; - assert!(b.split_last().is_none()); - assert_eq!(a.split_last(), Some((&11, b))); - a = vec![11, 12]; - let b: &[_] = &[11]; - assert_eq!(a.split_last(), Some((&12, b))); -} - -#[test] -fn test_split_last_mut() { - let mut a = vec![11]; - let b: &mut [i32] = &mut []; - assert!(b.split_last_mut().is_none()); - assert!(a.split_last_mut() == Some((&mut 11, b))); - - a = vec![11, 12]; - let b: &mut [_] = &mut [11]; - assert!(a.split_last_mut() == Some((&mut 12, b))); -} - -#[test] -fn test_last() { - let mut a = vec![]; - assert_eq!(a.last(), None); - a = vec![11]; - assert_eq!(a.last().unwrap(), &11); - a = vec![11, 12]; - assert_eq!(a.last().unwrap(), &12); -} - -#[test] -fn test_last_mut() { - let mut a = vec![]; - assert_eq!(a.last_mut(), None); - a = vec![11]; - assert_eq!(*a.last_mut().unwrap(), 11); - a = vec![11, 12]; - assert_eq!(*a.last_mut().unwrap(), 12); -} - -#[test] -fn test_slice() { - // Test fixed length vector. - let vec_fixed = [1, 2, 3, 4]; - let v_a = vec_fixed[1..vec_fixed.len()].to_vec(); - assert_eq!(v_a.len(), 3); - - assert_eq!(v_a[0], 2); - assert_eq!(v_a[1], 3); - assert_eq!(v_a[2], 4); - - // Test on stack. - let vec_stack: &[_] = &[1, 2, 3]; - let v_b = vec_stack[1..3].to_vec(); - assert_eq!(v_b.len(), 2); - - assert_eq!(v_b[0], 2); - assert_eq!(v_b[1], 3); - - // Test `Box<[T]>` - let vec_unique = vec![1, 2, 3, 4, 5, 6]; - let v_d = vec_unique[1..6].to_vec(); - assert_eq!(v_d.len(), 5); - - assert_eq!(v_d[0], 2); - assert_eq!(v_d[1], 3); - assert_eq!(v_d[2], 4); - assert_eq!(v_d[3], 5); - assert_eq!(v_d[4], 6); -} - -#[test] -fn test_slice_from() { - let vec: &[_] = &[1, 2, 3, 4]; - assert_eq!(&vec[..], vec); - let b: &[_] = &[3, 4]; - assert_eq!(&vec[2..], b); - let b: &[_] = &[]; - assert_eq!(&vec[4..], b); -} - -#[test] -fn test_slice_to() { - let vec: &[_] = &[1, 2, 3, 4]; - assert_eq!(&vec[..4], vec); - let b: &[_] = &[1, 2]; - assert_eq!(&vec[..2], b); - let b: &[_] = &[]; - assert_eq!(&vec[..0], b); -} - -#[test] -fn test_pop() { - let mut v = vec![5]; - let e = v.pop(); - assert_eq!(v.len(), 0); - assert_eq!(e, Some(5)); - let f = v.pop(); - assert_eq!(f, None); - let g = v.pop(); - assert_eq!(g, None); -} - -#[test] -fn test_swap_remove() { - let mut v = vec![1, 2, 3, 4, 5]; - let mut e = v.swap_remove(0); - assert_eq!(e, 1); - assert_eq!(v, [5, 2, 3, 4]); - e = v.swap_remove(3); - assert_eq!(e, 4); - assert_eq!(v, [5, 2, 3]); -} - -#[test] -#[should_panic] -fn test_swap_remove_fail() { - let mut v = vec![1]; - let _ = v.swap_remove(0); - let _ = v.swap_remove(0); -} - -#[test] -fn test_swap_remove_noncopyable() { - // Tests that we don't accidentally run destructors twice. - let mut v: Vec> = Vec::new(); - v.push(Box::new(0)); - v.push(Box::new(0)); - v.push(Box::new(0)); - let mut _e = v.swap_remove(0); - assert_eq!(v.len(), 2); - _e = v.swap_remove(1); - assert_eq!(v.len(), 1); - _e = v.swap_remove(0); - assert_eq!(v.len(), 0); -} - -#[test] -fn test_push() { - // Test on-stack push(). - let mut v = vec![]; - v.push(1); - assert_eq!(v.len(), 1); - assert_eq!(v[0], 1); - - // Test on-heap push(). - v.push(2); - assert_eq!(v.len(), 2); - assert_eq!(v[0], 1); - assert_eq!(v[1], 2); -} - -#[test] -fn test_truncate() { - let mut v: Vec> = vec![Box::new(6), Box::new(5), Box::new(4)]; - v.truncate(1); - let v = v; - assert_eq!(v.len(), 1); - assert_eq!(*(v[0]), 6); - // If the unsafe block didn't drop things properly, we blow up here. -} - -#[test] -fn test_clear() { - let mut v: Vec> = vec![Box::new(6), Box::new(5), Box::new(4)]; - v.clear(); - assert_eq!(v.len(), 0); - // If the unsafe block didn't drop things properly, we blow up here. -} - -#[test] -fn test_retain() { - let mut v = vec![1, 2, 3, 4, 5]; - v.retain(is_odd); - assert_eq!(v, [1, 3, 5]); -} - -#[test] -fn test_binary_search() { - assert_eq!([1, 2, 3, 4, 5].binary_search(&5).ok(), Some(4)); - assert_eq!([1, 2, 3, 4, 5].binary_search(&4).ok(), Some(3)); - assert_eq!([1, 2, 3, 4, 5].binary_search(&3).ok(), Some(2)); - assert_eq!([1, 2, 3, 4, 5].binary_search(&2).ok(), Some(1)); - assert_eq!([1, 2, 3, 4, 5].binary_search(&1).ok(), Some(0)); - - assert_eq!([2, 4, 6, 8, 10].binary_search(&1).ok(), None); - assert_eq!([2, 4, 6, 8, 10].binary_search(&5).ok(), None); - assert_eq!([2, 4, 6, 8, 10].binary_search(&4).ok(), Some(1)); - assert_eq!([2, 4, 6, 8, 10].binary_search(&10).ok(), Some(4)); - - assert_eq!([2, 4, 6, 8].binary_search(&1).ok(), None); - assert_eq!([2, 4, 6, 8].binary_search(&5).ok(), None); - assert_eq!([2, 4, 6, 8].binary_search(&4).ok(), Some(1)); - assert_eq!([2, 4, 6, 8].binary_search(&8).ok(), Some(3)); - - assert_eq!([2, 4, 6].binary_search(&1).ok(), None); - assert_eq!([2, 4, 6].binary_search(&5).ok(), None); - assert_eq!([2, 4, 6].binary_search(&4).ok(), Some(1)); - assert_eq!([2, 4, 6].binary_search(&6).ok(), Some(2)); - - assert_eq!([2, 4].binary_search(&1).ok(), None); - assert_eq!([2, 4].binary_search(&5).ok(), None); - assert_eq!([2, 4].binary_search(&2).ok(), Some(0)); - assert_eq!([2, 4].binary_search(&4).ok(), Some(1)); - - assert_eq!([2].binary_search(&1).ok(), None); - assert_eq!([2].binary_search(&5).ok(), None); - assert_eq!([2].binary_search(&2).ok(), Some(0)); - - assert_eq!([].binary_search(&1).ok(), None); - assert_eq!([].binary_search(&5).ok(), None); - - assert!([1, 1, 1, 1, 1].binary_search(&1).ok() != None); - assert!([1, 1, 1, 1, 2].binary_search(&1).ok() != None); - assert!([1, 1, 1, 2, 2].binary_search(&1).ok() != None); - assert!([1, 1, 2, 2, 2].binary_search(&1).ok() != None); - assert_eq!([1, 2, 2, 2, 2].binary_search(&1).ok(), Some(0)); - - assert_eq!([1, 2, 3, 4, 5].binary_search(&6).ok(), None); - assert_eq!([1, 2, 3, 4, 5].binary_search(&0).ok(), None); -} - -#[test] -fn test_reverse() { - let mut v = vec![10, 20]; - assert_eq!(v[0], 10); - assert_eq!(v[1], 20); - v.reverse(); - assert_eq!(v[0], 20); - assert_eq!(v[1], 10); - - let mut v3 = Vec::::new(); - v3.reverse(); - assert!(v3.is_empty()); - - // check the 1-byte-types path - let mut v = (-50..51i8).collect::>(); - v.reverse(); - assert_eq!(v, (-50..51i8).rev().collect::>()); - - // check the 2-byte-types path - let mut v = (-50..51i16).collect::>(); - v.reverse(); - assert_eq!(v, (-50..51i16).rev().collect::>()); -} - -#[test] -fn test_rotate_left() { - let expected: Vec<_> = (0..13).collect(); - let mut v = Vec::new(); - - // no-ops - v.clone_from(&expected); - v.rotate_left(0); - assert_eq!(v, expected); - v.rotate_left(expected.len()); - assert_eq!(v, expected); - let mut zst_array = [(), (), ()]; - zst_array.rotate_left(2); - - // happy path - v = (5..13).chain(0..5).collect(); - v.rotate_left(8); - assert_eq!(v, expected); - - let expected: Vec<_> = (0..1000).collect(); - - // small rotations in large slice, uses ptr::copy - v = (2..1000).chain(0..2).collect(); - v.rotate_left(998); - assert_eq!(v, expected); - v = (998..1000).chain(0..998).collect(); - v.rotate_left(2); - assert_eq!(v, expected); - - // non-small prime rotation, has a few rounds of swapping - v = (389..1000).chain(0..389).collect(); - v.rotate_left(1000 - 389); - assert_eq!(v, expected); -} - -#[test] -fn test_rotate_right() { - let expected: Vec<_> = (0..13).collect(); - let mut v = Vec::new(); - - // no-ops - v.clone_from(&expected); - v.rotate_right(0); - assert_eq!(v, expected); - v.rotate_right(expected.len()); - assert_eq!(v, expected); - let mut zst_array = [(), (), ()]; - zst_array.rotate_right(2); - - // happy path - v = (5..13).chain(0..5).collect(); - v.rotate_right(5); - assert_eq!(v, expected); - - let expected: Vec<_> = (0..1000).collect(); - - // small rotations in large slice, uses ptr::copy - v = (2..1000).chain(0..2).collect(); - v.rotate_right(2); - assert_eq!(v, expected); - v = (998..1000).chain(0..998).collect(); - v.rotate_right(998); - assert_eq!(v, expected); - - // non-small prime rotation, has a few rounds of swapping - v = (389..1000).chain(0..389).collect(); - v.rotate_right(389); - assert_eq!(v, expected); -} - -#[test] -fn test_concat() { - let v: [Vec; 0] = []; - let c = v.concat(); - assert_eq!(c, []); - let d = [vec![1], vec![2, 3]].concat(); - assert_eq!(d, [1, 2, 3]); - - let v: &[&[_]] = &[&[1], &[2, 3]]; - assert_eq!(v.join(&0), [1, 0, 2, 3]); - let v: &[&[_]] = &[&[1], &[2], &[3]]; - assert_eq!(v.join(&0), [1, 0, 2, 0, 3]); -} - -#[test] -fn test_join() { - let v: [Vec; 0] = []; - assert_eq!(v.join(&0), []); - assert_eq!([vec![1], vec![2, 3]].join(&0), [1, 0, 2, 3]); - assert_eq!([vec![1], vec![2], vec![3]].join(&0), [1, 0, 2, 0, 3]); - - let v: [&[_]; 2] = [&[1], &[2, 3]]; - assert_eq!(v.join(&0), [1, 0, 2, 3]); - let v: [&[_]; 3] = [&[1], &[2], &[3]]; - assert_eq!(v.join(&0), [1, 0, 2, 0, 3]); -} - -#[test] -fn test_join_nocopy() { - let v: [String; 0] = []; - assert_eq!(v.join(","), ""); - assert_eq!(["a".to_string(), "ab".into()].join(","), "a,ab"); - assert_eq!(["a".to_string(), "ab".into(), "abc".into()].join(","), "a,ab,abc"); - assert_eq!(["a".to_string(), "ab".into(), "".into()].join(","), "a,ab,"); -} - -#[test] -fn test_insert() { - let mut a = vec![1, 2, 4]; - a.insert(2, 3); - assert_eq!(a, [1, 2, 3, 4]); - - let mut a = vec![1, 2, 3]; - a.insert(0, 0); - assert_eq!(a, [0, 1, 2, 3]); - - let mut a = vec![1, 2, 3]; - a.insert(3, 4); - assert_eq!(a, [1, 2, 3, 4]); - - let mut a = vec![]; - a.insert(0, 1); - assert_eq!(a, [1]); -} - -#[test] -#[should_panic] -fn test_insert_oob() { - let mut a = vec![1, 2, 3]; - a.insert(4, 5); -} - -#[test] -fn test_remove() { - let mut a = vec![1, 2, 3, 4]; - - assert_eq!(a.remove(2), 3); - assert_eq!(a, [1, 2, 4]); - - assert_eq!(a.remove(2), 4); - assert_eq!(a, [1, 2]); - - assert_eq!(a.remove(0), 1); - assert_eq!(a, [2]); - - assert_eq!(a.remove(0), 2); - assert_eq!(a, []); -} - -#[test] -#[should_panic] -fn test_remove_fail() { - let mut a = vec![1]; - let _ = a.remove(0); - let _ = a.remove(0); -} - -#[test] -fn test_capacity() { - let mut v = vec![0]; - v.reserve_exact(10); - assert!(v.capacity() >= 11); -} - -#[test] -fn test_slice_2() { - let v = vec![1, 2, 3, 4, 5]; - let v = &v[1..3]; - assert_eq!(v.len(), 2); - assert_eq!(v[0], 2); - assert_eq!(v[1], 3); -} - -macro_rules! assert_order { - (Greater, $a:expr, $b:expr) => { - assert_eq!($a.cmp($b), Greater); - assert!($a > $b); - }; - (Less, $a:expr, $b:expr) => { - assert_eq!($a.cmp($b), Less); - assert!($a < $b); - }; - (Equal, $a:expr, $b:expr) => { - assert_eq!($a.cmp($b), Equal); - assert_eq!($a, $b); - }; -} - -#[test] -fn test_total_ord_u8() { - let c = &[1u8, 2, 3]; - assert_order!(Greater, &[1u8, 2, 3, 4][..], &c[..]); - let c = &[1u8, 2, 3, 4]; - assert_order!(Less, &[1u8, 2, 3][..], &c[..]); - let c = &[1u8, 2, 3, 6]; - assert_order!(Equal, &[1u8, 2, 3, 6][..], &c[..]); - let c = &[1u8, 2, 3, 4, 5, 6]; - assert_order!(Less, &[1u8, 2, 3, 4, 5, 5, 5, 5][..], &c[..]); - let c = &[1u8, 2, 3, 4]; - assert_order!(Greater, &[2u8, 2][..], &c[..]); -} - -#[test] -fn test_total_ord_i32() { - let c = &[1, 2, 3]; - assert_order!(Greater, &[1, 2, 3, 4][..], &c[..]); - let c = &[1, 2, 3, 4]; - assert_order!(Less, &[1, 2, 3][..], &c[..]); - let c = &[1, 2, 3, 6]; - assert_order!(Equal, &[1, 2, 3, 6][..], &c[..]); - let c = &[1, 2, 3, 4, 5, 6]; - assert_order!(Less, &[1, 2, 3, 4, 5, 5, 5, 5][..], &c[..]); - let c = &[1, 2, 3, 4]; - assert_order!(Greater, &[2, 2][..], &c[..]); -} - -#[test] -fn test_iterator() { - let xs = [1, 2, 5, 10, 11]; - let mut it = xs.iter(); - assert_eq!(it.size_hint(), (5, Some(5))); - assert_eq!(it.next().unwrap(), &1); - assert_eq!(it.size_hint(), (4, Some(4))); - assert_eq!(it.next().unwrap(), &2); - assert_eq!(it.size_hint(), (3, Some(3))); - assert_eq!(it.next().unwrap(), &5); - assert_eq!(it.size_hint(), (2, Some(2))); - assert_eq!(it.next().unwrap(), &10); - assert_eq!(it.size_hint(), (1, Some(1))); - assert_eq!(it.next().unwrap(), &11); - assert_eq!(it.size_hint(), (0, Some(0))); - assert!(it.next().is_none()); -} - -#[test] -fn test_iter_size_hints() { - let mut xs = [1, 2, 5, 10, 11]; - assert_eq!(xs.iter().size_hint(), (5, Some(5))); - assert_eq!(xs.iter_mut().size_hint(), (5, Some(5))); -} - -#[test] -fn test_iter_as_slice() { - let xs = [1, 2, 5, 10, 11]; - let mut iter = xs.iter(); - assert_eq!(iter.as_slice(), &[1, 2, 5, 10, 11]); - iter.next(); - assert_eq!(iter.as_slice(), &[2, 5, 10, 11]); -} - -#[test] -fn test_iter_as_ref() { - let xs = [1, 2, 5, 10, 11]; - let mut iter = xs.iter(); - assert_eq!(iter.as_ref(), &[1, 2, 5, 10, 11]); - iter.next(); - assert_eq!(iter.as_ref(), &[2, 5, 10, 11]); -} - -#[test] -fn test_iter_clone() { - let xs = [1, 2, 5]; - let mut it = xs.iter(); - it.next(); - let mut jt = it.clone(); - assert_eq!(it.next(), jt.next()); - assert_eq!(it.next(), jt.next()); - assert_eq!(it.next(), jt.next()); -} - -#[test] -fn test_iter_is_empty() { - let xs = [1, 2, 5, 10, 11]; - for i in 0..xs.len() { - for j in i..xs.len() { - assert_eq!(xs[i..j].iter().is_empty(), xs[i..j].is_empty()); - } - } -} - -#[test] -fn test_mut_iterator() { - let mut xs = [1, 2, 3, 4, 5]; - for x in &mut xs { - *x += 1; - } - assert!(xs == [2, 3, 4, 5, 6]) -} - -#[test] -fn test_rev_iterator() { - let xs = [1, 2, 5, 10, 11]; - let ys = [11, 10, 5, 2, 1]; - let mut i = 0; - for &x in xs.iter().rev() { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, 5); -} - -#[test] -fn test_mut_rev_iterator() { - let mut xs = [1, 2, 3, 4, 5]; - for (i, x) in xs.iter_mut().rev().enumerate() { - *x += i; - } - assert!(xs == [5, 5, 5, 5, 5]) -} - -#[test] -fn test_move_iterator() { - let xs = vec![1, 2, 3, 4, 5]; - assert_eq!(xs.into_iter().fold(0, |a: usize, b: usize| 10 * a + b), 12345); -} - -#[test] -fn test_move_rev_iterator() { - let xs = vec![1, 2, 3, 4, 5]; - assert_eq!(xs.into_iter().rev().fold(0, |a: usize, b: usize| 10 * a + b), 54321); -} - -#[test] -fn test_split_iterator() { - let xs = &[1, 2, 3, 4, 5]; - - let splits: &[&[_]] = &[&[1], &[3], &[5]]; - assert_eq!(xs.split(|x| *x % 2 == 0).collect::>(), splits); - let splits: &[&[_]] = &[&[], &[2, 3, 4, 5]]; - assert_eq!(xs.split(|x| *x == 1).collect::>(), splits); - let splits: &[&[_]] = &[&[1, 2, 3, 4], &[]]; - assert_eq!(xs.split(|x| *x == 5).collect::>(), splits); - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.split(|x| *x == 10).collect::>(), splits); - let splits: &[&[_]] = &[&[], &[], &[], &[], &[], &[]]; - assert_eq!(xs.split(|_| true).collect::>(), splits); - - let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[&[]]; - assert_eq!(xs.split(|x| *x == 5).collect::>(), splits); -} - -#[test] -fn test_split_iterator_inclusive() { - let xs = &[1, 2, 3, 4, 5]; - - let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]]; - assert_eq!(xs.split_inclusive(|x| *x % 2 == 0).collect::>(), splits); - let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]]; - assert_eq!(xs.split_inclusive(|x| *x == 1).collect::>(), splits); - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.split_inclusive(|x| *x == 5).collect::>(), splits); - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.split_inclusive(|x| *x == 10).collect::>(), splits); - let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; - assert_eq!(xs.split_inclusive(|_| true).collect::>(), splits); - - let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[]; - assert_eq!(xs.split_inclusive(|x| *x == 5).collect::>(), splits); -} - -#[test] -fn test_split_iterator_inclusive_reverse() { - let xs = &[1, 2, 3, 4, 5]; - - let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]]; - assert_eq!(xs.split_inclusive(|x| *x % 2 == 0).rev().collect::>(), splits); - let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]]; - assert_eq!(xs.split_inclusive(|x| *x == 1).rev().collect::>(), splits); - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::>(), splits); - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.split_inclusive(|x| *x == 10).rev().collect::>(), splits); - let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; - assert_eq!(xs.split_inclusive(|_| true).rev().collect::>(), splits); - - let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[]; - assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::>(), splits); -} - -#[test] -fn test_split_iterator_mut_inclusive() { - let xs = &mut [1, 2, 3, 4, 5]; - - let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]]; - assert_eq!(xs.split_inclusive_mut(|x| *x % 2 == 0).collect::>(), splits); - let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]]; - assert_eq!(xs.split_inclusive_mut(|x| *x == 1).collect::>(), splits); - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::>(), splits); - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.split_inclusive_mut(|x| *x == 10).collect::>(), splits); - let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; - assert_eq!(xs.split_inclusive_mut(|_| true).collect::>(), splits); - - let xs: &mut [i32] = &mut []; - let splits: &[&[i32]] = &[]; - assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::>(), splits); -} - -#[test] -fn test_split_iterator_mut_inclusive_reverse() { - let xs = &mut [1, 2, 3, 4, 5]; - - let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]]; - assert_eq!(xs.split_inclusive_mut(|x| *x % 2 == 0).rev().collect::>(), splits); - let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]]; - assert_eq!(xs.split_inclusive_mut(|x| *x == 1).rev().collect::>(), splits); - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.split_inclusive_mut(|x| *x == 10).rev().collect::>(), splits); - let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; - assert_eq!(xs.split_inclusive_mut(|_| true).rev().collect::>(), splits); - - let xs: &mut [i32] = &mut []; - let splits: &[&[i32]] = &[]; - assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); -} - -#[test] -fn test_splitn_iterator() { - let xs = &[1, 2, 3, 4, 5]; - - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::>(), splits); - let splits: &[&[_]] = &[&[1], &[3, 4, 5]]; - assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::>(), splits); - let splits: &[&[_]] = &[&[], &[], &[], &[4, 5]]; - assert_eq!(xs.splitn(4, |_| true).collect::>(), splits); - - let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[&[]]; - assert_eq!(xs.splitn(2, |x| *x == 5).collect::>(), splits); -} - -#[test] -fn test_splitn_iterator_mut() { - let xs = &mut [1, 2, 3, 4, 5]; - - let splits: &[&mut [_]] = &[&mut [1, 2, 3, 4, 5]]; - assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::>(), splits); - let splits: &[&mut [_]] = &[&mut [1], &mut [3, 4, 5]]; - assert_eq!(xs.splitn_mut(2, |x| *x % 2 == 0).collect::>(), splits); - let splits: &[&mut [_]] = &[&mut [], &mut [], &mut [], &mut [4, 5]]; - assert_eq!(xs.splitn_mut(4, |_| true).collect::>(), splits); - - let xs: &mut [i32] = &mut []; - let splits: &[&mut [i32]] = &[&mut []]; - assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::>(), splits); -} - -#[test] -fn test_rsplit_iterator() { - let xs = &[1, 2, 3, 4, 5]; - - let splits: &[&[_]] = &[&[5], &[3], &[1]]; - assert_eq!(xs.split(|x| *x % 2 == 0).rev().collect::>(), splits); - let splits: &[&[_]] = &[&[2, 3, 4, 5], &[]]; - assert_eq!(xs.split(|x| *x == 1).rev().collect::>(), splits); - let splits: &[&[_]] = &[&[], &[1, 2, 3, 4]]; - assert_eq!(xs.split(|x| *x == 5).rev().collect::>(), splits); - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.split(|x| *x == 10).rev().collect::>(), splits); - - let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[&[]]; - assert_eq!(xs.split(|x| *x == 5).rev().collect::>(), splits); -} - -#[test] -fn test_rsplitn_iterator() { - let xs = &[1, 2, 3, 4, 5]; - - let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::>(), splits); - let splits: &[&[_]] = &[&[5], &[1, 2, 3]]; - assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::>(), splits); - let splits: &[&[_]] = &[&[], &[], &[], &[1, 2]]; - assert_eq!(xs.rsplitn(4, |_| true).collect::>(), splits); - - let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[&[]]; - assert_eq!(xs.rsplitn(2, |x| *x == 5).collect::>(), splits); - assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none()); -} - -#[test] -fn test_split_iterators_size_hint() { - #[derive(Copy, Clone)] - enum Bounds { - Lower, - Upper, - } - fn assert_tight_size_hints(mut it: impl Iterator, which: Bounds, ctx: impl fmt::Display) { - match which { - Bounds::Lower => { - let mut lower_bounds = vec![it.size_hint().0]; - while let Some(_) = it.next() { - lower_bounds.push(it.size_hint().0); - } - let target: Vec<_> = (0..lower_bounds.len()).rev().collect(); - assert_eq!(lower_bounds, target, "lower bounds incorrect or not tight: {}", ctx); - } - Bounds::Upper => { - let mut upper_bounds = vec![it.size_hint().1]; - while let Some(_) = it.next() { - upper_bounds.push(it.size_hint().1); - } - let target: Vec<_> = (0..upper_bounds.len()).map(Some).rev().collect(); - assert_eq!(upper_bounds, target, "upper bounds incorrect or not tight: {}", ctx); - } - } - } - - for len in 0..=2 { - let mut v: Vec = (0..len).collect(); - - // p: predicate, b: bound selection - for (p, b) in [ - // with a predicate always returning false, the split*-iterators - // become maximally short, so the size_hint lower bounds are tight - ((|_| false) as fn(&_) -> _, Bounds::Lower), - // with a predicate always returning true, the split*-iterators - // become maximally long, so the size_hint upper bounds are tight - ((|_| true) as fn(&_) -> _, Bounds::Upper), - ] { - use {assert_tight_size_hints as a, format_args as f}; - - a(v.split(p), b, "split"); - a(v.split_mut(p), b, "split_mut"); - a(v.split_inclusive(p), b, "split_inclusive"); - a(v.split_inclusive_mut(p), b, "split_inclusive_mut"); - a(v.rsplit(p), b, "rsplit"); - a(v.rsplit_mut(p), b, "rsplit_mut"); - - for n in 0..=3 { - a(v.splitn(n, p), b, f!("splitn, n = {n}")); - a(v.splitn_mut(n, p), b, f!("splitn_mut, n = {n}")); - a(v.rsplitn(n, p), b, f!("rsplitn, n = {n}")); - a(v.rsplitn_mut(n, p), b, f!("rsplitn_mut, n = {n}")); - } - } - } -} - -#[test] -fn test_windows_iterator() { - let v = &[1, 2, 3, 4]; - - let wins: &[&[_]] = &[&[1, 2], &[2, 3], &[3, 4]]; - assert_eq!(v.windows(2).collect::>(), wins); - - let wins: &[&[_]] = &[&[1, 2, 3], &[2, 3, 4]]; - assert_eq!(v.windows(3).collect::>(), wins); - assert!(v.windows(6).next().is_none()); - - let wins: &[&[_]] = &[&[3, 4], &[2, 3], &[1, 2]]; - assert_eq!(v.windows(2).rev().collect::>(), wins); -} - -#[test] -#[should_panic] -fn test_windows_iterator_0() { - let v = &[1, 2, 3, 4]; - let _it = v.windows(0); -} - -#[test] -fn test_chunks_iterator() { - let v = &[1, 2, 3, 4, 5]; - - assert_eq!(v.chunks(2).len(), 3); - - let chunks: &[&[_]] = &[&[1, 2], &[3, 4], &[5]]; - assert_eq!(v.chunks(2).collect::>(), chunks); - let chunks: &[&[_]] = &[&[1, 2, 3], &[4, 5]]; - assert_eq!(v.chunks(3).collect::>(), chunks); - let chunks: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(v.chunks(6).collect::>(), chunks); - - let chunks: &[&[_]] = &[&[5], &[3, 4], &[1, 2]]; - assert_eq!(v.chunks(2).rev().collect::>(), chunks); -} - -#[test] -#[should_panic] -fn test_chunks_iterator_0() { - let v = &[1, 2, 3, 4]; - let _it = v.chunks(0); -} - -#[test] -fn test_chunks_exact_iterator() { - let v = &[1, 2, 3, 4, 5]; - - assert_eq!(v.chunks_exact(2).len(), 2); - - let chunks: &[&[_]] = &[&[1, 2], &[3, 4]]; - assert_eq!(v.chunks_exact(2).collect::>(), chunks); - let chunks: &[&[_]] = &[&[1, 2, 3]]; - assert_eq!(v.chunks_exact(3).collect::>(), chunks); - let chunks: &[&[_]] = &[]; - assert_eq!(v.chunks_exact(6).collect::>(), chunks); - - let chunks: &[&[_]] = &[&[3, 4], &[1, 2]]; - assert_eq!(v.chunks_exact(2).rev().collect::>(), chunks); -} - -#[test] -#[should_panic] -fn test_chunks_exact_iterator_0() { - let v = &[1, 2, 3, 4]; - let _it = v.chunks_exact(0); -} - -#[test] -fn test_rchunks_iterator() { - let v = &[1, 2, 3, 4, 5]; - - assert_eq!(v.rchunks(2).len(), 3); - - let chunks: &[&[_]] = &[&[4, 5], &[2, 3], &[1]]; - assert_eq!(v.rchunks(2).collect::>(), chunks); - let chunks: &[&[_]] = &[&[3, 4, 5], &[1, 2]]; - assert_eq!(v.rchunks(3).collect::>(), chunks); - let chunks: &[&[_]] = &[&[1, 2, 3, 4, 5]]; - assert_eq!(v.rchunks(6).collect::>(), chunks); - - let chunks: &[&[_]] = &[&[1], &[2, 3], &[4, 5]]; - assert_eq!(v.rchunks(2).rev().collect::>(), chunks); -} - -#[test] -#[should_panic] -fn test_rchunks_iterator_0() { - let v = &[1, 2, 3, 4]; - let _it = v.rchunks(0); -} - -#[test] -fn test_rchunks_exact_iterator() { - let v = &[1, 2, 3, 4, 5]; - - assert_eq!(v.rchunks_exact(2).len(), 2); - - let chunks: &[&[_]] = &[&[4, 5], &[2, 3]]; - assert_eq!(v.rchunks_exact(2).collect::>(), chunks); - let chunks: &[&[_]] = &[&[3, 4, 5]]; - assert_eq!(v.rchunks_exact(3).collect::>(), chunks); - let chunks: &[&[_]] = &[]; - assert_eq!(v.rchunks_exact(6).collect::>(), chunks); - - let chunks: &[&[_]] = &[&[2, 3], &[4, 5]]; - assert_eq!(v.rchunks_exact(2).rev().collect::>(), chunks); -} - -#[test] -#[should_panic] -fn test_rchunks_exact_iterator_0() { - let v = &[1, 2, 3, 4]; - let _it = v.rchunks_exact(0); -} - -#[test] -fn test_reverse_part() { - let mut values = [1, 2, 3, 4, 5]; - values[1..4].reverse(); - assert!(values == [1, 4, 3, 2, 5]); -} - -#[test] -fn test_show() { - macro_rules! test_show_vec { - ($x:expr, $x_str:expr) => {{ - let (x, x_str) = ($x, $x_str); - assert_eq!(format!("{x:?}"), x_str); - assert_eq!(format!("{x:?}"), x_str); - }}; - } - let empty = Vec::::new(); - test_show_vec!(empty, "[]"); - test_show_vec!(vec![1], "[1]"); - test_show_vec!(vec![1, 2, 3], "[1, 2, 3]"); - test_show_vec!(vec![vec![], vec![1], vec![1, 1]], "[[], [1], [1, 1]]"); - - let empty_mut: &mut [i32] = &mut []; - test_show_vec!(empty_mut, "[]"); - let v = &mut [1]; - test_show_vec!(v, "[1]"); - let v = &mut [1, 2, 3]; - test_show_vec!(v, "[1, 2, 3]"); - let v: &mut [&mut [_]] = &mut [&mut [], &mut [1], &mut [1, 1]]; - test_show_vec!(v, "[[], [1], [1, 1]]"); -} - -#[test] -fn test_vec_default() { - macro_rules! t { - ($ty:ty) => {{ - let v: $ty = Default::default(); - assert!(v.is_empty()); - }}; - } - - t!(&[i32]); - t!(Vec); -} - -#[test] -#[should_panic] -fn test_overflow_does_not_cause_segfault() { - let mut v = vec![]; - v.reserve_exact(!0); - v.push(1); - v.push(2); -} - -#[test] -#[should_panic] -fn test_overflow_does_not_cause_segfault_managed() { - let mut v = vec![Rc::new(1)]; - v.reserve_exact(!0); - v.push(Rc::new(2)); -} - -#[test] -fn test_mut_split_at() { - let mut values = [1, 2, 3, 4, 5]; - { - let (left, right) = values.split_at_mut(2); - { - let left: &[_] = left; - assert!(left[..left.len()] == [1, 2]); - } - for p in left { - *p += 1; - } - - { - let right: &[_] = right; - assert!(right[..right.len()] == [3, 4, 5]); - } - for p in right { - *p += 2; - } - } - - assert!(values == [2, 3, 5, 6, 7]); -} - -#[derive(Clone, PartialEq)] -struct Foo; - -#[test] -fn test_iter_zero_sized() { - let mut v = vec![Foo, Foo, Foo]; - assert_eq!(v.len(), 3); - let mut cnt = 0; - - for f in &v { - assert!(*f == Foo); - cnt += 1; - } - assert_eq!(cnt, 3); - - for f in &v[1..3] { - assert!(*f == Foo); - cnt += 1; - } - assert_eq!(cnt, 5); - - for f in &mut v { - assert!(*f == Foo); - cnt += 1; - } - assert_eq!(cnt, 8); - - for f in v { - assert!(f == Foo); - cnt += 1; - } - assert_eq!(cnt, 11); - - let xs: [Foo; 3] = [Foo, Foo, Foo]; - cnt = 0; - for f in &xs { - assert!(*f == Foo); - cnt += 1; - } - assert!(cnt == 3); -} - -#[test] -fn test_shrink_to_fit() { - let mut xs = vec![0, 1, 2, 3]; - for i in 4..100 { - xs.push(i) - } - assert_eq!(xs.capacity(), 128); - xs.shrink_to_fit(); - assert_eq!(xs.capacity(), 100); - assert_eq!(xs, (0..100).collect::>()); -} - -#[test] -fn test_starts_with() { - assert!(b"foobar".starts_with(b"foo")); - assert!(!b"foobar".starts_with(b"oob")); - assert!(!b"foobar".starts_with(b"bar")); - assert!(!b"foo".starts_with(b"foobar")); - assert!(!b"bar".starts_with(b"foobar")); - assert!(b"foobar".starts_with(b"foobar")); - let empty: &[u8] = &[]; - assert!(empty.starts_with(empty)); - assert!(!empty.starts_with(b"foo")); - assert!(b"foobar".starts_with(empty)); -} - -#[test] -fn test_ends_with() { - assert!(b"foobar".ends_with(b"bar")); - assert!(!b"foobar".ends_with(b"oba")); - assert!(!b"foobar".ends_with(b"foo")); - assert!(!b"foo".ends_with(b"foobar")); - assert!(!b"bar".ends_with(b"foobar")); - assert!(b"foobar".ends_with(b"foobar")); - let empty: &[u8] = &[]; - assert!(empty.ends_with(empty)); - assert!(!empty.ends_with(b"foo")); - assert!(b"foobar".ends_with(empty)); -} - -#[test] -fn test_mut_split_iterator() { - let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0]; - assert_eq!(xs.split_mut(|x| *x == 0).count(), 6); - for slice in xs.split_mut(|x| *x == 0) { - slice.reverse(); - } - assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0]); - - let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0, 6, 7]; - for slice in xs.split_mut(|x| *x == 0).take(5) { - slice.reverse(); - } - assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0, 6, 7]); -} - -#[test] -fn test_mut_split_iterator_rev() { - let mut xs = [1, 2, 0, 3, 4, 0, 0, 5, 6, 0]; - for slice in xs.split_mut(|x| *x == 0).rev().take(4) { - slice.reverse(); - } - assert!(xs == [1, 2, 0, 4, 3, 0, 0, 6, 5, 0]); -} - -#[test] -fn test_get_mut() { - let mut v = [0, 1, 2]; - assert_eq!(v.get_mut(3), None); - v.get_mut(1).map(|e| *e = 7); - assert_eq!(v[1], 7); - let mut x = 2; - assert_eq!(v.get_mut(2), Some(&mut x)); -} - -#[test] -fn test_mut_chunks() { - let mut v = [0, 1, 2, 3, 4, 5, 6]; - assert_eq!(v.chunks_mut(3).len(), 3); - for (i, chunk) in v.chunks_mut(3).enumerate() { - for x in chunk { - *x = i as u8; - } - } - let result = [0, 0, 0, 1, 1, 1, 2]; - assert_eq!(v, result); -} - -#[test] -fn test_mut_chunks_rev() { - let mut v = [0, 1, 2, 3, 4, 5, 6]; - for (i, chunk) in v.chunks_mut(3).rev().enumerate() { - for x in chunk { - *x = i as u8; - } - } - let result = [2, 2, 2, 1, 1, 1, 0]; - assert_eq!(v, result); -} - -#[test] -#[should_panic] -fn test_mut_chunks_0() { - let mut v = [1, 2, 3, 4]; - let _it = v.chunks_mut(0); -} - -#[test] -fn test_mut_chunks_exact() { - let mut v = [0, 1, 2, 3, 4, 5, 6]; - assert_eq!(v.chunks_exact_mut(3).len(), 2); - for (i, chunk) in v.chunks_exact_mut(3).enumerate() { - for x in chunk { - *x = i as u8; - } - } - let result = [0, 0, 0, 1, 1, 1, 6]; - assert_eq!(v, result); -} - -#[test] -fn test_mut_chunks_exact_rev() { - let mut v = [0, 1, 2, 3, 4, 5, 6]; - for (i, chunk) in v.chunks_exact_mut(3).rev().enumerate() { - for x in chunk { - *x = i as u8; - } - } - let result = [1, 1, 1, 0, 0, 0, 6]; - assert_eq!(v, result); -} - -#[test] -#[should_panic] -fn test_mut_chunks_exact_0() { - let mut v = [1, 2, 3, 4]; - let _it = v.chunks_exact_mut(0); -} - -#[test] -fn test_mut_rchunks() { - let mut v = [0, 1, 2, 3, 4, 5, 6]; - assert_eq!(v.rchunks_mut(3).len(), 3); - for (i, chunk) in v.rchunks_mut(3).enumerate() { - for x in chunk { - *x = i as u8; - } - } - let result = [2, 1, 1, 1, 0, 0, 0]; - assert_eq!(v, result); -} - -#[test] -fn test_mut_rchunks_rev() { - let mut v = [0, 1, 2, 3, 4, 5, 6]; - for (i, chunk) in v.rchunks_mut(3).rev().enumerate() { - for x in chunk { - *x = i as u8; - } - } - let result = [0, 1, 1, 1, 2, 2, 2]; - assert_eq!(v, result); -} - -#[test] -#[should_panic] -fn test_mut_rchunks_0() { - let mut v = [1, 2, 3, 4]; - let _it = v.rchunks_mut(0); -} - -#[test] -fn test_mut_rchunks_exact() { - let mut v = [0, 1, 2, 3, 4, 5, 6]; - assert_eq!(v.rchunks_exact_mut(3).len(), 2); - for (i, chunk) in v.rchunks_exact_mut(3).enumerate() { - for x in chunk { - *x = i as u8; - } - } - let result = [0, 1, 1, 1, 0, 0, 0]; - assert_eq!(v, result); -} - -#[test] -fn test_mut_rchunks_exact_rev() { - let mut v = [0, 1, 2, 3, 4, 5, 6]; - for (i, chunk) in v.rchunks_exact_mut(3).rev().enumerate() { - for x in chunk { - *x = i as u8; - } - } - let result = [0, 0, 0, 0, 1, 1, 1]; - assert_eq!(v, result); -} - -#[test] -#[should_panic] -fn test_mut_rchunks_exact_0() { - let mut v = [1, 2, 3, 4]; - let _it = v.rchunks_exact_mut(0); -} - -#[test] -fn test_mut_last() { - let mut x = [1, 2, 3, 4, 5]; - let h = x.last_mut(); - assert_eq!(*h.unwrap(), 5); - - let y: &mut [i32] = &mut []; - assert!(y.last_mut().is_none()); -} - -#[test] -fn test_to_vec() { - let xs: Box<_> = Box::new([1, 2, 3]); - let ys = xs.to_vec(); - assert_eq!(ys, [1, 2, 3]); -} - -#[test] -fn test_in_place_iterator_specialization() { - let src: Box<[usize]> = Box::new([1, 2, 3]); - let src_ptr = src.as_ptr(); - let sink: Box<_> = src.into_vec().into_iter().map(std::convert::identity).collect(); - let sink_ptr = sink.as_ptr(); - assert_eq!(src_ptr, sink_ptr); -} - -#[test] -fn test_box_slice_clone() { - let data = vec![vec![0, 1], vec![0], vec![1]]; - let data2 = data.clone().into_boxed_slice().clone().to_vec(); - - assert_eq!(data, data2); -} - -#[test] -#[allow(unused_must_use)] // here, we care about the side effects of `.clone()` -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_box_slice_clone_panics() { - use std::sync::Arc; - use std::sync::atomic::{AtomicUsize, Ordering}; - - struct Canary { - count: Arc, - panics: bool, - } - - impl Drop for Canary { - fn drop(&mut self) { - self.count.fetch_add(1, Ordering::SeqCst); - } - } - - impl Clone for Canary { - fn clone(&self) -> Self { - if self.panics { - panic!() - } - - Canary { count: self.count.clone(), panics: self.panics } - } - } - - let drop_count = Arc::new(AtomicUsize::new(0)); - let canary = Canary { count: drop_count.clone(), panics: false }; - let panic = Canary { count: drop_count.clone(), panics: true }; - - std::panic::catch_unwind(move || { - // When xs is dropped, +5. - let xs = - vec![canary.clone(), canary.clone(), canary.clone(), panic, canary].into_boxed_slice(); - - // When panic is cloned, +3. - xs.clone(); - }) - .unwrap_err(); - - // Total = 8 - assert_eq!(drop_count.load(Ordering::SeqCst), 8); -} - -#[test] -fn test_copy_from_slice() { - let src = [0, 1, 2, 3, 4, 5]; - let mut dst = [0; 6]; - dst.copy_from_slice(&src); - assert_eq!(src, dst) -} - -#[test] -#[should_panic(expected = "source slice length (4) does not match destination slice length (5)")] -fn test_copy_from_slice_dst_longer() { - let src = [0, 1, 2, 3]; - let mut dst = [0; 5]; - dst.copy_from_slice(&src); -} - -#[test] -#[should_panic(expected = "source slice length (4) does not match destination slice length (3)")] -fn test_copy_from_slice_dst_shorter() { - let src = [0, 1, 2, 3]; - let mut dst = [0; 3]; - dst.copy_from_slice(&src); -} - -#[test] -fn repeat_generic_slice() { - assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]); - assert_eq!([1, 2, 3, 4].repeat(0), vec![]); - assert_eq!([1, 2, 3, 4].repeat(1), vec![1, 2, 3, 4]); - assert_eq!([1, 2, 3, 4].repeat(3), vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]); -} - -#[test] -#[allow(unreachable_patterns)] -fn subslice_patterns() { - // This test comprehensively checks the passing static and dynamic semantics - // of subslice patterns `..`, `x @ ..`, `ref x @ ..`, and `ref mut @ ..` - // in slice patterns `[$($pat), $(,)?]` . - - #[derive(PartialEq, Debug, Clone)] - struct N(u8); - - macro_rules! n { - ($($e:expr),* $(,)?) => { - [$(N($e)),*] - } - } - - macro_rules! c { - ($inp:expr, $typ:ty, $out:expr $(,)?) => { - assert_eq!($out, identity::<$typ>($inp)) - }; - } - - macro_rules! m { - ($e:expr, $p:pat => $b:expr) => { - match $e { - $p => $b, - _ => panic!(), - } - }; - } - - // == Slices == - - // Matching slices using `ref` patterns: - let mut v = vec![N(0), N(1), N(2), N(3), N(4)]; - let mut vc = (0..=4).collect::>(); - - let [..] = v[..]; // Always matches. - m!(v[..], [N(0), ref sub @ .., N(4)] => c!(sub, &[N], n![1, 2, 3])); - m!(v[..], [N(0), ref sub @ ..] => c!(sub, &[N], n![1, 2, 3, 4])); - m!(v[..], [ref sub @ .., N(4)] => c!(sub, &[N], n![0, 1, 2, 3])); - m!(v[..], [ref sub @ .., _, _, _, _, _] => c!(sub, &[N], &n![] as &[N])); - m!(v[..], [_, _, _, _, _, ref sub @ ..] => c!(sub, &[N], &n![] as &[N])); - m!(vc[..], [x, .., y] => c!((x, y), (u8, u8), (0, 4))); - - // Matching slices using `ref mut` patterns: - let [..] = v[..]; // Always matches. - m!(v[..], [N(0), ref mut sub @ .., N(4)] => c!(sub, &mut [N], n![1, 2, 3])); - m!(v[..], [N(0), ref mut sub @ ..] => c!(sub, &mut [N], n![1, 2, 3, 4])); - m!(v[..], [ref mut sub @ .., N(4)] => c!(sub, &mut [N], n![0, 1, 2, 3])); - m!(v[..], [ref mut sub @ .., _, _, _, _, _] => c!(sub, &mut [N], &mut n![] as &mut [N])); - m!(v[..], [_, _, _, _, _, ref mut sub @ ..] => c!(sub, &mut [N], &mut n![] as &mut [N])); - m!(vc[..], [x, .., y] => c!((x, y), (u8, u8), (0, 4))); - - // Matching slices using default binding modes (&): - let [..] = &v[..]; // Always matches. - m!(&v[..], [N(0), sub @ .., N(4)] => c!(sub, &[N], n![1, 2, 3])); - m!(&v[..], [N(0), sub @ ..] => c!(sub, &[N], n![1, 2, 3, 4])); - m!(&v[..], [sub @ .., N(4)] => c!(sub, &[N], n![0, 1, 2, 3])); - m!(&v[..], [sub @ .., _, _, _, _, _] => c!(sub, &[N], &n![] as &[N])); - m!(&v[..], [_, _, _, _, _, sub @ ..] => c!(sub, &[N], &n![] as &[N])); - m!(&vc[..], [x, .., y] => c!((x, y), (&u8, &u8), (&0, &4))); - - // Matching slices using default binding modes (&mut): - let [..] = &mut v[..]; // Always matches. - m!(&mut v[..], [N(0), sub @ .., N(4)] => c!(sub, &mut [N], n![1, 2, 3])); - m!(&mut v[..], [N(0), sub @ ..] => c!(sub, &mut [N], n![1, 2, 3, 4])); - m!(&mut v[..], [sub @ .., N(4)] => c!(sub, &mut [N], n![0, 1, 2, 3])); - m!(&mut v[..], [sub @ .., _, _, _, _, _] => c!(sub, &mut [N], &mut n![] as &mut [N])); - m!(&mut v[..], [_, _, _, _, _, sub @ ..] => c!(sub, &mut [N], &mut n![] as &mut [N])); - m!(&mut vc[..], [x, .., y] => c!((x, y), (&mut u8, &mut u8), (&mut 0, &mut 4))); - - // == Arrays == - let mut v = n![0, 1, 2, 3, 4]; - let vc = [0, 1, 2, 3, 4]; - - // Matching arrays by value: - m!(v.clone(), [N(0), sub @ .., N(4)] => c!(sub, [N; 3], n![1, 2, 3])); - m!(v.clone(), [N(0), sub @ ..] => c!(sub, [N; 4], n![1, 2, 3, 4])); - m!(v.clone(), [sub @ .., N(4)] => c!(sub, [N; 4], n![0, 1, 2, 3])); - m!(v.clone(), [sub @ .., _, _, _, _, _] => c!(sub, [N; 0], n![] as [N; 0])); - m!(v.clone(), [_, _, _, _, _, sub @ ..] => c!(sub, [N; 0], n![] as [N; 0])); - m!(v.clone(), [x, .., y] => c!((x, y), (N, N), (N(0), N(4)))); - m!(v.clone(), [..] => ()); - - // Matching arrays by ref patterns: - m!(v, [N(0), ref sub @ .., N(4)] => c!(sub, &[N; 3], &n![1, 2, 3])); - m!(v, [N(0), ref sub @ ..] => c!(sub, &[N; 4], &n![1, 2, 3, 4])); - m!(v, [ref sub @ .., N(4)] => c!(sub, &[N; 4], &n![0, 1, 2, 3])); - m!(v, [ref sub @ .., _, _, _, _, _] => c!(sub, &[N; 0], &n![] as &[N; 0])); - m!(v, [_, _, _, _, _, ref sub @ ..] => c!(sub, &[N; 0], &n![] as &[N; 0])); - m!(vc, [x, .., y] => c!((x, y), (u8, u8), (0, 4))); - - // Matching arrays by ref mut patterns: - m!(v, [N(0), ref mut sub @ .., N(4)] => c!(sub, &mut [N; 3], &mut n![1, 2, 3])); - m!(v, [N(0), ref mut sub @ ..] => c!(sub, &mut [N; 4], &mut n![1, 2, 3, 4])); - m!(v, [ref mut sub @ .., N(4)] => c!(sub, &mut [N; 4], &mut n![0, 1, 2, 3])); - m!(v, [ref mut sub @ .., _, _, _, _, _] => c!(sub, &mut [N; 0], &mut n![] as &mut [N; 0])); - m!(v, [_, _, _, _, _, ref mut sub @ ..] => c!(sub, &mut [N; 0], &mut n![] as &mut [N; 0])); - - // Matching arrays by default binding modes (&): - m!(&v, [N(0), sub @ .., N(4)] => c!(sub, &[N; 3], &n![1, 2, 3])); - m!(&v, [N(0), sub @ ..] => c!(sub, &[N; 4], &n![1, 2, 3, 4])); - m!(&v, [sub @ .., N(4)] => c!(sub, &[N; 4], &n![0, 1, 2, 3])); - m!(&v, [sub @ .., _, _, _, _, _] => c!(sub, &[N; 0], &n![] as &[N; 0])); - m!(&v, [_, _, _, _, _, sub @ ..] => c!(sub, &[N; 0], &n![] as &[N; 0])); - m!(&v, [..] => ()); - m!(&v, [x, .., y] => c!((x, y), (&N, &N), (&N(0), &N(4)))); - - // Matching arrays by default binding modes (&mut): - m!(&mut v, [N(0), sub @ .., N(4)] => c!(sub, &mut [N; 3], &mut n![1, 2, 3])); - m!(&mut v, [N(0), sub @ ..] => c!(sub, &mut [N; 4], &mut n![1, 2, 3, 4])); - m!(&mut v, [sub @ .., N(4)] => c!(sub, &mut [N; 4], &mut n![0, 1, 2, 3])); - m!(&mut v, [sub @ .., _, _, _, _, _] => c!(sub, &mut [N; 0], &mut n![] as &[N; 0])); - m!(&mut v, [_, _, _, _, _, sub @ ..] => c!(sub, &mut [N; 0], &mut n![] as &[N; 0])); - m!(&mut v, [..] => ()); - m!(&mut v, [x, .., y] => c!((x, y), (&mut N, &mut N), (&mut N(0), &mut N(4)))); -} - -#[test] -fn test_chunk_by() { - let slice = &[1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; - - 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(), Some(&[1][..])); - assert_eq!(iter.next(), Some(&[0][..])); - assert_eq!(iter.next(), None); - - let mut iter = slice.chunk_by(|a, b| a == b); - assert_eq!(iter.next_back(), Some(&[0][..])); - assert_eq!(iter.next_back(), Some(&[1][..])); - assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); - assert_eq!(iter.next_back(), Some(&[3, 3][..])); - assert_eq!(iter.next_back(), Some(&[1, 1, 1][..])); - assert_eq!(iter.next_back(), None); - - let mut iter = slice.chunk_by(|a, b| a == b); - assert_eq!(iter.next(), Some(&[1, 1, 1][..])); - assert_eq!(iter.next_back(), Some(&[0][..])); - assert_eq!(iter.next(), Some(&[3, 3][..])); - assert_eq!(iter.next_back(), Some(&[1][..])); - assert_eq!(iter.next(), Some(&[2, 2, 2][..])); - assert_eq!(iter.next_back(), None); -} - -#[test] -fn test_chunk_by_mut() { - let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; - - 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(), Some(&mut [1][..])); - assert_eq!(iter.next(), Some(&mut [0][..])); - assert_eq!(iter.next(), None); - - let mut iter = slice.chunk_by_mut(|a, b| a == b); - assert_eq!(iter.next_back(), Some(&mut [0][..])); - assert_eq!(iter.next_back(), Some(&mut [1][..])); - assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..])); - assert_eq!(iter.next_back(), Some(&mut [3, 3][..])); - assert_eq!(iter.next_back(), Some(&mut [1, 1, 1][..])); - assert_eq!(iter.next_back(), None); - - let mut iter = slice.chunk_by_mut(|a, b| a == b); - assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); - assert_eq!(iter.next_back(), Some(&mut [0][..])); - assert_eq!(iter.next(), Some(&mut [3, 3][..])); - assert_eq!(iter.next_back(), Some(&mut [1][..])); - assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); - assert_eq!(iter.next_back(), None); -} diff --git a/library/alloc/tests/sort/ffi_types.rs b/library/alloc/tests/sort/ffi_types.rs deleted file mode 100644 index 11515ea4769..00000000000 --- a/library/alloc/tests/sort/ffi_types.rs +++ /dev/null @@ -1,82 +0,0 @@ -use std::cmp::Ordering; - -// Very large stack value. -#[repr(C)] -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct FFIOneKibiByte { - values: [i64; 128], -} - -impl FFIOneKibiByte { - pub fn new(val: i32) -> Self { - let mut values = [0i64; 128]; - let mut val_i64 = val as i64; - - for elem in &mut values { - *elem = val_i64; - val_i64 = std::hint::black_box(val_i64 + 1); - } - Self { values } - } - - fn as_i64(&self) -> i64 { - self.values[11] + self.values[55] + self.values[77] - } -} - -impl PartialOrd for FFIOneKibiByte { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for FFIOneKibiByte { - fn cmp(&self, other: &Self) -> Ordering { - self.as_i64().cmp(&other.as_i64()) - } -} - -// 16 byte stack value, with more expensive comparison. -#[repr(C)] -#[derive(PartialEq, Debug, Clone, Copy)] -pub struct F128 { - x: f64, - y: f64, -} - -impl F128 { - pub fn new(val: i32) -> Self { - let val_f = (val as f64) + (i32::MAX as f64) + 10.0; - - let x = val_f + 0.1; - let y = val_f.log(4.1); - - assert!(y < x); - assert!(x.is_normal() && y.is_normal()); - - Self { x, y } - } -} - -// This is kind of hacky, but we know we only have normal comparable floats in there. -impl Eq for F128 {} - -impl PartialOrd for F128 { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -// Goal is similar code-gen between Rust and C++ -// - Rust https://godbolt.org/z/3YM3xenPP -// - C++ https://godbolt.org/z/178M6j1zz -impl Ord for F128 { - fn cmp(&self, other: &Self) -> Ordering { - // Simulate expensive comparison function. - let this_div = self.x / self.y; - let other_div = other.x / other.y; - - // SAFETY: We checked in the ctor that both are normal. - unsafe { this_div.partial_cmp(&other_div).unwrap_unchecked() } - } -} diff --git a/library/alloc/tests/sort/known_good_stable_sort.rs b/library/alloc/tests/sort/known_good_stable_sort.rs deleted file mode 100644 index 2df89146253..00000000000 --- a/library/alloc/tests/sort/known_good_stable_sort.rs +++ /dev/null @@ -1,192 +0,0 @@ -// This module implements a known good stable sort implementation that helps provide better error -// messages when the correctness tests fail, we can't use the stdlib sort functions because we are -// testing them for correctness. -// -// Based on https://github.com/voultapher/tiny-sort-rs. - -use alloc::alloc::{Layout, alloc, dealloc}; -use std::ptr; - -/// Sort `v` preserving initial order of equal elements. -/// -/// - Guaranteed O(N * log(N)) worst case perf -/// - No adaptiveness -/// - Branch miss-prediction not affected by outcome of comparison function -/// - Uses `v.len()` auxiliary memory. -/// -/// If `T: Ord` does not implement a total order the resulting order is -/// unspecified. All original elements will remain in `v` and any possible modifications via -/// interior mutability will be observable. Same is true if `T: Ord` panics. -/// -/// Panics if allocating the auxiliary memory fails. -#[inline(always)] -pub fn sort(v: &mut [T]) { - stable_sort(v, |a, b| a.lt(b)) -} - -#[inline(always)] -fn stable_sort bool>(v: &mut [T], mut is_less: F) { - if size_of::() == 0 { - return; - } - - let len = v.len(); - - // Inline the check for len < 2. This happens a lot, instrumenting the Rust compiler suggests - // len < 2 accounts for 94% of its calls to `slice::sort`. - if len < 2 { - return; - } - - // SAFETY: We checked that len is > 0 and that T is not a ZST. - unsafe { - mergesort_main(v, &mut is_less); - } -} - -/// The core logic should not be inlined. -/// -/// SAFETY: The caller has to ensure that len is > 0 and that T is not a ZST. -#[inline(never)] -unsafe fn mergesort_main bool>(v: &mut [T], is_less: &mut F) { - // While it would be nice to have a merge implementation that only requires N / 2 auxiliary - // memory. Doing so would make the merge implementation significantly more complex and - - // SAFETY: See function safety description. - let buf = unsafe { BufGuard::new(v.len()) }; - - // SAFETY: `scratch` has space for `v.len()` writes. And does not alias `v`. - unsafe { - mergesort_core(v, buf.buf_ptr.as_ptr(), is_less); - } -} - -/// Tiny recursive top-down merge sort optimized for binary size. It has no adaptiveness whatsoever, -/// no run detection, etc. -/// -/// Buffer as pointed to by `scratch` must have space for `v.len()` writes. And must not alias `v`. -#[inline(always)] -unsafe fn mergesort_core bool>( - v: &mut [T], - scratch_ptr: *mut T, - is_less: &mut F, -) { - let len = v.len(); - - if len > 2 { - // SAFETY: `mid` is guaranteed in-bounds. And caller has to ensure that `scratch_ptr` can - // hold `v.len()` values. - unsafe { - let mid = len / 2; - // Sort the left half recursively. - mergesort_core(v.get_unchecked_mut(..mid), scratch_ptr, is_less); - // Sort the right half recursively. - mergesort_core(v.get_unchecked_mut(mid..), scratch_ptr, is_less); - // Combine the two halves. - merge(v, scratch_ptr, is_less, mid); - } - } else if len == 2 { - if is_less(&v[1], &v[0]) { - v.swap(0, 1); - } - } -} - -/// Branchless merge function. -/// -/// SAFETY: The caller must ensure that `scratch_ptr` is valid for `v.len()` writes. And that mid is -/// in-bounds. -#[inline(always)] -unsafe fn merge(v: &mut [T], scratch_ptr: *mut T, is_less: &mut F, mid: usize) -where - F: FnMut(&T, &T) -> bool, -{ - let len = v.len(); - debug_assert!(mid > 0 && mid < len); - - let len = v.len(); - - // Indexes to track the positions while merging. - let mut l = 0; - let mut r = mid; - - // SAFETY: No matter what the result of is_less is we check that l and r remain in-bounds and if - // is_less panics the original elements remain in `v`. - unsafe { - let arr_ptr = v.as_ptr(); - - for i in 0..len { - let left_ptr = arr_ptr.add(l); - let right_ptr = arr_ptr.add(r); - - let is_lt = !is_less(&*right_ptr, &*left_ptr); - let copy_ptr = if is_lt { left_ptr } else { right_ptr }; - ptr::copy_nonoverlapping(copy_ptr, scratch_ptr.add(i), 1); - - l += is_lt as usize; - r += !is_lt as usize; - - // As long as neither side is exhausted merge left and right elements. - if ((l == mid) as u8 + (r == len) as u8) != 0 { - break; - } - } - - // The left or right side is exhausted, drain the right side in one go. - let copy_ptr = if l == mid { arr_ptr.add(r) } else { arr_ptr.add(l) }; - let i = l + (r - mid); - ptr::copy_nonoverlapping(copy_ptr, scratch_ptr.add(i), len - i); - - // Now that scratch_ptr holds the full merged content, write it back on-top of v. - ptr::copy_nonoverlapping(scratch_ptr, v.as_mut_ptr(), len); - } -} - -// SAFETY: The caller has to ensure that Option is Some, UB otherwise. -unsafe fn unwrap_unchecked(opt_val: Option) -> T { - match opt_val { - Some(val) => val, - None => { - // SAFETY: See function safety description. - unsafe { - core::hint::unreachable_unchecked(); - } - } - } -} - -// Extremely basic versions of Vec. -// Their use is super limited and by having the code here, it allows reuse between the sort -// implementations. -struct BufGuard { - buf_ptr: ptr::NonNull, - capacity: usize, -} - -impl BufGuard { - // SAFETY: The caller has to ensure that len is not 0 and that T is not a ZST. - unsafe fn new(len: usize) -> Self { - debug_assert!(len > 0 && size_of::() > 0); - - // SAFETY: See function safety description. - let layout = unsafe { unwrap_unchecked(Layout::array::(len).ok()) }; - - // SAFETY: We checked that T is not a ZST. - let buf_ptr = unsafe { alloc(layout) as *mut T }; - - if buf_ptr.is_null() { - panic!("allocation failure"); - } - - Self { buf_ptr: ptr::NonNull::new(buf_ptr).unwrap(), capacity: len } - } -} - -impl Drop for BufGuard { - fn drop(&mut self) { - // SAFETY: We checked that T is not a ZST. - unsafe { - dealloc(self.buf_ptr.as_ptr() as *mut u8, Layout::array::(self.capacity).unwrap()); - } - } -} diff --git a/library/alloc/tests/sort/mod.rs b/library/alloc/tests/sort/mod.rs deleted file mode 100644 index 0e2494ca9d3..00000000000 --- a/library/alloc/tests/sort/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub trait Sort { - fn name() -> String; - - fn sort(v: &mut [T]) - where - T: Ord; - - fn sort_by(v: &mut [T], compare: F) - where - F: FnMut(&T, &T) -> std::cmp::Ordering; -} - -mod ffi_types; -mod known_good_stable_sort; -mod patterns; -mod tests; -mod zipf; diff --git a/library/alloc/tests/sort/patterns.rs b/library/alloc/tests/sort/patterns.rs deleted file mode 100644 index 0f1ec664d3d..00000000000 --- a/library/alloc/tests/sort/patterns.rs +++ /dev/null @@ -1,211 +0,0 @@ -use std::env; -use std::str::FromStr; -use std::sync::OnceLock; - -use rand::distr::Uniform; -use rand::prelude::*; -use rand_xorshift::XorShiftRng; - -use crate::sort::zipf::ZipfDistribution; - -/// Provides a set of patterns useful for testing and benchmarking sorting algorithms. -/// Currently limited to i32 values. - -// --- Public --- - -pub fn random(len: usize) -> Vec { - // . - // : . : : - // :.:::.:: - - random_vec(len) -} - -pub fn random_uniform(len: usize, range: R) -> Vec -where - Uniform: TryFrom, -{ - // :.:.:.:: - - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); - - // Abstracting over ranges in Rust :( - let dist = Uniform::try_from(range).unwrap(); - (0..len).map(|_| dist.sample(&mut rng)).collect() -} - -pub fn random_zipf(len: usize, exponent: f64) -> Vec { - // https://en.wikipedia.org/wiki/Zipf's_law - - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); - - // Abstracting over ranges in Rust :( - let dist = ZipfDistribution::new(len, exponent).unwrap(); - (0..len).map(|_| dist.sample(&mut rng) as i32).collect() -} - -pub fn random_sorted(len: usize, sorted_percent: f64) -> Vec { - // .: - // .:::. : - // .::::::.:: - // [----][--] - // ^ ^ - // | | - // sorted | - // unsorted - - // Simulate pre-existing sorted slice, where len - sorted_percent are the new unsorted values - // and part of the overall distribution. - let mut v = random_vec(len); - let sorted_len = ((len as f64) * (sorted_percent / 100.0)).round() as usize; - - v[0..sorted_len].sort_unstable(); - - v -} - -pub fn all_equal(len: usize) -> Vec { - // ...... - // :::::: - - (0..len).map(|_| 66).collect::>() -} - -pub fn ascending(len: usize) -> Vec { - // .: - // .::: - // .::::: - - (0..len as i32).collect::>() -} - -pub fn descending(len: usize) -> Vec { - // :. - // :::. - // :::::. - - (0..len as i32).rev().collect::>() -} - -pub fn saw_mixed(len: usize, saw_count: usize) -> Vec { - // :. :. .::. .: - // :::.:::..::::::..::: - - if len == 0 { - return Vec::new(); - } - - let mut vals = random_vec(len); - let chunks_size = len / saw_count.max(1); - let saw_directions = random_uniform((len / chunks_size) + 1, 0..=1); - - for (i, chunk) in vals.chunks_mut(chunks_size).enumerate() { - if saw_directions[i] == 0 { - chunk.sort_unstable(); - } else if saw_directions[i] == 1 { - chunk.sort_unstable_by_key(|&e| std::cmp::Reverse(e)); - } else { - unreachable!(); - } - } - - vals -} - -pub fn saw_mixed_range(len: usize, range: std::ops::Range) -> Vec { - // :. - // :. :::. .::. .: - // :::.:::::..::::::..:.::: - - // ascending and descending randomly picked, with length in `range`. - - if len == 0 { - return Vec::new(); - } - - let mut vals = random_vec(len); - - let max_chunks = len / range.start; - let saw_directions = random_uniform(max_chunks + 1, 0..=1); - let chunk_sizes = random_uniform(max_chunks + 1, (range.start as i32)..(range.end as i32)); - - let mut i = 0; - let mut l = 0; - while l < len { - let chunk_size = chunk_sizes[i] as usize; - let chunk_end = std::cmp::min(l + chunk_size, len); - let chunk = &mut vals[l..chunk_end]; - - if saw_directions[i] == 0 { - chunk.sort_unstable(); - } else if saw_directions[i] == 1 { - chunk.sort_unstable_by_key(|&e| std::cmp::Reverse(e)); - } else { - unreachable!(); - } - - i += 1; - l += chunk_size; - } - - vals -} - -pub fn pipe_organ(len: usize) -> Vec { - // .:. - // .:::::. - - let mut vals = random_vec(len); - - let first_half = &mut vals[0..(len / 2)]; - first_half.sort_unstable(); - - let second_half = &mut vals[(len / 2)..len]; - second_half.sort_unstable_by_key(|&e| std::cmp::Reverse(e)); - - vals -} - -pub fn get_or_init_rand_seed() -> u64 { - *SEED_VALUE.get_or_init(|| { - env::var("OVERRIDE_SEED") - .ok() - .map(|seed| u64::from_str(&seed).unwrap()) - .unwrap_or_else(rand_root_seed) - }) -} - -// --- Private --- - -static SEED_VALUE: OnceLock = OnceLock::new(); - -#[cfg(not(miri))] -fn rand_root_seed() -> u64 { - // Other test code hashes `panic::Location::caller()` and constructs a seed from that, in these - // tests we want to have a fuzzer like exploration of the test space, if we used the same caller - // based construction we would always test the same. - // - // Instead we use the seconds since UNIX epoch / 10, given CI log output this value should be - // reasonably easy to re-construct. - - use std::time::{SystemTime, UNIX_EPOCH}; - - let epoch_seconds = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); - - epoch_seconds / 10 -} - -#[cfg(miri)] -fn rand_root_seed() -> u64 { - // Miri is usually run with isolation with gives us repeatability but also permutations based on - // other code that runs before. - use core::hash::{BuildHasher, Hash, Hasher}; - let mut hasher = std::hash::RandomState::new().build_hasher(); - core::panic::Location::caller().hash(&mut hasher); - hasher.finish() -} - -fn random_vec(len: usize) -> Vec { - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); - (0..len).map(|_| rng.random::()).collect() -} diff --git a/library/alloc/tests/sort/tests.rs b/library/alloc/tests/sort/tests.rs deleted file mode 100644 index d321f8df518..00000000000 --- a/library/alloc/tests/sort/tests.rs +++ /dev/null @@ -1,1240 +0,0 @@ -use std::cell::Cell; -use std::cmp::Ordering; -use std::fmt::Debug; -use std::panic::{self, AssertUnwindSafe}; -use std::rc::Rc; -use std::{env, fs}; - -use crate::sort::ffi_types::{F128, FFIOneKibiByte}; -use crate::sort::{Sort, known_good_stable_sort, patterns}; - -#[cfg(miri)] -const TEST_LENGTHS: &[usize] = &[2, 3, 4, 7, 10, 15, 20, 24, 33, 50, 100, 171, 300]; - -// node.js gives out of memory error to use with length 1_100_000 -#[cfg(all(not(miri), target_os = "emscripten"))] -const TEST_LENGTHS: &[usize] = &[ - 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 20, 24, 30, 32, 33, 35, 50, 100, 200, 500, 1_000, - 2_048, 5_000, 10_000, 100_000, -]; - -#[cfg(all(not(miri), not(target_os = "emscripten")))] -const TEST_LENGTHS: &[usize] = &[ - 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 20, 24, 30, 32, 33, 35, 50, 100, 200, 500, 1_000, - 2_048, 5_000, 10_000, 100_000, 1_100_000, -]; - -fn check_is_sorted(v: &mut [T]) { - let seed = patterns::get_or_init_rand_seed(); - - let is_small_test = v.len() <= 100; - let v_orig = v.to_vec(); - - ::sort(v); - - assert_eq!(v.len(), v_orig.len()); - - for window in v.windows(2) { - if window[0] > window[1] { - let mut known_good_sorted_vec = v_orig.clone(); - known_good_stable_sort::sort(known_good_sorted_vec.as_mut_slice()); - - if is_small_test { - eprintln!("Original: {:?}", v_orig); - eprintln!("Expected: {:?}", known_good_sorted_vec); - eprintln!("Got: {:?}", v); - } else { - if env::var("WRITE_LARGE_FAILURE").is_ok() { - // Large arrays output them as files. - let original_name = format!("original_{}.txt", seed); - let std_name = format!("known_good_sorted_{}.txt", seed); - let testsort_name = format!("{}_sorted_{}.txt", S::name(), seed); - - fs::write(&original_name, format!("{:?}", v_orig)).unwrap(); - fs::write(&std_name, format!("{:?}", known_good_sorted_vec)).unwrap(); - fs::write(&testsort_name, format!("{:?}", v)).unwrap(); - - eprintln!( - "Failed comparison, see files {original_name}, {std_name}, and {testsort_name}" - ); - } else { - eprintln!( - "Failed comparison, re-run with WRITE_LARGE_FAILURE env var set, to get output." - ); - } - } - - panic!("Test assertion failed!") - } - } -} - -fn test_is_sorted( - test_len: usize, - map_fn: impl Fn(i32) -> T, - pattern_fn: impl Fn(usize) -> Vec, -) { - let mut test_data: Vec = pattern_fn(test_len).into_iter().map(map_fn).collect(); - check_is_sorted::(test_data.as_mut_slice()); -} - -trait DynTrait: Debug { - fn get_val(&self) -> i32; -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -struct DynValA { - value: i32, -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -struct DynValB { - value: u64, -} - -impl DynTrait for DynValA { - fn get_val(&self) -> i32 { - self.value - } -} -impl DynTrait for DynValB { - fn get_val(&self) -> i32 { - let bytes = self.value.to_ne_bytes(); - i32::from_ne_bytes([bytes[0], bytes[1], bytes[6], bytes[7]]) - } -} - -impl PartialOrd for dyn DynTrait { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for dyn DynTrait { - fn cmp(&self, other: &Self) -> Ordering { - self.get_val().cmp(&other.get_val()) - } -} - -impl PartialEq for dyn DynTrait { - fn eq(&self, other: &Self) -> bool { - self.get_val() == other.get_val() - } -} - -impl Eq for dyn DynTrait {} - -fn shift_i32_to_u32(val: i32) -> u32 { - (val as i64 + (i32::MAX as i64 + 1)) as u32 -} - -fn reverse_shift_i32_to_u32(val: u32) -> i32 { - (val as i64 - (i32::MAX as i64 + 1)) as i32 -} - -fn extend_i32_to_u64(val: i32) -> u64 { - // Extends the value into the 64 bit range, - // while preserving input order. - (shift_i32_to_u32(val) as u64) * i32::MAX as u64 -} - -fn extend_i32_to_u128(val: i32) -> u128 { - // Extends the value into the 64 bit range, - // while preserving input order. - (shift_i32_to_u32(val) as u128) * i64::MAX as u128 -} - -fn dyn_trait_from_i32(val: i32) -> Rc { - if val % 2 == 0 { - Rc::new(DynValA { value: val }) - } else { - Rc::new(DynValB { value: extend_i32_to_u64(val) }) - } -} - -fn i32_from_i32(val: i32) -> i32 { - val -} - -fn i32_from_i32_ref(val: &i32) -> i32 { - *val -} - -fn string_from_i32(val: i32) -> String { - format!("{:010}", shift_i32_to_u32(val)) -} - -fn i32_from_string(val: &String) -> i32 { - reverse_shift_i32_to_u32(val.parse::().unwrap()) -} - -fn cell_i32_from_i32(val: i32) -> Cell { - Cell::new(val) -} - -fn i32_from_cell_i32(val: &Cell) -> i32 { - val.get() -} - -fn calc_comps_required(v: &mut [T], mut cmp_fn: impl FnMut(&T, &T) -> Ordering) -> u32 { - let mut comp_counter = 0u32; - - ::sort_by(v, |a, b| { - comp_counter += 1; - - cmp_fn(a, b) - }); - - comp_counter -} - -#[derive(PartialEq, Eq, Debug, Clone)] -#[repr(C)] -struct CompCount { - val: i32, - comp_count: Cell, -} - -impl CompCount { - fn new(val: i32) -> Self { - Self { val, comp_count: Cell::new(0) } - } -} - -/// Generates $base_name_pattern_name_impl functions calling the test_fns for all test_len. -macro_rules! gen_sort_test_fns { - ( - $base_name:ident, - $test_fn:expr, - $test_lengths:expr, - [$(($pattern_name:ident, $pattern_fn:expr)),* $(,)?] $(,)? - ) => { - $(fn ${concat($base_name, _, $pattern_name, _impl)}() { - for test_len in $test_lengths { - $test_fn(*test_len, $pattern_fn); - } - })* - }; -} - -/// Generates $base_name_pattern_name_impl functions calling the test_fns for all test_len, -/// with a default set of patterns that can be extended by the caller. -macro_rules! gen_sort_test_fns_with_default_patterns { - ( - $base_name:ident, - $test_fn:expr, - $test_lengths:expr, - [$(($pattern_name:ident, $pattern_fn:expr)),* $(,)?] $(,)? - ) => { - gen_sort_test_fns!( - $base_name, - $test_fn, - $test_lengths, - [ - (random, patterns::random), - (random_z1, |len| patterns::random_zipf(len, 1.0)), - (random_d2, |len| patterns::random_uniform(len, 0..2)), - (random_d20, |len| patterns::random_uniform(len, 0..16)), - (random_s95, |len| patterns::random_sorted(len, 95.0)), - (ascending, patterns::ascending), - (descending, patterns::descending), - (saw_mixed, |len| patterns::saw_mixed( - len, - ((len as f64).log2().round()) as usize - )), - $(($pattern_name, $pattern_fn),)* - ] - ); - }; -} - -/// Generates $base_name_type_pattern_name_impl functions calling the test_fns for all test_len for -/// three types that cover the core specialization differences in the sort implementations, with a -/// default set of patterns that can be extended by the caller. -macro_rules! gen_sort_test_fns_with_default_patterns_3_ty { - ( - $base_name:ident, - $test_fn:ident, - [$(($pattern_name:ident, $pattern_fn:expr)),* $(,)?] $(,)? - ) => { - gen_sort_test_fns_with_default_patterns!( - ${concat($base_name, _i32)}, - |len, pattern_fn| $test_fn::(len, i32_from_i32, i32_from_i32_ref, pattern_fn), - &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], - [$(($pattern_name, $pattern_fn),)*], - ); - - gen_sort_test_fns_with_default_patterns!( - ${concat($base_name, _cell_i32)}, - |len, pattern_fn| $test_fn::, S>(len, cell_i32_from_i32, i32_from_cell_i32, pattern_fn), - &TEST_LENGTHS[..TEST_LENGTHS.len() - 3], - [$(($pattern_name, $pattern_fn),)*], - ); - - gen_sort_test_fns_with_default_patterns!( - ${concat($base_name, _string)}, - |len, pattern_fn| $test_fn::(len, string_from_i32, i32_from_string, pattern_fn), - &TEST_LENGTHS[..TEST_LENGTHS.len() - 3], - [$(($pattern_name, $pattern_fn),)*], - ); - }; -} - -// --- TESTS --- - -pub fn basic_impl() { - check_is_sorted::(&mut []); - check_is_sorted::<(), S>(&mut []); - check_is_sorted::<(), S>(&mut [()]); - check_is_sorted::<(), S>(&mut [(), ()]); - check_is_sorted::<(), S>(&mut [(), (), ()]); - check_is_sorted::(&mut []); - check_is_sorted::(&mut [77]); - check_is_sorted::(&mut [2, 3]); - check_is_sorted::(&mut [2, 3, 6]); - check_is_sorted::(&mut [2, 3, 99, 6]); - check_is_sorted::(&mut [2, 7709, 400, 90932]); - check_is_sorted::(&mut [15, -1, 3, -1, -3, -1, 7]); -} - -fn fixed_seed_impl() { - let fixed_seed_a = patterns::get_or_init_rand_seed(); - let fixed_seed_b = patterns::get_or_init_rand_seed(); - - assert_eq!(fixed_seed_a, fixed_seed_b); -} - -fn fixed_seed_rand_vec_prefix_impl() { - let vec_rand_len_5 = patterns::random(5); - let vec_rand_len_7 = patterns::random(7); - - assert_eq!(vec_rand_len_5, vec_rand_len_7[..5]); -} - -fn int_edge_impl() { - // Ensure that the sort can handle integer edge cases. - check_is_sorted::(&mut [i32::MIN, i32::MAX]); - check_is_sorted::(&mut [i32::MAX, i32::MIN]); - check_is_sorted::(&mut [i32::MIN, 3]); - check_is_sorted::(&mut [i32::MIN, -3]); - check_is_sorted::(&mut [i32::MIN, -3, i32::MAX]); - check_is_sorted::(&mut [i32::MIN, -3, i32::MAX, i32::MIN, 5]); - check_is_sorted::(&mut [i32::MAX, 3, i32::MIN, 5, i32::MIN, -3, 60, 200, 50, 7, 10]); - - check_is_sorted::(&mut [u64::MIN, u64::MAX]); - check_is_sorted::(&mut [u64::MAX, u64::MIN]); - check_is_sorted::(&mut [u64::MIN, 3]); - check_is_sorted::(&mut [u64::MIN, u64::MAX - 3]); - check_is_sorted::(&mut [u64::MIN, u64::MAX - 3, u64::MAX]); - check_is_sorted::(&mut [u64::MIN, u64::MAX - 3, u64::MAX, u64::MIN, 5]); - check_is_sorted::(&mut [ - u64::MAX, - 3, - u64::MIN, - 5, - u64::MIN, - u64::MAX - 3, - 60, - 200, - 50, - 7, - 10, - ]); - - let mut large = patterns::random(TEST_LENGTHS[TEST_LENGTHS.len() - 2]); - large.push(i32::MAX); - large.push(i32::MIN); - large.push(i32::MAX); - check_is_sorted::(&mut large); -} - -fn sort_vs_sort_by_impl() { - // Ensure that sort and sort_by produce the same result. - let mut input_normal = [800, 3, -801, 5, -801, -3, 60, 200, 50, 7, 10]; - let expected = [-801, -801, -3, 3, 5, 7, 10, 50, 60, 200, 800]; - - let mut input_sort_by = input_normal.to_vec(); - - ::sort(&mut input_normal); - ::sort_by(&mut input_sort_by, |a, b| a.cmp(b)); - - assert_eq!(input_normal, expected); - assert_eq!(input_sort_by, expected); -} - -gen_sort_test_fns_with_default_patterns!( - correct_i32, - |len, pattern_fn| test_is_sorted::(len, |val| val, pattern_fn), - TEST_LENGTHS, - [ - (random_d4, |len| patterns::random_uniform(len, 0..4)), - (random_d8, |len| patterns::random_uniform(len, 0..8)), - (random_d311, |len| patterns::random_uniform(len, 0..311)), - (random_d1024, |len| patterns::random_uniform(len, 0..1024)), - (random_z1_03, |len| patterns::random_zipf(len, 1.03)), - (random_z2, |len| patterns::random_zipf(len, 2.0)), - (random_s50, |len| patterns::random_sorted(len, 50.0)), - (narrow, |len| patterns::random_uniform( - len, - 0..=(((len as f64).log2().round()) as i32) * 100 - )), - (all_equal, patterns::all_equal), - (saw_mixed_range, |len| patterns::saw_mixed_range(len, 20..50)), - (pipe_organ, patterns::pipe_organ), - ] -); - -gen_sort_test_fns_with_default_patterns!( - correct_u64, - |len, pattern_fn| test_is_sorted::(len, extend_i32_to_u64, pattern_fn), - TEST_LENGTHS, - [] -); - -gen_sort_test_fns_with_default_patterns!( - correct_u128, - |len, pattern_fn| test_is_sorted::(len, extend_i32_to_u128, pattern_fn), - &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], - [] -); - -gen_sort_test_fns_with_default_patterns!( - correct_cell_i32, - |len, pattern_fn| test_is_sorted::, S>(len, Cell::new, pattern_fn), - &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], - [] -); - -gen_sort_test_fns_with_default_patterns!( - correct_string, - |len, pattern_fn| test_is_sorted::( - len, - |val| format!("{:010}", shift_i32_to_u32(val)), - pattern_fn - ), - &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], - [] -); - -gen_sort_test_fns_with_default_patterns!( - correct_f128, - |len, pattern_fn| test_is_sorted::(len, F128::new, pattern_fn), - &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], - [] -); - -gen_sort_test_fns_with_default_patterns!( - correct_1k, - |len, pattern_fn| test_is_sorted::(len, FFIOneKibiByte::new, pattern_fn), - &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], - [] -); - -// Dyn values are fat pointers, something the implementation might have overlooked. -gen_sort_test_fns_with_default_patterns!( - correct_dyn_val, - |len, pattern_fn| test_is_sorted::, S>(len, dyn_trait_from_i32, pattern_fn), - &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], - [] -); - -fn stability_legacy_impl() { - // This non pattern variant has proven to catch some bugs the pattern version of this function - // doesn't catch, so it remains in conjunction with the other one. - - if ::name().contains("unstable") { - // It would be great to mark the test as skipped, but that isn't possible as of now. - return; - } - - let large_range = if cfg!(miri) { 100..110 } else { 3000..3010 }; - let rounds = if cfg!(miri) { 1 } else { 10 }; - - let rand_vals = patterns::random_uniform(5_000, 0..=9); - let mut rand_idx = 0; - - for len in (2..55).chain(large_range) { - for _ in 0..rounds { - let mut counts = [0; 10]; - - // create a vector like [(6, 1), (5, 1), (6, 2), ...], - // where the first item of each tuple is random, but - // the second item represents which occurrence of that - // number this element is, i.e., the second elements - // will occur in sorted order. - let orig: Vec<_> = (0..len) - .map(|_| { - let n = rand_vals[rand_idx]; - rand_idx += 1; - if rand_idx >= rand_vals.len() { - rand_idx = 0; - } - - counts[n as usize] += 1; - i32_tup_as_u64((n, counts[n as usize])) - }) - .collect(); - - let mut v = orig.clone(); - // Only sort on the first element, so an unstable sort - // may mix up the counts. - ::sort_by(&mut v, |a_packed, b_packed| { - let a = i32_tup_from_u64(*a_packed).0; - let b = i32_tup_from_u64(*b_packed).0; - - a.cmp(&b) - }); - - // This comparison includes the count (the second item - // of the tuple), so elements with equal first items - // will need to be ordered with increasing - // counts... i.e., exactly asserting that this sort is - // stable. - assert!(v.windows(2).all(|w| i32_tup_from_u64(w[0]) <= i32_tup_from_u64(w[1]))); - } - } - - // For cpp_sorts that only support u64 we can pack the two i32 inside a u64. - fn i32_tup_as_u64(val: (i32, i32)) -> u64 { - let a_bytes = val.0.to_le_bytes(); - let b_bytes = val.1.to_le_bytes(); - - u64::from_le_bytes([a_bytes, b_bytes].concat().try_into().unwrap()) - } - - fn i32_tup_from_u64(val: u64) -> (i32, i32) { - let bytes = val.to_le_bytes(); - - let a = i32::from_le_bytes(bytes[0..4].try_into().unwrap()); - let b = i32::from_le_bytes(bytes[4..8].try_into().unwrap()); - - (a, b) - } -} - -fn stability_with_patterns( - len: usize, - type_into_fn: impl Fn(i32) -> T, - _type_from_fn: impl Fn(&T) -> i32, - pattern_fn: fn(usize) -> Vec, -) { - if ::name().contains("unstable") { - // It would be great to mark the test as skipped, but that isn't possible as of now. - return; - } - - let pattern = pattern_fn(len); - - let mut counts = [0i32; 128]; - - // create a vector like [(6, 1), (5, 1), (6, 2), ...], - // where the first item of each tuple is random, but - // the second item represents which occurrence of that - // number this element is, i.e., the second elements - // will occur in sorted order. - let orig: Vec<_> = pattern - .iter() - .map(|val| { - let n = val.saturating_abs() % counts.len() as i32; - counts[n as usize] += 1; - (type_into_fn(n), counts[n as usize]) - }) - .collect(); - - let mut v = orig.clone(); - // Only sort on the first element, so an unstable sort - // may mix up the counts. - ::sort(&mut v); - - // This comparison includes the count (the second item - // of the tuple), so elements with equal first items - // will need to be ordered with increasing - // counts... i.e., exactly asserting that this sort is - // stable. - assert!(v.windows(2).all(|w| w[0] <= w[1])); -} - -gen_sort_test_fns_with_default_patterns_3_ty!(stability, stability_with_patterns, []); - -fn observable_is_less(len: usize, pattern_fn: fn(usize) -> Vec) { - // This test, tests that every is_less is actually observable. Ie. this can go wrong if a hole - // is created using temporary memory and, the whole is used as comparison but not copied back. - // - // If this is not upheld a custom type + comparison function could yield UB in otherwise safe - // code. Eg T == Mutex>> which replaces the pointer with none in the comparison - // function, which would not be observed in the original slice and would lead to a double free. - - let pattern = pattern_fn(len); - let mut test_input = pattern.into_iter().map(|val| CompCount::new(val)).collect::>(); - - let mut comp_count_global = 0; - - ::sort_by(&mut test_input, |a, b| { - a.comp_count.replace(a.comp_count.get() + 1); - b.comp_count.replace(b.comp_count.get() + 1); - comp_count_global += 1; - - a.val.cmp(&b.val) - }); - - let total_inner: u64 = test_input.iter().map(|c| c.comp_count.get() as u64).sum(); - - assert_eq!(total_inner, comp_count_global * 2); -} - -gen_sort_test_fns_with_default_patterns!( - observable_is_less, - observable_is_less::, - &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], - [] -); - -fn panic_retain_orig_set( - len: usize, - type_into_fn: impl Fn(i32) -> T + Copy, - type_from_fn: impl Fn(&T) -> i32, - pattern_fn: fn(usize) -> Vec, -) { - let mut test_data: Vec = pattern_fn(len).into_iter().map(type_into_fn).collect(); - - let sum_before: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); - - // Calculate a specific comparison that should panic. - // Ensure that it can be any of the possible comparisons and that it always panics. - let required_comps = calc_comps_required::(&mut test_data.clone(), |a, b| a.cmp(b)); - let panic_threshold = patterns::random_uniform(1, 1..=required_comps as i32)[0] as usize - 1; - - let mut comp_counter = 0; - - let res = panic::catch_unwind(AssertUnwindSafe(|| { - ::sort_by(&mut test_data, |a, b| { - if comp_counter == panic_threshold { - // Make the panic dependent on the test len and some random factor. We want to - // make sure that panicking may also happen when comparing elements a second - // time. - panic!(); - } - comp_counter += 1; - - a.cmp(b) - }); - })); - - assert!(res.is_err()); - - // If the sum before and after don't match, it means the set of elements hasn't remained the - // same. - let sum_after: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); - assert_eq!(sum_before, sum_after); -} - -gen_sort_test_fns_with_default_patterns_3_ty!(panic_retain_orig_set, panic_retain_orig_set, []); - -fn panic_observable_is_less(len: usize, pattern_fn: fn(usize) -> Vec) { - // This test, tests that every is_less is actually observable. Ie. this can go wrong if a hole - // is created using temporary memory and, the whole is used as comparison but not copied back. - // This property must also hold if the user provided comparison panics. - // - // If this is not upheld a custom type + comparison function could yield UB in otherwise safe - // code. Eg T == Mutex>> which replaces the pointer with none in the comparison - // function, which would not be observed in the original slice and would lead to a double free. - - let mut test_input = - pattern_fn(len).into_iter().map(|val| CompCount::new(val)).collect::>(); - - let sum_before: i64 = test_input.iter().map(|x| x.val as i64).sum(); - - // Calculate a specific comparison that should panic. - // Ensure that it can be any of the possible comparisons and that it always panics. - let required_comps = - calc_comps_required::(&mut test_input.clone(), |a, b| a.val.cmp(&b.val)); - - let panic_threshold = patterns::random_uniform(1, 1..=required_comps as i32)[0] as u64 - 1; - - let mut comp_count_global = 0; - - let res = panic::catch_unwind(AssertUnwindSafe(|| { - ::sort_by(&mut test_input, |a, b| { - if comp_count_global == panic_threshold { - // Make the panic dependent on the test len and some random factor. We want to - // make sure that panicking may also happen when comparing elements a second - // time. - panic!(); - } - - a.comp_count.replace(a.comp_count.get() + 1); - b.comp_count.replace(b.comp_count.get() + 1); - comp_count_global += 1; - - a.val.cmp(&b.val) - }); - })); - - assert!(res.is_err()); - - let total_inner: u64 = test_input.iter().map(|c| c.comp_count.get() as u64).sum(); - - assert_eq!(total_inner, comp_count_global * 2); - - // If the sum before and after don't match, it means the set of elements hasn't remained the - // same. - let sum_after: i64 = test_input.iter().map(|x| x.val as i64).sum(); - assert_eq!(sum_before, sum_after); -} - -gen_sort_test_fns_with_default_patterns!( - panic_observable_is_less, - panic_observable_is_less::, - &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], - [] -); - -fn deterministic( - len: usize, - type_into_fn: impl Fn(i32) -> T + Copy, - type_from_fn: impl Fn(&T) -> i32, - pattern_fn: fn(usize) -> Vec, -) { - // A property similar to stability is deterministic output order. If the entire value is used as - // the comparison key a lack of determinism has no effect. But if only a part of the value is - // used as comparison key, a lack of determinism can manifest itself in the order of values - // considered equal by the comparison predicate. - // - // This test only tests that results are deterministic across runs, it does not test determinism - // on different platforms and with different toolchains. - - let mut test_input = - pattern_fn(len).into_iter().map(|val| type_into_fn(val)).collect::>(); - - let mut test_input_clone = test_input.clone(); - - let comparison_fn = |a: &T, b: &T| { - let a_i32 = type_from_fn(a); - let b_i32 = type_from_fn(b); - - let a_i32_key_space_reduced = a_i32 % 10_000; - let b_i32_key_space_reduced = b_i32 % 10_000; - - a_i32_key_space_reduced.cmp(&b_i32_key_space_reduced) - }; - - ::sort_by(&mut test_input, comparison_fn); - ::sort_by(&mut test_input_clone, comparison_fn); - - assert_eq!(test_input, test_input_clone); -} - -gen_sort_test_fns_with_default_patterns_3_ty!(deterministic, deterministic, []); - -fn self_cmp( - len: usize, - type_into_fn: impl Fn(i32) -> T + Copy, - _type_from_fn: impl Fn(&T) -> i32, - pattern_fn: fn(usize) -> Vec, -) { - // It's possible for comparisons to run into problems if the values of `a` and `b` passed into - // the comparison function are the same reference. So this tests that they never are. - - let mut test_input = - pattern_fn(len).into_iter().map(|val| type_into_fn(val)).collect::>(); - - let comparison_fn = |a: &T, b: &T| { - assert_ne!(a as *const T as usize, b as *const T as usize); - a.cmp(b) - }; - - ::sort_by(&mut test_input, comparison_fn); - - // Check that the output is actually sorted and wasn't stopped by the assert. - for window in test_input.windows(2) { - assert!(window[0] <= window[1]); - } -} - -gen_sort_test_fns_with_default_patterns_3_ty!(self_cmp, self_cmp, []); - -fn violate_ord_retain_orig_set( - len: usize, - type_into_fn: impl Fn(i32) -> T + Copy, - type_from_fn: impl Fn(&T) -> i32, - pattern_fn: fn(usize) -> Vec, -) { - // A user may implement Ord incorrectly for a type or violate it by calling sort_by with a - // comparison function that violates Ord with the orderings it returns. Even under such - // circumstances the input must retain its original set of elements. - - // Ord implies a strict total order see https://en.wikipedia.org/wiki/Total_order. - - // Generating random numbers with miri is quite expensive. - let random_orderings_len = if cfg!(miri) { 200 } else { 10_000 }; - - // Make sure we get a good distribution of random orderings, that are repeatable with the seed. - // Just using random_uniform with the same len and range will always yield the same value. - let random_orderings = patterns::random_uniform(random_orderings_len, 0..2); - - let get_random_0_1_or_2 = |random_idx: &mut usize| { - let ridx = *random_idx; - *random_idx += 1; - if ridx + 1 == random_orderings.len() { - *random_idx = 0; - } - - random_orderings[ridx] as usize - }; - - let mut random_idx_a = 0; - let mut random_idx_b = 0; - let mut random_idx_c = 0; - - let mut last_element_a = -1; - let mut last_element_b = -1; - - let mut rand_counter_b = 0; - let mut rand_counter_c = 0; - - let mut streak_counter_a = 0; - let mut streak_counter_b = 0; - - // Examples, a = 3, b = 5, c = 9. - // Correct Ord -> 10010 | is_less(a, b) is_less(a, a) is_less(b, a) is_less(a, c) is_less(c, a) - let mut invalid_ord_comp_functions: Vec Ordering>> = vec![ - Box::new(|_a, _b| -> Ordering { - // random - // Eg. is_less(3, 5) == true, is_less(3, 5) == false - - let idx = get_random_0_1_or_2(&mut random_idx_a); - [Ordering::Less, Ordering::Equal, Ordering::Greater][idx] - }), - Box::new(|_a, _b| -> Ordering { - // everything is less -> 11111 - Ordering::Less - }), - Box::new(|_a, _b| -> Ordering { - // everything is equal -> 00000 - Ordering::Equal - }), - Box::new(|_a, _b| -> Ordering { - // everything is greater -> 00000 - // Eg. is_less(3, 5) == false, is_less(5, 3) == false, is_less(3, 3) == false - Ordering::Greater - }), - Box::new(|a, b| -> Ordering { - // equal means less else greater -> 01000 - if a == b { Ordering::Less } else { Ordering::Greater } - }), - Box::new(|a, b| -> Ordering { - // Transitive breaker. remember last element -> 10001 - let lea = last_element_a; - let leb = last_element_b; - - let a_as_i32 = type_from_fn(a); - let b_as_i32 = type_from_fn(b); - - last_element_a = a_as_i32; - last_element_b = b_as_i32; - - if a_as_i32 == lea && b_as_i32 != leb { b.cmp(a) } else { a.cmp(b) } - }), - Box::new(|a, b| -> Ordering { - // Sampled random 1% of comparisons are reversed. - rand_counter_b += get_random_0_1_or_2(&mut random_idx_b); - if rand_counter_b >= 100 { - rand_counter_b = 0; - b.cmp(a) - } else { - a.cmp(b) - } - }), - Box::new(|a, b| -> Ordering { - // Sampled random 33% of comparisons are reversed. - rand_counter_c += get_random_0_1_or_2(&mut random_idx_c); - if rand_counter_c >= 3 { - rand_counter_c = 0; - b.cmp(a) - } else { - a.cmp(b) - } - }), - Box::new(|a, b| -> Ordering { - // STREAK_LEN comparisons yield a.cmp(b) then STREAK_LEN comparisons less. This can - // discover bugs that neither, random Ord, or just Less or Greater can find. Because it - // can push a pointer further than expected. Random Ord will average out how far a - // comparison based pointer travels. Just Less or Greater will be caught by pattern - // analysis and never enter interesting code. - const STREAK_LEN: usize = 50; - - streak_counter_a += 1; - if streak_counter_a <= STREAK_LEN { - a.cmp(b) - } else { - if streak_counter_a == STREAK_LEN * 2 { - streak_counter_a = 0; - } - Ordering::Less - } - }), - Box::new(|a, b| -> Ordering { - // See above. - const STREAK_LEN: usize = 50; - - streak_counter_b += 1; - if streak_counter_b <= STREAK_LEN { - a.cmp(b) - } else { - if streak_counter_b == STREAK_LEN * 2 { - streak_counter_b = 0; - } - Ordering::Greater - } - }), - ]; - - for comp_func in &mut invalid_ord_comp_functions { - let mut test_data: Vec = pattern_fn(len).into_iter().map(type_into_fn).collect(); - let sum_before: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); - - // It's ok to panic on Ord violation or to complete. - // In both cases the original elements must still be present. - let _ = panic::catch_unwind(AssertUnwindSafe(|| { - ::sort_by(&mut test_data, &mut *comp_func); - })); - - // If the sum before and after don't match, it means the set of elements hasn't remained the - // same. - let sum_after: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); - assert_eq!(sum_before, sum_after); - - if cfg!(miri) { - // This test is prohibitively expensive in miri, so only run one of the comparison - // functions. This test is not expected to yield direct UB, but rather surface potential - // UB by showing that the sum is different now. - break; - } - } -} - -gen_sort_test_fns_with_default_patterns_3_ty!( - violate_ord_retain_orig_set, - violate_ord_retain_orig_set, - [] -); - -macro_rules! instantiate_sort_test_inner { - ($sort_impl:ty, miri_yes, $test_fn_name:ident) => { - #[test] - fn $test_fn_name() { - $crate::sort::tests::$test_fn_name::<$sort_impl>(); - } - }; - ($sort_impl:ty, miri_no, $test_fn_name:ident) => { - #[test] - #[cfg_attr(miri, ignore)] - fn $test_fn_name() { - $crate::sort::tests::$test_fn_name::<$sort_impl>(); - } - }; -} - -// Using this construct allows us to get warnings for unused test functions. -macro_rules! define_instantiate_sort_tests { - ($([$miri_use:ident, $test_fn_name:ident]),*,) => { - $(pub fn $test_fn_name() { - ${concat($test_fn_name, _impl)}::(); - })* - - - macro_rules! instantiate_sort_tests_gen { - ($sort_impl:ty) => { - $( - instantiate_sort_test_inner!( - $sort_impl, - $miri_use, - $test_fn_name - ); - )* - } - } - }; -} - -// Some tests are not tested with miri to avoid prohibitively long test times. This leaves coverage -// holes, but the way they are selected should make for relatively small holes. Many properties that -// can lead to UB are tested directly, for example that the original set of elements is retained -// even when a panic occurs or Ord is implemented incorrectly. -define_instantiate_sort_tests!( - [miri_yes, basic], - [miri_yes, fixed_seed], - [miri_yes, fixed_seed_rand_vec_prefix], - [miri_yes, int_edge], - [miri_yes, sort_vs_sort_by], - [miri_yes, correct_i32_random], - [miri_yes, correct_i32_random_z1], - [miri_yes, correct_i32_random_d2], - [miri_yes, correct_i32_random_d20], - [miri_yes, correct_i32_random_s95], - [miri_yes, correct_i32_ascending], - [miri_yes, correct_i32_descending], - [miri_yes, correct_i32_saw_mixed], - [miri_no, correct_i32_random_d4], - [miri_no, correct_i32_random_d8], - [miri_no, correct_i32_random_d311], - [miri_no, correct_i32_random_d1024], - [miri_no, correct_i32_random_z1_03], - [miri_no, correct_i32_random_z2], - [miri_no, correct_i32_random_s50], - [miri_no, correct_i32_narrow], - [miri_no, correct_i32_all_equal], - [miri_no, correct_i32_saw_mixed_range], - [miri_yes, correct_i32_pipe_organ], - [miri_no, correct_u64_random], - [miri_yes, correct_u64_random_z1], - [miri_no, correct_u64_random_d2], - [miri_no, correct_u64_random_d20], - [miri_no, correct_u64_random_s95], - [miri_no, correct_u64_ascending], - [miri_no, correct_u64_descending], - [miri_no, correct_u64_saw_mixed], - [miri_no, correct_u128_random], - [miri_yes, correct_u128_random_z1], - [miri_no, correct_u128_random_d2], - [miri_no, correct_u128_random_d20], - [miri_no, correct_u128_random_s95], - [miri_no, correct_u128_ascending], - [miri_no, correct_u128_descending], - [miri_no, correct_u128_saw_mixed], - [miri_no, correct_cell_i32_random], - [miri_yes, correct_cell_i32_random_z1], - [miri_no, correct_cell_i32_random_d2], - [miri_no, correct_cell_i32_random_d20], - [miri_no, correct_cell_i32_random_s95], - [miri_no, correct_cell_i32_ascending], - [miri_no, correct_cell_i32_descending], - [miri_no, correct_cell_i32_saw_mixed], - [miri_no, correct_string_random], - [miri_yes, correct_string_random_z1], - [miri_no, correct_string_random_d2], - [miri_no, correct_string_random_d20], - [miri_no, correct_string_random_s95], - [miri_no, correct_string_ascending], - [miri_no, correct_string_descending], - [miri_no, correct_string_saw_mixed], - [miri_no, correct_f128_random], - [miri_yes, correct_f128_random_z1], - [miri_no, correct_f128_random_d2], - [miri_no, correct_f128_random_d20], - [miri_no, correct_f128_random_s95], - [miri_no, correct_f128_ascending], - [miri_no, correct_f128_descending], - [miri_no, correct_f128_saw_mixed], - [miri_no, correct_1k_random], - [miri_yes, correct_1k_random_z1], - [miri_no, correct_1k_random_d2], - [miri_no, correct_1k_random_d20], - [miri_no, correct_1k_random_s95], - [miri_no, correct_1k_ascending], - [miri_no, correct_1k_descending], - [miri_no, correct_1k_saw_mixed], - [miri_no, correct_dyn_val_random], - [miri_yes, correct_dyn_val_random_z1], - [miri_no, correct_dyn_val_random_d2], - [miri_no, correct_dyn_val_random_d20], - [miri_no, correct_dyn_val_random_s95], - [miri_no, correct_dyn_val_ascending], - [miri_no, correct_dyn_val_descending], - [miri_no, correct_dyn_val_saw_mixed], - [miri_no, stability_legacy], - [miri_no, stability_i32_random], - [miri_yes, stability_i32_random_z1], - [miri_no, stability_i32_random_d2], - [miri_no, stability_i32_random_d20], - [miri_no, stability_i32_random_s95], - [miri_no, stability_i32_ascending], - [miri_no, stability_i32_descending], - [miri_no, stability_i32_saw_mixed], - [miri_no, stability_cell_i32_random], - [miri_yes, stability_cell_i32_random_z1], - [miri_no, stability_cell_i32_random_d2], - [miri_no, stability_cell_i32_random_d20], - [miri_no, stability_cell_i32_random_s95], - [miri_no, stability_cell_i32_ascending], - [miri_no, stability_cell_i32_descending], - [miri_no, stability_cell_i32_saw_mixed], - [miri_no, stability_string_random], - [miri_yes, stability_string_random_z1], - [miri_no, stability_string_random_d2], - [miri_no, stability_string_random_d20], - [miri_no, stability_string_random_s95], - [miri_no, stability_string_ascending], - [miri_no, stability_string_descending], - [miri_no, stability_string_saw_mixed], - [miri_no, observable_is_less_random], - [miri_yes, observable_is_less_random_z1], - [miri_no, observable_is_less_random_d2], - [miri_no, observable_is_less_random_d20], - [miri_no, observable_is_less_random_s95], - [miri_no, observable_is_less_ascending], - [miri_no, observable_is_less_descending], - [miri_no, observable_is_less_saw_mixed], - [miri_no, panic_retain_orig_set_i32_random], - [miri_yes, panic_retain_orig_set_i32_random_z1], - [miri_no, panic_retain_orig_set_i32_random_d2], - [miri_no, panic_retain_orig_set_i32_random_d20], - [miri_no, panic_retain_orig_set_i32_random_s95], - [miri_no, panic_retain_orig_set_i32_ascending], - [miri_no, panic_retain_orig_set_i32_descending], - [miri_no, panic_retain_orig_set_i32_saw_mixed], - [miri_no, panic_retain_orig_set_cell_i32_random], - [miri_yes, panic_retain_orig_set_cell_i32_random_z1], - [miri_no, panic_retain_orig_set_cell_i32_random_d2], - [miri_no, panic_retain_orig_set_cell_i32_random_d20], - [miri_no, panic_retain_orig_set_cell_i32_random_s95], - [miri_no, panic_retain_orig_set_cell_i32_ascending], - [miri_no, panic_retain_orig_set_cell_i32_descending], - [miri_no, panic_retain_orig_set_cell_i32_saw_mixed], - [miri_no, panic_retain_orig_set_string_random], - [miri_yes, panic_retain_orig_set_string_random_z1], - [miri_no, panic_retain_orig_set_string_random_d2], - [miri_no, panic_retain_orig_set_string_random_d20], - [miri_no, panic_retain_orig_set_string_random_s95], - [miri_no, panic_retain_orig_set_string_ascending], - [miri_no, panic_retain_orig_set_string_descending], - [miri_no, panic_retain_orig_set_string_saw_mixed], - [miri_no, panic_observable_is_less_random], - [miri_yes, panic_observable_is_less_random_z1], - [miri_no, panic_observable_is_less_random_d2], - [miri_no, panic_observable_is_less_random_d20], - [miri_no, panic_observable_is_less_random_s95], - [miri_no, panic_observable_is_less_ascending], - [miri_no, panic_observable_is_less_descending], - [miri_no, panic_observable_is_less_saw_mixed], - [miri_no, deterministic_i32_random], - [miri_yes, deterministic_i32_random_z1], - [miri_no, deterministic_i32_random_d2], - [miri_no, deterministic_i32_random_d20], - [miri_no, deterministic_i32_random_s95], - [miri_no, deterministic_i32_ascending], - [miri_no, deterministic_i32_descending], - [miri_no, deterministic_i32_saw_mixed], - [miri_no, deterministic_cell_i32_random], - [miri_yes, deterministic_cell_i32_random_z1], - [miri_no, deterministic_cell_i32_random_d2], - [miri_no, deterministic_cell_i32_random_d20], - [miri_no, deterministic_cell_i32_random_s95], - [miri_no, deterministic_cell_i32_ascending], - [miri_no, deterministic_cell_i32_descending], - [miri_no, deterministic_cell_i32_saw_mixed], - [miri_no, deterministic_string_random], - [miri_yes, deterministic_string_random_z1], - [miri_no, deterministic_string_random_d2], - [miri_no, deterministic_string_random_d20], - [miri_no, deterministic_string_random_s95], - [miri_no, deterministic_string_ascending], - [miri_no, deterministic_string_descending], - [miri_no, deterministic_string_saw_mixed], - [miri_no, self_cmp_i32_random], - [miri_yes, self_cmp_i32_random_z1], - [miri_no, self_cmp_i32_random_d2], - [miri_no, self_cmp_i32_random_d20], - [miri_no, self_cmp_i32_random_s95], - [miri_no, self_cmp_i32_ascending], - [miri_no, self_cmp_i32_descending], - [miri_no, self_cmp_i32_saw_mixed], - [miri_no, self_cmp_cell_i32_random], - [miri_yes, self_cmp_cell_i32_random_z1], - [miri_no, self_cmp_cell_i32_random_d2], - [miri_no, self_cmp_cell_i32_random_d20], - [miri_no, self_cmp_cell_i32_random_s95], - [miri_no, self_cmp_cell_i32_ascending], - [miri_no, self_cmp_cell_i32_descending], - [miri_no, self_cmp_cell_i32_saw_mixed], - [miri_no, self_cmp_string_random], - [miri_yes, self_cmp_string_random_z1], - [miri_no, self_cmp_string_random_d2], - [miri_no, self_cmp_string_random_d20], - [miri_no, self_cmp_string_random_s95], - [miri_no, self_cmp_string_ascending], - [miri_no, self_cmp_string_descending], - [miri_no, self_cmp_string_saw_mixed], - [miri_no, violate_ord_retain_orig_set_i32_random], - [miri_yes, violate_ord_retain_orig_set_i32_random_z1], - [miri_no, violate_ord_retain_orig_set_i32_random_d2], - [miri_no, violate_ord_retain_orig_set_i32_random_d20], - [miri_no, violate_ord_retain_orig_set_i32_random_s95], - [miri_no, violate_ord_retain_orig_set_i32_ascending], - [miri_no, violate_ord_retain_orig_set_i32_descending], - [miri_no, violate_ord_retain_orig_set_i32_saw_mixed], - [miri_no, violate_ord_retain_orig_set_cell_i32_random], - [miri_yes, violate_ord_retain_orig_set_cell_i32_random_z1], - [miri_no, violate_ord_retain_orig_set_cell_i32_random_d2], - [miri_no, violate_ord_retain_orig_set_cell_i32_random_d20], - [miri_no, violate_ord_retain_orig_set_cell_i32_random_s95], - [miri_no, violate_ord_retain_orig_set_cell_i32_ascending], - [miri_no, violate_ord_retain_orig_set_cell_i32_descending], - [miri_no, violate_ord_retain_orig_set_cell_i32_saw_mixed], - [miri_no, violate_ord_retain_orig_set_string_random], - [miri_yes, violate_ord_retain_orig_set_string_random_z1], - [miri_no, violate_ord_retain_orig_set_string_random_d2], - [miri_no, violate_ord_retain_orig_set_string_random_d20], - [miri_no, violate_ord_retain_orig_set_string_random_s95], - [miri_no, violate_ord_retain_orig_set_string_ascending], - [miri_no, violate_ord_retain_orig_set_string_descending], - [miri_no, violate_ord_retain_orig_set_string_saw_mixed], -); - -macro_rules! instantiate_sort_tests { - ($sort_impl:ty) => { - instantiate_sort_tests_gen!($sort_impl); - }; -} - -mod unstable { - struct SortImpl {} - - impl crate::sort::Sort for SortImpl { - fn name() -> String { - "rust_std_unstable".into() - } - - fn sort(v: &mut [T]) - where - T: Ord, - { - v.sort_unstable(); - } - - fn sort_by(v: &mut [T], mut compare: F) - where - F: FnMut(&T, &T) -> std::cmp::Ordering, - { - v.sort_unstable_by(|a, b| compare(a, b)); - } - } - - instantiate_sort_tests!(SortImpl); -} - -mod stable { - struct SortImpl {} - - impl crate::sort::Sort for SortImpl { - fn name() -> String { - "rust_std_stable".into() - } - - fn sort(v: &mut [T]) - where - T: Ord, - { - v.sort(); - } - - fn sort_by(v: &mut [T], mut compare: F) - where - F: FnMut(&T, &T) -> std::cmp::Ordering, - { - v.sort_by(|a, b| compare(a, b)); - } - } - - instantiate_sort_tests!(SortImpl); -} diff --git a/library/alloc/tests/sort/zipf.rs b/library/alloc/tests/sort/zipf.rs deleted file mode 100644 index 3dad2db521f..00000000000 --- a/library/alloc/tests/sort/zipf.rs +++ /dev/null @@ -1,208 +0,0 @@ -// This module implements a Zipfian distribution generator. -// -// Based on https://github.com/jonhoo/rust-zipf. - -use rand::Rng; - -/// Random number generator that generates Zipf-distributed random numbers using rejection -/// inversion. -#[derive(Clone, Copy)] -pub struct ZipfDistribution { - /// Number of elements - num_elements: f64, - /// Exponent parameter of the distribution - exponent: f64, - /// `hIntegral(1.5) - 1}` - h_integral_x1: f64, - /// `hIntegral(num_elements + 0.5)}` - h_integral_num_elements: f64, - /// `2 - hIntegralInverse(hIntegral(2.5) - h(2)}` - s: f64, -} - -impl ZipfDistribution { - /// Creates a new [Zipf-distributed](https://en.wikipedia.org/wiki/Zipf's_law) - /// random number generator. - /// - /// Note that both the number of elements and the exponent must be greater than 0. - pub fn new(num_elements: usize, exponent: f64) -> Result { - if num_elements == 0 { - return Err(()); - } - if exponent <= 0f64 { - return Err(()); - } - - let z = ZipfDistribution { - num_elements: num_elements as f64, - exponent, - h_integral_x1: ZipfDistribution::h_integral(1.5, exponent) - 1f64, - h_integral_num_elements: ZipfDistribution::h_integral( - num_elements as f64 + 0.5, - exponent, - ), - s: 2f64 - - ZipfDistribution::h_integral_inv( - ZipfDistribution::h_integral(2.5, exponent) - - ZipfDistribution::h(2f64, exponent), - exponent, - ), - }; - - // populate cache - - Ok(z) - } -} - -impl ZipfDistribution { - fn next(&self, rng: &mut R) -> usize { - // The paper describes an algorithm for exponents larger than 1 (Algorithm ZRI). - // - // The original method uses - // H(x) = (v + x)^(1 - q) / (1 - q) - // as the integral of the hat function. - // - // This function is undefined for q = 1, which is the reason for the limitation of the - // exponent. - // - // If instead the integral function - // H(x) = ((v + x)^(1 - q) - 1) / (1 - q) - // is used, for which a meaningful limit exists for q = 1, the method works for all - // positive exponents. - // - // The following implementation uses v = 0 and generates integral number in the range [1, - // num_elements]. This is different to the original method where v is defined to - // be positive and numbers are taken from [0, i_max]. This explains why the implementation - // looks slightly different. - - let hnum = self.h_integral_num_elements; - - loop { - use std::cmp; - let u: f64 = hnum + rng.random::() * (self.h_integral_x1 - hnum); - // u is uniformly distributed in (h_integral_x1, h_integral_num_elements] - - let x: f64 = ZipfDistribution::h_integral_inv(u, self.exponent); - - // Limit k to the range [1, num_elements] if it would be outside - // due to numerical inaccuracies. - let k64 = x.max(1.0).min(self.num_elements); - // float -> integer rounds towards zero, so we add 0.5 - // to prevent bias towards k == 1 - let k = cmp::max(1, (k64 + 0.5) as usize); - - // Here, the distribution of k is given by: - // - // P(k = 1) = C * (hIntegral(1.5) - h_integral_x1) = C - // P(k = m) = C * (hIntegral(m + 1/2) - hIntegral(m - 1/2)) for m >= 2 - // - // where C = 1 / (h_integral_num_elements - h_integral_x1) - if k64 - x <= self.s - || u >= ZipfDistribution::h_integral(k64 + 0.5, self.exponent) - - ZipfDistribution::h(k64, self.exponent) - { - // Case k = 1: - // - // The right inequality is always true, because replacing k by 1 gives - // u >= hIntegral(1.5) - h(1) = h_integral_x1 and u is taken from - // (h_integral_x1, h_integral_num_elements]. - // - // Therefore, the acceptance rate for k = 1 is P(accepted | k = 1) = 1 - // and the probability that 1 is returned as random value is - // P(k = 1 and accepted) = P(accepted | k = 1) * P(k = 1) = C = C / 1^exponent - // - // Case k >= 2: - // - // The left inequality (k - x <= s) is just a short cut - // to avoid the more expensive evaluation of the right inequality - // (u >= hIntegral(k + 0.5) - h(k)) in many cases. - // - // If the left inequality is true, the right inequality is also true: - // Theorem 2 in the paper is valid for all positive exponents, because - // the requirements h'(x) = -exponent/x^(exponent + 1) < 0 and - // (-1/hInverse'(x))'' = (1+1/exponent) * x^(1/exponent-1) >= 0 - // are both fulfilled. - // Therefore, f(x) = x - hIntegralInverse(hIntegral(x + 0.5) - h(x)) - // is a non-decreasing function. If k - x <= s holds, - // k - x <= s + f(k) - f(2) is obviously also true which is equivalent to - // -x <= -hIntegralInverse(hIntegral(k + 0.5) - h(k)), - // -hIntegralInverse(u) <= -hIntegralInverse(hIntegral(k + 0.5) - h(k)), - // and finally u >= hIntegral(k + 0.5) - h(k). - // - // Hence, the right inequality determines the acceptance rate: - // P(accepted | k = m) = h(m) / (hIntegrated(m+1/2) - hIntegrated(m-1/2)) - // The probability that m is returned is given by - // P(k = m and accepted) = P(accepted | k = m) * P(k = m) - // = C * h(m) = C / m^exponent. - // - // In both cases the probabilities are proportional to the probability mass - // function of the Zipf distribution. - - return k; - } - } - } -} - -impl rand::distr::Distribution for ZipfDistribution { - fn sample(&self, rng: &mut R) -> usize { - self.next(rng) - } -} - -use std::fmt; -impl fmt::Debug for ZipfDistribution { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.debug_struct("ZipfDistribution") - .field("e", &self.exponent) - .field("n", &self.num_elements) - .finish() - } -} - -impl ZipfDistribution { - /// Computes `H(x)`, defined as - /// - /// - `(x^(1 - exponent) - 1) / (1 - exponent)`, if `exponent != 1` - /// - `log(x)`, if `exponent == 1` - /// - /// `H(x)` is an integral function of `h(x)`, the derivative of `H(x)` is `h(x)`. - fn h_integral(x: f64, exponent: f64) -> f64 { - let log_x = x.ln(); - helper2((1f64 - exponent) * log_x) * log_x - } - - /// Computes `h(x) = 1 / x^exponent` - fn h(x: f64, exponent: f64) -> f64 { - (-exponent * x.ln()).exp() - } - - /// The inverse function of `H(x)`. - /// Returns the `y` for which `H(y) = x`. - fn h_integral_inv(x: f64, exponent: f64) -> f64 { - let mut t: f64 = x * (1f64 - exponent); - if t < -1f64 { - // Limit value to the range [-1, +inf). - // t could be smaller than -1 in some rare cases due to numerical errors. - t = -1f64; - } - (helper1(t) * x).exp() - } -} - -/// Helper function that calculates `log(1 + x) / x`. -/// A Taylor series expansion is used, if x is close to 0. -fn helper1(x: f64) -> f64 { - if x.abs() > 1e-8 { x.ln_1p() / x } else { 1f64 - x * (0.5 - x * (1.0 / 3.0 - 0.25 * x)) } -} - -/// Helper function to calculate `(exp(x) - 1) / x`. -/// A Taylor series expansion is used, if x is close to 0. -fn helper2(x: f64) -> f64 { - if x.abs() > 1e-8 { - x.exp_m1() / x - } else { - 1f64 + x * 0.5 * (1f64 + x * 1.0 / 3.0 * (1f64 + 0.25 * x)) - } -} diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs deleted file mode 100644 index 906fa2d425e..00000000000 --- a/library/alloc/tests/str.rs +++ /dev/null @@ -1,2461 +0,0 @@ -#![allow(invalid_from_utf8)] - -use std::assert_matches::assert_matches; -use std::borrow::Cow; -use std::char::MAX_LEN_UTF8; -use std::cmp::Ordering::{Equal, Greater, Less}; -use std::str::{from_utf8, from_utf8_unchecked}; - -#[test] -fn test_le() { - assert!("" <= ""); - assert!("" <= "foo"); - assert!("foo" <= "foo"); - assert_ne!("foo", "bar"); -} - -#[test] -fn test_find() { - assert_eq!("hello".find('l'), Some(2)); - assert_eq!("hello".find(|c: char| c == 'o'), Some(4)); - assert!("hello".find('x').is_none()); - assert!("hello".find(|c: char| c == 'x').is_none()); - assert_eq!("ประเทศไทย中华Việt Nam".find('华'), Some(30)); - assert_eq!("ประเทศไทย中华Việt Nam".find(|c: char| c == '华'), Some(30)); -} - -#[test] -fn test_rfind() { - assert_eq!("hello".rfind('l'), Some(3)); - assert_eq!("hello".rfind(|c: char| c == 'o'), Some(4)); - assert!("hello".rfind('x').is_none()); - assert!("hello".rfind(|c: char| c == 'x').is_none()); - assert_eq!("ประเทศไทย中华Việt Nam".rfind('华'), Some(30)); - assert_eq!("ประเทศไทย中华Việt Nam".rfind(|c: char| c == '华'), Some(30)); -} - -#[test] -fn test_collect() { - let empty = ""; - let s: String = empty.chars().collect(); - assert_eq!(empty, s); - let data = "ประเทศไทย中"; - let s: String = data.chars().collect(); - assert_eq!(data, s); -} - -#[test] -fn test_into_bytes() { - let data = String::from("asdf"); - let buf = data.into_bytes(); - assert_eq!(buf, b"asdf"); -} - -#[test] -fn test_find_str() { - // byte positions - assert_eq!("".find(""), Some(0)); - assert!("banana".find("apple pie").is_none()); - - let data = "abcabc"; - assert_eq!(data[0..6].find("ab"), Some(0)); - assert_eq!(data[2..6].find("ab"), Some(3 - 2)); - assert!(data[2..4].find("ab").is_none()); - - let string = "ประเทศไทย中华Việt Nam"; - let mut data = String::from(string); - data.push_str(string); - assert!(data.find("ไท华").is_none()); - assert_eq!(data[0..43].find(""), Some(0)); - assert_eq!(data[6..43].find(""), Some(6 - 6)); - - assert_eq!(data[0..43].find("ประ"), Some(0)); - assert_eq!(data[0..43].find("ทศไ"), Some(12)); - assert_eq!(data[0..43].find("ย中"), Some(24)); - assert_eq!(data[0..43].find("iệt"), Some(34)); - assert_eq!(data[0..43].find("Nam"), Some(40)); - - assert_eq!(data[43..86].find("ประ"), Some(43 - 43)); - assert_eq!(data[43..86].find("ทศไ"), Some(55 - 43)); - assert_eq!(data[43..86].find("ย中"), Some(67 - 43)); - assert_eq!(data[43..86].find("iệt"), Some(77 - 43)); - assert_eq!(data[43..86].find("Nam"), Some(83 - 43)); - - // find every substring -- assert that it finds it, or an earlier occurrence. - let string = "Việt Namacbaabcaabaaba"; - for (i, ci) in string.char_indices() { - let ip = i + ci.len_utf8(); - for j in string[ip..].char_indices().map(|(i, _)| i).chain(Some(string.len() - ip)) { - let pat = &string[i..ip + j]; - assert!(match string.find(pat) { - None => false, - Some(x) => x <= i, - }); - assert!(match string.rfind(pat) { - None => false, - Some(x) => x >= i, - }); - } - } -} - -fn s(x: &str) -> String { - x.to_string() -} - -macro_rules! test_concat { - ($expected: expr, $string: expr) => {{ - let s: String = $string.concat(); - assert_eq!($expected, s); - }}; -} - -#[test] -fn test_concat_for_different_types() { - test_concat!("ab", vec![s("a"), s("b")]); - test_concat!("ab", vec!["a", "b"]); -} - -#[test] -fn test_concat_for_different_lengths() { - let empty: &[&str] = &[]; - test_concat!("", empty); - test_concat!("a", ["a"]); - test_concat!("ab", ["a", "b"]); - test_concat!("abc", ["", "a", "bc"]); -} - -macro_rules! test_join { - ($expected: expr, $string: expr, $delim: expr) => {{ - let s = $string.join($delim); - assert_eq!($expected, s); - }}; -} - -#[test] -fn test_join_for_different_types() { - test_join!("a-b", ["a", "b"], "-"); - let hyphen = "-".to_string(); - test_join!("a-b", [s("a"), s("b")], &*hyphen); - test_join!("a-b", vec!["a", "b"], &*hyphen); - test_join!("a-b", &*vec!["a", "b"], "-"); - test_join!("a-b", vec![s("a"), s("b")], "-"); -} - -#[test] -fn test_join_for_different_lengths() { - let empty: &[&str] = &[]; - test_join!("", empty, "-"); - test_join!("a", ["a"], "-"); - test_join!("a-b", ["a", "b"], "-"); - test_join!("-a-bc", ["", "a", "bc"], "-"); -} - -// join has fast paths for small separators up to 4 bytes -// this tests the slow paths. -#[test] -fn test_join_for_different_lengths_with_long_separator() { - assert_eq!("~~~~~".len(), 15); - - let empty: &[&str] = &[]; - test_join!("", empty, "~~~~~"); - test_join!("a", ["a"], "~~~~~"); - test_join!("a~~~~~b", ["a", "b"], "~~~~~"); - test_join!("~~~~~a~~~~~bc", ["", "a", "bc"], "~~~~~"); -} - -#[test] -fn test_join_issue_80335() { - use core::borrow::Borrow; - use core::cell::Cell; - - struct WeirdBorrow { - state: Cell, - } - - impl Default for WeirdBorrow { - fn default() -> Self { - WeirdBorrow { state: Cell::new(false) } - } - } - - impl Borrow for WeirdBorrow { - fn borrow(&self) -> &str { - let state = self.state.get(); - if state { - "0" - } else { - self.state.set(true); - "123456" - } - } - } - - let arr: [WeirdBorrow; 3] = Default::default(); - test_join!("0-0-0", arr, "-"); -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri is too slow -fn test_unsafe_slice() { - assert_eq!("ab", unsafe { "abc".get_unchecked(0..2) }); - assert_eq!("bc", unsafe { "abc".get_unchecked(1..3) }); - assert_eq!("", unsafe { "abc".get_unchecked(1..1) }); - fn a_million_letter_a() -> String { - let mut i = 0; - let mut rs = String::new(); - while i < 100000 { - rs.push_str("aaaaaaaaaa"); - i += 1; - } - rs - } - fn half_a_million_letter_a() -> String { - let mut i = 0; - let mut rs = String::new(); - while i < 100000 { - rs.push_str("aaaaa"); - i += 1; - } - rs - } - let letters = a_million_letter_a(); - assert_eq!(half_a_million_letter_a(), unsafe { letters.get_unchecked(0..500000) }); -} - -#[test] -fn test_starts_with() { - assert!("".starts_with("")); - assert!("abc".starts_with("")); - assert!("abc".starts_with("a")); - assert!(!"a".starts_with("abc")); - assert!(!"".starts_with("abc")); - assert!(!"ödd".starts_with("-")); - assert!("ödd".starts_with("öd")); -} - -#[test] -fn test_ends_with() { - assert!("".ends_with("")); - assert!("abc".ends_with("")); - assert!("abc".ends_with("c")); - assert!(!"a".ends_with("abc")); - assert!(!"".ends_with("abc")); - assert!(!"ddö".ends_with("-")); - assert!("ddö".ends_with("dö")); -} - -#[test] -fn test_is_empty() { - assert!("".is_empty()); - assert!(!"a".is_empty()); -} - -#[test] -fn test_replacen() { - assert_eq!("".replacen('a', "b", 5), ""); - assert_eq!("acaaa".replacen("a", "b", 3), "bcbba"); - assert_eq!("aaaa".replacen("a", "b", 0), "aaaa"); - - let test = "test"; - assert_eq!(" test test ".replacen(test, "toast", 3), " toast toast "); - assert_eq!(" test test ".replacen(test, "toast", 0), " test test "); - assert_eq!(" test test ".replacen(test, "", 5), " "); - - assert_eq!("qwer123zxc789".replacen(char::is_numeric, "", 3), "qwerzxc789"); -} - -#[test] -fn test_replace() { - let a = "a"; - assert_eq!("".replace(a, "b"), ""); - assert_eq!("a".replace(a, "b"), "b"); - assert_eq!("ab".replace(a, "b"), "bb"); - let test = "test"; - assert_eq!(" test test ".replace(test, "toast"), " toast toast "); - assert_eq!(" test test ".replace(test, ""), " "); -} - -#[test] -fn test_replace_2a() { - let data = "ประเทศไทย中华"; - let repl = "دولة الكويت"; - - let a = "ประเ"; - let a2 = "دولة الكويتทศไทย中华"; - assert_eq!(data.replace(a, repl), a2); -} - -#[test] -fn test_replace_2b() { - let data = "ประเทศไทย中华"; - let repl = "دولة الكويت"; - - let b = "ะเ"; - let b2 = "ปรدولة الكويتทศไทย中华"; - assert_eq!(data.replace(b, repl), b2); -} - -#[test] -fn test_replace_2c() { - let data = "ประเทศไทย中华"; - let repl = "دولة الكويت"; - - let c = "中华"; - let c2 = "ประเทศไทยدولة الكويت"; - assert_eq!(data.replace(c, repl), c2); -} - -#[test] -fn test_replace_2d() { - let data = "ประเทศไทย中华"; - let repl = "دولة الكويت"; - - let d = "ไท华"; - assert_eq!(data.replace(d, repl), data); -} - -#[test] -fn test_replace_pattern() { - let data = "abcdαβγδabcdαβγδ"; - assert_eq!(data.replace("dαβ", "😺😺😺"), "abc😺😺😺γδabc😺😺😺γδ"); - assert_eq!(data.replace('γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ"); - assert_eq!(data.replace(&['a', 'γ'] as &[_], "😺😺😺"), "😺😺😺bcdαβ😺😺😺δ😺😺😺bcdαβ😺😺😺δ"); - assert_eq!(data.replace(|c| c == 'γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ"); -} - -// The current implementation of SliceIndex fails to handle methods -// orthogonally from range types; therefore, it is worth testing -// all of the indexing operations on each input. -mod slice_index { - // Test a slicing operation **that should succeed,** - // testing it on all of the indexing methods. - // - // This is not suitable for testing failure on invalid inputs. - macro_rules! assert_range_eq { - ($s:expr, $range:expr, $expected:expr) => { - let mut s: String = $s.to_owned(); - let mut expected: String = $expected.to_owned(); - { - let s: &str = &s; - let expected: &str = &expected; - - assert_eq!(&s[$range], expected, "(in assertion for: index)"); - assert_eq!(s.get($range), Some(expected), "(in assertion for: get)"); - unsafe { - assert_eq!( - s.get_unchecked($range), - expected, - "(in assertion for: get_unchecked)", - ); - } - } - { - let s: &mut str = &mut s; - let expected: &mut str = &mut expected; - - assert_eq!(&mut s[$range], expected, "(in assertion for: index_mut)",); - assert_eq!( - s.get_mut($range), - Some(&mut expected[..]), - "(in assertion for: get_mut)", - ); - unsafe { - assert_eq!( - s.get_unchecked_mut($range), - expected, - "(in assertion for: get_unchecked_mut)", - ); - } - } - }; - } - - // Make sure the macro can actually detect bugs, - // because if it can't, then what are we even doing here? - // - // (Be aware this only demonstrates the ability to detect bugs - // in the FIRST method that panics, as the macro is not designed - // to be used in `should_panic`) - #[test] - #[should_panic(expected = "out of bounds")] - fn assert_range_eq_can_fail_by_panic() { - assert_range_eq!("abc", 0..5, "abc"); - } - - // (Be aware this only demonstrates the ability to detect bugs - // in the FIRST method it calls, as the macro is not designed - // to be used in `should_panic`) - #[test] - #[should_panic(expected = "==")] - fn assert_range_eq_can_fail_by_inequality() { - assert_range_eq!("abc", 0..2, "abc"); - } - - // Generates test cases for bad index operations. - // - // This generates `should_panic` test cases for Index/IndexMut - // and `None` test cases for get/get_mut. - macro_rules! panic_cases { - ($( - in mod $case_name:ident { - data: $data:expr; - - // optional: - // - // a similar input for which DATA[input] succeeds, and the corresponding - // output str. This helps validate "critical points" where an input range - // straddles the boundary between valid and invalid. - // (such as the input `len..len`, which is just barely valid) - $( - good: data[$good:expr] == $output:expr; - )* - - bad: data[$bad:expr]; - message: $expect_msg:expr; // must be a literal - } - )*) => {$( - mod $case_name { - #[test] - fn pass() { - let mut v: String = $data.into(); - - $( assert_range_eq!(v, $good, $output); )* - - { - let v: &str = &v; - assert_eq!(v.get($bad), None, "(in None assertion for get)"); - } - - { - let v: &mut str = &mut v; - assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)"); - } - } - - #[test] - #[should_panic(expected = $expect_msg)] - fn index_fail() { - let v: String = $data.into(); - let v: &str = &v; - let _v = &v[$bad]; - } - - #[test] - #[should_panic(expected = $expect_msg)] - fn index_mut_fail() { - let mut v: String = $data.into(); - let v: &mut str = &mut v; - let _v = &mut v[$bad]; - } - } - )*}; - } - - #[test] - fn simple_ascii() { - assert_range_eq!("abc", .., "abc"); - - assert_range_eq!("abc", 0..2, "ab"); - assert_range_eq!("abc", 0..=1, "ab"); - assert_range_eq!("abc", ..2, "ab"); - assert_range_eq!("abc", ..=1, "ab"); - - assert_range_eq!("abc", 1..3, "bc"); - assert_range_eq!("abc", 1..=2, "bc"); - assert_range_eq!("abc", 1..1, ""); - assert_range_eq!("abc", 1..=0, ""); - } - - #[test] - fn simple_unicode() { - // 日本 - assert_range_eq!("\u{65e5}\u{672c}", .., "\u{65e5}\u{672c}"); - - assert_range_eq!("\u{65e5}\u{672c}", 0..3, "\u{65e5}"); - assert_range_eq!("\u{65e5}\u{672c}", 0..=2, "\u{65e5}"); - assert_range_eq!("\u{65e5}\u{672c}", ..3, "\u{65e5}"); - assert_range_eq!("\u{65e5}\u{672c}", ..=2, "\u{65e5}"); - - assert_range_eq!("\u{65e5}\u{672c}", 3..6, "\u{672c}"); - assert_range_eq!("\u{65e5}\u{672c}", 3..=5, "\u{672c}"); - assert_range_eq!("\u{65e5}\u{672c}", 3.., "\u{672c}"); - - let data = "ประเทศไทย中华"; - assert_range_eq!(data, 0..3, "ป"); - assert_range_eq!(data, 3..6, "ร"); - assert_range_eq!(data, 3..3, ""); - assert_range_eq!(data, 30..33, "华"); - - /*0: 中 - 3: 华 - 6: V - 7: i - 8: ệ - 11: t - 12: - 13: N - 14: a - 15: m */ - let ss = "中华Việt Nam"; - assert_range_eq!(ss, 3..6, "华"); - assert_range_eq!(ss, 6..16, "Việt Nam"); - assert_range_eq!(ss, 6..=15, "Việt Nam"); - assert_range_eq!(ss, 6.., "Việt Nam"); - - assert_range_eq!(ss, 0..3, "中"); - assert_range_eq!(ss, 3..7, "华V"); - assert_range_eq!(ss, 3..=6, "华V"); - assert_range_eq!(ss, 3..3, ""); - assert_range_eq!(ss, 3..=2, ""); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] // hits an OOM - #[cfg_attr(miri, ignore)] // Miri is too slow - fn simple_big() { - fn a_million_letter_x() -> String { - let mut i = 0; - let mut rs = String::new(); - while i < 100000 { - rs.push_str("华华华华华华华华华华"); - i += 1; - } - rs - } - fn half_a_million_letter_x() -> String { - let mut i = 0; - let mut rs = String::new(); - while i < 100000 { - rs.push_str("华华华华华"); - i += 1; - } - rs - } - let letters = a_million_letter_x(); - assert_range_eq!(letters, 0..3 * 500000, half_a_million_letter_x()); - } - - #[test] - #[should_panic] - fn test_slice_fail() { - let _ = &"中华Việt Nam"[0..2]; - } - - panic_cases! { - in mod rangefrom_len { - data: "abcdef"; - good: data[6..] == ""; - bad: data[7..]; - message: "out of bounds"; - } - - in mod rangeto_len { - data: "abcdef"; - good: data[..6] == "abcdef"; - bad: data[..7]; - message: "out of bounds"; - } - - in mod rangetoinclusive_len { - data: "abcdef"; - good: data[..=5] == "abcdef"; - bad: data[..=6]; - message: "out of bounds"; - } - - in mod rangeinclusive_len { - data: "abcdef"; - good: data[0..=5] == "abcdef"; - bad: data[0..=6]; - message: "out of bounds"; - } - - in mod range_len_len { - data: "abcdef"; - good: data[6..6] == ""; - bad: data[7..7]; - message: "out of bounds"; - } - - in mod rangeinclusive_len_len { - data: "abcdef"; - good: data[6..=5] == ""; - bad: data[7..=6]; - message: "out of bounds"; - } - } - - panic_cases! { - in mod rangeinclusive_exhausted { - data: "abcdef"; - - good: data[0..=5] == "abcdef"; - good: data[{ - let mut iter = 0..=5; - iter.by_ref().count(); // exhaust it - iter - }] == ""; - - // 0..=6 is out of bounds before exhaustion, so it - // stands to reason that it still would be after. - bad: data[{ - let mut iter = 0..=6; - iter.by_ref().count(); // exhaust it - iter - }]; - message: "out of bounds"; - } - } - - panic_cases! { - in mod range_neg_width { - data: "abcdef"; - good: data[4..4] == ""; - bad: data[4..3]; - message: "begin <= end (4 <= 3)"; - } - - in mod rangeinclusive_neg_width { - data: "abcdef"; - good: data[4..=3] == ""; - bad: data[4..=2]; - message: "begin <= end (4 <= 3)"; - } - } - - mod overflow { - panic_cases! { - in mod rangeinclusive { - data: "hello"; - // note: using 0 specifically ensures that the result of overflowing is 0..0, - // so that `get` doesn't simply return None for the wrong reason. - bad: data[0..=usize::MAX]; - message: "maximum usize"; - } - - in mod rangetoinclusive { - data: "hello"; - bad: data[..=usize::MAX]; - message: "maximum usize"; - } - } - } - - mod boundary { - const DATA: &str = "abcαβγ"; - - const BAD_START: usize = 4; - const GOOD_START: usize = 3; - const BAD_END: usize = 6; - const GOOD_END: usize = 7; - const BAD_END_INCL: usize = BAD_END - 1; - const GOOD_END_INCL: usize = GOOD_END - 1; - - // it is especially important to test all of the different range types here - // because some of the logic may be duplicated as part of micro-optimizations - // to dodge unicode boundary checks on half-ranges. - panic_cases! { - in mod range_1 { - data: super::DATA; - bad: data[super::BAD_START..super::GOOD_END]; - message: - "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; - } - - in mod range_2 { - data: super::DATA; - bad: data[super::GOOD_START..super::BAD_END]; - message: - "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; - } - - in mod rangefrom { - data: super::DATA; - bad: data[super::BAD_START..]; - message: - "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; - } - - in mod rangeto { - data: super::DATA; - bad: data[..super::BAD_END]; - message: - "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; - } - - in mod rangeinclusive_1 { - data: super::DATA; - bad: data[super::BAD_START..=super::GOOD_END_INCL]; - message: - "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; - } - - in mod rangeinclusive_2 { - data: super::DATA; - bad: data[super::GOOD_START..=super::BAD_END_INCL]; - message: - "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; - } - - in mod rangetoinclusive { - data: super::DATA; - bad: data[..=super::BAD_END_INCL]; - message: - "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; - } - } - } - - const LOREM_PARAGRAPH: &str = "\ - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \ - sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \ - quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \ - nunc luctus, imperdiet mi. Integer fringilla non sem ut lacinia. Fusce varius \ - tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec tempus vel, \ - gravida nec quam."; - - // check the panic includes the prefix of the sliced string - #[test] - #[should_panic(expected = "byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")] - fn test_slice_fail_truncated_1() { - let _ = &LOREM_PARAGRAPH[..1024]; - } - // check the truncation in the panic message - #[test] - #[should_panic(expected = "luctus, im`[...]")] - fn test_slice_fail_truncated_2() { - let _ = &LOREM_PARAGRAPH[..1024]; - } -} - -#[test] -fn test_str_slice_rangetoinclusive_ok() { - let s = "abcαβγ"; - assert_eq!(&s[..=2], "abc"); - assert_eq!(&s[..=4], "abcα"); -} - -#[test] -#[should_panic] -fn test_str_slice_rangetoinclusive_notok() { - let s = "abcαβγ"; - let _ = &s[..=3]; -} - -#[test] -fn test_str_slicemut_rangetoinclusive_ok() { - let mut s = "abcαβγ".to_owned(); - let s: &mut str = &mut s; - assert_eq!(&mut s[..=2], "abc"); - assert_eq!(&mut s[..=4], "abcα"); -} - -#[test] -#[should_panic] -fn test_str_slicemut_rangetoinclusive_notok() { - let mut s = "abcαβγ".to_owned(); - let s: &mut str = &mut s; - let _ = &mut s[..=3]; -} - -#[test] -fn test_is_char_boundary() { - let s = "ศไทย中华Việt Nam β-release 🐱123"; - assert!(s.is_char_boundary(0)); - assert!(s.is_char_boundary(s.len())); - assert!(!s.is_char_boundary(s.len() + 1)); - for (i, ch) in s.char_indices() { - // ensure character locations are boundaries and continuation bytes are not - assert!(s.is_char_boundary(i), "{} is a char boundary in {:?}", i, s); - for j in 1..ch.len_utf8() { - assert!( - !s.is_char_boundary(i + j), - "{} should not be a char boundary in {:?}", - i + j, - s - ); - } - } -} - -#[test] -fn test_trim_start_matches() { - let v: &[char] = &[]; - assert_eq!(" *** foo *** ".trim_start_matches(v), " *** foo *** "); - let chars: &[char] = &['*', ' ']; - assert_eq!(" *** foo *** ".trim_start_matches(chars), "foo *** "); - assert_eq!(" *** *** ".trim_start_matches(chars), ""); - assert_eq!("foo *** ".trim_start_matches(chars), "foo *** "); - - assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11"); - let chars: &[char] = &['1', '2']; - assert_eq!("12foo1bar12".trim_start_matches(chars), "foo1bar12"); - assert_eq!("123foo1bar123".trim_start_matches(|c: char| c.is_numeric()), "foo1bar123"); -} - -#[test] -fn test_trim_end_matches() { - let v: &[char] = &[]; - assert_eq!(" *** foo *** ".trim_end_matches(v), " *** foo *** "); - let chars: &[char] = &['*', ' ']; - assert_eq!(" *** foo *** ".trim_end_matches(chars), " *** foo"); - assert_eq!(" *** *** ".trim_end_matches(chars), ""); - assert_eq!(" *** foo".trim_end_matches(chars), " *** foo"); - - assert_eq!("11foo1bar11".trim_end_matches('1'), "11foo1bar"); - let chars: &[char] = &['1', '2']; - assert_eq!("12foo1bar12".trim_end_matches(chars), "12foo1bar"); - assert_eq!("123foo1bar123".trim_end_matches(|c: char| c.is_numeric()), "123foo1bar"); -} - -#[test] -fn test_trim_matches() { - let v: &[char] = &[]; - assert_eq!(" *** foo *** ".trim_matches(v), " *** foo *** "); - let chars: &[char] = &['*', ' ']; - assert_eq!(" *** foo *** ".trim_matches(chars), "foo"); - assert_eq!(" *** *** ".trim_matches(chars), ""); - assert_eq!("foo".trim_matches(chars), "foo"); - - assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); - let chars: &[char] = &['1', '2']; - assert_eq!("12foo1bar12".trim_matches(chars), "foo1bar"); - assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar"); -} - -#[test] -fn test_trim_start() { - assert_eq!("".trim_start(), ""); - assert_eq!("a".trim_start(), "a"); - assert_eq!(" ".trim_start(), ""); - assert_eq!(" blah".trim_start(), "blah"); - assert_eq!(" \u{3000} wut".trim_start(), "wut"); - assert_eq!("hey ".trim_start(), "hey "); -} - -#[test] -fn test_trim_end() { - assert_eq!("".trim_end(), ""); - assert_eq!("a".trim_end(), "a"); - assert_eq!(" ".trim_end(), ""); - assert_eq!("blah ".trim_end(), "blah"); - assert_eq!("wut \u{3000} ".trim_end(), "wut"); - assert_eq!(" hey".trim_end(), " hey"); -} - -#[test] -fn test_trim() { - assert_eq!("".trim(), ""); - assert_eq!("a".trim(), "a"); - assert_eq!(" ".trim(), ""); - assert_eq!(" blah ".trim(), "blah"); - assert_eq!("\nwut \u{3000} ".trim(), "wut"); - assert_eq!(" hey dude ".trim(), "hey dude"); -} - -#[test] -fn test_is_whitespace() { - assert!("".chars().all(|c| c.is_whitespace())); - assert!(" ".chars().all(|c| c.is_whitespace())); - assert!("\u{2009}".chars().all(|c| c.is_whitespace())); // Thin space - assert!(" \n\t ".chars().all(|c| c.is_whitespace())); - assert!(!" _ ".chars().all(|c| c.is_whitespace())); -} - -#[test] -fn test_is_utf8() { - // deny overlong encodings - assert!(from_utf8(&[0xc0, 0x80]).is_err()); - assert!(from_utf8(&[0xc0, 0xae]).is_err()); - assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err()); - assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err()); - assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err()); - assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err()); - assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err()); - - // deny surrogates - assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err()); - assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err()); - - assert!(from_utf8(&[0xC2, 0x80]).is_ok()); - assert!(from_utf8(&[0xDF, 0xBF]).is_ok()); - assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok()); - assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok()); - assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok()); - assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok()); - assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok()); - assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok()); -} - -#[test] -fn test_const_is_utf8() { - const _: () = { - // deny overlong encodings - assert!(from_utf8(&[0xc0, 0x80]).is_err()); - assert!(from_utf8(&[0xc0, 0xae]).is_err()); - assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err()); - assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err()); - assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err()); - assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err()); - assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err()); - - // deny surrogates - assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err()); - assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err()); - - assert!(from_utf8(&[0xC2, 0x80]).is_ok()); - assert!(from_utf8(&[0xDF, 0xBF]).is_ok()); - assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok()); - assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok()); - assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok()); - assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok()); - assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok()); - assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok()); - }; -} - -#[test] -fn from_utf8_mostly_ascii() { - // deny invalid bytes embedded in long stretches of ascii - for i in 32..64 { - let mut data = [0; 128]; - data[i] = 0xC0; - assert!(from_utf8(&data).is_err()); - data[i] = 0xC2; - assert!(from_utf8(&data).is_err()); - } -} - -#[test] -fn const_from_utf8_mostly_ascii() { - const _: () = { - // deny invalid bytes embedded in long stretches of ascii - let mut i = 32; - while i < 64 { - let mut data = [0; 128]; - data[i] = 0xC0; - assert!(from_utf8(&data).is_err()); - data[i] = 0xC2; - assert!(from_utf8(&data).is_err()); - - i = i + 1; - } - }; -} - -#[test] -fn from_utf8_error() { - macro_rules! test { - ($input: expr, $expected_valid_up_to:pat, $expected_error_len:pat) => { - let error = from_utf8($input).unwrap_err(); - assert_matches!(error.valid_up_to(), $expected_valid_up_to); - assert_matches!(error.error_len(), $expected_error_len); - - const _: () = { - match from_utf8($input) { - Err(error) => { - let valid_up_to = error.valid_up_to(); - let error_len = error.error_len(); - - assert!(matches!(valid_up_to, $expected_valid_up_to)); - assert!(matches!(error_len, $expected_error_len)); - } - Ok(_) => unreachable!(), - } - }; - }; - } - test!(b"A\xC3\xA9 \xFF ", 4, Some(1)); - test!(b"A\xC3\xA9 \x80 ", 4, Some(1)); - test!(b"A\xC3\xA9 \xC1 ", 4, Some(1)); - test!(b"A\xC3\xA9 \xC1", 4, Some(1)); - test!(b"A\xC3\xA9 \xC2", 4, None); - test!(b"A\xC3\xA9 \xC2 ", 4, Some(1)); - test!(b"A\xC3\xA9 \xC2\xC0", 4, Some(1)); - test!(b"A\xC3\xA9 \xE0", 4, None); - test!(b"A\xC3\xA9 \xE0\x9F", 4, Some(1)); - test!(b"A\xC3\xA9 \xE0\xA0", 4, None); - test!(b"A\xC3\xA9 \xE0\xA0\xC0", 4, Some(2)); - test!(b"A\xC3\xA9 \xE0\xA0 ", 4, Some(2)); - test!(b"A\xC3\xA9 \xED\xA0\x80 ", 4, Some(1)); - test!(b"A\xC3\xA9 \xF1", 4, None); - test!(b"A\xC3\xA9 \xF1\x80", 4, None); - test!(b"A\xC3\xA9 \xF1\x80\x80", 4, None); - test!(b"A\xC3\xA9 \xF1 ", 4, Some(1)); - test!(b"A\xC3\xA9 \xF1\x80 ", 4, Some(2)); - test!(b"A\xC3\xA9 \xF1\x80\x80 ", 4, Some(3)); -} - -#[test] -fn test_as_bytes() { - // no null - let v = [ - 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142, - 86, 105, 225, 187, 135, 116, 32, 78, 97, 109, - ]; - let b: &[u8] = &[]; - assert_eq!("".as_bytes(), b); - assert_eq!("abc".as_bytes(), b"abc"); - assert_eq!("ศไทย中华Việt Nam".as_bytes(), v); -} - -#[test] -#[should_panic] -fn test_as_bytes_fail() { - // Don't double free. (I'm not sure if this exercises the - // original problem code path anymore.) - let s = String::from(""); - let _bytes = s.as_bytes(); - panic!(); -} - -#[test] -fn test_as_ptr() { - let buf = "hello".as_ptr(); - unsafe { - assert_eq!(*buf.add(0), b'h'); - assert_eq!(*buf.add(1), b'e'); - assert_eq!(*buf.add(2), b'l'); - assert_eq!(*buf.add(3), b'l'); - assert_eq!(*buf.add(4), b'o'); - } -} - -#[test] -fn vec_str_conversions() { - let s1: String = String::from("All mimsy were the borogoves"); - - let v: Vec = s1.as_bytes().to_vec(); - let s2: String = String::from(from_utf8(&v).unwrap()); - let mut i = 0; - let n1 = s1.len(); - let n2 = v.len(); - assert_eq!(n1, n2); - while i < n1 { - let a: u8 = s1.as_bytes()[i]; - let b: u8 = s2.as_bytes()[i]; - assert_eq!(a, b); - i += 1; - } -} - -#[test] -fn test_contains() { - assert!("abcde".contains("bcd")); - assert!("abcde".contains("abcd")); - assert!("abcde".contains("bcde")); - assert!("abcde".contains("")); - assert!("".contains("")); - assert!(!"abcde".contains("def")); - assert!(!"".contains("a")); - - let data = "ประเทศไทย中华Việt Nam"; - assert!(data.contains("ประเ")); - assert!(data.contains("ะเ")); - assert!(data.contains("中华")); - assert!(!data.contains("ไท华")); -} - -#[test] -fn test_contains_char() { - assert!("abc".contains('b')); - assert!("a".contains('a')); - assert!(!"abc".contains('d')); - assert!(!"".contains('a')); -} - -#[test] -fn test_split_at() { - let s = "ศไทย中华Việt Nam"; - for (index, _) in s.char_indices() { - let (a, b) = s.split_at(index); - assert_eq!(&s[..a.len()], a); - assert_eq!(&s[a.len()..], b); - } - let (a, b) = s.split_at(s.len()); - assert_eq!(a, s); - assert_eq!(b, ""); -} - -#[test] -fn test_split_at_mut() { - let mut s = "Hello World".to_string(); - { - let (a, b) = s.split_at_mut(5); - a.make_ascii_uppercase(); - b.make_ascii_lowercase(); - } - assert_eq!(s, "HELLO world"); -} - -#[test] -#[should_panic] -fn test_split_at_boundscheck() { - let s = "ศไทย中华Việt Nam"; - let _ = s.split_at(1); -} - -#[test] -fn test_escape_unicode() { - assert_eq!("abc".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{63}"); - assert_eq!("a c".escape_unicode().to_string(), "\\u{61}\\u{20}\\u{63}"); - assert_eq!("\r\n\t".escape_unicode().to_string(), "\\u{d}\\u{a}\\u{9}"); - assert_eq!("'\"\\".escape_unicode().to_string(), "\\u{27}\\u{22}\\u{5c}"); - assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode().to_string(), "\\u{0}\\u{1}\\u{fe}\\u{ff}"); - assert_eq!("\u{100}\u{ffff}".escape_unicode().to_string(), "\\u{100}\\u{ffff}"); - assert_eq!("\u{10000}\u{10ffff}".escape_unicode().to_string(), "\\u{10000}\\u{10ffff}"); - assert_eq!("ab\u{fb00}".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{fb00}"); - assert_eq!("\u{1d4ea}\r".escape_unicode().to_string(), "\\u{1d4ea}\\u{d}"); -} - -#[test] -fn test_escape_debug() { - // Note that there are subtleties with the number of backslashes - // on the left- and right-hand sides. In particular, Unicode code points - // are usually escaped with two backslashes on the right-hand side, as - // they are escaped. However, when the character is unescaped (e.g., for - // printable characters), only a single backslash appears (as the character - // itself appears in the debug string). - assert_eq!("abc".escape_debug().to_string(), "abc"); - assert_eq!("a c".escape_debug().to_string(), "a c"); - assert_eq!("éèê".escape_debug().to_string(), "éèê"); - assert_eq!("\0\r\n\t".escape_debug().to_string(), "\\0\\r\\n\\t"); - assert_eq!("'\"\\".escape_debug().to_string(), "\\'\\\"\\\\"); - assert_eq!("\u{7f}\u{ff}".escape_debug().to_string(), "\\u{7f}\u{ff}"); - assert_eq!("\u{100}\u{ffff}".escape_debug().to_string(), "\u{100}\\u{ffff}"); - assert_eq!("\u{10000}\u{10ffff}".escape_debug().to_string(), "\u{10000}\\u{10ffff}"); - assert_eq!("ab\u{200b}".escape_debug().to_string(), "ab\\u{200b}"); - assert_eq!("\u{10d4ea}\r".escape_debug().to_string(), "\\u{10d4ea}\\r"); - assert_eq!( - "\u{301}a\u{301}bé\u{e000}".escape_debug().to_string(), - "\\u{301}a\u{301}bé\\u{e000}" - ); -} - -#[test] -fn test_escape_default() { - assert_eq!("abc".escape_default().to_string(), "abc"); - assert_eq!("a c".escape_default().to_string(), "a c"); - assert_eq!("éèê".escape_default().to_string(), "\\u{e9}\\u{e8}\\u{ea}"); - assert_eq!("\r\n\t".escape_default().to_string(), "\\r\\n\\t"); - assert_eq!("'\"\\".escape_default().to_string(), "\\'\\\"\\\\"); - assert_eq!("\u{7f}\u{ff}".escape_default().to_string(), "\\u{7f}\\u{ff}"); - assert_eq!("\u{100}\u{ffff}".escape_default().to_string(), "\\u{100}\\u{ffff}"); - assert_eq!("\u{10000}\u{10ffff}".escape_default().to_string(), "\\u{10000}\\u{10ffff}"); - assert_eq!("ab\u{200b}".escape_default().to_string(), "ab\\u{200b}"); - assert_eq!("\u{10d4ea}\r".escape_default().to_string(), "\\u{10d4ea}\\r"); -} - -#[test] -fn test_total_ord() { - assert_eq!("1234".cmp("123"), Greater); - assert_eq!("123".cmp("1234"), Less); - assert_eq!("1234".cmp("1234"), Equal); - assert_eq!("12345555".cmp("123456"), Less); - assert_eq!("22".cmp("1234"), Greater); -} - -#[test] -fn test_iterator() { - let s = "ศไทย中华Việt Nam"; - let v = ['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm']; - - let mut pos = 0; - let it = s.chars(); - - for c in it { - assert_eq!(c, v[pos]); - pos += 1; - } - assert_eq!(pos, v.len()); - assert_eq!(s.chars().count(), v.len()); -} - -#[test] -fn test_iterator_advance() { - let s = "「赤錆」と呼ばれる鉄錆は、水の存在下での鉄の自然酸化によって生じる、オキシ水酸化鉄(III) 等の(含水)酸化物粒子の疎な凝集膜であるとみなせる。"; - let chars: Vec = s.chars().collect(); - let mut it = s.chars(); - it.advance_by(1).unwrap(); - assert_eq!(it.next(), Some(chars[1])); - it.advance_by(33).unwrap(); - assert_eq!(it.next(), Some(chars[35])); -} - -#[test] -fn test_rev_iterator() { - let s = "ศไทย中华Việt Nam"; - let v = ['m', 'a', 'N', ' ', 't', 'ệ', 'i', 'V', '华', '中', 'ย', 'ท', 'ไ', 'ศ']; - - let mut pos = 0; - let it = s.chars().rev(); - - for c in it { - assert_eq!(c, v[pos]); - pos += 1; - } - assert_eq!(pos, v.len()); -} - -#[test] -fn test_to_lowercase_rev_iterator() { - let s = "AÖßÜ💩ΣΤΙΓΜΑΣDžfiİ"; - let v = ['\u{307}', 'i', 'fi', 'dž', 'σ', 'α', 'μ', 'γ', 'ι', 'τ', 'σ', '💩', 'ü', 'ß', 'ö', 'a']; - - let mut pos = 0; - let it = s.chars().flat_map(|c| c.to_lowercase()).rev(); - - for c in it { - assert_eq!(c, v[pos]); - pos += 1; - } - assert_eq!(pos, v.len()); -} - -#[test] -fn test_to_uppercase_rev_iterator() { - let s = "aößü💩στιγμαςDžfiᾀ"; - let v = - ['Ι', 'Ἀ', 'I', 'F', 'DŽ', 'Σ', 'Α', 'Μ', 'Γ', 'Ι', 'Τ', 'Σ', '💩', 'Ü', 'S', 'S', 'Ö', 'A']; - - let mut pos = 0; - let it = s.chars().flat_map(|c| c.to_uppercase()).rev(); - - for c in it { - assert_eq!(c, v[pos]); - pos += 1; - } - assert_eq!(pos, v.len()); -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri is too slow -fn test_chars_decoding() { - let mut bytes = [0; MAX_LEN_UTF8]; - for c in (0..0x110000).filter_map(std::char::from_u32) { - let s = c.encode_utf8(&mut bytes); - if Some(c) != s.chars().next() { - panic!("character {:x}={} does not decode correctly", c as u32, c); - } - } -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri is too slow -fn test_chars_rev_decoding() { - let mut bytes = [0; MAX_LEN_UTF8]; - for c in (0..0x110000).filter_map(std::char::from_u32) { - let s = c.encode_utf8(&mut bytes); - if Some(c) != s.chars().rev().next() { - panic!("character {:x}={} does not decode correctly", c as u32, c); - } - } -} - -#[test] -fn test_iterator_clone() { - let s = "ศไทย中华Việt Nam"; - let mut it = s.chars(); - it.next(); - assert!(it.clone().zip(it).all(|(x, y)| x == y)); -} - -#[test] -fn test_iterator_last() { - let s = "ศไทย中华Việt Nam"; - let mut it = s.chars(); - it.next(); - assert_eq!(it.last(), Some('m')); -} - -#[test] -fn test_chars_debug() { - let s = "ศไทย中华Việt Nam"; - let c = s.chars(); - assert_eq!( - format!("{c:?}"), - r#"Chars(['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'])"# - ); -} - -#[test] -fn test_bytesator() { - let s = "ศไทย中华Việt Nam"; - let v = [ - 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142, - 86, 105, 225, 187, 135, 116, 32, 78, 97, 109, - ]; - let mut pos = 0; - - for b in s.bytes() { - assert_eq!(b, v[pos]); - pos += 1; - } -} - -#[test] -fn test_bytes_revator() { - let s = "ศไทย中华Việt Nam"; - let v = [ - 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142, - 86, 105, 225, 187, 135, 116, 32, 78, 97, 109, - ]; - let mut pos = v.len(); - - for b in s.bytes().rev() { - pos -= 1; - assert_eq!(b, v[pos]); - } -} - -#[test] -fn test_bytesator_nth() { - let s = "ศไทย中华Việt Nam"; - let v = [ - 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142, - 86, 105, 225, 187, 135, 116, 32, 78, 97, 109, - ]; - - let mut b = s.bytes(); - assert_eq!(b.nth(2).unwrap(), v[2]); - assert_eq!(b.nth(10).unwrap(), v[10]); - assert_eq!(b.nth(200), None); -} - -#[test] -fn test_bytesator_count() { - let s = "ศไทย中华Việt Nam"; - - let b = s.bytes(); - assert_eq!(b.count(), 28) -} - -#[test] -fn test_bytesator_last() { - let s = "ศไทย中华Việt Nam"; - - let b = s.bytes(); - assert_eq!(b.last().unwrap(), 109) -} - -#[test] -fn test_char_indicesator() { - let s = "ศไทย中华Việt Nam"; - let p = [0, 3, 6, 9, 12, 15, 18, 19, 20, 23, 24, 25, 26, 27]; - let v = ['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm']; - - let mut pos = 0; - let it = s.char_indices(); - - for c in it { - assert_eq!(c, (p[pos], v[pos])); - pos += 1; - } - assert_eq!(pos, v.len()); - assert_eq!(pos, p.len()); -} - -#[test] -fn test_char_indices_revator() { - let s = "ศไทย中华Việt Nam"; - let p = [27, 26, 25, 24, 23, 20, 19, 18, 15, 12, 9, 6, 3, 0]; - let v = ['m', 'a', 'N', ' ', 't', 'ệ', 'i', 'V', '华', '中', 'ย', 'ท', 'ไ', 'ศ']; - - let mut pos = 0; - let it = s.char_indices().rev(); - - for c in it { - assert_eq!(c, (p[pos], v[pos])); - pos += 1; - } - assert_eq!(pos, v.len()); - assert_eq!(pos, p.len()); -} - -#[test] -fn test_char_indices_last() { - let s = "ศไทย中华Việt Nam"; - let mut it = s.char_indices(); - it.next(); - assert_eq!(it.last(), Some((27, 'm'))); -} - -#[test] -fn test_splitn_char_iterator() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let split: Vec<&str> = data.splitn(4, ' ').collect(); - assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]); - - let split: Vec<&str> = data.splitn(4, |c: char| c == ' ').collect(); - assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]); - - // Unicode - let split: Vec<&str> = data.splitn(4, 'ä').collect(); - assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]); - - let split: Vec<&str> = data.splitn(4, |c: char| c == 'ä').collect(); - assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]); -} - -#[test] -fn test_split_char_iterator_no_trailing() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let split: Vec<&str> = data.split('\n').collect(); - assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]); - - let split: Vec<&str> = data.split_terminator('\n').collect(); - assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]); -} - -#[test] -fn test_split_char_iterator_inclusive() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let split: Vec<&str> = data.split_inclusive('\n').collect(); - assert_eq!(split, ["\n", "Märy häd ä little lämb\n", "Little lämb\n"]); - - let uppercase_separated = "SheePSharKTurtlECaT"; - let mut first_char = true; - let split: Vec<&str> = uppercase_separated - .split_inclusive(|c: char| { - let split = !first_char && c.is_uppercase(); - first_char = split; - split - }) - .collect(); - assert_eq!(split, ["SheeP", "SharK", "TurtlE", "CaT"]); -} - -#[test] -fn test_split_char_iterator_inclusive_rev() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let split: Vec<&str> = data.split_inclusive('\n').rev().collect(); - assert_eq!(split, ["Little lämb\n", "Märy häd ä little lämb\n", "\n"]); - - // Note that the predicate is stateful and thus dependent - // on the iteration order. - // (A different predicate is needed for reverse iterator vs normal iterator.) - // Not sure if anything can be done though. - let uppercase_separated = "SheePSharKTurtlECaT"; - let mut term_char = true; - let split: Vec<&str> = uppercase_separated - .split_inclusive(|c: char| { - let split = term_char && c.is_uppercase(); - term_char = c.is_uppercase(); - split - }) - .rev() - .collect(); - assert_eq!(split, ["CaT", "TurtlE", "SharK", "SheeP"]); -} - -#[test] -fn test_rsplit() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let split: Vec<&str> = data.rsplit(' ').collect(); - assert_eq!(split, ["lämb\n", "lämb\nLittle", "little", "ä", "häd", "\nMäry"]); - - let split: Vec<&str> = data.rsplit("lämb").collect(); - assert_eq!(split, ["\n", "\nLittle ", "\nMäry häd ä little "]); - - let split: Vec<&str> = data.rsplit(|c: char| c == 'ä').collect(); - assert_eq!(split, ["mb\n", "mb\nLittle l", " little l", "d ", "ry h", "\nM"]); -} - -#[test] -fn test_rsplitn() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let split: Vec<&str> = data.rsplitn(2, ' ').collect(); - assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]); - - let split: Vec<&str> = data.rsplitn(2, "lämb").collect(); - assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]); - - let split: Vec<&str> = data.rsplitn(2, |c: char| c == 'ä').collect(); - assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]); -} - -#[test] -fn test_split_once() { - assert_eq!("".split_once("->"), None); - assert_eq!("-".split_once("->"), None); - assert_eq!("->".split_once("->"), Some(("", ""))); - assert_eq!("a->".split_once("->"), Some(("a", ""))); - assert_eq!("->b".split_once("->"), Some(("", "b"))); - assert_eq!("a->b".split_once("->"), Some(("a", "b"))); - assert_eq!("a->b->c".split_once("->"), Some(("a", "b->c"))); - assert_eq!("---".split_once("--"), Some(("", "-"))); -} - -#[test] -fn test_rsplit_once() { - assert_eq!("".rsplit_once("->"), None); - assert_eq!("-".rsplit_once("->"), None); - assert_eq!("->".rsplit_once("->"), Some(("", ""))); - assert_eq!("a->".rsplit_once("->"), Some(("a", ""))); - assert_eq!("->b".rsplit_once("->"), Some(("", "b"))); - assert_eq!("a->b".rsplit_once("->"), Some(("a", "b"))); - assert_eq!("a->b->c".rsplit_once("->"), Some(("a->b", "c"))); - assert_eq!("---".rsplit_once("--"), Some(("-", ""))); -} - -#[test] -fn test_split_whitespace() { - let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n"; - let words: Vec<&str> = data.split_whitespace().collect(); - assert_eq!(words, ["Märy", "häd", "ä", "little", "lämb", "Little", "lämb"]) -} - -#[test] -fn test_lines() { - fn t(data: &str, expected: &[&str]) { - let lines: Vec<&str> = data.lines().collect(); - assert_eq!(lines, expected); - } - t("", &[]); - t("\n", &[""]); - t("\n2nd", &["", "2nd"]); - t("\r\n", &[""]); - t("bare\r", &["bare\r"]); - t("bare\rcr", &["bare\rcr"]); - t("Text\n\r", &["Text", "\r"]); - t( - "\nMäry häd ä little lämb\n\r\nLittle lämb\n", - &["", "Märy häd ä little lämb", "", "Little lämb"], - ); - t( - "\r\nMäry häd ä little lämb\n\nLittle lämb", - &["", "Märy häd ä little lämb", "", "Little lämb"], - ); -} - -#[test] -fn test_splitator() { - fn t(s: &str, sep: &str, u: &[&str]) { - let v: Vec<&str> = s.split(sep).collect(); - assert_eq!(v, u); - } - t("--1233345--", "12345", &["--1233345--"]); - t("abc::hello::there", "::", &["abc", "hello", "there"]); - t("::hello::there", "::", &["", "hello", "there"]); - t("hello::there::", "::", &["hello", "there", ""]); - t("::hello::there::", "::", &["", "hello", "there", ""]); - t("ประเทศไทย中华Việt Nam", "中华", &["ประเทศไทย", "Việt Nam"]); - t("zzXXXzzYYYzz", "zz", &["", "XXX", "YYY", ""]); - t("zzXXXzYYYz", "XXX", &["zz", "zYYYz"]); - t(".XXX.YYY.", ".", &["", "XXX", "YYY", ""]); - t("", ".", &[""]); - t("zz", "zz", &["", ""]); - t("ok", "z", &["ok"]); - t("zzz", "zz", &["", "z"]); - t("zzzzz", "zz", &["", "", "z"]); -} - -#[test] -fn test_str_default() { - use std::default::Default; - - fn t>() { - let s: S = Default::default(); - assert_eq!(s.as_ref(), ""); - } - - t::<&str>(); - t::(); - t::<&mut str>(); -} - -#[test] -fn test_str_container() { - fn sum_len(v: &[&str]) -> usize { - v.iter().map(|x| x.len()).sum() - } - - let s = "01234"; - assert_eq!(5, sum_len(&["012", "", "34"])); - assert_eq!(5, sum_len(&["01", "2", "34", ""])); - assert_eq!(5, sum_len(&[s])); -} - -#[test] -fn test_str_from_utf8() { - let xs = b"hello"; - assert_eq!(from_utf8(xs), Ok("hello")); - - let xs = "ศไทย中华Việt Nam".as_bytes(); - assert_eq!(from_utf8(xs), Ok("ศไทย中华Việt Nam")); - - let xs = b"hello\xFF"; - assert!(from_utf8(xs).is_err()); -} - -#[test] -fn test_pattern_deref_forward() { - let data = "aabcdaa"; - assert!(data.contains("bcd")); - assert!(data.contains(&"bcd")); - assert!(data.contains(&"bcd".to_string())); -} - -#[test] -fn test_empty_match_indices() { - let data = "aä中!"; - let vec: Vec<_> = data.match_indices("").collect(); - assert_eq!(vec, [(0, ""), (1, ""), (3, ""), (6, ""), (7, "")]); -} - -#[test] -fn test_bool_from_str() { - assert_eq!("true".parse().ok(), Some(true)); - assert_eq!("false".parse().ok(), Some(false)); - assert_eq!("not even a boolean".parse::().ok(), None); -} - -fn check_contains_all_substrings(haystack: &str) { - let mut modified_needle = String::new(); - - for i in 0..haystack.len() { - // check different haystack lengths since we special-case short haystacks. - let haystack = &haystack[0..i]; - assert!(haystack.contains("")); - for j in 0..haystack.len() { - for k in j + 1..=haystack.len() { - let needle = &haystack[j..k]; - assert!(haystack.contains(needle)); - modified_needle.clear(); - modified_needle.push_str(needle); - modified_needle.replace_range(0..1, "\0"); - assert!(!haystack.contains(&modified_needle)); - - modified_needle.clear(); - modified_needle.push_str(needle); - modified_needle.replace_range(needle.len() - 1..needle.len(), "\0"); - assert!(!haystack.contains(&modified_needle)); - } - } - } -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri is too slow -fn strslice_issue_16589() { - assert!("bananas".contains("nana")); - - // prior to the fix for #16589, x.contains("abcdabcd") returned false - // test all substrings for good measure - check_contains_all_substrings("012345678901234567890123456789bcdabcdabcd"); -} - -#[test] -fn strslice_issue_16878() { - assert!(!"1234567ah012345678901ah".contains("hah")); - assert!(!"00abc01234567890123456789abc".contains("bcabc")); -} - -#[test] -fn strslice_issue_104726() { - // Edge-case in the simd_contains impl. - // The first and last byte are the same so it backtracks by one byte - // which aligns with the end of the string. Previously incorrect offset calculations - // lead to out-of-bounds slicing. - #[rustfmt::skip] - let needle = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaba"; - let haystack = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"; - assert!(!haystack.contains(needle)); -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri is too slow -fn test_strslice_contains() { - let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'"; - check_contains_all_substrings(x); -} - -#[test] -fn test_rsplitn_char_iterator() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let mut split: Vec<&str> = data.rsplitn(4, ' ').collect(); - split.reverse(); - assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); - - let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect(); - split.reverse(); - assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); - - // Unicode - let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect(); - split.reverse(); - assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); - - let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect(); - split.reverse(); - assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); -} - -#[test] -fn test_split_char_iterator() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let split: Vec<&str> = data.split(' ').collect(); - assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); - - let mut rsplit: Vec<&str> = data.split(' ').rev().collect(); - rsplit.reverse(); - assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); - - let split: Vec<&str> = data.split(|c: char| c == ' ').collect(); - assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); - - let mut rsplit: Vec<&str> = data.split(|c: char| c == ' ').rev().collect(); - rsplit.reverse(); - assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); - - // Unicode - let split: Vec<&str> = data.split('ä').collect(); - assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); - - let mut rsplit: Vec<&str> = data.split('ä').rev().collect(); - rsplit.reverse(); - assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); - - let split: Vec<&str> = data.split(|c: char| c == 'ä').collect(); - assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); - - let mut rsplit: Vec<&str> = data.split(|c: char| c == 'ä').rev().collect(); - rsplit.reverse(); - assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); -} - -#[test] -fn test_rev_split_char_iterator_no_trailing() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let mut split: Vec<&str> = data.split('\n').rev().collect(); - split.reverse(); - assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]); - - let mut split: Vec<&str> = data.split_terminator('\n').rev().collect(); - split.reverse(); - assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]); -} - -#[test] -fn test_utf16_code_units() { - assert_eq!("é\u{1F4A9}".encode_utf16().collect::>(), [0xE9, 0xD83D, 0xDCA9]) -} - -#[test] -fn test_utf16_size_hint() { - assert_eq!("".encode_utf16().size_hint(), (0, Some(0))); - assert_eq!("123".encode_utf16().size_hint(), (1, Some(3))); - assert_eq!("1234".encode_utf16().size_hint(), (2, Some(4))); - assert_eq!("12345678".encode_utf16().size_hint(), (3, Some(8))); - - fn hint_vec(src: &str) -> Vec<(usize, Option)> { - let mut it = src.encode_utf16(); - let mut result = Vec::new(); - result.push(it.size_hint()); - while it.next().is_some() { - result.push(it.size_hint()) - } - result - } - - assert_eq!(hint_vec("12"), [(1, Some(2)), (1, Some(1)), (0, Some(0))]); - assert_eq!(hint_vec("\u{101234}"), [(2, Some(4)), (1, Some(1)), (0, Some(0))]); - assert_eq!(hint_vec("\u{101234}a"), [(2, Some(5)), (2, Some(2)), (1, Some(1)), (0, Some(0))]); -} - -#[test] -fn starts_with_in_unicode() { - assert!(!"├── Cargo.toml".starts_with("# ")); -} - -#[test] -fn starts_short_long() { - assert!(!"".starts_with("##")); - assert!(!"##".starts_with("####")); - assert!("####".starts_with("##")); - assert!(!"##ä".starts_with("####")); - assert!("####ä".starts_with("##")); - assert!(!"##".starts_with("####ä")); - assert!("##ä##".starts_with("##ä")); - - assert!("".starts_with("")); - assert!("ä".starts_with("")); - assert!("#ä".starts_with("")); - assert!("##ä".starts_with("")); - assert!("ä###".starts_with("")); - assert!("#ä##".starts_with("")); - assert!("##ä#".starts_with("")); -} - -#[test] -fn contains_weird_cases() { - assert!("* \t".contains(' ')); - assert!(!"* \t".contains('?')); - assert!(!"* \t".contains('\u{1F4A9}')); -} - -#[test] -fn trim_ws() { - assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t "); - assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a"); - assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t "); - assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a"); - assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()), "a"); - assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), ""); - assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), ""); - assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), ""); - assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), ""); - assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()), ""); -} - -#[test] -fn to_lowercase() { - assert_eq!("".to_lowercase(), ""); - assert_eq!("AÉDžaé ".to_lowercase(), "aédžaé "); - - // https://github.com/rust-lang/rust/issues/26035 - assert_eq!("ΑΣ".to_lowercase(), "ας"); - assert_eq!("Α'Σ".to_lowercase(), "α'ς"); - assert_eq!("Α''Σ".to_lowercase(), "α''ς"); - - assert_eq!("ΑΣ Α".to_lowercase(), "ας α"); - assert_eq!("Α'Σ Α".to_lowercase(), "α'ς α"); - assert_eq!("Α''Σ Α".to_lowercase(), "α''ς α"); - - assert_eq!("ΑΣ' Α".to_lowercase(), "ας' α"); - assert_eq!("ΑΣ'' Α".to_lowercase(), "ας'' α"); - - assert_eq!("Α'Σ' Α".to_lowercase(), "α'ς' α"); - assert_eq!("Α''Σ'' Α".to_lowercase(), "α''ς'' α"); - - assert_eq!("Α Σ".to_lowercase(), "α σ"); - assert_eq!("Α 'Σ".to_lowercase(), "α 'σ"); - assert_eq!("Α ''Σ".to_lowercase(), "α ''σ"); - - assert_eq!("Σ".to_lowercase(), "σ"); - assert_eq!("'Σ".to_lowercase(), "'σ"); - assert_eq!("''Σ".to_lowercase(), "''σ"); - - assert_eq!("ΑΣΑ".to_lowercase(), "ασα"); - assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α"); - assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α"); - - // https://github.com/rust-lang/rust/issues/124714 - // input lengths around the boundary of the chunk size used by the ascii prefix optimization - assert_eq!("abcdefghijklmnoΣ".to_lowercase(), "abcdefghijklmnoς"); - assert_eq!("abcdefghijklmnopΣ".to_lowercase(), "abcdefghijklmnopς"); - assert_eq!("abcdefghijklmnopqΣ".to_lowercase(), "abcdefghijklmnopqς"); - - // a really long string that has it's lowercase form - // even longer. this tests that implementations don't assume - // an incorrect upper bound on allocations - let upper = str::repeat("İ", 512); - let lower = str::repeat("i̇", 512); - assert_eq!(upper.to_lowercase(), lower); - - // a really long ascii-only string. - // This test that the ascii hot-path - // functions correctly - let upper = str::repeat("A", 511); - let lower = str::repeat("a", 511); - assert_eq!(upper.to_lowercase(), lower); -} - -#[test] -fn to_uppercase() { - assert_eq!("".to_uppercase(), ""); - assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ"); -} - -#[test] -fn test_into_string() { - // The only way to acquire a Box in the first place is through a String, so just - // test that we can round-trip between Box and String. - let string = String::from("Some text goes here"); - assert_eq!(string.clone().into_boxed_str().into_string(), string); -} - -#[test] -fn test_box_slice_clone() { - let data = String::from("hello HELLO hello HELLO yes YES 5 中ä华!!!"); - let data2 = data.clone().into_boxed_str().clone().into_string(); - - assert_eq!(data, data2); -} - -#[test] -fn test_cow_from() { - let borrowed = "borrowed"; - let owned = String::from("owned"); - match (Cow::from(owned.clone()), Cow::from(borrowed)) { - (Cow::Owned(o), Cow::Borrowed(b)) => assert!(o == owned && b == borrowed), - _ => panic!("invalid `Cow::from`"), - } -} - -#[test] -fn test_repeat() { - assert_eq!("".repeat(3), ""); - assert_eq!("abc".repeat(0), ""); - assert_eq!("α".repeat(3), "ααα"); -} - -mod pattern { - use std::str::pattern::SearchStep::{self, Done, Match, Reject}; - use std::str::pattern::{Pattern, ReverseSearcher, Searcher}; - - macro_rules! make_test { - ($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => { - #[allow(unused_imports)] - mod $name { - use std::str::pattern::SearchStep::{Match, Reject}; - use super::{cmp_search_to_vec}; - #[test] - fn fwd() { - cmp_search_to_vec(false, $p, $h, vec![$($e),*]); - } - #[test] - fn bwd() { - cmp_search_to_vec(true, $p, $h, vec![$($e),*]); - } - } - } - } - - fn cmp_search_to_vec

(rev: bool, pat: P, haystack: &str, right: Vec) - where - P: for<'a> Pattern: ReverseSearcher<'a>>, - { - let mut searcher = pat.into_searcher(haystack); - let mut v = vec![]; - loop { - match if !rev { searcher.next() } else { searcher.next_back() } { - Match(a, b) => v.push(Match(a, b)), - Reject(a, b) => v.push(Reject(a, b)), - Done => break, - } - } - if rev { - v.reverse(); - } - - let mut first_index = 0; - let mut err = None; - - for (i, e) in right.iter().enumerate() { - match *e { - Match(a, b) | Reject(a, b) if a <= b && a == first_index => { - first_index = b; - } - _ => { - err = Some(i); - break; - } - } - } - - if let Some(err) = err { - panic!("Input skipped range at {err}"); - } - - if first_index != haystack.len() { - panic!("Did not cover whole input"); - } - - assert_eq!(v, right); - } - - make_test!( - str_searcher_ascii_haystack, - "bb", - "abbcbbd", - [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Reject(6, 7),] - ); - make_test!( - str_searcher_ascii_haystack_seq, - "bb", - "abbcbbbbd", - [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Match(6, 8), Reject(8, 9),] - ); - make_test!( - str_searcher_empty_needle_ascii_haystack, - "", - "abbcbbd", - [ - Match(0, 0), - Reject(0, 1), - Match(1, 1), - Reject(1, 2), - Match(2, 2), - Reject(2, 3), - Match(3, 3), - Reject(3, 4), - Match(4, 4), - Reject(4, 5), - Match(5, 5), - Reject(5, 6), - Match(6, 6), - Reject(6, 7), - Match(7, 7), - ] - ); - make_test!( - str_searcher_multibyte_haystack, - " ", - "├──", - [Reject(0, 3), Reject(3, 6), Reject(6, 9),] - ); - make_test!( - str_searcher_empty_needle_multibyte_haystack, - "", - "├──", - [ - Match(0, 0), - Reject(0, 3), - Match(3, 3), - Reject(3, 6), - Match(6, 6), - Reject(6, 9), - Match(9, 9), - ] - ); - make_test!(str_searcher_empty_needle_empty_haystack, "", "", [Match(0, 0),]); - make_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", []); - make_test!( - char_searcher_ascii_haystack, - 'b', - "abbcbbd", - [ - Reject(0, 1), - Match(1, 2), - Match(2, 3), - Reject(3, 4), - Match(4, 5), - Match(5, 6), - Reject(6, 7), - ] - ); - make_test!( - char_searcher_multibyte_haystack, - ' ', - "├──", - [Reject(0, 3), Reject(3, 6), Reject(6, 9),] - ); - make_test!( - char_searcher_short_haystack, - '\u{1F4A9}', - "* \t", - [Reject(0, 1), Reject(1, 2), Reject(2, 3),] - ); - - // See #85462 - #[test] - fn str_searcher_empty_needle_after_done() { - // Empty needle and haystack - { - let mut searcher = "".into_searcher(""); - - assert_eq!(searcher.next(), SearchStep::Match(0, 0)); - assert_eq!(searcher.next(), SearchStep::Done); - assert_eq!(searcher.next(), SearchStep::Done); - assert_eq!(searcher.next(), SearchStep::Done); - - let mut searcher = "".into_searcher(""); - - assert_eq!(searcher.next_back(), SearchStep::Match(0, 0)); - assert_eq!(searcher.next_back(), SearchStep::Done); - assert_eq!(searcher.next_back(), SearchStep::Done); - assert_eq!(searcher.next_back(), SearchStep::Done); - } - // Empty needle and non-empty haystack - { - let mut searcher = "".into_searcher("a"); - - assert_eq!(searcher.next(), SearchStep::Match(0, 0)); - assert_eq!(searcher.next(), SearchStep::Reject(0, 1)); - assert_eq!(searcher.next(), SearchStep::Match(1, 1)); - assert_eq!(searcher.next(), SearchStep::Done); - assert_eq!(searcher.next(), SearchStep::Done); - assert_eq!(searcher.next(), SearchStep::Done); - - let mut searcher = "".into_searcher("a"); - - assert_eq!(searcher.next_back(), SearchStep::Match(1, 1)); - assert_eq!(searcher.next_back(), SearchStep::Reject(0, 1)); - assert_eq!(searcher.next_back(), SearchStep::Match(0, 0)); - assert_eq!(searcher.next_back(), SearchStep::Done); - assert_eq!(searcher.next_back(), SearchStep::Done); - assert_eq!(searcher.next_back(), SearchStep::Done); - } - } -} - -macro_rules! generate_iterator_test { - { - $name:ident { - $( - ($($arg:expr),*) -> [$($t:tt)*]; - )* - } - with $fwd:expr, $bwd:expr; - } => { - #[test] - fn $name() { - $( - { - let res = vec![$($t)*]; - - let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect(); - assert_eq!(fwd_vec, res); - - let mut bwd_vec: Vec<_> = ($bwd)($($arg),*).collect(); - bwd_vec.reverse(); - assert_eq!(bwd_vec, res); - } - )* - } - }; - { - $name:ident { - $( - ($($arg:expr),*) -> [$($t:tt)*]; - )* - } - with $fwd:expr; - } => { - #[test] - fn $name() { - $( - { - let res = vec![$($t)*]; - - let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect(); - assert_eq!(fwd_vec, res); - } - )* - } - } -} - -generate_iterator_test! { - double_ended_split { - ("foo.bar.baz", '.') -> ["foo", "bar", "baz"]; - ("foo::bar::baz", "::") -> ["foo", "bar", "baz"]; - } - with str::split, str::rsplit; -} - -generate_iterator_test! { - double_ended_split_terminator { - ("foo;bar;baz;", ';') -> ["foo", "bar", "baz"]; - } - with str::split_terminator, str::rsplit_terminator; -} - -generate_iterator_test! { - double_ended_matches { - ("a1b2c3", char::is_numeric) -> ["1", "2", "3"]; - } - with str::matches, str::rmatches; -} - -generate_iterator_test! { - double_ended_match_indices { - ("a1b2c3", char::is_numeric) -> [(1, "1"), (3, "2"), (5, "3")]; - } - with str::match_indices, str::rmatch_indices; -} - -generate_iterator_test! { - not_double_ended_splitn { - ("foo::bar::baz", 2, "::") -> ["foo", "bar::baz"]; - } - with str::splitn; -} - -generate_iterator_test! { - not_double_ended_rsplitn { - ("foo::bar::baz", 2, "::") -> ["baz", "foo::bar"]; - } - with str::rsplitn; -} - -#[test] -fn different_str_pattern_forwarding_lifetimes() { - use std::str::pattern::Pattern; - - fn foo

(rev: bool, pat: P, haystack: &str, right: Vec) + where + P: for<'a> Pattern: ReverseSearcher<'a>>, + { + let mut searcher = pat.into_searcher(haystack); + let mut v = vec![]; + loop { + match if !rev { searcher.next() } else { searcher.next_back() } { + Match(a, b) => v.push(Match(a, b)), + Reject(a, b) => v.push(Reject(a, b)), + Done => break, + } + } + if rev { + v.reverse(); + } + + let mut first_index = 0; + let mut err = None; + + for (i, e) in right.iter().enumerate() { + match *e { + Match(a, b) | Reject(a, b) if a <= b && a == first_index => { + first_index = b; + } + _ => { + err = Some(i); + break; + } + } + } + + if let Some(err) = err { + panic!("Input skipped range at {err}"); + } + + if first_index != haystack.len() { + panic!("Did not cover whole input"); + } + + assert_eq!(v, right); + } + + make_test!( + str_searcher_ascii_haystack, + "bb", + "abbcbbd", + [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Reject(6, 7),] + ); + make_test!( + str_searcher_ascii_haystack_seq, + "bb", + "abbcbbbbd", + [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Match(6, 8), Reject(8, 9),] + ); + make_test!( + str_searcher_empty_needle_ascii_haystack, + "", + "abbcbbd", + [ + Match(0, 0), + Reject(0, 1), + Match(1, 1), + Reject(1, 2), + Match(2, 2), + Reject(2, 3), + Match(3, 3), + Reject(3, 4), + Match(4, 4), + Reject(4, 5), + Match(5, 5), + Reject(5, 6), + Match(6, 6), + Reject(6, 7), + Match(7, 7), + ] + ); + make_test!( + str_searcher_multibyte_haystack, + " ", + "├──", + [Reject(0, 3), Reject(3, 6), Reject(6, 9),] + ); + make_test!( + str_searcher_empty_needle_multibyte_haystack, + "", + "├──", + [ + Match(0, 0), + Reject(0, 3), + Match(3, 3), + Reject(3, 6), + Match(6, 6), + Reject(6, 9), + Match(9, 9), + ] + ); + make_test!(str_searcher_empty_needle_empty_haystack, "", "", [Match(0, 0),]); + make_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", []); + make_test!( + char_searcher_ascii_haystack, + 'b', + "abbcbbd", + [ + Reject(0, 1), + Match(1, 2), + Match(2, 3), + Reject(3, 4), + Match(4, 5), + Match(5, 6), + Reject(6, 7), + ] + ); + make_test!( + char_searcher_multibyte_haystack, + ' ', + "├──", + [Reject(0, 3), Reject(3, 6), Reject(6, 9),] + ); + make_test!( + char_searcher_short_haystack, + '\u{1F4A9}', + "* \t", + [Reject(0, 1), Reject(1, 2), Reject(2, 3),] + ); + + // See #85462 + #[test] + fn str_searcher_empty_needle_after_done() { + // Empty needle and haystack + { + let mut searcher = "".into_searcher(""); + + assert_eq!(searcher.next(), SearchStep::Match(0, 0)); + assert_eq!(searcher.next(), SearchStep::Done); + assert_eq!(searcher.next(), SearchStep::Done); + assert_eq!(searcher.next(), SearchStep::Done); + + let mut searcher = "".into_searcher(""); + + assert_eq!(searcher.next_back(), SearchStep::Match(0, 0)); + assert_eq!(searcher.next_back(), SearchStep::Done); + assert_eq!(searcher.next_back(), SearchStep::Done); + assert_eq!(searcher.next_back(), SearchStep::Done); + } + // Empty needle and non-empty haystack + { + let mut searcher = "".into_searcher("a"); + + assert_eq!(searcher.next(), SearchStep::Match(0, 0)); + assert_eq!(searcher.next(), SearchStep::Reject(0, 1)); + assert_eq!(searcher.next(), SearchStep::Match(1, 1)); + assert_eq!(searcher.next(), SearchStep::Done); + assert_eq!(searcher.next(), SearchStep::Done); + assert_eq!(searcher.next(), SearchStep::Done); + + let mut searcher = "".into_searcher("a"); + + assert_eq!(searcher.next_back(), SearchStep::Match(1, 1)); + assert_eq!(searcher.next_back(), SearchStep::Reject(0, 1)); + assert_eq!(searcher.next_back(), SearchStep::Match(0, 0)); + assert_eq!(searcher.next_back(), SearchStep::Done); + assert_eq!(searcher.next_back(), SearchStep::Done); + assert_eq!(searcher.next_back(), SearchStep::Done); + } + } +} + +macro_rules! generate_iterator_test { + { + $name:ident { + $( + ($($arg:expr),*) -> [$($t:tt)*]; + )* + } + with $fwd:expr, $bwd:expr; + } => { + #[test] + fn $name() { + $( + { + let res = vec![$($t)*]; + + let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect(); + assert_eq!(fwd_vec, res); + + let mut bwd_vec: Vec<_> = ($bwd)($($arg),*).collect(); + bwd_vec.reverse(); + assert_eq!(bwd_vec, res); + } + )* + } + }; + { + $name:ident { + $( + ($($arg:expr),*) -> [$($t:tt)*]; + )* + } + with $fwd:expr; + } => { + #[test] + fn $name() { + $( + { + let res = vec![$($t)*]; + + let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect(); + assert_eq!(fwd_vec, res); + } + )* + } + } +} + +generate_iterator_test! { + double_ended_split { + ("foo.bar.baz", '.') -> ["foo", "bar", "baz"]; + ("foo::bar::baz", "::") -> ["foo", "bar", "baz"]; + } + with str::split, str::rsplit; +} + +generate_iterator_test! { + double_ended_split_terminator { + ("foo;bar;baz;", ';') -> ["foo", "bar", "baz"]; + } + with str::split_terminator, str::rsplit_terminator; +} + +generate_iterator_test! { + double_ended_matches { + ("a1b2c3", char::is_numeric) -> ["1", "2", "3"]; + } + with str::matches, str::rmatches; +} + +generate_iterator_test! { + double_ended_match_indices { + ("a1b2c3", char::is_numeric) -> [(1, "1"), (3, "2"), (5, "3")]; + } + with str::match_indices, str::rmatch_indices; +} + +generate_iterator_test! { + not_double_ended_splitn { + ("foo::bar::baz", 2, "::") -> ["foo", "bar::baz"]; + } + with str::splitn; +} + +generate_iterator_test! { + not_double_ended_rsplitn { + ("foo::bar::baz", 2, "::") -> ["baz", "foo::bar"]; + } + with str::rsplitn; +} + +#[test] +fn different_str_pattern_forwarding_lifetimes() { + use std::str::pattern::Pattern; + + fn foo

(p: P) + where + for<'b> &'b P: Pattern, + { + for _ in 0..3 { + "asdf".find(&p); + } + } + + foo::<&str>("x"); +} + +#[test] +fn test_str_multiline() { + let a: String = "this \ +is a test" + .to_string(); + let b: String = "this \ + is \ + another \ + test" + .to_string(); + assert_eq!(a, "this is a test".to_string()); + assert_eq!(b, "this is another test".to_string()); +} + +#[test] +fn test_str_escapes() { + let x = "\\\\\ + "; + assert_eq!(x, r"\\"); // extraneous whitespace stripped +} + +#[test] +fn const_str_ptr() { + const A: [u8; 2] = ['h' as u8, 'i' as u8]; + const B: &'static [u8; 2] = &A; + const C: *const u8 = B as *const u8; + + // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131) + #[cfg(not(miri))] + { + let foo = &A as *const u8; + assert_eq!(foo, C); + } + + unsafe { + assert_eq!(from_utf8_unchecked(&A), "hi"); + assert_eq!(*C, A[0]); + assert_eq!(*(&B[0] as *const u8), A[0]); + } +} + +#[test] +fn utf8() { + let yen: char = '¥'; // 0xa5 + let c_cedilla: char = 'ç'; // 0xe7 + let thorn: char = 'þ'; // 0xfe + let y_diaeresis: char = 'ÿ'; // 0xff + let pi: char = 'Π'; // 0x3a0 + + assert_eq!(yen as isize, 0xa5); + assert_eq!(c_cedilla as isize, 0xe7); + assert_eq!(thorn as isize, 0xfe); + assert_eq!(y_diaeresis as isize, 0xff); + assert_eq!(pi as isize, 0x3a0); + + assert_eq!(pi as isize, '\u{3a0}' as isize); + assert_eq!('\x0a' as isize, '\n' as isize); + + let bhutan: String = "འབྲུག་ཡུལ།".to_string(); + let japan: String = "日本".to_string(); + let uzbekistan: String = "Ўзбекистон".to_string(); + let austria: String = "Österreich".to_string(); + + let bhutan_e: String = + "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string(); + let japan_e: String = "\u{65e5}\u{672c}".to_string(); + let uzbekistan_e: String = + "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string(); + let austria_e: String = "\u{d6}sterreich".to_string(); + + let oo: char = 'Ö'; + assert_eq!(oo as isize, 0xd6); + + fn check_str_eq(a: String, b: String) { + let mut i: isize = 0; + for ab in a.bytes() { + println!("{i}"); + println!("{ab}"); + let bb: u8 = b.as_bytes()[i as usize]; + println!("{bb}"); + assert_eq!(ab, bb); + i += 1; + } + } + + check_str_eq(bhutan, bhutan_e); + check_str_eq(japan, japan_e); + check_str_eq(uzbekistan, uzbekistan_e); + check_str_eq(austria, austria_e); +} + +#[test] +fn utf8_chars() { + // Chars of 1, 2, 3, and 4 bytes + let chs: Vec = vec!['e', 'é', '€', '\u{10000}']; + let s: String = chs.iter().cloned().collect(); + let schs: Vec = s.chars().collect(); + + assert_eq!(s.len(), 10); + assert_eq!(s.chars().count(), 4); + assert_eq!(schs.len(), 4); + assert_eq!(schs.iter().cloned().collect::(), s); + + assert!(from_utf8(s.as_bytes()).is_ok()); + // invalid prefix + assert!(!from_utf8(&[0x80]).is_ok()); + // invalid 2 byte prefix + assert!(!from_utf8(&[0xc0]).is_ok()); + assert!(!from_utf8(&[0xc0, 0x10]).is_ok()); + // invalid 3 byte prefix + assert!(!from_utf8(&[0xe0]).is_ok()); + assert!(!from_utf8(&[0xe0, 0x10]).is_ok()); + assert!(!from_utf8(&[0xe0, 0xff, 0x10]).is_ok()); + // invalid 4 byte prefix + assert!(!from_utf8(&[0xf0]).is_ok()); + assert!(!from_utf8(&[0xf0, 0x10]).is_ok()); + assert!(!from_utf8(&[0xf0, 0xff, 0x10]).is_ok()); + assert!(!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()); +} + +#[test] +fn utf8_char_counts() { + let strs = [("e", 1), ("é", 1), ("€", 1), ("\u{10000}", 1), ("eé€\u{10000}", 4)]; + let spread = if cfg!(miri) { 4 } else { 8 }; + let mut reps = [8, 64, 256, 512] + .iter() + .copied() + .flat_map(|n| n - spread..=n + spread) + .collect::>(); + if cfg!(not(miri)) { + reps.extend([1024, 1 << 16].iter().copied().flat_map(|n| n - spread..=n + spread)); + } + let counts = if cfg!(miri) { 0..1 } else { 0..8 }; + let padding = counts.map(|len| " ".repeat(len)).collect::>(); + + for repeat in reps { + for (tmpl_str, tmpl_char_count) in strs { + for pad_start in &padding { + for pad_end in &padding { + // Create a string with padding... + let with_padding = + format!("{}{}{}", pad_start, tmpl_str.repeat(repeat), pad_end); + // ...and then skip past that padding. This should ensure + // that we test several different alignments for both head + // and tail. + let si = pad_start.len(); + let ei = with_padding.len() - pad_end.len(); + let target = &with_padding[si..ei]; + + assert!(!target.starts_with(" ") && !target.ends_with(" ")); + let expected_count = tmpl_char_count * repeat; + assert_eq!( + expected_count, + target.chars().count(), + "wrong count for `{:?}.repeat({})` (padding: `{:?}`)", + tmpl_str, + repeat, + (pad_start.len(), pad_end.len()), + ); + } + } + } + } +} + +#[test] +fn floor_char_boundary() { + fn check_many(s: &str, arg: impl IntoIterator, ret: usize) { + for idx in arg { + assert_eq!( + s.floor_char_boundary(idx), + ret, + "{:?}.floor_char_boundary({:?}) != {:?}", + s, + idx, + ret + ); + } + } + + // edge case + check_many("", [0, 1, isize::MAX as usize, usize::MAX], 0); + + // basic check + check_many("x", [0], 0); + check_many("x", [1, isize::MAX as usize, usize::MAX], 1); + + // 1-byte chars + check_many("jp", [0], 0); + check_many("jp", [1], 1); + check_many("jp", 2..4, 2); + + // 2-byte chars + check_many("ĵƥ", 0..2, 0); + check_many("ĵƥ", 2..4, 2); + check_many("ĵƥ", 4..6, 4); + + // 3-byte chars + check_many("日本", 0..3, 0); + check_many("日本", 3..6, 3); + check_many("日本", 6..8, 6); + + // 4-byte chars + check_many("🇯🇵", 0..4, 0); + check_many("🇯🇵", 4..8, 4); + check_many("🇯🇵", 8..10, 8); +} + +#[test] +fn ceil_char_boundary() { + fn check_many(s: &str, arg: impl IntoIterator, ret: usize) { + for idx in arg { + assert_eq!( + s.ceil_char_boundary(idx), + ret, + "{:?}.ceil_char_boundary({:?}) != {:?}", + s, + idx, + ret + ); + } + } + + // edge case + check_many("", [0], 0); + + // basic check + check_many("x", [0], 0); + check_many("x", [1], 1); + + // 1-byte chars + check_many("jp", [0], 0); + check_many("jp", [1], 1); + check_many("jp", [2], 2); + + // 2-byte chars + check_many("ĵƥ", 0..=0, 0); + check_many("ĵƥ", 1..=2, 2); + check_many("ĵƥ", 3..=4, 4); + + // 3-byte chars + check_many("日本", 0..=0, 0); + check_many("日本", 1..=3, 3); + check_many("日本", 4..=6, 6); + + // 4-byte chars + check_many("🇯🇵", 0..=0, 0); + check_many("🇯🇵", 1..=4, 4); + check_many("🇯🇵", 5..=8, 8); + + // above len + check_many("hello", 5..=10, 5); +} diff --git a/library/alloctests/tests/string.rs b/library/alloctests/tests/string.rs new file mode 100644 index 00000000000..d996c55f946 --- /dev/null +++ b/library/alloctests/tests/string.rs @@ -0,0 +1,914 @@ +use std::assert_matches::assert_matches; +use std::borrow::Cow; +use std::cell::Cell; +use std::collections::TryReserveErrorKind::*; +use std::ops::Bound::*; +use std::ops::{Bound, RangeBounds}; +use std::{panic, str}; + +pub trait IntoCow<'a, B: ?Sized> +where + B: ToOwned, +{ + fn into_cow(self) -> Cow<'a, B>; +} + +impl<'a> IntoCow<'a, str> for String { + fn into_cow(self) -> Cow<'a, str> { + Cow::Owned(self) + } +} + +impl<'a> IntoCow<'a, str> for &'a str { + fn into_cow(self) -> Cow<'a, str> { + Cow::Borrowed(self) + } +} + +#[test] +fn test_from_str() { + let owned: Option = "string".parse().ok(); + assert_eq!(owned.as_ref().map(|s| &**s), Some("string")); +} + +#[test] +fn test_from_cow_str() { + assert_eq!(String::from(Cow::Borrowed("string")), "string"); + assert_eq!(String::from(Cow::Owned(String::from("string"))), "string"); +} + +#[test] +fn test_unsized_to_string() { + let s: &str = "abc"; + let _: String = (*s).to_string(); +} + +#[test] +fn test_from_utf8() { + let xs = b"hello".to_vec(); + assert_eq!(String::from_utf8(xs).unwrap(), String::from("hello")); + + let xs = "ศไทย中华Việt Nam".as_bytes().to_vec(); + assert_eq!(String::from_utf8(xs).unwrap(), String::from("ศไทย中华Việt Nam")); + + let xs = b"hello\xFF".to_vec(); + let err = String::from_utf8(xs).unwrap_err(); + assert_eq!(err.as_bytes(), b"hello\xff"); + let err_clone = err.clone(); + assert_eq!(err, err_clone); + assert_eq!(err.into_bytes(), b"hello\xff".to_vec()); + assert_eq!(err_clone.utf8_error().valid_up_to(), 5); +} + +#[test] +fn test_from_utf8_lossy() { + let xs = b"hello"; + let ys: Cow<'_, str> = "hello".into_cow(); + assert_eq!(String::from_utf8_lossy(xs), ys); + + let xs = "ศไทย中华Việt Nam".as_bytes(); + let ys: Cow<'_, str> = "ศไทย中华Việt Nam".into_cow(); + assert_eq!(String::from_utf8_lossy(xs), ys); + + let xs = b"Hello\xC2 There\xFF Goodbye"; + assert_eq!( + String::from_utf8_lossy(xs), + String::from("Hello\u{FFFD} There\u{FFFD} Goodbye").into_cow() + ); + + let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; + assert_eq!( + String::from_utf8_lossy(xs), + String::from("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye").into_cow() + ); + + let xs = b"\xF5foo\xF5\x80bar"; + assert_eq!( + String::from_utf8_lossy(xs), + String::from("\u{FFFD}foo\u{FFFD}\u{FFFD}bar").into_cow() + ); + + let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz"; + assert_eq!( + String::from_utf8_lossy(xs), + String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}baz").into_cow() + ); + + let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz"; + assert_eq!( + String::from_utf8_lossy(xs), + String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}\u{FFFD}baz").into_cow() + ); + + let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar"; + assert_eq!( + String::from_utf8_lossy(xs), + String::from("\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}foo\u{10000}bar").into_cow() + ); + + // surrogates + let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar"; + assert_eq!( + String::from_utf8_lossy(xs), + String::from("\u{FFFD}\u{FFFD}\u{FFFD}foo\u{FFFD}\u{FFFD}\u{FFFD}bar").into_cow() + ); +} + +#[test] +fn test_fromutf8error_into_lossy() { + fn func(input: &[u8]) -> String { + String::from_utf8(input.to_owned()).unwrap_or_else(|e| e.into_utf8_lossy()) + } + + let xs = b"hello"; + let ys = "hello".to_owned(); + assert_eq!(func(xs), ys); + + let xs = "ศไทย中华Việt Nam".as_bytes(); + let ys = "ศไทย中华Việt Nam".to_owned(); + assert_eq!(func(xs), ys); + + let xs = b"Hello\xC2 There\xFF Goodbye"; + assert_eq!(func(xs), "Hello\u{FFFD} There\u{FFFD} Goodbye".to_owned()); + + let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; + assert_eq!(func(xs), "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye".to_owned()); + + let xs = b"\xF5foo\xF5\x80bar"; + assert_eq!(func(xs), "\u{FFFD}foo\u{FFFD}\u{FFFD}bar".to_owned()); + + let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz"; + assert_eq!(func(xs), "\u{FFFD}foo\u{FFFD}bar\u{FFFD}baz".to_owned()); + + let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz"; + assert_eq!(func(xs), "\u{FFFD}foo\u{FFFD}bar\u{FFFD}\u{FFFD}baz".to_owned()); + + let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar"; + assert_eq!(func(xs), "\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}foo\u{10000}bar".to_owned()); + + // surrogates + let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar"; + assert_eq!(func(xs), "\u{FFFD}\u{FFFD}\u{FFFD}foo\u{FFFD}\u{FFFD}\u{FFFD}bar".to_owned()); +} + +#[test] +fn test_from_utf16() { + let pairs = [ + ( + String::from("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"), + vec![ + 0xd800, 0xdf45, 0xd800, 0xdf3f, 0xd800, 0xdf3b, 0xd800, 0xdf46, 0xd800, 0xdf39, + 0xd800, 0xdf3b, 0xd800, 0xdf30, 0x000a, + ], + ), + ( + String::from("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"), + vec![ + 0xd801, 0xdc12, 0xd801, 0xdc49, 0xd801, 0xdc2e, 0xd801, 0xdc40, 0xd801, 0xdc32, + 0xd801, 0xdc4b, 0x0020, 0xd801, 0xdc0f, 0xd801, 0xdc32, 0xd801, 0xdc4d, 0x000a, + ], + ), + ( + String::from("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"), + vec![ + 0xd800, 0xdf00, 0xd800, 0xdf16, 0xd800, 0xdf0b, 0xd800, 0xdf04, 0xd800, 0xdf11, + 0xd800, 0xdf09, 0x00b7, 0xd800, 0xdf0c, 0xd800, 0xdf04, 0xd800, 0xdf15, 0xd800, + 0xdf04, 0xd800, 0xdf0b, 0xd800, 0xdf09, 0xd800, 0xdf11, 0x000a, + ], + ), + ( + String::from("𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n"), + vec![ + 0xd801, 0xdc8b, 0xd801, 0xdc98, 0xd801, 0xdc88, 0xd801, 0xdc91, 0xd801, 0xdc9b, + 0xd801, 0xdc92, 0x0020, 0xd801, 0xdc95, 0xd801, 0xdc93, 0x0020, 0xd801, 0xdc88, + 0xd801, 0xdc9a, 0xd801, 0xdc8d, 0x0020, 0xd801, 0xdc8f, 0xd801, 0xdc9c, 0xd801, + 0xdc92, 0xd801, 0xdc96, 0xd801, 0xdc86, 0x0020, 0xd801, 0xdc95, 0xd801, 0xdc86, + 0x000a, + ], + ), + // Issue #12318, even-numbered non-BMP planes + (String::from("\u{20000}"), vec![0xD840, 0xDC00]), + ]; + + for p in &pairs { + let (s, u) = (*p).clone(); + let s_as_utf16 = s.encode_utf16().collect::>(); + let u_as_string = String::from_utf16(&u).unwrap(); + + assert!(core::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); + assert_eq!(s_as_utf16, u); + + assert_eq!(u_as_string, s); + assert_eq!(String::from_utf16_lossy(&u), s); + + assert_eq!(String::from_utf16(&s_as_utf16).unwrap(), s); + assert_eq!(u_as_string.encode_utf16().collect::>(), u); + } +} + +#[test] +fn test_utf16_invalid() { + // completely positive cases tested above. + // lead + eof + assert!(String::from_utf16(&[0xD800]).is_err()); + // lead + lead + assert!(String::from_utf16(&[0xD800, 0xD800]).is_err()); + + // isolated trail + assert!(String::from_utf16(&[0x0061, 0xDC00]).is_err()); + + // general + assert!(String::from_utf16(&[0xD800, 0xd801, 0xdc8b, 0xD800]).is_err()); +} + +#[test] +fn test_from_utf16_lossy() { + // completely positive cases tested above. + // lead + eof + assert_eq!(String::from_utf16_lossy(&[0xD800]), String::from("\u{FFFD}")); + // lead + lead + assert_eq!(String::from_utf16_lossy(&[0xD800, 0xD800]), String::from("\u{FFFD}\u{FFFD}")); + + // isolated trail + assert_eq!(String::from_utf16_lossy(&[0x0061, 0xDC00]), String::from("a\u{FFFD}")); + + // general + assert_eq!( + String::from_utf16_lossy(&[0xD800, 0xd801, 0xdc8b, 0xD800]), + String::from("\u{FFFD}𐒋\u{FFFD}") + ); +} + +#[test] +fn test_push_bytes() { + let mut s = String::from("ABC"); + unsafe { + let mv = s.as_mut_vec(); + mv.extend_from_slice(&[b'D']); + } + assert_eq!(s, "ABCD"); +} + +#[test] +fn test_push_str() { + let mut s = String::new(); + s.push_str(""); + assert_eq!(&s[0..], ""); + s.push_str("abc"); + assert_eq!(&s[0..], "abc"); + s.push_str("ประเทศไทย中华Việt Nam"); + assert_eq!(&s[0..], "abcประเทศไทย中华Việt Nam"); +} + +#[test] +fn test_add_assign() { + let mut s = String::new(); + s += ""; + assert_eq!(s.as_str(), ""); + s += "abc"; + assert_eq!(s.as_str(), "abc"); + s += "ประเทศไทย中华Việt Nam"; + assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam"); +} + +#[test] +fn test_push() { + let mut data = String::from("ประเทศไทย中"); + data.push('华'); + data.push('b'); // 1 byte + data.push('¢'); // 2 byte + data.push('€'); // 3 byte + data.push('𤭢'); // 4 byte + assert_eq!(data, "ประเทศไทย中华b¢€𤭢"); +} + +#[test] +fn test_pop() { + let mut data = String::from("ประเทศไทย中华b¢€𤭢"); + assert_eq!(data.pop().unwrap(), '𤭢'); // 4 bytes + assert_eq!(data.pop().unwrap(), '€'); // 3 bytes + assert_eq!(data.pop().unwrap(), '¢'); // 2 bytes + assert_eq!(data.pop().unwrap(), 'b'); // 1 bytes + assert_eq!(data.pop().unwrap(), '华'); + assert_eq!(data, "ประเทศไทย中"); +} + +#[test] +fn test_split_off_empty() { + let orig = "Hello, world!"; + let mut split = String::from(orig); + let empty: String = split.split_off(orig.len()); + assert!(empty.is_empty()); +} + +#[test] +#[should_panic] +fn test_split_off_past_end() { + let orig = "Hello, world!"; + let mut split = String::from(orig); + let _ = split.split_off(orig.len() + 1); +} + +#[test] +#[should_panic] +fn test_split_off_mid_char() { + let mut shan = String::from("山"); + let _broken_mountain = shan.split_off(1); +} + +#[test] +fn test_split_off_ascii() { + let mut ab = String::from("ABCD"); + let orig_capacity = ab.capacity(); + let cd = ab.split_off(2); + assert_eq!(ab, "AB"); + assert_eq!(cd, "CD"); + assert_eq!(ab.capacity(), orig_capacity); +} + +#[test] +fn test_split_off_unicode() { + let mut nihon = String::from("日本語"); + let orig_capacity = nihon.capacity(); + let go = nihon.split_off("日本".len()); + assert_eq!(nihon, "日本"); + assert_eq!(go, "語"); + assert_eq!(nihon.capacity(), orig_capacity); +} + +#[test] +fn test_str_truncate() { + let mut s = String::from("12345"); + s.truncate(5); + assert_eq!(s, "12345"); + s.truncate(3); + assert_eq!(s, "123"); + s.truncate(0); + assert_eq!(s, ""); + + let mut s = String::from("12345"); + let p = s.as_ptr(); + s.truncate(3); + s.push_str("6"); + let p_ = s.as_ptr(); + assert_eq!(p_, p); +} + +#[test] +fn test_str_truncate_invalid_len() { + let mut s = String::from("12345"); + s.truncate(6); + assert_eq!(s, "12345"); +} + +#[test] +#[should_panic] +fn test_str_truncate_split_codepoint() { + let mut s = String::from("\u{FC}"); // ü + s.truncate(1); +} + +#[test] +fn test_str_clear() { + let mut s = String::from("12345"); + s.clear(); + assert_eq!(s.len(), 0); + assert_eq!(s, ""); +} + +#[test] +fn test_str_add() { + let a = String::from("12345"); + let b = a + "2"; + let b = b + "2"; + assert_eq!(b.len(), 7); + assert_eq!(b, "1234522"); +} + +#[test] +fn remove() { + let mut s = "ศไทย中华Việt Nam; foobar".to_string(); + assert_eq!(s.remove(0), 'ศ'); + assert_eq!(s.len(), 33); + assert_eq!(s, "ไทย中华Việt Nam; foobar"); + assert_eq!(s.remove(17), 'ệ'); + assert_eq!(s, "ไทย中华Vit Nam; foobar"); +} + +#[test] +#[should_panic] +fn remove_bad() { + "ศ".to_string().remove(1); +} + +#[test] +fn test_remove_matches() { + // test_single_pattern_occurrence + let mut s = "abc".to_string(); + s.remove_matches('b'); + assert_eq!(s, "ac"); + // repeat_test_single_pattern_occurrence + s.remove_matches('b'); + assert_eq!(s, "ac"); + + // test_single_character_pattern + let mut s = "abcb".to_string(); + s.remove_matches('b'); + assert_eq!(s, "ac"); + + // test_pattern_with_special_characters + let mut s = "ศไทย中华Việt Nam; foobarศ".to_string(); + s.remove_matches('ศ'); + assert_eq!(s, "ไทย中华Việt Nam; foobar"); + + // test_pattern_empty_text_and_pattern + let mut s = "".to_string(); + s.remove_matches(""); + assert_eq!(s, ""); + + // test_pattern_empty_text + let mut s = "".to_string(); + s.remove_matches("something"); + assert_eq!(s, ""); + + // test_empty_pattern + let mut s = "Testing with empty pattern.".to_string(); + s.remove_matches(""); + assert_eq!(s, "Testing with empty pattern."); + + // test_multiple_consecutive_patterns_1 + let mut s = "aaaaa".to_string(); + s.remove_matches('a'); + assert_eq!(s, ""); + + // test_multiple_consecutive_patterns_2 + let mut s = "Hello **world****today!**".to_string(); + s.remove_matches("**"); + assert_eq!(s, "Hello worldtoday!"); + + // test_case_insensitive_pattern + let mut s = "CASE ** SeNsItIvE ** PaTtErN.".to_string(); + s.remove_matches("sEnSiTiVe"); + assert_eq!(s, "CASE ** SeNsItIvE ** PaTtErN."); + + // test_pattern_with_digits + let mut s = "123 ** 456 ** 789".to_string(); + s.remove_matches("**"); + assert_eq!(s, "123 456 789"); + + // test_pattern_occurs_after_empty_string + let mut s = "abc X defXghi".to_string(); + s.remove_matches("X"); + assert_eq!(s, "abc defghi"); + + // test_large_pattern + let mut s = "aaaXbbbXcccXdddXeee".to_string(); + s.remove_matches("X"); + assert_eq!(s, "aaabbbcccdddeee"); + + // test_pattern_at_multiple_positions + let mut s = "Pattern ** found ** multiple ** times ** in ** text.".to_string(); + s.remove_matches("**"); + assert_eq!(s, "Pattern found multiple times in text."); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_retain() { + let mut s = String::from("α_β_γ"); + + s.retain(|_| true); + assert_eq!(s, "α_β_γ"); + + s.retain(|c| c != '_'); + assert_eq!(s, "αβγ"); + + s.retain(|c| c != 'β'); + assert_eq!(s, "αγ"); + + s.retain(|c| c == 'α'); + assert_eq!(s, "α"); + + s.retain(|_| false); + assert_eq!(s, ""); + + let mut s = String::from("0è0"); + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let mut count = 0; + s.retain(|_| { + count += 1; + match count { + 1 => false, + 2 => true, + _ => panic!(), + } + }); + })); + assert!(std::str::from_utf8(s.as_bytes()).is_ok()); +} + +#[test] +fn insert() { + let mut s = "foobar".to_string(); + s.insert(0, 'ệ'); + assert_eq!(s, "ệfoobar"); + s.insert(6, 'ย'); + assert_eq!(s, "ệfooยbar"); +} + +#[test] +#[should_panic] +fn insert_bad1() { + "".to_string().insert(1, 't'); +} +#[test] +#[should_panic] +fn insert_bad2() { + "ệ".to_string().insert(1, 't'); +} + +#[test] +fn test_slicing() { + let s = "foobar".to_string(); + assert_eq!("foobar", &s[..]); + assert_eq!("foo", &s[..3]); + assert_eq!("bar", &s[3..]); + assert_eq!("oob", &s[1..4]); +} + +#[test] +fn test_simple_types() { + assert_eq!(1.to_string(), "1"); + assert_eq!((-1).to_string(), "-1"); + assert_eq!(200.to_string(), "200"); + assert_eq!(2.to_string(), "2"); + assert_eq!(true.to_string(), "true"); + assert_eq!(false.to_string(), "false"); + assert_eq!(("hi".to_string()).to_string(), "hi"); +} + +#[test] +fn test_vectors() { + let x: Vec = vec![]; + assert_eq!(format!("{x:?}"), "[]"); + assert_eq!(format!("{:?}", vec![1]), "[1]"); + assert_eq!(format!("{:?}", vec![1, 2, 3]), "[1, 2, 3]"); + assert!(format!("{:?}", vec![vec![], vec![1], vec![1, 1]]) == "[[], [1], [1, 1]]"); +} + +#[test] +fn test_from_iterator() { + let s = "ศไทย中华Việt Nam".to_string(); + let t = "ศไทย中华"; + let u = "Việt Nam"; + + let a: String = s.chars().collect(); + assert_eq!(s, a); + + let mut b = t.to_string(); + b.extend(u.chars()); + assert_eq!(s, b); + + let c: String = [t, u].into_iter().collect(); + assert_eq!(s, c); + + let mut d = t.to_string(); + d.extend(vec![u]); + assert_eq!(s, d); +} + +#[test] +fn test_drain() { + let mut s = String::from("αβγ"); + assert_eq!(s.drain(2..4).collect::(), "β"); + assert_eq!(s, "αγ"); + + let mut t = String::from("abcd"); + t.drain(..0); + assert_eq!(t, "abcd"); + t.drain(..1); + assert_eq!(t, "bcd"); + t.drain(3..); + assert_eq!(t, "bcd"); + t.drain(..); + assert_eq!(t, ""); +} + +#[test] +#[should_panic] +fn test_drain_start_overflow() { + let mut s = String::from("abc"); + s.drain((Excluded(usize::MAX), Included(0))); +} + +#[test] +#[should_panic] +fn test_drain_end_overflow() { + let mut s = String::from("abc"); + s.drain((Included(0), Included(usize::MAX))); +} + +#[test] +fn test_replace_range() { + let mut s = "Hello, world!".to_owned(); + s.replace_range(7..12, "世界"); + assert_eq!(s, "Hello, 世界!"); +} + +#[test] +#[should_panic] +fn test_replace_range_char_boundary() { + let mut s = "Hello, 世界!".to_owned(); + s.replace_range(..8, ""); +} + +#[test] +fn test_replace_range_inclusive_range() { + let mut v = String::from("12345"); + v.replace_range(2..=3, "789"); + assert_eq!(v, "127895"); + v.replace_range(1..=2, "A"); + assert_eq!(v, "1A895"); +} + +#[test] +#[should_panic] +fn test_replace_range_out_of_bounds() { + let mut s = String::from("12345"); + s.replace_range(5..6, "789"); +} + +#[test] +#[should_panic] +fn test_replace_range_inclusive_out_of_bounds() { + let mut s = String::from("12345"); + s.replace_range(5..=5, "789"); +} + +#[test] +#[should_panic] +fn test_replace_range_start_overflow() { + let mut s = String::from("123"); + s.replace_range((Excluded(usize::MAX), Included(0)), ""); +} + +#[test] +#[should_panic] +fn test_replace_range_end_overflow() { + let mut s = String::from("456"); + s.replace_range((Included(0), Included(usize::MAX)), ""); +} + +#[test] +fn test_replace_range_empty() { + let mut s = String::from("12345"); + s.replace_range(1..2, ""); + assert_eq!(s, "1345"); +} + +#[test] +fn test_replace_range_unbounded() { + let mut s = String::from("12345"); + s.replace_range(.., ""); + assert_eq!(s, ""); +} + +#[test] +fn test_replace_range_evil_start_bound() { + struct EvilRange(Cell); + + impl RangeBounds for EvilRange { + fn start_bound(&self) -> Bound<&usize> { + Bound::Included(if self.0.get() { + &1 + } else { + self.0.set(true); + &0 + }) + } + fn end_bound(&self) -> Bound<&usize> { + Bound::Unbounded + } + } + + let mut s = String::from("🦀"); + s.replace_range(EvilRange(Cell::new(false)), ""); + assert_eq!(Ok(""), str::from_utf8(s.as_bytes())); +} + +#[test] +fn test_replace_range_evil_end_bound() { + struct EvilRange(Cell); + + impl RangeBounds for EvilRange { + fn start_bound(&self) -> Bound<&usize> { + Bound::Included(&0) + } + fn end_bound(&self) -> Bound<&usize> { + Bound::Excluded(if self.0.get() { + &3 + } else { + self.0.set(true); + &4 + }) + } + } + + let mut s = String::from("🦀"); + s.replace_range(EvilRange(Cell::new(false)), ""); + assert_eq!(Ok(""), str::from_utf8(s.as_bytes())); +} + +#[test] +fn test_extend_ref() { + let mut a = "foo".to_string(); + a.extend(&['b', 'a', 'r']); + + assert_eq!(&a, "foobar"); +} + +#[test] +fn test_into_boxed_str() { + let xs = String::from("hello my name is bob"); + let ys = xs.into_boxed_str(); + assert_eq!(&*ys, "hello my name is bob"); +} + +#[test] +fn test_reserve_exact() { + // This is all the same as test_reserve + + let mut s = String::new(); + assert_eq!(s.capacity(), 0); + + s.reserve_exact(2); + assert!(s.capacity() >= 2); + + for _i in 0..16 { + s.push('0'); + } + + assert!(s.capacity() >= 16); + s.reserve_exact(16); + assert!(s.capacity() >= 32); + + s.push('0'); + + s.reserve_exact(16); + assert!(s.capacity() >= 33) +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +fn test_try_with_capacity() { + let string = String::try_with_capacity(1000).unwrap(); + assert_eq!(0, string.len()); + assert!(string.capacity() >= 1000 && string.capacity() <= isize::MAX as usize); + + assert!(String::try_with_capacity(usize::MAX).is_err()); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +fn test_try_reserve() { + // These are the interesting cases: + // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM) + // * > isize::MAX should always fail + // * On 16/32-bit should CapacityOverflow + // * On 64-bit should OOM + // * overflow may trigger when adding `len` to `cap` (in number of elements) + // * overflow may trigger when multiplying `new_cap` by size_of:: (to get bytes) + + const MAX_CAP: usize = isize::MAX as usize; + const MAX_USIZE: usize = usize::MAX; + + { + // Note: basic stuff is checked by test_reserve + let mut empty_string: String = String::new(); + + // Check isize::MAX doesn't count as an overflow + if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + // Play it again, frank! (just to be sure) + if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } + + { + // Same basic idea, but with non-zero len + let mut ten_bytes: String = String::from("0123456789"); + + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Should always overflow in the add-to-len + assert_matches!( + ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +fn test_try_reserve_exact() { + // This is exactly the same as test_try_reserve with the method changed. + // See that test for comments. + + const MAX_CAP: usize = isize::MAX as usize; + const MAX_USIZE: usize = usize::MAX; + + { + let mut empty_string: String = String::new(); + + if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } + + { + let mut ten_bytes: String = String::from("0123456789"); + + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } +} + +#[test] +fn test_from_char() { + assert_eq!(String::from('a'), 'a'.to_string()); + let s: String = 'x'.into(); + assert_eq!(s, 'x'.to_string()); +} + +#[test] +fn test_str_concat() { + let a: String = "hello".to_string(); + let b: String = "world".to_string(); + let s: String = format!("{a}{b}"); + assert_eq!(s.as_bytes()[9], 'd' as u8); +} diff --git a/library/alloctests/tests/sync.rs b/library/alloctests/tests/sync.rs new file mode 100644 index 00000000000..6d3ab1b1d11 --- /dev/null +++ b/library/alloctests/tests/sync.rs @@ -0,0 +1,720 @@ +use alloc::sync::*; +use std::alloc::{AllocError, Allocator, Layout}; +use std::any::Any; +use std::clone::Clone; +use std::mem::MaybeUninit; +use std::option::Option::None; +use std::ptr::NonNull; +use std::sync::Mutex; +use std::sync::atomic::Ordering::*; +use std::sync::atomic::{self, AtomicUsize}; +use std::sync::mpsc::channel; +use std::thread; + +struct Canary(*mut AtomicUsize); + +impl Drop for Canary { + fn drop(&mut self) { + unsafe { + match *self { + Canary(c) => { + (*c).fetch_add(1, SeqCst); + } + } + } + } +} + +struct AllocCanary<'a>(&'a AtomicUsize); + +impl<'a> AllocCanary<'a> { + fn new(counter: &'a AtomicUsize) -> Self { + counter.fetch_add(1, SeqCst); + Self(counter) + } +} + +unsafe impl Allocator for AllocCanary<'_> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + std::alloc::Global.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { std::alloc::Global.deallocate(ptr, layout) } + } +} + +impl Clone for AllocCanary<'_> { + fn clone(&self) -> Self { + Self::new(self.0) + } +} + +impl Drop for AllocCanary<'_> { + fn drop(&mut self) { + self.0.fetch_sub(1, SeqCst); + } +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn manually_share_arc() { + let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let arc_v = Arc::new(v); + + let (tx, rx) = channel(); + + let _t = thread::spawn(move || { + let arc_v: Arc> = rx.recv().unwrap(); + assert_eq!((*arc_v)[3], 4); + }); + + tx.send(arc_v.clone()).unwrap(); + + assert_eq!((*arc_v)[2], 3); + assert_eq!((*arc_v)[4], 5); +} + +#[test] +fn test_arc_get_mut() { + let mut x = Arc::new(3); + *Arc::get_mut(&mut x).unwrap() = 4; + assert_eq!(*x, 4); + let y = x.clone(); + assert!(Arc::get_mut(&mut x).is_none()); + drop(y); + assert!(Arc::get_mut(&mut x).is_some()); + let _w = Arc::downgrade(&x); + assert!(Arc::get_mut(&mut x).is_none()); +} + +#[test] +fn weak_counts() { + assert_eq!(Weak::weak_count(&Weak::::new()), 0); + assert_eq!(Weak::strong_count(&Weak::::new()), 0); + + let a = Arc::new(0); + let w = Arc::downgrade(&a); + assert_eq!(Weak::strong_count(&w), 1); + assert_eq!(Weak::weak_count(&w), 1); + let w2 = w.clone(); + assert_eq!(Weak::strong_count(&w), 1); + assert_eq!(Weak::weak_count(&w), 2); + assert_eq!(Weak::strong_count(&w2), 1); + assert_eq!(Weak::weak_count(&w2), 2); + drop(w); + assert_eq!(Weak::strong_count(&w2), 1); + assert_eq!(Weak::weak_count(&w2), 1); + let a2 = a.clone(); + assert_eq!(Weak::strong_count(&w2), 2); + assert_eq!(Weak::weak_count(&w2), 1); + drop(a2); + drop(a); + assert_eq!(Weak::strong_count(&w2), 0); + assert_eq!(Weak::weak_count(&w2), 0); + drop(w2); +} + +#[test] +fn try_unwrap() { + let x = Arc::new(3); + assert_eq!(Arc::try_unwrap(x), Ok(3)); + let x = Arc::new(4); + let _y = x.clone(); + assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4))); + let x = Arc::new(5); + let _w = Arc::downgrade(&x); + assert_eq!(Arc::try_unwrap(x), Ok(5)); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +fn into_inner() { + for _ in 0..100 + // ^ Increase chances of hitting potential race conditions + { + let x = Arc::new(3); + let y = Arc::clone(&x); + let r_thread = std::thread::spawn(|| Arc::into_inner(x)); + let s_thread = std::thread::spawn(|| Arc::into_inner(y)); + let r = r_thread.join().expect("r_thread panicked"); + let s = s_thread.join().expect("s_thread panicked"); + assert!( + matches!((r, s), (None, Some(3)) | (Some(3), None)), + "assertion failed: unexpected result `{:?}`\ + \n expected `(None, Some(3))` or `(Some(3), None)`", + (r, s), + ); + } + + let x = Arc::new(3); + assert_eq!(Arc::into_inner(x), Some(3)); + + let x = Arc::new(4); + let y = Arc::clone(&x); + assert_eq!(Arc::into_inner(x), None); + assert_eq!(Arc::into_inner(y), Some(4)); + + let x = Arc::new(5); + let _w = Arc::downgrade(&x); + assert_eq!(Arc::into_inner(x), Some(5)); +} + +#[test] +fn into_from_raw() { + let x = Arc::new(Box::new("hello")); + let y = x.clone(); + + let x_ptr = Arc::into_raw(x); + drop(y); + unsafe { + assert_eq!(**x_ptr, "hello"); + + let x = Arc::from_raw(x_ptr); + assert_eq!(**x, "hello"); + + assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello")); + } +} + +#[test] +fn test_into_from_raw_unsized() { + use std::fmt::Display; + use std::string::ToString; + + let arc: Arc = Arc::from("foo"); + + let ptr = Arc::into_raw(arc.clone()); + let arc2 = unsafe { Arc::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }, "foo"); + assert_eq!(arc, arc2); + + let arc: Arc = Arc::new(123); + + let ptr = Arc::into_raw(arc.clone()); + let arc2 = unsafe { Arc::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }.to_string(), "123"); + assert_eq!(arc2.to_string(), "123"); +} + +#[test] +fn into_from_weak_raw() { + let x = Arc::new(Box::new("hello")); + let y = Arc::downgrade(&x); + + let y_ptr = Weak::into_raw(y); + unsafe { + assert_eq!(**y_ptr, "hello"); + + let y = Weak::from_raw(y_ptr); + let y_up = Weak::upgrade(&y).unwrap(); + assert_eq!(**y_up, "hello"); + drop(y_up); + + assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello")); + } +} + +#[test] +fn test_into_from_weak_raw_unsized() { + use std::fmt::Display; + use std::string::ToString; + + let arc: Arc = Arc::from("foo"); + let weak: Weak = Arc::downgrade(&arc); + + let ptr = Weak::into_raw(weak.clone()); + let weak2 = unsafe { Weak::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }, "foo"); + assert!(weak.ptr_eq(&weak2)); + + let arc: Arc = Arc::new(123); + let weak: Weak = Arc::downgrade(&arc); + + let ptr = Weak::into_raw(weak.clone()); + let weak2 = unsafe { Weak::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }.to_string(), "123"); + assert!(weak.ptr_eq(&weak2)); +} + +#[test] +fn test_cowarc_clone_make_mut() { + let mut cow0 = Arc::new(75); + let mut cow1 = cow0.clone(); + let mut cow2 = cow1.clone(); + + assert!(75 == *Arc::make_mut(&mut cow0)); + assert!(75 == *Arc::make_mut(&mut cow1)); + assert!(75 == *Arc::make_mut(&mut cow2)); + + *Arc::make_mut(&mut cow0) += 1; + *Arc::make_mut(&mut cow1) += 2; + *Arc::make_mut(&mut cow2) += 3; + + assert!(76 == *cow0); + assert!(77 == *cow1); + assert!(78 == *cow2); + + // none should point to the same backing memory + assert!(*cow0 != *cow1); + assert!(*cow0 != *cow2); + assert!(*cow1 != *cow2); +} + +#[test] +fn test_cowarc_clone_unique2() { + let mut cow0 = Arc::new(75); + let cow1 = cow0.clone(); + let cow2 = cow1.clone(); + + assert!(75 == *cow0); + assert!(75 == *cow1); + assert!(75 == *cow2); + + *Arc::make_mut(&mut cow0) += 1; + assert!(76 == *cow0); + assert!(75 == *cow1); + assert!(75 == *cow2); + + // cow1 and cow2 should share the same contents + // cow0 should have a unique reference + assert!(*cow0 != *cow1); + assert!(*cow0 != *cow2); + assert!(*cow1 == *cow2); +} + +#[test] +fn test_cowarc_clone_weak() { + let mut cow0 = Arc::new(75); + let cow1_weak = Arc::downgrade(&cow0); + + assert!(75 == *cow0); + assert!(75 == *cow1_weak.upgrade().unwrap()); + + *Arc::make_mut(&mut cow0) += 1; + + assert!(76 == *cow0); + assert!(cow1_weak.upgrade().is_none()); +} + +#[test] +fn test_live() { + let x = Arc::new(5); + let y = Arc::downgrade(&x); + assert!(y.upgrade().is_some()); +} + +#[test] +fn test_dead() { + let x = Arc::new(5); + let y = Arc::downgrade(&x); + drop(x); + assert!(y.upgrade().is_none()); +} + +#[test] +fn weak_self_cyclic() { + struct Cycle { + x: Mutex>>, + } + + let a = Arc::new(Cycle { x: Mutex::new(None) }); + let b = Arc::downgrade(&a.clone()); + *a.x.lock().unwrap() = Some(b); + + // hopefully we don't double-free (or leak)... +} + +#[test] +fn drop_arc() { + let mut canary = AtomicUsize::new(0); + let x = Arc::new(Canary(&mut canary as *mut AtomicUsize)); + drop(x); + assert!(canary.load(Acquire) == 1); +} + +#[test] +fn drop_arc_weak() { + let mut canary = AtomicUsize::new(0); + let arc = Arc::new(Canary(&mut canary as *mut AtomicUsize)); + let arc_weak = Arc::downgrade(&arc); + assert!(canary.load(Acquire) == 0); + drop(arc); + assert!(canary.load(Acquire) == 1); + drop(arc_weak); +} + +#[test] +fn test_strong_count() { + let a = Arc::new(0); + assert!(Arc::strong_count(&a) == 1); + let w = Arc::downgrade(&a); + assert!(Arc::strong_count(&a) == 1); + let b = w.upgrade().expect(""); + assert!(Arc::strong_count(&b) == 2); + assert!(Arc::strong_count(&a) == 2); + drop(w); + drop(a); + assert!(Arc::strong_count(&b) == 1); + let c = b.clone(); + assert!(Arc::strong_count(&b) == 2); + assert!(Arc::strong_count(&c) == 2); +} + +#[test] +fn test_weak_count() { + let a = Arc::new(0); + assert!(Arc::strong_count(&a) == 1); + assert!(Arc::weak_count(&a) == 0); + let w = Arc::downgrade(&a); + assert!(Arc::strong_count(&a) == 1); + assert!(Arc::weak_count(&a) == 1); + let x = w.clone(); + assert!(Arc::weak_count(&a) == 2); + drop(w); + drop(x); + assert!(Arc::strong_count(&a) == 1); + assert!(Arc::weak_count(&a) == 0); + let c = a.clone(); + assert!(Arc::strong_count(&a) == 2); + assert!(Arc::weak_count(&a) == 0); + let d = Arc::downgrade(&c); + assert!(Arc::weak_count(&c) == 1); + assert!(Arc::strong_count(&c) == 2); + + drop(a); + drop(c); + drop(d); +} + +#[test] +fn show_arc() { + let a = Arc::new(5); + assert_eq!(format!("{a:?}"), "5"); +} + +// Make sure deriving works with Arc +#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)] +struct _Foo { + inner: Arc, +} + +#[test] +fn test_unsized() { + let x: Arc<[i32]> = Arc::new([1, 2, 3]); + assert_eq!(format!("{x:?}"), "[1, 2, 3]"); + let y = Arc::downgrade(&x.clone()); + drop(x); + assert!(y.upgrade().is_none()); +} + +#[test] +fn test_maybe_thin_unsized() { + // If/when custom thin DSTs exist, this test should be updated to use one + use std::ffi::CStr; + + let x: Arc = Arc::from(c"swordfish"); + assert_eq!(format!("{x:?}"), "\"swordfish\""); + let y: Weak = Arc::downgrade(&x); + drop(x); + + // At this point, the weak points to a dropped DST + assert!(y.upgrade().is_none()); + // But we still need to be able to get the alloc layout to drop. + // CStr has no drop glue, but custom DSTs might, and need to work. + drop(y); +} + +#[test] +fn test_from_owned() { + let foo = 123; + let foo_arc = Arc::from(foo); + assert!(123 == *foo_arc); +} + +#[test] +fn test_new_weak() { + let foo: Weak = Weak::new(); + assert!(foo.upgrade().is_none()); +} + +#[test] +fn test_ptr_eq() { + let five = Arc::new(5); + let same_five = five.clone(); + let other_five = Arc::new(5); + + assert!(Arc::ptr_eq(&five, &same_five)); + assert!(!Arc::ptr_eq(&five, &other_five)); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_weak_count_locked() { + let mut a = Arc::new(atomic::AtomicBool::new(false)); + let a2 = a.clone(); + let t = thread::spawn(move || { + // Miri is too slow + let count = if cfg!(miri) { 1000 } else { 1000000 }; + for _i in 0..count { + Arc::get_mut(&mut a); + } + a.store(true, SeqCst); + }); + + while !a2.load(SeqCst) { + let n = Arc::weak_count(&a2); + assert!(n < 2, "bad weak count: {}", n); + #[cfg(miri)] // Miri's scheduler does not guarantee liveness, and thus needs this hint. + std::hint::spin_loop(); + } + t.join().unwrap(); +} + +#[test] +fn test_from_str() { + let r: Arc = Arc::from("foo"); + + assert_eq!(&r[..], "foo"); +} + +#[test] +fn test_copy_from_slice() { + let s: &[u32] = &[1, 2, 3]; + let r: Arc<[u32]> = Arc::from(s); + + assert_eq!(&r[..], [1, 2, 3]); +} + +#[test] +fn test_clone_from_slice() { + #[derive(Clone, Debug, Eq, PartialEq)] + struct X(u32); + + let s: &[X] = &[X(1), X(2), X(3)]; + let r: Arc<[X]> = Arc::from(s); + + assert_eq!(&r[..], s); +} + +#[test] +#[should_panic] +fn test_clone_from_slice_panic() { + use std::string::{String, ToString}; + + struct Fail(u32, String); + + impl Clone for Fail { + fn clone(&self) -> Fail { + if self.0 == 2 { + panic!(); + } + Fail(self.0, self.1.clone()) + } + } + + let s: &[Fail] = + &[Fail(0, "foo".to_string()), Fail(1, "bar".to_string()), Fail(2, "baz".to_string())]; + + // Should panic, but not cause memory corruption + let _r: Arc<[Fail]> = Arc::from(s); +} + +#[test] +fn test_from_box() { + let b: Box = Box::new(123); + let r: Arc = Arc::from(b); + + assert_eq!(*r, 123); +} + +#[test] +fn test_from_box_str() { + use std::string::String; + + let s = String::from("foo").into_boxed_str(); + let r: Arc = Arc::from(s); + + assert_eq!(&r[..], "foo"); +} + +#[test] +fn test_from_box_slice() { + let s = vec![1, 2, 3].into_boxed_slice(); + let r: Arc<[u32]> = Arc::from(s); + + assert_eq!(&r[..], [1, 2, 3]); +} + +#[test] +fn test_from_box_trait() { + use std::fmt::Display; + use std::string::ToString; + + let b: Box = Box::new(123); + let r: Arc = Arc::from(b); + + assert_eq!(r.to_string(), "123"); +} + +#[test] +fn test_from_box_trait_zero_sized() { + use std::fmt::Debug; + + let b: Box = Box::new(()); + let r: Arc = Arc::from(b); + + assert_eq!(format!("{r:?}"), "()"); +} + +#[test] +fn test_from_vec() { + let v = vec![1, 2, 3]; + let r: Arc<[u32]> = Arc::from(v); + + assert_eq!(&r[..], [1, 2, 3]); +} + +#[test] +fn test_downcast() { + use std::any::Any; + + let r1: Arc = Arc::new(i32::MAX); + let r2: Arc = Arc::new("abc"); + + assert!(r1.clone().downcast::().is_err()); + + let r1i32 = r1.downcast::(); + assert!(r1i32.is_ok()); + assert_eq!(r1i32.unwrap(), Arc::new(i32::MAX)); + + assert!(r2.clone().downcast::().is_err()); + + let r2str = r2.downcast::<&'static str>(); + assert!(r2str.is_ok()); + assert_eq!(r2str.unwrap(), Arc::new("abc")); +} + +#[test] +fn test_array_from_slice() { + let v = vec![1, 2, 3]; + let r: Arc<[u32]> = Arc::from(v); + + let a: Result, _> = r.clone().try_into(); + assert!(a.is_ok()); + + let a: Result, _> = r.clone().try_into(); + assert!(a.is_err()); +} + +#[test] +fn test_arc_cyclic_with_zero_refs() { + struct ZeroRefs { + inner: Weak, + } + let zero_refs = Arc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + ZeroRefs { inner: Weak::new() } + }); + + assert_eq!(Arc::strong_count(&zero_refs), 1); + assert_eq!(Arc::weak_count(&zero_refs), 0); + assert_eq!(zero_refs.inner.strong_count(), 0); + assert_eq!(zero_refs.inner.weak_count(), 0); +} + +#[test] +fn test_arc_new_cyclic_one_ref() { + struct OneRef { + inner: Weak, + } + let one_ref = Arc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + OneRef { inner: inner.clone() } + }); + + assert_eq!(Arc::strong_count(&one_ref), 1); + assert_eq!(Arc::weak_count(&one_ref), 1); + + let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap(); + assert!(Arc::ptr_eq(&one_ref, &one_ref2)); + + assert_eq!(Arc::strong_count(&one_ref), 2); + assert_eq!(Arc::weak_count(&one_ref), 1); +} + +#[test] +fn test_arc_cyclic_two_refs() { + struct TwoRefs { + inner1: Weak, + inner2: Weak, + } + let two_refs = Arc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + + let inner1 = inner.clone(); + let inner2 = inner1.clone(); + + TwoRefs { inner1, inner2 } + }); + + assert_eq!(Arc::strong_count(&two_refs), 1); + assert_eq!(Arc::weak_count(&two_refs), 2); + + let two_refs1 = Weak::upgrade(&two_refs.inner1).unwrap(); + assert!(Arc::ptr_eq(&two_refs, &two_refs1)); + + let two_refs2 = Weak::upgrade(&two_refs.inner2).unwrap(); + assert!(Arc::ptr_eq(&two_refs, &two_refs2)); + + assert_eq!(Arc::strong_count(&two_refs), 3); + assert_eq!(Arc::weak_count(&two_refs), 2); +} + +/// Test for Arc::drop bug (https://github.com/rust-lang/rust/issues/55005) +#[test] +#[cfg(miri)] // relies on Stacked Borrows in Miri +fn arc_drop_dereferenceable_race() { + // The bug seems to take up to 700 iterations to reproduce with most seeds (tested 0-9). + for _ in 0..750 { + let arc_1 = Arc::new(()); + let arc_2 = arc_1.clone(); + let thread = thread::spawn(|| drop(arc_2)); + // Spin a bit; makes the race more likely to appear + let mut i = 0; + while i < 256 { + i += 1; + } + drop(arc_1); + thread.join().unwrap(); + } +} + +#[test] +fn arc_doesnt_leak_allocator() { + let counter = AtomicUsize::new(0); + + { + let arc: Arc = Arc::new_in(5usize, AllocCanary::new(&counter)); + drop(arc.downcast::().unwrap()); + + let arc: Arc = Arc::new_in(5usize, AllocCanary::new(&counter)); + drop(unsafe { arc.downcast_unchecked::() }); + + let arc = Arc::new_in(MaybeUninit::::new(5usize), AllocCanary::new(&counter)); + drop(unsafe { arc.assume_init() }); + + let arc: Arc<[MaybeUninit], _> = + Arc::new_zeroed_slice_in(5, AllocCanary::new(&counter)); + drop(unsafe { arc.assume_init() }); + } + + assert_eq!(counter.load(SeqCst), 0); +} diff --git a/library/alloctests/tests/task.rs b/library/alloctests/tests/task.rs new file mode 100644 index 00000000000..390dec14484 --- /dev/null +++ b/library/alloctests/tests/task.rs @@ -0,0 +1,36 @@ +use alloc::rc::Rc; +use alloc::sync::Arc; +use alloc::task::{LocalWake, Wake}; +use core::task::{LocalWaker, Waker}; + +#[test] +#[cfg_attr(miri, ignore)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail +fn test_waker_will_wake_clone() { + struct NoopWaker; + + impl Wake for NoopWaker { + fn wake(self: Arc) {} + } + + let waker = Waker::from(Arc::new(NoopWaker)); + let clone = waker.clone(); + + assert!(waker.will_wake(&clone)); + assert!(clone.will_wake(&waker)); +} + +#[test] +#[cfg_attr(miri, ignore)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail +fn test_local_waker_will_wake_clone() { + struct NoopWaker; + + impl LocalWake for NoopWaker { + fn wake(self: Rc) {} + } + + let waker = LocalWaker::from(Rc::new(NoopWaker)); + let clone = waker.clone(); + + assert!(waker.will_wake(&clone)); + assert!(clone.will_wake(&waker)); +} diff --git a/library/alloctests/tests/testing/crash_test.rs b/library/alloctests/tests/testing/crash_test.rs new file mode 100644 index 00000000000..502fe6c10c6 --- /dev/null +++ b/library/alloctests/tests/testing/crash_test.rs @@ -0,0 +1,80 @@ +use std::cmp::Ordering; +use std::fmt::Debug; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; + +/// A blueprint for crash test dummy instances that monitor drops. +/// Some instances may be configured to panic at some point. +/// +/// Crash test dummies are identified and ordered by an id, so they can be used +/// as keys in a BTreeMap. +#[derive(Debug)] +pub struct CrashTestDummy { + pub id: usize, + dropped: AtomicUsize, +} + +impl CrashTestDummy { + /// Creates a crash test dummy design. The `id` determines order and equality of instances. + pub fn new(id: usize) -> CrashTestDummy { + CrashTestDummy { id, dropped: AtomicUsize::new(0) } + } + + /// Creates an instance of a crash test dummy that records what events it experiences + /// and optionally panics. + pub fn spawn(&self, panic: Panic) -> Instance<'_> { + Instance { origin: self, panic } + } + + /// Returns how many times instances of the dummy have been dropped. + pub fn dropped(&self) -> usize { + self.dropped.load(SeqCst) + } +} + +#[derive(Debug)] +pub struct Instance<'a> { + origin: &'a CrashTestDummy, + panic: Panic, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Panic { + Never, + InDrop, +} + +impl Instance<'_> { + pub fn id(&self) -> usize { + self.origin.id + } +} + +impl Drop for Instance<'_> { + fn drop(&mut self) { + self.origin.dropped.fetch_add(1, SeqCst); + if self.panic == Panic::InDrop { + panic!("panic in `drop`"); + } + } +} + +impl PartialOrd for Instance<'_> { + fn partial_cmp(&self, other: &Self) -> Option { + self.id().partial_cmp(&other.id()) + } +} + +impl Ord for Instance<'_> { + fn cmp(&self, other: &Self) -> Ordering { + self.id().cmp(&other.id()) + } +} + +impl PartialEq for Instance<'_> { + fn eq(&self, other: &Self) -> bool { + self.id().eq(&other.id()) + } +} + +impl Eq for Instance<'_> {} diff --git a/library/alloctests/tests/testing/mod.rs b/library/alloctests/tests/testing/mod.rs new file mode 100644 index 00000000000..0a3dd191dc8 --- /dev/null +++ b/library/alloctests/tests/testing/mod.rs @@ -0,0 +1 @@ +pub mod crash_test; diff --git a/library/alloctests/tests/thin_box.rs b/library/alloctests/tests/thin_box.rs new file mode 100644 index 00000000000..4c46b614127 --- /dev/null +++ b/library/alloctests/tests/thin_box.rs @@ -0,0 +1,261 @@ +use core::fmt::Debug; +use std::boxed::ThinBox; + +#[test] +fn want_niche_optimization() { + fn uses_niche() -> bool { + size_of::<*const ()>() == size_of::>>() + } + + trait Tr {} + assert!(uses_niche::()); + assert!(uses_niche::<[i32]>()); + assert!(uses_niche::()); +} + +#[test] +fn want_thin() { + fn is_thin() -> bool { + size_of::<*const ()>() == size_of::>() + } + + trait Tr {} + assert!(is_thin::()); + assert!(is_thin::<[i32]>()); + assert!(is_thin::()); +} + +#[allow(dead_code)] +fn assert_covariance() { + fn thin_box<'new>(b: ThinBox<[&'static str]>) -> ThinBox<[&'new str]> { + b + } +} + +#[track_caller] +fn verify_aligned(ptr: *const T) { + // Use `black_box` to attempt to obscure the fact that we're calling this + // function on pointers that come from box/references, which the compiler + // would otherwise realize is impossible (because it would mean we've + // already executed UB). + // + // That is, we'd *like* it to be possible for the asserts in this function + // to detect brokenness in the ThinBox impl. + // + // It would probably be better if we instead had these as debug_asserts + // inside `ThinBox`, prior to the point where we do the UB. Anyway, in + // practice these checks are mostly just smoke-detectors for an extremely + // broken `ThinBox` impl, since it's an extremely subtle piece of code. + let ptr = core::hint::black_box(ptr); + assert!( + ptr.is_aligned() && !ptr.is_null(), + "misaligned ThinBox data; valid pointers to `{ty}` should be aligned to {align}: {ptr:p}", + ty = core::any::type_name::(), + align = align_of::(), + ); +} + +#[track_caller] +fn check_thin_sized(make: impl FnOnce() -> T) { + let value = make(); + let boxed = ThinBox::new(value.clone()); + let val = &*boxed; + verify_aligned(val as *const T); + assert_eq!(val, &value); +} + +#[track_caller] +fn check_thin_dyn(make: impl FnOnce() -> T) { + let value = make(); + let wanted_debug = format!("{value:?}"); + let boxed: ThinBox = ThinBox::new_unsize(value.clone()); + let val = &*boxed; + // wide reference -> wide pointer -> thin pointer + verify_aligned(val as *const dyn Debug as *const T); + let got_debug = format!("{val:?}"); + assert_eq!(wanted_debug, got_debug); +} + +macro_rules! define_test { + ( + @test_name: $testname:ident; + + $(#[$m:meta])* + struct $Type:ident($inner:ty); + + $($test_stmts:tt)* + ) => { + #[test] + fn $testname() { + use core::sync::atomic::{AtomicIsize, Ordering}; + // Define the type, and implement new/clone/drop in such a way that + // the number of live instances will be counted. + $(#[$m])* + #[derive(Debug, PartialEq)] + struct $Type { + _priv: $inner, + } + + impl Clone for $Type { + fn clone(&self) -> Self { + verify_aligned(self); + Self::new(self._priv.clone()) + } + } + + impl Drop for $Type { + fn drop(&mut self) { + verify_aligned(self); + Self::modify_live(-1); + } + } + + impl $Type { + fn new(i: $inner) -> Self { + Self::modify_live(1); + Self { _priv: i } + } + + fn modify_live(n: isize) -> isize { + static COUNTER: AtomicIsize = AtomicIsize::new(0); + COUNTER.fetch_add(n, Ordering::Relaxed) + n + } + + fn live_objects() -> isize { + Self::modify_live(0) + } + } + // Run the test statements + let _: () = { $($test_stmts)* }; + // Check that we didn't leak anything, or call drop too many times. + assert_eq!( + $Type::live_objects(), 0, + "Wrong number of drops of {}, `initializations - drops` should be 0.", + stringify!($Type), + ); + } + }; +} + +define_test! { + @test_name: align1zst; + struct Align1Zst(()); + + check_thin_sized(|| Align1Zst::new(())); + check_thin_dyn(|| Align1Zst::new(())); +} + +define_test! { + @test_name: align1small; + struct Align1Small(u8); + + check_thin_sized(|| Align1Small::new(50)); + check_thin_dyn(|| Align1Small::new(50)); +} + +define_test! { + @test_name: align1_size_not_pow2; + struct Align64NotPow2Size([u8; 79]); + + check_thin_sized(|| Align64NotPow2Size::new([100; 79])); + check_thin_dyn(|| Align64NotPow2Size::new([100; 79])); +} + +define_test! { + @test_name: align1big; + struct Align1Big([u8; 256]); + + check_thin_sized(|| Align1Big::new([5u8; 256])); + check_thin_dyn(|| Align1Big::new([5u8; 256])); +} + +// Note: `#[repr(align(2))]` is worth testing because +// - can have pointers which are misaligned, unlike align(1) +// - is still expected to have an alignment less than the alignment of a vtable. +define_test! { + @test_name: align2zst; + #[repr(align(2))] + struct Align2Zst(()); + + check_thin_sized(|| Align2Zst::new(())); + check_thin_dyn(|| Align2Zst::new(())); +} + +define_test! { + @test_name: align2small; + #[repr(align(2))] + struct Align2Small(u8); + + check_thin_sized(|| Align2Small::new(60)); + check_thin_dyn(|| Align2Small::new(60)); +} + +define_test! { + @test_name: align2full; + #[repr(align(2))] + struct Align2Full([u8; 2]); + check_thin_sized(|| Align2Full::new([3u8; 2])); + check_thin_dyn(|| Align2Full::new([3u8; 2])); +} + +define_test! { + @test_name: align2_size_not_pow2; + #[repr(align(2))] + struct Align2NotPower2Size([u8; 6]); + + check_thin_sized(|| Align2NotPower2Size::new([3; 6])); + check_thin_dyn(|| Align2NotPower2Size::new([3; 6])); +} + +define_test! { + @test_name: align2big; + #[repr(align(2))] + struct Align2Big([u8; 256]); + + check_thin_sized(|| Align2Big::new([5u8; 256])); + check_thin_dyn(|| Align2Big::new([5u8; 256])); +} + +define_test! { + @test_name: align64zst; + #[repr(align(64))] + struct Align64Zst(()); + + check_thin_sized(|| Align64Zst::new(())); + check_thin_dyn(|| Align64Zst::new(())); +} + +define_test! { + @test_name: align64small; + #[repr(align(64))] + struct Align64Small(u8); + + check_thin_sized(|| Align64Small::new(50)); + check_thin_dyn(|| Align64Small::new(50)); +} + +define_test! { + @test_name: align64med; + #[repr(align(64))] + struct Align64Med([u8; 64]); + check_thin_sized(|| Align64Med::new([10; 64])); + check_thin_dyn(|| Align64Med::new([10; 64])); +} + +define_test! { + @test_name: align64_size_not_pow2; + #[repr(align(64))] + struct Align64NotPow2Size([u8; 192]); + + check_thin_sized(|| Align64NotPow2Size::new([10; 192])); + check_thin_dyn(|| Align64NotPow2Size::new([10; 192])); +} + +define_test! { + @test_name: align64big; + #[repr(align(64))] + struct Align64Big([u8; 256]); + + check_thin_sized(|| Align64Big::new([10; 256])); + check_thin_dyn(|| Align64Big::new([10; 256])); +} diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs new file mode 100644 index 00000000000..f430d979fa8 --- /dev/null +++ b/library/alloctests/tests/vec.rs @@ -0,0 +1,2750 @@ +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + +use core::alloc::{Allocator, Layout}; +use core::num::NonZero; +use core::ptr::NonNull; +use core::{assert_eq, assert_ne}; +use std::alloc::System; +use std::assert_matches::assert_matches; +use std::borrow::Cow; +use std::cell::Cell; +use std::collections::TryReserveErrorKind::*; +use std::fmt::Debug; +use std::hint; +use std::iter::InPlaceIterable; +use std::mem::swap; +use std::ops::Bound::*; +use std::panic::{AssertUnwindSafe, catch_unwind}; +use std::rc::Rc; +use std::sync::atomic::{AtomicU32, Ordering}; +use std::vec::{Drain, IntoIter}; + +struct DropCounter<'a> { + count: &'a mut u32, +} + +impl Drop for DropCounter<'_> { + fn drop(&mut self) { + *self.count += 1; + } +} + +#[test] +fn test_small_vec_struct() { + assert_eq!(size_of::>(), size_of::() * 3); +} + +#[test] +fn test_double_drop() { + struct TwoVec { + x: Vec, + y: Vec, + } + + let (mut count_x, mut count_y) = (0, 0); + { + let mut tv = TwoVec { x: Vec::new(), y: Vec::new() }; + tv.x.push(DropCounter { count: &mut count_x }); + tv.y.push(DropCounter { count: &mut count_y }); + + // If Vec had a drop flag, here is where it would be zeroed. + // Instead, it should rely on its internal state to prevent + // doing anything significant when dropped multiple times. + drop(tv.x); + + // Here tv goes out of scope, tv.y should be dropped, but not tv.x. + } + + assert_eq!(count_x, 1); + assert_eq!(count_y, 1); +} + +#[test] +fn test_reserve() { + let mut v = Vec::new(); + assert_eq!(v.capacity(), 0); + + v.reserve(2); + assert!(v.capacity() >= 2); + + for i in 0..16 { + v.push(i); + } + + assert!(v.capacity() >= 16); + v.reserve(16); + assert!(v.capacity() >= 32); + + v.push(16); + + v.reserve(16); + assert!(v.capacity() >= 33) +} + +#[test] +fn test_zst_capacity() { + assert_eq!(Vec::<()>::new().capacity(), usize::MAX); +} + +#[test] +fn test_indexing() { + let v: Vec = vec![10, 20]; + assert_eq!(v[0], 10); + assert_eq!(v[1], 20); + let mut x: usize = 0; + assert_eq!(v[x], 10); + assert_eq!(v[x + 1], 20); + x = x + 1; + assert_eq!(v[x], 20); + assert_eq!(v[x - 1], 10); +} + +#[test] +fn test_debug_fmt() { + let vec1: Vec = vec![]; + assert_eq!("[]", format!("{:?}", vec1)); + + let vec2 = vec![0, 1]; + assert_eq!("[0, 1]", format!("{:?}", vec2)); + + let slice: &[isize] = &[4, 5]; + assert_eq!("[4, 5]", format!("{slice:?}")); +} + +#[test] +fn test_push() { + let mut v = vec![]; + v.push(1); + assert_eq!(v, [1]); + v.push(2); + assert_eq!(v, [1, 2]); + v.push(3); + assert_eq!(v, [1, 2, 3]); +} + +#[test] +fn test_extend() { + let mut v = Vec::new(); + let mut w = Vec::new(); + + v.extend(w.clone()); + assert_eq!(v, &[]); + + v.extend(0..3); + for i in 0..3 { + w.push(i) + } + + assert_eq!(v, w); + + v.extend(3..10); + for i in 3..10 { + w.push(i) + } + + assert_eq!(v, w); + + v.extend(w.clone()); // specializes to `append` + assert!(v.iter().eq(w.iter().chain(w.iter()))); + + // Zero sized types + #[derive(PartialEq, Debug)] + struct Foo; + + let mut a = Vec::new(); + let b = vec![Foo, Foo]; + + a.extend(b); + assert_eq!(a, &[Foo, Foo]); + + // Double drop + let mut count_x = 0; + { + let mut x = Vec::new(); + let y = vec![DropCounter { count: &mut count_x }]; + x.extend(y); + } + assert_eq!(count_x, 1); +} + +#[test] +fn test_extend_from_slice() { + let a: Vec = vec![1, 2, 3, 4, 5]; + let b: Vec = vec![6, 7, 8, 9, 0]; + + let mut v: Vec = a; + + v.extend_from_slice(&b); + + assert_eq!(v, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); +} + +#[test] +fn test_extend_ref() { + let mut v = vec![1, 2]; + v.extend(&[3, 4, 5]); + + assert_eq!(v.len(), 5); + assert_eq!(v, [1, 2, 3, 4, 5]); + + let w = vec![6, 7]; + v.extend(&w); + + assert_eq!(v.len(), 7); + assert_eq!(v, [1, 2, 3, 4, 5, 6, 7]); +} + +#[test] +fn test_slice_from_ref() { + let values = vec![1, 2, 3, 4, 5]; + let slice = &values[1..3]; + + assert_eq!(slice, [2, 3]); +} + +#[test] +fn test_slice_from_mut() { + let mut values = vec![1, 2, 3, 4, 5]; + { + let slice = &mut values[2..]; + assert!(slice == [3, 4, 5]); + for p in slice { + *p += 2; + } + } + + assert!(values == [1, 2, 5, 6, 7]); +} + +#[test] +fn test_slice_to_mut() { + let mut values = vec![1, 2, 3, 4, 5]; + { + let slice = &mut values[..2]; + assert!(slice == [1, 2]); + for p in slice { + *p += 1; + } + } + + assert!(values == [2, 3, 3, 4, 5]); +} + +#[test] +fn test_split_at_mut() { + let mut values = vec![1, 2, 3, 4, 5]; + { + let (left, right) = values.split_at_mut(2); + { + let left: &[_] = left; + assert!(&left[..left.len()] == &[1, 2]); + } + for p in left { + *p += 1; + } + + { + let right: &[_] = right; + assert!(&right[..right.len()] == &[3, 4, 5]); + } + for p in right { + *p += 2; + } + } + + assert_eq!(values, [2, 3, 5, 6, 7]); +} + +#[test] +fn test_clone() { + let v: Vec = vec![]; + let w = vec![1, 2, 3]; + + assert_eq!(v, v.clone()); + + let z = w.clone(); + assert_eq!(w, z); + // they should be disjoint in memory. + assert!(w.as_ptr() != z.as_ptr()) +} + +#[test] +fn test_clone_from() { + let mut v = vec![]; + let three: Vec> = vec![Box::new(1), Box::new(2), Box::new(3)]; + let two: Vec> = vec![Box::new(4), Box::new(5)]; + // zero, long + v.clone_from(&three); + assert_eq!(v, three); + + // equal + v.clone_from(&three); + assert_eq!(v, three); + + // long, short + v.clone_from(&two); + assert_eq!(v, two); + + // short, long + v.clone_from(&three); + assert_eq!(v, three) +} + +#[test] +fn test_retain() { + let mut vec = vec![1, 2, 3, 4]; + vec.retain(|&x| x % 2 == 0); + assert_eq!(vec, [2, 4]); +} + +#[test] +fn test_retain_predicate_order() { + for to_keep in [true, false] { + let mut number_of_executions = 0; + let mut vec = vec![1, 2, 3, 4]; + let mut next_expected = 1; + vec.retain(|&x| { + assert_eq!(next_expected, x); + next_expected += 1; + number_of_executions += 1; + to_keep + }); + assert_eq!(number_of_executions, 4); + } +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_retain_pred_panic_with_hole() { + let v = (0..5).map(Rc::new).collect::>(); + catch_unwind(AssertUnwindSafe(|| { + let mut v = v.clone(); + v.retain(|r| match **r { + 0 => true, + 1 => false, + 2 => true, + _ => panic!(), + }); + })) + .unwrap_err(); + // Everything is dropped when predicate panicked. + assert!(v.iter().all(|r| Rc::strong_count(r) == 1)); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_retain_pred_panic_no_hole() { + let v = (0..5).map(Rc::new).collect::>(); + catch_unwind(AssertUnwindSafe(|| { + let mut v = v.clone(); + v.retain(|r| match **r { + 0 | 1 | 2 => true, + _ => panic!(), + }); + })) + .unwrap_err(); + // Everything is dropped when predicate panicked. + assert!(v.iter().all(|r| Rc::strong_count(r) == 1)); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_retain_drop_panic() { + struct Wrap(Rc); + + impl Drop for Wrap { + fn drop(&mut self) { + if *self.0 == 3 { + panic!(); + } + } + } + + let v = (0..5).map(|x| Rc::new(x)).collect::>(); + catch_unwind(AssertUnwindSafe(|| { + let mut v = v.iter().map(|r| Wrap(r.clone())).collect::>(); + v.retain(|w| match *w.0 { + 0 => true, + 1 => false, + 2 => true, + 3 => false, // Drop panic. + _ => true, + }); + })) + .unwrap_err(); + // Other elements are dropped when `drop` of one element panicked. + // The panicked wrapper also has its Rc dropped. + assert!(v.iter().all(|r| Rc::strong_count(r) == 1)); +} + +#[test] +fn test_retain_maybeuninits() { + // This test aimed to be run under miri. + use core::mem::MaybeUninit; + let mut vec: Vec<_> = [1i32, 2, 3, 4].map(|v| MaybeUninit::new(vec![v])).into(); + vec.retain(|x| { + // SAFETY: Retain must visit every element of Vec in original order and exactly once. + // Our values is initialized at creation of Vec. + let v = unsafe { x.assume_init_ref()[0] }; + if v & 1 == 0 { + return true; + } + // SAFETY: Value is initialized. + // Value wouldn't be dropped by `Vec::retain` + // because `MaybeUninit` doesn't drop content. + drop(unsafe { x.assume_init_read() }); + false + }); + let vec: Vec = vec + .into_iter() + .map(|x| unsafe { + // SAFETY: All values dropped in retain predicate must be removed by `Vec::retain`. + // Remaining values are initialized. + x.assume_init()[0] + }) + .collect(); + assert_eq!(vec, [2, 4]); +} + +#[test] +fn test_dedup() { + fn case(a: Vec, b: Vec) { + let mut v = a; + v.dedup(); + assert_eq!(v, b); + } + case(vec![], vec![]); + case(vec![1], vec![1]); + case(vec![1, 1], vec![1]); + case(vec![1, 2, 3], vec![1, 2, 3]); + case(vec![1, 1, 2, 3], vec![1, 2, 3]); + case(vec![1, 2, 2, 3], vec![1, 2, 3]); + case(vec![1, 2, 3, 3], vec![1, 2, 3]); + case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]); +} + +#[test] +fn test_dedup_by_key() { + fn case(a: Vec, b: Vec) { + let mut v = a; + v.dedup_by_key(|i| *i / 10); + assert_eq!(v, b); + } + case(vec![], vec![]); + case(vec![10], vec![10]); + case(vec![10, 11], vec![10]); + case(vec![10, 20, 30], vec![10, 20, 30]); + case(vec![10, 11, 20, 30], vec![10, 20, 30]); + case(vec![10, 20, 21, 30], vec![10, 20, 30]); + case(vec![10, 20, 30, 31], vec![10, 20, 30]); + case(vec![10, 11, 20, 21, 22, 30, 31], vec![10, 20, 30]); +} + +#[test] +fn test_dedup_by() { + let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"]; + vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); + + assert_eq!(vec, ["foo", "bar", "baz", "bar"]); + + let mut vec = vec![("foo", 1), ("foo", 2), ("bar", 3), ("bar", 4), ("bar", 5)]; + vec.dedup_by(|a, b| { + a.0 == b.0 && { + b.1 += a.1; + true + } + }); + + assert_eq!(vec, [("foo", 3), ("bar", 12)]); +} + +#[test] +fn test_dedup_unique() { + let mut v0: Vec> = vec![Box::new(1), Box::new(1), Box::new(2), Box::new(3)]; + v0.dedup(); + let mut v1: Vec> = vec![Box::new(1), Box::new(2), Box::new(2), Box::new(3)]; + v1.dedup(); + let mut v2: Vec> = vec![Box::new(1), Box::new(2), Box::new(3), Box::new(3)]; + v2.dedup(); + // If the boxed pointers were leaked or otherwise misused, valgrind + // and/or rt should raise errors. +} + +#[test] +fn zero_sized_values() { + let mut v = Vec::new(); + assert_eq!(v.len(), 0); + v.push(()); + assert_eq!(v.len(), 1); + v.push(()); + assert_eq!(v.len(), 2); + assert_eq!(v.pop(), Some(())); + assert_eq!(v.pop(), Some(())); + assert_eq!(v.pop(), None); + + assert_eq!(v.iter().count(), 0); + v.push(()); + assert_eq!(v.iter().count(), 1); + v.push(()); + assert_eq!(v.iter().count(), 2); + + for &() in &v {} + + assert_eq!(v.iter_mut().count(), 2); + v.push(()); + assert_eq!(v.iter_mut().count(), 3); + v.push(()); + assert_eq!(v.iter_mut().count(), 4); + + for &mut () in &mut v {} + unsafe { + v.set_len(0); + } + assert_eq!(v.iter_mut().count(), 0); +} + +#[test] +fn test_partition() { + assert_eq!([].into_iter().partition(|x: &i32| *x < 3), (vec![], vec![])); + assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 4), (vec![1, 2, 3], vec![])); + assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 2), (vec![1], vec![2, 3])); + assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 0), (vec![], vec![1, 2, 3])); +} + +#[test] +fn test_zip_unzip() { + let z1 = vec![(1, 4), (2, 5), (3, 6)]; + + let (left, right): (Vec<_>, Vec<_>) = z1.iter().cloned().unzip(); + + assert_eq!((1, 4), (left[0], right[0])); + assert_eq!((2, 5), (left[1], right[1])); + assert_eq!((3, 6), (left[2], right[2])); +} + +#[test] +fn test_cmp() { + let x: &[isize] = &[1, 2, 3, 4, 5]; + let cmp: &[isize] = &[1, 2, 3, 4, 5]; + assert_eq!(&x[..], cmp); + let cmp: &[isize] = &[3, 4, 5]; + assert_eq!(&x[2..], cmp); + let cmp: &[isize] = &[1, 2, 3]; + assert_eq!(&x[..3], cmp); + let cmp: &[isize] = &[2, 3, 4]; + assert_eq!(&x[1..4], cmp); + + let x: Vec = vec![1, 2, 3, 4, 5]; + let cmp: &[isize] = &[1, 2, 3, 4, 5]; + assert_eq!(&x[..], cmp); + let cmp: &[isize] = &[3, 4, 5]; + assert_eq!(&x[2..], cmp); + let cmp: &[isize] = &[1, 2, 3]; + assert_eq!(&x[..3], cmp); + let cmp: &[isize] = &[2, 3, 4]; + assert_eq!(&x[1..4], cmp); +} + +#[test] +fn test_vec_truncate_drop() { + static mut DROPS: u32 = 0; + struct Elem(#[allow(dead_code)] i32); + impl Drop for Elem { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + } + } + + let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)]; + assert_eq!(unsafe { DROPS }, 0); + v.truncate(3); + assert_eq!(unsafe { DROPS }, 2); + v.truncate(0); + assert_eq!(unsafe { DROPS }, 5); +} + +#[test] +#[should_panic] +fn test_vec_truncate_fail() { + struct BadElem(i32); + impl Drop for BadElem { + fn drop(&mut self) { + let BadElem(ref mut x) = *self; + if *x == 0xbadbeef { + panic!("BadElem panic: 0xbadbeef") + } + } + } + + let mut v = vec![BadElem(1), BadElem(2), BadElem(0xbadbeef), BadElem(4)]; + v.truncate(0); +} + +#[test] +fn test_index() { + let vec = vec![1, 2, 3]; + assert!(vec[1] == 2); +} + +#[test] +#[should_panic] +fn test_index_out_of_bounds() { + let vec = vec![1, 2, 3]; + let _ = vec[3]; +} + +#[test] +#[should_panic] +fn test_slice_out_of_bounds_1() { + let x = vec![1, 2, 3, 4, 5]; + let _ = &x[!0..]; +} + +#[test] +#[should_panic] +fn test_slice_out_of_bounds_2() { + let x = vec![1, 2, 3, 4, 5]; + let _ = &x[..6]; +} + +#[test] +#[should_panic] +fn test_slice_out_of_bounds_3() { + let x = vec![1, 2, 3, 4, 5]; + let _ = &x[!0..4]; +} + +#[test] +#[should_panic] +fn test_slice_out_of_bounds_4() { + let x = vec![1, 2, 3, 4, 5]; + let _ = &x[1..6]; +} + +#[test] +#[should_panic] +fn test_slice_out_of_bounds_5() { + let x = vec![1, 2, 3, 4, 5]; + let _ = &x[3..2]; +} + +#[test] +#[should_panic] +fn test_swap_remove_empty() { + let mut vec = Vec::::new(); + vec.swap_remove(0); +} + +#[test] +fn test_move_items() { + let vec = vec![1, 2, 3]; + let mut vec2 = vec![]; + for i in vec { + vec2.push(i); + } + assert_eq!(vec2, [1, 2, 3]); +} + +#[test] +fn test_move_items_reverse() { + let vec = vec![1, 2, 3]; + let mut vec2 = vec![]; + for i in vec.into_iter().rev() { + vec2.push(i); + } + assert_eq!(vec2, [3, 2, 1]); +} + +#[test] +fn test_move_items_zero_sized() { + let vec = vec![(), (), ()]; + let mut vec2 = vec![]; + for i in vec { + vec2.push(i); + } + assert_eq!(vec2, [(), (), ()]); +} + +#[test] +fn test_drain_empty_vec() { + let mut vec: Vec = vec![]; + let mut vec2: Vec = vec![]; + for i in vec.drain(..) { + vec2.push(i); + } + assert!(vec.is_empty()); + assert!(vec2.is_empty()); +} + +#[test] +fn test_drain_items() { + let mut vec = vec![1, 2, 3]; + let mut vec2 = vec![]; + for i in vec.drain(..) { + vec2.push(i); + } + assert_eq!(vec, []); + assert_eq!(vec2, [1, 2, 3]); +} + +#[test] +fn test_drain_items_reverse() { + let mut vec = vec![1, 2, 3]; + let mut vec2 = vec![]; + for i in vec.drain(..).rev() { + vec2.push(i); + } + assert_eq!(vec, []); + assert_eq!(vec2, [3, 2, 1]); +} + +#[test] +fn test_drain_items_zero_sized() { + let mut vec = vec![(), (), ()]; + let mut vec2 = vec![]; + for i in vec.drain(..) { + vec2.push(i); + } + assert_eq!(vec, []); + assert_eq!(vec2, [(), (), ()]); +} + +#[test] +#[should_panic] +fn test_drain_out_of_bounds() { + let mut v = vec![1, 2, 3, 4, 5]; + v.drain(5..6); +} + +#[test] +fn test_drain_range() { + let mut v = vec![1, 2, 3, 4, 5]; + for _ in v.drain(4..) {} + assert_eq!(v, &[1, 2, 3, 4]); + + let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect(); + for _ in v.drain(1..4) {} + assert_eq!(v, &[1.to_string(), 5.to_string()]); + + let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect(); + for _ in v.drain(1..4).rev() {} + assert_eq!(v, &[1.to_string(), 5.to_string()]); + + let mut v: Vec<_> = vec![(); 5]; + for _ in v.drain(1..4).rev() {} + assert_eq!(v, &[(), ()]); +} + +#[test] +fn test_drain_inclusive_range() { + let mut v = vec!['a', 'b', 'c', 'd', 'e']; + for _ in v.drain(1..=3) {} + assert_eq!(v, &['a', 'e']); + + let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect(); + for _ in v.drain(1..=5) {} + assert_eq!(v, &["0".to_string()]); + + let mut v: Vec = (0..=5).map(|x| x.to_string()).collect(); + for _ in v.drain(0..=5) {} + assert_eq!(v, Vec::::new()); + + let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect(); + for _ in v.drain(0..=3) {} + assert_eq!(v, &["4".to_string(), "5".to_string()]); + + let mut v: Vec<_> = (0..=1).map(|x| x.to_string()).collect(); + for _ in v.drain(..=0) {} + assert_eq!(v, &["1".to_string()]); +} + +#[test] +fn test_drain_max_vec_size() { + let mut v = Vec::<()>::with_capacity(usize::MAX); + unsafe { + v.set_len(usize::MAX); + } + for _ in v.drain(usize::MAX - 1..) {} + assert_eq!(v.len(), usize::MAX - 1); + + let mut v = Vec::<()>::with_capacity(usize::MAX); + unsafe { + v.set_len(usize::MAX); + } + for _ in v.drain(usize::MAX - 1..=usize::MAX - 1) {} + assert_eq!(v.len(), usize::MAX - 1); +} + +#[test] +#[should_panic] +fn test_drain_index_overflow() { + let mut v = Vec::<()>::with_capacity(usize::MAX); + unsafe { + v.set_len(usize::MAX); + } + v.drain(0..=usize::MAX); +} + +#[test] +#[should_panic] +fn test_drain_inclusive_out_of_bounds() { + let mut v = vec![1, 2, 3, 4, 5]; + v.drain(5..=5); +} + +#[test] +#[should_panic] +fn test_drain_start_overflow() { + let mut v = vec![1, 2, 3]; + v.drain((Excluded(usize::MAX), Included(0))); +} + +#[test] +#[should_panic] +fn test_drain_end_overflow() { + let mut v = vec![1, 2, 3]; + v.drain((Included(0), Included(usize::MAX))); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_drain_leak() { + static mut DROPS: i32 = 0; + + #[derive(Debug, PartialEq)] + struct D(u32, bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.1 { + panic!("panic in `drop`"); + } + } + } + + let mut v = vec![ + D(0, false), + D(1, false), + D(2, false), + D(3, false), + D(4, true), + D(5, false), + D(6, false), + ]; + + catch_unwind(AssertUnwindSafe(|| { + v.drain(2..=5); + })) + .ok(); + + assert_eq!(unsafe { DROPS }, 4); + assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]); +} + +#[test] +fn test_drain_keep_rest() { + let mut v = vec![0, 1, 2, 3, 4, 5, 6]; + let mut drain = v.drain(1..6); + assert_eq!(drain.next(), Some(1)); + assert_eq!(drain.next_back(), Some(5)); + assert_eq!(drain.next(), Some(2)); + + drain.keep_rest(); + assert_eq!(v, &[0, 3, 4, 6]); +} + +#[test] +fn test_drain_keep_rest_all() { + let mut v = vec![0, 1, 2, 3, 4, 5, 6]; + v.drain(1..6).keep_rest(); + assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]); +} + +#[test] +fn test_drain_keep_rest_none() { + let mut v = vec![0, 1, 2, 3, 4, 5, 6]; + let mut drain = v.drain(1..6); + + drain.by_ref().for_each(drop); + + drain.keep_rest(); + assert_eq!(v, &[0, 6]); +} + +#[test] +fn test_splice() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(2..4, a); + assert_eq!(v, &[1, 2, 10, 11, 12, 5]); + v.splice(1..3, Some(20)); + assert_eq!(v, &[1, 20, 11, 12, 5]); +} + +#[test] +fn test_splice_inclusive_range() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + let t1: Vec<_> = v.splice(2..=3, a).collect(); + assert_eq!(v, &[1, 2, 10, 11, 12, 5]); + assert_eq!(t1, &[3, 4]); + let t2: Vec<_> = v.splice(1..=2, Some(20)).collect(); + assert_eq!(v, &[1, 20, 11, 12, 5]); + assert_eq!(t2, &[2, 10]); +} + +#[test] +#[should_panic] +fn test_splice_out_of_bounds() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(5..6, a); +} + +#[test] +#[should_panic] +fn test_splice_inclusive_out_of_bounds() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(5..=5, a); +} + +#[test] +fn test_splice_items_zero_sized() { + let mut vec = vec![(), (), ()]; + let vec2 = vec![]; + let t: Vec<_> = vec.splice(1..2, vec2.iter().cloned()).collect(); + assert_eq!(vec, &[(), ()]); + assert_eq!(t, &[()]); +} + +#[test] +fn test_splice_unbounded() { + let mut vec = vec![1, 2, 3, 4, 5]; + let t: Vec<_> = vec.splice(.., None).collect(); + assert_eq!(vec, &[]); + assert_eq!(t, &[1, 2, 3, 4, 5]); +} + +#[test] +fn test_splice_forget() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + std::mem::forget(v.splice(2..4, a)); + assert_eq!(v, &[1, 2]); +} + +#[test] +fn test_into_boxed_slice() { + let xs = vec![1, 2, 3]; + let ys = xs.into_boxed_slice(); + assert_eq!(&*ys, [1, 2, 3]); +} + +#[test] +fn test_append() { + let mut vec = vec![1, 2, 3]; + let mut vec2 = vec![4, 5, 6]; + vec.append(&mut vec2); + assert_eq!(vec, [1, 2, 3, 4, 5, 6]); + assert_eq!(vec2, []); +} + +#[test] +fn test_split_off() { + let mut vec = vec![1, 2, 3, 4, 5, 6]; + let orig_ptr = vec.as_ptr(); + let orig_capacity = vec.capacity(); + + let split_off = vec.split_off(4); + assert_eq!(vec, [1, 2, 3, 4]); + assert_eq!(split_off, [5, 6]); + assert_eq!(vec.capacity(), orig_capacity); + assert_eq!(vec.as_ptr(), orig_ptr); +} + +#[test] +fn test_split_off_take_all() { + // Allocate enough capacity that we can tell whether the split-off vector's + // capacity is based on its size, or (incorrectly) on the original capacity. + let mut vec = Vec::with_capacity(1000); + vec.extend([1, 2, 3, 4, 5, 6]); + let orig_ptr = vec.as_ptr(); + let orig_capacity = vec.capacity(); + + let split_off = vec.split_off(0); + assert_eq!(vec, []); + assert_eq!(split_off, [1, 2, 3, 4, 5, 6]); + assert_eq!(vec.capacity(), orig_capacity); + assert_eq!(vec.as_ptr(), orig_ptr); + + // The split-off vector should be newly-allocated, and should not have + // stolen the original vector's allocation. + assert!(split_off.capacity() < orig_capacity); + assert_ne!(split_off.as_ptr(), orig_ptr); +} + +#[test] +fn test_into_iter_as_slice() { + let vec = vec!['a', 'b', 'c']; + let mut into_iter = vec.into_iter(); + assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + let _ = into_iter.next().unwrap(); + assert_eq!(into_iter.as_slice(), &['b', 'c']); + let _ = into_iter.next().unwrap(); + let _ = into_iter.next().unwrap(); + assert_eq!(into_iter.as_slice(), &[]); +} + +#[test] +fn test_into_iter_as_mut_slice() { + let vec = vec!['a', 'b', 'c']; + let mut into_iter = vec.into_iter(); + assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + into_iter.as_mut_slice()[0] = 'x'; + into_iter.as_mut_slice()[1] = 'y'; + assert_eq!(into_iter.next().unwrap(), 'x'); + assert_eq!(into_iter.as_slice(), &['y', 'c']); +} + +#[test] +fn test_into_iter_debug() { + let vec = vec!['a', 'b', 'c']; + let into_iter = vec.into_iter(); + let debug = format!("{into_iter:?}"); + assert_eq!(debug, "IntoIter(['a', 'b', 'c'])"); +} + +#[test] +fn test_into_iter_count() { + assert_eq!([1, 2, 3].into_iter().count(), 3); +} + +#[test] +fn test_into_iter_next_chunk() { + let mut iter = b"lorem".to_vec().into_iter(); + + assert_eq!(iter.next_chunk().unwrap(), [b'l', b'o']); // N is inferred as 2 + assert_eq!(iter.next_chunk().unwrap(), [b'r', b'e', b'm']); // N is inferred as 3 + assert_eq!(iter.next_chunk::<4>().unwrap_err().as_slice(), &[]); // N is explicitly 4 +} + +#[test] +fn test_into_iter_clone() { + fn iter_equal>(it: I, slice: &[i32]) { + let v: Vec = it.collect(); + assert_eq!(&v[..], slice); + } + let mut it = [1, 2, 3].into_iter(); + iter_equal(it.clone(), &[1, 2, 3]); + assert_eq!(it.next(), Some(1)); + let mut it = it.rev(); + iter_equal(it.clone(), &[3, 2]); + assert_eq!(it.next(), Some(3)); + iter_equal(it.clone(), &[2]); + assert_eq!(it.next(), Some(2)); + iter_equal(it.clone(), &[]); + assert_eq!(it.next(), None); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_into_iter_leak() { + static mut DROPS: i32 = 0; + + struct D(bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.0 { + panic!("panic in `drop`"); + } + } + } + + let v = vec![D(false), D(true), D(false)]; + + catch_unwind(move || drop(v.into_iter())).ok(); + + assert_eq!(unsafe { DROPS }, 3); +} + +#[test] +fn test_into_iter_advance_by() { + let mut i = vec![1, 2, 3, 4, 5].into_iter(); + assert_eq!(i.advance_by(0), Ok(())); + assert_eq!(i.advance_back_by(0), Ok(())); + assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]); + + assert_eq!(i.advance_by(1), Ok(())); + assert_eq!(i.advance_back_by(1), Ok(())); + assert_eq!(i.as_slice(), [2, 3, 4]); + + assert_eq!(i.advance_back_by(usize::MAX), Err(NonZero::new(usize::MAX - 3).unwrap())); + + assert_eq!(i.advance_by(usize::MAX), Err(NonZero::new(usize::MAX).unwrap())); + + assert_eq!(i.advance_by(0), Ok(())); + assert_eq!(i.advance_back_by(0), Ok(())); + + assert_eq!(i.len(), 0); +} + +#[test] +fn test_into_iter_drop_allocator() { + struct ReferenceCountedAllocator<'a>(#[allow(dead_code)] DropCounter<'a>); + + unsafe impl Allocator for ReferenceCountedAllocator<'_> { + fn allocate(&self, layout: Layout) -> Result, core::alloc::AllocError> { + System.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + // Safety: Invariants passed to caller. + unsafe { System.deallocate(ptr, layout) } + } + } + + let mut drop_count = 0; + + let allocator = ReferenceCountedAllocator(DropCounter { count: &mut drop_count }); + let _ = Vec::::new_in(allocator); + assert_eq!(drop_count, 1); + + let allocator = ReferenceCountedAllocator(DropCounter { count: &mut drop_count }); + let _ = Vec::::new_in(allocator).into_iter(); + assert_eq!(drop_count, 2); +} + +#[test] +fn test_into_iter_zst() { + #[derive(Debug, Clone)] + struct AlignedZstWithDrop([u64; 0]); + impl Drop for AlignedZstWithDrop { + fn drop(&mut self) { + let addr = self as *mut _ as usize; + assert!(hint::black_box(addr) % align_of::() == 0); + } + } + + const C: AlignedZstWithDrop = AlignedZstWithDrop([0u64; 0]); + + for _ in vec![C].into_iter() {} + for _ in vec![C; 5].into_iter().rev() {} + + let mut it = vec![C, C].into_iter(); + assert_eq!(it.advance_by(1), Ok(())); + drop(it); + + let mut it = vec![C, C].into_iter(); + it.next_chunk::<1>().unwrap(); + drop(it); + + let mut it = vec![C, C].into_iter(); + it.next_chunk::<4>().unwrap_err(); + drop(it); +} + +#[test] +fn test_from_iter_specialization() { + let src: Vec = vec![0usize; 1]; + let srcptr = src.as_ptr(); + let sink = src.into_iter().collect::>(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr); +} + +#[test] +fn test_from_iter_partially_drained_in_place_specialization() { + let src: Vec = vec![0usize; 10]; + let srcptr = src.as_ptr(); + let mut iter = src.into_iter(); + iter.next(); + iter.next(); + let sink = iter.collect::>(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr); +} + +#[test] +fn test_from_iter_specialization_with_iterator_adapters() { + fn assert_in_place_trait(_: &T) {} + let owned: Vec = vec![0usize; 256]; + let refd: Vec<&usize> = owned.iter().collect(); + let src: Vec<&&usize> = refd.iter().collect(); + let srcptr = src.as_ptr(); + let iter = src + .into_iter() + .copied() + .cloned() + .enumerate() + .map(|i| i.0 + i.1) + .zip(std::iter::repeat(1usize)) + .map(|(a, b)| a + b) + .map_while(Option::Some) + .skip(1) + .map(|e| if e != usize::MAX { Ok(NonZero::new(e)) } else { Err(()) }); + assert_in_place_trait(&iter); + let sink = iter.collect::, _>>().unwrap(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr as *const usize, sinkptr as *const usize); +} + +#[test] +fn test_in_place_specialization_step_up_down() { + fn assert_in_place_trait(_: &T) {} + + let src = vec![0u8; 1024]; + let srcptr = src.as_ptr(); + let src_bytes = src.capacity(); + let iter = src.into_iter().array_chunks::<4>(); + assert_in_place_trait(&iter); + let sink = iter.collect::>(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr.addr(), sinkptr.addr()); + assert_eq!(src_bytes, sink.capacity() * 4); + + let mut src: Vec = Vec::with_capacity(17); + let src_bytes = src.capacity(); + src.resize(8, 0u8); + let sink: Vec<[u8; 4]> = src.into_iter().array_chunks::<4>().collect(); + let sink_bytes = sink.capacity() * 4; + assert_ne!(src_bytes, sink_bytes); + assert_eq!(sink.len(), 2); + + let mut src: Vec<[u8; 3]> = Vec::with_capacity(17); + src.resize(8, [0; 3]); + let iter = src.into_iter().map(|[a, b, _]| [a, b]); + assert_in_place_trait(&iter); + let sink: Vec<[u8; 2]> = iter.collect(); + assert_eq!(sink.len(), 8); + assert!(sink.capacity() <= 25); +} + +#[test] +fn test_from_iter_specialization_head_tail_drop() { + let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect(); + let src: Vec<_> = drop_count.iter().cloned().collect(); + let srcptr = src.as_ptr(); + let iter = src.into_iter(); + let sink: Vec<_> = iter.skip(1).take(1).collect(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr, "specialization was applied"); + assert_eq!(Rc::strong_count(&drop_count[0]), 1, "front was dropped"); + assert_eq!(Rc::strong_count(&drop_count[1]), 2, "one element was collected"); + assert_eq!(Rc::strong_count(&drop_count[2]), 1, "tail was dropped"); + assert_eq!(sink.len(), 1); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_from_iter_specialization_panic_during_iteration_drops() { + let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect(); + let src: Vec<_> = drop_count.iter().cloned().collect(); + let iter = src.into_iter(); + + let _ = std::panic::catch_unwind(AssertUnwindSafe(|| { + let _ = iter + .enumerate() + .filter_map(|(i, e)| { + if i == 1 { + std::panic!("aborting iteration"); + } + Some(e) + }) + .collect::>(); + })); + + assert!( + drop_count.iter().map(Rc::strong_count).all(|count| count == 1), + "all items were dropped once" + ); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#[allow(static_mut_refs)] +fn test_from_iter_specialization_panic_during_drop_doesnt_leak() { + static mut DROP_COUNTER_OLD: [usize; 5] = [0; 5]; + static mut DROP_COUNTER_NEW: [usize; 2] = [0; 2]; + + #[derive(Debug)] + struct Old(usize); + + impl Drop for Old { + fn drop(&mut self) { + unsafe { + DROP_COUNTER_OLD[self.0] += 1; + } + + if self.0 == 3 { + panic!(); + } + + println!("Dropped Old: {}", self.0); + } + } + + #[derive(Debug)] + struct New(usize); + + impl Drop for New { + fn drop(&mut self) { + unsafe { + DROP_COUNTER_NEW[self.0] += 1; + } + + println!("Dropped New: {}", self.0); + } + } + + let _ = std::panic::catch_unwind(AssertUnwindSafe(|| { + let v = vec![Old(0), Old(1), Old(2), Old(3), Old(4)]; + let _ = v.into_iter().map(|x| New(x.0)).take(2).collect::>(); + })); + + assert_eq!(unsafe { DROP_COUNTER_OLD[0] }, 1); + assert_eq!(unsafe { DROP_COUNTER_OLD[1] }, 1); + assert_eq!(unsafe { DROP_COUNTER_OLD[2] }, 1); + assert_eq!(unsafe { DROP_COUNTER_OLD[3] }, 1); + assert_eq!(unsafe { DROP_COUNTER_OLD[4] }, 1); + + assert_eq!(unsafe { DROP_COUNTER_NEW[0] }, 1); + assert_eq!(unsafe { DROP_COUNTER_NEW[1] }, 1); +} + +// regression test for issue #85322. Peekable previously implemented InPlaceIterable, +// but due to an interaction with IntoIter's current Clone implementation it failed to uphold +// the contract. +#[test] +fn test_collect_after_iterator_clone() { + let v = vec![0; 5]; + let mut i = v.into_iter().map(|i| i + 1).peekable(); + i.peek(); + let v = i.clone().collect::>(); + assert_eq!(v, [1, 1, 1, 1, 1]); + assert!(v.len() <= v.capacity()); +} + +// regression test for #135103, similar to the one above Flatten/FlatMap had an unsound InPlaceIterable +// implementation. +#[test] +fn test_flatten_clone() { + const S: String = String::new(); + + let v = vec![[S, "Hello World!".into()], [S, S]]; + let mut i = v.into_iter().flatten(); + let _ = i.next(); + let result: Vec = i.clone().collect(); + assert_eq!(result, ["Hello World!", "", ""]); +} + +#[test] +fn test_cow_from() { + let borrowed: &[_] = &["borrowed", "(slice)"]; + let owned = vec!["owned", "(vec)"]; + match (Cow::from(owned.clone()), Cow::from(borrowed)) { + (Cow::Owned(o), Cow::Borrowed(b)) => assert!(o == owned && b == borrowed), + _ => panic!("invalid `Cow::from`"), + } +} + +#[test] +fn test_from_cow() { + let borrowed: &[_] = &["borrowed", "(slice)"]; + let owned = vec!["owned", "(vec)"]; + assert_eq!(Vec::from(Cow::Borrowed(borrowed)), vec!["borrowed", "(slice)"]); + assert_eq!(Vec::from(Cow::Owned(owned)), vec!["owned", "(vec)"]); +} + +#[allow(dead_code)] +fn assert_covariance() { + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { + d + } + fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> { + i + } +} + +#[test] +fn from_into_inner() { + let vec = vec![1, 2, 3]; + let ptr = vec.as_ptr(); + let vec = vec.into_iter().collect::>(); + assert_eq!(vec, [1, 2, 3]); + assert_eq!(vec.as_ptr(), ptr); + + let ptr = &vec[1] as *const _; + let mut it = vec.into_iter(); + it.next().unwrap(); + let vec = it.collect::>(); + assert_eq!(vec, [2, 3]); + assert!(ptr != vec.as_ptr()); +} + +#[test] +fn overaligned_allocations() { + #[repr(align(256))] + struct Foo(usize); + let mut v = vec![Foo(273)]; + for i in 0..0x1000 { + v.reserve_exact(i); + assert!(v[0].0 == 273); + assert!(v.as_ptr() as usize & 0xff == 0); + v.shrink_to_fit(); + assert!(v[0].0 == 273); + assert!(v.as_ptr() as usize & 0xff == 0); + } +} + +#[test] +fn extract_if_empty() { + let mut vec: Vec = vec![]; + + { + let mut iter = vec.extract_if(.., |_| true); + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + assert_eq!(iter.size_hint(), (0, Some(0))); + } + assert_eq!(vec.len(), 0); + assert_eq!(vec, vec![]); +} + +#[test] +fn extract_if_zst() { + let mut vec = vec![(), (), (), (), ()]; + let initial_len = vec.len(); + let mut count = 0; + { + let mut iter = vec.extract_if(.., |_| true); + assert_eq!(iter.size_hint(), (0, Some(initial_len))); + while let Some(_) = iter.next() { + count += 1; + assert_eq!(iter.size_hint(), (0, Some(initial_len - count))); + } + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + assert_eq!(iter.size_hint(), (0, Some(0))); + } + + assert_eq!(count, initial_len); + assert_eq!(vec.len(), 0); + assert_eq!(vec, vec![]); +} + +#[test] +fn extract_if_false() { + let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + let initial_len = vec.len(); + let mut count = 0; + { + let mut iter = vec.extract_if(.., |_| false); + assert_eq!(iter.size_hint(), (0, Some(initial_len))); + for _ in iter.by_ref() { + count += 1; + } + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + assert_eq!(iter.size_hint(), (0, Some(0))); + } + + assert_eq!(count, 0); + assert_eq!(vec.len(), initial_len); + assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); +} + +#[test] +fn extract_if_true() { + let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + let initial_len = vec.len(); + let mut count = 0; + { + let mut iter = vec.extract_if(.., |_| true); + assert_eq!(iter.size_hint(), (0, Some(initial_len))); + while let Some(_) = iter.next() { + count += 1; + assert_eq!(iter.size_hint(), (0, Some(initial_len - count))); + } + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + assert_eq!(iter.size_hint(), (0, Some(0))); + } + + assert_eq!(count, initial_len); + assert_eq!(vec.len(), 0); + assert_eq!(vec, vec![]); +} + +#[test] +fn extract_if_ranges() { + let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + let mut count = 0; + let it = vec.extract_if(1..=3, |_| { + count += 1; + true + }); + assert_eq!(it.collect::>(), vec![1, 2, 3]); + assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]); + assert_eq!(count, 3); + + let it = vec.extract_if(1..=3, |_| false); + assert_eq!(it.collect::>(), vec![]); + assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]); +} + +#[test] +#[should_panic] +fn extract_if_out_of_bounds() { + let mut vec = vec![0, 1]; + let _ = vec.extract_if(5.., |_| true).for_each(drop); +} + +#[test] +fn extract_if_complex() { + { + // [+xxx++++++xxxxx++++x+x++] + let mut vec = vec![ + 1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, + 39, + ]; + + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); + assert_eq!(removed.len(), 10); + assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); + + assert_eq!(vec.len(), 14); + assert_eq!(vec, vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]); + } + + { + // [xxx++++++xxxxx++++x+x++] + let mut vec = vec![ + 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39, + ]; + + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); + assert_eq!(removed.len(), 10); + assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); + + assert_eq!(vec.len(), 13); + assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]); + } + + { + // [xxx++++++xxxxx++++x+x] + let mut vec = + vec![2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]; + + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); + assert_eq!(removed.len(), 10); + assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); + + assert_eq!(vec.len(), 11); + assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]); + } + + { + // [xxxxxxxxxx+++++++++++] + let mut vec = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; + + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); + assert_eq!(removed.len(), 10); + assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); + + assert_eq!(vec.len(), 10); + assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]); + } + + { + // [+++++++++++xxxxxxxxxx] + let mut vec = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; + + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); + assert_eq!(removed.len(), 10); + assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); + + assert_eq!(vec.len(), 10); + assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]); + } +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn extract_if_consumed_panic() { + use std::rc::Rc; + use std::sync::Mutex; + + struct Check { + index: usize, + drop_counts: Rc>>, + } + + impl Drop for Check { + fn drop(&mut self) { + self.drop_counts.lock().unwrap()[self.index] += 1; + println!("drop: {}", self.index); + } + } + + let check_count = 10; + let drop_counts = Rc::new(Mutex::new(vec![0_usize; check_count])); + let mut data: Vec = (0..check_count) + .map(|index| Check { index, drop_counts: Rc::clone(&drop_counts) }) + .collect(); + + let _ = std::panic::catch_unwind(move || { + let filter = |c: &mut Check| { + if c.index == 2 { + panic!("panic at index: {}", c.index); + } + // Verify that if the filter could panic again on another element + // that it would not cause a double panic and all elements of the + // vec would still be dropped exactly once. + if c.index == 4 { + panic!("panic at index: {}", c.index); + } + c.index < 6 + }; + let drain = data.extract_if(.., filter); + + // NOTE: The ExtractIf is explicitly consumed + drain.for_each(drop); + }); + + let drop_counts = drop_counts.lock().unwrap(); + assert_eq!(check_count, drop_counts.len()); + + for (index, count) in drop_counts.iter().cloned().enumerate() { + assert_eq!(1, count, "unexpected drop count at index: {} (count: {})", index, count); + } +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn extract_if_unconsumed_panic() { + use std::rc::Rc; + use std::sync::Mutex; + + struct Check { + index: usize, + drop_counts: Rc>>, + } + + impl Drop for Check { + fn drop(&mut self) { + self.drop_counts.lock().unwrap()[self.index] += 1; + println!("drop: {}", self.index); + } + } + + let check_count = 10; + let drop_counts = Rc::new(Mutex::new(vec![0_usize; check_count])); + let mut data: Vec = (0..check_count) + .map(|index| Check { index, drop_counts: Rc::clone(&drop_counts) }) + .collect(); + + let _ = std::panic::catch_unwind(move || { + let filter = |c: &mut Check| { + if c.index == 2 { + panic!("panic at index: {}", c.index); + } + // Verify that if the filter could panic again on another element + // that it would not cause a double panic and all elements of the + // vec would still be dropped exactly once. + if c.index == 4 { + panic!("panic at index: {}", c.index); + } + c.index < 6 + }; + let _drain = data.extract_if(.., filter); + + // NOTE: The ExtractIf is dropped without being consumed + }); + + let drop_counts = drop_counts.lock().unwrap(); + assert_eq!(check_count, drop_counts.len()); + + for (index, count) in drop_counts.iter().cloned().enumerate() { + assert_eq!(1, count, "unexpected drop count at index: {} (count: {})", index, count); + } +} + +#[test] +fn extract_if_unconsumed() { + let mut vec = vec![1, 2, 3, 4]; + let drain = vec.extract_if(.., |&mut x| x % 2 != 0); + drop(drain); + assert_eq!(vec, [1, 2, 3, 4]); +} + +#[test] +fn test_reserve_exact() { + // This is all the same as test_reserve + + let mut v = Vec::new(); + assert_eq!(v.capacity(), 0); + + v.reserve_exact(2); + assert!(v.capacity() >= 2); + + for i in 0..16 { + v.push(i); + } + + assert!(v.capacity() >= 16); + v.reserve_exact(16); + assert!(v.capacity() >= 32); + + v.push(16); + + v.reserve_exact(16); + assert!(v.capacity() >= 33) +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +fn test_try_with_capacity() { + let mut vec: Vec = Vec::try_with_capacity(5).unwrap(); + assert_eq!(0, vec.len()); + assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4); + assert!(vec.spare_capacity_mut().len() >= 5); + + assert!(Vec::::try_with_capacity(isize::MAX as usize + 1).is_err()); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +fn test_try_reserve() { + // These are the interesting cases: + // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM) + // * > isize::MAX should always fail + // * On 16/32-bit should CapacityOverflow + // * On 64-bit should OOM + // * overflow may trigger when adding `len` to `cap` (in number of elements) + // * overflow may trigger when multiplying `new_cap` by size_of:: (to get bytes) + + const MAX_CAP: usize = isize::MAX as usize; + const MAX_USIZE: usize = usize::MAX; + + { + // Note: basic stuff is checked by test_reserve + let mut empty_bytes: Vec = Vec::new(); + + // Check isize::MAX doesn't count as an overflow + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + // Play it again, frank! (just to be sure) + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } + + { + // Same basic idea, but with non-zero len + let mut ten_bytes: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Should always overflow in the add-to-len + assert_matches!( + ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } + + { + // Same basic idea, but with interesting type size + let mut ten_u32s: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Should fail in the mul-by-size + assert_matches!( + ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +fn test_try_reserve_exact() { + // This is exactly the same as test_try_reserve with the method changed. + // See that test for comments. + + const MAX_CAP: usize = isize::MAX as usize; + const MAX_USIZE: usize = usize::MAX; + + { + let mut empty_bytes: Vec = Vec::new(); + + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } + + { + let mut ten_bytes: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } + + { + let mut ten_u32s: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } +} + +#[test] +fn test_stable_pointers() { + /// Pull an element from the iterator, then drop it. + /// Useful to cover both the `next` and `drop` paths of an iterator. + fn next_then_drop(mut i: I) { + i.next().unwrap(); + drop(i); + } + + // Test that, if we reserved enough space, adding and removing elements does not + // invalidate references into the vector (such as `v0`). This test also + // runs in Miri, which would detect such problems. + // Note that this test does *not* constitute a stable guarantee that all these functions do not + // reallocate! Only what is explicitly documented at + // is stably guaranteed. + let mut v = Vec::with_capacity(128); + v.push(13); + + // Laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + let v0 = &mut v[0]; + let v0 = unsafe { &mut *(v0 as *mut _) }; + // Now do a bunch of things and occasionally use `v0` again to assert it is still valid. + + // Pushing/inserting and popping/removing + v.push(1); + v.push(2); + v.insert(1, 1); + assert_eq!(*v0, 13); + v.remove(1); + v.pop().unwrap(); + assert_eq!(*v0, 13); + v.push(1); + v.swap_remove(1); + assert_eq!(v.len(), 2); + v.swap_remove(1); // swap_remove the last element + assert_eq!(*v0, 13); + + // Appending + v.append(&mut vec![27, 19]); + assert_eq!(*v0, 13); + + // Extending + v.extend_from_slice(&[1, 2]); + v.extend(&[1, 2]); // `slice::Iter` (with `T: Copy`) specialization + v.extend(vec![2, 3]); // `vec::IntoIter` specialization + v.extend(std::iter::once(3)); // `TrustedLen` specialization + v.extend(std::iter::empty::()); // `TrustedLen` specialization with empty iterator + v.extend(std::iter::once(3).filter(|_| true)); // base case + v.extend(std::iter::once(&3)); // `cloned` specialization + assert_eq!(*v0, 13); + + // Truncation + v.truncate(2); + assert_eq!(*v0, 13); + + // Resizing + v.resize_with(v.len() + 10, || 42); + assert_eq!(*v0, 13); + v.resize_with(2, || panic!()); + assert_eq!(*v0, 13); + + // No-op reservation + v.reserve(32); + v.reserve_exact(32); + assert_eq!(*v0, 13); + + // Partial draining + v.resize_with(10, || 42); + next_then_drop(v.drain(5..)); + assert_eq!(*v0, 13); + + // Splicing + v.resize_with(10, || 42); + next_then_drop(v.splice(5.., vec![1, 2, 3, 4, 5])); // empty tail after range + assert_eq!(*v0, 13); + next_then_drop(v.splice(5..8, vec![1])); // replacement is smaller than original range + assert_eq!(*v0, 13); + next_then_drop(v.splice(5..6, [1; 10].into_iter().filter(|_| true))); // lower bound not exact + assert_eq!(*v0, 13); + + // spare_capacity_mut + v.spare_capacity_mut(); + assert_eq!(*v0, 13); + + // Smoke test that would fire even outside Miri if an actual relocation happened. + // Also ensures the pointer is still writeable after all this. + *v0 -= 13; + assert_eq!(v[0], 0); +} + +// https://github.com/rust-lang/rust/pull/49496 introduced specialization based on: +// +// ``` +// unsafe impl IsZero for *mut T { +// fn is_zero(&self) -> bool { +// (*self).is_null() +// } +// } +// ``` +// +// … to call `RawVec::with_capacity_zeroed` for creating `Vec<*mut T>`, +// which is incorrect for fat pointers since `<*mut T>::is_null` only looks at the data component. +// That is, a fat pointer can be “null” without being made entirely of zero bits. +#[test] +fn vec_macro_repeating_null_raw_fat_pointer() { + let raw_dyn = &mut (|| ()) as &mut dyn Fn() as *mut dyn Fn(); + let vtable = dbg!(ptr_metadata(raw_dyn)); + let null_raw_dyn = ptr_from_raw_parts(std::ptr::null_mut(), vtable); + assert!(null_raw_dyn.is_null()); + + let vec = vec![null_raw_dyn; 1]; + dbg!(ptr_metadata(vec[0])); + assert!(std::ptr::eq(vec[0], null_raw_dyn)); + + // Polyfill for https://github.com/rust-lang/rfcs/pull/2580 + + fn ptr_metadata(ptr: *mut dyn Fn()) -> *mut () { + unsafe { std::mem::transmute::<*mut dyn Fn(), DynRepr>(ptr).vtable } + } + + fn ptr_from_raw_parts(data: *mut (), vtable: *mut ()) -> *mut dyn Fn() { + unsafe { std::mem::transmute::(DynRepr { data, vtable }) } + } + + #[repr(C)] + struct DynRepr { + data: *mut (), + vtable: *mut (), + } +} + +// This test will likely fail if you change the capacities used in +// `RawVec::grow_amortized`. +#[test] +fn test_push_growth_strategy() { + // If the element size is 1, we jump from 0 to 8, then double. + { + let mut v1: Vec = vec![]; + assert_eq!(v1.capacity(), 0); + + for _ in 0..8 { + v1.push(0); + assert_eq!(v1.capacity(), 8); + } + + for _ in 8..16 { + v1.push(0); + assert_eq!(v1.capacity(), 16); + } + + for _ in 16..32 { + v1.push(0); + assert_eq!(v1.capacity(), 32); + } + + for _ in 32..64 { + v1.push(0); + assert_eq!(v1.capacity(), 64); + } + } + + // If the element size is 2..=1024, we jump from 0 to 4, then double. + { + let mut v2: Vec = vec![]; + let mut v1024: Vec<[u8; 1024]> = vec![]; + assert_eq!(v2.capacity(), 0); + assert_eq!(v1024.capacity(), 0); + + for _ in 0..4 { + v2.push(0); + v1024.push([0; 1024]); + assert_eq!(v2.capacity(), 4); + assert_eq!(v1024.capacity(), 4); + } + + for _ in 4..8 { + v2.push(0); + v1024.push([0; 1024]); + assert_eq!(v2.capacity(), 8); + assert_eq!(v1024.capacity(), 8); + } + + for _ in 8..16 { + v2.push(0); + v1024.push([0; 1024]); + assert_eq!(v2.capacity(), 16); + assert_eq!(v1024.capacity(), 16); + } + + for _ in 16..32 { + v2.push(0); + v1024.push([0; 1024]); + assert_eq!(v2.capacity(), 32); + assert_eq!(v1024.capacity(), 32); + } + + for _ in 32..64 { + v2.push(0); + v1024.push([0; 1024]); + assert_eq!(v2.capacity(), 64); + assert_eq!(v1024.capacity(), 64); + } + } + + // If the element size is > 1024, we jump from 0 to 1, then double. + { + let mut v1025: Vec<[u8; 1025]> = vec![]; + assert_eq!(v1025.capacity(), 0); + + for _ in 0..1 { + v1025.push([0; 1025]); + assert_eq!(v1025.capacity(), 1); + } + + for _ in 1..2 { + v1025.push([0; 1025]); + assert_eq!(v1025.capacity(), 2); + } + + for _ in 2..4 { + v1025.push([0; 1025]); + assert_eq!(v1025.capacity(), 4); + } + + for _ in 4..8 { + v1025.push([0; 1025]); + assert_eq!(v1025.capacity(), 8); + } + + for _ in 8..16 { + v1025.push([0; 1025]); + assert_eq!(v1025.capacity(), 16); + } + + for _ in 16..32 { + v1025.push([0; 1025]); + assert_eq!(v1025.capacity(), 32); + } + + for _ in 32..64 { + v1025.push([0; 1025]); + assert_eq!(v1025.capacity(), 64); + } + } +} + +macro_rules! generate_assert_eq_vec_and_prim { + ($name:ident<$B:ident>($type:ty)) => { + fn $name + Debug, $B: Debug>(a: Vec, b: $type) { + assert!(a == b); + assert_eq!(a, b); + } + }; +} + +generate_assert_eq_vec_and_prim! { assert_eq_vec_and_slice (&[B]) } +generate_assert_eq_vec_and_prim! { assert_eq_vec_and_array_3([B; 3]) } + +#[test] +fn partialeq_vec_and_prim() { + assert_eq_vec_and_slice(vec![1, 2, 3], &[1, 2, 3]); + assert_eq_vec_and_array_3(vec![1, 2, 3], [1, 2, 3]); +} + +macro_rules! assert_partial_eq_valid { + ($a2:expr, $a3:expr; $b2:expr, $b3: expr) => { + assert!($a2 == $b2); + assert!($a2 != $b3); + assert!($a3 != $b2); + assert!($a3 == $b3); + assert_eq!($a2, $b2); + assert_ne!($a2, $b3); + assert_ne!($a3, $b2); + assert_eq!($a3, $b3); + }; +} + +#[test] +fn partialeq_vec_full() { + let vec2: Vec<_> = vec![1, 2]; + let vec3: Vec<_> = vec![1, 2, 3]; + let slice2: &[_] = &[1, 2]; + let slice3: &[_] = &[1, 2, 3]; + let slicemut2: &[_] = &mut [1, 2]; + let slicemut3: &[_] = &mut [1, 2, 3]; + let array2: [_; 2] = [1, 2]; + let array3: [_; 3] = [1, 2, 3]; + let arrayref2: &[_; 2] = &[1, 2]; + let arrayref3: &[_; 3] = &[1, 2, 3]; + + assert_partial_eq_valid!(vec2,vec3; vec2,vec3); + assert_partial_eq_valid!(vec2,vec3; slice2,slice3); + assert_partial_eq_valid!(vec2,vec3; slicemut2,slicemut3); + assert_partial_eq_valid!(slice2,slice3; vec2,vec3); + assert_partial_eq_valid!(slicemut2,slicemut3; vec2,vec3); + assert_partial_eq_valid!(vec2,vec3; array2,array3); + assert_partial_eq_valid!(vec2,vec3; arrayref2,arrayref3); + assert_partial_eq_valid!(vec2,vec3; arrayref2[..],arrayref3[..]); +} + +#[test] +fn test_vec_cycle() { + #[derive(Debug)] + struct C<'a> { + v: Vec>>>, + } + + impl<'a> C<'a> { + fn new() -> C<'a> { + C { v: Vec::new() } + } + } + + let mut c1 = C::new(); + let mut c2 = C::new(); + let mut c3 = C::new(); + + // Push + c1.v.push(Cell::new(None)); + c1.v.push(Cell::new(None)); + + c2.v.push(Cell::new(None)); + c2.v.push(Cell::new(None)); + + c3.v.push(Cell::new(None)); + c3.v.push(Cell::new(None)); + + // Set + c1.v[0].set(Some(&c2)); + c1.v[1].set(Some(&c3)); + + c2.v[0].set(Some(&c2)); + c2.v[1].set(Some(&c3)); + + c3.v[0].set(Some(&c1)); + c3.v[1].set(Some(&c2)); +} + +#[test] +fn test_vec_cycle_wrapped() { + struct Refs<'a> { + v: Vec>>>, + } + + struct C<'a> { + refs: Refs<'a>, + } + + impl<'a> Refs<'a> { + fn new() -> Refs<'a> { + Refs { v: Vec::new() } + } + } + + impl<'a> C<'a> { + fn new() -> C<'a> { + C { refs: Refs::new() } + } + } + + let mut c1 = C::new(); + let mut c2 = C::new(); + let mut c3 = C::new(); + + c1.refs.v.push(Cell::new(None)); + c1.refs.v.push(Cell::new(None)); + c2.refs.v.push(Cell::new(None)); + c2.refs.v.push(Cell::new(None)); + c3.refs.v.push(Cell::new(None)); + c3.refs.v.push(Cell::new(None)); + + c1.refs.v[0].set(Some(&c2)); + c1.refs.v[1].set(Some(&c3)); + c2.refs.v[0].set(Some(&c2)); + c2.refs.v[1].set(Some(&c3)); + c3.refs.v[0].set(Some(&c1)); + c3.refs.v[1].set(Some(&c2)); +} + +#[test] +fn test_zero_sized_capacity() { + for len in [0, 1, 2, 4, 8, 16, 32, 64, 128, 256] { + let v = Vec::<()>::with_capacity(len); + assert_eq!(v.len(), 0); + assert_eq!(v.capacity(), usize::MAX); + } +} + +#[test] +fn test_zero_sized_vec_push() { + const N: usize = 8; + + for len in 0..N { + let mut tester = Vec::with_capacity(len); + assert_eq!(tester.len(), 0); + assert!(tester.capacity() >= len); + for _ in 0..len { + tester.push(()); + } + assert_eq!(tester.len(), len); + assert_eq!(tester.iter().count(), len); + tester.clear(); + } +} + +#[test] +fn test_vec_macro_repeat() { + assert_eq!(vec![1; 3], vec![1, 1, 1]); + assert_eq!(vec![1; 2], vec![1, 1]); + assert_eq!(vec![1; 1], vec![1]); + assert_eq!(vec![1; 0], vec![]); + + // from_elem syntax (see RFC 832) + let el = Box::new(1); + let n = 3; + assert_eq!(vec![el; n], vec![Box::new(1), Box::new(1), Box::new(1)]); +} + +#[test] +fn test_vec_swap() { + let mut a: Vec = vec![0, 1, 2, 3, 4, 5, 6]; + a.swap(2, 4); + assert_eq!(a[2], 4); + assert_eq!(a[4], 2); + let mut n = 42; + swap(&mut n, &mut a[0]); + assert_eq!(a[0], 42); + assert_eq!(n, 0); +} + +#[test] +fn test_extend_from_within_spec() { + #[derive(Copy)] + struct CopyOnly; + + impl Clone for CopyOnly { + fn clone(&self) -> Self { + panic!("extend_from_within must use specialization on copy"); + } + } + + vec![CopyOnly, CopyOnly].extend_from_within(..); +} + +#[test] +fn test_extend_from_within_clone() { + let mut v = vec![String::from("sssss"), String::from("12334567890"), String::from("c")]; + v.extend_from_within(1..); + + assert_eq!(v, ["sssss", "12334567890", "c", "12334567890", "c"]); +} + +#[test] +fn test_extend_from_within_complete_rande() { + let mut v = vec![0, 1, 2, 3]; + v.extend_from_within(..); + + assert_eq!(v, [0, 1, 2, 3, 0, 1, 2, 3]); +} + +#[test] +fn test_extend_from_within_empty_rande() { + let mut v = vec![0, 1, 2, 3]; + v.extend_from_within(1..1); + + assert_eq!(v, [0, 1, 2, 3]); +} + +#[test] +#[should_panic] +fn test_extend_from_within_out_of_rande() { + let mut v = vec![0, 1]; + v.extend_from_within(..3); +} + +#[test] +fn test_extend_from_within_zst() { + let mut v = vec![(); 8]; + v.extend_from_within(3..7); + + assert_eq!(v, [(); 12]); +} + +#[test] +fn test_extend_from_within_empty_vec() { + let mut v = Vec::::new(); + v.extend_from_within(..); + + assert_eq!(v, []); +} + +#[test] +fn test_extend_from_within() { + let mut v = vec![String::from("a"), String::from("b"), String::from("c")]; + v.extend_from_within(1..=2); + v.extend_from_within(..=1); + + assert_eq!(v, ["a", "b", "c", "b", "c", "a", "b"]); +} + +#[test] +fn test_vec_dedup_by() { + let mut vec: Vec = vec![1, -1, 2, 3, 1, -5, 5, -2, 2]; + + vec.dedup_by(|a, b| a.abs() == b.abs()); + + assert_eq!(vec, [1, 2, 3, 1, -5, -2]); +} + +#[test] +fn test_vec_dedup_empty() { + let mut vec: Vec = Vec::new(); + + vec.dedup(); + + assert_eq!(vec, []); +} + +#[test] +fn test_vec_dedup_one() { + let mut vec = vec![12i32]; + + vec.dedup(); + + assert_eq!(vec, [12]); +} + +#[test] +fn test_vec_dedup_multiple_ident() { + let mut vec = vec![12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11]; + + vec.dedup(); + + assert_eq!(vec, [12, 11]); +} + +#[test] +fn test_vec_dedup_partialeq() { + #[derive(Debug)] + struct Foo(i32, #[allow(dead_code)] i32); + + impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.0 == other.0 + } + } + + let mut vec = vec![Foo(0, 1), Foo(0, 5), Foo(1, 7), Foo(1, 9)]; + + vec.dedup(); + assert_eq!(vec, [Foo(0, 1), Foo(1, 7)]); +} + +#[test] +fn test_vec_dedup() { + let mut vec: Vec = Vec::with_capacity(8); + let mut template = vec.clone(); + + for x in 0u8..255u8 { + vec.clear(); + template.clear(); + + let iter = (0..8).map(move |bit| (x >> bit) & 1 == 1); + vec.extend(iter); + template.extend_from_slice(&vec); + + let (dedup, _) = template.partition_dedup(); + vec.dedup(); + + assert_eq!(vec, dedup); + } +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_vec_dedup_panicking() { + #[derive(Debug)] + struct Panic<'a> { + drop_counter: &'a Cell, + value: bool, + index: usize, + } + + impl<'a> PartialEq for Panic<'a> { + fn eq(&self, other: &Self) -> bool { + self.value == other.value + } + } + + impl<'a> Drop for Panic<'a> { + fn drop(&mut self) { + self.drop_counter.set(self.drop_counter.get() + 1); + if !std::thread::panicking() { + assert!(self.index != 4); + } + } + } + + let drop_counter = &Cell::new(0); + let expected = [ + Panic { drop_counter, value: false, index: 0 }, + Panic { drop_counter, value: false, index: 5 }, + Panic { drop_counter, value: true, index: 6 }, + Panic { drop_counter, value: true, index: 7 }, + ]; + let mut vec = vec![ + Panic { drop_counter, value: false, index: 0 }, + // these elements get deduplicated + Panic { drop_counter, value: false, index: 1 }, + Panic { drop_counter, value: false, index: 2 }, + Panic { drop_counter, value: false, index: 3 }, + Panic { drop_counter, value: false, index: 4 }, + // here it panics while dropping the item with index==4 + Panic { drop_counter, value: false, index: 5 }, + Panic { drop_counter, value: true, index: 6 }, + Panic { drop_counter, value: true, index: 7 }, + ]; + + let _ = catch_unwind(AssertUnwindSafe(|| vec.dedup())).unwrap_err(); + + assert_eq!(drop_counter.get(), 4); + + let ok = vec.iter().zip(expected.iter()).all(|(x, y)| x.index == y.index); + + if !ok { + panic!("expected: {expected:?}\ngot: {vec:?}\n"); + } +} + +// Regression test for issue #82533 +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_extend_from_within_panicking_clone() { + struct Panic<'dc> { + drop_count: &'dc AtomicU32, + aaaaa: bool, + } + + impl Clone for Panic<'_> { + fn clone(&self) -> Self { + if self.aaaaa { + panic!("panic! at the clone"); + } + + Self { ..*self } + } + } + + impl Drop for Panic<'_> { + fn drop(&mut self) { + self.drop_count.fetch_add(1, Ordering::SeqCst); + } + } + + let count = core::sync::atomic::AtomicU32::new(0); + let mut vec = vec![ + Panic { drop_count: &count, aaaaa: false }, + Panic { drop_count: &count, aaaaa: true }, + Panic { drop_count: &count, aaaaa: false }, + ]; + + // This should clone&append one Panic{..} at the end, and then panic while + // cloning second Panic{..}. This means that `Panic::drop` should be called + // 4 times (3 for items already in vector, 1 for just appended). + // + // Previously just appended item was leaked, making drop_count = 3, instead of 4. + std::panic::catch_unwind(move || vec.extend_from_within(..)).unwrap_err(); + + assert_eq!(count.load(Ordering::SeqCst), 4); +} + +#[test] +#[should_panic = "vec len overflow"] +fn test_into_flattened_size_overflow() { + let v = vec![[(); usize::MAX]; 2]; + let _ = v.into_flattened(); +} + +#[test] +fn test_box_zero_allocator() { + use core::alloc::AllocError; + use core::cell::RefCell; + use std::collections::HashSet; + + // Track ZST allocations and ensure that they all have a matching free. + struct ZstTracker { + state: RefCell<(HashSet, usize)>, + } + unsafe impl Allocator for ZstTracker { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + let ptr = if layout.size() == 0 { + let mut state = self.state.borrow_mut(); + let addr = state.1; + assert!(state.0.insert(addr)); + state.1 += 1; + std::println!("allocating {addr}"); + std::ptr::without_provenance_mut(addr) + } else { + unsafe { std::alloc::alloc(layout) } + }; + Ok(NonNull::slice_from_raw_parts(NonNull::new(ptr).ok_or(AllocError)?, layout.size())) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + if layout.size() == 0 { + let addr = ptr.as_ptr() as usize; + let mut state = self.state.borrow_mut(); + std::println!("freeing {addr}"); + assert!(state.0.remove(&addr), "ZST free that wasn't allocated"); + } else { + unsafe { std::alloc::dealloc(ptr.as_ptr(), layout) } + } + } + } + + // Start the state at 100 to avoid returning null pointers. + let alloc = ZstTracker { state: RefCell::new((HashSet::new(), 100)) }; + + // Ensure that unsizing retains the same behavior. + { + let b1: Box<[u8; 0], &ZstTracker> = Box::new_in([], &alloc); + let b2: Box<[u8], &ZstTracker> = b1.clone(); + let _b3: Box<[u8], &ZstTracker> = b2.clone(); + } + + // Ensure that shrinking doesn't leak a ZST allocation. + { + let mut v1: Vec = Vec::with_capacity_in(100, &alloc); + v1.shrink_to_fit(); + } + + // Ensure that conversion to/from vec works. + { + let v1: Vec<(), &ZstTracker> = Vec::with_capacity_in(100, &alloc); + let _b1: Box<[()], &ZstTracker> = v1.into_boxed_slice(); + let b2: Box<[()], &ZstTracker> = Box::new_in([(), (), ()], &alloc); + let _v2: Vec<(), &ZstTracker> = b2.into(); + } + + // Ensure all ZSTs have been freed. + assert!(alloc.state.borrow().0.is_empty()); +} + +#[test] +fn test_vec_from_array_ref() { + assert_eq!(Vec::from(&[1, 2, 3]), vec![1, 2, 3]); +} + +#[test] +fn test_vec_from_array_mut_ref() { + assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]); +} + +#[test] +fn test_pop_if() { + let mut v = vec![1, 2, 3, 4]; + let pred = |x: &mut i32| *x % 2 == 0; + + assert_eq!(v.pop_if(pred), Some(4)); + assert_eq!(v, [1, 2, 3]); + + assert_eq!(v.pop_if(pred), None); + assert_eq!(v, [1, 2, 3]); +} + +#[test] +fn test_pop_if_empty() { + let mut v = Vec::::new(); + assert_eq!(v.pop_if(|_| true), None); + assert!(v.is_empty()); +} + +#[test] +fn test_pop_if_mutates() { + let mut v = vec![1]; + let pred = |x: &mut i32| { + *x += 1; + false + }; + assert_eq!(v.pop_if(pred), None); + assert_eq!(v, [2]); +} + +/// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments +/// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but +/// `vec.insert(usize::MAX, val)` once slipped by! +/// +/// All code that manipulates the collection types should be tested with "trivially wrong" args. +#[test] +fn max_dont_panic() { + let mut v = vec![0]; + let _ = v.get(usize::MAX); + v.shrink_to(usize::MAX); + v.truncate(usize::MAX); +} + +#[test] +#[should_panic] +fn max_insert() { + let mut v = vec![0]; + v.insert(usize::MAX, 1); +} + +#[test] +#[should_panic] +fn max_remove() { + let mut v = vec![0]; + v.remove(usize::MAX); +} + +#[test] +#[should_panic] +fn max_splice() { + let mut v = vec![0]; + v.splice(usize::MAX.., core::iter::once(1)); +} + +#[test] +#[should_panic] +fn max_swap_remove() { + let mut v = vec![0]; + v.swap_remove(usize::MAX); +} + +// Regression test for #135338 +#[test] +fn vec_null_ptr_roundtrip() { + let ptr = std::ptr::from_ref(&42); + let zero = ptr.with_addr(0); + let roundtripped = vec![zero; 1].pop().unwrap(); + let new = roundtripped.with_addr(ptr.addr()); + unsafe { new.read() }; +} diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs new file mode 100644 index 00000000000..1b03c29e5bd --- /dev/null +++ b/library/alloctests/tests/vec_deque.rs @@ -0,0 +1,1865 @@ +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + +use core::num::NonZero; +use std::assert_matches::assert_matches; +use std::collections::TryReserveErrorKind::*; +use std::collections::VecDeque; +use std::collections::vec_deque::Drain; +use std::fmt::Debug; +use std::ops::Bound::*; +use std::panic::{AssertUnwindSafe, catch_unwind}; + +use Taggy::*; +use Taggypar::*; + +use crate::hash; + +#[test] +fn test_simple() { + let mut d = VecDeque::new(); + assert_eq!(d.len(), 0); + d.push_front(17); + d.push_front(42); + d.push_back(137); + assert_eq!(d.len(), 3); + d.push_back(137); + assert_eq!(d.len(), 4); + assert_eq!(*d.front().unwrap(), 42); + assert_eq!(*d.back().unwrap(), 137); + let mut i = d.pop_front(); + assert_eq!(i, Some(42)); + i = d.pop_back(); + assert_eq!(i, Some(137)); + i = d.pop_back(); + assert_eq!(i, Some(137)); + i = d.pop_back(); + assert_eq!(i, Some(17)); + assert_eq!(d.len(), 0); + d.push_back(3); + assert_eq!(d.len(), 1); + d.push_front(2); + assert_eq!(d.len(), 2); + d.push_back(4); + assert_eq!(d.len(), 3); + d.push_front(1); + assert_eq!(d.len(), 4); + assert_eq!(d[0], 1); + assert_eq!(d[1], 2); + assert_eq!(d[2], 3); + assert_eq!(d[3], 4); +} + +fn test_parameterized(a: T, b: T, c: T, d: T) { + let mut deq = VecDeque::new(); + assert_eq!(deq.len(), 0); + deq.push_front(a.clone()); + deq.push_front(b.clone()); + deq.push_back(c.clone()); + assert_eq!(deq.len(), 3); + deq.push_back(d.clone()); + assert_eq!(deq.len(), 4); + assert_eq!((*deq.front().unwrap()).clone(), b.clone()); + assert_eq!((*deq.back().unwrap()).clone(), d.clone()); + assert_eq!(deq.pop_front().unwrap(), b.clone()); + assert_eq!(deq.pop_back().unwrap(), d.clone()); + assert_eq!(deq.pop_back().unwrap(), c.clone()); + assert_eq!(deq.pop_back().unwrap(), a.clone()); + assert_eq!(deq.len(), 0); + deq.push_back(c.clone()); + assert_eq!(deq.len(), 1); + deq.push_front(b.clone()); + assert_eq!(deq.len(), 2); + deq.push_back(d.clone()); + assert_eq!(deq.len(), 3); + deq.push_front(a.clone()); + assert_eq!(deq.len(), 4); + assert_eq!(deq[0].clone(), a.clone()); + assert_eq!(deq[1].clone(), b.clone()); + assert_eq!(deq[2].clone(), c.clone()); + assert_eq!(deq[3].clone(), d.clone()); +} + +#[test] +fn test_pop_if() { + let mut deq: VecDeque<_> = vec![0, 1, 2, 3, 4].into(); + let pred = |x: &mut i32| *x % 2 == 0; + + assert_eq!(deq.pop_front_if(pred), Some(0)); + assert_eq!(deq, [1, 2, 3, 4]); + + assert_eq!(deq.pop_front_if(pred), None); + assert_eq!(deq, [1, 2, 3, 4]); + + assert_eq!(deq.pop_back_if(pred), Some(4)); + assert_eq!(deq, [1, 2, 3]); + + assert_eq!(deq.pop_back_if(pred), None); + assert_eq!(deq, [1, 2, 3]); +} + +#[test] +fn test_pop_if_empty() { + let mut deq = VecDeque::::new(); + assert_eq!(deq.pop_front_if(|_| true), None); + assert_eq!(deq.pop_back_if(|_| true), None); + assert!(deq.is_empty()); +} + +#[test] +fn test_pop_if_mutates() { + let mut v: VecDeque<_> = vec![-1, 1].into(); + let pred = |x: &mut i32| { + *x *= 2; + false + }; + assert_eq!(v.pop_front_if(pred), None); + assert_eq!(v, [-2, 1]); + assert_eq!(v.pop_back_if(pred), None); + assert_eq!(v, [-2, 2]); +} + +#[test] +fn test_push_front_grow() { + let mut deq = VecDeque::new(); + for i in 0..66 { + deq.push_front(i); + } + assert_eq!(deq.len(), 66); + + for i in 0..66 { + assert_eq!(deq[i], 65 - i); + } + + let mut deq = VecDeque::new(); + for i in 0..66 { + deq.push_back(i); + } + + for i in 0..66 { + assert_eq!(deq[i], i); + } +} + +#[test] +fn test_index() { + let mut deq = VecDeque::new(); + for i in 1..4 { + deq.push_front(i); + } + assert_eq!(deq[1], 2); +} + +#[test] +#[should_panic] +fn test_index_out_of_bounds() { + let mut deq = VecDeque::new(); + for i in 1..4 { + deq.push_front(i); + } + deq[3]; +} + +#[test] +#[should_panic] +fn test_range_start_overflow() { + let deq = VecDeque::from(vec![1, 2, 3]); + deq.range((Included(0), Included(usize::MAX))); +} + +#[test] +#[should_panic] +fn test_range_end_overflow() { + let deq = VecDeque::from(vec![1, 2, 3]); + deq.range((Excluded(usize::MAX), Included(0))); +} + +#[derive(Clone, PartialEq, Debug)] +enum Taggy { + One(i32), + Two(i32, i32), + Three(i32, i32, i32), +} + +#[derive(Clone, PartialEq, Debug)] +enum Taggypar { + Onepar(T), + Twopar(T, T), + Threepar(T, T, T), +} + +#[derive(Clone, PartialEq, Debug)] +struct RecCy { + x: i32, + y: i32, + t: Taggy, +} + +#[test] +fn test_param_int() { + test_parameterized::(5, 72, 64, 175); +} + +#[test] +fn test_param_taggy() { + test_parameterized::(One(1), Two(1, 2), Three(1, 2, 3), Two(17, 42)); +} + +#[test] +fn test_param_taggypar() { + test_parameterized::>( + Onepar::(1), + Twopar::(1, 2), + Threepar::(1, 2, 3), + Twopar::(17, 42), + ); +} + +#[test] +fn test_param_reccy() { + let reccy1 = RecCy { x: 1, y: 2, t: One(1) }; + let reccy2 = RecCy { x: 345, y: 2, t: Two(1, 2) }; + let reccy3 = RecCy { x: 1, y: 777, t: Three(1, 2, 3) }; + let reccy4 = RecCy { x: 19, y: 252, t: Two(17, 42) }; + test_parameterized::(reccy1, reccy2, reccy3, reccy4); +} + +#[test] +fn test_with_capacity() { + let mut d = VecDeque::with_capacity(0); + d.push_back(1); + assert_eq!(d.len(), 1); + let mut d = VecDeque::with_capacity(50); + d.push_back(1); + assert_eq!(d.len(), 1); +} + +#[test] +fn test_with_capacity_non_power_two() { + let mut d3 = VecDeque::with_capacity(3); + d3.push_back(1); + + // X = None, | = lo + // [|1, X, X] + assert_eq!(d3.pop_front(), Some(1)); + // [X, |X, X] + assert_eq!(d3.front(), None); + + // [X, |3, X] + d3.push_back(3); + // [X, |3, 6] + d3.push_back(6); + // [X, X, |6] + assert_eq!(d3.pop_front(), Some(3)); + + // Pushing the lo past half way point to trigger + // the 'B' scenario for growth + // [9, X, |6] + d3.push_back(9); + // [9, 12, |6] + d3.push_back(12); + + d3.push_back(15); + // There used to be a bug here about how the + // VecDeque made growth assumptions about the + // underlying Vec which didn't hold and lead + // to corruption. + // (Vec grows to next power of two) + // good- [9, 12, 15, X, X, X, X, |6] + // bug- [15, 12, X, X, X, |6, X, X] + assert_eq!(d3.pop_front(), Some(6)); + + // Which leads us to the following state which + // would be a failure case. + // bug- [15, 12, X, X, X, X, |X, X] + assert_eq!(d3.front(), Some(&9)); +} + +#[test] +fn test_reserve_exact() { + let mut d = VecDeque::new(); + d.push_back(0); + d.reserve_exact(50); + assert!(d.capacity() >= 51); +} + +#[test] +fn test_reserve() { + let mut d = VecDeque::new(); + d.push_back(0); + d.reserve(50); + assert!(d.capacity() >= 51); +} + +#[test] +fn test_swap() { + let mut d: VecDeque<_> = (0..5).collect(); + d.pop_front(); + d.swap(0, 3); + assert_eq!(d.iter().cloned().collect::>(), [4, 2, 3, 1]); +} + +#[test] +fn test_iter() { + let mut d = VecDeque::new(); + assert_eq!(d.iter().next(), None); + assert_eq!(d.iter().size_hint(), (0, Some(0))); + + for i in 0..5 { + d.push_back(i); + } + { + let b: &[_] = &[&0, &1, &2, &3, &4]; + assert_eq!(d.iter().collect::>(), b); + } + + for i in 6..9 { + d.push_front(i); + } + { + let b: &[_] = &[&8, &7, &6, &0, &1, &2, &3, &4]; + assert_eq!(d.iter().collect::>(), b); + } + + let mut it = d.iter(); + let mut len = d.len(); + loop { + match it.next() { + None => break, + _ => { + len -= 1; + assert_eq!(it.size_hint(), (len, Some(len))) + } + } + } +} + +#[test] +fn test_rev_iter() { + let mut d = VecDeque::new(); + assert_eq!(d.iter().rev().next(), None); + + for i in 0..5 { + d.push_back(i); + } + { + let b: &[_] = &[&4, &3, &2, &1, &0]; + assert_eq!(d.iter().rev().collect::>(), b); + } + + for i in 6..9 { + d.push_front(i); + } + let b: &[_] = &[&4, &3, &2, &1, &0, &6, &7, &8]; + assert_eq!(d.iter().rev().collect::>(), b); +} + +#[test] +fn test_mut_rev_iter_wrap() { + let mut d = VecDeque::with_capacity(3); + assert!(d.iter_mut().rev().next().is_none()); + + d.push_back(1); + d.push_back(2); + d.push_back(3); + assert_eq!(d.pop_front(), Some(1)); + d.push_back(4); + + assert_eq!(d.iter_mut().rev().map(|x| *x).collect::>(), vec![4, 3, 2]); +} + +#[test] +fn test_mut_iter() { + let mut d = VecDeque::new(); + assert!(d.iter_mut().next().is_none()); + + for i in 0..3 { + d.push_front(i); + } + + for (i, elt) in d.iter_mut().enumerate() { + assert_eq!(*elt, 2 - i); + *elt = i; + } + + { + let mut it = d.iter_mut(); + assert_eq!(*it.next().unwrap(), 0); + assert_eq!(*it.next().unwrap(), 1); + assert_eq!(*it.next().unwrap(), 2); + assert!(it.next().is_none()); + } +} + +#[test] +fn test_mut_rev_iter() { + let mut d = VecDeque::new(); + assert!(d.iter_mut().rev().next().is_none()); + + for i in 0..3 { + d.push_front(i); + } + + for (i, elt) in d.iter_mut().rev().enumerate() { + assert_eq!(*elt, i); + *elt = i; + } + + { + let mut it = d.iter_mut().rev(); + assert_eq!(*it.next().unwrap(), 0); + assert_eq!(*it.next().unwrap(), 1); + assert_eq!(*it.next().unwrap(), 2); + assert!(it.next().is_none()); + } +} + +#[test] +fn test_into_iter() { + // Empty iter + { + let d: VecDeque = VecDeque::new(); + let mut iter = d.into_iter(); + + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + assert_eq!(iter.size_hint(), (0, Some(0))); + } + + // simple iter + { + let mut d = VecDeque::new(); + for i in 0..5 { + d.push_back(i); + } + + let b = vec![0, 1, 2, 3, 4]; + assert_eq!(d.into_iter().collect::>(), b); + } + + // wrapped iter + { + let mut d = VecDeque::new(); + for i in 0..5 { + d.push_back(i); + } + for i in 6..9 { + d.push_front(i); + } + + let b = vec![8, 7, 6, 0, 1, 2, 3, 4]; + assert_eq!(d.into_iter().collect::>(), b); + } + + // partially used + { + let mut d = VecDeque::new(); + for i in 0..5 { + d.push_back(i); + } + for i in 6..9 { + d.push_front(i); + } + + let mut it = d.into_iter(); + assert_eq!(it.size_hint(), (8, Some(8))); + assert_eq!(it.next(), Some(8)); + assert_eq!(it.size_hint(), (7, Some(7))); + assert_eq!(it.next_back(), Some(4)); + assert_eq!(it.size_hint(), (6, Some(6))); + assert_eq!(it.next(), Some(7)); + assert_eq!(it.size_hint(), (5, Some(5))); + } + + // advance_by + { + let mut d = VecDeque::new(); + for i in 0..=4 { + d.push_back(i); + } + for i in 6..=8 { + d.push_front(i); + } + + let mut it = d.into_iter(); + assert_eq!(it.advance_by(1), Ok(())); + assert_eq!(it.next(), Some(7)); + assert_eq!(it.advance_back_by(1), Ok(())); + assert_eq!(it.next_back(), Some(3)); + + let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter(); + assert_eq!(it.advance_by(10), Err(NonZero::new(5).unwrap())); + let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter(); + assert_eq!(it.advance_back_by(10), Err(NonZero::new(5).unwrap())); + } +} + +#[test] +fn test_drain() { + // Empty iter + { + let mut d: VecDeque = VecDeque::new(); + + { + let mut iter = d.drain(..); + + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + assert_eq!(iter.size_hint(), (0, Some(0))); + } + + assert!(d.is_empty()); + } + + // simple iter + { + let mut d = VecDeque::new(); + for i in 0..5 { + d.push_back(i); + } + + assert_eq!(d.drain(..).collect::>(), [0, 1, 2, 3, 4]); + assert!(d.is_empty()); + } + + // wrapped iter + { + let mut d = VecDeque::new(); + for i in 0..5 { + d.push_back(i); + } + for i in 6..9 { + d.push_front(i); + } + assert_eq!(d.drain(..).collect::>(), [8, 7, 6, 0, 1, 2, 3, 4]); + assert!(d.is_empty()); + } + + // partially used + { + let mut d: VecDeque<_> = VecDeque::new(); + for i in 0..5 { + d.push_back(i); + } + for i in 6..9 { + d.push_front(i); + } + + { + let mut it = d.drain(..); + assert_eq!(it.size_hint(), (8, Some(8))); + assert_eq!(it.next(), Some(8)); + assert_eq!(it.size_hint(), (7, Some(7))); + assert_eq!(it.next_back(), Some(4)); + assert_eq!(it.size_hint(), (6, Some(6))); + assert_eq!(it.next(), Some(7)); + assert_eq!(it.size_hint(), (5, Some(5))); + } + assert!(d.is_empty()); + } +} + +#[test] +fn test_from_iter() { + let v = vec![1, 2, 3, 4, 5, 6, 7]; + let deq: VecDeque<_> = v.iter().cloned().collect(); + let u: Vec<_> = deq.iter().cloned().collect(); + assert_eq!(u, v); + + let seq = (0..).step_by(2).take(256); + let deq: VecDeque<_> = seq.collect(); + for (i, &x) in deq.iter().enumerate() { + assert_eq!(2 * i, x); + } + assert_eq!(deq.len(), 256); +} + +#[test] +fn test_clone() { + let mut d = VecDeque::new(); + d.push_front(17); + d.push_front(42); + d.push_back(137); + d.push_back(137); + assert_eq!(d.len(), 4); + let mut e = d.clone(); + assert_eq!(e.len(), 4); + while !d.is_empty() { + assert_eq!(d.pop_back(), e.pop_back()); + } + assert_eq!(d.len(), 0); + assert_eq!(e.len(), 0); +} + +#[test] +fn test_eq() { + let mut d = VecDeque::new(); + assert!(d == VecDeque::with_capacity(0)); + d.push_front(137); + d.push_front(17); + d.push_front(42); + d.push_back(137); + let mut e = VecDeque::with_capacity(0); + e.push_back(42); + e.push_back(17); + e.push_back(137); + e.push_back(137); + assert!(&e == &d); + e.pop_back(); + e.push_back(0); + assert!(e != d); + e.clear(); + assert!(e == VecDeque::new()); +} + +#[test] +fn test_partial_eq_array() { + let d = VecDeque::::new(); + assert!(d == []); + + let mut d = VecDeque::new(); + d.push_front('a'); + assert!(d == ['a']); + + let mut d = VecDeque::new(); + d.push_back('a'); + assert!(d == ['a']); + + let mut d = VecDeque::new(); + d.push_back('a'); + d.push_back('b'); + assert!(d == ['a', 'b']); +} + +#[test] +fn test_hash() { + let mut x = VecDeque::new(); + let mut y = VecDeque::new(); + + x.push_back(1); + x.push_back(2); + x.push_back(3); + + y.push_back(0); + y.push_back(1); + y.pop_front(); + y.push_back(2); + y.push_back(3); + + assert!(hash(&x) == hash(&y)); +} + +#[test] +fn test_hash_after_rotation() { + // test that two deques hash equal even if elements are laid out differently + let len = 28; + let mut ring: VecDeque = (0..len as i32).collect(); + let orig = ring.clone(); + for _ in 0..ring.capacity() { + // shift values 1 step to the right by pop, sub one, push + ring.pop_front(); + for elt in &mut ring { + *elt -= 1; + } + ring.push_back(len - 1); + assert_eq!(hash(&orig), hash(&ring)); + assert_eq!(orig, ring); + assert_eq!(ring, orig); + } +} + +#[test] +fn test_eq_after_rotation() { + // test that two deques are equal even if elements are laid out differently + let len = 28; + let mut ring: VecDeque = (0..len as i32).collect(); + let mut shifted = ring.clone(); + for _ in 0..10 { + // shift values 1 step to the right by pop, sub one, push + ring.pop_front(); + for elt in &mut ring { + *elt -= 1; + } + ring.push_back(len - 1); + } + + // try every shift + for _ in 0..shifted.capacity() { + shifted.pop_front(); + for elt in &mut shifted { + *elt -= 1; + } + shifted.push_back(len - 1); + assert_eq!(shifted, ring); + assert_eq!(ring, shifted); + } +} + +#[test] +fn test_ord() { + let x = VecDeque::new(); + let mut y = VecDeque::new(); + y.push_back(1); + y.push_back(2); + y.push_back(3); + assert!(x < y); + assert!(y > x); + assert!(x <= x); + assert!(x >= x); +} + +#[test] +fn test_show() { + let ringbuf: VecDeque<_> = (0..10).collect(); + assert_eq!(format!("{ringbuf:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"); + + let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"].iter().cloned().collect(); + assert_eq!(format!("{ringbuf:?}"), "[\"just\", \"one\", \"test\", \"more\"]"); +} + +#[test] +fn test_drop() { + static mut DROPS: i32 = 0; + struct Elem; + impl Drop for Elem { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + } + } + + let mut ring = VecDeque::new(); + ring.push_back(Elem); + ring.push_front(Elem); + ring.push_back(Elem); + ring.push_front(Elem); + drop(ring); + + assert_eq!(unsafe { DROPS }, 4); +} + +#[test] +fn test_drop_with_pop() { + static mut DROPS: i32 = 0; + struct Elem; + impl Drop for Elem { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + } + } + + let mut ring = VecDeque::new(); + ring.push_back(Elem); + ring.push_front(Elem); + ring.push_back(Elem); + ring.push_front(Elem); + + drop(ring.pop_back()); + drop(ring.pop_front()); + assert_eq!(unsafe { DROPS }, 2); + + drop(ring); + assert_eq!(unsafe { DROPS }, 4); +} + +#[test] +fn test_drop_clear() { + static mut DROPS: i32 = 0; + struct Elem; + impl Drop for Elem { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + } + } + + let mut ring = VecDeque::new(); + ring.push_back(Elem); + ring.push_front(Elem); + ring.push_back(Elem); + ring.push_front(Elem); + ring.clear(); + assert_eq!(unsafe { DROPS }, 4); + + drop(ring); + assert_eq!(unsafe { DROPS }, 4); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_drop_panic() { + static mut DROPS: i32 = 0; + + struct D(bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.0 { + panic!("panic in `drop`"); + } + } + } + + let mut q = VecDeque::new(); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_front(D(false)); + q.push_front(D(false)); + q.push_front(D(true)); + + catch_unwind(move || drop(q)).ok(); + + assert_eq!(unsafe { DROPS }, 8); +} + +#[test] +fn test_reserve_grow() { + // test growth path A + // [T o o H] -> [T o o H . . . . ] + let mut ring = VecDeque::with_capacity(4); + for i in 0..3 { + ring.push_back(i); + } + ring.reserve(7); + for i in 0..3 { + assert_eq!(ring.pop_front(), Some(i)); + } + + // test growth path B + // [H T o o] -> [. T o o H . . . ] + let mut ring = VecDeque::with_capacity(4); + for i in 0..1 { + ring.push_back(i); + assert_eq!(ring.pop_front(), Some(i)); + } + for i in 0..3 { + ring.push_back(i); + } + ring.reserve(7); + for i in 0..3 { + assert_eq!(ring.pop_front(), Some(i)); + } + + // test growth path C + // [o o H T] -> [o o H . . . . T ] + let mut ring = VecDeque::with_capacity(4); + for i in 0..3 { + ring.push_back(i); + assert_eq!(ring.pop_front(), Some(i)); + } + for i in 0..3 { + ring.push_back(i); + } + ring.reserve(7); + for i in 0..3 { + assert_eq!(ring.pop_front(), Some(i)); + } +} + +#[test] +fn test_get() { + let mut ring = VecDeque::new(); + ring.push_back(0); + assert_eq!(ring.get(0), Some(&0)); + assert_eq!(ring.get(1), None); + + ring.push_back(1); + assert_eq!(ring.get(0), Some(&0)); + assert_eq!(ring.get(1), Some(&1)); + assert_eq!(ring.get(2), None); + + ring.push_back(2); + assert_eq!(ring.get(0), Some(&0)); + assert_eq!(ring.get(1), Some(&1)); + assert_eq!(ring.get(2), Some(&2)); + assert_eq!(ring.get(3), None); + + assert_eq!(ring.pop_front(), Some(0)); + assert_eq!(ring.get(0), Some(&1)); + assert_eq!(ring.get(1), Some(&2)); + assert_eq!(ring.get(2), None); + + assert_eq!(ring.pop_front(), Some(1)); + assert_eq!(ring.get(0), Some(&2)); + assert_eq!(ring.get(1), None); + + assert_eq!(ring.pop_front(), Some(2)); + assert_eq!(ring.get(0), None); + assert_eq!(ring.get(1), None); +} + +#[test] +fn test_get_mut() { + let mut ring = VecDeque::new(); + for i in 0..3 { + ring.push_back(i); + } + + match ring.get_mut(1) { + Some(x) => *x = -1, + None => (), + }; + + assert_eq!(ring.get_mut(0), Some(&mut 0)); + assert_eq!(ring.get_mut(1), Some(&mut -1)); + assert_eq!(ring.get_mut(2), Some(&mut 2)); + assert_eq!(ring.get_mut(3), None); + + assert_eq!(ring.pop_front(), Some(0)); + assert_eq!(ring.get_mut(0), Some(&mut -1)); + assert_eq!(ring.get_mut(1), Some(&mut 2)); + assert_eq!(ring.get_mut(2), None); +} + +#[test] +fn test_front() { + let mut ring = VecDeque::new(); + ring.push_back(10); + ring.push_back(20); + assert_eq!(ring.front(), Some(&10)); + ring.pop_front(); + assert_eq!(ring.front(), Some(&20)); + ring.pop_front(); + assert_eq!(ring.front(), None); +} + +#[test] +fn test_as_slices() { + let mut ring: VecDeque = VecDeque::with_capacity(127); + let cap = ring.capacity() as i32; + let first = cap / 2; + let last = cap - first; + for i in 0..first { + ring.push_back(i); + + let (left, right) = ring.as_slices(); + let expected: Vec<_> = (0..=i).collect(); + assert_eq!(left, &expected[..]); + assert_eq!(right, []); + } + + for j in -last..0 { + ring.push_front(j); + let (left, right) = ring.as_slices(); + let expected_left: Vec<_> = (-last..=j).rev().collect(); + let expected_right: Vec<_> = (0..first).collect(); + assert_eq!(left, &expected_left[..]); + assert_eq!(right, &expected_right[..]); + } + + assert_eq!(ring.len() as i32, cap); + assert_eq!(ring.capacity() as i32, cap); +} + +#[test] +fn test_as_mut_slices() { + let mut ring: VecDeque = VecDeque::with_capacity(127); + let cap = ring.capacity() as i32; + let first = cap / 2; + let last = cap - first; + for i in 0..first { + ring.push_back(i); + + let (left, right) = ring.as_mut_slices(); + let expected: Vec<_> = (0..=i).collect(); + assert_eq!(left, &expected[..]); + assert_eq!(right, []); + } + + for j in -last..0 { + ring.push_front(j); + let (left, right) = ring.as_mut_slices(); + let expected_left: Vec<_> = (-last..=j).rev().collect(); + let expected_right: Vec<_> = (0..first).collect(); + assert_eq!(left, &expected_left[..]); + assert_eq!(right, &expected_right[..]); + } + + assert_eq!(ring.len() as i32, cap); + assert_eq!(ring.capacity() as i32, cap); +} + +#[test] +fn test_append() { + let mut a: VecDeque<_> = [1, 2, 3].into_iter().collect(); + let mut b: VecDeque<_> = [4, 5, 6].into_iter().collect(); + + // normal append + a.append(&mut b); + assert_eq!(a.iter().cloned().collect::>(), [1, 2, 3, 4, 5, 6]); + assert_eq!(b.iter().cloned().collect::>(), []); + + // append nothing to something + a.append(&mut b); + assert_eq!(a.iter().cloned().collect::>(), [1, 2, 3, 4, 5, 6]); + assert_eq!(b.iter().cloned().collect::>(), []); + + // append something to nothing + b.append(&mut a); + assert_eq!(b.iter().cloned().collect::>(), [1, 2, 3, 4, 5, 6]); + assert_eq!(a.iter().cloned().collect::>(), []); +} + +#[test] +fn test_append_permutations() { + fn construct_vec_deque( + push_back: usize, + pop_back: usize, + push_front: usize, + pop_front: usize, + ) -> VecDeque { + let mut out = VecDeque::new(); + for a in 0..push_back { + out.push_back(a); + } + for b in 0..push_front { + out.push_front(push_back + b); + } + for _ in 0..pop_back { + out.pop_back(); + } + for _ in 0..pop_front { + out.pop_front(); + } + out + } + + // Miri is too slow + let max = if cfg!(miri) { 3 } else { 5 }; + + // Many different permutations of both the `VecDeque` getting appended to + // and the one getting appended are generated to check `append`. + // This ensures all 6 code paths of `append` are tested. + for src_push_back in 0..max { + for src_push_front in 0..max { + // doesn't pop more values than are pushed + for src_pop_back in 0..(src_push_back + src_push_front) { + for src_pop_front in 0..(src_push_back + src_push_front - src_pop_back) { + let src = construct_vec_deque( + src_push_back, + src_pop_back, + src_push_front, + src_pop_front, + ); + + for dst_push_back in 0..max { + for dst_push_front in 0..max { + for dst_pop_back in 0..(dst_push_back + dst_push_front) { + for dst_pop_front in + 0..(dst_push_back + dst_push_front - dst_pop_back) + { + let mut dst = construct_vec_deque( + dst_push_back, + dst_pop_back, + dst_push_front, + dst_pop_front, + ); + let mut src = src.clone(); + + // Assert that appending `src` to `dst` gives the same order + // of values as iterating over both in sequence. + let correct = dst + .iter() + .chain(src.iter()) + .cloned() + .collect::>(); + dst.append(&mut src); + assert_eq!(dst, correct); + assert!(src.is_empty()); + } + } + } + } + } + } + } + } +} + +struct DropCounter<'a> { + count: &'a mut u32, +} + +impl Drop for DropCounter<'_> { + fn drop(&mut self) { + *self.count += 1; + } +} + +#[test] +fn test_append_double_drop() { + let (mut count_a, mut count_b) = (0, 0); + { + let mut a = VecDeque::new(); + let mut b = VecDeque::new(); + a.push_back(DropCounter { count: &mut count_a }); + b.push_back(DropCounter { count: &mut count_b }); + + a.append(&mut b); + } + assert_eq!(count_a, 1); + assert_eq!(count_b, 1); +} + +#[test] +#[should_panic] +fn test_append_zst_capacity_overflow() { + let mut v = Vec::with_capacity(usize::MAX); + // note: using resize instead of set_len here would + // be *extremely* slow in unoptimized builds. + // SAFETY: `v` has capacity `usize::MAX`, and no initialization + // is needed for empty tuples. + unsafe { v.set_len(usize::MAX) }; + let mut v = VecDeque::from(v); + let mut w = vec![()].into(); + v.append(&mut w); +} + +#[test] +fn test_retain() { + let mut buf = VecDeque::new(); + buf.extend(1..5); + buf.retain(|&x| x % 2 == 0); + let v: Vec<_> = buf.into_iter().collect(); + assert_eq!(&v[..], &[2, 4]); +} + +#[test] +fn test_extend_ref() { + let mut v = VecDeque::new(); + v.push_back(1); + v.extend(&[2, 3, 4]); + + assert_eq!(v.len(), 4); + assert_eq!(v[0], 1); + assert_eq!(v[1], 2); + assert_eq!(v[2], 3); + assert_eq!(v[3], 4); + + let mut w = VecDeque::new(); + w.push_back(5); + w.push_back(6); + v.extend(&w); + + assert_eq!(v.len(), 6); + assert_eq!(v[0], 1); + assert_eq!(v[1], 2); + assert_eq!(v[2], 3); + assert_eq!(v[3], 4); + assert_eq!(v[4], 5); + assert_eq!(v[5], 6); +} + +#[test] +fn test_contains() { + let mut v = VecDeque::new(); + v.extend(&[2, 3, 4]); + + assert!(v.contains(&3)); + assert!(!v.contains(&1)); + + v.clear(); + + assert!(!v.contains(&3)); +} + +#[allow(dead_code)] +fn assert_covariance() { + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { + d + } +} + +#[test] +fn test_is_empty() { + let mut v = VecDeque::::new(); + assert!(v.is_empty()); + assert!(v.iter().is_empty()); + assert!(v.iter_mut().is_empty()); + v.extend(&[2, 3, 4]); + assert!(!v.is_empty()); + assert!(!v.iter().is_empty()); + assert!(!v.iter_mut().is_empty()); + while let Some(_) = v.pop_front() { + assert_eq!(v.is_empty(), v.len() == 0); + assert_eq!(v.iter().is_empty(), v.iter().len() == 0); + assert_eq!(v.iter_mut().is_empty(), v.iter_mut().len() == 0); + } + assert!(v.is_empty()); + assert!(v.iter().is_empty()); + assert!(v.iter_mut().is_empty()); + assert!(v.into_iter().is_empty()); +} + +#[test] +fn test_reserve_exact_2() { + // This is all the same as test_reserve + + let mut v = VecDeque::new(); + + v.reserve_exact(2); + assert!(v.capacity() >= 2); + + for i in 0..16 { + v.push_back(i); + } + + assert!(v.capacity() >= 16); + v.reserve_exact(16); + assert!(v.capacity() >= 32); + + v.push_back(16); + + v.reserve_exact(16); + assert!(v.capacity() >= 33) +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +fn test_try_with_capacity() { + let vec: VecDeque = VecDeque::try_with_capacity(5).unwrap(); + assert_eq!(0, vec.len()); + assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4); + + assert!(VecDeque::::try_with_capacity(isize::MAX as usize + 1).is_err()); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +fn test_try_reserve() { + // These are the interesting cases: + // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM) + // * > isize::MAX should always fail + // * On 16/32-bit should CapacityOverflow + // * On 64-bit should OOM + // * overflow may trigger when adding `len` to `cap` (in number of elements) + // * overflow may trigger when multiplying `new_cap` by size_of:: (to get bytes) + + const MAX_CAP: usize = isize::MAX as usize; + const MAX_USIZE: usize = usize::MAX; + + { + // Note: basic stuff is checked by test_reserve + let mut empty_bytes: VecDeque = VecDeque::new(); + + // Check isize::MAX doesn't count as an overflow + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + // Play it again, frank! (just to be sure) + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } + + { + // Same basic idea, but with non-zero len + let mut ten_bytes: VecDeque = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); + + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Should always overflow in the add-to-len + assert_matches!( + ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } + + { + // Same basic idea, but with interesting type size + let mut ten_u32s: VecDeque = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); + + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Should fail in the mul-by-size + assert_matches!( + ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +fn test_try_reserve_exact() { + // This is exactly the same as test_try_reserve with the method changed. + // See that test for comments. + + const MAX_CAP: usize = isize::MAX as usize; + const MAX_USIZE: usize = usize::MAX; + + { + let mut empty_bytes: VecDeque = VecDeque::new(); + + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } + + { + let mut ten_bytes: VecDeque = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); + + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } + + { + let mut ten_u32s: VecDeque = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); + + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } +} + +#[test] +fn test_rotate_nop() { + let mut v: VecDeque<_> = (0..10).collect(); + assert_unchanged(&v); + + v.rotate_left(0); + assert_unchanged(&v); + + v.rotate_left(10); + assert_unchanged(&v); + + v.rotate_right(0); + assert_unchanged(&v); + + v.rotate_right(10); + assert_unchanged(&v); + + v.rotate_left(3); + v.rotate_right(3); + assert_unchanged(&v); + + v.rotate_right(3); + v.rotate_left(3); + assert_unchanged(&v); + + v.rotate_left(6); + v.rotate_right(6); + assert_unchanged(&v); + + v.rotate_right(6); + v.rotate_left(6); + assert_unchanged(&v); + + v.rotate_left(3); + v.rotate_left(7); + assert_unchanged(&v); + + v.rotate_right(4); + v.rotate_right(6); + assert_unchanged(&v); + + v.rotate_left(1); + v.rotate_left(2); + v.rotate_left(3); + v.rotate_left(4); + assert_unchanged(&v); + + v.rotate_right(1); + v.rotate_right(2); + v.rotate_right(3); + v.rotate_right(4); + assert_unchanged(&v); + + fn assert_unchanged(v: &VecDeque) { + assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + } +} + +#[test] +fn test_rotate_left_parts() { + let mut v: VecDeque<_> = VecDeque::with_capacity(8); + v.extend(1..=7); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[3, 4, 5, 6, 7, 1][..], &[2][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[5, 6, 7, 1][..], &[2, 3, 4][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[7, 1][..], &[2, 3, 4, 5, 6][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7, 1][..], &[][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[4, 5, 6, 7, 1, 2][..], &[3][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[6, 7, 1, 2][..], &[3, 4, 5][..])); + v.rotate_left(2); + assert_eq!(v.as_slices(), (&[1, 2][..], &[3, 4, 5, 6, 7][..])); +} + +#[test] +fn test_rotate_right_parts() { + let mut v: VecDeque<_> = VecDeque::with_capacity(8); + v.extend(1..=7); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[6, 7][..], &[1, 2, 3, 4, 5][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[4, 5, 6, 7][..], &[1, 2, 3][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7][..], &[1][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[7, 1, 2, 3, 4, 5, 6][..], &[][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[5, 6][..], &[7, 1, 2, 3, 4][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[3, 4, 5, 6][..], &[7, 1, 2][..])); + v.rotate_right(2); + assert_eq!(v.as_slices(), (&[1, 2, 3, 4, 5, 6][..], &[7][..])); +} + +#[test] +fn test_rotate_left_random() { + let shifts = [ + 6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1, 4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11, 9, 4, 12, 3, + 12, 9, 11, 1, 7, 9, 7, 2, + ]; + let n = 12; + let mut v: VecDeque<_> = (0..n).collect(); + let mut total_shift = 0; + for shift in shifts.iter().cloned() { + v.rotate_left(shift); + total_shift += shift; + for i in 0..n { + assert_eq!(v[i], (i + total_shift) % n); + } + } +} + +#[test] +fn test_rotate_right_random() { + let shifts = [ + 6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1, 4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11, 9, 4, 12, 3, + 12, 9, 11, 1, 7, 9, 7, 2, + ]; + let n = 12; + let mut v: VecDeque<_> = (0..n).collect(); + let mut total_shift = 0; + for shift in shifts.iter().cloned() { + v.rotate_right(shift); + total_shift += shift; + for i in 0..n { + assert_eq!(v[(i + total_shift) % n], i); + } + } +} + +#[test] +fn test_try_fold_empty() { + assert_eq!(Some(0), VecDeque::::new().iter().try_fold(0, |_, _| None)); +} + +#[test] +fn test_try_fold_none() { + let v: VecDeque = (0..12).collect(); + assert_eq!(None, v.into_iter().try_fold(0, |a, b| if b < 11 { Some(a + b) } else { None })); +} + +#[test] +fn test_try_fold_ok() { + let v: VecDeque = (0..12).collect(); + assert_eq!(Ok::<_, ()>(66), v.into_iter().try_fold(0, |a, b| Ok(a + b))); +} + +#[test] +fn test_try_fold_unit() { + let v: VecDeque<()> = std::iter::repeat(()).take(42).collect(); + assert_eq!(Some(()), v.into_iter().try_fold((), |(), ()| Some(()))); +} + +#[test] +fn test_try_fold_unit_none() { + let v: std::collections::VecDeque<()> = [(); 10].iter().cloned().collect(); + let mut iter = v.into_iter(); + assert!(iter.try_fold((), |_, _| None).is_none()); + assert_eq!(iter.len(), 9); +} + +#[test] +fn test_try_fold_rotated() { + let mut v: VecDeque<_> = (0..12).collect(); + for n in 0..10 { + if n & 1 == 0 { + v.rotate_left(n); + } else { + v.rotate_right(n); + } + assert_eq!(Ok::<_, ()>(66), v.iter().try_fold(0, |a, b| Ok(a + b))); + } +} + +#[test] +fn test_try_fold_moves_iter() { + let v: VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect(); + let mut iter = v.into_iter(); + assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None); + assert_eq!(iter.next(), Some(&60)); +} + +#[test] +fn test_try_fold_exhaust_wrap() { + let mut v = VecDeque::with_capacity(7); + v.push_back(1); + v.push_back(1); + v.push_back(1); + v.pop_front(); + v.pop_front(); + let mut iter = v.iter(); + let _ = iter.try_fold(0, |_, _| Some(1)); + assert!(iter.is_empty()); +} + +#[test] +fn test_try_fold_wraparound() { + let mut v = VecDeque::with_capacity(8); + v.push_back(7); + v.push_back(8); + v.push_back(9); + v.push_front(2); + v.push_front(1); + let mut iter = v.iter(); + let _ = iter.find(|&&x| x == 2); + assert_eq!(Some(&7), iter.next()); +} + +#[test] +fn test_try_rfold_rotated() { + let mut v: VecDeque<_> = (0..12).collect(); + for n in 0..10 { + if n & 1 == 0 { + v.rotate_left(n); + } else { + v.rotate_right(n); + } + assert_eq!(Ok::<_, ()>(66), v.iter().try_rfold(0, |a, b| Ok(a + b))); + } +} + +#[test] +fn test_try_rfold_moves_iter() { + let v: VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect(); + let mut iter = v.into_iter(); + assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None); + assert_eq!(iter.next_back(), Some(&70)); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn truncate_leak() { + static mut DROPS: i32 = 0; + + struct D(bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.0 { + panic!("panic in `drop`"); + } + } + } + + let mut q = VecDeque::new(); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_front(D(true)); + q.push_front(D(false)); + q.push_front(D(false)); + + catch_unwind(AssertUnwindSafe(|| q.truncate(1))).ok(); + + assert_eq!(unsafe { DROPS }, 7); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_drain_leak() { + static mut DROPS: i32 = 0; + + #[derive(Debug, PartialEq)] + struct D(u32, bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.1 { + panic!("panic in `drop`"); + } + } + } + + let mut v = VecDeque::new(); + v.push_back(D(4, false)); + v.push_back(D(5, false)); + v.push_back(D(6, false)); + v.push_front(D(3, false)); + v.push_front(D(2, true)); + v.push_front(D(1, false)); + v.push_front(D(0, false)); + + catch_unwind(AssertUnwindSafe(|| { + v.drain(1..=4); + })) + .ok(); + + assert_eq!(unsafe { DROPS }, 4); + assert_eq!(v.len(), 3); + drop(v); + assert_eq!(unsafe { DROPS }, 7); +} + +#[test] +fn test_binary_search() { + // Contiguous (front only) search: + let deque: VecDeque<_> = vec![1, 2, 3, 5, 6].into(); + assert!(deque.as_slices().1.is_empty()); + assert_eq!(deque.binary_search(&3), Ok(2)); + assert_eq!(deque.binary_search(&4), Err(3)); + + // Split search (both front & back non-empty): + let mut deque: VecDeque<_> = vec![5, 6].into(); + deque.push_front(3); + deque.push_front(2); + deque.push_front(1); + deque.push_back(10); + assert!(!deque.as_slices().0.is_empty()); + assert!(!deque.as_slices().1.is_empty()); + assert_eq!(deque.binary_search(&0), Err(0)); + assert_eq!(deque.binary_search(&1), Ok(0)); + assert_eq!(deque.binary_search(&5), Ok(3)); + assert_eq!(deque.binary_search(&7), Err(5)); + assert_eq!(deque.binary_search(&20), Err(6)); +} + +#[test] +fn test_binary_search_by() { + let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into(); + + assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&3)), Ok(2)); + assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&4)), Err(3)); +} + +#[test] +fn test_binary_search_by_key() { + let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into(); + + assert_eq!(deque.binary_search_by_key(&3, |&(v,)| v), Ok(2)); + assert_eq!(deque.binary_search_by_key(&4, |&(v,)| v), Err(3)); +} + +#[test] +fn test_partition_point() { + // Contiguous (front only) search: + let deque: VecDeque<_> = vec![1, 2, 3, 5, 6].into(); + assert!(deque.as_slices().1.is_empty()); + assert_eq!(deque.partition_point(|&v| v <= 3), 3); + + // Split search (both front & back non-empty): + let mut deque: VecDeque<_> = vec![5, 6].into(); + deque.push_front(3); + deque.push_front(2); + deque.push_front(1); + deque.push_back(10); + assert!(!deque.as_slices().0.is_empty()); + assert!(!deque.as_slices().1.is_empty()); + assert_eq!(deque.partition_point(|&v| v <= 5), 4); +} + +#[test] +fn test_zero_sized_push() { + const N: usize = 8; + + // Zero sized type + struct Zst; + + // Test that for all possible sequences of push_front / push_back, + // we end up with a deque of the correct size + + for len in 0..N { + let mut tester = VecDeque::with_capacity(len); + assert_eq!(tester.len(), 0); + assert!(tester.capacity() >= len); + for case in 0..(1 << len) { + assert_eq!(tester.len(), 0); + for bit in 0..len { + if case & (1 << bit) != 0 { + tester.push_front(Zst); + } else { + tester.push_back(Zst); + } + } + assert_eq!(tester.len(), len); + assert_eq!(tester.iter().count(), len); + tester.clear(); + } + } +} + +#[test] +fn test_from_zero_sized_vec() { + let v = vec![(); 100]; + let queue = VecDeque::from(v); + assert_eq!(queue.len(), 100); +} + +#[test] +fn test_resize_keeps_reserved_space_from_item() { + let v = Vec::::with_capacity(1234); + let mut d = VecDeque::new(); + d.resize(1, v); + assert_eq!(d[0].capacity(), 1234); +} + +#[test] +fn test_collect_from_into_iter_keeps_allocation() { + let mut v = Vec::with_capacity(13); + v.extend(0..7); + check(v.as_ptr(), v.last().unwrap(), v.into_iter()); + + let mut v = VecDeque::with_capacity(13); + v.extend(0..7); + check(&v[0], &v[v.len() - 1], v.into_iter()); + + fn check(buf: *const i32, last: *const i32, mut it: impl Iterator) { + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(1)); + + let mut v: VecDeque = it.collect(); + assert_eq!(v.capacity(), 13); + assert_eq!(v.as_slices().0.as_ptr(), buf.wrapping_add(2)); + assert_eq!(&v[v.len() - 1] as *const _, last); + + assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice())); + v.push_front(7); + assert_eq!(v.as_slices(), ([7, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); + v.push_front(8); + assert_eq!(v.as_slices(), ([8, 7, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); + + // Now that we've adding thing in place of the two that we removed from + // the front of the iterator, we're back to matching the buffer pointer. + assert_eq!(v.as_slices().0.as_ptr(), buf); + assert_eq!(&v[v.len() - 1] as *const _, last); + + v.push_front(9); + assert_eq!(v.as_slices(), ([9].as_slice(), [8, 7, 2, 3, 4, 5, 6].as_slice())); + assert_eq!(v.capacity(), 13); + } +} diff --git a/library/alloctests/tests/vec_deque_alloc_error.rs b/library/alloctests/tests/vec_deque_alloc_error.rs new file mode 100644 index 00000000000..21a9118a05b --- /dev/null +++ b/library/alloctests/tests/vec_deque_alloc_error.rs @@ -0,0 +1,48 @@ +#![feature(alloc_error_hook, allocator_api)] + +use std::alloc::{AllocError, Allocator, Layout, System, set_alloc_error_hook}; +use std::collections::VecDeque; +use std::panic::{AssertUnwindSafe, catch_unwind}; +use std::ptr::NonNull; + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_shrink_to_unwind() { + // This tests that `shrink_to` leaves the deque in a consistent state when + // the call to `RawVec::shrink_to_fit` unwinds. The code is adapted from #123369 + // but changed to hopefully not have any UB even if the test fails. + + struct BadAlloc; + + unsafe impl Allocator for BadAlloc { + fn allocate(&self, l: Layout) -> Result, AllocError> { + // We allocate zeroed here so that the whole buffer of the deque + // is always initialized. That way, even if the deque is left in + // an inconsistent state, no uninitialized memory should be accessed. + System.allocate_zeroed(l) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { System.deallocate(ptr, layout) } + } + + unsafe fn shrink( + &self, + _ptr: NonNull, + _old_layout: Layout, + _new_layout: Layout, + ) -> Result, AllocError> { + Err(AllocError) + } + } + + set_alloc_error_hook(|_| panic!("alloc error")); + + let mut v = VecDeque::with_capacity_in(15, BadAlloc); + v.push_back(1); + v.push_front(2); + // This should unwind because it calls `BadAlloc::shrink` and then `handle_alloc_error` which unwinds. + assert!(catch_unwind(AssertUnwindSafe(|| v.shrink_to_fit())).is_err()); + // This should only pass if the deque is left in a consistent state. + assert_eq!(v, [2, 1]); +} diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 88aa70d4f2f..6cb0b19d763 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -56,6 +56,7 @@ check-aux: # Run standard library tests in Miri. $(Q)$(BOOTSTRAP) miri --stage 2 \ library/coretests \ + library/alloctests \ library/alloc \ $(BOOTSTRAP_ARGS) \ --no-doc @@ -63,6 +64,7 @@ check-aux: $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 \ library/coretests \ + library/alloctests \ library/alloc \ $(BOOTSTRAP_ARGS) \ --doc diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index b8bbe1eb5f8..18aa3119842 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -45,7 +45,10 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.crate_or_deps("sysroot").crate_or_deps("coretests").path("library") + run.crate_or_deps("sysroot") + .crate_or_deps("coretests") + .crate_or_deps("alloctests") + .path("library") } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 4b7c8d5770e..e80f8f9a4b7 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2609,7 +2609,7 @@ impl Step for Crate { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.crate_or_deps("sysroot").crate_or_deps("coretests") + run.crate_or_deps("sysroot").crate_or_deps("coretests").crate_or_deps("alloctests") } fn make_run(run: RunConfig<'_>) { @@ -2724,12 +2724,16 @@ impl Step for Crate { }; let mut crates = self.crates.clone(); - // The core crate can't directly be tested. We could silently - // ignore it, but adding it's own test crate is less confusing - // for users. We still keep core itself for doctests. + // The core and alloc crates can't directly be tested. We + // could silently ignore them, but adding their own test + // crates is less confusing for users. We still keep core and + // alloc themself for doctests if crates.iter().any(|crate_| crate_ == "core") { crates.push("coretests".to_owned()); } + if crates.iter().any(|crate_| crate_ == "alloc") { + crates.push("alloctests".to_owned()); + } run_cargo_test(cargo, &[], &crates, &*crate_description(&self.crates), target, builder); } diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 205d6720718..2237eac200d 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -475,7 +475,7 @@ pub fn check(path: &Path, bad: &mut bool) { && !trimmed.starts_with("//") && !file.ancestors().any(|a| { (a.ends_with("tests") && a.join("COMPILER_TESTS.md").exists()) - || a.ends_with("library/alloc/tests") + || a.ends_with("library/alloctests") }) && filename != "tests.rs" { -- cgit 1.4.1-3-g733a5 From be1e0b786df35a535327ed3b1457622e357bae6d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Feb 2025 12:07:24 +0000 Subject: Move most Rc tests to alloctests --- library/alloc/src/rc/tests.rs | 649 ----------------------------------------- library/alloctests/tests/rc.rs | 649 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 648 insertions(+), 650 deletions(-) diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 2210a7c24c0..35ff6b7d570 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -1,64 +1,5 @@ -use std::cell::RefCell; -use std::clone::Clone; - use super::*; -#[test] -fn test_clone() { - let x = Rc::new(RefCell::new(5)); - let y = x.clone(); - *x.borrow_mut() = 20; - assert_eq!(*y.borrow(), 20); -} - -#[test] -fn test_simple() { - let x = Rc::new(5); - assert_eq!(*x, 5); -} - -#[test] -fn test_simple_clone() { - let x = Rc::new(5); - let y = x.clone(); - assert_eq!(*x, 5); - assert_eq!(*y, 5); -} - -#[test] -fn test_destructor() { - let x: Rc> = Rc::new(Box::new(5)); - assert_eq!(**x, 5); -} - -#[test] -fn test_live() { - let x = Rc::new(5); - let y = Rc::downgrade(&x); - assert!(y.upgrade().is_some()); -} - -#[test] -fn test_dead() { - let x = Rc::new(5); - let y = Rc::downgrade(&x); - drop(x); - assert!(y.upgrade().is_none()); -} - -#[test] -fn weak_self_cyclic() { - struct Cycle { - x: RefCell>>, - } - - let a = Rc::new(Cycle { x: RefCell::new(None) }); - let b = Rc::downgrade(&a.clone()); - *a.x.borrow_mut() = Some(b); - - // hopefully we don't double-free (or leak)... -} - #[test] fn is_unique() { let x = Rc::new(3); @@ -72,593 +13,3 @@ fn is_unique() { drop(w); assert!(Rc::is_unique(&x)); } - -#[test] -fn test_strong_count() { - let a = Rc::new(0); - assert!(Rc::strong_count(&a) == 1); - let w = Rc::downgrade(&a); - assert!(Rc::strong_count(&a) == 1); - let b = w.upgrade().expect("upgrade of live rc failed"); - assert!(Rc::strong_count(&b) == 2); - assert!(Rc::strong_count(&a) == 2); - drop(w); - drop(a); - assert!(Rc::strong_count(&b) == 1); - let c = b.clone(); - assert!(Rc::strong_count(&b) == 2); - assert!(Rc::strong_count(&c) == 2); -} - -#[test] -fn test_weak_count() { - let a = Rc::new(0); - assert!(Rc::strong_count(&a) == 1); - assert!(Rc::weak_count(&a) == 0); - let w = Rc::downgrade(&a); - assert!(Rc::strong_count(&a) == 1); - assert!(Rc::weak_count(&a) == 1); - drop(w); - assert!(Rc::strong_count(&a) == 1); - assert!(Rc::weak_count(&a) == 0); - let c = a.clone(); - assert!(Rc::strong_count(&a) == 2); - assert!(Rc::weak_count(&a) == 0); - drop(c); -} - -#[test] -fn weak_counts() { - assert_eq!(Weak::weak_count(&Weak::::new()), 0); - assert_eq!(Weak::strong_count(&Weak::::new()), 0); - - let a = Rc::new(0); - let w = Rc::downgrade(&a); - assert_eq!(Weak::strong_count(&w), 1); - assert_eq!(Weak::weak_count(&w), 1); - let w2 = w.clone(); - assert_eq!(Weak::strong_count(&w), 1); - assert_eq!(Weak::weak_count(&w), 2); - assert_eq!(Weak::strong_count(&w2), 1); - assert_eq!(Weak::weak_count(&w2), 2); - drop(w); - assert_eq!(Weak::strong_count(&w2), 1); - assert_eq!(Weak::weak_count(&w2), 1); - let a2 = a.clone(); - assert_eq!(Weak::strong_count(&w2), 2); - assert_eq!(Weak::weak_count(&w2), 1); - drop(a2); - drop(a); - assert_eq!(Weak::strong_count(&w2), 0); - assert_eq!(Weak::weak_count(&w2), 0); - drop(w2); -} - -#[test] -fn try_unwrap() { - let x = Rc::new(3); - assert_eq!(Rc::try_unwrap(x), Ok(3)); - let x = Rc::new(4); - let _y = x.clone(); - assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4))); - let x = Rc::new(5); - let _w = Rc::downgrade(&x); - assert_eq!(Rc::try_unwrap(x), Ok(5)); -} - -#[test] -fn into_inner() { - let x = Rc::new(3); - assert_eq!(Rc::into_inner(x), Some(3)); - - let x = Rc::new(4); - let y = Rc::clone(&x); - assert_eq!(Rc::into_inner(x), None); - assert_eq!(Rc::into_inner(y), Some(4)); - - let x = Rc::new(5); - let _w = Rc::downgrade(&x); - assert_eq!(Rc::into_inner(x), Some(5)); -} - -#[test] -fn into_from_raw() { - let x = Rc::new(Box::new("hello")); - let y = x.clone(); - - let x_ptr = Rc::into_raw(x); - drop(y); - unsafe { - assert_eq!(**x_ptr, "hello"); - - let x = Rc::from_raw(x_ptr); - assert_eq!(**x, "hello"); - - assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello")); - } -} - -#[test] -fn test_into_from_raw_unsized() { - use std::fmt::Display; - use std::string::ToString; - - let rc: Rc = Rc::from("foo"); - - let ptr = Rc::into_raw(rc.clone()); - let rc2 = unsafe { Rc::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }, "foo"); - assert_eq!(rc, rc2); - - let rc: Rc = Rc::new(123); - - let ptr = Rc::into_raw(rc.clone()); - let rc2 = unsafe { Rc::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }.to_string(), "123"); - assert_eq!(rc2.to_string(), "123"); -} - -#[test] -fn into_from_weak_raw() { - let x = Rc::new(Box::new("hello")); - let y = Rc::downgrade(&x); - - let y_ptr = Weak::into_raw(y); - unsafe { - assert_eq!(**y_ptr, "hello"); - - let y = Weak::from_raw(y_ptr); - let y_up = Weak::upgrade(&y).unwrap(); - assert_eq!(**y_up, "hello"); - drop(y_up); - - assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello")); - } -} - -#[test] -fn test_into_from_weak_raw_unsized() { - use std::fmt::Display; - use std::string::ToString; - - let arc: Rc = Rc::from("foo"); - let weak: Weak = Rc::downgrade(&arc); - - let ptr = Weak::into_raw(weak.clone()); - let weak2 = unsafe { Weak::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }, "foo"); - assert!(weak.ptr_eq(&weak2)); - - let arc: Rc = Rc::new(123); - let weak: Weak = Rc::downgrade(&arc); - - let ptr = Weak::into_raw(weak.clone()); - let weak2 = unsafe { Weak::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }.to_string(), "123"); - assert!(weak.ptr_eq(&weak2)); -} - -#[test] -fn get_mut() { - let mut x = Rc::new(3); - *Rc::get_mut(&mut x).unwrap() = 4; - assert_eq!(*x, 4); - let y = x.clone(); - assert!(Rc::get_mut(&mut x).is_none()); - drop(y); - assert!(Rc::get_mut(&mut x).is_some()); - let _w = Rc::downgrade(&x); - assert!(Rc::get_mut(&mut x).is_none()); -} - -#[test] -fn test_cowrc_clone_make_unique() { - let mut cow0 = Rc::new(75); - let mut cow1 = cow0.clone(); - let mut cow2 = cow1.clone(); - - assert!(75 == *Rc::make_mut(&mut cow0)); - assert!(75 == *Rc::make_mut(&mut cow1)); - assert!(75 == *Rc::make_mut(&mut cow2)); - - *Rc::make_mut(&mut cow0) += 1; - *Rc::make_mut(&mut cow1) += 2; - *Rc::make_mut(&mut cow2) += 3; - - assert!(76 == *cow0); - assert!(77 == *cow1); - assert!(78 == *cow2); - - // none should point to the same backing memory - assert!(*cow0 != *cow1); - assert!(*cow0 != *cow2); - assert!(*cow1 != *cow2); -} - -#[test] -fn test_cowrc_clone_unique2() { - let mut cow0 = Rc::new(75); - let cow1 = cow0.clone(); - let cow2 = cow1.clone(); - - assert!(75 == *cow0); - assert!(75 == *cow1); - assert!(75 == *cow2); - - *Rc::make_mut(&mut cow0) += 1; - - assert!(76 == *cow0); - assert!(75 == *cow1); - assert!(75 == *cow2); - - // cow1 and cow2 should share the same contents - // cow0 should have a unique reference - assert!(*cow0 != *cow1); - assert!(*cow0 != *cow2); - assert!(*cow1 == *cow2); -} - -#[test] -fn test_cowrc_clone_weak() { - let mut cow0 = Rc::new(75); - let cow1_weak = Rc::downgrade(&cow0); - - assert!(75 == *cow0); - assert!(75 == *cow1_weak.upgrade().unwrap()); - - *Rc::make_mut(&mut cow0) += 1; - - assert!(76 == *cow0); - assert!(cow1_weak.upgrade().is_none()); -} - -/// This is similar to the doc-test for `Rc::make_mut()`, but on an unsized type (slice). -#[test] -fn test_cowrc_unsized() { - use std::rc::Rc; - - let mut data: Rc<[i32]> = Rc::new([10, 20, 30]); - - Rc::make_mut(&mut data)[0] += 1; // Won't clone anything - let mut other_data = Rc::clone(&data); // Won't clone inner data - Rc::make_mut(&mut data)[1] += 1; // Clones inner data - Rc::make_mut(&mut data)[2] += 1; // Won't clone anything - Rc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything - - // Now `data` and `other_data` point to different allocations. - assert_eq!(*data, [11, 21, 31]); - assert_eq!(*other_data, [110, 20, 30]); -} - -#[test] -fn test_show() { - let foo = Rc::new(75); - assert_eq!(format!("{foo:?}"), "75"); -} - -#[test] -fn test_unsized() { - let foo: Rc<[i32]> = Rc::new([1, 2, 3]); - assert_eq!(foo, foo.clone()); -} - -#[test] -fn test_maybe_thin_unsized() { - // If/when custom thin DSTs exist, this test should be updated to use one - use std::ffi::CStr; - - let x: Rc = Rc::from(c"swordfish"); - assert_eq!(format!("{x:?}"), "\"swordfish\""); - let y: Weak = Rc::downgrade(&x); - drop(x); - - // At this point, the weak points to a dropped DST - assert!(y.upgrade().is_none()); - // But we still need to be able to get the alloc layout to drop. - // CStr has no drop glue, but custom DSTs might, and need to work. - drop(y); -} - -#[test] -fn test_from_owned() { - let foo = 123; - let foo_rc = Rc::from(foo); - assert!(123 == *foo_rc); -} - -#[test] -fn test_new_weak() { - let foo: Weak = Weak::new(); - assert!(foo.upgrade().is_none()); -} - -#[test] -fn test_ptr_eq() { - let five = Rc::new(5); - let same_five = five.clone(); - let other_five = Rc::new(5); - - assert!(Rc::ptr_eq(&five, &same_five)); - assert!(!Rc::ptr_eq(&five, &other_five)); -} - -#[test] -fn test_from_str() { - let r: Rc = Rc::from("foo"); - - assert_eq!(&r[..], "foo"); -} - -#[test] -fn test_copy_from_slice() { - let s: &[u32] = &[1, 2, 3]; - let r: Rc<[u32]> = Rc::from(s); - - assert_eq!(&r[..], [1, 2, 3]); -} - -#[test] -fn test_clone_from_slice() { - #[derive(Clone, Debug, Eq, PartialEq)] - struct X(u32); - - let s: &[X] = &[X(1), X(2), X(3)]; - let r: Rc<[X]> = Rc::from(s); - - assert_eq!(&r[..], s); -} - -#[test] -#[should_panic] -fn test_clone_from_slice_panic() { - use std::string::{String, ToString}; - - struct Fail(u32, String); - - impl Clone for Fail { - fn clone(&self) -> Fail { - if self.0 == 2 { - panic!(); - } - Fail(self.0, self.1.clone()) - } - } - - let s: &[Fail] = - &[Fail(0, "foo".to_string()), Fail(1, "bar".to_string()), Fail(2, "baz".to_string())]; - - // Should panic, but not cause memory corruption - let _r: Rc<[Fail]> = Rc::from(s); -} - -#[test] -fn test_from_box() { - let b: Box = Box::new(123); - let r: Rc = Rc::from(b); - - assert_eq!(*r, 123); -} - -#[test] -fn test_from_box_str() { - use std::string::String; - - let s = String::from("foo").into_boxed_str(); - assert_eq!((&&&s).as_str(), "foo"); - - let r: Rc = Rc::from(s); - assert_eq!((&r).as_str(), "foo"); - assert_eq!(r.as_str(), "foo"); - - assert_eq!(&r[..], "foo"); -} - -#[test] -fn test_from_box_slice() { - let s = vec![1, 2, 3].into_boxed_slice(); - let r: Rc<[u32]> = Rc::from(s); - - assert_eq!(&r[..], [1, 2, 3]); -} - -#[test] -fn test_from_box_trait() { - use std::fmt::Display; - use std::string::ToString; - - let b: Box = Box::new(123); - let r: Rc = Rc::from(b); - - assert_eq!(r.to_string(), "123"); -} - -#[test] -fn test_from_box_trait_zero_sized() { - use std::fmt::Debug; - - let b: Box = Box::new(()); - let r: Rc = Rc::from(b); - - assert_eq!(format!("{r:?}"), "()"); -} - -#[test] -fn test_from_vec() { - let v = vec![1, 2, 3]; - let r: Rc<[u32]> = Rc::from(v); - - assert_eq!(&r[..], [1, 2, 3]); -} - -#[test] -fn test_downcast() { - use std::any::Any; - - let r1: Rc = Rc::new(i32::MAX); - let r2: Rc = Rc::new("abc"); - - assert!(r1.clone().downcast::().is_err()); - - let r1i32 = r1.downcast::(); - assert!(r1i32.is_ok()); - assert_eq!(r1i32.unwrap(), Rc::new(i32::MAX)); - - assert!(r2.clone().downcast::().is_err()); - - let r2str = r2.downcast::<&'static str>(); - assert!(r2str.is_ok()); - assert_eq!(r2str.unwrap(), Rc::new("abc")); -} - -#[test] -fn test_array_from_slice() { - let v = vec![1, 2, 3]; - let r: Rc<[u32]> = Rc::from(v); - - let a: Result, _> = r.clone().try_into(); - assert!(a.is_ok()); - - let a: Result, _> = r.clone().try_into(); - assert!(a.is_err()); -} - -#[test] -fn test_rc_cyclic_with_zero_refs() { - struct ZeroRefs { - inner: Weak, - } - - let zero_refs = Rc::new_cyclic(|inner| { - assert_eq!(inner.strong_count(), 0); - assert!(inner.upgrade().is_none()); - ZeroRefs { inner: Weak::new() } - }); - - assert_eq!(Rc::strong_count(&zero_refs), 1); - assert_eq!(Rc::weak_count(&zero_refs), 0); - assert_eq!(zero_refs.inner.strong_count(), 0); - assert_eq!(zero_refs.inner.weak_count(), 0); -} - -#[test] -fn test_rc_cyclic_with_one_ref() { - struct OneRef { - inner: Weak, - } - - let one_ref = Rc::new_cyclic(|inner| { - assert_eq!(inner.strong_count(), 0); - assert!(inner.upgrade().is_none()); - OneRef { inner: inner.clone() } - }); - - assert_eq!(Rc::strong_count(&one_ref), 1); - assert_eq!(Rc::weak_count(&one_ref), 1); - - let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap(); - assert!(Rc::ptr_eq(&one_ref, &one_ref2)); - - assert_eq!(one_ref.inner.strong_count(), 2); - assert_eq!(one_ref.inner.weak_count(), 1); -} - -#[test] -fn test_rc_cyclic_with_two_ref() { - struct TwoRefs { - inner: Weak, - inner1: Weak, - } - - let two_refs = Rc::new_cyclic(|inner| { - assert_eq!(inner.strong_count(), 0); - assert!(inner.upgrade().is_none()); - TwoRefs { inner: inner.clone(), inner1: inner.clone() } - }); - - assert_eq!(Rc::strong_count(&two_refs), 1); - assert_eq!(Rc::weak_count(&two_refs), 2); - - let two_ref3 = Weak::upgrade(&two_refs.inner).unwrap(); - assert!(Rc::ptr_eq(&two_refs, &two_ref3)); - - let two_ref2 = Weak::upgrade(&two_refs.inner1).unwrap(); - assert!(Rc::ptr_eq(&two_refs, &two_ref2)); - - assert_eq!(Rc::strong_count(&two_refs), 3); - assert_eq!(Rc::weak_count(&two_refs), 2); -} - -#[test] -fn test_unique_rc_weak() { - let rc = UniqueRc::new(42); - let weak = UniqueRc::downgrade(&rc); - assert!(weak.upgrade().is_none()); - - let _rc = UniqueRc::into_rc(rc); - assert_eq!(*weak.upgrade().unwrap(), 42); -} - -#[test] -fn test_unique_rc_drop_weak() { - let rc = UniqueRc::new(42); - let weak = UniqueRc::downgrade(&rc); - mem::drop(weak); - - let rc = UniqueRc::into_rc(rc); - assert_eq!(*rc, 42); -} - -#[test] -fn test_unique_rc_drops_contents() { - let mut dropped = false; - struct DropMe<'a>(&'a mut bool); - impl Drop for DropMe<'_> { - fn drop(&mut self) { - *self.0 = true; - } - } - { - let rc = UniqueRc::new(DropMe(&mut dropped)); - drop(rc); - } - assert!(dropped); -} - -/// Exercise the non-default allocator usage. -#[test] -fn test_unique_rc_with_alloc_drops_contents() { - let mut dropped = false; - struct DropMe<'a>(&'a mut bool); - impl Drop for DropMe<'_> { - fn drop(&mut self) { - *self.0 = true; - } - } - { - let rc = UniqueRc::new_in(DropMe(&mut dropped), std::alloc::System); - drop(rc); - } - assert!(dropped); -} - -#[test] -fn test_unique_rc_weak_clone_holding_ref() { - let mut v = UniqueRc::new(0u8); - let w = UniqueRc::downgrade(&v); - let r = &mut *v; - let _ = w.clone(); // touch weak count - *r = 123; -} - -#[test] -fn test_unique_rc_unsizing_coercion() { - let mut rc: UniqueRc<[u8]> = UniqueRc::new([0u8; 3]); - assert_eq!(rc.len(), 3); - rc[0] = 123; - let rc: Rc<[u8]> = UniqueRc::into_rc(rc); - assert_eq!(*rc, [123, 0, 0]); -} diff --git a/library/alloctests/tests/rc.rs b/library/alloctests/tests/rc.rs index 9d82a7621a2..0628011ba68 100644 --- a/library/alloctests/tests/rc.rs +++ b/library/alloctests/tests/rc.rs @@ -1,7 +1,8 @@ use std::any::Any; use std::cell::{Cell, RefCell}; use std::iter::TrustedLen; -use std::rc::{Rc, Weak}; +use std::mem; +use std::rc::{Rc, UniqueRc, Weak}; #[test] fn uninhabited() { @@ -257,3 +258,649 @@ mod pin_coerce_unsized { arg } } + +#[test] +fn test_clone() { + let x = Rc::new(RefCell::new(5)); + let y = x.clone(); + *x.borrow_mut() = 20; + assert_eq!(*y.borrow(), 20); +} + +#[test] +fn test_simple() { + let x = Rc::new(5); + assert_eq!(*x, 5); +} + +#[test] +fn test_simple_clone() { + let x = Rc::new(5); + let y = x.clone(); + assert_eq!(*x, 5); + assert_eq!(*y, 5); +} + +#[test] +fn test_destructor() { + let x: Rc> = Rc::new(Box::new(5)); + assert_eq!(**x, 5); +} + +#[test] +fn test_live() { + let x = Rc::new(5); + let y = Rc::downgrade(&x); + assert!(y.upgrade().is_some()); +} + +#[test] +fn test_dead() { + let x = Rc::new(5); + let y = Rc::downgrade(&x); + drop(x); + assert!(y.upgrade().is_none()); +} + +#[test] +fn weak_self_cyclic() { + struct Cycle { + x: RefCell>>, + } + + let a = Rc::new(Cycle { x: RefCell::new(None) }); + let b = Rc::downgrade(&a.clone()); + *a.x.borrow_mut() = Some(b); + + // hopefully we don't double-free (or leak)... +} + +#[test] +fn test_strong_count() { + let a = Rc::new(0); + assert!(Rc::strong_count(&a) == 1); + let w = Rc::downgrade(&a); + assert!(Rc::strong_count(&a) == 1); + let b = w.upgrade().expect("upgrade of live rc failed"); + assert!(Rc::strong_count(&b) == 2); + assert!(Rc::strong_count(&a) == 2); + drop(w); + drop(a); + assert!(Rc::strong_count(&b) == 1); + let c = b.clone(); + assert!(Rc::strong_count(&b) == 2); + assert!(Rc::strong_count(&c) == 2); +} + +#[test] +fn test_weak_count() { + let a = Rc::new(0); + assert!(Rc::strong_count(&a) == 1); + assert!(Rc::weak_count(&a) == 0); + let w = Rc::downgrade(&a); + assert!(Rc::strong_count(&a) == 1); + assert!(Rc::weak_count(&a) == 1); + drop(w); + assert!(Rc::strong_count(&a) == 1); + assert!(Rc::weak_count(&a) == 0); + let c = a.clone(); + assert!(Rc::strong_count(&a) == 2); + assert!(Rc::weak_count(&a) == 0); + drop(c); +} + +#[test] +fn weak_counts() { + assert_eq!(Weak::weak_count(&Weak::::new()), 0); + assert_eq!(Weak::strong_count(&Weak::::new()), 0); + + let a = Rc::new(0); + let w = Rc::downgrade(&a); + assert_eq!(Weak::strong_count(&w), 1); + assert_eq!(Weak::weak_count(&w), 1); + let w2 = w.clone(); + assert_eq!(Weak::strong_count(&w), 1); + assert_eq!(Weak::weak_count(&w), 2); + assert_eq!(Weak::strong_count(&w2), 1); + assert_eq!(Weak::weak_count(&w2), 2); + drop(w); + assert_eq!(Weak::strong_count(&w2), 1); + assert_eq!(Weak::weak_count(&w2), 1); + let a2 = a.clone(); + assert_eq!(Weak::strong_count(&w2), 2); + assert_eq!(Weak::weak_count(&w2), 1); + drop(a2); + drop(a); + assert_eq!(Weak::strong_count(&w2), 0); + assert_eq!(Weak::weak_count(&w2), 0); + drop(w2); +} + +#[test] +fn try_unwrap() { + let x = Rc::new(3); + assert_eq!(Rc::try_unwrap(x), Ok(3)); + let x = Rc::new(4); + let _y = x.clone(); + assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4))); + let x = Rc::new(5); + let _w = Rc::downgrade(&x); + assert_eq!(Rc::try_unwrap(x), Ok(5)); +} + +#[test] +fn into_inner() { + let x = Rc::new(3); + assert_eq!(Rc::into_inner(x), Some(3)); + + let x = Rc::new(4); + let y = Rc::clone(&x); + assert_eq!(Rc::into_inner(x), None); + assert_eq!(Rc::into_inner(y), Some(4)); + + let x = Rc::new(5); + let _w = Rc::downgrade(&x); + assert_eq!(Rc::into_inner(x), Some(5)); +} + +#[test] +fn into_from_raw() { + let x = Rc::new(Box::new("hello")); + let y = x.clone(); + + let x_ptr = Rc::into_raw(x); + drop(y); + unsafe { + assert_eq!(**x_ptr, "hello"); + + let x = Rc::from_raw(x_ptr); + assert_eq!(**x, "hello"); + + assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello")); + } +} + +#[test] +fn test_into_from_raw_unsized() { + use std::fmt::Display; + use std::string::ToString; + + let rc: Rc = Rc::from("foo"); + + let ptr = Rc::into_raw(rc.clone()); + let rc2 = unsafe { Rc::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }, "foo"); + assert_eq!(rc, rc2); + + let rc: Rc = Rc::new(123); + + let ptr = Rc::into_raw(rc.clone()); + let rc2 = unsafe { Rc::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }.to_string(), "123"); + assert_eq!(rc2.to_string(), "123"); +} + +#[test] +fn into_from_weak_raw() { + let x = Rc::new(Box::new("hello")); + let y = Rc::downgrade(&x); + + let y_ptr = Weak::into_raw(y); + unsafe { + assert_eq!(**y_ptr, "hello"); + + let y = Weak::from_raw(y_ptr); + let y_up = Weak::upgrade(&y).unwrap(); + assert_eq!(**y_up, "hello"); + drop(y_up); + + assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello")); + } +} + +#[test] +fn test_into_from_weak_raw_unsized() { + use std::fmt::Display; + use std::string::ToString; + + let arc: Rc = Rc::from("foo"); + let weak: Weak = Rc::downgrade(&arc); + + let ptr = Weak::into_raw(weak.clone()); + let weak2 = unsafe { Weak::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }, "foo"); + assert!(weak.ptr_eq(&weak2)); + + let arc: Rc = Rc::new(123); + let weak: Weak = Rc::downgrade(&arc); + + let ptr = Weak::into_raw(weak.clone()); + let weak2 = unsafe { Weak::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }.to_string(), "123"); + assert!(weak.ptr_eq(&weak2)); +} + +#[test] +fn get_mut() { + let mut x = Rc::new(3); + *Rc::get_mut(&mut x).unwrap() = 4; + assert_eq!(*x, 4); + let y = x.clone(); + assert!(Rc::get_mut(&mut x).is_none()); + drop(y); + assert!(Rc::get_mut(&mut x).is_some()); + let _w = Rc::downgrade(&x); + assert!(Rc::get_mut(&mut x).is_none()); +} + +#[test] +fn test_cowrc_clone_make_unique() { + let mut cow0 = Rc::new(75); + let mut cow1 = cow0.clone(); + let mut cow2 = cow1.clone(); + + assert!(75 == *Rc::make_mut(&mut cow0)); + assert!(75 == *Rc::make_mut(&mut cow1)); + assert!(75 == *Rc::make_mut(&mut cow2)); + + *Rc::make_mut(&mut cow0) += 1; + *Rc::make_mut(&mut cow1) += 2; + *Rc::make_mut(&mut cow2) += 3; + + assert!(76 == *cow0); + assert!(77 == *cow1); + assert!(78 == *cow2); + + // none should point to the same backing memory + assert!(*cow0 != *cow1); + assert!(*cow0 != *cow2); + assert!(*cow1 != *cow2); +} + +#[test] +fn test_cowrc_clone_unique2() { + let mut cow0 = Rc::new(75); + let cow1 = cow0.clone(); + let cow2 = cow1.clone(); + + assert!(75 == *cow0); + assert!(75 == *cow1); + assert!(75 == *cow2); + + *Rc::make_mut(&mut cow0) += 1; + + assert!(76 == *cow0); + assert!(75 == *cow1); + assert!(75 == *cow2); + + // cow1 and cow2 should share the same contents + // cow0 should have a unique reference + assert!(*cow0 != *cow1); + assert!(*cow0 != *cow2); + assert!(*cow1 == *cow2); +} + +#[test] +fn test_cowrc_clone_weak() { + let mut cow0 = Rc::new(75); + let cow1_weak = Rc::downgrade(&cow0); + + assert!(75 == *cow0); + assert!(75 == *cow1_weak.upgrade().unwrap()); + + *Rc::make_mut(&mut cow0) += 1; + + assert!(76 == *cow0); + assert!(cow1_weak.upgrade().is_none()); +} + +/// This is similar to the doc-test for `Rc::make_mut()`, but on an unsized type (slice). +#[test] +fn test_cowrc_unsized() { + use std::rc::Rc; + + let mut data: Rc<[i32]> = Rc::new([10, 20, 30]); + + Rc::make_mut(&mut data)[0] += 1; // Won't clone anything + let mut other_data = Rc::clone(&data); // Won't clone inner data + Rc::make_mut(&mut data)[1] += 1; // Clones inner data + Rc::make_mut(&mut data)[2] += 1; // Won't clone anything + Rc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything + + // Now `data` and `other_data` point to different allocations. + assert_eq!(*data, [11, 21, 31]); + assert_eq!(*other_data, [110, 20, 30]); +} + +#[test] +fn test_show() { + let foo = Rc::new(75); + assert_eq!(format!("{foo:?}"), "75"); +} + +#[test] +fn test_unsized() { + let foo: Rc<[i32]> = Rc::new([1, 2, 3]); + assert_eq!(foo, foo.clone()); +} + +#[test] +fn test_maybe_thin_unsized() { + // If/when custom thin DSTs exist, this test should be updated to use one + use std::ffi::CStr; + + let x: Rc = Rc::from(c"swordfish"); + assert_eq!(format!("{x:?}"), "\"swordfish\""); + let y: Weak = Rc::downgrade(&x); + drop(x); + + // At this point, the weak points to a dropped DST + assert!(y.upgrade().is_none()); + // But we still need to be able to get the alloc layout to drop. + // CStr has no drop glue, but custom DSTs might, and need to work. + drop(y); +} + +#[test] +fn test_from_owned() { + let foo = 123; + let foo_rc = Rc::from(foo); + assert!(123 == *foo_rc); +} + +#[test] +fn test_new_weak() { + let foo: Weak = Weak::new(); + assert!(foo.upgrade().is_none()); +} + +#[test] +fn test_ptr_eq() { + let five = Rc::new(5); + let same_five = five.clone(); + let other_five = Rc::new(5); + + assert!(Rc::ptr_eq(&five, &same_five)); + assert!(!Rc::ptr_eq(&five, &other_five)); +} + +#[test] +fn test_from_str() { + let r: Rc = Rc::from("foo"); + + assert_eq!(&r[..], "foo"); +} + +#[test] +fn test_copy_from_slice() { + let s: &[u32] = &[1, 2, 3]; + let r: Rc<[u32]> = Rc::from(s); + + assert_eq!(&r[..], [1, 2, 3]); +} + +#[test] +fn test_clone_from_slice() { + #[derive(Clone, Debug, Eq, PartialEq)] + struct X(u32); + + let s: &[X] = &[X(1), X(2), X(3)]; + let r: Rc<[X]> = Rc::from(s); + + assert_eq!(&r[..], s); +} + +#[test] +#[should_panic] +fn test_clone_from_slice_panic() { + use std::string::{String, ToString}; + + struct Fail(u32, String); + + impl Clone for Fail { + fn clone(&self) -> Fail { + if self.0 == 2 { + panic!(); + } + Fail(self.0, self.1.clone()) + } + } + + let s: &[Fail] = + &[Fail(0, "foo".to_string()), Fail(1, "bar".to_string()), Fail(2, "baz".to_string())]; + + // Should panic, but not cause memory corruption + let _r: Rc<[Fail]> = Rc::from(s); +} + +#[test] +fn test_from_box() { + let b: Box = Box::new(123); + let r: Rc = Rc::from(b); + + assert_eq!(*r, 123); +} + +#[test] +fn test_from_box_str() { + use std::string::String; + + let s = String::from("foo").into_boxed_str(); + assert_eq!((&&&s).as_str(), "foo"); + + let r: Rc = Rc::from(s); + assert_eq!((&r).as_str(), "foo"); + assert_eq!(r.as_str(), "foo"); + + assert_eq!(&r[..], "foo"); +} + +#[test] +fn test_from_box_slice() { + let s = vec![1, 2, 3].into_boxed_slice(); + let r: Rc<[u32]> = Rc::from(s); + + assert_eq!(&r[..], [1, 2, 3]); +} + +#[test] +fn test_from_box_trait() { + use std::fmt::Display; + use std::string::ToString; + + let b: Box = Box::new(123); + let r: Rc = Rc::from(b); + + assert_eq!(r.to_string(), "123"); +} + +#[test] +fn test_from_box_trait_zero_sized() { + use std::fmt::Debug; + + let b: Box = Box::new(()); + let r: Rc = Rc::from(b); + + assert_eq!(format!("{r:?}"), "()"); +} + +#[test] +fn test_from_vec() { + let v = vec![1, 2, 3]; + let r: Rc<[u32]> = Rc::from(v); + + assert_eq!(&r[..], [1, 2, 3]); +} + +#[test] +fn test_downcast() { + use std::any::Any; + + let r1: Rc = Rc::new(i32::MAX); + let r2: Rc = Rc::new("abc"); + + assert!(r1.clone().downcast::().is_err()); + + let r1i32 = r1.downcast::(); + assert!(r1i32.is_ok()); + assert_eq!(r1i32.unwrap(), Rc::new(i32::MAX)); + + assert!(r2.clone().downcast::().is_err()); + + let r2str = r2.downcast::<&'static str>(); + assert!(r2str.is_ok()); + assert_eq!(r2str.unwrap(), Rc::new("abc")); +} + +#[test] +fn test_array_from_slice() { + let v = vec![1, 2, 3]; + let r: Rc<[u32]> = Rc::from(v); + + let a: Result, _> = r.clone().try_into(); + assert!(a.is_ok()); + + let a: Result, _> = r.clone().try_into(); + assert!(a.is_err()); +} + +#[test] +fn test_rc_cyclic_with_zero_refs() { + struct ZeroRefs { + inner: Weak, + } + + let zero_refs = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + ZeroRefs { inner: Weak::new() } + }); + + assert_eq!(Rc::strong_count(&zero_refs), 1); + assert_eq!(Rc::weak_count(&zero_refs), 0); + assert_eq!(zero_refs.inner.strong_count(), 0); + assert_eq!(zero_refs.inner.weak_count(), 0); +} + +#[test] +fn test_rc_cyclic_with_one_ref() { + struct OneRef { + inner: Weak, + } + + let one_ref = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + OneRef { inner: inner.clone() } + }); + + assert_eq!(Rc::strong_count(&one_ref), 1); + assert_eq!(Rc::weak_count(&one_ref), 1); + + let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap(); + assert!(Rc::ptr_eq(&one_ref, &one_ref2)); + + assert_eq!(one_ref.inner.strong_count(), 2); + assert_eq!(one_ref.inner.weak_count(), 1); +} + +#[test] +fn test_rc_cyclic_with_two_ref() { + struct TwoRefs { + inner: Weak, + inner1: Weak, + } + + let two_refs = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + TwoRefs { inner: inner.clone(), inner1: inner.clone() } + }); + + assert_eq!(Rc::strong_count(&two_refs), 1); + assert_eq!(Rc::weak_count(&two_refs), 2); + + let two_ref3 = Weak::upgrade(&two_refs.inner).unwrap(); + assert!(Rc::ptr_eq(&two_refs, &two_ref3)); + + let two_ref2 = Weak::upgrade(&two_refs.inner1).unwrap(); + assert!(Rc::ptr_eq(&two_refs, &two_ref2)); + + assert_eq!(Rc::strong_count(&two_refs), 3); + assert_eq!(Rc::weak_count(&two_refs), 2); +} + +#[test] +fn test_unique_rc_weak() { + let rc = UniqueRc::new(42); + let weak = UniqueRc::downgrade(&rc); + assert!(weak.upgrade().is_none()); + + let _rc = UniqueRc::into_rc(rc); + assert_eq!(*weak.upgrade().unwrap(), 42); +} + +#[test] +fn test_unique_rc_drop_weak() { + let rc = UniqueRc::new(42); + let weak = UniqueRc::downgrade(&rc); + mem::drop(weak); + + let rc = UniqueRc::into_rc(rc); + assert_eq!(*rc, 42); +} + +#[test] +fn test_unique_rc_drops_contents() { + let mut dropped = false; + struct DropMe<'a>(&'a mut bool); + impl Drop for DropMe<'_> { + fn drop(&mut self) { + *self.0 = true; + } + } + { + let rc = UniqueRc::new(DropMe(&mut dropped)); + drop(rc); + } + assert!(dropped); +} + +/// Exercise the non-default allocator usage. +#[test] +fn test_unique_rc_with_alloc_drops_contents() { + let mut dropped = false; + struct DropMe<'a>(&'a mut bool); + impl Drop for DropMe<'_> { + fn drop(&mut self) { + *self.0 = true; + } + } + { + let rc = UniqueRc::new_in(DropMe(&mut dropped), std::alloc::System); + drop(rc); + } + assert!(dropped); +} + +#[test] +fn test_unique_rc_weak_clone_holding_ref() { + let mut v = UniqueRc::new(0u8); + let w = UniqueRc::downgrade(&v); + let r = &mut *v; + let _ = w.clone(); // touch weak count + *r = 123; +} + +#[test] +fn test_unique_rc_unsizing_coercion() { + let mut rc: UniqueRc<[u8]> = UniqueRc::new([0u8; 3]); + assert_eq!(rc.len(), 3); + rc[0] = 123; + let rc: Rc<[u8]> = UniqueRc::into_rc(rc); + assert_eq!(*rc, [123, 0, 0]); +} -- cgit 1.4.1-3-g733a5 From 701bedc323b0314ef6f084ba98ed18327faa36bc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Feb 2025 12:09:45 +0000 Subject: Move last remaining Rc test to alloctests --- library/alloc/src/rc.rs | 4145 +++++++++++++++++++++++++++++++++++++++ library/alloc/src/rc/mod.rs | 4148 ---------------------------------------- library/alloc/src/rc/tests.rs | 15 - library/alloctests/tests/rc.rs | 18 + 4 files changed, 4163 insertions(+), 4163 deletions(-) create mode 100644 library/alloc/src/rc.rs delete mode 100644 library/alloc/src/rc/mod.rs delete mode 100644 library/alloc/src/rc/tests.rs diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs new file mode 100644 index 00000000000..2a4d4f26444 --- /dev/null +++ b/library/alloc/src/rc.rs @@ -0,0 +1,4145 @@ +//! Single-threaded reference-counting pointers. 'Rc' stands for 'Reference +//! Counted'. +//! +//! The type [`Rc`][`Rc`] provides shared ownership of a value of type `T`, +//! allocated in the heap. Invoking [`clone`][clone] on [`Rc`] produces a new +//! pointer to the same allocation in the heap. When the last [`Rc`] pointer to a +//! given allocation is destroyed, the value stored in that allocation (often +//! referred to as "inner value") is also dropped. +//! +//! Shared references in Rust disallow mutation by default, and [`Rc`] +//! is no exception: you cannot generally obtain a mutable reference to +//! something inside an [`Rc`]. If you need mutability, put a [`Cell`] +//! or [`RefCell`] inside the [`Rc`]; see [an example of mutability +//! inside an `Rc`][mutability]. +//! +//! [`Rc`] uses non-atomic reference counting. This means that overhead is very +//! low, but an [`Rc`] cannot be sent between threads, and consequently [`Rc`] +//! does not implement [`Send`]. As a result, the Rust compiler +//! will check *at compile time* that you are not sending [`Rc`]s between +//! threads. If you need multi-threaded, atomic reference counting, use +//! [`sync::Arc`][arc]. +//! +//! The [`downgrade`][downgrade] method can be used to create a non-owning +//! [`Weak`] pointer. A [`Weak`] pointer can be [`upgrade`][upgrade]d +//! to an [`Rc`], but this will return [`None`] if the value stored in the allocation has +//! already been dropped. In other words, `Weak` pointers do not keep the value +//! inside the allocation alive; however, they *do* keep the allocation +//! (the backing store for the inner value) alive. +//! +//! A cycle between [`Rc`] pointers will never be deallocated. For this reason, +//! [`Weak`] is used to break cycles. For example, a tree could have strong +//! [`Rc`] pointers from parent nodes to children, and [`Weak`] pointers from +//! children back to their parents. +//! +//! `Rc` automatically dereferences to `T` (via the [`Deref`] trait), +//! so you can call `T`'s methods on a value of type [`Rc`][`Rc`]. To avoid name +//! clashes with `T`'s methods, the methods of [`Rc`][`Rc`] itself are associated +//! functions, called using [fully qualified syntax]: +//! +//! ``` +//! use std::rc::Rc; +//! +//! let my_rc = Rc::new(()); +//! let my_weak = Rc::downgrade(&my_rc); +//! ``` +//! +//! `Rc`'s implementations of traits like `Clone` may also be called using +//! fully qualified syntax. Some people prefer to use fully qualified syntax, +//! while others prefer using method-call syntax. +//! +//! ``` +//! use std::rc::Rc; +//! +//! let rc = Rc::new(()); +//! // Method-call syntax +//! let rc2 = rc.clone(); +//! // Fully qualified syntax +//! let rc3 = Rc::clone(&rc); +//! ``` +//! +//! [`Weak`][`Weak`] does not auto-dereference to `T`, because the inner value may have +//! already been dropped. +//! +//! # Cloning references +//! +//! Creating a new reference to the same allocation as an existing reference counted pointer +//! is done using the `Clone` trait implemented for [`Rc`][`Rc`] and [`Weak`][`Weak`]. +//! +//! ``` +//! use std::rc::Rc; +//! +//! let foo = Rc::new(vec![1.0, 2.0, 3.0]); +//! // The two syntaxes below are equivalent. +//! let a = foo.clone(); +//! let b = Rc::clone(&foo); +//! // a and b both point to the same memory location as foo. +//! ``` +//! +//! The `Rc::clone(&from)` syntax is the most idiomatic because it conveys more explicitly +//! the meaning of the code. In the example above, this syntax makes it easier to see that +//! this code is creating a new reference rather than copying the whole content of foo. +//! +//! # Examples +//! +//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. +//! We want to have our `Gadget`s point to their `Owner`. We can't do this with +//! unique ownership, because more than one gadget may belong to the same +//! `Owner`. [`Rc`] allows us to share an `Owner` between multiple `Gadget`s, +//! and have the `Owner` remain allocated as long as any `Gadget` points at it. +//! +//! ``` +//! use std::rc::Rc; +//! +//! struct Owner { +//! name: String, +//! // ...other fields +//! } +//! +//! struct Gadget { +//! id: i32, +//! owner: Rc, +//! // ...other fields +//! } +//! +//! fn main() { +//! // Create a reference-counted `Owner`. +//! let gadget_owner: Rc = Rc::new( +//! Owner { +//! name: "Gadget Man".to_string(), +//! } +//! ); +//! +//! // Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc` +//! // gives us a new pointer to the same `Owner` allocation, incrementing +//! // the reference count in the process. +//! let gadget1 = Gadget { +//! id: 1, +//! owner: Rc::clone(&gadget_owner), +//! }; +//! let gadget2 = Gadget { +//! id: 2, +//! owner: Rc::clone(&gadget_owner), +//! }; +//! +//! // Dispose of our local variable `gadget_owner`. +//! drop(gadget_owner); +//! +//! // Despite dropping `gadget_owner`, we're still able to print out the name +//! // of the `Owner` of the `Gadget`s. This is because we've only dropped a +//! // single `Rc`, not the `Owner` it points to. As long as there are +//! // other `Rc` pointing at the same `Owner` allocation, it will remain +//! // live. The field projection `gadget1.owner.name` works because +//! // `Rc` automatically dereferences to `Owner`. +//! println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name); +//! println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name); +//! +//! // At the end of the function, `gadget1` and `gadget2` are destroyed, and +//! // with them the last counted references to our `Owner`. Gadget Man now +//! // gets destroyed as well. +//! } +//! ``` +//! +//! If our requirements change, and we also need to be able to traverse from +//! `Owner` to `Gadget`, we will run into problems. An [`Rc`] pointer from `Owner` +//! to `Gadget` introduces a cycle. This means that their +//! reference counts can never reach 0, and the allocation will never be destroyed: +//! a memory leak. In order to get around this, we can use [`Weak`] +//! pointers. +//! +//! Rust actually makes it somewhat difficult to produce this loop in the first +//! place. In order to end up with two values that point at each other, one of +//! them needs to be mutable. This is difficult because [`Rc`] enforces +//! memory safety by only giving out shared references to the value it wraps, +//! and these don't allow direct mutation. We need to wrap the part of the +//! value we wish to mutate in a [`RefCell`], which provides *interior +//! mutability*: a method to achieve mutability through a shared reference. +//! [`RefCell`] enforces Rust's borrowing rules at runtime. +//! +//! ``` +//! use std::rc::Rc; +//! use std::rc::Weak; +//! use std::cell::RefCell; +//! +//! struct Owner { +//! name: String, +//! gadgets: RefCell>>, +//! // ...other fields +//! } +//! +//! struct Gadget { +//! id: i32, +//! owner: Rc, +//! // ...other fields +//! } +//! +//! fn main() { +//! // Create a reference-counted `Owner`. Note that we've put the `Owner`'s +//! // vector of `Gadget`s inside a `RefCell` so that we can mutate it through +//! // a shared reference. +//! let gadget_owner: Rc = Rc::new( +//! Owner { +//! name: "Gadget Man".to_string(), +//! gadgets: RefCell::new(vec![]), +//! } +//! ); +//! +//! // Create `Gadget`s belonging to `gadget_owner`, as before. +//! let gadget1 = Rc::new( +//! Gadget { +//! id: 1, +//! owner: Rc::clone(&gadget_owner), +//! } +//! ); +//! let gadget2 = Rc::new( +//! Gadget { +//! id: 2, +//! owner: Rc::clone(&gadget_owner), +//! } +//! ); +//! +//! // Add the `Gadget`s to their `Owner`. +//! { +//! let mut gadgets = gadget_owner.gadgets.borrow_mut(); +//! gadgets.push(Rc::downgrade(&gadget1)); +//! gadgets.push(Rc::downgrade(&gadget2)); +//! +//! // `RefCell` dynamic borrow ends here. +//! } +//! +//! // Iterate over our `Gadget`s, printing their details out. +//! for gadget_weak in gadget_owner.gadgets.borrow().iter() { +//! +//! // `gadget_weak` is a `Weak`. Since `Weak` pointers can't +//! // guarantee the allocation still exists, we need to call +//! // `upgrade`, which returns an `Option>`. +//! // +//! // In this case we know the allocation still exists, so we simply +//! // `unwrap` the `Option`. In a more complicated program, you might +//! // need graceful error handling for a `None` result. +//! +//! let gadget = gadget_weak.upgrade().unwrap(); +//! println!("Gadget {} owned by {}", gadget.id, gadget.owner.name); +//! } +//! +//! // At the end of the function, `gadget_owner`, `gadget1`, and `gadget2` +//! // are destroyed. There are now no strong (`Rc`) pointers to the +//! // gadgets, so they are destroyed. This zeroes the reference count on +//! // Gadget Man, so he gets destroyed as well. +//! } +//! ``` +//! +//! [clone]: Clone::clone +//! [`Cell`]: core::cell::Cell +//! [`RefCell`]: core::cell::RefCell +//! [arc]: crate::sync::Arc +//! [`Deref`]: core::ops::Deref +//! [downgrade]: Rc::downgrade +//! [upgrade]: Weak::upgrade +//! [mutability]: core::cell#introducing-mutability-inside-of-something-immutable +//! [fully qualified syntax]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name + +#![stable(feature = "rust1", since = "1.0.0")] + +use core::any::Any; +use core::cell::Cell; +#[cfg(not(no_global_oom_handling))] +use core::clone::CloneToUninit; +use core::cmp::Ordering; +use core::hash::{Hash, Hasher}; +use core::intrinsics::abort; +#[cfg(not(no_global_oom_handling))] +use core::iter; +use core::marker::{PhantomData, Unsize}; +use core::mem::{self, ManuallyDrop, align_of_val_raw}; +use core::num::NonZeroUsize; +use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; +use core::panic::{RefUnwindSafe, UnwindSafe}; +#[cfg(not(no_global_oom_handling))] +use core::pin::Pin; +use core::pin::PinCoerceUnsized; +use core::ptr::{self, NonNull, drop_in_place}; +#[cfg(not(no_global_oom_handling))] +use core::slice::from_raw_parts_mut; +use core::{borrow, fmt, hint}; +#[cfg(test)] +use std::boxed::Box; + +#[cfg(not(no_global_oom_handling))] +use crate::alloc::handle_alloc_error; +use crate::alloc::{AllocError, Allocator, Global, Layout}; +use crate::borrow::{Cow, ToOwned}; +#[cfg(not(test))] +use crate::boxed::Box; +#[cfg(not(no_global_oom_handling))] +use crate::string::String; +#[cfg(not(no_global_oom_handling))] +use crate::vec::Vec; + +// This is repr(C) to future-proof against possible field-reordering, which +// would interfere with otherwise safe [into|from]_raw() of transmutable +// inner types. +#[repr(C)] +struct RcInner { + strong: Cell, + weak: Cell, + value: T, +} + +/// Calculate layout for `RcInner` using the inner value's layout +fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout { + // Calculate layout using the given value layout. + // Previously, layout was calculated on the expression + // `&*(ptr as *const RcInner)`, but this created a misaligned + // reference (see #54908). + Layout::new::>().extend(layout).unwrap().0.pad_to_align() +} + +/// A single-threaded reference-counting pointer. 'Rc' stands for 'Reference +/// Counted'. +/// +/// See the [module-level documentation](./index.html) for more details. +/// +/// The inherent methods of `Rc` are all associated functions, which means +/// that you have to call them as e.g., [`Rc::get_mut(&mut value)`][get_mut] instead of +/// `value.get_mut()`. This avoids conflicts with methods of the inner type `T`. +/// +/// [get_mut]: Rc::get_mut +#[doc(search_unbox)] +#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] +pub struct Rc< + T: ?Sized, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + ptr: NonNull>, + phantom: PhantomData>, + alloc: A, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl !Send for Rc {} + +// Note that this negative impl isn't strictly necessary for correctness, +// as `Rc` transitively contains a `Cell`, which is itself `!Sync`. +// However, given how important `Rc`'s `!Sync`-ness is, +// having an explicit negative impl is nice for documentation purposes +// and results in nicer error messages. +#[stable(feature = "rust1", since = "1.0.0")] +impl !Sync for Rc {} + +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl UnwindSafe for Rc {} +#[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")] +impl RefUnwindSafe for Rc {} + +#[unstable(feature = "coerce_unsized", issue = "18598")] +impl, U: ?Sized, A: Allocator> CoerceUnsized> for Rc {} + +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +impl, U: ?Sized> DispatchFromDyn> for Rc {} + +impl Rc { + #[inline] + unsafe fn from_inner(ptr: NonNull>) -> Self { + unsafe { Self::from_inner_in(ptr, Global) } + } + + #[inline] + unsafe fn from_ptr(ptr: *mut RcInner) -> Self { + unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) } + } +} + +impl Rc { + #[inline(always)] + fn inner(&self) -> &RcInner { + // This unsafety is ok because while this Rc is alive we're guaranteed + // that the inner pointer is valid. + unsafe { self.ptr.as_ref() } + } + + #[inline] + fn into_inner_with_allocator(this: Self) -> (NonNull>, A) { + let this = mem::ManuallyDrop::new(this); + (this.ptr, unsafe { ptr::read(&this.alloc) }) + } + + #[inline] + unsafe fn from_inner_in(ptr: NonNull>, alloc: A) -> Self { + Self { ptr, phantom: PhantomData, alloc } + } + + #[inline] + unsafe fn from_ptr_in(ptr: *mut RcInner, alloc: A) -> Self { + unsafe { Self::from_inner_in(NonNull::new_unchecked(ptr), alloc) } + } + + // Non-inlined part of `drop`. + #[inline(never)] + unsafe fn drop_slow(&mut self) { + // Reconstruct the "strong weak" pointer and drop it when this + // variable goes out of scope. This ensures that the memory is + // deallocated even if the destructor of `T` panics. + let _weak = Weak { ptr: self.ptr, alloc: &self.alloc }; + + // Destroy the contained object. + // We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed. + unsafe { + ptr::drop_in_place(&mut (*self.ptr.as_ptr()).value); + } + } +} + +impl Rc { + /// Constructs a new `Rc`. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(value: T) -> Rc { + // There is an implicit weak pointer owned by all the strong + // pointers, which ensures that the weak destructor never frees + // the allocation while the strong destructor is running, even + // if the weak pointer is stored inside the strong one. + unsafe { + Self::from_inner( + Box::leak(Box::new(RcInner { strong: Cell::new(1), weak: Cell::new(1), value })) + .into(), + ) + } + } + + /// Constructs a new `Rc` while giving you a `Weak` to the allocation, + /// to allow you to construct a `T` which holds a weak pointer to itself. + /// + /// Generally, a structure circularly referencing itself, either directly or + /// indirectly, should not hold a strong reference to itself to prevent a memory leak. + /// Using this function, you get access to the weak pointer during the + /// initialization of `T`, before the `Rc` is created, such that you can + /// clone and store it inside the `T`. + /// + /// `new_cyclic` first allocates the managed allocation for the `Rc`, + /// then calls your closure, giving it a `Weak` to this allocation, + /// and only afterwards completes the construction of the `Rc` by placing + /// the `T` returned from your closure into the allocation. + /// + /// Since the new `Rc` is not fully-constructed until `Rc::new_cyclic` + /// returns, calling [`upgrade`] on the weak reference inside your closure will + /// fail and result in a `None` value. + /// + /// # Panics + /// + /// If `data_fn` panics, the panic is propagated to the caller, and the + /// temporary [`Weak`] is dropped normally. + /// + /// # Examples + /// + /// ``` + /// # #![allow(dead_code)] + /// use std::rc::{Rc, Weak}; + /// + /// struct Gadget { + /// me: Weak, + /// } + /// + /// impl Gadget { + /// /// Constructs a reference counted Gadget. + /// fn new() -> Rc { + /// // `me` is a `Weak` pointing at the new allocation of the + /// // `Rc` we're constructing. + /// Rc::new_cyclic(|me| { + /// // Create the actual struct here. + /// Gadget { me: me.clone() } + /// }) + /// } + /// + /// /// Returns a reference counted pointer to Self. + /// fn me(&self) -> Rc { + /// self.me.upgrade().unwrap() + /// } + /// } + /// ``` + /// [`upgrade`]: Weak::upgrade + #[cfg(not(no_global_oom_handling))] + #[stable(feature = "arc_new_cyclic", since = "1.60.0")] + pub fn new_cyclic(data_fn: F) -> Rc + where + F: FnOnce(&Weak) -> T, + { + Self::new_cyclic_in(data_fn, Global) + } + + /// Constructs a new `Rc` with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut five = Rc::::new_uninit(); + /// + /// // Deferred initialization: + /// Rc::get_mut(&mut five).unwrap().write(5); + /// + /// let five = unsafe { five.assume_init() }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[stable(feature = "new_uninit", since = "1.82.0")] + #[must_use] + pub fn new_uninit() -> Rc> { + unsafe { + Rc::from_ptr(Rc::allocate_for_layout( + Layout::new::(), + |layout| Global.allocate(layout), + <*mut u8>::cast, + )) + } + } + + /// Constructs a new `Rc` with uninitialized contents, with the memory + /// being filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_zeroed_alloc)] + /// + /// use std::rc::Rc; + /// + /// let zero = Rc::::new_zeroed(); + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "new_zeroed_alloc", issue = "129396")] + #[must_use] + pub fn new_zeroed() -> Rc> { + unsafe { + Rc::from_ptr(Rc::allocate_for_layout( + Layout::new::(), + |layout| Global.allocate_zeroed(layout), + <*mut u8>::cast, + )) + } + } + + /// Constructs a new `Rc`, returning an error if the allocation fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// use std::rc::Rc; + /// + /// let five = Rc::try_new(5); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn try_new(value: T) -> Result, AllocError> { + // There is an implicit weak pointer owned by all the strong + // pointers, which ensures that the weak destructor never frees + // the allocation while the strong destructor is running, even + // if the weak pointer is stored inside the strong one. + unsafe { + Ok(Self::from_inner( + Box::leak(Box::try_new(RcInner { + strong: Cell::new(1), + weak: Cell::new(1), + value, + })?) + .into(), + )) + } + } + + /// Constructs a new `Rc` with uninitialized contents, returning an error if the allocation fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut five = Rc::::try_new_uninit()?; + /// + /// // Deferred initialization: + /// Rc::get_mut(&mut five).unwrap().write(5); + /// + /// let five = unsafe { five.assume_init() }; + /// + /// assert_eq!(*five, 5); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + pub fn try_new_uninit() -> Result>, AllocError> { + unsafe { + Ok(Rc::from_ptr(Rc::try_allocate_for_layout( + Layout::new::(), + |layout| Global.allocate(layout), + <*mut u8>::cast, + )?)) + } + } + + /// Constructs a new `Rc` with uninitialized contents, with the memory + /// being filled with `0` bytes, returning an error if the allocation fails + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// + /// let zero = Rc::::try_new_zeroed()?; + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[unstable(feature = "allocator_api", issue = "32838")] + //#[unstable(feature = "new_uninit", issue = "63291")] + pub fn try_new_zeroed() -> Result>, AllocError> { + unsafe { + Ok(Rc::from_ptr(Rc::try_allocate_for_layout( + Layout::new::(), + |layout| Global.allocate_zeroed(layout), + <*mut u8>::cast, + )?)) + } + } + /// Constructs a new `Pin>`. If `T` does not implement `Unpin`, then + /// `value` will be pinned in memory and unable to be moved. + #[cfg(not(no_global_oom_handling))] + #[stable(feature = "pin", since = "1.33.0")] + #[must_use] + pub fn pin(value: T) -> Pin> { + unsafe { Pin::new_unchecked(Rc::new(value)) } + } +} + +impl Rc { + /// Constructs a new `Rc` in the provided allocator. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let five = Rc::new_in(5, System); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn new_in(value: T, alloc: A) -> Rc { + // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. + // That would make code size bigger. + match Self::try_new_in(value, alloc) { + Ok(m) => m, + Err(_) => handle_alloc_error(Layout::new::>()), + } + } + + /// Constructs a new `Rc` with uninitialized contents in the provided allocator. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let mut five = Rc::::new_uninit_in(System); + /// + /// let five = unsafe { + /// // Deferred initialization: + /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn new_uninit_in(alloc: A) -> Rc, A> { + unsafe { + Rc::from_ptr_in( + Rc::allocate_for_layout( + Layout::new::(), + |layout| alloc.allocate(layout), + <*mut u8>::cast, + ), + alloc, + ) + } + } + + /// Constructs a new `Rc` with uninitialized contents, with the memory + /// being filled with `0` bytes, in the provided allocator. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let zero = Rc::::new_zeroed_in(System); + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn new_zeroed_in(alloc: A) -> Rc, A> { + unsafe { + Rc::from_ptr_in( + Rc::allocate_for_layout( + Layout::new::(), + |layout| alloc.allocate_zeroed(layout), + <*mut u8>::cast, + ), + alloc, + ) + } + } + + /// Constructs a new `Rc` in the given allocator while giving you a `Weak` to the allocation, + /// to allow you to construct a `T` which holds a weak pointer to itself. + /// + /// Generally, a structure circularly referencing itself, either directly or + /// indirectly, should not hold a strong reference to itself to prevent a memory leak. + /// Using this function, you get access to the weak pointer during the + /// initialization of `T`, before the `Rc` is created, such that you can + /// clone and store it inside the `T`. + /// + /// `new_cyclic_in` first allocates the managed allocation for the `Rc`, + /// then calls your closure, giving it a `Weak` to this allocation, + /// and only afterwards completes the construction of the `Rc` by placing + /// the `T` returned from your closure into the allocation. + /// + /// Since the new `Rc` is not fully-constructed until `Rc::new_cyclic_in` + /// returns, calling [`upgrade`] on the weak reference inside your closure will + /// fail and result in a `None` value. + /// + /// # Panics + /// + /// If `data_fn` panics, the panic is propagated to the caller, and the + /// temporary [`Weak`] is dropped normally. + /// + /// # Examples + /// + /// See [`new_cyclic`]. + /// + /// [`new_cyclic`]: Rc::new_cyclic + /// [`upgrade`]: Weak::upgrade + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_cyclic_in(data_fn: F, alloc: A) -> Rc + where + F: FnOnce(&Weak) -> T, + { + // Construct the inner in the "uninitialized" state with a single + // weak reference. + let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in( + RcInner { + strong: Cell::new(0), + weak: Cell::new(1), + value: mem::MaybeUninit::::uninit(), + }, + alloc, + )); + let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into(); + let init_ptr: NonNull> = uninit_ptr.cast(); + + let weak = Weak { ptr: init_ptr, alloc }; + + // It's important we don't give up ownership of the weak pointer, or + // else the memory might be freed by the time `data_fn` returns. If + // we really wanted to pass ownership, we could create an additional + // weak pointer for ourselves, but this would result in additional + // updates to the weak reference count which might not be necessary + // otherwise. + let data = data_fn(&weak); + + let strong = unsafe { + let inner = init_ptr.as_ptr(); + ptr::write(&raw mut (*inner).value, data); + + let prev_value = (*inner).strong.get(); + debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); + (*inner).strong.set(1); + + // Strong references should collectively own a shared weak reference, + // so don't run the destructor for our old weak reference. + // Calling into_raw_with_allocator has the double effect of giving us back the allocator, + // and forgetting the weak reference. + let alloc = weak.into_raw_with_allocator().1; + + Rc::from_inner_in(init_ptr, alloc) + }; + + strong + } + + /// Constructs a new `Rc` in the provided allocator, returning an error if the allocation + /// fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let five = Rc::try_new_in(5, System); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn try_new_in(value: T, alloc: A) -> Result { + // There is an implicit weak pointer owned by all the strong + // pointers, which ensures that the weak destructor never frees + // the allocation while the strong destructor is running, even + // if the weak pointer is stored inside the strong one. + let (ptr, alloc) = Box::into_unique(Box::try_new_in( + RcInner { strong: Cell::new(1), weak: Cell::new(1), value }, + alloc, + )?); + Ok(unsafe { Self::from_inner_in(ptr.into(), alloc) }) + } + + /// Constructs a new `Rc` with uninitialized contents, in the provided allocator, returning an + /// error if the allocation fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let mut five = Rc::::try_new_uninit_in(System)?; + /// + /// let five = unsafe { + /// // Deferred initialization: + /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// + /// five.assume_init() + /// }; + /// + /// assert_eq!(*five, 5); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> { + unsafe { + Ok(Rc::from_ptr_in( + Rc::try_allocate_for_layout( + Layout::new::(), + |layout| alloc.allocate(layout), + <*mut u8>::cast, + )?, + alloc, + )) + } + } + + /// Constructs a new `Rc` with uninitialized contents, with the memory + /// being filled with `0` bytes, in the provided allocator, returning an error if the allocation + /// fails + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let zero = Rc::::try_new_zeroed_in(System)?; + /// let zero = unsafe { zero.assume_init() }; + /// + /// assert_eq!(*zero, 0); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[unstable(feature = "allocator_api", issue = "32838")] + //#[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> { + unsafe { + Ok(Rc::from_ptr_in( + Rc::try_allocate_for_layout( + Layout::new::(), + |layout| alloc.allocate_zeroed(layout), + <*mut u8>::cast, + )?, + alloc, + )) + } + } + + /// Constructs a new `Pin>` in the provided allocator. If `T` does not implement `Unpin`, then + /// `value` will be pinned in memory and unable to be moved. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn pin_in(value: T, alloc: A) -> Pin + where + A: 'static, + { + unsafe { Pin::new_unchecked(Rc::new_in(value, alloc)) } + } + + /// Returns the inner value, if the `Rc` has exactly one strong reference. + /// + /// Otherwise, an [`Err`] is returned with the same `Rc` that was + /// passed in. + /// + /// This will succeed even if there are outstanding weak references. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new(3); + /// assert_eq!(Rc::try_unwrap(x), Ok(3)); + /// + /// let x = Rc::new(4); + /// let _y = Rc::clone(&x); + /// assert_eq!(*Rc::try_unwrap(x).unwrap_err(), 4); + /// ``` + #[inline] + #[stable(feature = "rc_unique", since = "1.4.0")] + pub fn try_unwrap(this: Self) -> Result { + if Rc::strong_count(&this) == 1 { + let this = ManuallyDrop::new(this); + + let val: T = unsafe { ptr::read(&**this) }; // copy the contained object + let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator + + // Indicate to Weaks that they can't be promoted by decrementing + // the strong count, and then remove the implicit "strong weak" + // pointer while also handling drop logic by just crafting a + // fake Weak. + this.inner().dec_strong(); + let _weak = Weak { ptr: this.ptr, alloc }; + Ok(val) + } else { + Err(this) + } + } + + /// Returns the inner value, if the `Rc` has exactly one strong reference. + /// + /// Otherwise, [`None`] is returned and the `Rc` is dropped. + /// + /// This will succeed even if there are outstanding weak references. + /// + /// If `Rc::into_inner` is called on every clone of this `Rc`, + /// it is guaranteed that exactly one of the calls returns the inner value. + /// This means in particular that the inner value is not dropped. + /// + /// [`Rc::try_unwrap`] is conceptually similar to `Rc::into_inner`. + /// And while they are meant for different use-cases, `Rc::into_inner(this)` + /// is in fact equivalent to [Rc::try_unwrap]\(this).[ok][Result::ok](). + /// (Note that the same kind of equivalence does **not** hold true for + /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`!) + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new(3); + /// assert_eq!(Rc::into_inner(x), Some(3)); + /// + /// let x = Rc::new(4); + /// let y = Rc::clone(&x); + /// + /// assert_eq!(Rc::into_inner(y), None); + /// assert_eq!(Rc::into_inner(x), Some(4)); + /// ``` + #[inline] + #[stable(feature = "rc_into_inner", since = "1.70.0")] + pub fn into_inner(this: Self) -> Option { + Rc::try_unwrap(this).ok() + } +} + +impl Rc<[T]> { + /// Constructs a new reference-counted slice with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut values = Rc::<[u32]>::new_uninit_slice(3); + /// + /// // Deferred initialization: + /// let data = Rc::get_mut(&mut values).unwrap(); + /// data[0].write(1); + /// data[1].write(2); + /// data[2].write(3); + /// + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[stable(feature = "new_uninit", since = "1.82.0")] + #[must_use] + pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit]> { + unsafe { Rc::from_ptr(Rc::allocate_for_slice(len)) } + } + + /// Constructs a new reference-counted slice with uninitialized contents, with the memory being + /// filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_zeroed_alloc)] + /// + /// use std::rc::Rc; + /// + /// let values = Rc::<[u32]>::new_zeroed_slice(3); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "new_zeroed_alloc", issue = "129396")] + #[must_use] + pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit]> { + unsafe { + Rc::from_ptr(Rc::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| Global.allocate_zeroed(layout), + |mem| { + ptr::slice_from_raw_parts_mut(mem.cast::(), len) + as *mut RcInner<[mem::MaybeUninit]> + }, + )) + } + } + + /// Converts the reference-counted slice into a reference-counted array. + /// + /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type. + /// + /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. + #[unstable(feature = "slice_as_array", issue = "133508")] + #[inline] + #[must_use] + pub fn into_array(self) -> Option> { + if self.len() == N { + let ptr = Self::into_raw(self) as *const [T; N]; + + // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length. + let me = unsafe { Rc::from_raw(ptr) }; + Some(me) + } else { + None + } + } +} + +impl Rc<[T], A> { + /// Constructs a new reference-counted slice with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let mut values = Rc::<[u32], _>::new_uninit_slice_in(3, System); + /// + /// let values = unsafe { + /// // Deferred initialization: + /// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); + /// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); + /// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); + /// + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn new_uninit_slice_in(len: usize, alloc: A) -> Rc<[mem::MaybeUninit], A> { + unsafe { Rc::from_ptr_in(Rc::allocate_for_slice_in(len, &alloc), alloc) } + } + + /// Constructs a new reference-counted slice with uninitialized contents, with the memory being + /// filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let values = Rc::<[u32], _>::new_zeroed_slice_in(3, System); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "new_uninit", issue = "63291")] + #[inline] + pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Rc<[mem::MaybeUninit], A> { + unsafe { + Rc::from_ptr_in( + Rc::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| alloc.allocate_zeroed(layout), + |mem| { + ptr::slice_from_raw_parts_mut(mem.cast::(), len) + as *mut RcInner<[mem::MaybeUninit]> + }, + ), + alloc, + ) + } + } +} + +impl Rc, A> { + /// Converts to `Rc`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the inner value + /// really is in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut five = Rc::::new_uninit(); + /// + /// // Deferred initialization: + /// Rc::get_mut(&mut five).unwrap().write(5); + /// + /// let five = unsafe { five.assume_init() }; + /// + /// assert_eq!(*five, 5) + /// ``` + #[stable(feature = "new_uninit", since = "1.82.0")] + #[inline] + pub unsafe fn assume_init(self) -> Rc { + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + unsafe { Rc::from_inner_in(ptr.cast(), alloc) } + } +} + +impl Rc<[mem::MaybeUninit], A> { + /// Converts to `Rc<[T]>`. + /// + /// # Safety + /// + /// As with [`MaybeUninit::assume_init`], + /// it is up to the caller to guarantee that the inner value + /// really is in an initialized state. + /// Calling this when the content is not yet fully initialized + /// causes immediate undefined behavior. + /// + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut values = Rc::<[u32]>::new_uninit_slice(3); + /// + /// // Deferred initialization: + /// let data = Rc::get_mut(&mut values).unwrap(); + /// data[0].write(1); + /// data[1].write(2); + /// data[2].write(3); + /// + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [1, 2, 3]) + /// ``` + #[stable(feature = "new_uninit", since = "1.82.0")] + #[inline] + pub unsafe fn assume_init(self) -> Rc<[T], A> { + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + unsafe { Rc::from_ptr_in(ptr.as_ptr() as _, alloc) } + } +} + +impl Rc { + /// Constructs an `Rc` from a raw pointer. + /// + /// The raw pointer must have been previously returned by a call to + /// [`Rc::into_raw`][into_raw] with the following requirements: + /// + /// * If `U` is sized, it must have the same size and alignment as `T`. This + /// is trivially true if `U` is `T`. + /// * If `U` is unsized, its data pointer must have the same size and + /// alignment as `T`. This is trivially true if `Rc` was constructed + /// through `Rc` and then converted to `Rc` through an [unsized + /// coercion]. + /// + /// Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// + /// The raw pointer must point to a block of memory allocated by the global allocator + /// + /// The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. + /// + /// This function is unsafe because improper use may lead to memory unsafety, + /// even if the returned `Rc` is never accessed. + /// + /// [into_raw]: Rc::into_raw + /// [transmute]: core::mem::transmute + /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new("hello".to_owned()); + /// let x_ptr = Rc::into_raw(x); + /// + /// unsafe { + /// // Convert back to an `Rc` to prevent leak. + /// let x = Rc::from_raw(x_ptr); + /// assert_eq!(&*x, "hello"); + /// + /// // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// ``` + /// + /// Convert a slice back into its original array: + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x: Rc<[u32]> = Rc::new([1, 2, 3]); + /// let x_ptr: *const [u32] = Rc::into_raw(x); + /// + /// unsafe { + /// let x: Rc<[u32; 3]> = Rc::from_raw(x_ptr.cast::<[u32; 3]>()); + /// assert_eq!(&*x, &[1, 2, 3]); + /// } + /// ``` + #[inline] + #[stable(feature = "rc_raw", since = "1.17.0")] + pub unsafe fn from_raw(ptr: *const T) -> Self { + unsafe { Self::from_raw_in(ptr, Global) } + } + + /// Increments the strong reference count on the `Rc` associated with the + /// provided pointer by one. + /// + /// # Safety + /// + /// The pointer must have been obtained through `Rc::into_raw`, the + /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// least 1) for the duration of this method, and `ptr` must point to a block of memory + /// allocated by the global allocator. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// unsafe { + /// let ptr = Rc::into_raw(five); + /// Rc::increment_strong_count(ptr); + /// + /// let five = Rc::from_raw(ptr); + /// assert_eq!(2, Rc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Rc::decrement_strong_count(ptr); + /// } + /// ``` + #[inline] + #[stable(feature = "rc_mutate_strong_count", since = "1.53.0")] + pub unsafe fn increment_strong_count(ptr: *const T) { + unsafe { Self::increment_strong_count_in(ptr, Global) } + } + + /// Decrements the strong reference count on the `Rc` associated with the + /// provided pointer by one. + /// + /// # Safety + /// + /// The pointer must have been obtained through `Rc::into_raw`, the + /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// least 1) when invoking this method, and `ptr` must point to a block of memory + /// allocated by the global allocator. This method can be used to release the final `Rc` and + /// backing storage, but **should not** be called after the final `Rc` has been released. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// unsafe { + /// let ptr = Rc::into_raw(five); + /// Rc::increment_strong_count(ptr); + /// + /// let five = Rc::from_raw(ptr); + /// assert_eq!(2, Rc::strong_count(&five)); + /// Rc::decrement_strong_count(ptr); + /// assert_eq!(1, Rc::strong_count(&five)); + /// } + /// ``` + #[inline] + #[stable(feature = "rc_mutate_strong_count", since = "1.53.0")] + pub unsafe fn decrement_strong_count(ptr: *const T) { + unsafe { Self::decrement_strong_count_in(ptr, Global) } + } +} + +impl Rc { + /// Returns a reference to the underlying allocator. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This + /// is so that there is no conflict with a method on the inner type. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(this: &Self) -> &A { + &this.alloc + } + + /// Consumes the `Rc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Rc` using + /// [`Rc::from_raw`]. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new("hello".to_owned()); + /// let x_ptr = Rc::into_raw(x); + /// assert_eq!(unsafe { &*x_ptr }, "hello"); + /// # // Prevent leaks for Miri. + /// # drop(unsafe { Rc::from_raw(x_ptr) }); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "rc_raw", since = "1.17.0")] + #[rustc_never_returns_null_ptr] + pub fn into_raw(this: Self) -> *const T { + let this = ManuallyDrop::new(this); + Self::as_ptr(&*this) + } + + /// Consumes the `Rc`, returning the wrapped pointer and allocator. + /// + /// To avoid a memory leak the pointer must be converted back to an `Rc` using + /// [`Rc::from_raw_in`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let x = Rc::new_in("hello".to_owned(), System); + /// let (ptr, alloc) = Rc::into_raw_with_allocator(x); + /// assert_eq!(unsafe { &*ptr }, "hello"); + /// let x = unsafe { Rc::from_raw_in(ptr, alloc) }; + /// assert_eq!(&*x, "hello"); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn into_raw_with_allocator(this: Self) -> (*const T, A) { + let this = mem::ManuallyDrop::new(this); + let ptr = Self::as_ptr(&this); + // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped + let alloc = unsafe { ptr::read(&this.alloc) }; + (ptr, alloc) + } + + /// Provides a raw pointer to the data. + /// + /// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid + /// for as long as there are strong counts in the `Rc`. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x = Rc::new(0); + /// let y = Rc::clone(&x); + /// let x_ptr = Rc::as_ptr(&x); + /// assert_eq!(x_ptr, Rc::as_ptr(&y)); + /// assert_eq!(unsafe { *x_ptr }, 0); + /// ``` + #[stable(feature = "weak_into_raw", since = "1.45.0")] + #[rustc_never_returns_null_ptr] + pub fn as_ptr(this: &Self) -> *const T { + let ptr: *mut RcInner = NonNull::as_ptr(this.ptr); + + // SAFETY: This cannot go through Deref::deref or Rc::inner because + // this is required to retain raw/mut provenance such that e.g. `get_mut` can + // write through the pointer after the Rc is recovered through `from_raw`. + unsafe { &raw mut (*ptr).value } + } + + /// Constructs an `Rc` from a raw pointer in the provided allocator. + /// + /// The raw pointer must have been previously returned by a call to [`Rc::into_raw`][into_raw] with the following requirements: + /// + /// * If `U` is sized, it must have the same size and alignment as `T`. This + /// is trivially true if `U` is `T`. + /// * If `U` is unsized, its data pointer must have the same size and + /// alignment as `T`. This is trivially true if `Rc` was constructed + /// through `Rc` and then converted to `Rc` through an [unsized + /// coercion]. + /// + /// Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// + /// The raw pointer must point to a block of memory allocated by `alloc` + /// + /// The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. + /// + /// This function is unsafe because improper use may lead to memory unsafety, + /// even if the returned `Rc` is never accessed. + /// + /// [into_raw]: Rc::into_raw + /// [transmute]: core::mem::transmute + /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let x = Rc::new_in("hello".to_owned(), System); + /// let x_ptr = Rc::into_raw(x); + /// + /// unsafe { + /// // Convert back to an `Rc` to prevent leak. + /// let x = Rc::from_raw_in(x_ptr, System); + /// assert_eq!(&*x, "hello"); + /// + /// // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// ``` + /// + /// Convert a slice back into its original array: + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let x: Rc<[u32], _> = Rc::new_in([1, 2, 3], System); + /// let x_ptr: *const [u32] = Rc::into_raw(x); + /// + /// unsafe { + /// let x: Rc<[u32; 3], _> = Rc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); + /// assert_eq!(&*x, &[1, 2, 3]); + /// } + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { + let offset = unsafe { data_offset(ptr) }; + + // Reverse the offset to find the original RcInner. + let rc_ptr = unsafe { ptr.byte_sub(offset) as *mut RcInner }; + + unsafe { Self::from_ptr_in(rc_ptr, alloc) } + } + + /// Creates a new [`Weak`] pointer to this allocation. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let weak_five = Rc::downgrade(&five); + /// ``` + #[must_use = "this returns a new `Weak` pointer, \ + without modifying the original `Rc`"] + #[stable(feature = "rc_weak", since = "1.4.0")] + pub fn downgrade(this: &Self) -> Weak + where + A: Clone, + { + this.inner().inc_weak(); + // Make sure we do not create a dangling Weak + debug_assert!(!is_dangling(this.ptr.as_ptr())); + Weak { ptr: this.ptr, alloc: this.alloc.clone() } + } + + /// Gets the number of [`Weak`] pointers to this allocation. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// let _weak_five = Rc::downgrade(&five); + /// + /// assert_eq!(1, Rc::weak_count(&five)); + /// ``` + #[inline] + #[stable(feature = "rc_counts", since = "1.15.0")] + pub fn weak_count(this: &Self) -> usize { + this.inner().weak() - 1 + } + + /// Gets the number of strong (`Rc`) pointers to this allocation. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// let _also_five = Rc::clone(&five); + /// + /// assert_eq!(2, Rc::strong_count(&five)); + /// ``` + #[inline] + #[stable(feature = "rc_counts", since = "1.15.0")] + pub fn strong_count(this: &Self) -> usize { + this.inner().strong() + } + + /// Increments the strong reference count on the `Rc` associated with the + /// provided pointer by one. + /// + /// # Safety + /// + /// The pointer must have been obtained through `Rc::into_raw`, the + /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// least 1) for the duration of this method, and `ptr` must point to a block of memory + /// allocated by `alloc` + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let five = Rc::new_in(5, System); + /// + /// unsafe { + /// let ptr = Rc::into_raw(five); + /// Rc::increment_strong_count_in(ptr, System); + /// + /// let five = Rc::from_raw_in(ptr, System); + /// assert_eq!(2, Rc::strong_count(&five)); + /// # // Prevent leaks for Miri. + /// # Rc::decrement_strong_count_in(ptr, System); + /// } + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub unsafe fn increment_strong_count_in(ptr: *const T, alloc: A) + where + A: Clone, + { + // Retain Rc, but don't touch refcount by wrapping in ManuallyDrop + let rc = unsafe { mem::ManuallyDrop::new(Rc::::from_raw_in(ptr, alloc)) }; + // Now increase refcount, but don't drop new refcount either + let _rc_clone: mem::ManuallyDrop<_> = rc.clone(); + } + + /// Decrements the strong reference count on the `Rc` associated with the + /// provided pointer by one. + /// + /// # Safety + /// + /// The pointer must have been obtained through `Rc::into_raw`, the + /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// least 1) when invoking this method, and `ptr` must point to a block of memory + /// allocated by `alloc`. This method can be used to release the final `Rc` and backing storage, + /// but **should not** be called after the final `Rc` has been released. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// let five = Rc::new_in(5, System); + /// + /// unsafe { + /// let ptr = Rc::into_raw(five); + /// Rc::increment_strong_count_in(ptr, System); + /// + /// let five = Rc::from_raw_in(ptr, System); + /// assert_eq!(2, Rc::strong_count(&five)); + /// Rc::decrement_strong_count_in(ptr, System); + /// assert_eq!(1, Rc::strong_count(&five)); + /// } + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub unsafe fn decrement_strong_count_in(ptr: *const T, alloc: A) { + unsafe { drop(Rc::from_raw_in(ptr, alloc)) }; + } + + /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to + /// this allocation. + #[inline] + fn is_unique(this: &Self) -> bool { + Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 + } + + /// Returns a mutable reference into the given `Rc`, if there are + /// no other `Rc` or [`Weak`] pointers to the same allocation. + /// + /// Returns [`None`] otherwise, because it is not safe to + /// mutate a shared value. + /// + /// See also [`make_mut`][make_mut], which will [`clone`][clone] + /// the inner value when there are other `Rc` pointers. + /// + /// [make_mut]: Rc::make_mut + /// [clone]: Clone::clone + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let mut x = Rc::new(3); + /// *Rc::get_mut(&mut x).unwrap() = 4; + /// assert_eq!(*x, 4); + /// + /// let _y = Rc::clone(&x); + /// assert!(Rc::get_mut(&mut x).is_none()); + /// ``` + #[inline] + #[stable(feature = "rc_unique", since = "1.4.0")] + pub fn get_mut(this: &mut Self) -> Option<&mut T> { + if Rc::is_unique(this) { unsafe { Some(Rc::get_mut_unchecked(this)) } } else { None } + } + + /// Returns a mutable reference into the given `Rc`, + /// without any check. + /// + /// See also [`get_mut`], which is safe and does appropriate checks. + /// + /// [`get_mut`]: Rc::get_mut + /// + /// # Safety + /// + /// If any other `Rc` or [`Weak`] pointers to the same allocation exist, then + /// they must not be dereferenced or have active borrows for the duration + /// of the returned borrow, and their inner type must be exactly the same as the + /// inner type of this Rc (including lifetimes). This is trivially the case if no + /// such pointers exist, for example immediately after `Rc::new`. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut x = Rc::new(String::new()); + /// unsafe { + /// Rc::get_mut_unchecked(&mut x).push_str("foo") + /// } + /// assert_eq!(*x, "foo"); + /// ``` + /// Other `Rc` pointers to the same allocation must be to the same type. + /// ```no_run + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let x: Rc = Rc::from("Hello, world!"); + /// let mut y: Rc<[u8]> = x.clone().into(); + /// unsafe { + /// // this is Undefined Behavior, because x's inner type is str, not [u8] + /// Rc::get_mut_unchecked(&mut y).fill(0xff); // 0xff is invalid in UTF-8 + /// } + /// println!("{}", &*x); // Invalid UTF-8 in a str + /// ``` + /// Other `Rc` pointers to the same allocation must be to the exact same type, including lifetimes. + /// ```no_run + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let x: Rc<&str> = Rc::new("Hello, world!"); + /// { + /// let s = String::from("Oh, no!"); + /// let mut y: Rc<&str> = x.clone(); + /// unsafe { + /// // this is Undefined Behavior, because x's inner type + /// // is &'long str, not &'short str + /// *Rc::get_mut_unchecked(&mut y) = &s; + /// } + /// } + /// println!("{}", &*x); // Use-after-free + /// ``` + #[inline] + #[unstable(feature = "get_mut_unchecked", issue = "63292")] + pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { + // We are careful to *not* create a reference covering the "count" fields, as + // this would conflict with accesses to the reference counts (e.g. by `Weak`). + unsafe { &mut (*this.ptr.as_ptr()).value } + } + + #[inline] + #[stable(feature = "ptr_eq", since = "1.17.0")] + /// Returns `true` if the two `Rc`s point to the same allocation in a vein similar to + /// [`ptr::eq`]. This function ignores the metadata of `dyn Trait` pointers. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// let same_five = Rc::clone(&five); + /// let other_five = Rc::new(5); + /// + /// assert!(Rc::ptr_eq(&five, &same_five)); + /// assert!(!Rc::ptr_eq(&five, &other_five)); + /// ``` + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + ptr::addr_eq(this.ptr.as_ptr(), other.ptr.as_ptr()) + } +} + +#[cfg(not(no_global_oom_handling))] +impl Rc { + /// Makes a mutable reference into the given `Rc`. + /// + /// If there are other `Rc` pointers to the same allocation, then `make_mut` will + /// [`clone`] the inner value to a new allocation to ensure unique ownership. This is also + /// referred to as clone-on-write. + /// + /// However, if there are no other `Rc` pointers to this allocation, but some [`Weak`] + /// pointers, then the [`Weak`] pointers will be disassociated and the inner value will not + /// be cloned. + /// + /// See also [`get_mut`], which will fail rather than cloning the inner value + /// or disassociating [`Weak`] pointers. + /// + /// [`clone`]: Clone::clone + /// [`get_mut`]: Rc::get_mut + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let mut data = Rc::new(5); + /// + /// *Rc::make_mut(&mut data) += 1; // Won't clone anything + /// let mut other_data = Rc::clone(&data); // Won't clone inner data + /// *Rc::make_mut(&mut data) += 1; // Clones inner data + /// *Rc::make_mut(&mut data) += 1; // Won't clone anything + /// *Rc::make_mut(&mut other_data) *= 2; // Won't clone anything + /// + /// // Now `data` and `other_data` point to different allocations. + /// assert_eq!(*data, 8); + /// assert_eq!(*other_data, 12); + /// ``` + /// + /// [`Weak`] pointers will be disassociated: + /// + /// ``` + /// use std::rc::Rc; + /// + /// let mut data = Rc::new(75); + /// let weak = Rc::downgrade(&data); + /// + /// assert!(75 == *data); + /// assert!(75 == *weak.upgrade().unwrap()); + /// + /// *Rc::make_mut(&mut data) += 1; + /// + /// assert!(76 == *data); + /// assert!(weak.upgrade().is_none()); + /// ``` + #[inline] + #[stable(feature = "rc_unique", since = "1.4.0")] + pub fn make_mut(this: &mut Self) -> &mut T { + let size_of_val = size_of_val::(&**this); + + if Rc::strong_count(this) != 1 { + // Gotta clone the data, there are other Rcs. + + let this_data_ref: &T = &**this; + // `in_progress` drops the allocation if we panic before finishing initializing it. + let mut in_progress: UniqueRcUninit = + UniqueRcUninit::new(this_data_ref, this.alloc.clone()); + + // Initialize with clone of this. + let initialized_clone = unsafe { + // Clone. If the clone panics, `in_progress` will be dropped and clean up. + this_data_ref.clone_to_uninit(in_progress.data_ptr().cast()); + // Cast type of pointer, now that it is initialized. + in_progress.into_rc() + }; + + // Replace `this` with newly constructed Rc. + *this = initialized_clone; + } else if Rc::weak_count(this) != 0 { + // Can just steal the data, all that's left is Weaks + + // We don't need panic-protection like the above branch does, but we might as well + // use the same mechanism. + let mut in_progress: UniqueRcUninit = + UniqueRcUninit::new(&**this, this.alloc.clone()); + unsafe { + // Initialize `in_progress` with move of **this. + // We have to express this in terms of bytes because `T: ?Sized`; there is no + // operation that just copies a value based on its `size_of_val()`. + ptr::copy_nonoverlapping( + ptr::from_ref(&**this).cast::(), + in_progress.data_ptr().cast::(), + size_of_val, + ); + + this.inner().dec_strong(); + // Remove implicit strong-weak ref (no need to craft a fake + // Weak here -- we know other Weaks can clean up for us) + this.inner().dec_weak(); + // Replace `this` with newly constructed Rc that has the moved data. + ptr::write(this, in_progress.into_rc()); + } + } + // This unsafety is ok because we're guaranteed that the pointer + // returned is the *only* pointer that will ever be returned to T. Our + // reference count is guaranteed to be 1 at this point, and we required + // the `Rc` itself to be `mut`, so we're returning the only possible + // reference to the allocation. + unsafe { &mut this.ptr.as_mut().value } + } +} + +impl Rc { + /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the + /// clone. + /// + /// Assuming `rc_t` is of type `Rc`, this function is functionally equivalent to + /// `(*rc_t).clone()`, but will avoid cloning the inner value where possible. + /// + /// # Examples + /// + /// ``` + /// # use std::{ptr, rc::Rc}; + /// let inner = String::from("test"); + /// let ptr = inner.as_ptr(); + /// + /// let rc = Rc::new(inner); + /// let inner = Rc::unwrap_or_clone(rc); + /// // The inner value was not cloned + /// assert!(ptr::eq(ptr, inner.as_ptr())); + /// + /// let rc = Rc::new(inner); + /// let rc2 = rc.clone(); + /// let inner = Rc::unwrap_or_clone(rc); + /// // Because there were 2 references, we had to clone the inner value. + /// assert!(!ptr::eq(ptr, inner.as_ptr())); + /// // `rc2` is the last reference, so when we unwrap it we get back + /// // the original `String`. + /// let inner = Rc::unwrap_or_clone(rc2); + /// assert!(ptr::eq(ptr, inner.as_ptr())); + /// ``` + #[inline] + #[stable(feature = "arc_unwrap_or_clone", since = "1.76.0")] + pub fn unwrap_or_clone(this: Self) -> T { + Rc::try_unwrap(this).unwrap_or_else(|rc| (*rc).clone()) + } +} + +impl Rc { + /// Attempts to downcast the `Rc` to a concrete type. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// use std::rc::Rc; + /// + /// fn print_if_string(value: Rc) { + /// if let Ok(string) = value.downcast::() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// let my_string = "Hello World".to_string(); + /// print_if_string(Rc::new(my_string)); + /// print_if_string(Rc::new(0i8)); + /// ``` + #[inline] + #[stable(feature = "rc_downcast", since = "1.29.0")] + pub fn downcast(self) -> Result, Self> { + if (*self).is::() { + unsafe { + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + Ok(Rc::from_inner_in(ptr.cast(), alloc)) + } + } else { + Err(self) + } + } + + /// Downcasts the `Rc` to a concrete type. + /// + /// For a safe alternative see [`downcast`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// use std::rc::Rc; + /// + /// let x: Rc = Rc::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + /// + /// + /// [`downcast`]: Self::downcast + #[inline] + #[unstable(feature = "downcast_unchecked", issue = "90850")] + pub unsafe fn downcast_unchecked(self) -> Rc { + unsafe { + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + Rc::from_inner_in(ptr.cast(), alloc) + } + } +} + +impl Rc { + /// Allocates an `RcInner` with sufficient space for + /// a possibly-unsized inner value where the value has the layout provided. + /// + /// The function `mem_to_rc_inner` is called with the data pointer + /// and must return back a (potentially fat)-pointer for the `RcInner`. + #[cfg(not(no_global_oom_handling))] + unsafe fn allocate_for_layout( + value_layout: Layout, + allocate: impl FnOnce(Layout) -> Result, AllocError>, + mem_to_rc_inner: impl FnOnce(*mut u8) -> *mut RcInner, + ) -> *mut RcInner { + let layout = rc_inner_layout_for_value_layout(value_layout); + unsafe { + Rc::try_allocate_for_layout(value_layout, allocate, mem_to_rc_inner) + .unwrap_or_else(|_| handle_alloc_error(layout)) + } + } + + /// Allocates an `RcInner` with sufficient space for + /// a possibly-unsized inner value where the value has the layout provided, + /// returning an error if allocation fails. + /// + /// The function `mem_to_rc_inner` is called with the data pointer + /// and must return back a (potentially fat)-pointer for the `RcInner`. + #[inline] + unsafe fn try_allocate_for_layout( + value_layout: Layout, + allocate: impl FnOnce(Layout) -> Result, AllocError>, + mem_to_rc_inner: impl FnOnce(*mut u8) -> *mut RcInner, + ) -> Result<*mut RcInner, AllocError> { + let layout = rc_inner_layout_for_value_layout(value_layout); + + // Allocate for the layout. + let ptr = allocate(layout)?; + + // Initialize the RcInner + let inner = mem_to_rc_inner(ptr.as_non_null_ptr().as_ptr()); + unsafe { + debug_assert_eq!(Layout::for_value_raw(inner), layout); + + (&raw mut (*inner).strong).write(Cell::new(1)); + (&raw mut (*inner).weak).write(Cell::new(1)); + } + + Ok(inner) + } +} + +impl Rc { + /// Allocates an `RcInner` with sufficient space for an unsized inner value + #[cfg(not(no_global_oom_handling))] + unsafe fn allocate_for_ptr_in(ptr: *const T, alloc: &A) -> *mut RcInner { + // Allocate for the `RcInner` using the given value. + unsafe { + Rc::::allocate_for_layout( + Layout::for_value_raw(ptr), + |layout| alloc.allocate(layout), + |mem| mem.with_metadata_of(ptr as *const RcInner), + ) + } + } + + #[cfg(not(no_global_oom_handling))] + fn from_box_in(src: Box) -> Rc { + unsafe { + let value_size = size_of_val(&*src); + let ptr = Self::allocate_for_ptr_in(&*src, Box::allocator(&src)); + + // Copy value as bytes + ptr::copy_nonoverlapping( + (&raw const *src) as *const u8, + (&raw mut (*ptr).value) as *mut u8, + value_size, + ); + + // Free the allocation without dropping its contents + let (bptr, alloc) = Box::into_raw_with_allocator(src); + let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, alloc.by_ref()); + drop(src); + + Self::from_ptr_in(ptr, alloc) + } + } +} + +impl Rc<[T]> { + /// Allocates an `RcInner<[T]>` with the given length. + #[cfg(not(no_global_oom_handling))] + unsafe fn allocate_for_slice(len: usize) -> *mut RcInner<[T]> { + unsafe { + Self::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| Global.allocate(layout), + |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, + ) + } + } + + /// Copy elements from slice into newly allocated `Rc<[T]>` + /// + /// Unsafe because the caller must either take ownership or bind `T: Copy` + #[cfg(not(no_global_oom_handling))] + unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { + unsafe { + let ptr = Self::allocate_for_slice(v.len()); + ptr::copy_nonoverlapping(v.as_ptr(), (&raw mut (*ptr).value) as *mut T, v.len()); + Self::from_ptr(ptr) + } + } + + /// Constructs an `Rc<[T]>` from an iterator known to be of a certain size. + /// + /// Behavior is undefined should the size be wrong. + #[cfg(not(no_global_oom_handling))] + unsafe fn from_iter_exact(iter: impl Iterator, len: usize) -> Rc<[T]> { + // Panic guard while cloning T elements. + // In the event of a panic, elements that have been written + // into the new RcInner will be dropped, then the memory freed. + struct Guard { + mem: NonNull, + elems: *mut T, + layout: Layout, + n_elems: usize, + } + + impl Drop for Guard { + fn drop(&mut self) { + unsafe { + let slice = from_raw_parts_mut(self.elems, self.n_elems); + ptr::drop_in_place(slice); + + Global.deallocate(self.mem, self.layout); + } + } + } + + unsafe { + let ptr = Self::allocate_for_slice(len); + + let mem = ptr as *mut _ as *mut u8; + let layout = Layout::for_value_raw(ptr); + + // Pointer to first element + let elems = (&raw mut (*ptr).value) as *mut T; + + let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; + + for (i, item) in iter.enumerate() { + ptr::write(elems.add(i), item); + guard.n_elems += 1; + } + + // All clear. Forget the guard so it doesn't free the new RcInner. + mem::forget(guard); + + Self::from_ptr(ptr) + } + } +} + +impl Rc<[T], A> { + /// Allocates an `RcInner<[T]>` with the given length. + #[inline] + #[cfg(not(no_global_oom_handling))] + unsafe fn allocate_for_slice_in(len: usize, alloc: &A) -> *mut RcInner<[T]> { + unsafe { + Rc::<[T]>::allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| alloc.allocate(layout), + |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, + ) + } + } +} + +#[cfg(not(no_global_oom_handling))] +/// Specialization trait used for `From<&[T]>`. +trait RcFromSlice { + fn from_slice(slice: &[T]) -> Self; +} + +#[cfg(not(no_global_oom_handling))] +impl RcFromSlice for Rc<[T]> { + #[inline] + default fn from_slice(v: &[T]) -> Self { + unsafe { Self::from_iter_exact(v.iter().cloned(), v.len()) } + } +} + +#[cfg(not(no_global_oom_handling))] +impl RcFromSlice for Rc<[T]> { + #[inline] + fn from_slice(v: &[T]) -> Self { + unsafe { Rc::copy_from_slice(v) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Deref for Rc { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + &self.inner().value + } +} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for Rc {} + +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for UniqueRc {} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for Weak {} + +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for Rc {} + +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for UniqueRc {} + +#[unstable(feature = "legacy_receiver_trait", issue = "none")] +impl LegacyReceiver for Rc {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc { + /// Drops the `Rc`. + /// + /// This will decrement the strong reference count. If the strong reference + /// count reaches zero then the only other references (if any) are + /// [`Weak`], so we `drop` the inner value. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// struct Foo; + /// + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } + /// } + /// + /// let foo = Rc::new(Foo); + /// let foo2 = Rc::clone(&foo); + /// + /// drop(foo); // Doesn't print anything + /// drop(foo2); // Prints "dropped!" + /// ``` + #[inline] + fn drop(&mut self) { + unsafe { + self.inner().dec_strong(); + if self.inner().strong() == 0 { + self.drop_slow(); + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Rc { + /// Makes a clone of the `Rc` pointer. + /// + /// This creates another pointer to the same allocation, increasing the + /// strong reference count. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let _ = Rc::clone(&five); + /// ``` + #[inline] + fn clone(&self) -> Self { + unsafe { + self.inner().inc_strong(); + Self::from_inner_in(self.ptr, self.alloc.clone()) + } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Default for Rc { + /// Creates a new `Rc`, with the `Default` value for `T`. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let x: Rc = Default::default(); + /// assert_eq!(*x, 0); + /// ``` + #[inline] + fn default() -> Rc { + unsafe { + Self::from_inner( + Box::leak(Box::write( + Box::new_uninit(), + RcInner { strong: Cell::new(1), weak: Cell::new(1), value: T::default() }, + )) + .into(), + ) + } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "more_rc_default_impls", since = "1.80.0")] +impl Default for Rc { + /// Creates an empty str inside an Rc + /// + /// This may or may not share an allocation with other Rcs on the same thread. + #[inline] + fn default() -> Self { + let rc = Rc::<[u8]>::default(); + // `[u8]` has the same layout as `str`. + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const str) } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "more_rc_default_impls", since = "1.80.0")] +impl Default for Rc<[T]> { + /// Creates an empty `[T]` inside an Rc + /// + /// This may or may not share an allocation with other Rcs on the same thread. + #[inline] + fn default() -> Self { + let arr: [T; 0] = []; + Rc::from(arr) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +trait RcEqIdent { + fn eq(&self, other: &Rc) -> bool; + fn ne(&self, other: &Rc) -> bool; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl RcEqIdent for Rc { + #[inline] + default fn eq(&self, other: &Rc) -> bool { + **self == **other + } + + #[inline] + default fn ne(&self, other: &Rc) -> bool { + **self != **other + } +} + +// Hack to allow specializing on `Eq` even though `Eq` has a method. +#[rustc_unsafe_specialization_marker] +pub(crate) trait MarkerEq: PartialEq {} + +impl MarkerEq for T {} + +/// We're doing this specialization here, and not as a more general optimization on `&T`, because it +/// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to +/// store large values, that are slow to clone, but also heavy to check for equality, causing this +/// cost to pay off more easily. It's also more likely to have two `Rc` clones, that point to +/// the same value, than two `&T`s. +/// +/// We can only do this when `T: Eq` as a `PartialEq` might be deliberately irreflexive. +#[stable(feature = "rust1", since = "1.0.0")] +impl RcEqIdent for Rc { + #[inline] + fn eq(&self, other: &Rc) -> bool { + Rc::ptr_eq(self, other) || **self == **other + } + + #[inline] + fn ne(&self, other: &Rc) -> bool { + !Rc::ptr_eq(self, other) && **self != **other + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for Rc { + /// Equality for two `Rc`s. + /// + /// Two `Rc`s are equal if their inner values are equal, even if they are + /// stored in different allocation. + /// + /// If `T` also implements `Eq` (implying reflexivity of equality), + /// two `Rc`s that point to the same allocation are + /// always equal. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five == Rc::new(5)); + /// ``` + #[inline] + fn eq(&self, other: &Rc) -> bool { + RcEqIdent::eq(self, other) + } + + /// Inequality for two `Rc`s. + /// + /// Two `Rc`s are not equal if their inner values are not equal. + /// + /// If `T` also implements `Eq` (implying reflexivity of equality), + /// two `Rc`s that point to the same allocation are + /// always equal. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five != Rc::new(6)); + /// ``` + #[inline] + fn ne(&self, other: &Rc) -> bool { + RcEqIdent::ne(self, other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for Rc {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for Rc { + /// Partial comparison for two `Rc`s. + /// + /// The two are compared by calling `partial_cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// use std::cmp::Ordering; + /// + /// let five = Rc::new(5); + /// + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Rc::new(6))); + /// ``` + #[inline(always)] + fn partial_cmp(&self, other: &Rc) -> Option { + (**self).partial_cmp(&**other) + } + + /// Less-than comparison for two `Rc`s. + /// + /// The two are compared by calling `<` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five < Rc::new(6)); + /// ``` + #[inline(always)] + fn lt(&self, other: &Rc) -> bool { + **self < **other + } + + /// 'Less than or equal to' comparison for two `Rc`s. + /// + /// The two are compared by calling `<=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five <= Rc::new(5)); + /// ``` + #[inline(always)] + fn le(&self, other: &Rc) -> bool { + **self <= **other + } + + /// Greater-than comparison for two `Rc`s. + /// + /// The two are compared by calling `>` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five > Rc::new(4)); + /// ``` + #[inline(always)] + fn gt(&self, other: &Rc) -> bool { + **self > **other + } + + /// 'Greater than or equal to' comparison for two `Rc`s. + /// + /// The two are compared by calling `>=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// assert!(five >= Rc::new(5)); + /// ``` + #[inline(always)] + fn ge(&self, other: &Rc) -> bool { + **self >= **other + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for Rc { + /// Comparison for two `Rc`s. + /// + /// The two are compared by calling `cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// use std::cmp::Ordering; + /// + /// let five = Rc::new(5); + /// + /// assert_eq!(Ordering::Less, five.cmp(&Rc::new(6))); + /// ``` + #[inline] + fn cmp(&self, other: &Rc) -> Ordering { + (**self).cmp(&**other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for Rc { + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Rc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Rc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Rc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&(&raw const **self), f) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "from_for_ptrs", since = "1.6.0")] +impl From for Rc { + /// Converts a generic type `T` into an `Rc` + /// + /// The conversion allocates on the heap and moves `t` + /// from the stack into it. + /// + /// # Example + /// ```rust + /// # use std::rc::Rc; + /// let x = 5; + /// let rc = Rc::new(5); + /// + /// assert_eq!(Rc::from(x), rc); + /// ``` + fn from(t: T) -> Self { + Rc::new(t) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_array", since = "1.74.0")] +impl From<[T; N]> for Rc<[T]> { + /// Converts a [`[T; N]`](prim@array) into an `Rc<[T]>`. + /// + /// The conversion moves the array into a newly allocated `Rc`. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let original: [i32; 3] = [1, 2, 3]; + /// let shared: Rc<[i32]> = Rc::from(original); + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// ``` + #[inline] + fn from(v: [T; N]) -> Rc<[T]> { + Rc::<[T; N]>::from(v) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From<&[T]> for Rc<[T]> { + /// Allocates a reference-counted slice and fills it by cloning `v`'s items. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let original: &[i32] = &[1, 2, 3]; + /// let shared: Rc<[i32]> = Rc::from(original); + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// ``` + #[inline] + fn from(v: &[T]) -> Rc<[T]> { + >::from_slice(v) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] +impl From<&mut [T]> for Rc<[T]> { + /// Allocates a reference-counted slice and fills it by cloning `v`'s items. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let mut original = [1, 2, 3]; + /// let original: &mut [i32] = &mut original; + /// let shared: Rc<[i32]> = Rc::from(original); + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// ``` + #[inline] + fn from(v: &mut [T]) -> Rc<[T]> { + Rc::from(&*v) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From<&str> for Rc { + /// Allocates a reference-counted string slice and copies `v` into it. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let shared: Rc = Rc::from("statue"); + /// assert_eq!("statue", &shared[..]); + /// ``` + #[inline] + fn from(v: &str) -> Rc { + let rc = Rc::<[u8]>::from(v.as_bytes()); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const str) } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] +impl From<&mut str> for Rc { + /// Allocates a reference-counted string slice and copies `v` into it. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let mut original = String::from("statue"); + /// let original: &mut str = &mut original; + /// let shared: Rc = Rc::from(original); + /// assert_eq!("statue", &shared[..]); + /// ``` + #[inline] + fn from(v: &mut str) -> Rc { + Rc::from(&*v) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From for Rc { + /// Allocates a reference-counted string slice and copies `v` into it. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let original: String = "statue".to_owned(); + /// let shared: Rc = Rc::from(original); + /// assert_eq!("statue", &shared[..]); + /// ``` + #[inline] + fn from(v: String) -> Rc { + Rc::from(&v[..]) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From> for Rc { + /// Move a boxed object to a new, reference counted, allocation. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let original: Box = Box::new(1); + /// let shared: Rc = Rc::from(original); + /// assert_eq!(1, *shared); + /// ``` + #[inline] + fn from(v: Box) -> Rc { + Rc::from_box_in(v) + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From> for Rc<[T], A> { + /// Allocates a reference-counted slice and moves `v`'s items into it. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let unique: Vec = vec![1, 2, 3]; + /// let shared: Rc<[i32]> = Rc::from(unique); + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// ``` + #[inline] + fn from(v: Vec) -> Rc<[T], A> { + unsafe { + let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); + + let rc_ptr = Self::allocate_for_slice_in(len, &alloc); + ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).value) as *mut T, len); + + // Create a `Vec` with length 0, to deallocate the buffer + // without dropping its contents or the allocator + let _ = Vec::from_raw_parts_in(vec_ptr, 0, cap, &alloc); + + Self::from_ptr_in(rc_ptr, alloc) + } + } +} + +#[stable(feature = "shared_from_cow", since = "1.45.0")] +impl<'a, B> From> for Rc +where + B: ToOwned + ?Sized, + Rc: From<&'a B> + From, +{ + /// Creates a reference-counted pointer from a clone-on-write pointer by + /// copying its content. + /// + /// # Example + /// + /// ```rust + /// # use std::rc::Rc; + /// # use std::borrow::Cow; + /// let cow: Cow<'_, str> = Cow::Borrowed("eggplant"); + /// let shared: Rc = Rc::from(cow); + /// assert_eq!("eggplant", &shared[..]); + /// ``` + #[inline] + fn from(cow: Cow<'a, B>) -> Rc { + match cow { + Cow::Borrowed(s) => Rc::from(s), + Cow::Owned(s) => Rc::from(s), + } + } +} + +#[stable(feature = "shared_from_str", since = "1.62.0")] +impl From> for Rc<[u8]> { + /// Converts a reference-counted string slice into a byte slice. + /// + /// # Example + /// + /// ``` + /// # use std::rc::Rc; + /// let string: Rc = Rc::from("eggplant"); + /// let bytes: Rc<[u8]> = Rc::from(string); + /// assert_eq!("eggplant".as_bytes(), bytes.as_ref()); + /// ``` + #[inline] + fn from(rc: Rc) -> Self { + // SAFETY: `str` has the same layout as `[u8]`. + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const [u8]) } + } +} + +#[stable(feature = "boxed_slice_try_from", since = "1.43.0")] +impl TryFrom> for Rc<[T; N], A> { + type Error = Rc<[T], A>; + + fn try_from(boxed_slice: Rc<[T], A>) -> Result { + if boxed_slice.len() == N { + let (ptr, alloc) = Rc::into_inner_with_allocator(boxed_slice); + Ok(unsafe { Rc::from_inner_in(ptr.cast(), alloc) }) + } else { + Err(boxed_slice) + } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "shared_from_iter", since = "1.37.0")] +impl FromIterator for Rc<[T]> { + /// Takes each element in the `Iterator` and collects it into an `Rc<[T]>`. + /// + /// # Performance characteristics + /// + /// ## The general case + /// + /// In the general case, collecting into `Rc<[T]>` is done by first + /// collecting into a `Vec`. That is, when writing the following: + /// + /// ```rust + /// # use std::rc::Rc; + /// let evens: Rc<[u8]> = (0..10).filter(|&x| x % 2 == 0).collect(); + /// # assert_eq!(&*evens, &[0, 2, 4, 6, 8]); + /// ``` + /// + /// this behaves as if we wrote: + /// + /// ```rust + /// # use std::rc::Rc; + /// let evens: Rc<[u8]> = (0..10).filter(|&x| x % 2 == 0) + /// .collect::>() // The first set of allocations happens here. + /// .into(); // A second allocation for `Rc<[T]>` happens here. + /// # assert_eq!(&*evens, &[0, 2, 4, 6, 8]); + /// ``` + /// + /// This will allocate as many times as needed for constructing the `Vec` + /// and then it will allocate once for turning the `Vec` into the `Rc<[T]>`. + /// + /// ## Iterators of known length + /// + /// When your `Iterator` implements `TrustedLen` and is of an exact size, + /// a single allocation will be made for the `Rc<[T]>`. For example: + /// + /// ```rust + /// # use std::rc::Rc; + /// let evens: Rc<[u8]> = (0..10).collect(); // Just a single allocation happens here. + /// # assert_eq!(&*evens, &*(0..10).collect::>()); + /// ``` + fn from_iter>(iter: I) -> Self { + ToRcSlice::to_rc_slice(iter.into_iter()) + } +} + +/// Specialization trait used for collecting into `Rc<[T]>`. +#[cfg(not(no_global_oom_handling))] +trait ToRcSlice: Iterator + Sized { + fn to_rc_slice(self) -> Rc<[T]>; +} + +#[cfg(not(no_global_oom_handling))] +impl> ToRcSlice for I { + default fn to_rc_slice(self) -> Rc<[T]> { + self.collect::>().into() + } +} + +#[cfg(not(no_global_oom_handling))] +impl> ToRcSlice for I { + fn to_rc_slice(self) -> Rc<[T]> { + // This is the case for a `TrustedLen` iterator. + let (low, high) = self.size_hint(); + if let Some(high) = high { + debug_assert_eq!( + low, + high, + "TrustedLen iterator's size hint is not exact: {:?}", + (low, high) + ); + + unsafe { + // SAFETY: We need to ensure that the iterator has an exact length and we have. + Rc::from_iter_exact(self, low) + } + } else { + // TrustedLen contract guarantees that `upper_bound == None` implies an iterator + // length exceeding `usize::MAX`. + // The default implementation would collect into a vec which would panic. + // Thus we panic here immediately without invoking `Vec` code. + panic!("capacity overflow"); + } + } +} + +/// `Weak` is a version of [`Rc`] that holds a non-owning reference to the +/// managed allocation. +/// +/// The allocation is accessed by calling [`upgrade`] on the `Weak` +/// pointer, which returns an [Option]<[Rc]\>. +/// +/// Since a `Weak` reference does not count towards ownership, it will not +/// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no +/// guarantees about the value still being present. Thus it may return [`None`] +/// when [`upgrade`]d. Note however that a `Weak` reference *does* prevent the allocation +/// itself (the backing store) from being deallocated. +/// +/// A `Weak` pointer is useful for keeping a temporary reference to the allocation +/// managed by [`Rc`] without preventing its inner value from being dropped. It is also used to +/// prevent circular references between [`Rc`] pointers, since mutual owning references +/// would never allow either [`Rc`] to be dropped. For example, a tree could +/// have strong [`Rc`] pointers from parent nodes to children, and `Weak` +/// pointers from children back to their parents. +/// +/// The typical way to obtain a `Weak` pointer is to call [`Rc::downgrade`]. +/// +/// [`upgrade`]: Weak::upgrade +#[stable(feature = "rc_weak", since = "1.4.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "RcWeak")] +pub struct Weak< + T: ?Sized, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + // This is a `NonNull` to allow optimizing the size of this type in enums, + // but it is not necessarily a valid pointer. + // `Weak::new` sets this to `usize::MAX` so that it doesn’t need + // to allocate space on the heap. That's not a value a real pointer + // will ever have because RcInner has alignment at least 2. + // This is only possible when `T: Sized`; unsized `T` never dangle. + ptr: NonNull>, + alloc: A, +} + +#[stable(feature = "rc_weak", since = "1.4.0")] +impl !Send for Weak {} +#[stable(feature = "rc_weak", since = "1.4.0")] +impl !Sync for Weak {} + +#[unstable(feature = "coerce_unsized", issue = "18598")] +impl, U: ?Sized, A: Allocator> CoerceUnsized> for Weak {} + +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +impl, U: ?Sized> DispatchFromDyn> for Weak {} + +impl Weak { + /// Constructs a new `Weak`, without allocating any memory. + /// Calling [`upgrade`] on the return value always gives [`None`]. + /// + /// [`upgrade`]: Weak::upgrade + /// + /// # Examples + /// + /// ``` + /// use std::rc::Weak; + /// + /// let empty: Weak = Weak::new(); + /// assert!(empty.upgrade().is_none()); + /// ``` + #[inline] + #[stable(feature = "downgraded_weak", since = "1.10.0")] + #[rustc_const_stable(feature = "const_weak_new", since = "1.73.0")] + #[must_use] + pub const fn new() -> Weak { + Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc: Global } + } +} + +impl Weak { + /// Constructs a new `Weak`, without allocating any memory, technically in the provided + /// allocator. + /// Calling [`upgrade`] on the return value always gives [`None`]. + /// + /// [`upgrade`]: Weak::upgrade + /// + /// # Examples + /// + /// ``` + /// use std::rc::Weak; + /// + /// let empty: Weak = Weak::new(); + /// assert!(empty.upgrade().is_none()); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_in(alloc: A) -> Weak { + Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc } + } +} + +pub(crate) fn is_dangling(ptr: *const T) -> bool { + (ptr.cast::<()>()).addr() == usize::MAX +} + +/// Helper type to allow accessing the reference counts without +/// making any assertions about the data field. +struct WeakInner<'a> { + weak: &'a Cell, + strong: &'a Cell, +} + +impl Weak { + /// Converts a raw pointer previously created by [`into_raw`] back into `Weak`. + /// + /// This can be used to safely get a strong reference (by calling [`upgrade`] + /// later) or to deallocate the weak count by dropping the `Weak`. + /// + /// It takes ownership of one weak reference (with the exception of pointers created by [`new`], + /// as these don't own anything; the method still works on them). + /// + /// # Safety + /// + /// The pointer must have originated from the [`into_raw`] and must still own its potential + /// weak reference, and `ptr` must point to a block of memory allocated by the global allocator. + /// + /// It is allowed for the strong count to be 0 at the time of calling this. Nevertheless, this + /// takes ownership of one weak reference currently represented as a raw pointer (the weak + /// count is not modified by this operation) and therefore it must be paired with a previous + /// call to [`into_raw`]. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let strong = Rc::new("hello".to_owned()); + /// + /// let raw_1 = Rc::downgrade(&strong).into_raw(); + /// let raw_2 = Rc::downgrade(&strong).into_raw(); + /// + /// assert_eq!(2, Rc::weak_count(&strong)); + /// + /// assert_eq!("hello", &*unsafe { Weak::from_raw(raw_1) }.upgrade().unwrap()); + /// assert_eq!(1, Rc::weak_count(&strong)); + /// + /// drop(strong); + /// + /// // Decrement the last weak count. + /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none()); + /// ``` + /// + /// [`into_raw`]: Weak::into_raw + /// [`upgrade`]: Weak::upgrade + /// [`new`]: Weak::new + #[inline] + #[stable(feature = "weak_into_raw", since = "1.45.0")] + pub unsafe fn from_raw(ptr: *const T) -> Self { + unsafe { Self::from_raw_in(ptr, Global) } + } +} + +impl Weak { + /// Returns a reference to the underlying allocator. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn allocator(&self) -> &A { + &self.alloc + } + + /// Returns a raw pointer to the object `T` pointed to by this `Weak`. + /// + /// The pointer is valid only if there are some strong references. The pointer may be dangling, + /// unaligned or even [`null`] otherwise. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// use std::ptr; + /// + /// let strong = Rc::new("hello".to_owned()); + /// let weak = Rc::downgrade(&strong); + /// // Both point to the same object + /// assert!(ptr::eq(&*strong, weak.as_ptr())); + /// // The strong here keeps it alive, so we can still access the object. + /// assert_eq!("hello", unsafe { &*weak.as_ptr() }); + /// + /// drop(strong); + /// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to + /// // undefined behavior. + /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); + /// ``` + /// + /// [`null`]: ptr::null + #[must_use] + #[stable(feature = "rc_as_ptr", since = "1.45.0")] + pub fn as_ptr(&self) -> *const T { + let ptr: *mut RcInner = NonNull::as_ptr(self.ptr); + + if is_dangling(ptr) { + // If the pointer is dangling, we return the sentinel directly. This cannot be + // a valid payload address, as the payload is at least as aligned as RcInner (usize). + ptr as *const T + } else { + // SAFETY: if is_dangling returns false, then the pointer is dereferenceable. + // The payload may be dropped at this point, and we have to maintain provenance, + // so use raw pointer manipulation. + unsafe { &raw mut (*ptr).value } + } + } + + /// Consumes the `Weak` and turns it into a raw pointer. + /// + /// This converts the weak pointer into a raw pointer, while still preserving the ownership of + /// one weak reference (the weak count is not modified by this operation). It can be turned + /// back into the `Weak` with [`from_raw`]. + /// + /// The same restrictions of accessing the target of the pointer as with + /// [`as_ptr`] apply. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let strong = Rc::new("hello".to_owned()); + /// let weak = Rc::downgrade(&strong); + /// let raw = weak.into_raw(); + /// + /// assert_eq!(1, Rc::weak_count(&strong)); + /// assert_eq!("hello", unsafe { &*raw }); + /// + /// drop(unsafe { Weak::from_raw(raw) }); + /// assert_eq!(0, Rc::weak_count(&strong)); + /// ``` + /// + /// [`from_raw`]: Weak::from_raw + /// [`as_ptr`]: Weak::as_ptr + #[must_use = "losing the pointer will leak memory"] + #[stable(feature = "weak_into_raw", since = "1.45.0")] + pub fn into_raw(self) -> *const T { + mem::ManuallyDrop::new(self).as_ptr() + } + + /// Consumes the `Weak`, returning the wrapped pointer and allocator. + /// + /// This converts the weak pointer into a raw pointer, while still preserving the ownership of + /// one weak reference (the weak count is not modified by this operation). It can be turned + /// back into the `Weak` with [`from_raw_in`]. + /// + /// The same restrictions of accessing the target of the pointer as with + /// [`as_ptr`] apply. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// use std::rc::{Rc, Weak}; + /// use std::alloc::System; + /// + /// let strong = Rc::new_in("hello".to_owned(), System); + /// let weak = Rc::downgrade(&strong); + /// let (raw, alloc) = weak.into_raw_with_allocator(); + /// + /// assert_eq!(1, Rc::weak_count(&strong)); + /// assert_eq!("hello", unsafe { &*raw }); + /// + /// drop(unsafe { Weak::from_raw_in(raw, alloc) }); + /// assert_eq!(0, Rc::weak_count(&strong)); + /// ``` + /// + /// [`from_raw_in`]: Weak::from_raw_in + /// [`as_ptr`]: Weak::as_ptr + #[must_use = "losing the pointer will leak memory"] + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn into_raw_with_allocator(self) -> (*const T, A) { + let this = mem::ManuallyDrop::new(self); + let result = this.as_ptr(); + // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped + let alloc = unsafe { ptr::read(&this.alloc) }; + (result, alloc) + } + + /// Converts a raw pointer previously created by [`into_raw`] back into `Weak`. + /// + /// This can be used to safely get a strong reference (by calling [`upgrade`] + /// later) or to deallocate the weak count by dropping the `Weak`. + /// + /// It takes ownership of one weak reference (with the exception of pointers created by [`new`], + /// as these don't own anything; the method still works on them). + /// + /// # Safety + /// + /// The pointer must have originated from the [`into_raw`] and must still own its potential + /// weak reference, and `ptr` must point to a block of memory allocated by `alloc`. + /// + /// It is allowed for the strong count to be 0 at the time of calling this. Nevertheless, this + /// takes ownership of one weak reference currently represented as a raw pointer (the weak + /// count is not modified by this operation) and therefore it must be paired with a previous + /// call to [`into_raw`]. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let strong = Rc::new("hello".to_owned()); + /// + /// let raw_1 = Rc::downgrade(&strong).into_raw(); + /// let raw_2 = Rc::downgrade(&strong).into_raw(); + /// + /// assert_eq!(2, Rc::weak_count(&strong)); + /// + /// assert_eq!("hello", &*unsafe { Weak::from_raw(raw_1) }.upgrade().unwrap()); + /// assert_eq!(1, Rc::weak_count(&strong)); + /// + /// drop(strong); + /// + /// // Decrement the last weak count. + /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none()); + /// ``` + /// + /// [`into_raw`]: Weak::into_raw + /// [`upgrade`]: Weak::upgrade + /// [`new`]: Weak::new + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { + // See Weak::as_ptr for context on how the input pointer is derived. + + let ptr = if is_dangling(ptr) { + // This is a dangling Weak. + ptr as *mut RcInner + } else { + // Otherwise, we're guaranteed the pointer came from a nondangling Weak. + // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. + let offset = unsafe { data_offset(ptr) }; + // Thus, we reverse the offset to get the whole RcInner. + // SAFETY: the pointer originated from a Weak, so this offset is safe. + unsafe { ptr.byte_sub(offset) as *mut RcInner } + }; + + // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. + Weak { ptr: unsafe { NonNull::new_unchecked(ptr) }, alloc } + } + + /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying + /// dropping of the inner value if successful. + /// + /// Returns [`None`] if the inner value has since been dropped. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let weak_five = Rc::downgrade(&five); + /// + /// let strong_five: Option> = weak_five.upgrade(); + /// assert!(strong_five.is_some()); + /// + /// // Destroy all strong pointers. + /// drop(strong_five); + /// drop(five); + /// + /// assert!(weak_five.upgrade().is_none()); + /// ``` + #[must_use = "this returns a new `Rc`, \ + without modifying the original weak pointer"] + #[stable(feature = "rc_weak", since = "1.4.0")] + pub fn upgrade(&self) -> Option> + where + A: Clone, + { + let inner = self.inner()?; + + if inner.strong() == 0 { + None + } else { + unsafe { + inner.inc_strong(); + Some(Rc::from_inner_in(self.ptr, self.alloc.clone())) + } + } + } + + /// Gets the number of strong (`Rc`) pointers pointing to this allocation. + /// + /// If `self` was created using [`Weak::new`], this will return 0. + #[must_use] + #[stable(feature = "weak_counts", since = "1.41.0")] + pub fn strong_count(&self) -> usize { + if let Some(inner) = self.inner() { inner.strong() } else { 0 } + } + + /// Gets the number of `Weak` pointers pointing to this allocation. + /// + /// If no strong pointers remain, this will return zero. + #[must_use] + #[stable(feature = "weak_counts", since = "1.41.0")] + pub fn weak_count(&self) -> usize { + if let Some(inner) = self.inner() { + if inner.strong() > 0 { + inner.weak() - 1 // subtract the implicit weak ptr + } else { + 0 + } + } else { + 0 + } + } + + /// Returns `None` when the pointer is dangling and there is no allocated `RcInner`, + /// (i.e., when this `Weak` was created by `Weak::new`). + #[inline] + fn inner(&self) -> Option> { + if is_dangling(self.ptr.as_ptr()) { + None + } else { + // We are careful to *not* create a reference covering the "data" field, as + // the field may be mutated concurrently (for example, if the last `Rc` + // is dropped, the data field will be dropped in-place). + Some(unsafe { + let ptr = self.ptr.as_ptr(); + WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } + }) + } + } + + /// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if + /// both don't point to any allocation (because they were created with `Weak::new()`). However, + /// this function ignores the metadata of `dyn Trait` pointers. + /// + /// # Notes + /// + /// Since this compares pointers it means that `Weak::new()` will equal each + /// other, even though they don't point to any allocation. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Rc; + /// + /// let first_rc = Rc::new(5); + /// let first = Rc::downgrade(&first_rc); + /// let second = Rc::downgrade(&first_rc); + /// + /// assert!(first.ptr_eq(&second)); + /// + /// let third_rc = Rc::new(5); + /// let third = Rc::downgrade(&third_rc); + /// + /// assert!(!first.ptr_eq(&third)); + /// ``` + /// + /// Comparing `Weak::new`. + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let first = Weak::new(); + /// let second = Weak::new(); + /// assert!(first.ptr_eq(&second)); + /// + /// let third_rc = Rc::new(()); + /// let third = Rc::downgrade(&third_rc); + /// assert!(!first.ptr_eq(&third)); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "weak_ptr_eq", since = "1.39.0")] + pub fn ptr_eq(&self, other: &Self) -> bool { + ptr::addr_eq(self.ptr.as_ptr(), other.ptr.as_ptr()) + } +} + +#[stable(feature = "rc_weak", since = "1.4.0")] +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Weak { + /// Drops the `Weak` pointer. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// struct Foo; + /// + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } + /// } + /// + /// let foo = Rc::new(Foo); + /// let weak_foo = Rc::downgrade(&foo); + /// let other_weak_foo = Weak::clone(&weak_foo); + /// + /// drop(weak_foo); // Doesn't print anything + /// drop(foo); // Prints "dropped!" + /// + /// assert!(other_weak_foo.upgrade().is_none()); + /// ``` + fn drop(&mut self) { + let inner = if let Some(inner) = self.inner() { inner } else { return }; + + inner.dec_weak(); + // the weak count starts at 1, and will only go to zero if all + // the strong pointers have disappeared. + if inner.weak() == 0 { + unsafe { + self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); + } + } + } +} + +#[stable(feature = "rc_weak", since = "1.4.0")] +impl Clone for Weak { + /// Makes a clone of the `Weak` pointer that points to the same allocation. + /// + /// # Examples + /// + /// ``` + /// use std::rc::{Rc, Weak}; + /// + /// let weak_five = Rc::downgrade(&Rc::new(5)); + /// + /// let _ = Weak::clone(&weak_five); + /// ``` + #[inline] + fn clone(&self) -> Weak { + if let Some(inner) = self.inner() { + inner.inc_weak() + } + Weak { ptr: self.ptr, alloc: self.alloc.clone() } + } +} + +#[stable(feature = "rc_weak", since = "1.4.0")] +impl fmt::Debug for Weak { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(Weak)") + } +} + +#[stable(feature = "downgraded_weak", since = "1.10.0")] +impl Default for Weak { + /// Constructs a new `Weak`, without allocating any memory. + /// Calling [`upgrade`] on the return value always gives [`None`]. + /// + /// [`upgrade`]: Weak::upgrade + /// + /// # Examples + /// + /// ``` + /// use std::rc::Weak; + /// + /// let empty: Weak = Default::default(); + /// assert!(empty.upgrade().is_none()); + /// ``` + fn default() -> Weak { + Weak::new() + } +} + +// NOTE: We checked_add here to deal with mem::forget safely. In particular +// if you mem::forget Rcs (or Weaks), the ref-count can overflow, and then +// you can free the allocation while outstanding Rcs (or Weaks) exist. +// We abort because this is such a degenerate scenario that we don't care about +// what happens -- no real program should ever experience this. +// +// This should have negligible overhead since you don't actually need to +// clone these much in Rust thanks to ownership and move-semantics. + +#[doc(hidden)] +trait RcInnerPtr { + fn weak_ref(&self) -> &Cell; + fn strong_ref(&self) -> &Cell; + + #[inline] + fn strong(&self) -> usize { + self.strong_ref().get() + } + + #[inline] + fn inc_strong(&self) { + let strong = self.strong(); + + // We insert an `assume` here to hint LLVM at an otherwise + // missed optimization. + // SAFETY: The reference count will never be zero when this is + // called. + unsafe { + hint::assert_unchecked(strong != 0); + } + + let strong = strong.wrapping_add(1); + self.strong_ref().set(strong); + + // We want to abort on overflow instead of dropping the value. + // Checking for overflow after the store instead of before + // allows for slightly better code generation. + if core::intrinsics::unlikely(strong == 0) { + abort(); + } + } + + #[inline] + fn dec_strong(&self) { + self.strong_ref().set(self.strong() - 1); + } + + #[inline] + fn weak(&self) -> usize { + self.weak_ref().get() + } + + #[inline] + fn inc_weak(&self) { + let weak = self.weak(); + + // We insert an `assume` here to hint LLVM at an otherwise + // missed optimization. + // SAFETY: The reference count will never be zero when this is + // called. + unsafe { + hint::assert_unchecked(weak != 0); + } + + let weak = weak.wrapping_add(1); + self.weak_ref().set(weak); + + // We want to abort on overflow instead of dropping the value. + // Checking for overflow after the store instead of before + // allows for slightly better code generation. + if core::intrinsics::unlikely(weak == 0) { + abort(); + } + } + + #[inline] + fn dec_weak(&self) { + self.weak_ref().set(self.weak() - 1); + } +} + +impl RcInnerPtr for RcInner { + #[inline(always)] + fn weak_ref(&self) -> &Cell { + &self.weak + } + + #[inline(always)] + fn strong_ref(&self) -> &Cell { + &self.strong + } +} + +impl<'a> RcInnerPtr for WeakInner<'a> { + #[inline(always)] + fn weak_ref(&self) -> &Cell { + self.weak + } + + #[inline(always)] + fn strong_ref(&self) -> &Cell { + self.strong + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl borrow::Borrow for Rc { + fn borrow(&self) -> &T { + &**self + } +} + +#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] +impl AsRef for Rc { + fn as_ref(&self) -> &T { + &**self + } +} + +#[stable(feature = "pin", since = "1.33.0")] +impl Unpin for Rc {} + +/// Gets the offset within an `RcInner` for the payload behind a pointer. +/// +/// # Safety +/// +/// The pointer must point to (and have valid metadata for) a previously +/// valid instance of T, but the T is allowed to be dropped. +unsafe fn data_offset(ptr: *const T) -> usize { + // Align the unsized value to the end of the RcInner. + // Because RcInner is repr(C), it will always be the last field in memory. + // SAFETY: since the only unsized types possible are slices, trait objects, + // and extern types, the input safety requirement is currently enough to + // satisfy the requirements of align_of_val_raw; this is an implementation + // detail of the language that must not be relied upon outside of std. + unsafe { data_offset_align(align_of_val_raw(ptr)) } +} + +#[inline] +fn data_offset_align(align: usize) -> usize { + let layout = Layout::new::>(); + layout.size() + layout.padding_needed_for(align) +} + +/// A uniquely owned [`Rc`]. +/// +/// This represents an `Rc` that is known to be uniquely owned -- that is, have exactly one strong +/// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong +/// references will fail unless the `UniqueRc` they point to has been converted into a regular `Rc`. +/// +/// Because they are uniquely owned, the contents of a `UniqueRc` can be freely mutated. A common +/// use case is to have an object be mutable during its initialization phase but then have it become +/// immutable and converted to a normal `Rc`. +/// +/// This can be used as a flexible way to create cyclic data structures, as in the example below. +/// +/// ``` +/// #![feature(unique_rc_arc)] +/// use std::rc::{Rc, Weak, UniqueRc}; +/// +/// struct Gadget { +/// #[allow(dead_code)] +/// me: Weak, +/// } +/// +/// fn create_gadget() -> Option> { +/// let mut rc = UniqueRc::new(Gadget { +/// me: Weak::new(), +/// }); +/// rc.me = UniqueRc::downgrade(&rc); +/// Some(UniqueRc::into_rc(rc)) +/// } +/// +/// create_gadget().unwrap(); +/// ``` +/// +/// An advantage of using `UniqueRc` over [`Rc::new_cyclic`] to build cyclic data structures is that +/// [`Rc::new_cyclic`]'s `data_fn` parameter cannot be async or return a [`Result`]. As shown in the +/// previous example, `UniqueRc` allows for more flexibility in the construction of cyclic data, +/// including fallible or async constructors. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +pub struct UniqueRc< + T: ?Sized, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + ptr: NonNull>, + // Define the ownership of `RcInner` for drop-check + _marker: PhantomData>, + // Invariance is necessary for soundness: once other `Weak` + // references exist, we already have a form of shared mutability! + _marker2: PhantomData<*mut T>, + alloc: A, +} + +// Not necessary for correctness since `UniqueRc` contains `NonNull`, +// but having an explicit negative impl is nice for documentation purposes +// and results in nicer error messages. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl !Send for UniqueRc {} + +// Not necessary for correctness since `UniqueRc` contains `NonNull`, +// but having an explicit negative impl is nice for documentation purposes +// and results in nicer error messages. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl !Sync for UniqueRc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl, U: ?Sized, A: Allocator> CoerceUnsized> + for UniqueRc +{ +} + +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +impl, U: ?Sized> DispatchFromDyn> for UniqueRc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Display for UniqueRc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Debug for UniqueRc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl fmt::Pointer for UniqueRc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&(&raw const **self), f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl borrow::Borrow for UniqueRc { + fn borrow(&self) -> &T { + &**self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl borrow::BorrowMut for UniqueRc { + fn borrow_mut(&mut self) -> &mut T { + &mut **self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsRef for UniqueRc { + fn as_ref(&self) -> &T { + &**self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl AsMut for UniqueRc { + fn as_mut(&mut self) -> &mut T { + &mut **self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Unpin for UniqueRc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl PartialEq for UniqueRc { + /// Equality for two `UniqueRc`s. + /// + /// Two `UniqueRc`s are equal if their inner values are equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five == UniqueRc::new(5)); + /// ``` + #[inline] + fn eq(&self, other: &Self) -> bool { + PartialEq::eq(&**self, &**other) + } + + /// Inequality for two `UniqueRc`s. + /// + /// Two `UniqueRc`s are not equal if their inner values are not equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five != UniqueRc::new(6)); + /// ``` + #[inline] + fn ne(&self, other: &Self) -> bool { + PartialEq::ne(&**self, &**other) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl PartialOrd for UniqueRc { + /// Partial comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `partial_cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// use std::cmp::Ordering; + /// + /// let five = UniqueRc::new(5); + /// + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&UniqueRc::new(6))); + /// ``` + #[inline(always)] + fn partial_cmp(&self, other: &UniqueRc) -> Option { + (**self).partial_cmp(&**other) + } + + /// Less-than comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `<` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five < UniqueRc::new(6)); + /// ``` + #[inline(always)] + fn lt(&self, other: &UniqueRc) -> bool { + **self < **other + } + + /// 'Less than or equal to' comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `<=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five <= UniqueRc::new(5)); + /// ``` + #[inline(always)] + fn le(&self, other: &UniqueRc) -> bool { + **self <= **other + } + + /// Greater-than comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `>` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five > UniqueRc::new(4)); + /// ``` + #[inline(always)] + fn gt(&self, other: &UniqueRc) -> bool { + **self > **other + } + + /// 'Greater than or equal to' comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `>=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five >= UniqueRc::new(5)); + /// ``` + #[inline(always)] + fn ge(&self, other: &UniqueRc) -> bool { + **self >= **other + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Ord for UniqueRc { + /// Comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// use std::cmp::Ordering; + /// + /// let five = UniqueRc::new(5); + /// + /// assert_eq!(Ordering::Less, five.cmp(&UniqueRc::new(6))); + /// ``` + #[inline] + fn cmp(&self, other: &UniqueRc) -> Ordering { + (**self).cmp(&**other) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Eq for UniqueRc {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Hash for UniqueRc { + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} + +// Depends on A = Global +impl UniqueRc { + /// Creates a new `UniqueRc`. + /// + /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. + /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will + /// point to the new [`Rc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new(value: T) -> Self { + Self::new_in(value, Global) + } +} + +impl UniqueRc { + /// Creates a new `UniqueRc` in the provided allocator. + /// + /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. + /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will + /// point to the new [`Rc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new_in(value: T, alloc: A) -> Self { + let (ptr, alloc) = Box::into_unique(Box::new_in( + RcInner { + strong: Cell::new(0), + // keep one weak reference so if all the weak pointers that are created are dropped + // the UniqueRc still stays valid. + weak: Cell::new(1), + value, + }, + alloc, + )); + Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc } + } +} + +impl UniqueRc { + /// Converts the `UniqueRc` into a regular [`Rc`]. + /// + /// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that + /// is passed to `into_rc`. + /// + /// Any weak references created before this method is called can now be upgraded to strong + /// references. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn into_rc(this: Self) -> Rc { + let mut this = ManuallyDrop::new(this); + + // Move the allocator out. + // SAFETY: `this.alloc` will not be accessed again, nor dropped because it is in + // a `ManuallyDrop`. + let alloc: A = unsafe { ptr::read(&this.alloc) }; + + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { + // Convert our weak reference into a strong reference + this.ptr.as_mut().strong.set(1); + Rc::from_inner_in(this.ptr, alloc) + } + } +} + +impl UniqueRc { + /// Creates a new weak reference to the `UniqueRc`. + /// + /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted + /// to a [`Rc`] using [`UniqueRc::into_rc`]. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn downgrade(this: &Self) -> Weak { + // SAFETY: This pointer was allocated at creation time and we guarantee that we only have + // one strong reference before converting to a regular Rc. + unsafe { + this.ptr.as_ref().inc_weak(); + } + Weak { ptr: this.ptr, alloc: this.alloc.clone() } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Deref for UniqueRc { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { &self.ptr.as_ref().value } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl DerefMut for UniqueRc { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. We know we + // have unique ownership and therefore it's safe to make a mutable reference because + // `UniqueRc` owns the only strong reference to itself. + unsafe { &mut (*self.ptr.as_ptr()).value } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc { + fn drop(&mut self) { + unsafe { + // destroy the contained object + drop_in_place(DerefMut::deref_mut(self)); + + // remove the implicit "strong weak" pointer now that we've destroyed the contents. + self.ptr.as_ref().dec_weak(); + + if self.ptr.as_ref().weak() == 0 { + self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); + } + } + } +} + +/// A unique owning pointer to a [`RcInner`] **that does not imply the contents are initialized,** +/// but will deallocate it (without dropping the value) when dropped. +/// +/// This is a helper for [`Rc::make_mut()`] to ensure correct cleanup on panic. +/// It is nearly a duplicate of `UniqueRc, A>` except that it allows `T: !Sized`, +/// which `MaybeUninit` does not. +#[cfg(not(no_global_oom_handling))] +struct UniqueRcUninit { + ptr: NonNull>, + layout_for_value: Layout, + alloc: Option, +} + +#[cfg(not(no_global_oom_handling))] +impl UniqueRcUninit { + /// Allocates a RcInner with layout suitable to contain `for_value` or a clone of it. + fn new(for_value: &T, alloc: A) -> UniqueRcUninit { + let layout = Layout::for_value(for_value); + let ptr = unsafe { + Rc::allocate_for_layout( + layout, + |layout_for_rc_inner| alloc.allocate(layout_for_rc_inner), + |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcInner), + ) + }; + Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) } + } + + /// Returns the pointer to be written into to initialize the [`Rc`]. + fn data_ptr(&mut self) -> *mut T { + let offset = data_offset_align(self.layout_for_value.align()); + unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } + } + + /// Upgrade this into a normal [`Rc`]. + /// + /// # Safety + /// + /// The data must have been initialized (by writing to [`Self::data_ptr()`]). + unsafe fn into_rc(self) -> Rc { + let mut this = ManuallyDrop::new(self); + let ptr = this.ptr; + let alloc = this.alloc.take().unwrap(); + + // SAFETY: The pointer is valid as per `UniqueRcUninit::new`, and the caller is responsible + // for having initialized the data. + unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) } + } +} + +#[cfg(not(no_global_oom_handling))] +impl Drop for UniqueRcUninit { + fn drop(&mut self) { + // SAFETY: + // * new() produced a pointer safe to deallocate. + // * We own the pointer unless into_rc() was called, which forgets us. + unsafe { + self.alloc.take().unwrap().deallocate( + self.ptr.cast(), + rc_inner_layout_for_value_layout(self.layout_for_value), + ); + } + } +} diff --git a/library/alloc/src/rc/mod.rs b/library/alloc/src/rc/mod.rs deleted file mode 100644 index 09206c2f8b2..00000000000 --- a/library/alloc/src/rc/mod.rs +++ /dev/null @@ -1,4148 +0,0 @@ -//! Single-threaded reference-counting pointers. 'Rc' stands for 'Reference -//! Counted'. -//! -//! The type [`Rc`][`Rc`] provides shared ownership of a value of type `T`, -//! allocated in the heap. Invoking [`clone`][clone] on [`Rc`] produces a new -//! pointer to the same allocation in the heap. When the last [`Rc`] pointer to a -//! given allocation is destroyed, the value stored in that allocation (often -//! referred to as "inner value") is also dropped. -//! -//! Shared references in Rust disallow mutation by default, and [`Rc`] -//! is no exception: you cannot generally obtain a mutable reference to -//! something inside an [`Rc`]. If you need mutability, put a [`Cell`] -//! or [`RefCell`] inside the [`Rc`]; see [an example of mutability -//! inside an `Rc`][mutability]. -//! -//! [`Rc`] uses non-atomic reference counting. This means that overhead is very -//! low, but an [`Rc`] cannot be sent between threads, and consequently [`Rc`] -//! does not implement [`Send`]. As a result, the Rust compiler -//! will check *at compile time* that you are not sending [`Rc`]s between -//! threads. If you need multi-threaded, atomic reference counting, use -//! [`sync::Arc`][arc]. -//! -//! The [`downgrade`][downgrade] method can be used to create a non-owning -//! [`Weak`] pointer. A [`Weak`] pointer can be [`upgrade`][upgrade]d -//! to an [`Rc`], but this will return [`None`] if the value stored in the allocation has -//! already been dropped. In other words, `Weak` pointers do not keep the value -//! inside the allocation alive; however, they *do* keep the allocation -//! (the backing store for the inner value) alive. -//! -//! A cycle between [`Rc`] pointers will never be deallocated. For this reason, -//! [`Weak`] is used to break cycles. For example, a tree could have strong -//! [`Rc`] pointers from parent nodes to children, and [`Weak`] pointers from -//! children back to their parents. -//! -//! `Rc` automatically dereferences to `T` (via the [`Deref`] trait), -//! so you can call `T`'s methods on a value of type [`Rc`][`Rc`]. To avoid name -//! clashes with `T`'s methods, the methods of [`Rc`][`Rc`] itself are associated -//! functions, called using [fully qualified syntax]: -//! -//! ``` -//! use std::rc::Rc; -//! -//! let my_rc = Rc::new(()); -//! let my_weak = Rc::downgrade(&my_rc); -//! ``` -//! -//! `Rc`'s implementations of traits like `Clone` may also be called using -//! fully qualified syntax. Some people prefer to use fully qualified syntax, -//! while others prefer using method-call syntax. -//! -//! ``` -//! use std::rc::Rc; -//! -//! let rc = Rc::new(()); -//! // Method-call syntax -//! let rc2 = rc.clone(); -//! // Fully qualified syntax -//! let rc3 = Rc::clone(&rc); -//! ``` -//! -//! [`Weak`][`Weak`] does not auto-dereference to `T`, because the inner value may have -//! already been dropped. -//! -//! # Cloning references -//! -//! Creating a new reference to the same allocation as an existing reference counted pointer -//! is done using the `Clone` trait implemented for [`Rc`][`Rc`] and [`Weak`][`Weak`]. -//! -//! ``` -//! use std::rc::Rc; -//! -//! let foo = Rc::new(vec![1.0, 2.0, 3.0]); -//! // The two syntaxes below are equivalent. -//! let a = foo.clone(); -//! let b = Rc::clone(&foo); -//! // a and b both point to the same memory location as foo. -//! ``` -//! -//! The `Rc::clone(&from)` syntax is the most idiomatic because it conveys more explicitly -//! the meaning of the code. In the example above, this syntax makes it easier to see that -//! this code is creating a new reference rather than copying the whole content of foo. -//! -//! # Examples -//! -//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. -//! We want to have our `Gadget`s point to their `Owner`. We can't do this with -//! unique ownership, because more than one gadget may belong to the same -//! `Owner`. [`Rc`] allows us to share an `Owner` between multiple `Gadget`s, -//! and have the `Owner` remain allocated as long as any `Gadget` points at it. -//! -//! ``` -//! use std::rc::Rc; -//! -//! struct Owner { -//! name: String, -//! // ...other fields -//! } -//! -//! struct Gadget { -//! id: i32, -//! owner: Rc, -//! // ...other fields -//! } -//! -//! fn main() { -//! // Create a reference-counted `Owner`. -//! let gadget_owner: Rc = Rc::new( -//! Owner { -//! name: "Gadget Man".to_string(), -//! } -//! ); -//! -//! // Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc` -//! // gives us a new pointer to the same `Owner` allocation, incrementing -//! // the reference count in the process. -//! let gadget1 = Gadget { -//! id: 1, -//! owner: Rc::clone(&gadget_owner), -//! }; -//! let gadget2 = Gadget { -//! id: 2, -//! owner: Rc::clone(&gadget_owner), -//! }; -//! -//! // Dispose of our local variable `gadget_owner`. -//! drop(gadget_owner); -//! -//! // Despite dropping `gadget_owner`, we're still able to print out the name -//! // of the `Owner` of the `Gadget`s. This is because we've only dropped a -//! // single `Rc`, not the `Owner` it points to. As long as there are -//! // other `Rc` pointing at the same `Owner` allocation, it will remain -//! // live. The field projection `gadget1.owner.name` works because -//! // `Rc` automatically dereferences to `Owner`. -//! println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name); -//! println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name); -//! -//! // At the end of the function, `gadget1` and `gadget2` are destroyed, and -//! // with them the last counted references to our `Owner`. Gadget Man now -//! // gets destroyed as well. -//! } -//! ``` -//! -//! If our requirements change, and we also need to be able to traverse from -//! `Owner` to `Gadget`, we will run into problems. An [`Rc`] pointer from `Owner` -//! to `Gadget` introduces a cycle. This means that their -//! reference counts can never reach 0, and the allocation will never be destroyed: -//! a memory leak. In order to get around this, we can use [`Weak`] -//! pointers. -//! -//! Rust actually makes it somewhat difficult to produce this loop in the first -//! place. In order to end up with two values that point at each other, one of -//! them needs to be mutable. This is difficult because [`Rc`] enforces -//! memory safety by only giving out shared references to the value it wraps, -//! and these don't allow direct mutation. We need to wrap the part of the -//! value we wish to mutate in a [`RefCell`], which provides *interior -//! mutability*: a method to achieve mutability through a shared reference. -//! [`RefCell`] enforces Rust's borrowing rules at runtime. -//! -//! ``` -//! use std::rc::Rc; -//! use std::rc::Weak; -//! use std::cell::RefCell; -//! -//! struct Owner { -//! name: String, -//! gadgets: RefCell>>, -//! // ...other fields -//! } -//! -//! struct Gadget { -//! id: i32, -//! owner: Rc, -//! // ...other fields -//! } -//! -//! fn main() { -//! // Create a reference-counted `Owner`. Note that we've put the `Owner`'s -//! // vector of `Gadget`s inside a `RefCell` so that we can mutate it through -//! // a shared reference. -//! let gadget_owner: Rc = Rc::new( -//! Owner { -//! name: "Gadget Man".to_string(), -//! gadgets: RefCell::new(vec![]), -//! } -//! ); -//! -//! // Create `Gadget`s belonging to `gadget_owner`, as before. -//! let gadget1 = Rc::new( -//! Gadget { -//! id: 1, -//! owner: Rc::clone(&gadget_owner), -//! } -//! ); -//! let gadget2 = Rc::new( -//! Gadget { -//! id: 2, -//! owner: Rc::clone(&gadget_owner), -//! } -//! ); -//! -//! // Add the `Gadget`s to their `Owner`. -//! { -//! let mut gadgets = gadget_owner.gadgets.borrow_mut(); -//! gadgets.push(Rc::downgrade(&gadget1)); -//! gadgets.push(Rc::downgrade(&gadget2)); -//! -//! // `RefCell` dynamic borrow ends here. -//! } -//! -//! // Iterate over our `Gadget`s, printing their details out. -//! for gadget_weak in gadget_owner.gadgets.borrow().iter() { -//! -//! // `gadget_weak` is a `Weak`. Since `Weak` pointers can't -//! // guarantee the allocation still exists, we need to call -//! // `upgrade`, which returns an `Option>`. -//! // -//! // In this case we know the allocation still exists, so we simply -//! // `unwrap` the `Option`. In a more complicated program, you might -//! // need graceful error handling for a `None` result. -//! -//! let gadget = gadget_weak.upgrade().unwrap(); -//! println!("Gadget {} owned by {}", gadget.id, gadget.owner.name); -//! } -//! -//! // At the end of the function, `gadget_owner`, `gadget1`, and `gadget2` -//! // are destroyed. There are now no strong (`Rc`) pointers to the -//! // gadgets, so they are destroyed. This zeroes the reference count on -//! // Gadget Man, so he gets destroyed as well. -//! } -//! ``` -//! -//! [clone]: Clone::clone -//! [`Cell`]: core::cell::Cell -//! [`RefCell`]: core::cell::RefCell -//! [arc]: crate::sync::Arc -//! [`Deref`]: core::ops::Deref -//! [downgrade]: Rc::downgrade -//! [upgrade]: Weak::upgrade -//! [mutability]: core::cell#introducing-mutability-inside-of-something-immutable -//! [fully qualified syntax]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name - -#![stable(feature = "rust1", since = "1.0.0")] - -use core::any::Any; -use core::cell::Cell; -#[cfg(not(no_global_oom_handling))] -use core::clone::CloneToUninit; -use core::cmp::Ordering; -use core::hash::{Hash, Hasher}; -use core::intrinsics::abort; -#[cfg(not(no_global_oom_handling))] -use core::iter; -use core::marker::{PhantomData, Unsize}; -use core::mem::{self, ManuallyDrop, align_of_val_raw}; -use core::num::NonZeroUsize; -use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; -use core::panic::{RefUnwindSafe, UnwindSafe}; -#[cfg(not(no_global_oom_handling))] -use core::pin::Pin; -use core::pin::PinCoerceUnsized; -use core::ptr::{self, NonNull, drop_in_place}; -#[cfg(not(no_global_oom_handling))] -use core::slice::from_raw_parts_mut; -use core::{borrow, fmt, hint}; -#[cfg(test)] -use std::boxed::Box; - -#[cfg(not(no_global_oom_handling))] -use crate::alloc::handle_alloc_error; -use crate::alloc::{AllocError, Allocator, Global, Layout}; -use crate::borrow::{Cow, ToOwned}; -#[cfg(not(test))] -use crate::boxed::Box; -#[cfg(not(no_global_oom_handling))] -use crate::string::String; -#[cfg(not(no_global_oom_handling))] -use crate::vec::Vec; - -#[cfg(test)] -mod tests; - -// This is repr(C) to future-proof against possible field-reordering, which -// would interfere with otherwise safe [into|from]_raw() of transmutable -// inner types. -#[repr(C)] -struct RcInner { - strong: Cell, - weak: Cell, - value: T, -} - -/// Calculate layout for `RcInner` using the inner value's layout -fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout { - // Calculate layout using the given value layout. - // Previously, layout was calculated on the expression - // `&*(ptr as *const RcInner)`, but this created a misaligned - // reference (see #54908). - Layout::new::>().extend(layout).unwrap().0.pad_to_align() -} - -/// A single-threaded reference-counting pointer. 'Rc' stands for 'Reference -/// Counted'. -/// -/// See the [module-level documentation](./index.html) for more details. -/// -/// The inherent methods of `Rc` are all associated functions, which means -/// that you have to call them as e.g., [`Rc::get_mut(&mut value)`][get_mut] instead of -/// `value.get_mut()`. This avoids conflicts with methods of the inner type `T`. -/// -/// [get_mut]: Rc::get_mut -#[doc(search_unbox)] -#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_insignificant_dtor] -pub struct Rc< - T: ?Sized, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> { - ptr: NonNull>, - phantom: PhantomData>, - alloc: A, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl !Send for Rc {} - -// Note that this negative impl isn't strictly necessary for correctness, -// as `Rc` transitively contains a `Cell`, which is itself `!Sync`. -// However, given how important `Rc`'s `!Sync`-ness is, -// having an explicit negative impl is nice for documentation purposes -// and results in nicer error messages. -#[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for Rc {} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for Rc {} -#[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")] -impl RefUnwindSafe for Rc {} - -#[unstable(feature = "coerce_unsized", issue = "18598")] -impl, U: ?Sized, A: Allocator> CoerceUnsized> for Rc {} - -#[unstable(feature = "dispatch_from_dyn", issue = "none")] -impl, U: ?Sized> DispatchFromDyn> for Rc {} - -impl Rc { - #[inline] - unsafe fn from_inner(ptr: NonNull>) -> Self { - unsafe { Self::from_inner_in(ptr, Global) } - } - - #[inline] - unsafe fn from_ptr(ptr: *mut RcInner) -> Self { - unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) } - } -} - -impl Rc { - #[inline(always)] - fn inner(&self) -> &RcInner { - // This unsafety is ok because while this Rc is alive we're guaranteed - // that the inner pointer is valid. - unsafe { self.ptr.as_ref() } - } - - #[inline] - fn into_inner_with_allocator(this: Self) -> (NonNull>, A) { - let this = mem::ManuallyDrop::new(this); - (this.ptr, unsafe { ptr::read(&this.alloc) }) - } - - #[inline] - unsafe fn from_inner_in(ptr: NonNull>, alloc: A) -> Self { - Self { ptr, phantom: PhantomData, alloc } - } - - #[inline] - unsafe fn from_ptr_in(ptr: *mut RcInner, alloc: A) -> Self { - unsafe { Self::from_inner_in(NonNull::new_unchecked(ptr), alloc) } - } - - // Non-inlined part of `drop`. - #[inline(never)] - unsafe fn drop_slow(&mut self) { - // Reconstruct the "strong weak" pointer and drop it when this - // variable goes out of scope. This ensures that the memory is - // deallocated even if the destructor of `T` panics. - let _weak = Weak { ptr: self.ptr, alloc: &self.alloc }; - - // Destroy the contained object. - // We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed. - unsafe { - ptr::drop_in_place(&mut (*self.ptr.as_ptr()).value); - } - } -} - -impl Rc { - /// Constructs a new `Rc`. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// ``` - #[cfg(not(no_global_oom_handling))] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(value: T) -> Rc { - // There is an implicit weak pointer owned by all the strong - // pointers, which ensures that the weak destructor never frees - // the allocation while the strong destructor is running, even - // if the weak pointer is stored inside the strong one. - unsafe { - Self::from_inner( - Box::leak(Box::new(RcInner { strong: Cell::new(1), weak: Cell::new(1), value })) - .into(), - ) - } - } - - /// Constructs a new `Rc` while giving you a `Weak` to the allocation, - /// to allow you to construct a `T` which holds a weak pointer to itself. - /// - /// Generally, a structure circularly referencing itself, either directly or - /// indirectly, should not hold a strong reference to itself to prevent a memory leak. - /// Using this function, you get access to the weak pointer during the - /// initialization of `T`, before the `Rc` is created, such that you can - /// clone and store it inside the `T`. - /// - /// `new_cyclic` first allocates the managed allocation for the `Rc`, - /// then calls your closure, giving it a `Weak` to this allocation, - /// and only afterwards completes the construction of the `Rc` by placing - /// the `T` returned from your closure into the allocation. - /// - /// Since the new `Rc` is not fully-constructed until `Rc::new_cyclic` - /// returns, calling [`upgrade`] on the weak reference inside your closure will - /// fail and result in a `None` value. - /// - /// # Panics - /// - /// If `data_fn` panics, the panic is propagated to the caller, and the - /// temporary [`Weak`] is dropped normally. - /// - /// # Examples - /// - /// ``` - /// # #![allow(dead_code)] - /// use std::rc::{Rc, Weak}; - /// - /// struct Gadget { - /// me: Weak, - /// } - /// - /// impl Gadget { - /// /// Constructs a reference counted Gadget. - /// fn new() -> Rc { - /// // `me` is a `Weak` pointing at the new allocation of the - /// // `Rc` we're constructing. - /// Rc::new_cyclic(|me| { - /// // Create the actual struct here. - /// Gadget { me: me.clone() } - /// }) - /// } - /// - /// /// Returns a reference counted pointer to Self. - /// fn me(&self) -> Rc { - /// self.me.upgrade().unwrap() - /// } - /// } - /// ``` - /// [`upgrade`]: Weak::upgrade - #[cfg(not(no_global_oom_handling))] - #[stable(feature = "arc_new_cyclic", since = "1.60.0")] - pub fn new_cyclic(data_fn: F) -> Rc - where - F: FnOnce(&Weak) -> T, - { - Self::new_cyclic_in(data_fn, Global) - } - - /// Constructs a new `Rc` with uninitialized contents. - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut five = Rc::::new_uninit(); - /// - /// // Deferred initialization: - /// Rc::get_mut(&mut five).unwrap().write(5); - /// - /// let five = unsafe { five.assume_init() }; - /// - /// assert_eq!(*five, 5) - /// ``` - #[cfg(not(no_global_oom_handling))] - #[stable(feature = "new_uninit", since = "1.82.0")] - #[must_use] - pub fn new_uninit() -> Rc> { - unsafe { - Rc::from_ptr(Rc::allocate_for_layout( - Layout::new::(), - |layout| Global.allocate(layout), - <*mut u8>::cast, - )) - } - } - - /// Constructs a new `Rc` with uninitialized contents, with the memory - /// being filled with `0` bytes. - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(new_zeroed_alloc)] - /// - /// use std::rc::Rc; - /// - /// let zero = Rc::::new_zeroed(); - /// let zero = unsafe { zero.assume_init() }; - /// - /// assert_eq!(*zero, 0) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "new_zeroed_alloc", issue = "129396")] - #[must_use] - pub fn new_zeroed() -> Rc> { - unsafe { - Rc::from_ptr(Rc::allocate_for_layout( - Layout::new::(), - |layout| Global.allocate_zeroed(layout), - <*mut u8>::cast, - )) - } - } - - /// Constructs a new `Rc`, returning an error if the allocation fails - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// use std::rc::Rc; - /// - /// let five = Rc::try_new(5); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn try_new(value: T) -> Result, AllocError> { - // There is an implicit weak pointer owned by all the strong - // pointers, which ensures that the weak destructor never frees - // the allocation while the strong destructor is running, even - // if the weak pointer is stored inside the strong one. - unsafe { - Ok(Self::from_inner( - Box::leak(Box::try_new(RcInner { - strong: Cell::new(1), - weak: Cell::new(1), - value, - })?) - .into(), - )) - } - } - - /// Constructs a new `Rc` with uninitialized contents, returning an error if the allocation fails - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut five = Rc::::try_new_uninit()?; - /// - /// // Deferred initialization: - /// Rc::get_mut(&mut five).unwrap().write(5); - /// - /// let five = unsafe { five.assume_init() }; - /// - /// assert_eq!(*five, 5); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - pub fn try_new_uninit() -> Result>, AllocError> { - unsafe { - Ok(Rc::from_ptr(Rc::try_allocate_for_layout( - Layout::new::(), - |layout| Global.allocate(layout), - <*mut u8>::cast, - )?)) - } - } - - /// Constructs a new `Rc` with uninitialized contents, with the memory - /// being filled with `0` bytes, returning an error if the allocation fails - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// - /// let zero = Rc::::try_new_zeroed()?; - /// let zero = unsafe { zero.assume_init() }; - /// - /// assert_eq!(*zero, 0); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[unstable(feature = "allocator_api", issue = "32838")] - //#[unstable(feature = "new_uninit", issue = "63291")] - pub fn try_new_zeroed() -> Result>, AllocError> { - unsafe { - Ok(Rc::from_ptr(Rc::try_allocate_for_layout( - Layout::new::(), - |layout| Global.allocate_zeroed(layout), - <*mut u8>::cast, - )?)) - } - } - /// Constructs a new `Pin>`. If `T` does not implement `Unpin`, then - /// `value` will be pinned in memory and unable to be moved. - #[cfg(not(no_global_oom_handling))] - #[stable(feature = "pin", since = "1.33.0")] - #[must_use] - pub fn pin(value: T) -> Pin> { - unsafe { Pin::new_unchecked(Rc::new(value)) } - } -} - -impl Rc { - /// Constructs a new `Rc` in the provided allocator. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let five = Rc::new_in(5, System); - /// ``` - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub fn new_in(value: T, alloc: A) -> Rc { - // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. - // That would make code size bigger. - match Self::try_new_in(value, alloc) { - Ok(m) => m, - Err(_) => handle_alloc_error(Layout::new::>()), - } - } - - /// Constructs a new `Rc` with uninitialized contents in the provided allocator. - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let mut five = Rc::::new_uninit_in(System); - /// - /// let five = unsafe { - /// // Deferred initialization: - /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); - /// - /// five.assume_init() - /// }; - /// - /// assert_eq!(*five, 5) - /// ``` - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn new_uninit_in(alloc: A) -> Rc, A> { - unsafe { - Rc::from_ptr_in( - Rc::allocate_for_layout( - Layout::new::(), - |layout| alloc.allocate(layout), - <*mut u8>::cast, - ), - alloc, - ) - } - } - - /// Constructs a new `Rc` with uninitialized contents, with the memory - /// being filled with `0` bytes, in the provided allocator. - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let zero = Rc::::new_zeroed_in(System); - /// let zero = unsafe { zero.assume_init() }; - /// - /// assert_eq!(*zero, 0) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn new_zeroed_in(alloc: A) -> Rc, A> { - unsafe { - Rc::from_ptr_in( - Rc::allocate_for_layout( - Layout::new::(), - |layout| alloc.allocate_zeroed(layout), - <*mut u8>::cast, - ), - alloc, - ) - } - } - - /// Constructs a new `Rc` in the given allocator while giving you a `Weak` to the allocation, - /// to allow you to construct a `T` which holds a weak pointer to itself. - /// - /// Generally, a structure circularly referencing itself, either directly or - /// indirectly, should not hold a strong reference to itself to prevent a memory leak. - /// Using this function, you get access to the weak pointer during the - /// initialization of `T`, before the `Rc` is created, such that you can - /// clone and store it inside the `T`. - /// - /// `new_cyclic_in` first allocates the managed allocation for the `Rc`, - /// then calls your closure, giving it a `Weak` to this allocation, - /// and only afterwards completes the construction of the `Rc` by placing - /// the `T` returned from your closure into the allocation. - /// - /// Since the new `Rc` is not fully-constructed until `Rc::new_cyclic_in` - /// returns, calling [`upgrade`] on the weak reference inside your closure will - /// fail and result in a `None` value. - /// - /// # Panics - /// - /// If `data_fn` panics, the panic is propagated to the caller, and the - /// temporary [`Weak`] is dropped normally. - /// - /// # Examples - /// - /// See [`new_cyclic`]. - /// - /// [`new_cyclic`]: Rc::new_cyclic - /// [`upgrade`]: Weak::upgrade - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn new_cyclic_in(data_fn: F, alloc: A) -> Rc - where - F: FnOnce(&Weak) -> T, - { - // Construct the inner in the "uninitialized" state with a single - // weak reference. - let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in( - RcInner { - strong: Cell::new(0), - weak: Cell::new(1), - value: mem::MaybeUninit::::uninit(), - }, - alloc, - )); - let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into(); - let init_ptr: NonNull> = uninit_ptr.cast(); - - let weak = Weak { ptr: init_ptr, alloc }; - - // It's important we don't give up ownership of the weak pointer, or - // else the memory might be freed by the time `data_fn` returns. If - // we really wanted to pass ownership, we could create an additional - // weak pointer for ourselves, but this would result in additional - // updates to the weak reference count which might not be necessary - // otherwise. - let data = data_fn(&weak); - - let strong = unsafe { - let inner = init_ptr.as_ptr(); - ptr::write(&raw mut (*inner).value, data); - - let prev_value = (*inner).strong.get(); - debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); - (*inner).strong.set(1); - - // Strong references should collectively own a shared weak reference, - // so don't run the destructor for our old weak reference. - // Calling into_raw_with_allocator has the double effect of giving us back the allocator, - // and forgetting the weak reference. - let alloc = weak.into_raw_with_allocator().1; - - Rc::from_inner_in(init_ptr, alloc) - }; - - strong - } - - /// Constructs a new `Rc` in the provided allocator, returning an error if the allocation - /// fails - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let five = Rc::try_new_in(5, System); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub fn try_new_in(value: T, alloc: A) -> Result { - // There is an implicit weak pointer owned by all the strong - // pointers, which ensures that the weak destructor never frees - // the allocation while the strong destructor is running, even - // if the weak pointer is stored inside the strong one. - let (ptr, alloc) = Box::into_unique(Box::try_new_in( - RcInner { strong: Cell::new(1), weak: Cell::new(1), value }, - alloc, - )?); - Ok(unsafe { Self::from_inner_in(ptr.into(), alloc) }) - } - - /// Constructs a new `Rc` with uninitialized contents, in the provided allocator, returning an - /// error if the allocation fails - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let mut five = Rc::::try_new_uninit_in(System)?; - /// - /// let five = unsafe { - /// // Deferred initialization: - /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); - /// - /// five.assume_init() - /// }; - /// - /// assert_eq!(*five, 5); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> { - unsafe { - Ok(Rc::from_ptr_in( - Rc::try_allocate_for_layout( - Layout::new::(), - |layout| alloc.allocate(layout), - <*mut u8>::cast, - )?, - alloc, - )) - } - } - - /// Constructs a new `Rc` with uninitialized contents, with the memory - /// being filled with `0` bytes, in the provided allocator, returning an error if the allocation - /// fails - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let zero = Rc::::try_new_zeroed_in(System)?; - /// let zero = unsafe { zero.assume_init() }; - /// - /// assert_eq!(*zero, 0); - /// # Ok::<(), std::alloc::AllocError>(()) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[unstable(feature = "allocator_api", issue = "32838")] - //#[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> { - unsafe { - Ok(Rc::from_ptr_in( - Rc::try_allocate_for_layout( - Layout::new::(), - |layout| alloc.allocate_zeroed(layout), - <*mut u8>::cast, - )?, - alloc, - )) - } - } - - /// Constructs a new `Pin>` in the provided allocator. If `T` does not implement `Unpin`, then - /// `value` will be pinned in memory and unable to be moved. - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub fn pin_in(value: T, alloc: A) -> Pin - where - A: 'static, - { - unsafe { Pin::new_unchecked(Rc::new_in(value, alloc)) } - } - - /// Returns the inner value, if the `Rc` has exactly one strong reference. - /// - /// Otherwise, an [`Err`] is returned with the same `Rc` that was - /// passed in. - /// - /// This will succeed even if there are outstanding weak references. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new(3); - /// assert_eq!(Rc::try_unwrap(x), Ok(3)); - /// - /// let x = Rc::new(4); - /// let _y = Rc::clone(&x); - /// assert_eq!(*Rc::try_unwrap(x).unwrap_err(), 4); - /// ``` - #[inline] - #[stable(feature = "rc_unique", since = "1.4.0")] - pub fn try_unwrap(this: Self) -> Result { - if Rc::strong_count(&this) == 1 { - let this = ManuallyDrop::new(this); - - let val: T = unsafe { ptr::read(&**this) }; // copy the contained object - let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator - - // Indicate to Weaks that they can't be promoted by decrementing - // the strong count, and then remove the implicit "strong weak" - // pointer while also handling drop logic by just crafting a - // fake Weak. - this.inner().dec_strong(); - let _weak = Weak { ptr: this.ptr, alloc }; - Ok(val) - } else { - Err(this) - } - } - - /// Returns the inner value, if the `Rc` has exactly one strong reference. - /// - /// Otherwise, [`None`] is returned and the `Rc` is dropped. - /// - /// This will succeed even if there are outstanding weak references. - /// - /// If `Rc::into_inner` is called on every clone of this `Rc`, - /// it is guaranteed that exactly one of the calls returns the inner value. - /// This means in particular that the inner value is not dropped. - /// - /// [`Rc::try_unwrap`] is conceptually similar to `Rc::into_inner`. - /// And while they are meant for different use-cases, `Rc::into_inner(this)` - /// is in fact equivalent to [Rc::try_unwrap]\(this).[ok][Result::ok](). - /// (Note that the same kind of equivalence does **not** hold true for - /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`!) - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new(3); - /// assert_eq!(Rc::into_inner(x), Some(3)); - /// - /// let x = Rc::new(4); - /// let y = Rc::clone(&x); - /// - /// assert_eq!(Rc::into_inner(y), None); - /// assert_eq!(Rc::into_inner(x), Some(4)); - /// ``` - #[inline] - #[stable(feature = "rc_into_inner", since = "1.70.0")] - pub fn into_inner(this: Self) -> Option { - Rc::try_unwrap(this).ok() - } -} - -impl Rc<[T]> { - /// Constructs a new reference-counted slice with uninitialized contents. - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut values = Rc::<[u32]>::new_uninit_slice(3); - /// - /// // Deferred initialization: - /// let data = Rc::get_mut(&mut values).unwrap(); - /// data[0].write(1); - /// data[1].write(2); - /// data[2].write(3); - /// - /// let values = unsafe { values.assume_init() }; - /// - /// assert_eq!(*values, [1, 2, 3]) - /// ``` - #[cfg(not(no_global_oom_handling))] - #[stable(feature = "new_uninit", since = "1.82.0")] - #[must_use] - pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit]> { - unsafe { Rc::from_ptr(Rc::allocate_for_slice(len)) } - } - - /// Constructs a new reference-counted slice with uninitialized contents, with the memory being - /// filled with `0` bytes. - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(new_zeroed_alloc)] - /// - /// use std::rc::Rc; - /// - /// let values = Rc::<[u32]>::new_zeroed_slice(3); - /// let values = unsafe { values.assume_init() }; - /// - /// assert_eq!(*values, [0, 0, 0]) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "new_zeroed_alloc", issue = "129396")] - #[must_use] - pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit]> { - unsafe { - Rc::from_ptr(Rc::allocate_for_layout( - Layout::array::(len).unwrap(), - |layout| Global.allocate_zeroed(layout), - |mem| { - ptr::slice_from_raw_parts_mut(mem.cast::(), len) - as *mut RcInner<[mem::MaybeUninit]> - }, - )) - } - } - - /// Converts the reference-counted slice into a reference-counted array. - /// - /// This operation does not reallocate; the underlying array of the slice is simply reinterpreted as an array type. - /// - /// If `N` is not exactly equal to the length of `self`, then this method returns `None`. - #[unstable(feature = "slice_as_array", issue = "133508")] - #[inline] - #[must_use] - pub fn into_array(self) -> Option> { - if self.len() == N { - let ptr = Self::into_raw(self) as *const [T; N]; - - // SAFETY: The underlying array of a slice has the exact same layout as an actual array `[T; N]` if `N` is equal to the slice's length. - let me = unsafe { Rc::from_raw(ptr) }; - Some(me) - } else { - None - } - } -} - -impl Rc<[T], A> { - /// Constructs a new reference-counted slice with uninitialized contents. - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let mut values = Rc::<[u32], _>::new_uninit_slice_in(3, System); - /// - /// let values = unsafe { - /// // Deferred initialization: - /// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); - /// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); - /// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); - /// - /// values.assume_init() - /// }; - /// - /// assert_eq!(*values, [1, 2, 3]) - /// ``` - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn new_uninit_slice_in(len: usize, alloc: A) -> Rc<[mem::MaybeUninit], A> { - unsafe { Rc::from_ptr_in(Rc::allocate_for_slice_in(len, &alloc), alloc) } - } - - /// Constructs a new reference-counted slice with uninitialized contents, with the memory being - /// filled with `0` bytes. - /// - /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and - /// incorrect usage of this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let values = Rc::<[u32], _>::new_zeroed_slice_in(3, System); - /// let values = unsafe { values.assume_init() }; - /// - /// assert_eq!(*values, [0, 0, 0]) - /// ``` - /// - /// [zeroed]: mem::MaybeUninit::zeroed - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "new_uninit", issue = "63291")] - #[inline] - pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Rc<[mem::MaybeUninit], A> { - unsafe { - Rc::from_ptr_in( - Rc::allocate_for_layout( - Layout::array::(len).unwrap(), - |layout| alloc.allocate_zeroed(layout), - |mem| { - ptr::slice_from_raw_parts_mut(mem.cast::(), len) - as *mut RcInner<[mem::MaybeUninit]> - }, - ), - alloc, - ) - } - } -} - -impl Rc, A> { - /// Converts to `Rc`. - /// - /// # Safety - /// - /// As with [`MaybeUninit::assume_init`], - /// it is up to the caller to guarantee that the inner value - /// really is in an initialized state. - /// Calling this when the content is not yet fully initialized - /// causes immediate undefined behavior. - /// - /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut five = Rc::::new_uninit(); - /// - /// // Deferred initialization: - /// Rc::get_mut(&mut five).unwrap().write(5); - /// - /// let five = unsafe { five.assume_init() }; - /// - /// assert_eq!(*five, 5) - /// ``` - #[stable(feature = "new_uninit", since = "1.82.0")] - #[inline] - pub unsafe fn assume_init(self) -> Rc { - let (ptr, alloc) = Rc::into_inner_with_allocator(self); - unsafe { Rc::from_inner_in(ptr.cast(), alloc) } - } -} - -impl Rc<[mem::MaybeUninit], A> { - /// Converts to `Rc<[T]>`. - /// - /// # Safety - /// - /// As with [`MaybeUninit::assume_init`], - /// it is up to the caller to guarantee that the inner value - /// really is in an initialized state. - /// Calling this when the content is not yet fully initialized - /// causes immediate undefined behavior. - /// - /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut values = Rc::<[u32]>::new_uninit_slice(3); - /// - /// // Deferred initialization: - /// let data = Rc::get_mut(&mut values).unwrap(); - /// data[0].write(1); - /// data[1].write(2); - /// data[2].write(3); - /// - /// let values = unsafe { values.assume_init() }; - /// - /// assert_eq!(*values, [1, 2, 3]) - /// ``` - #[stable(feature = "new_uninit", since = "1.82.0")] - #[inline] - pub unsafe fn assume_init(self) -> Rc<[T], A> { - let (ptr, alloc) = Rc::into_inner_with_allocator(self); - unsafe { Rc::from_ptr_in(ptr.as_ptr() as _, alloc) } - } -} - -impl Rc { - /// Constructs an `Rc` from a raw pointer. - /// - /// The raw pointer must have been previously returned by a call to - /// [`Rc::into_raw`][into_raw] with the following requirements: - /// - /// * If `U` is sized, it must have the same size and alignment as `T`. This - /// is trivially true if `U` is `T`. - /// * If `U` is unsized, its data pointer must have the same size and - /// alignment as `T`. This is trivially true if `Rc` was constructed - /// through `Rc` and then converted to `Rc` through an [unsized - /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by the global allocator - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. - /// - /// This function is unsafe because improper use may lead to memory unsafety, - /// even if the returned `Rc` is never accessed. - /// - /// [into_raw]: Rc::into_raw - /// [transmute]: core::mem::transmute - /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new("hello".to_owned()); - /// let x_ptr = Rc::into_raw(x); - /// - /// unsafe { - /// // Convert back to an `Rc` to prevent leak. - /// let x = Rc::from_raw(x_ptr); - /// assert_eq!(&*x, "hello"); - /// - /// // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe. - /// } - /// - /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! - /// ``` - /// - /// Convert a slice back into its original array: - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x: Rc<[u32]> = Rc::new([1, 2, 3]); - /// let x_ptr: *const [u32] = Rc::into_raw(x); - /// - /// unsafe { - /// let x: Rc<[u32; 3]> = Rc::from_raw(x_ptr.cast::<[u32; 3]>()); - /// assert_eq!(&*x, &[1, 2, 3]); - /// } - /// ``` - #[inline] - #[stable(feature = "rc_raw", since = "1.17.0")] - pub unsafe fn from_raw(ptr: *const T) -> Self { - unsafe { Self::from_raw_in(ptr, Global) } - } - - /// Increments the strong reference count on the `Rc` associated with the - /// provided pointer by one. - /// - /// # Safety - /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at - /// least 1) for the duration of this method, and `ptr` must point to a block of memory - /// allocated by the global allocator. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// unsafe { - /// let ptr = Rc::into_raw(five); - /// Rc::increment_strong_count(ptr); - /// - /// let five = Rc::from_raw(ptr); - /// assert_eq!(2, Rc::strong_count(&five)); - /// # // Prevent leaks for Miri. - /// # Rc::decrement_strong_count(ptr); - /// } - /// ``` - #[inline] - #[stable(feature = "rc_mutate_strong_count", since = "1.53.0")] - pub unsafe fn increment_strong_count(ptr: *const T) { - unsafe { Self::increment_strong_count_in(ptr, Global) } - } - - /// Decrements the strong reference count on the `Rc` associated with the - /// provided pointer by one. - /// - /// # Safety - /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at - /// least 1) when invoking this method, and `ptr` must point to a block of memory - /// allocated by the global allocator. This method can be used to release the final `Rc` and - /// backing storage, but **should not** be called after the final `Rc` has been released. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// unsafe { - /// let ptr = Rc::into_raw(five); - /// Rc::increment_strong_count(ptr); - /// - /// let five = Rc::from_raw(ptr); - /// assert_eq!(2, Rc::strong_count(&five)); - /// Rc::decrement_strong_count(ptr); - /// assert_eq!(1, Rc::strong_count(&five)); - /// } - /// ``` - #[inline] - #[stable(feature = "rc_mutate_strong_count", since = "1.53.0")] - pub unsafe fn decrement_strong_count(ptr: *const T) { - unsafe { Self::decrement_strong_count_in(ptr, Global) } - } -} - -impl Rc { - /// Returns a reference to the underlying allocator. - /// - /// Note: this is an associated function, which means that you have - /// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This - /// is so that there is no conflict with a method on the inner type. - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn allocator(this: &Self) -> &A { - &this.alloc - } - - /// Consumes the `Rc`, returning the wrapped pointer. - /// - /// To avoid a memory leak the pointer must be converted back to an `Rc` using - /// [`Rc::from_raw`]. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new("hello".to_owned()); - /// let x_ptr = Rc::into_raw(x); - /// assert_eq!(unsafe { &*x_ptr }, "hello"); - /// # // Prevent leaks for Miri. - /// # drop(unsafe { Rc::from_raw(x_ptr) }); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "rc_raw", since = "1.17.0")] - #[rustc_never_returns_null_ptr] - pub fn into_raw(this: Self) -> *const T { - let this = ManuallyDrop::new(this); - Self::as_ptr(&*this) - } - - /// Consumes the `Rc`, returning the wrapped pointer and allocator. - /// - /// To avoid a memory leak the pointer must be converted back to an `Rc` using - /// [`Rc::from_raw_in`]. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let x = Rc::new_in("hello".to_owned(), System); - /// let (ptr, alloc) = Rc::into_raw_with_allocator(x); - /// assert_eq!(unsafe { &*ptr }, "hello"); - /// let x = unsafe { Rc::from_raw_in(ptr, alloc) }; - /// assert_eq!(&*x, "hello"); - /// ``` - #[must_use = "losing the pointer will leak memory"] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn into_raw_with_allocator(this: Self) -> (*const T, A) { - let this = mem::ManuallyDrop::new(this); - let ptr = Self::as_ptr(&this); - // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped - let alloc = unsafe { ptr::read(&this.alloc) }; - (ptr, alloc) - } - - /// Provides a raw pointer to the data. - /// - /// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid - /// for as long as there are strong counts in the `Rc`. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x = Rc::new(0); - /// let y = Rc::clone(&x); - /// let x_ptr = Rc::as_ptr(&x); - /// assert_eq!(x_ptr, Rc::as_ptr(&y)); - /// assert_eq!(unsafe { *x_ptr }, 0); - /// ``` - #[stable(feature = "weak_into_raw", since = "1.45.0")] - #[rustc_never_returns_null_ptr] - pub fn as_ptr(this: &Self) -> *const T { - let ptr: *mut RcInner = NonNull::as_ptr(this.ptr); - - // SAFETY: This cannot go through Deref::deref or Rc::inner because - // this is required to retain raw/mut provenance such that e.g. `get_mut` can - // write through the pointer after the Rc is recovered through `from_raw`. - unsafe { &raw mut (*ptr).value } - } - - /// Constructs an `Rc` from a raw pointer in the provided allocator. - /// - /// The raw pointer must have been previously returned by a call to [`Rc::into_raw`][into_raw] with the following requirements: - /// - /// * If `U` is sized, it must have the same size and alignment as `T`. This - /// is trivially true if `U` is `T`. - /// * If `U` is unsized, its data pointer must have the same size and - /// alignment as `T`. This is trivially true if `Rc` was constructed - /// through `Rc` and then converted to `Rc` through an [unsized - /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by `alloc` - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. - /// - /// This function is unsafe because improper use may lead to memory unsafety, - /// even if the returned `Rc` is never accessed. - /// - /// [into_raw]: Rc::into_raw - /// [transmute]: core::mem::transmute - /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let x = Rc::new_in("hello".to_owned(), System); - /// let x_ptr = Rc::into_raw(x); - /// - /// unsafe { - /// // Convert back to an `Rc` to prevent leak. - /// let x = Rc::from_raw_in(x_ptr, System); - /// assert_eq!(&*x, "hello"); - /// - /// // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe. - /// } - /// - /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! - /// ``` - /// - /// Convert a slice back into its original array: - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let x: Rc<[u32], _> = Rc::new_in([1, 2, 3], System); - /// let x_ptr: *const [u32] = Rc::into_raw(x); - /// - /// unsafe { - /// let x: Rc<[u32; 3], _> = Rc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System); - /// assert_eq!(&*x, &[1, 2, 3]); - /// } - /// ``` - #[unstable(feature = "allocator_api", issue = "32838")] - pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { - let offset = unsafe { data_offset(ptr) }; - - // Reverse the offset to find the original RcInner. - let rc_ptr = unsafe { ptr.byte_sub(offset) as *mut RcInner }; - - unsafe { Self::from_ptr_in(rc_ptr, alloc) } - } - - /// Creates a new [`Weak`] pointer to this allocation. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// let weak_five = Rc::downgrade(&five); - /// ``` - #[must_use = "this returns a new `Weak` pointer, \ - without modifying the original `Rc`"] - #[stable(feature = "rc_weak", since = "1.4.0")] - pub fn downgrade(this: &Self) -> Weak - where - A: Clone, - { - this.inner().inc_weak(); - // Make sure we do not create a dangling Weak - debug_assert!(!is_dangling(this.ptr.as_ptr())); - Weak { ptr: this.ptr, alloc: this.alloc.clone() } - } - - /// Gets the number of [`Weak`] pointers to this allocation. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// let _weak_five = Rc::downgrade(&five); - /// - /// assert_eq!(1, Rc::weak_count(&five)); - /// ``` - #[inline] - #[stable(feature = "rc_counts", since = "1.15.0")] - pub fn weak_count(this: &Self) -> usize { - this.inner().weak() - 1 - } - - /// Gets the number of strong (`Rc`) pointers to this allocation. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// let _also_five = Rc::clone(&five); - /// - /// assert_eq!(2, Rc::strong_count(&five)); - /// ``` - #[inline] - #[stable(feature = "rc_counts", since = "1.15.0")] - pub fn strong_count(this: &Self) -> usize { - this.inner().strong() - } - - /// Increments the strong reference count on the `Rc` associated with the - /// provided pointer by one. - /// - /// # Safety - /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at - /// least 1) for the duration of this method, and `ptr` must point to a block of memory - /// allocated by `alloc` - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let five = Rc::new_in(5, System); - /// - /// unsafe { - /// let ptr = Rc::into_raw(five); - /// Rc::increment_strong_count_in(ptr, System); - /// - /// let five = Rc::from_raw_in(ptr, System); - /// assert_eq!(2, Rc::strong_count(&five)); - /// # // Prevent leaks for Miri. - /// # Rc::decrement_strong_count_in(ptr, System); - /// } - /// ``` - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub unsafe fn increment_strong_count_in(ptr: *const T, alloc: A) - where - A: Clone, - { - // Retain Rc, but don't touch refcount by wrapping in ManuallyDrop - let rc = unsafe { mem::ManuallyDrop::new(Rc::::from_raw_in(ptr, alloc)) }; - // Now increase refcount, but don't drop new refcount either - let _rc_clone: mem::ManuallyDrop<_> = rc.clone(); - } - - /// Decrements the strong reference count on the `Rc` associated with the - /// provided pointer by one. - /// - /// # Safety - /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at - /// least 1) when invoking this method, and `ptr` must point to a block of memory - /// allocated by `alloc`. This method can be used to release the final `Rc` and backing storage, - /// but **should not** be called after the final `Rc` has been released. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::rc::Rc; - /// use std::alloc::System; - /// - /// let five = Rc::new_in(5, System); - /// - /// unsafe { - /// let ptr = Rc::into_raw(five); - /// Rc::increment_strong_count_in(ptr, System); - /// - /// let five = Rc::from_raw_in(ptr, System); - /// assert_eq!(2, Rc::strong_count(&five)); - /// Rc::decrement_strong_count_in(ptr, System); - /// assert_eq!(1, Rc::strong_count(&five)); - /// } - /// ``` - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub unsafe fn decrement_strong_count_in(ptr: *const T, alloc: A) { - unsafe { drop(Rc::from_raw_in(ptr, alloc)) }; - } - - /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to - /// this allocation. - #[inline] - fn is_unique(this: &Self) -> bool { - Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 - } - - /// Returns a mutable reference into the given `Rc`, if there are - /// no other `Rc` or [`Weak`] pointers to the same allocation. - /// - /// Returns [`None`] otherwise, because it is not safe to - /// mutate a shared value. - /// - /// See also [`make_mut`][make_mut], which will [`clone`][clone] - /// the inner value when there are other `Rc` pointers. - /// - /// [make_mut]: Rc::make_mut - /// [clone]: Clone::clone - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let mut x = Rc::new(3); - /// *Rc::get_mut(&mut x).unwrap() = 4; - /// assert_eq!(*x, 4); - /// - /// let _y = Rc::clone(&x); - /// assert!(Rc::get_mut(&mut x).is_none()); - /// ``` - #[inline] - #[stable(feature = "rc_unique", since = "1.4.0")] - pub fn get_mut(this: &mut Self) -> Option<&mut T> { - if Rc::is_unique(this) { unsafe { Some(Rc::get_mut_unchecked(this)) } } else { None } - } - - /// Returns a mutable reference into the given `Rc`, - /// without any check. - /// - /// See also [`get_mut`], which is safe and does appropriate checks. - /// - /// [`get_mut`]: Rc::get_mut - /// - /// # Safety - /// - /// If any other `Rc` or [`Weak`] pointers to the same allocation exist, then - /// they must not be dereferenced or have active borrows for the duration - /// of the returned borrow, and their inner type must be exactly the same as the - /// inner type of this Rc (including lifetimes). This is trivially the case if no - /// such pointers exist, for example immediately after `Rc::new`. - /// - /// # Examples - /// - /// ``` - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let mut x = Rc::new(String::new()); - /// unsafe { - /// Rc::get_mut_unchecked(&mut x).push_str("foo") - /// } - /// assert_eq!(*x, "foo"); - /// ``` - /// Other `Rc` pointers to the same allocation must be to the same type. - /// ```no_run - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let x: Rc = Rc::from("Hello, world!"); - /// let mut y: Rc<[u8]> = x.clone().into(); - /// unsafe { - /// // this is Undefined Behavior, because x's inner type is str, not [u8] - /// Rc::get_mut_unchecked(&mut y).fill(0xff); // 0xff is invalid in UTF-8 - /// } - /// println!("{}", &*x); // Invalid UTF-8 in a str - /// ``` - /// Other `Rc` pointers to the same allocation must be to the exact same type, including lifetimes. - /// ```no_run - /// #![feature(get_mut_unchecked)] - /// - /// use std::rc::Rc; - /// - /// let x: Rc<&str> = Rc::new("Hello, world!"); - /// { - /// let s = String::from("Oh, no!"); - /// let mut y: Rc<&str> = x.clone(); - /// unsafe { - /// // this is Undefined Behavior, because x's inner type - /// // is &'long str, not &'short str - /// *Rc::get_mut_unchecked(&mut y) = &s; - /// } - /// } - /// println!("{}", &*x); // Use-after-free - /// ``` - #[inline] - #[unstable(feature = "get_mut_unchecked", issue = "63292")] - pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { - // We are careful to *not* create a reference covering the "count" fields, as - // this would conflict with accesses to the reference counts (e.g. by `Weak`). - unsafe { &mut (*this.ptr.as_ptr()).value } - } - - #[inline] - #[stable(feature = "ptr_eq", since = "1.17.0")] - /// Returns `true` if the two `Rc`s point to the same allocation in a vein similar to - /// [`ptr::eq`]. This function ignores the metadata of `dyn Trait` pointers. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// let same_five = Rc::clone(&five); - /// let other_five = Rc::new(5); - /// - /// assert!(Rc::ptr_eq(&five, &same_five)); - /// assert!(!Rc::ptr_eq(&five, &other_five)); - /// ``` - pub fn ptr_eq(this: &Self, other: &Self) -> bool { - ptr::addr_eq(this.ptr.as_ptr(), other.ptr.as_ptr()) - } -} - -#[cfg(not(no_global_oom_handling))] -impl Rc { - /// Makes a mutable reference into the given `Rc`. - /// - /// If there are other `Rc` pointers to the same allocation, then `make_mut` will - /// [`clone`] the inner value to a new allocation to ensure unique ownership. This is also - /// referred to as clone-on-write. - /// - /// However, if there are no other `Rc` pointers to this allocation, but some [`Weak`] - /// pointers, then the [`Weak`] pointers will be disassociated and the inner value will not - /// be cloned. - /// - /// See also [`get_mut`], which will fail rather than cloning the inner value - /// or disassociating [`Weak`] pointers. - /// - /// [`clone`]: Clone::clone - /// [`get_mut`]: Rc::get_mut - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let mut data = Rc::new(5); - /// - /// *Rc::make_mut(&mut data) += 1; // Won't clone anything - /// let mut other_data = Rc::clone(&data); // Won't clone inner data - /// *Rc::make_mut(&mut data) += 1; // Clones inner data - /// *Rc::make_mut(&mut data) += 1; // Won't clone anything - /// *Rc::make_mut(&mut other_data) *= 2; // Won't clone anything - /// - /// // Now `data` and `other_data` point to different allocations. - /// assert_eq!(*data, 8); - /// assert_eq!(*other_data, 12); - /// ``` - /// - /// [`Weak`] pointers will be disassociated: - /// - /// ``` - /// use std::rc::Rc; - /// - /// let mut data = Rc::new(75); - /// let weak = Rc::downgrade(&data); - /// - /// assert!(75 == *data); - /// assert!(75 == *weak.upgrade().unwrap()); - /// - /// *Rc::make_mut(&mut data) += 1; - /// - /// assert!(76 == *data); - /// assert!(weak.upgrade().is_none()); - /// ``` - #[inline] - #[stable(feature = "rc_unique", since = "1.4.0")] - pub fn make_mut(this: &mut Self) -> &mut T { - let size_of_val = size_of_val::(&**this); - - if Rc::strong_count(this) != 1 { - // Gotta clone the data, there are other Rcs. - - let this_data_ref: &T = &**this; - // `in_progress` drops the allocation if we panic before finishing initializing it. - let mut in_progress: UniqueRcUninit = - UniqueRcUninit::new(this_data_ref, this.alloc.clone()); - - // Initialize with clone of this. - let initialized_clone = unsafe { - // Clone. If the clone panics, `in_progress` will be dropped and clean up. - this_data_ref.clone_to_uninit(in_progress.data_ptr().cast()); - // Cast type of pointer, now that it is initialized. - in_progress.into_rc() - }; - - // Replace `this` with newly constructed Rc. - *this = initialized_clone; - } else if Rc::weak_count(this) != 0 { - // Can just steal the data, all that's left is Weaks - - // We don't need panic-protection like the above branch does, but we might as well - // use the same mechanism. - let mut in_progress: UniqueRcUninit = - UniqueRcUninit::new(&**this, this.alloc.clone()); - unsafe { - // Initialize `in_progress` with move of **this. - // We have to express this in terms of bytes because `T: ?Sized`; there is no - // operation that just copies a value based on its `size_of_val()`. - ptr::copy_nonoverlapping( - ptr::from_ref(&**this).cast::(), - in_progress.data_ptr().cast::(), - size_of_val, - ); - - this.inner().dec_strong(); - // Remove implicit strong-weak ref (no need to craft a fake - // Weak here -- we know other Weaks can clean up for us) - this.inner().dec_weak(); - // Replace `this` with newly constructed Rc that has the moved data. - ptr::write(this, in_progress.into_rc()); - } - } - // This unsafety is ok because we're guaranteed that the pointer - // returned is the *only* pointer that will ever be returned to T. Our - // reference count is guaranteed to be 1 at this point, and we required - // the `Rc` itself to be `mut`, so we're returning the only possible - // reference to the allocation. - unsafe { &mut this.ptr.as_mut().value } - } -} - -impl Rc { - /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the - /// clone. - /// - /// Assuming `rc_t` is of type `Rc`, this function is functionally equivalent to - /// `(*rc_t).clone()`, but will avoid cloning the inner value where possible. - /// - /// # Examples - /// - /// ``` - /// # use std::{ptr, rc::Rc}; - /// let inner = String::from("test"); - /// let ptr = inner.as_ptr(); - /// - /// let rc = Rc::new(inner); - /// let inner = Rc::unwrap_or_clone(rc); - /// // The inner value was not cloned - /// assert!(ptr::eq(ptr, inner.as_ptr())); - /// - /// let rc = Rc::new(inner); - /// let rc2 = rc.clone(); - /// let inner = Rc::unwrap_or_clone(rc); - /// // Because there were 2 references, we had to clone the inner value. - /// assert!(!ptr::eq(ptr, inner.as_ptr())); - /// // `rc2` is the last reference, so when we unwrap it we get back - /// // the original `String`. - /// let inner = Rc::unwrap_or_clone(rc2); - /// assert!(ptr::eq(ptr, inner.as_ptr())); - /// ``` - #[inline] - #[stable(feature = "arc_unwrap_or_clone", since = "1.76.0")] - pub fn unwrap_or_clone(this: Self) -> T { - Rc::try_unwrap(this).unwrap_or_else(|rc| (*rc).clone()) - } -} - -impl Rc { - /// Attempts to downcast the `Rc` to a concrete type. - /// - /// # Examples - /// - /// ``` - /// use std::any::Any; - /// use std::rc::Rc; - /// - /// fn print_if_string(value: Rc) { - /// if let Ok(string) = value.downcast::() { - /// println!("String ({}): {}", string.len(), string); - /// } - /// } - /// - /// let my_string = "Hello World".to_string(); - /// print_if_string(Rc::new(my_string)); - /// print_if_string(Rc::new(0i8)); - /// ``` - #[inline] - #[stable(feature = "rc_downcast", since = "1.29.0")] - pub fn downcast(self) -> Result, Self> { - if (*self).is::() { - unsafe { - let (ptr, alloc) = Rc::into_inner_with_allocator(self); - Ok(Rc::from_inner_in(ptr.cast(), alloc)) - } - } else { - Err(self) - } - } - - /// Downcasts the `Rc` to a concrete type. - /// - /// For a safe alternative see [`downcast`]. - /// - /// # Examples - /// - /// ``` - /// #![feature(downcast_unchecked)] - /// - /// use std::any::Any; - /// use std::rc::Rc; - /// - /// let x: Rc = Rc::new(1_usize); - /// - /// unsafe { - /// assert_eq!(*x.downcast_unchecked::(), 1); - /// } - /// ``` - /// - /// # Safety - /// - /// The contained value must be of type `T`. Calling this method - /// with the incorrect type is *undefined behavior*. - /// - /// - /// [`downcast`]: Self::downcast - #[inline] - #[unstable(feature = "downcast_unchecked", issue = "90850")] - pub unsafe fn downcast_unchecked(self) -> Rc { - unsafe { - let (ptr, alloc) = Rc::into_inner_with_allocator(self); - Rc::from_inner_in(ptr.cast(), alloc) - } - } -} - -impl Rc { - /// Allocates an `RcInner` with sufficient space for - /// a possibly-unsized inner value where the value has the layout provided. - /// - /// The function `mem_to_rc_inner` is called with the data pointer - /// and must return back a (potentially fat)-pointer for the `RcInner`. - #[cfg(not(no_global_oom_handling))] - unsafe fn allocate_for_layout( - value_layout: Layout, - allocate: impl FnOnce(Layout) -> Result, AllocError>, - mem_to_rc_inner: impl FnOnce(*mut u8) -> *mut RcInner, - ) -> *mut RcInner { - let layout = rc_inner_layout_for_value_layout(value_layout); - unsafe { - Rc::try_allocate_for_layout(value_layout, allocate, mem_to_rc_inner) - .unwrap_or_else(|_| handle_alloc_error(layout)) - } - } - - /// Allocates an `RcInner` with sufficient space for - /// a possibly-unsized inner value where the value has the layout provided, - /// returning an error if allocation fails. - /// - /// The function `mem_to_rc_inner` is called with the data pointer - /// and must return back a (potentially fat)-pointer for the `RcInner`. - #[inline] - unsafe fn try_allocate_for_layout( - value_layout: Layout, - allocate: impl FnOnce(Layout) -> Result, AllocError>, - mem_to_rc_inner: impl FnOnce(*mut u8) -> *mut RcInner, - ) -> Result<*mut RcInner, AllocError> { - let layout = rc_inner_layout_for_value_layout(value_layout); - - // Allocate for the layout. - let ptr = allocate(layout)?; - - // Initialize the RcInner - let inner = mem_to_rc_inner(ptr.as_non_null_ptr().as_ptr()); - unsafe { - debug_assert_eq!(Layout::for_value_raw(inner), layout); - - (&raw mut (*inner).strong).write(Cell::new(1)); - (&raw mut (*inner).weak).write(Cell::new(1)); - } - - Ok(inner) - } -} - -impl Rc { - /// Allocates an `RcInner` with sufficient space for an unsized inner value - #[cfg(not(no_global_oom_handling))] - unsafe fn allocate_for_ptr_in(ptr: *const T, alloc: &A) -> *mut RcInner { - // Allocate for the `RcInner` using the given value. - unsafe { - Rc::::allocate_for_layout( - Layout::for_value_raw(ptr), - |layout| alloc.allocate(layout), - |mem| mem.with_metadata_of(ptr as *const RcInner), - ) - } - } - - #[cfg(not(no_global_oom_handling))] - fn from_box_in(src: Box) -> Rc { - unsafe { - let value_size = size_of_val(&*src); - let ptr = Self::allocate_for_ptr_in(&*src, Box::allocator(&src)); - - // Copy value as bytes - ptr::copy_nonoverlapping( - (&raw const *src) as *const u8, - (&raw mut (*ptr).value) as *mut u8, - value_size, - ); - - // Free the allocation without dropping its contents - let (bptr, alloc) = Box::into_raw_with_allocator(src); - let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, alloc.by_ref()); - drop(src); - - Self::from_ptr_in(ptr, alloc) - } - } -} - -impl Rc<[T]> { - /// Allocates an `RcInner<[T]>` with the given length. - #[cfg(not(no_global_oom_handling))] - unsafe fn allocate_for_slice(len: usize) -> *mut RcInner<[T]> { - unsafe { - Self::allocate_for_layout( - Layout::array::(len).unwrap(), - |layout| Global.allocate(layout), - |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, - ) - } - } - - /// Copy elements from slice into newly allocated `Rc<[T]>` - /// - /// Unsafe because the caller must either take ownership or bind `T: Copy` - #[cfg(not(no_global_oom_handling))] - unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { - unsafe { - let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping(v.as_ptr(), (&raw mut (*ptr).value) as *mut T, v.len()); - Self::from_ptr(ptr) - } - } - - /// Constructs an `Rc<[T]>` from an iterator known to be of a certain size. - /// - /// Behavior is undefined should the size be wrong. - #[cfg(not(no_global_oom_handling))] - unsafe fn from_iter_exact(iter: impl Iterator, len: usize) -> Rc<[T]> { - // Panic guard while cloning T elements. - // In the event of a panic, elements that have been written - // into the new RcInner will be dropped, then the memory freed. - struct Guard { - mem: NonNull, - elems: *mut T, - layout: Layout, - n_elems: usize, - } - - impl Drop for Guard { - fn drop(&mut self) { - unsafe { - let slice = from_raw_parts_mut(self.elems, self.n_elems); - ptr::drop_in_place(slice); - - Global.deallocate(self.mem, self.layout); - } - } - } - - unsafe { - let ptr = Self::allocate_for_slice(len); - - let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value_raw(ptr); - - // Pointer to first element - let elems = (&raw mut (*ptr).value) as *mut T; - - let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; - - for (i, item) in iter.enumerate() { - ptr::write(elems.add(i), item); - guard.n_elems += 1; - } - - // All clear. Forget the guard so it doesn't free the new RcInner. - mem::forget(guard); - - Self::from_ptr(ptr) - } - } -} - -impl Rc<[T], A> { - /// Allocates an `RcInner<[T]>` with the given length. - #[inline] - #[cfg(not(no_global_oom_handling))] - unsafe fn allocate_for_slice_in(len: usize, alloc: &A) -> *mut RcInner<[T]> { - unsafe { - Rc::<[T]>::allocate_for_layout( - Layout::array::(len).unwrap(), - |layout| alloc.allocate(layout), - |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, - ) - } - } -} - -#[cfg(not(no_global_oom_handling))] -/// Specialization trait used for `From<&[T]>`. -trait RcFromSlice { - fn from_slice(slice: &[T]) -> Self; -} - -#[cfg(not(no_global_oom_handling))] -impl RcFromSlice for Rc<[T]> { - #[inline] - default fn from_slice(v: &[T]) -> Self { - unsafe { Self::from_iter_exact(v.iter().cloned(), v.len()) } - } -} - -#[cfg(not(no_global_oom_handling))] -impl RcFromSlice for Rc<[T]> { - #[inline] - fn from_slice(v: &[T]) -> Self { - unsafe { Rc::copy_from_slice(v) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Rc { - type Target = T; - - #[inline(always)] - fn deref(&self) -> &T { - &self.inner().value - } -} - -#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] -unsafe impl PinCoerceUnsized for Rc {} - -//#[unstable(feature = "unique_rc_arc", issue = "112566")] -#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] -unsafe impl PinCoerceUnsized for UniqueRc {} - -#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] -unsafe impl PinCoerceUnsized for Weak {} - -#[unstable(feature = "deref_pure_trait", issue = "87121")] -unsafe impl DerefPure for Rc {} - -//#[unstable(feature = "unique_rc_arc", issue = "112566")] -#[unstable(feature = "deref_pure_trait", issue = "87121")] -unsafe impl DerefPure for UniqueRc {} - -#[unstable(feature = "legacy_receiver_trait", issue = "none")] -impl LegacyReceiver for Rc {} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc { - /// Drops the `Rc`. - /// - /// This will decrement the strong reference count. If the strong reference - /// count reaches zero then the only other references (if any) are - /// [`Weak`], so we `drop` the inner value. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// struct Foo; - /// - /// impl Drop for Foo { - /// fn drop(&mut self) { - /// println!("dropped!"); - /// } - /// } - /// - /// let foo = Rc::new(Foo); - /// let foo2 = Rc::clone(&foo); - /// - /// drop(foo); // Doesn't print anything - /// drop(foo2); // Prints "dropped!" - /// ``` - #[inline] - fn drop(&mut self) { - unsafe { - self.inner().dec_strong(); - if self.inner().strong() == 0 { - self.drop_slow(); - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Rc { - /// Makes a clone of the `Rc` pointer. - /// - /// This creates another pointer to the same allocation, increasing the - /// strong reference count. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// let _ = Rc::clone(&five); - /// ``` - #[inline] - fn clone(&self) -> Self { - unsafe { - self.inner().inc_strong(); - Self::from_inner_in(self.ptr, self.alloc.clone()) - } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for Rc { - /// Creates a new `Rc`, with the `Default` value for `T`. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let x: Rc = Default::default(); - /// assert_eq!(*x, 0); - /// ``` - #[inline] - fn default() -> Rc { - unsafe { - Self::from_inner( - Box::leak(Box::write( - Box::new_uninit(), - RcInner { strong: Cell::new(1), weak: Cell::new(1), value: T::default() }, - )) - .into(), - ) - } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "more_rc_default_impls", since = "1.80.0")] -impl Default for Rc { - /// Creates an empty str inside an Rc - /// - /// This may or may not share an allocation with other Rcs on the same thread. - #[inline] - fn default() -> Self { - let rc = Rc::<[u8]>::default(); - // `[u8]` has the same layout as `str`. - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const str) } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "more_rc_default_impls", since = "1.80.0")] -impl Default for Rc<[T]> { - /// Creates an empty `[T]` inside an Rc - /// - /// This may or may not share an allocation with other Rcs on the same thread. - #[inline] - fn default() -> Self { - let arr: [T; 0] = []; - Rc::from(arr) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -trait RcEqIdent { - fn eq(&self, other: &Rc) -> bool; - fn ne(&self, other: &Rc) -> bool; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl RcEqIdent for Rc { - #[inline] - default fn eq(&self, other: &Rc) -> bool { - **self == **other - } - - #[inline] - default fn ne(&self, other: &Rc) -> bool { - **self != **other - } -} - -// Hack to allow specializing on `Eq` even though `Eq` has a method. -#[rustc_unsafe_specialization_marker] -pub(crate) trait MarkerEq: PartialEq {} - -impl MarkerEq for T {} - -/// We're doing this specialization here, and not as a more general optimization on `&T`, because it -/// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to -/// store large values, that are slow to clone, but also heavy to check for equality, causing this -/// cost to pay off more easily. It's also more likely to have two `Rc` clones, that point to -/// the same value, than two `&T`s. -/// -/// We can only do this when `T: Eq` as a `PartialEq` might be deliberately irreflexive. -#[stable(feature = "rust1", since = "1.0.0")] -impl RcEqIdent for Rc { - #[inline] - fn eq(&self, other: &Rc) -> bool { - Rc::ptr_eq(self, other) || **self == **other - } - - #[inline] - fn ne(&self, other: &Rc) -> bool { - !Rc::ptr_eq(self, other) && **self != **other - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Rc { - /// Equality for two `Rc`s. - /// - /// Two `Rc`s are equal if their inner values are equal, even if they are - /// stored in different allocation. - /// - /// If `T` also implements `Eq` (implying reflexivity of equality), - /// two `Rc`s that point to the same allocation are - /// always equal. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five == Rc::new(5)); - /// ``` - #[inline] - fn eq(&self, other: &Rc) -> bool { - RcEqIdent::eq(self, other) - } - - /// Inequality for two `Rc`s. - /// - /// Two `Rc`s are not equal if their inner values are not equal. - /// - /// If `T` also implements `Eq` (implying reflexivity of equality), - /// two `Rc`s that point to the same allocation are - /// always equal. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five != Rc::new(6)); - /// ``` - #[inline] - fn ne(&self, other: &Rc) -> bool { - RcEqIdent::ne(self, other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Rc {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Rc { - /// Partial comparison for two `Rc`s. - /// - /// The two are compared by calling `partial_cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// use std::cmp::Ordering; - /// - /// let five = Rc::new(5); - /// - /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Rc::new(6))); - /// ``` - #[inline(always)] - fn partial_cmp(&self, other: &Rc) -> Option { - (**self).partial_cmp(&**other) - } - - /// Less-than comparison for two `Rc`s. - /// - /// The two are compared by calling `<` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five < Rc::new(6)); - /// ``` - #[inline(always)] - fn lt(&self, other: &Rc) -> bool { - **self < **other - } - - /// 'Less than or equal to' comparison for two `Rc`s. - /// - /// The two are compared by calling `<=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five <= Rc::new(5)); - /// ``` - #[inline(always)] - fn le(&self, other: &Rc) -> bool { - **self <= **other - } - - /// Greater-than comparison for two `Rc`s. - /// - /// The two are compared by calling `>` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five > Rc::new(4)); - /// ``` - #[inline(always)] - fn gt(&self, other: &Rc) -> bool { - **self > **other - } - - /// 'Greater than or equal to' comparison for two `Rc`s. - /// - /// The two are compared by calling `>=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// assert!(five >= Rc::new(5)); - /// ``` - #[inline(always)] - fn ge(&self, other: &Rc) -> bool { - **self >= **other - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Rc { - /// Comparison for two `Rc`s. - /// - /// The two are compared by calling `cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// use std::cmp::Ordering; - /// - /// let five = Rc::new(5); - /// - /// assert_eq!(Ordering::Less, five.cmp(&Rc::new(6))); - /// ``` - #[inline] - fn cmp(&self, other: &Rc) -> Ordering { - (**self).cmp(&**other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Rc { - fn hash(&self, state: &mut H) { - (**self).hash(state); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Rc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Rc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Pointer for Rc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&(&raw const **self), f) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "from_for_ptrs", since = "1.6.0")] -impl From for Rc { - /// Converts a generic type `T` into an `Rc` - /// - /// The conversion allocates on the heap and moves `t` - /// from the stack into it. - /// - /// # Example - /// ```rust - /// # use std::rc::Rc; - /// let x = 5; - /// let rc = Rc::new(5); - /// - /// assert_eq!(Rc::from(x), rc); - /// ``` - fn from(t: T) -> Self { - Rc::new(t) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_array", since = "1.74.0")] -impl From<[T; N]> for Rc<[T]> { - /// Converts a [`[T; N]`](prim@array) into an `Rc<[T]>`. - /// - /// The conversion moves the array into a newly allocated `Rc`. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let original: [i32; 3] = [1, 2, 3]; - /// let shared: Rc<[i32]> = Rc::from(original); - /// assert_eq!(&[1, 2, 3], &shared[..]); - /// ``` - #[inline] - fn from(v: [T; N]) -> Rc<[T]> { - Rc::<[T; N]>::from(v) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From<&[T]> for Rc<[T]> { - /// Allocates a reference-counted slice and fills it by cloning `v`'s items. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let original: &[i32] = &[1, 2, 3]; - /// let shared: Rc<[i32]> = Rc::from(original); - /// assert_eq!(&[1, 2, 3], &shared[..]); - /// ``` - #[inline] - fn from(v: &[T]) -> Rc<[T]> { - >::from_slice(v) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] -impl From<&mut [T]> for Rc<[T]> { - /// Allocates a reference-counted slice and fills it by cloning `v`'s items. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let mut original = [1, 2, 3]; - /// let original: &mut [i32] = &mut original; - /// let shared: Rc<[i32]> = Rc::from(original); - /// assert_eq!(&[1, 2, 3], &shared[..]); - /// ``` - #[inline] - fn from(v: &mut [T]) -> Rc<[T]> { - Rc::from(&*v) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From<&str> for Rc { - /// Allocates a reference-counted string slice and copies `v` into it. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let shared: Rc = Rc::from("statue"); - /// assert_eq!("statue", &shared[..]); - /// ``` - #[inline] - fn from(v: &str) -> Rc { - let rc = Rc::<[u8]>::from(v.as_bytes()); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const str) } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] -impl From<&mut str> for Rc { - /// Allocates a reference-counted string slice and copies `v` into it. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let mut original = String::from("statue"); - /// let original: &mut str = &mut original; - /// let shared: Rc = Rc::from(original); - /// assert_eq!("statue", &shared[..]); - /// ``` - #[inline] - fn from(v: &mut str) -> Rc { - Rc::from(&*v) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From for Rc { - /// Allocates a reference-counted string slice and copies `v` into it. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let original: String = "statue".to_owned(); - /// let shared: Rc = Rc::from(original); - /// assert_eq!("statue", &shared[..]); - /// ``` - #[inline] - fn from(v: String) -> Rc { - Rc::from(&v[..]) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From> for Rc { - /// Move a boxed object to a new, reference counted, allocation. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let original: Box = Box::new(1); - /// let shared: Rc = Rc::from(original); - /// assert_eq!(1, *shared); - /// ``` - #[inline] - fn from(v: Box) -> Rc { - Rc::from_box_in(v) - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From> for Rc<[T], A> { - /// Allocates a reference-counted slice and moves `v`'s items into it. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let unique: Vec = vec![1, 2, 3]; - /// let shared: Rc<[i32]> = Rc::from(unique); - /// assert_eq!(&[1, 2, 3], &shared[..]); - /// ``` - #[inline] - fn from(v: Vec) -> Rc<[T], A> { - unsafe { - let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); - - let rc_ptr = Self::allocate_for_slice_in(len, &alloc); - ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).value) as *mut T, len); - - // Create a `Vec` with length 0, to deallocate the buffer - // without dropping its contents or the allocator - let _ = Vec::from_raw_parts_in(vec_ptr, 0, cap, &alloc); - - Self::from_ptr_in(rc_ptr, alloc) - } - } -} - -#[stable(feature = "shared_from_cow", since = "1.45.0")] -impl<'a, B> From> for Rc -where - B: ToOwned + ?Sized, - Rc: From<&'a B> + From, -{ - /// Creates a reference-counted pointer from a clone-on-write pointer by - /// copying its content. - /// - /// # Example - /// - /// ```rust - /// # use std::rc::Rc; - /// # use std::borrow::Cow; - /// let cow: Cow<'_, str> = Cow::Borrowed("eggplant"); - /// let shared: Rc = Rc::from(cow); - /// assert_eq!("eggplant", &shared[..]); - /// ``` - #[inline] - fn from(cow: Cow<'a, B>) -> Rc { - match cow { - Cow::Borrowed(s) => Rc::from(s), - Cow::Owned(s) => Rc::from(s), - } - } -} - -#[stable(feature = "shared_from_str", since = "1.62.0")] -impl From> for Rc<[u8]> { - /// Converts a reference-counted string slice into a byte slice. - /// - /// # Example - /// - /// ``` - /// # use std::rc::Rc; - /// let string: Rc = Rc::from("eggplant"); - /// let bytes: Rc<[u8]> = Rc::from(string); - /// assert_eq!("eggplant".as_bytes(), bytes.as_ref()); - /// ``` - #[inline] - fn from(rc: Rc) -> Self { - // SAFETY: `str` has the same layout as `[u8]`. - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const [u8]) } - } -} - -#[stable(feature = "boxed_slice_try_from", since = "1.43.0")] -impl TryFrom> for Rc<[T; N], A> { - type Error = Rc<[T], A>; - - fn try_from(boxed_slice: Rc<[T], A>) -> Result { - if boxed_slice.len() == N { - let (ptr, alloc) = Rc::into_inner_with_allocator(boxed_slice); - Ok(unsafe { Rc::from_inner_in(ptr.cast(), alloc) }) - } else { - Err(boxed_slice) - } - } -} - -#[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_iter", since = "1.37.0")] -impl FromIterator for Rc<[T]> { - /// Takes each element in the `Iterator` and collects it into an `Rc<[T]>`. - /// - /// # Performance characteristics - /// - /// ## The general case - /// - /// In the general case, collecting into `Rc<[T]>` is done by first - /// collecting into a `Vec`. That is, when writing the following: - /// - /// ```rust - /// # use std::rc::Rc; - /// let evens: Rc<[u8]> = (0..10).filter(|&x| x % 2 == 0).collect(); - /// # assert_eq!(&*evens, &[0, 2, 4, 6, 8]); - /// ``` - /// - /// this behaves as if we wrote: - /// - /// ```rust - /// # use std::rc::Rc; - /// let evens: Rc<[u8]> = (0..10).filter(|&x| x % 2 == 0) - /// .collect::>() // The first set of allocations happens here. - /// .into(); // A second allocation for `Rc<[T]>` happens here. - /// # assert_eq!(&*evens, &[0, 2, 4, 6, 8]); - /// ``` - /// - /// This will allocate as many times as needed for constructing the `Vec` - /// and then it will allocate once for turning the `Vec` into the `Rc<[T]>`. - /// - /// ## Iterators of known length - /// - /// When your `Iterator` implements `TrustedLen` and is of an exact size, - /// a single allocation will be made for the `Rc<[T]>`. For example: - /// - /// ```rust - /// # use std::rc::Rc; - /// let evens: Rc<[u8]> = (0..10).collect(); // Just a single allocation happens here. - /// # assert_eq!(&*evens, &*(0..10).collect::>()); - /// ``` - fn from_iter>(iter: I) -> Self { - ToRcSlice::to_rc_slice(iter.into_iter()) - } -} - -/// Specialization trait used for collecting into `Rc<[T]>`. -#[cfg(not(no_global_oom_handling))] -trait ToRcSlice: Iterator + Sized { - fn to_rc_slice(self) -> Rc<[T]>; -} - -#[cfg(not(no_global_oom_handling))] -impl> ToRcSlice for I { - default fn to_rc_slice(self) -> Rc<[T]> { - self.collect::>().into() - } -} - -#[cfg(not(no_global_oom_handling))] -impl> ToRcSlice for I { - fn to_rc_slice(self) -> Rc<[T]> { - // This is the case for a `TrustedLen` iterator. - let (low, high) = self.size_hint(); - if let Some(high) = high { - debug_assert_eq!( - low, - high, - "TrustedLen iterator's size hint is not exact: {:?}", - (low, high) - ); - - unsafe { - // SAFETY: We need to ensure that the iterator has an exact length and we have. - Rc::from_iter_exact(self, low) - } - } else { - // TrustedLen contract guarantees that `upper_bound == None` implies an iterator - // length exceeding `usize::MAX`. - // The default implementation would collect into a vec which would panic. - // Thus we panic here immediately without invoking `Vec` code. - panic!("capacity overflow"); - } - } -} - -/// `Weak` is a version of [`Rc`] that holds a non-owning reference to the -/// managed allocation. -/// -/// The allocation is accessed by calling [`upgrade`] on the `Weak` -/// pointer, which returns an [Option]<[Rc]\>. -/// -/// Since a `Weak` reference does not count towards ownership, it will not -/// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no -/// guarantees about the value still being present. Thus it may return [`None`] -/// when [`upgrade`]d. Note however that a `Weak` reference *does* prevent the allocation -/// itself (the backing store) from being deallocated. -/// -/// A `Weak` pointer is useful for keeping a temporary reference to the allocation -/// managed by [`Rc`] without preventing its inner value from being dropped. It is also used to -/// prevent circular references between [`Rc`] pointers, since mutual owning references -/// would never allow either [`Rc`] to be dropped. For example, a tree could -/// have strong [`Rc`] pointers from parent nodes to children, and `Weak` -/// pointers from children back to their parents. -/// -/// The typical way to obtain a `Weak` pointer is to call [`Rc::downgrade`]. -/// -/// [`upgrade`]: Weak::upgrade -#[stable(feature = "rc_weak", since = "1.4.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "RcWeak")] -pub struct Weak< - T: ?Sized, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> { - // This is a `NonNull` to allow optimizing the size of this type in enums, - // but it is not necessarily a valid pointer. - // `Weak::new` sets this to `usize::MAX` so that it doesn’t need - // to allocate space on the heap. That's not a value a real pointer - // will ever have because RcInner has alignment at least 2. - // This is only possible when `T: Sized`; unsized `T` never dangle. - ptr: NonNull>, - alloc: A, -} - -#[stable(feature = "rc_weak", since = "1.4.0")] -impl !Send for Weak {} -#[stable(feature = "rc_weak", since = "1.4.0")] -impl !Sync for Weak {} - -#[unstable(feature = "coerce_unsized", issue = "18598")] -impl, U: ?Sized, A: Allocator> CoerceUnsized> for Weak {} - -#[unstable(feature = "dispatch_from_dyn", issue = "none")] -impl, U: ?Sized> DispatchFromDyn> for Weak {} - -impl Weak { - /// Constructs a new `Weak`, without allocating any memory. - /// Calling [`upgrade`] on the return value always gives [`None`]. - /// - /// [`upgrade`]: Weak::upgrade - /// - /// # Examples - /// - /// ``` - /// use std::rc::Weak; - /// - /// let empty: Weak = Weak::new(); - /// assert!(empty.upgrade().is_none()); - /// ``` - #[inline] - #[stable(feature = "downgraded_weak", since = "1.10.0")] - #[rustc_const_stable(feature = "const_weak_new", since = "1.73.0")] - #[must_use] - pub const fn new() -> Weak { - Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc: Global } - } -} - -impl Weak { - /// Constructs a new `Weak`, without allocating any memory, technically in the provided - /// allocator. - /// Calling [`upgrade`] on the return value always gives [`None`]. - /// - /// [`upgrade`]: Weak::upgrade - /// - /// # Examples - /// - /// ``` - /// use std::rc::Weak; - /// - /// let empty: Weak = Weak::new(); - /// assert!(empty.upgrade().is_none()); - /// ``` - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn new_in(alloc: A) -> Weak { - Weak { ptr: NonNull::without_provenance(NonZeroUsize::MAX), alloc } - } -} - -pub(crate) fn is_dangling(ptr: *const T) -> bool { - (ptr.cast::<()>()).addr() == usize::MAX -} - -/// Helper type to allow accessing the reference counts without -/// making any assertions about the data field. -struct WeakInner<'a> { - weak: &'a Cell, - strong: &'a Cell, -} - -impl Weak { - /// Converts a raw pointer previously created by [`into_raw`] back into `Weak`. - /// - /// This can be used to safely get a strong reference (by calling [`upgrade`] - /// later) or to deallocate the weak count by dropping the `Weak`. - /// - /// It takes ownership of one weak reference (with the exception of pointers created by [`new`], - /// as these don't own anything; the method still works on them). - /// - /// # Safety - /// - /// The pointer must have originated from the [`into_raw`] and must still own its potential - /// weak reference, and `ptr` must point to a block of memory allocated by the global allocator. - /// - /// It is allowed for the strong count to be 0 at the time of calling this. Nevertheless, this - /// takes ownership of one weak reference currently represented as a raw pointer (the weak - /// count is not modified by this operation) and therefore it must be paired with a previous - /// call to [`into_raw`]. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let strong = Rc::new("hello".to_owned()); - /// - /// let raw_1 = Rc::downgrade(&strong).into_raw(); - /// let raw_2 = Rc::downgrade(&strong).into_raw(); - /// - /// assert_eq!(2, Rc::weak_count(&strong)); - /// - /// assert_eq!("hello", &*unsafe { Weak::from_raw(raw_1) }.upgrade().unwrap()); - /// assert_eq!(1, Rc::weak_count(&strong)); - /// - /// drop(strong); - /// - /// // Decrement the last weak count. - /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none()); - /// ``` - /// - /// [`into_raw`]: Weak::into_raw - /// [`upgrade`]: Weak::upgrade - /// [`new`]: Weak::new - #[inline] - #[stable(feature = "weak_into_raw", since = "1.45.0")] - pub unsafe fn from_raw(ptr: *const T) -> Self { - unsafe { Self::from_raw_in(ptr, Global) } - } -} - -impl Weak { - /// Returns a reference to the underlying allocator. - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn allocator(&self) -> &A { - &self.alloc - } - - /// Returns a raw pointer to the object `T` pointed to by this `Weak`. - /// - /// The pointer is valid only if there are some strong references. The pointer may be dangling, - /// unaligned or even [`null`] otherwise. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// use std::ptr; - /// - /// let strong = Rc::new("hello".to_owned()); - /// let weak = Rc::downgrade(&strong); - /// // Both point to the same object - /// assert!(ptr::eq(&*strong, weak.as_ptr())); - /// // The strong here keeps it alive, so we can still access the object. - /// assert_eq!("hello", unsafe { &*weak.as_ptr() }); - /// - /// drop(strong); - /// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to - /// // undefined behavior. - /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); - /// ``` - /// - /// [`null`]: ptr::null - #[must_use] - #[stable(feature = "rc_as_ptr", since = "1.45.0")] - pub fn as_ptr(&self) -> *const T { - let ptr: *mut RcInner = NonNull::as_ptr(self.ptr); - - if is_dangling(ptr) { - // If the pointer is dangling, we return the sentinel directly. This cannot be - // a valid payload address, as the payload is at least as aligned as RcInner (usize). - ptr as *const T - } else { - // SAFETY: if is_dangling returns false, then the pointer is dereferenceable. - // The payload may be dropped at this point, and we have to maintain provenance, - // so use raw pointer manipulation. - unsafe { &raw mut (*ptr).value } - } - } - - /// Consumes the `Weak` and turns it into a raw pointer. - /// - /// This converts the weak pointer into a raw pointer, while still preserving the ownership of - /// one weak reference (the weak count is not modified by this operation). It can be turned - /// back into the `Weak` with [`from_raw`]. - /// - /// The same restrictions of accessing the target of the pointer as with - /// [`as_ptr`] apply. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let strong = Rc::new("hello".to_owned()); - /// let weak = Rc::downgrade(&strong); - /// let raw = weak.into_raw(); - /// - /// assert_eq!(1, Rc::weak_count(&strong)); - /// assert_eq!("hello", unsafe { &*raw }); - /// - /// drop(unsafe { Weak::from_raw(raw) }); - /// assert_eq!(0, Rc::weak_count(&strong)); - /// ``` - /// - /// [`from_raw`]: Weak::from_raw - /// [`as_ptr`]: Weak::as_ptr - #[must_use = "losing the pointer will leak memory"] - #[stable(feature = "weak_into_raw", since = "1.45.0")] - pub fn into_raw(self) -> *const T { - mem::ManuallyDrop::new(self).as_ptr() - } - - /// Consumes the `Weak`, returning the wrapped pointer and allocator. - /// - /// This converts the weak pointer into a raw pointer, while still preserving the ownership of - /// one weak reference (the weak count is not modified by this operation). It can be turned - /// back into the `Weak` with [`from_raw_in`]. - /// - /// The same restrictions of accessing the target of the pointer as with - /// [`as_ptr`] apply. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// use std::rc::{Rc, Weak}; - /// use std::alloc::System; - /// - /// let strong = Rc::new_in("hello".to_owned(), System); - /// let weak = Rc::downgrade(&strong); - /// let (raw, alloc) = weak.into_raw_with_allocator(); - /// - /// assert_eq!(1, Rc::weak_count(&strong)); - /// assert_eq!("hello", unsafe { &*raw }); - /// - /// drop(unsafe { Weak::from_raw_in(raw, alloc) }); - /// assert_eq!(0, Rc::weak_count(&strong)); - /// ``` - /// - /// [`from_raw_in`]: Weak::from_raw_in - /// [`as_ptr`]: Weak::as_ptr - #[must_use = "losing the pointer will leak memory"] - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn into_raw_with_allocator(self) -> (*const T, A) { - let this = mem::ManuallyDrop::new(self); - let result = this.as_ptr(); - // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped - let alloc = unsafe { ptr::read(&this.alloc) }; - (result, alloc) - } - - /// Converts a raw pointer previously created by [`into_raw`] back into `Weak`. - /// - /// This can be used to safely get a strong reference (by calling [`upgrade`] - /// later) or to deallocate the weak count by dropping the `Weak`. - /// - /// It takes ownership of one weak reference (with the exception of pointers created by [`new`], - /// as these don't own anything; the method still works on them). - /// - /// # Safety - /// - /// The pointer must have originated from the [`into_raw`] and must still own its potential - /// weak reference, and `ptr` must point to a block of memory allocated by `alloc`. - /// - /// It is allowed for the strong count to be 0 at the time of calling this. Nevertheless, this - /// takes ownership of one weak reference currently represented as a raw pointer (the weak - /// count is not modified by this operation) and therefore it must be paired with a previous - /// call to [`into_raw`]. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let strong = Rc::new("hello".to_owned()); - /// - /// let raw_1 = Rc::downgrade(&strong).into_raw(); - /// let raw_2 = Rc::downgrade(&strong).into_raw(); - /// - /// assert_eq!(2, Rc::weak_count(&strong)); - /// - /// assert_eq!("hello", &*unsafe { Weak::from_raw(raw_1) }.upgrade().unwrap()); - /// assert_eq!(1, Rc::weak_count(&strong)); - /// - /// drop(strong); - /// - /// // Decrement the last weak count. - /// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none()); - /// ``` - /// - /// [`into_raw`]: Weak::into_raw - /// [`upgrade`]: Weak::upgrade - /// [`new`]: Weak::new - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { - // See Weak::as_ptr for context on how the input pointer is derived. - - let ptr = if is_dangling(ptr) { - // This is a dangling Weak. - ptr as *mut RcInner - } else { - // Otherwise, we're guaranteed the pointer came from a nondangling Weak. - // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. - let offset = unsafe { data_offset(ptr) }; - // Thus, we reverse the offset to get the whole RcInner. - // SAFETY: the pointer originated from a Weak, so this offset is safe. - unsafe { ptr.byte_sub(offset) as *mut RcInner } - }; - - // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. - Weak { ptr: unsafe { NonNull::new_unchecked(ptr) }, alloc } - } - - /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying - /// dropping of the inner value if successful. - /// - /// Returns [`None`] if the inner value has since been dropped. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let five = Rc::new(5); - /// - /// let weak_five = Rc::downgrade(&five); - /// - /// let strong_five: Option> = weak_five.upgrade(); - /// assert!(strong_five.is_some()); - /// - /// // Destroy all strong pointers. - /// drop(strong_five); - /// drop(five); - /// - /// assert!(weak_five.upgrade().is_none()); - /// ``` - #[must_use = "this returns a new `Rc`, \ - without modifying the original weak pointer"] - #[stable(feature = "rc_weak", since = "1.4.0")] - pub fn upgrade(&self) -> Option> - where - A: Clone, - { - let inner = self.inner()?; - - if inner.strong() == 0 { - None - } else { - unsafe { - inner.inc_strong(); - Some(Rc::from_inner_in(self.ptr, self.alloc.clone())) - } - } - } - - /// Gets the number of strong (`Rc`) pointers pointing to this allocation. - /// - /// If `self` was created using [`Weak::new`], this will return 0. - #[must_use] - #[stable(feature = "weak_counts", since = "1.41.0")] - pub fn strong_count(&self) -> usize { - if let Some(inner) = self.inner() { inner.strong() } else { 0 } - } - - /// Gets the number of `Weak` pointers pointing to this allocation. - /// - /// If no strong pointers remain, this will return zero. - #[must_use] - #[stable(feature = "weak_counts", since = "1.41.0")] - pub fn weak_count(&self) -> usize { - if let Some(inner) = self.inner() { - if inner.strong() > 0 { - inner.weak() - 1 // subtract the implicit weak ptr - } else { - 0 - } - } else { - 0 - } - } - - /// Returns `None` when the pointer is dangling and there is no allocated `RcInner`, - /// (i.e., when this `Weak` was created by `Weak::new`). - #[inline] - fn inner(&self) -> Option> { - if is_dangling(self.ptr.as_ptr()) { - None - } else { - // We are careful to *not* create a reference covering the "data" field, as - // the field may be mutated concurrently (for example, if the last `Rc` - // is dropped, the data field will be dropped in-place). - Some(unsafe { - let ptr = self.ptr.as_ptr(); - WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } - }) - } - } - - /// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if - /// both don't point to any allocation (because they were created with `Weak::new()`). However, - /// this function ignores the metadata of `dyn Trait` pointers. - /// - /// # Notes - /// - /// Since this compares pointers it means that `Weak::new()` will equal each - /// other, even though they don't point to any allocation. - /// - /// # Examples - /// - /// ``` - /// use std::rc::Rc; - /// - /// let first_rc = Rc::new(5); - /// let first = Rc::downgrade(&first_rc); - /// let second = Rc::downgrade(&first_rc); - /// - /// assert!(first.ptr_eq(&second)); - /// - /// let third_rc = Rc::new(5); - /// let third = Rc::downgrade(&third_rc); - /// - /// assert!(!first.ptr_eq(&third)); - /// ``` - /// - /// Comparing `Weak::new`. - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let first = Weak::new(); - /// let second = Weak::new(); - /// assert!(first.ptr_eq(&second)); - /// - /// let third_rc = Rc::new(()); - /// let third = Rc::downgrade(&third_rc); - /// assert!(!first.ptr_eq(&third)); - /// ``` - #[inline] - #[must_use] - #[stable(feature = "weak_ptr_eq", since = "1.39.0")] - pub fn ptr_eq(&self, other: &Self) -> bool { - ptr::addr_eq(self.ptr.as_ptr(), other.ptr.as_ptr()) - } -} - -#[stable(feature = "rc_weak", since = "1.4.0")] -unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Weak { - /// Drops the `Weak` pointer. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// struct Foo; - /// - /// impl Drop for Foo { - /// fn drop(&mut self) { - /// println!("dropped!"); - /// } - /// } - /// - /// let foo = Rc::new(Foo); - /// let weak_foo = Rc::downgrade(&foo); - /// let other_weak_foo = Weak::clone(&weak_foo); - /// - /// drop(weak_foo); // Doesn't print anything - /// drop(foo); // Prints "dropped!" - /// - /// assert!(other_weak_foo.upgrade().is_none()); - /// ``` - fn drop(&mut self) { - let inner = if let Some(inner) = self.inner() { inner } else { return }; - - inner.dec_weak(); - // the weak count starts at 1, and will only go to zero if all - // the strong pointers have disappeared. - if inner.weak() == 0 { - unsafe { - self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); - } - } - } -} - -#[stable(feature = "rc_weak", since = "1.4.0")] -impl Clone for Weak { - /// Makes a clone of the `Weak` pointer that points to the same allocation. - /// - /// # Examples - /// - /// ``` - /// use std::rc::{Rc, Weak}; - /// - /// let weak_five = Rc::downgrade(&Rc::new(5)); - /// - /// let _ = Weak::clone(&weak_five); - /// ``` - #[inline] - fn clone(&self) -> Weak { - if let Some(inner) = self.inner() { - inner.inc_weak() - } - Weak { ptr: self.ptr, alloc: self.alloc.clone() } - } -} - -#[stable(feature = "rc_weak", since = "1.4.0")] -impl fmt::Debug for Weak { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "(Weak)") - } -} - -#[stable(feature = "downgraded_weak", since = "1.10.0")] -impl Default for Weak { - /// Constructs a new `Weak`, without allocating any memory. - /// Calling [`upgrade`] on the return value always gives [`None`]. - /// - /// [`upgrade`]: Weak::upgrade - /// - /// # Examples - /// - /// ``` - /// use std::rc::Weak; - /// - /// let empty: Weak = Default::default(); - /// assert!(empty.upgrade().is_none()); - /// ``` - fn default() -> Weak { - Weak::new() - } -} - -// NOTE: We checked_add here to deal with mem::forget safely. In particular -// if you mem::forget Rcs (or Weaks), the ref-count can overflow, and then -// you can free the allocation while outstanding Rcs (or Weaks) exist. -// We abort because this is such a degenerate scenario that we don't care about -// what happens -- no real program should ever experience this. -// -// This should have negligible overhead since you don't actually need to -// clone these much in Rust thanks to ownership and move-semantics. - -#[doc(hidden)] -trait RcInnerPtr { - fn weak_ref(&self) -> &Cell; - fn strong_ref(&self) -> &Cell; - - #[inline] - fn strong(&self) -> usize { - self.strong_ref().get() - } - - #[inline] - fn inc_strong(&self) { - let strong = self.strong(); - - // We insert an `assume` here to hint LLVM at an otherwise - // missed optimization. - // SAFETY: The reference count will never be zero when this is - // called. - unsafe { - hint::assert_unchecked(strong != 0); - } - - let strong = strong.wrapping_add(1); - self.strong_ref().set(strong); - - // We want to abort on overflow instead of dropping the value. - // Checking for overflow after the store instead of before - // allows for slightly better code generation. - if core::intrinsics::unlikely(strong == 0) { - abort(); - } - } - - #[inline] - fn dec_strong(&self) { - self.strong_ref().set(self.strong() - 1); - } - - #[inline] - fn weak(&self) -> usize { - self.weak_ref().get() - } - - #[inline] - fn inc_weak(&self) { - let weak = self.weak(); - - // We insert an `assume` here to hint LLVM at an otherwise - // missed optimization. - // SAFETY: The reference count will never be zero when this is - // called. - unsafe { - hint::assert_unchecked(weak != 0); - } - - let weak = weak.wrapping_add(1); - self.weak_ref().set(weak); - - // We want to abort on overflow instead of dropping the value. - // Checking for overflow after the store instead of before - // allows for slightly better code generation. - if core::intrinsics::unlikely(weak == 0) { - abort(); - } - } - - #[inline] - fn dec_weak(&self) { - self.weak_ref().set(self.weak() - 1); - } -} - -impl RcInnerPtr for RcInner { - #[inline(always)] - fn weak_ref(&self) -> &Cell { - &self.weak - } - - #[inline(always)] - fn strong_ref(&self) -> &Cell { - &self.strong - } -} - -impl<'a> RcInnerPtr for WeakInner<'a> { - #[inline(always)] - fn weak_ref(&self) -> &Cell { - self.weak - } - - #[inline(always)] - fn strong_ref(&self) -> &Cell { - self.strong - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl borrow::Borrow for Rc { - fn borrow(&self) -> &T { - &**self - } -} - -#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] -impl AsRef for Rc { - fn as_ref(&self) -> &T { - &**self - } -} - -#[stable(feature = "pin", since = "1.33.0")] -impl Unpin for Rc {} - -/// Gets the offset within an `RcInner` for the payload behind a pointer. -/// -/// # Safety -/// -/// The pointer must point to (and have valid metadata for) a previously -/// valid instance of T, but the T is allowed to be dropped. -unsafe fn data_offset(ptr: *const T) -> usize { - // Align the unsized value to the end of the RcInner. - // Because RcInner is repr(C), it will always be the last field in memory. - // SAFETY: since the only unsized types possible are slices, trait objects, - // and extern types, the input safety requirement is currently enough to - // satisfy the requirements of align_of_val_raw; this is an implementation - // detail of the language that must not be relied upon outside of std. - unsafe { data_offset_align(align_of_val_raw(ptr)) } -} - -#[inline] -fn data_offset_align(align: usize) -> usize { - let layout = Layout::new::>(); - layout.size() + layout.padding_needed_for(align) -} - -/// A uniquely owned [`Rc`]. -/// -/// This represents an `Rc` that is known to be uniquely owned -- that is, have exactly one strong -/// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong -/// references will fail unless the `UniqueRc` they point to has been converted into a regular `Rc`. -/// -/// Because they are uniquely owned, the contents of a `UniqueRc` can be freely mutated. A common -/// use case is to have an object be mutable during its initialization phase but then have it become -/// immutable and converted to a normal `Rc`. -/// -/// This can be used as a flexible way to create cyclic data structures, as in the example below. -/// -/// ``` -/// #![feature(unique_rc_arc)] -/// use std::rc::{Rc, Weak, UniqueRc}; -/// -/// struct Gadget { -/// #[allow(dead_code)] -/// me: Weak, -/// } -/// -/// fn create_gadget() -> Option> { -/// let mut rc = UniqueRc::new(Gadget { -/// me: Weak::new(), -/// }); -/// rc.me = UniqueRc::downgrade(&rc); -/// Some(UniqueRc::into_rc(rc)) -/// } -/// -/// create_gadget().unwrap(); -/// ``` -/// -/// An advantage of using `UniqueRc` over [`Rc::new_cyclic`] to build cyclic data structures is that -/// [`Rc::new_cyclic`]'s `data_fn` parameter cannot be async or return a [`Result`]. As shown in the -/// previous example, `UniqueRc` allows for more flexibility in the construction of cyclic data, -/// including fallible or async constructors. -#[unstable(feature = "unique_rc_arc", issue = "112566")] -pub struct UniqueRc< - T: ?Sized, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> { - ptr: NonNull>, - // Define the ownership of `RcInner` for drop-check - _marker: PhantomData>, - // Invariance is necessary for soundness: once other `Weak` - // references exist, we already have a form of shared mutability! - _marker2: PhantomData<*mut T>, - alloc: A, -} - -// Not necessary for correctness since `UniqueRc` contains `NonNull`, -// but having an explicit negative impl is nice for documentation purposes -// and results in nicer error messages. -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl !Send for UniqueRc {} - -// Not necessary for correctness since `UniqueRc` contains `NonNull`, -// but having an explicit negative impl is nice for documentation purposes -// and results in nicer error messages. -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl !Sync for UniqueRc {} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl, U: ?Sized, A: Allocator> CoerceUnsized> - for UniqueRc -{ -} - -//#[unstable(feature = "unique_rc_arc", issue = "112566")] -#[unstable(feature = "dispatch_from_dyn", issue = "none")] -impl, U: ?Sized> DispatchFromDyn> for UniqueRc {} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl fmt::Display for UniqueRc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl fmt::Debug for UniqueRc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl fmt::Pointer for UniqueRc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&(&raw const **self), f) - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl borrow::Borrow for UniqueRc { - fn borrow(&self) -> &T { - &**self - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl borrow::BorrowMut for UniqueRc { - fn borrow_mut(&mut self) -> &mut T { - &mut **self - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl AsRef for UniqueRc { - fn as_ref(&self) -> &T { - &**self - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl AsMut for UniqueRc { - fn as_mut(&mut self) -> &mut T { - &mut **self - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Unpin for UniqueRc {} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl PartialEq for UniqueRc { - /// Equality for two `UniqueRc`s. - /// - /// Two `UniqueRc`s are equal if their inner values are equal. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five == UniqueRc::new(5)); - /// ``` - #[inline] - fn eq(&self, other: &Self) -> bool { - PartialEq::eq(&**self, &**other) - } - - /// Inequality for two `UniqueRc`s. - /// - /// Two `UniqueRc`s are not equal if their inner values are not equal. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five != UniqueRc::new(6)); - /// ``` - #[inline] - fn ne(&self, other: &Self) -> bool { - PartialEq::ne(&**self, &**other) - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl PartialOrd for UniqueRc { - /// Partial comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `partial_cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// use std::cmp::Ordering; - /// - /// let five = UniqueRc::new(5); - /// - /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&UniqueRc::new(6))); - /// ``` - #[inline(always)] - fn partial_cmp(&self, other: &UniqueRc) -> Option { - (**self).partial_cmp(&**other) - } - - /// Less-than comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `<` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five < UniqueRc::new(6)); - /// ``` - #[inline(always)] - fn lt(&self, other: &UniqueRc) -> bool { - **self < **other - } - - /// 'Less than or equal to' comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `<=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five <= UniqueRc::new(5)); - /// ``` - #[inline(always)] - fn le(&self, other: &UniqueRc) -> bool { - **self <= **other - } - - /// Greater-than comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `>` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five > UniqueRc::new(4)); - /// ``` - #[inline(always)] - fn gt(&self, other: &UniqueRc) -> bool { - **self > **other - } - - /// 'Greater than or equal to' comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `>=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// - /// let five = UniqueRc::new(5); - /// - /// assert!(five >= UniqueRc::new(5)); - /// ``` - #[inline(always)] - fn ge(&self, other: &UniqueRc) -> bool { - **self >= **other - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Ord for UniqueRc { - /// Comparison for two `UniqueRc`s. - /// - /// The two are compared by calling `cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// #![feature(unique_rc_arc)] - /// use std::rc::UniqueRc; - /// use std::cmp::Ordering; - /// - /// let five = UniqueRc::new(5); - /// - /// assert_eq!(Ordering::Less, five.cmp(&UniqueRc::new(6))); - /// ``` - #[inline] - fn cmp(&self, other: &UniqueRc) -> Ordering { - (**self).cmp(&**other) - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Eq for UniqueRc {} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Hash for UniqueRc { - fn hash(&self, state: &mut H) { - (**self).hash(state); - } -} - -// Depends on A = Global -impl UniqueRc { - /// Creates a new `UniqueRc`. - /// - /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading - /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. - /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will - /// point to the new [`Rc`]. - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn new(value: T) -> Self { - Self::new_in(value, Global) - } -} - -impl UniqueRc { - /// Creates a new `UniqueRc` in the provided allocator. - /// - /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading - /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. - /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will - /// point to the new [`Rc`]. - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn new_in(value: T, alloc: A) -> Self { - let (ptr, alloc) = Box::into_unique(Box::new_in( - RcInner { - strong: Cell::new(0), - // keep one weak reference so if all the weak pointers that are created are dropped - // the UniqueRc still stays valid. - weak: Cell::new(1), - value, - }, - alloc, - )); - Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc } - } -} - -impl UniqueRc { - /// Converts the `UniqueRc` into a regular [`Rc`]. - /// - /// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that - /// is passed to `into_rc`. - /// - /// Any weak references created before this method is called can now be upgraded to strong - /// references. - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn into_rc(this: Self) -> Rc { - let mut this = ManuallyDrop::new(this); - - // Move the allocator out. - // SAFETY: `this.alloc` will not be accessed again, nor dropped because it is in - // a `ManuallyDrop`. - let alloc: A = unsafe { ptr::read(&this.alloc) }; - - // SAFETY: This pointer was allocated at creation time so we know it is valid. - unsafe { - // Convert our weak reference into a strong reference - this.ptr.as_mut().strong.set(1); - Rc::from_inner_in(this.ptr, alloc) - } - } -} - -impl UniqueRc { - /// Creates a new weak reference to the `UniqueRc`. - /// - /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted - /// to a [`Rc`] using [`UniqueRc::into_rc`]. - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn downgrade(this: &Self) -> Weak { - // SAFETY: This pointer was allocated at creation time and we guarantee that we only have - // one strong reference before converting to a regular Rc. - unsafe { - this.ptr.as_ref().inc_weak(); - } - Weak { ptr: this.ptr, alloc: this.alloc.clone() } - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Deref for UniqueRc { - type Target = T; - - fn deref(&self) -> &T { - // SAFETY: This pointer was allocated at creation time so we know it is valid. - unsafe { &self.ptr.as_ref().value } - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -impl DerefMut for UniqueRc { - fn deref_mut(&mut self) -> &mut T { - // SAFETY: This pointer was allocated at creation time so we know it is valid. We know we - // have unique ownership and therefore it's safe to make a mutable reference because - // `UniqueRc` owns the only strong reference to itself. - unsafe { &mut (*self.ptr.as_ptr()).value } - } -} - -#[unstable(feature = "unique_rc_arc", issue = "112566")] -unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc { - fn drop(&mut self) { - unsafe { - // destroy the contained object - drop_in_place(DerefMut::deref_mut(self)); - - // remove the implicit "strong weak" pointer now that we've destroyed the contents. - self.ptr.as_ref().dec_weak(); - - if self.ptr.as_ref().weak() == 0 { - self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); - } - } - } -} - -/// A unique owning pointer to a [`RcInner`] **that does not imply the contents are initialized,** -/// but will deallocate it (without dropping the value) when dropped. -/// -/// This is a helper for [`Rc::make_mut()`] to ensure correct cleanup on panic. -/// It is nearly a duplicate of `UniqueRc, A>` except that it allows `T: !Sized`, -/// which `MaybeUninit` does not. -#[cfg(not(no_global_oom_handling))] -struct UniqueRcUninit { - ptr: NonNull>, - layout_for_value: Layout, - alloc: Option, -} - -#[cfg(not(no_global_oom_handling))] -impl UniqueRcUninit { - /// Allocates a RcInner with layout suitable to contain `for_value` or a clone of it. - fn new(for_value: &T, alloc: A) -> UniqueRcUninit { - let layout = Layout::for_value(for_value); - let ptr = unsafe { - Rc::allocate_for_layout( - layout, - |layout_for_rc_inner| alloc.allocate(layout_for_rc_inner), - |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcInner), - ) - }; - Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) } - } - - /// Returns the pointer to be written into to initialize the [`Rc`]. - fn data_ptr(&mut self) -> *mut T { - let offset = data_offset_align(self.layout_for_value.align()); - unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } - } - - /// Upgrade this into a normal [`Rc`]. - /// - /// # Safety - /// - /// The data must have been initialized (by writing to [`Self::data_ptr()`]). - unsafe fn into_rc(self) -> Rc { - let mut this = ManuallyDrop::new(self); - let ptr = this.ptr; - let alloc = this.alloc.take().unwrap(); - - // SAFETY: The pointer is valid as per `UniqueRcUninit::new`, and the caller is responsible - // for having initialized the data. - unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) } - } -} - -#[cfg(not(no_global_oom_handling))] -impl Drop for UniqueRcUninit { - fn drop(&mut self) { - // SAFETY: - // * new() produced a pointer safe to deallocate. - // * We own the pointer unless into_rc() was called, which forgets us. - unsafe { - self.alloc.take().unwrap().deallocate( - self.ptr.cast(), - rc_inner_layout_for_value_layout(self.layout_for_value), - ); - } - } -} diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs deleted file mode 100644 index 35ff6b7d570..00000000000 --- a/library/alloc/src/rc/tests.rs +++ /dev/null @@ -1,15 +0,0 @@ -use super::*; - -#[test] -fn is_unique() { - let x = Rc::new(3); - assert!(Rc::is_unique(&x)); - let y = x.clone(); - assert!(!Rc::is_unique(&x)); - drop(y); - assert!(Rc::is_unique(&x)); - let w = Rc::downgrade(&x); - assert!(!Rc::is_unique(&x)); - drop(w); - assert!(Rc::is_unique(&x)); -} diff --git a/library/alloctests/tests/rc.rs b/library/alloctests/tests/rc.rs index 0628011ba68..bb68eb4ac9e 100644 --- a/library/alloctests/tests/rc.rs +++ b/library/alloctests/tests/rc.rs @@ -315,6 +315,24 @@ fn weak_self_cyclic() { // hopefully we don't double-free (or leak)... } +#[test] +fn is_unique() { + fn is_unique(this: &Rc) -> bool { + Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 + } + + let x = Rc::new(3); + assert!(is_unique(&x)); + let y = x.clone(); + assert!(!is_unique(&x)); + drop(y); + assert!(is_unique(&x)); + let w = Rc::downgrade(&x); + assert!(!is_unique(&x)); + drop(w); + assert!(is_unique(&x)); +} + #[test] fn test_strong_count() { let a = Rc::new(0); -- cgit 1.4.1-3-g733a5 From ae5687e4b0a375d3307856fb81810f6cc9019be5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Feb 2025 12:46:33 +0000 Subject: Fully test the alloc crate through alloctests For the tests that make use of internal implementation details, we include the module to test using #[path] in alloctests now. --- ...Disable-f16-and-f128-in-compiler-builtins.patch | 6 +- library/Cargo.lock | 2 - library/alloc/Cargo.toml | 8 +- library/alloc/src/alloc.rs | 18 +- library/alloc/src/borrow.rs | 6 +- library/alloc/src/bstr.rs | 20 --- library/alloc/src/collections/binary_heap/mod.rs | 5 +- library/alloc/src/collections/mod.rs | 21 +++ library/alloc/src/collections/vec_deque/mod.rs | 1 + .../alloc/src/collections/vec_deque/spec_extend.rs | 2 + .../src/collections/vec_deque/spec_from_iter.rs | 1 + library/alloc/src/ffi/c_str.rs | 16 +- library/alloc/src/lib.rs | 39 +---- library/alloc/src/macros.rs | 23 +-- library/alloc/src/raw_vec/mod.rs | 1 + library/alloc/src/rc.rs | 7 +- library/alloc/src/slice.rs | 182 ++++++++------------- library/alloc/src/str.rs | 3 - library/alloc/src/string.rs | 30 +--- library/alloc/src/sync.rs | 4 +- library/alloc/src/testing/crash_test.rs | 120 -------------- library/alloc/src/testing/mod.rs | 3 - library/alloc/src/testing/ord_chaos.rs | 81 --------- library/alloc/src/testing/rng.rs | 28 ---- library/alloc/src/vec/into_iter.rs | 5 - library/alloc/src/vec/mod.rs | 47 +----- library/alloctests/Cargo.toml | 5 +- library/alloctests/lib.rs | 91 ++++++++++- library/alloctests/testing/crash_test.rs | 120 ++++++++++++++ library/alloctests/testing/mod.rs | 3 + library/alloctests/testing/ord_chaos.rs | 81 +++++++++ library/alloctests/testing/rng.rs | 28 ++++ 32 files changed, 464 insertions(+), 543 deletions(-) delete mode 100644 library/alloc/src/testing/crash_test.rs delete mode 100644 library/alloc/src/testing/mod.rs delete mode 100644 library/alloc/src/testing/ord_chaos.rs delete mode 100644 library/alloc/src/testing/rng.rs create mode 100644 library/alloctests/testing/crash_test.rs create mode 100644 library/alloctests/testing/mod.rs create mode 100644 library/alloctests/testing/ord_chaos.rs create mode 100644 library/alloctests/testing/rng.rs diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index c2027863b00..754025ff49d 100644 --- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -12,15 +12,15 @@ index 7165c3e48af..968552ad435 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -11,7 +11,7 @@ test = { path = "../test" } - edition = "2021" + bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] } - [dev-dependencies] - rand = { version = "0.8.5", default-features = false, features = ["alloc"] } + [features] + compiler-builtins-mem = ['compiler_builtins/mem'] -- 2.34.1 diff --git a/library/Cargo.lock b/library/Cargo.lock index bdf50a5b383..405c69d9568 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -30,8 +30,6 @@ version = "0.0.0" dependencies = [ "compiler_builtins", "core", - "rand", - "rand_xorshift", ] [[package]] diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index d9e1c9b38a8..dbdf292433b 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,14 +10,14 @@ autotests = false autobenches = false edition = "2021" +[lib] +test = false +bench = false + [dependencies] core = { path = "../core", public = true } compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } -[dev-dependencies] -rand = { version = "0.9.0", default-features = false, features = ["alloc"] } -rand_xorshift = "0.4.0" - [features] compiler-builtins-mem = ['compiler_builtins/mem'] compiler-builtins-c = ["compiler_builtins/c"] diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 3bfdc68dcda..2f752f6eb39 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -5,9 +5,7 @@ #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] pub use core::alloc::*; -#[cfg(not(test))] use core::hint; -#[cfg(not(test))] use core::ptr::{self, NonNull}; unsafe extern "Rust" { @@ -44,14 +42,10 @@ unsafe extern "Rust" { /// accessed through the [free functions in `alloc`](self#functions). #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] -#[cfg(not(test))] // the compiler needs to know when a Box uses the global allocator vs a custom one #[lang = "global_alloc_ty"] pub struct Global; -#[cfg(test)] -pub use std::alloc::Global; - /// Allocates memory with the global allocator. /// /// This function forwards calls to the [`GlobalAlloc::alloc`] method @@ -180,7 +174,6 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { } } -#[cfg(not(test))] impl Global { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -246,7 +239,6 @@ impl Global { } #[unstable(feature = "allocator_api", issue = "32838")] -#[cfg(not(test))] unsafe impl Allocator for Global { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -346,7 +338,7 @@ unsafe impl Allocator for Global { } /// The allocator for `Box`. -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[lang = "exchange_malloc"] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -395,7 +387,7 @@ unsafe extern "Rust" { /// [no_std]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute #[stable(feature = "global_alloc", since = "1.28.0")] #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")] -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[cold] #[optimize(size)] pub const fn handle_alloc_error(layout: Layout) -> ! { @@ -419,11 +411,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! { ct_error(layout) } -// For alloc test `std::alloc::handle_alloc_error` can be used directly. -#[cfg(all(not(no_global_oom_handling), test))] -pub use std::alloc::handle_alloc_error; - -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[doc(hidden)] #[allow(unused_attributes)] #[unstable(feature = "alloc_internals", issue = "none")] diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 17dad3277b9..07f51b7614f 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -32,7 +32,7 @@ where /// implementing the `Clone` trait. But `Clone` works only for going from `&T` /// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data /// from any borrow of a given type. -#[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")] +#[rustc_diagnostic_item = "ToOwned"] #[stable(feature = "rust1", since = "1.0.0")] pub trait ToOwned { /// The resulting type after obtaining ownership. @@ -54,7 +54,7 @@ pub trait ToOwned { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "cloning is often expensive and is not expected to have side effects"] - #[cfg_attr(not(test), rustc_diagnostic_item = "to_owned_method")] + #[rustc_diagnostic_item = "to_owned_method"] fn to_owned(&self) -> Self::Owned; /// Uses borrowed data to replace owned data, usually by cloning. @@ -175,7 +175,7 @@ where /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Cow")] +#[rustc_diagnostic_item = "Cow"] pub enum Cow<'a, B: ?Sized + 'a> where B: ToOwned, diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs index 61e61019b50..338c7ac7f88 100644 --- a/library/alloc/src/bstr.rs +++ b/library/alloc/src/bstr.rs @@ -12,13 +12,10 @@ use core::ops::{ Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, }; -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use core::str::FromStr; use core::{fmt, hash}; -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::borrow::{Cow, ToOwned}; -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::boxed::Box; #[cfg(not(no_rc))] use crate::rc::Rc; @@ -181,7 +178,6 @@ impl Default for ByteString { // Omitted due to inference failures // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { // #[inline] @@ -190,7 +186,6 @@ impl Default for ByteString { // } // } // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl From<[u8; N]> for ByteString { // #[inline] @@ -199,7 +194,6 @@ impl Default for ByteString { // } // } // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl<'a> From<&'a [u8]> for ByteString { // #[inline] @@ -226,7 +220,6 @@ impl From for Vec { // Omitted due to inference failures // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl<'a> From<&'a str> for ByteString { // #[inline] @@ -243,7 +236,6 @@ impl From for Vec { // } // } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteStr> for ByteString { #[inline] @@ -252,7 +244,6 @@ impl<'a> From<&'a ByteStr> for ByteString { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From for Cow<'a, ByteStr> { #[inline] @@ -261,7 +252,6 @@ impl<'a> From for Cow<'a, ByteStr> { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> { #[inline] @@ -330,7 +320,6 @@ impl FromIterator for ByteString { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl FromStr for ByteString { type Err = core::convert::Infallible; @@ -488,7 +477,6 @@ impl PartialEq for ByteString { macro_rules! impl_partial_eq_ord_cow { ($lhs:ty, $rhs:ty) => { - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialEq<$rhs> for $lhs { @@ -499,7 +487,6 @@ macro_rules! impl_partial_eq_ord_cow { } } - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialEq<$lhs> for $rhs { @@ -510,7 +497,6 @@ macro_rules! impl_partial_eq_ord_cow { } } - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialOrd<$rhs> for $lhs { @@ -521,7 +507,6 @@ macro_rules! impl_partial_eq_ord_cow { } } - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialOrd<$lhs> for $rhs { @@ -572,7 +557,6 @@ impl PartialOrd for ByteString { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl ToOwned for ByteStr { type Owned = ByteString; @@ -605,7 +589,6 @@ impl<'a> TryFrom<&'a ByteString> for &'a str { // Additional impls for `ByteStr` that require types from `alloc`: -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl Clone for Box { #[inline] @@ -614,7 +597,6 @@ impl Clone for Box { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { #[inline] @@ -623,7 +605,6 @@ impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl From> for Box { #[inline] @@ -633,7 +614,6 @@ impl From> for Box { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl From> for Box<[u8]> { #[inline] diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 965fd63a529..b764b8fa5d9 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -153,7 +153,9 @@ use core::{fmt, ptr}; use crate::alloc::Global; use crate::collections::TryReserveError; use crate::slice; -use crate::vec::{self, AsVecIntoIter, Vec}; +#[cfg(not(test))] +use crate::vec::AsVecIntoIter; +use crate::vec::{self, Vec}; /// A priority queue implemented with a binary heap. /// @@ -1600,6 +1602,7 @@ unsafe impl InPlaceIterable for IntoIter { const MERGE_BY: Option> = NonZero::new(1); } +#[cfg(not(test))] unsafe impl AsVecIntoIter for IntoIter { type Item = I; diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 020cf4d7365..1414f797e8a 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -24,41 +24,54 @@ pub mod btree_map { pub mod btree_set { //! An ordered set based on a B-Tree. #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(test))] pub use super::btree::set::*; } +#[cfg(not(test))] use core::fmt::Display; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use binary_heap::BinaryHeap; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use btree_map::BTreeMap; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use btree_set::BTreeSet; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use linked_list::LinkedList; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use vec_deque::VecDeque; +#[cfg(not(test))] use crate::alloc::{Layout, LayoutError}; /// The error type for `try_reserve` methods. #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "try_reserve", since = "1.57.0")] +#[cfg(not(test))] pub struct TryReserveError { kind: TryReserveErrorKind, } +#[cfg(test)] +pub use realalloc::collections::TryReserveError; + +#[cfg(not(test))] impl TryReserveError { /// Details about the allocation that caused the error #[inline] @@ -80,6 +93,7 @@ impl TryReserveError { reason = "Uncertain how much info should be exposed", issue = "48043" )] +#[cfg(not(test))] pub enum TryReserveErrorKind { /// Error due to the computed capacity exceeding the collection's maximum /// (usually `isize::MAX` bytes). @@ -103,11 +117,15 @@ pub enum TryReserveErrorKind { }, } +#[cfg(test)] +pub use realalloc::collections::TryReserveErrorKind; + #[unstable( feature = "try_reserve_kind", reason = "Uncertain how much info should be exposed", issue = "48043" )] +#[cfg(not(test))] impl From for TryReserveError { #[inline] fn from(kind: TryReserveErrorKind) -> Self { @@ -116,6 +134,7 @@ impl From for TryReserveError { } #[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")] +#[cfg(not(test))] impl From for TryReserveErrorKind { /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`]. #[inline] @@ -125,6 +144,7 @@ impl From for TryReserveErrorKind { } #[stable(feature = "try_reserve", since = "1.57.0")] +#[cfg(not(test))] impl Display for TryReserveError { fn fmt( &self, @@ -152,4 +172,5 @@ trait SpecExtend { } #[stable(feature = "try_reserve", since = "1.57.0")] +#[cfg(not(test))] impl core::error::Error for TryReserveError {} diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 299c8b8679e..f8844e2d3a5 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -645,6 +645,7 @@ impl VecDeque { /// initialized rather than only supporting `0..len`. Requires that /// `initialized.start` ≤ `initialized.end` ≤ `capacity`. #[inline] + #[cfg(not(test))] pub(crate) unsafe fn from_contiguous_raw_parts_in( ptr: *mut T, initialized: Range, diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index d246385ca84..7c7072c4c3a 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -3,6 +3,7 @@ use core::slice; use super::VecDeque; use crate::alloc::Allocator; +#[cfg(not(test))] use crate::vec; // Specialization trait used for VecDeque::extend @@ -78,6 +79,7 @@ where } } +#[cfg(not(test))] impl SpecExtend> for VecDeque { #[track_caller] fn spec_extend(&mut self, mut iterator: vec::IntoIter) { diff --git a/library/alloc/src/collections/vec_deque/spec_from_iter.rs b/library/alloc/src/collections/vec_deque/spec_from_iter.rs index 1efe84d6d7d..c80a30c2103 100644 --- a/library/alloc/src/collections/vec_deque/spec_from_iter.rs +++ b/library/alloc/src/collections/vec_deque/spec_from_iter.rs @@ -19,6 +19,7 @@ where } } +#[cfg(not(test))] impl SpecFromIter> for VecDeque { #[inline] fn spec_from_iter(iterator: crate::vec::IntoIter) -> Self { diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index fd93045a5ac..f6743c65710 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -10,7 +10,6 @@ use core::{fmt, mem, ops, ptr, slice}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::Rc; -use crate::slice::hack::into_vec; use crate::string::String; #[cfg(target_has_atomic = "ptr")] use crate::sync::Arc; @@ -103,7 +102,7 @@ use crate::vec::Vec; /// of `CString` instances can lead to invalid memory accesses, memory leaks, /// and other memory errors. #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] -#[cfg_attr(not(test), rustc_diagnostic_item = "cstring_type")] +#[rustc_diagnostic_item = "cstring_type"] #[stable(feature = "alloc_c_string", since = "1.64.0")] pub struct CString { // Invariant 1: the slice ends with a zero byte and has a length of at least one. @@ -491,7 +490,7 @@ impl CString { #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes(self) -> Vec { - let mut vec = into_vec(self.into_inner()); + let mut vec = self.into_inner().into_vec(); let _nul = vec.pop(); debug_assert_eq!(_nul, Some(0u8)); vec @@ -512,7 +511,7 @@ impl CString { #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes_with_nul(self) -> Vec { - into_vec(self.into_inner()) + self.into_inner().into_vec() } /// Returns the contents of this `CString` as a slice of bytes. @@ -573,7 +572,7 @@ impl CString { #[inline] #[must_use] #[stable(feature = "as_c_str", since = "1.20.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "cstring_as_c_str")] + #[rustc_diagnostic_item = "cstring_as_c_str"] pub fn as_c_str(&self) -> &CStr { &*self } @@ -755,7 +754,6 @@ impl<'a> From> for CString { } } -#[cfg(not(test))] #[stable(feature = "box_from_c_str", since = "1.17.0")] impl From<&CStr> for Box { /// Converts a `&CStr` into a `Box`, @@ -766,7 +764,6 @@ impl From<&CStr> for Box { } } -#[cfg(not(test))] #[stable(feature = "box_from_mut_slice", since = "1.84.0")] impl From<&mut CStr> for Box { /// Converts a `&mut CStr` into a `Box`, @@ -845,7 +842,6 @@ impl TryFrom for String { } } -#[cfg(not(test))] #[stable(feature = "more_box_slice_clone", since = "1.29.0")] impl Clone for Box { #[inline] @@ -971,7 +967,6 @@ impl Default for Rc { } } -#[cfg(not(test))] #[stable(feature = "default_box_extra", since = "1.17.0")] impl Default for Box { fn default() -> Box { @@ -1080,7 +1075,7 @@ impl ToOwned for CStr { } fn clone_into(&self, target: &mut CString) { - let mut b = into_vec(mem::take(&mut target.inner)); + let mut b = mem::take(&mut target.inner).into_vec(); self.to_bytes_with_nul().clone_into(&mut b); target.inner = b.into_boxed_slice(); } @@ -1113,7 +1108,6 @@ impl AsRef for CString { } } -#[cfg(not(test))] impl CStr { /// Converts a `CStr` into a [Cow]<[str]>. /// diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cb93100f56c..84bbc5a2973 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -92,7 +92,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(test, feature(str_as_str))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(array_chunks)] @@ -159,13 +158,11 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(not(test), feature(coroutine_trait))] -#![cfg_attr(test, feature(panic_update_hook))] -#![cfg_attr(test, feature(test))] #![feature(allocator_internals)] #![feature(allow_internal_unstable)] #![feature(cfg_sanitize)] #![feature(const_precise_live_drops)] +#![feature(coroutine_trait)] #![feature(decl_macro)] #![feature(dropck_eyepatch)] #![feature(fundamental)] @@ -198,15 +195,6 @@ // from other crates, but since this can only appear for lang items, it doesn't seem worth fixing. #![feature(intra_doc_pointers)] -// Allow testing this library -#[cfg(test)] -#[macro_use] -extern crate std; -#[cfg(test)] -extern crate test; -#[cfg(test)] -mod testing; - // Module with internal macros used by other modules (needs to be included before other modules). #[macro_use] mod macros; @@ -214,7 +202,6 @@ mod macros; mod raw_vec; // Heaps provided for low-level allocation strategies - pub mod alloc; // Primitive types using the heaps above @@ -222,13 +209,8 @@ pub mod alloc; // Need to conditionally define the mod from `boxed.rs` to avoid // duplicating the lang-items when building in test cfg; but also need // to allow code to have `use boxed::Box;` declarations. -#[cfg(not(test))] -pub mod boxed; -#[cfg(test)] -mod boxed { - pub(crate) use std::boxed::Box; -} pub mod borrow; +pub mod boxed; #[unstable(feature = "bstr", issue = "134915")] pub mod bstr; pub mod collections; @@ -252,20 +234,3 @@ pub mod __export { pub use core::format_args; pub use core::hint::must_use; } - -#[cfg(test)] -#[allow(dead_code)] // Not used in all configurations -pub(crate) mod test_helpers { - /// Copied from `std::test_helpers::test_rng`, since these tests rely on the - /// seed not being the same for every RNG invocation too. - pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { - use std::hash::{BuildHasher, Hash, Hasher}; - let mut hasher = std::hash::RandomState::new().build_hasher(); - std::panic::Location::caller().hash(&mut hasher); - let hc64 = hasher.finish(); - let seed_vec = - hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); - let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); - rand::SeedableRng::from_seed(seed) - } -} diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index c000fd6f4ef..214192b8c9a 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -34,7 +34,7 @@ /// be mindful of side effects. /// /// [`Vec`]: crate::vec::Vec -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "vec_macro"] @@ -55,25 +55,6 @@ macro_rules! vec { ); } -// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is -// required for this macro definition, is not available. Instead use the -// `slice::into_vec` function which is only available with cfg(test) -// NB see the slice::hack module in slice.rs for more information -#[cfg(all(not(no_global_oom_handling), test))] -#[allow(unused_macro_rules)] -macro_rules! vec { - () => ( - $crate::vec::Vec::new() - ); - ($elem:expr; $n:expr) => ( - $crate::vec::from_elem($elem, $n) - ); - ($($x:expr),*) => ( - $crate::slice::into_vec($crate::boxed::Box::new([$($x),*])) - ); - ($($x:expr,)*) => (vec![$($x),*]) -} - /// Creates a `String` using interpolation of runtime expressions. /// /// The first argument `format!` receives is a format string. This must be a string @@ -120,7 +101,7 @@ macro_rules! vec { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(hint_must_use, liballoc_internals)] -#[cfg_attr(not(test), rustc_diagnostic_item = "format_macro")] +#[rustc_diagnostic_item = "format_macro"] macro_rules! format { ($($arg:tt)*) => { $crate::__export::must_use({ diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 70f32fbaab4..f1f5ffefb9b 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -1,4 +1,5 @@ #![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")] +#![cfg_attr(test, allow(dead_code))] use core::marker::PhantomData; use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 2a4d4f26444..fe0b25f31b9 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -262,14 +262,11 @@ use core::ptr::{self, NonNull, drop_in_place}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; use core::{borrow, fmt, hint}; -#[cfg(test)] -use std::boxed::Box; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; -#[cfg(not(test))] use crate::boxed::Box; #[cfg(not(no_global_oom_handling))] use crate::string::String; @@ -306,7 +303,7 @@ fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout { /// /// [get_mut]: Rc::get_mut #[doc(search_unbox)] -#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] +#[rustc_diagnostic_item = "Rc"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] pub struct Rc< @@ -2981,7 +2978,7 @@ impl> ToRcSlice for I { /// /// [`upgrade`]: Weak::upgrade #[stable(feature = "rc_weak", since = "1.4.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "RcWeak")] +#[rustc_diagnostic_item = "RcWeak"] pub struct Weak< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 8baf9685062..7c5d22e1ee9 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -8,9 +8,6 @@ //! A few functions are provided to create a slice from a value reference //! or from a raw pointer. #![stable(feature = "rust1", since = "1.0.0")] -// Many of the usings in this module are only used in the test configuration. -// It's cleaner to just turn off the unused_imports warning than to fix them. -#![cfg_attr(test, allow(unused_imports, dead_code))] use core::borrow::{Borrow, BorrowMut}; #[cfg(not(no_global_oom_handling))] @@ -63,16 +60,6 @@ pub use core::slice::{range, try_range}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods //////////////////////////////////////////////////////////////////////////////// - -// HACK(japaric) needed for the implementation of `vec!` macro during testing -// N.B., see the `hack` module in this file for more details. -#[cfg(test)] -pub use hack::into_vec; -// HACK(japaric) needed for the implementation of `Vec::clone` during testing -// N.B., see the `hack` module in this file for more details. -#[cfg(test)] -pub use hack::to_vec; - use crate::alloc::Allocator; #[cfg(not(no_global_oom_handling))] use crate::alloc::Global; @@ -81,98 +68,6 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; -// HACK(japaric): With cfg(test) `impl [T]` is not available, these three -// functions are actually methods that are in `impl [T]` but not in -// `core::slice::SliceExt` - we need to supply these functions for the -// `test_permutations` test -#[allow(unreachable_pub)] // cfg(test) pub above -pub(crate) mod hack { - use core::alloc::Allocator; - - use crate::boxed::Box; - use crate::vec::Vec; - - // We shouldn't add inline attribute to this since this is used in - // `vec!` macro mostly and causes perf regression. See #71204 for - // discussion and perf results. - #[allow(missing_docs)] - pub fn into_vec(b: Box<[T], A>) -> Vec { - unsafe { - let len = b.len(); - let (b, alloc) = Box::into_raw_with_allocator(b); - Vec::from_raw_parts_in(b as *mut T, len, len, alloc) - } - } - - #[cfg(not(no_global_oom_handling))] - #[allow(missing_docs)] - #[inline] - pub fn to_vec(s: &[T], alloc: A) -> Vec { - T::to_vec(s, alloc) - } - - #[cfg(not(no_global_oom_handling))] - pub trait ConvertVec { - fn to_vec(s: &[Self], alloc: A) -> Vec - where - Self: Sized; - } - - #[cfg(not(no_global_oom_handling))] - impl ConvertVec for T { - #[inline] - default fn to_vec(s: &[Self], alloc: A) -> Vec { - struct DropGuard<'a, T, A: Allocator> { - vec: &'a mut Vec, - num_init: usize, - } - impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { - #[inline] - fn drop(&mut self) { - // SAFETY: - // items were marked initialized in the loop below - unsafe { - self.vec.set_len(self.num_init); - } - } - } - let mut vec = Vec::with_capacity_in(s.len(), alloc); - let mut guard = DropGuard { vec: &mut vec, num_init: 0 }; - let slots = guard.vec.spare_capacity_mut(); - // .take(slots.len()) is necessary for LLVM to remove bounds checks - // and has better codegen than zip. - for (i, b) in s.iter().enumerate().take(slots.len()) { - guard.num_init = i; - slots[i].write(b.clone()); - } - core::mem::forget(guard); - // SAFETY: - // the vec was allocated and initialized above to at least this length. - unsafe { - vec.set_len(s.len()); - } - vec - } - } - - #[cfg(not(no_global_oom_handling))] - impl ConvertVec for T { - #[inline] - fn to_vec(s: &[Self], alloc: A) -> Vec { - let mut v = Vec::with_capacity_in(s.len(), alloc); - // SAFETY: - // allocated above with the capacity of `s`, and initialize to `s.len()` in - // ptr::copy_to_non_overlapping below. - unsafe { - s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); - v.set_len(s.len()); - } - v - } - } -} - -#[cfg(not(test))] impl [T] { /// Sorts the slice, preserving initial order of equal elements. /// @@ -501,8 +396,64 @@ impl [T] { where T: Clone, { - // N.B., see the `hack` module in this file for more details. - hack::to_vec(self, alloc) + return T::to_vec(self, alloc); + + trait ConvertVec { + fn to_vec(s: &[Self], alloc: A) -> Vec + where + Self: Sized; + } + + impl ConvertVec for T { + #[inline] + default fn to_vec(s: &[Self], alloc: A) -> Vec { + struct DropGuard<'a, T, A: Allocator> { + vec: &'a mut Vec, + num_init: usize, + } + impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { + #[inline] + fn drop(&mut self) { + // SAFETY: + // items were marked initialized in the loop below + unsafe { + self.vec.set_len(self.num_init); + } + } + } + let mut vec = Vec::with_capacity_in(s.len(), alloc); + let mut guard = DropGuard { vec: &mut vec, num_init: 0 }; + let slots = guard.vec.spare_capacity_mut(); + // .take(slots.len()) is necessary for LLVM to remove bounds checks + // and has better codegen than zip. + for (i, b) in s.iter().enumerate().take(slots.len()) { + guard.num_init = i; + slots[i].write(b.clone()); + } + core::mem::forget(guard); + // SAFETY: + // the vec was allocated and initialized above to at least this length. + unsafe { + vec.set_len(s.len()); + } + vec + } + } + + impl ConvertVec for T { + #[inline] + fn to_vec(s: &[Self], alloc: A) -> Vec { + let mut v = Vec::with_capacity_in(s.len(), alloc); + // SAFETY: + // allocated above with the capacity of `s`, and initialize to `s.len()` in + // ptr::copy_to_non_overlapping below. + unsafe { + s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); + v.set_len(s.len()); + } + v + } + } } /// Converts `self` into a vector without clones or allocation. @@ -522,10 +473,13 @@ impl [T] { #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - #[cfg_attr(not(test), rustc_diagnostic_item = "slice_into_vec")] + #[rustc_diagnostic_item = "slice_into_vec"] pub fn into_vec(self: Box) -> Vec { - // N.B., see the `hack` module in this file for more details. - hack::into_vec(self) + unsafe { + let len = self.len(); + let (b, alloc) = Box::into_raw_with_allocator(self); + Vec::from_raw_parts_in(b as *mut T, len, len, alloc) + } } /// Creates a vector by copying a slice `n` times. @@ -666,7 +620,6 @@ impl [T] { } } -#[cfg(not(test))] impl [u8] { /// Returns a vector containing a copy of this slice where each byte /// is mapped to its ASCII upper case equivalent. @@ -883,14 +836,9 @@ impl SpecCloneIntoVec for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for [T] { type Owned = Vec; - #[cfg(not(test))] - fn to_owned(&self) -> Vec { - self.to_vec() - } - #[cfg(test)] fn to_owned(&self) -> Vec { - hack::to_vec(self, Global) + self.to_vec() } fn clone_into(&self, target: &mut Vec) { diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 6fee8d3fe33..0664f2c3cf2 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -219,7 +219,6 @@ impl ToOwned for str { } /// Methods for string slices. -#[cfg(not(test))] impl str { /// Converts a `Box` into a `Box<[u8]>` without copying or allocating. /// @@ -631,7 +630,6 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { #[unstable(feature = "str_internals", issue = "none")] #[doc(hidden)] #[inline] -#[cfg(not(test))] #[cfg(not(no_global_oom_handling))] pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) { // Process the input in chunks of 16 bytes to enable auto-vectorization. @@ -704,7 +702,6 @@ pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) { } } #[inline] -#[cfg(not(test))] #[cfg(not(no_global_oom_handling))] #[allow(dead_code)] /// Faster implementation of string replacement for ASCII to ASCII cases. diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 2c034786549..2ba797ab2ad 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -356,7 +356,7 @@ use crate::vec::{self, Vec}; /// [`as_str()`]: String::as_str #[derive(PartialEq, PartialOrd, Eq, Ord)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), lang = "String")] +#[lang = "String"] pub struct String { vec: Vec, } @@ -438,7 +438,7 @@ impl String { /// ``` #[inline] #[rustc_const_stable(feature = "const_string_new", since = "1.39.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_new")] + #[rustc_diagnostic_item = "string_new"] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub const fn new() -> String { @@ -501,17 +501,6 @@ impl String { Ok(String { vec: Vec::try_with_capacity(capacity)? }) } - // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is - // required for this method definition, is not available. Since we don't - // require this method for testing purposes, I'll just stub it - // NB see the slice::hack module in slice.rs for more information - #[inline] - #[cfg(test)] - #[allow(missing_docs)] - pub fn from_str(_: &str) -> String { - panic!("not available with cfg(test)"); - } - /// Converts a vector of bytes to a `String`. /// /// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes @@ -570,7 +559,7 @@ impl String { /// [`into_bytes`]: String::into_bytes #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_from_utf8")] + #[rustc_diagnostic_item = "string_from_utf8"] pub fn from_utf8(vec: Vec) -> Result { match str::from_utf8(&vec) { Ok(..) => Ok(String { vec }), @@ -1071,7 +1060,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")] + #[rustc_diagnostic_item = "string_as_str"] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] pub const fn as_str(&self) -> &str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error @@ -1094,7 +1083,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")] + #[rustc_diagnostic_item = "string_as_mut_str"] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] pub const fn as_mut_str(&mut self) -> &mut str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error @@ -1117,7 +1106,7 @@ impl String { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("append", "push")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_push_str")] + #[rustc_diagnostic_item = "string_push_str"] pub fn push_str(&mut self, string: &str) { self.vec.extend_from_slice(string.as_bytes()) } @@ -1755,7 +1744,7 @@ impl String { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "insert_str", since = "1.16.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_insert_str")] + #[rustc_diagnostic_item = "string_insert_str"] pub fn insert_str(&mut self, idx: usize, string: &str) { assert!(self.is_char_boundary(idx)); @@ -2724,7 +2713,7 @@ impl FromStr for String { /// implementation for free. /// /// [`Display`]: fmt::Display -#[cfg_attr(not(test), rustc_diagnostic_item = "ToString")] +#[rustc_diagnostic_item = "ToString"] #[stable(feature = "rust1", since = "1.0.0")] pub trait ToString { /// Converts the given value to a `String`. @@ -2739,7 +2728,7 @@ pub trait ToString { /// ``` #[rustc_conversion_suggestion] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")] + #[rustc_diagnostic_item = "to_string_method"] fn to_string(&self) -> String; } @@ -2979,7 +2968,6 @@ impl From<&String> for String { } // note: test pulls in std, which causes errors here -#[cfg(not(test))] #[stable(feature = "string_from_box", since = "1.18.0")] impl From> for String { /// Converts the given boxed `str` slice to a [`String`]. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 1956dda5388..faee15ab0c6 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -234,7 +234,7 @@ macro_rules! acquire { /// /// [rc_examples]: crate::rc#examples #[doc(search_unbox)] -#[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] +#[rustc_diagnostic_item = "Arc"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] pub struct Arc< @@ -311,7 +311,7 @@ impl Arc { /// /// [`upgrade`]: Weak::upgrade #[stable(feature = "arc_weak", since = "1.4.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "ArcWeak")] +#[rustc_diagnostic_item = "ArcWeak"] pub struct Weak< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, diff --git a/library/alloc/src/testing/crash_test.rs b/library/alloc/src/testing/crash_test.rs deleted file mode 100644 index 8e00e4f41e5..00000000000 --- a/library/alloc/src/testing/crash_test.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::cmp::Ordering; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering::SeqCst; - -use crate::fmt::Debug; // the `Debug` trait is the only thing we use from `crate::fmt` - -/// A blueprint for crash test dummy instances that monitor particular events. -/// Some instances may be configured to panic at some point. -/// Events are `clone`, `drop` or some anonymous `query`. -/// -/// Crash test dummies are identified and ordered by an id, so they can be used -/// as keys in a BTreeMap. -#[derive(Debug)] -pub(crate) struct CrashTestDummy { - pub id: usize, - cloned: AtomicUsize, - dropped: AtomicUsize, - queried: AtomicUsize, -} - -impl CrashTestDummy { - /// Creates a crash test dummy design. The `id` determines order and equality of instances. - pub(crate) fn new(id: usize) -> CrashTestDummy { - CrashTestDummy { - id, - cloned: AtomicUsize::new(0), - dropped: AtomicUsize::new(0), - queried: AtomicUsize::new(0), - } - } - - /// Creates an instance of a crash test dummy that records what events it experiences - /// and optionally panics. - pub(crate) fn spawn(&self, panic: Panic) -> Instance<'_> { - Instance { origin: self, panic } - } - - /// Returns how many times instances of the dummy have been cloned. - pub(crate) fn cloned(&self) -> usize { - self.cloned.load(SeqCst) - } - - /// Returns how many times instances of the dummy have been dropped. - pub(crate) fn dropped(&self) -> usize { - self.dropped.load(SeqCst) - } - - /// Returns how many times instances of the dummy have had their `query` member invoked. - pub(crate) fn queried(&self) -> usize { - self.queried.load(SeqCst) - } -} - -#[derive(Debug)] -pub(crate) struct Instance<'a> { - origin: &'a CrashTestDummy, - panic: Panic, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub(crate) enum Panic { - Never, - InClone, - InDrop, - InQuery, -} - -impl Instance<'_> { - pub(crate) fn id(&self) -> usize { - self.origin.id - } - - /// Some anonymous query, the result of which is already given. - pub(crate) fn query(&self, result: R) -> R { - self.origin.queried.fetch_add(1, SeqCst); - if self.panic == Panic::InQuery { - panic!("panic in `query`"); - } - result - } -} - -impl Clone for Instance<'_> { - fn clone(&self) -> Self { - self.origin.cloned.fetch_add(1, SeqCst); - if self.panic == Panic::InClone { - panic!("panic in `clone`"); - } - Self { origin: self.origin, panic: Panic::Never } - } -} - -impl Drop for Instance<'_> { - fn drop(&mut self) { - self.origin.dropped.fetch_add(1, SeqCst); - if self.panic == Panic::InDrop { - panic!("panic in `drop`"); - } - } -} - -impl PartialOrd for Instance<'_> { - fn partial_cmp(&self, other: &Self) -> Option { - self.id().partial_cmp(&other.id()) - } -} - -impl Ord for Instance<'_> { - fn cmp(&self, other: &Self) -> Ordering { - self.id().cmp(&other.id()) - } -} - -impl PartialEq for Instance<'_> { - fn eq(&self, other: &Self) -> bool { - self.id().eq(&other.id()) - } -} - -impl Eq for Instance<'_> {} diff --git a/library/alloc/src/testing/mod.rs b/library/alloc/src/testing/mod.rs deleted file mode 100644 index c8457daf93e..00000000000 --- a/library/alloc/src/testing/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub(crate) mod crash_test; -pub(crate) mod ord_chaos; -pub(crate) mod rng; diff --git a/library/alloc/src/testing/ord_chaos.rs b/library/alloc/src/testing/ord_chaos.rs deleted file mode 100644 index 55e1ae5e3de..00000000000 --- a/library/alloc/src/testing/ord_chaos.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::cell::Cell; -use std::cmp::Ordering::{self, *}; -use std::ptr; - -// Minimal type with an `Ord` implementation violating transitivity. -#[derive(Debug)] -pub(crate) enum Cyclic3 { - A, - B, - C, -} -use Cyclic3::*; - -impl PartialOrd for Cyclic3 { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Cyclic3 { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - (A, A) | (B, B) | (C, C) => Equal, - (A, B) | (B, C) | (C, A) => Less, - (A, C) | (B, A) | (C, B) => Greater, - } - } -} - -impl PartialEq for Cyclic3 { - fn eq(&self, other: &Self) -> bool { - self.cmp(&other) == Equal - } -} - -impl Eq for Cyclic3 {} - -// Controls the ordering of values wrapped by `Governed`. -#[derive(Debug)] -pub(crate) struct Governor { - flipped: Cell, -} - -impl Governor { - pub(crate) fn new() -> Self { - Governor { flipped: Cell::new(false) } - } - - pub(crate) fn flip(&self) { - self.flipped.set(!self.flipped.get()); - } -} - -// Type with an `Ord` implementation that forms a total order at any moment -// (assuming that `T` respects total order), but can suddenly be made to invert -// that total order. -#[derive(Debug)] -pub(crate) struct Governed<'a, T>(pub T, pub &'a Governor); - -impl PartialOrd for Governed<'_, T> { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Governed<'_, T> { - fn cmp(&self, other: &Self) -> Ordering { - assert!(ptr::eq(self.1, other.1)); - let ord = self.0.cmp(&other.0); - if self.1.flipped.get() { ord.reverse() } else { ord } - } -} - -impl PartialEq for Governed<'_, T> { - fn eq(&self, other: &Self) -> bool { - assert!(ptr::eq(self.1, other.1)); - self.0.eq(&other.0) - } -} - -impl Eq for Governed<'_, T> {} diff --git a/library/alloc/src/testing/rng.rs b/library/alloc/src/testing/rng.rs deleted file mode 100644 index 77d3348f38a..00000000000 --- a/library/alloc/src/testing/rng.rs +++ /dev/null @@ -1,28 +0,0 @@ -/// XorShiftRng -pub(crate) struct DeterministicRng { - count: usize, - x: u32, - y: u32, - z: u32, - w: u32, -} - -impl DeterministicRng { - pub(crate) fn new() -> Self { - DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb } - } - - /// Guarantees that each returned number is unique. - pub(crate) fn next(&mut self) -> u32 { - self.count += 1; - assert!(self.count <= 70029); - let x = self.x; - let t = x ^ (x << 11); - self.x = self.y; - self.y = self.z; - self.z = self.w; - let w_ = self.w; - self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); - self.w - } -} diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 52597e41c1c..3eee988b6c9 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -472,14 +472,9 @@ where #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] impl Clone for IntoIter { - #[cfg(not(test))] fn clone(&self) -> Self { self.as_slice().to_vec_in(self.alloc.deref().clone()).into_iter() } - #[cfg(test)] - fn clone(&self) -> Self { - crate::slice::to_vec(self.as_slice(), self.alloc.deref().clone()).into_iter() - } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 49878f2b6fa..ce668540598 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -404,7 +404,7 @@ mod spec_extend; /// [owned slice]: Box /// [`into_boxed_slice`]: Vec::into_boxed_slice #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Vec")] +#[rustc_diagnostic_item = "Vec"] #[rustc_insignificant_dtor] pub struct Vec { buf: RawVec, @@ -428,7 +428,7 @@ impl Vec { /// ``` #[inline] #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_new")] + #[rustc_diagnostic_item = "vec_new"] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub const fn new() -> Self { @@ -489,7 +489,7 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_with_capacity")] + #[rustc_diagnostic_item = "vec_with_capacity"] #[track_caller] pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) @@ -1279,7 +1279,7 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[track_caller] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_reserve")] + #[rustc_diagnostic_item = "vec_reserve"] pub fn reserve(&mut self, additional: usize) { self.buf.reserve(self.len, additional); } @@ -1568,7 +1568,7 @@ impl Vec { /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")] + #[rustc_diagnostic_item = "vec_as_slice"] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] pub const fn as_slice(&self) -> &[T] { // SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size @@ -1600,7 +1600,7 @@ impl Vec { /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")] + #[rustc_diagnostic_item = "vec_as_mut_slice"] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of @@ -2511,7 +2511,7 @@ impl Vec { /// Takes *O*(1) time. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_pop")] + #[rustc_diagnostic_item = "vec_pop"] pub fn pop(&mut self) -> Option { if self.len == 0 { None @@ -2712,7 +2712,7 @@ impl Vec { /// assert!(!v.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")] + #[rustc_diagnostic_item = "vec_is_empty"] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] pub const fn is_empty(&self) -> bool { self.len() == 0 @@ -3193,7 +3193,7 @@ impl Vec { #[doc(hidden)] #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "vec_from_elem")] +#[rustc_diagnostic_item = "vec_from_elem"] #[track_caller] pub fn from_elem(elem: T, n: usize) -> Vec { ::from_elem(elem, n, Global) @@ -3293,23 +3293,12 @@ unsafe impl ops::DerefPure for Vec {} #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Vec { - #[cfg(not(test))] #[track_caller] fn clone(&self) -> Self { let alloc = self.allocator().clone(); <[T]>::to_vec_in(&**self, alloc) } - // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is - // required for this method definition, is not available. Instead use the - // `slice::to_vec` function which is only available with cfg(test) - // NB see the slice::hack module in slice.rs for more information - #[cfg(test)] - fn clone(&self) -> Self { - let alloc = self.allocator().clone(); - crate::slice::to_vec(&**self, alloc) - } - /// Overwrites the contents of `self` with a clone of the contents of `source`. /// /// This method is preferred over simply assigning `source.clone()` to `self`, @@ -3854,15 +3843,10 @@ impl From<&[T]> for Vec { /// ``` /// assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]); /// ``` - #[cfg(not(test))] #[track_caller] fn from(s: &[T]) -> Vec { s.to_vec() } - #[cfg(test)] - fn from(s: &[T]) -> Vec { - crate::slice::to_vec(s, Global) - } } #[cfg(not(no_global_oom_handling))] @@ -3875,15 +3859,10 @@ impl From<&mut [T]> for Vec { /// ``` /// assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]); /// ``` - #[cfg(not(test))] #[track_caller] fn from(s: &mut [T]) -> Vec { s.to_vec() } - #[cfg(test)] - fn from(s: &mut [T]) -> Vec { - crate::slice::to_vec(s, Global) - } } #[cfg(not(no_global_oom_handling))] @@ -3928,16 +3907,10 @@ impl From<[T; N]> for Vec { /// ``` /// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]); /// ``` - #[cfg(not(test))] #[track_caller] fn from(s: [T; N]) -> Vec { <[T]>::into_vec(Box::new(s)) } - - #[cfg(test)] - fn from(s: [T; N]) -> Vec { - crate::slice::into_vec(Box::new(s)) - } } #[stable(feature = "vec_from_cow_slice", since = "1.14.0")] @@ -3966,7 +3939,6 @@ where } // note: test pulls in std, which causes errors here -#[cfg(not(test))] #[stable(feature = "vec_from_box", since = "1.18.0")] impl From> for Vec { /// Converts a boxed slice into a vector by transferring ownership of @@ -3985,7 +3957,6 @@ impl From> for Vec { // note: test pulls in std, which causes errors here #[cfg(not(no_global_oom_handling))] -#[cfg(not(test))] #[stable(feature = "box_from_vec", since = "1.20.0")] impl From> for Box<[T], A> { /// Converts a vector into a boxed slice. diff --git a/library/alloctests/Cargo.toml b/library/alloctests/Cargo.toml index f1a783b1e22..306375f5f01 100644 --- a/library/alloctests/Cargo.toml +++ b/library/alloctests/Cargo.toml @@ -10,8 +10,9 @@ edition = "2021" [lib] path = "lib.rs" -test = false -bench = false +test = true +bench = true +doc = false [dev-dependencies] rand = { version = "0.9.0", default-features = false, features = ["alloc"] } diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index b49208cd4eb..0b5aa2c575d 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -1 +1,90 @@ -// Intentionally left empty. +#![cfg(test)] +#![allow(unused_attributes)] +#![unstable(feature = "alloctests", issue = "none")] +#![no_std] +// Lints: +#![deny(unsafe_op_in_unsafe_fn)] +#![warn(deprecated_in_future)] +#![warn(missing_debug_implementations)] +#![allow(explicit_outlives_requirements)] +#![allow(internal_features)] +#![allow(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::unescaped_backticks)] +#![deny(ffi_unwind_calls)] +// +// Library features: +// tidy-alphabetical-start +#![feature(alloc_layout_extra)] +#![feature(allocator_api)] +#![feature(array_into_iter_constructors)] +#![feature(assert_matches)] +#![feature(core_intrinsics)] +#![feature(exact_size_is_empty)] +#![feature(extend_one)] +#![feature(extend_one_unchecked)] +#![feature(hasher_prefixfree_extras)] +#![feature(inplace_iteration)] +#![feature(iter_advance_by)] +#![feature(iter_next_chunk)] +#![feature(maybe_uninit_slice)] +#![feature(maybe_uninit_uninit_array_transpose)] +#![feature(ptr_internals)] +#![feature(sized_type_properties)] +#![feature(slice_iter_mut_as_mut_slice)] +#![feature(slice_ptr_get)] +#![feature(slice_range)] +#![feature(std_internals)] +#![feature(temporary_niche_types)] +#![feature(trusted_fused)] +#![feature(trusted_len)] +#![feature(trusted_random_access)] +#![feature(try_reserve_kind)] +#![feature(try_trait_v2)] +// tidy-alphabetical-end +// +// Language features: +// tidy-alphabetical-start +#![feature(cfg_sanitize)] +#![feature(dropck_eyepatch)] +#![feature(lang_items)] +#![feature(min_specialization)] +#![feature(negative_impls)] +#![feature(never_type)] +#![feature(optimize_attribute)] +#![feature(rustc_allow_const_fn_unstable)] +#![feature(rustc_attrs)] +#![feature(staged_api)] +#![feature(test)] +#![rustc_preserve_ub_checks] +// tidy-alphabetical-end + +// Allow testing this library +extern crate alloc as realalloc; +#[macro_use] +extern crate std; +#[cfg(test)] +extern crate test; +mod testing; +use realalloc::*; + +#[path = "../alloc/src/collections/mod.rs"] +mod collections; + +#[path = "../alloc/src/raw_vec/mod.rs"] +mod raw_vec; + +#[allow(dead_code)] // Not used in all configurations +pub(crate) mod test_helpers { + /// Copied from `std::test_helpers::test_rng`, since these tests rely on the + /// seed not being the same for every RNG invocation too. + pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { + use std::hash::{BuildHasher, Hash, Hasher}; + let mut hasher = std::hash::RandomState::new().build_hasher(); + std::panic::Location::caller().hash(&mut hasher); + let hc64 = hasher.finish(); + let seed_vec = + hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); + let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); + rand::SeedableRng::from_seed(seed) + } +} diff --git a/library/alloctests/testing/crash_test.rs b/library/alloctests/testing/crash_test.rs new file mode 100644 index 00000000000..8e00e4f41e5 --- /dev/null +++ b/library/alloctests/testing/crash_test.rs @@ -0,0 +1,120 @@ +use std::cmp::Ordering; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; + +use crate::fmt::Debug; // the `Debug` trait is the only thing we use from `crate::fmt` + +/// A blueprint for crash test dummy instances that monitor particular events. +/// Some instances may be configured to panic at some point. +/// Events are `clone`, `drop` or some anonymous `query`. +/// +/// Crash test dummies are identified and ordered by an id, so they can be used +/// as keys in a BTreeMap. +#[derive(Debug)] +pub(crate) struct CrashTestDummy { + pub id: usize, + cloned: AtomicUsize, + dropped: AtomicUsize, + queried: AtomicUsize, +} + +impl CrashTestDummy { + /// Creates a crash test dummy design. The `id` determines order and equality of instances. + pub(crate) fn new(id: usize) -> CrashTestDummy { + CrashTestDummy { + id, + cloned: AtomicUsize::new(0), + dropped: AtomicUsize::new(0), + queried: AtomicUsize::new(0), + } + } + + /// Creates an instance of a crash test dummy that records what events it experiences + /// and optionally panics. + pub(crate) fn spawn(&self, panic: Panic) -> Instance<'_> { + Instance { origin: self, panic } + } + + /// Returns how many times instances of the dummy have been cloned. + pub(crate) fn cloned(&self) -> usize { + self.cloned.load(SeqCst) + } + + /// Returns how many times instances of the dummy have been dropped. + pub(crate) fn dropped(&self) -> usize { + self.dropped.load(SeqCst) + } + + /// Returns how many times instances of the dummy have had their `query` member invoked. + pub(crate) fn queried(&self) -> usize { + self.queried.load(SeqCst) + } +} + +#[derive(Debug)] +pub(crate) struct Instance<'a> { + origin: &'a CrashTestDummy, + panic: Panic, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum Panic { + Never, + InClone, + InDrop, + InQuery, +} + +impl Instance<'_> { + pub(crate) fn id(&self) -> usize { + self.origin.id + } + + /// Some anonymous query, the result of which is already given. + pub(crate) fn query(&self, result: R) -> R { + self.origin.queried.fetch_add(1, SeqCst); + if self.panic == Panic::InQuery { + panic!("panic in `query`"); + } + result + } +} + +impl Clone for Instance<'_> { + fn clone(&self) -> Self { + self.origin.cloned.fetch_add(1, SeqCst); + if self.panic == Panic::InClone { + panic!("panic in `clone`"); + } + Self { origin: self.origin, panic: Panic::Never } + } +} + +impl Drop for Instance<'_> { + fn drop(&mut self) { + self.origin.dropped.fetch_add(1, SeqCst); + if self.panic == Panic::InDrop { + panic!("panic in `drop`"); + } + } +} + +impl PartialOrd for Instance<'_> { + fn partial_cmp(&self, other: &Self) -> Option { + self.id().partial_cmp(&other.id()) + } +} + +impl Ord for Instance<'_> { + fn cmp(&self, other: &Self) -> Ordering { + self.id().cmp(&other.id()) + } +} + +impl PartialEq for Instance<'_> { + fn eq(&self, other: &Self) -> bool { + self.id().eq(&other.id()) + } +} + +impl Eq for Instance<'_> {} diff --git a/library/alloctests/testing/mod.rs b/library/alloctests/testing/mod.rs new file mode 100644 index 00000000000..c8457daf93e --- /dev/null +++ b/library/alloctests/testing/mod.rs @@ -0,0 +1,3 @@ +pub(crate) mod crash_test; +pub(crate) mod ord_chaos; +pub(crate) mod rng; diff --git a/library/alloctests/testing/ord_chaos.rs b/library/alloctests/testing/ord_chaos.rs new file mode 100644 index 00000000000..55e1ae5e3de --- /dev/null +++ b/library/alloctests/testing/ord_chaos.rs @@ -0,0 +1,81 @@ +use std::cell::Cell; +use std::cmp::Ordering::{self, *}; +use std::ptr; + +// Minimal type with an `Ord` implementation violating transitivity. +#[derive(Debug)] +pub(crate) enum Cyclic3 { + A, + B, + C, +} +use Cyclic3::*; + +impl PartialOrd for Cyclic3 { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Cyclic3 { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (A, A) | (B, B) | (C, C) => Equal, + (A, B) | (B, C) | (C, A) => Less, + (A, C) | (B, A) | (C, B) => Greater, + } + } +} + +impl PartialEq for Cyclic3 { + fn eq(&self, other: &Self) -> bool { + self.cmp(&other) == Equal + } +} + +impl Eq for Cyclic3 {} + +// Controls the ordering of values wrapped by `Governed`. +#[derive(Debug)] +pub(crate) struct Governor { + flipped: Cell, +} + +impl Governor { + pub(crate) fn new() -> Self { + Governor { flipped: Cell::new(false) } + } + + pub(crate) fn flip(&self) { + self.flipped.set(!self.flipped.get()); + } +} + +// Type with an `Ord` implementation that forms a total order at any moment +// (assuming that `T` respects total order), but can suddenly be made to invert +// that total order. +#[derive(Debug)] +pub(crate) struct Governed<'a, T>(pub T, pub &'a Governor); + +impl PartialOrd for Governed<'_, T> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Governed<'_, T> { + fn cmp(&self, other: &Self) -> Ordering { + assert!(ptr::eq(self.1, other.1)); + let ord = self.0.cmp(&other.0); + if self.1.flipped.get() { ord.reverse() } else { ord } + } +} + +impl PartialEq for Governed<'_, T> { + fn eq(&self, other: &Self) -> bool { + assert!(ptr::eq(self.1, other.1)); + self.0.eq(&other.0) + } +} + +impl Eq for Governed<'_, T> {} diff --git a/library/alloctests/testing/rng.rs b/library/alloctests/testing/rng.rs new file mode 100644 index 00000000000..77d3348f38a --- /dev/null +++ b/library/alloctests/testing/rng.rs @@ -0,0 +1,28 @@ +/// XorShiftRng +pub(crate) struct DeterministicRng { + count: usize, + x: u32, + y: u32, + z: u32, + w: u32, +} + +impl DeterministicRng { + pub(crate) fn new() -> Self { + DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb } + } + + /// Guarantees that each returned number is unique. + pub(crate) fn next(&mut self) -> u32 { + self.count += 1; + assert!(self.count <= 70029); + let x = self.x; + let t = x ^ (x << 11); + self.x = self.y; + self.y = self.z; + self.z = self.w; + let w_ = self.w; + self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); + self.w + } +} -- cgit 1.4.1-3-g733a5 From 22d0440993d6eab6e9faf35f729e2d52ba6d72a6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 13 Feb 2025 15:38:07 +0000 Subject: Add comments --- library/alloc/src/collections/mod.rs | 3 +++ library/alloc/src/raw_vec/mod.rs | 3 +++ library/alloctests/lib.rs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 1414f797e8a..fac4d1a65ab 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -1,5 +1,8 @@ //! Collection types. +// Note: This module is also included in the alloctests crate using #[path] to +// run the tests. See the comment there for an explanation why this is the case. + #![stable(feature = "rust1", since = "1.0.0")] #[cfg(not(no_global_oom_handling))] diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index f1f5ffefb9b..99ebc5c4bfc 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -1,6 +1,9 @@ #![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")] #![cfg_attr(test, allow(dead_code))] +// Note: This module is also included in the alloctests crate using #[path] to +// run the tests. See the comment there for an explanation why this is the case. + use core::marker::PhantomData; use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ptr::{self, NonNull, Unique}; diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index 0b5aa2c575d..6ce8a6d9ca1 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -67,6 +67,9 @@ extern crate test; mod testing; use realalloc::*; +// We are directly including collections and raw_vec here as both use non-public +// methods and fields in tests and as such need to have the types to test in the +// same crate as the tests themself. #[path = "../alloc/src/collections/mod.rs"] mod collections; -- cgit 1.4.1-3-g733a5 From 17dd2b179c4fab87975bb1c23ea2b869ca516ea5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 7 Mar 2025 22:00:36 +0100 Subject: Mention `env` and `option_env` macros in `std::env::var` docs --- library/std/src/env.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index e62aeb2ede0..6961fa8ea94 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -202,6 +202,9 @@ impl fmt::Debug for VarsOs { /// Returns [`VarError::NotUnicode`] if the variable's value is not valid /// Unicode. If this is not desired, consider using [`var_os`]. /// +/// Use [`env!`] or [`option_env!`] instead if you want to check environment +/// variables at compile time. +/// /// # Examples /// /// ``` -- cgit 1.4.1-3-g733a5

(p: P) - where - for<'b> &'b P: Pattern, - { - for _ in 0..3 { - "asdf".find(&p); - } - } - - foo::<&str>("x"); -} - -#[test] -fn test_str_multiline() { - let a: String = "this \ -is a test" - .to_string(); - let b: String = "this \ - is \ - another \ - test" - .to_string(); - assert_eq!(a, "this is a test".to_string()); - assert_eq!(b, "this is another test".to_string()); -} - -#[test] -fn test_str_escapes() { - let x = "\\\\\ - "; - assert_eq!(x, r"\\"); // extraneous whitespace stripped -} - -#[test] -fn const_str_ptr() { - const A: [u8; 2] = ['h' as u8, 'i' as u8]; - const B: &'static [u8; 2] = &A; - const C: *const u8 = B as *const u8; - - // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131) - #[cfg(not(miri))] - { - let foo = &A as *const u8; - assert_eq!(foo, C); - } - - unsafe { - assert_eq!(from_utf8_unchecked(&A), "hi"); - assert_eq!(*C, A[0]); - assert_eq!(*(&B[0] as *const u8), A[0]); - } -} - -#[test] -fn utf8() { - let yen: char = '¥'; // 0xa5 - let c_cedilla: char = 'ç'; // 0xe7 - let thorn: char = 'þ'; // 0xfe - let y_diaeresis: char = 'ÿ'; // 0xff - let pi: char = 'Π'; // 0x3a0 - - assert_eq!(yen as isize, 0xa5); - assert_eq!(c_cedilla as isize, 0xe7); - assert_eq!(thorn as isize, 0xfe); - assert_eq!(y_diaeresis as isize, 0xff); - assert_eq!(pi as isize, 0x3a0); - - assert_eq!(pi as isize, '\u{3a0}' as isize); - assert_eq!('\x0a' as isize, '\n' as isize); - - let bhutan: String = "འབྲུག་ཡུལ།".to_string(); - let japan: String = "日本".to_string(); - let uzbekistan: String = "Ўзбекистон".to_string(); - let austria: String = "Österreich".to_string(); - - let bhutan_e: String = - "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string(); - let japan_e: String = "\u{65e5}\u{672c}".to_string(); - let uzbekistan_e: String = - "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string(); - let austria_e: String = "\u{d6}sterreich".to_string(); - - let oo: char = 'Ö'; - assert_eq!(oo as isize, 0xd6); - - fn check_str_eq(a: String, b: String) { - let mut i: isize = 0; - for ab in a.bytes() { - println!("{i}"); - println!("{ab}"); - let bb: u8 = b.as_bytes()[i as usize]; - println!("{bb}"); - assert_eq!(ab, bb); - i += 1; - } - } - - check_str_eq(bhutan, bhutan_e); - check_str_eq(japan, japan_e); - check_str_eq(uzbekistan, uzbekistan_e); - check_str_eq(austria, austria_e); -} - -#[test] -fn utf8_chars() { - // Chars of 1, 2, 3, and 4 bytes - let chs: Vec = vec!['e', 'é', '€', '\u{10000}']; - let s: String = chs.iter().cloned().collect(); - let schs: Vec = s.chars().collect(); - - assert_eq!(s.len(), 10); - assert_eq!(s.chars().count(), 4); - assert_eq!(schs.len(), 4); - assert_eq!(schs.iter().cloned().collect::(), s); - - assert!(from_utf8(s.as_bytes()).is_ok()); - // invalid prefix - assert!(!from_utf8(&[0x80]).is_ok()); - // invalid 2 byte prefix - assert!(!from_utf8(&[0xc0]).is_ok()); - assert!(!from_utf8(&[0xc0, 0x10]).is_ok()); - // invalid 3 byte prefix - assert!(!from_utf8(&[0xe0]).is_ok()); - assert!(!from_utf8(&[0xe0, 0x10]).is_ok()); - assert!(!from_utf8(&[0xe0, 0xff, 0x10]).is_ok()); - // invalid 4 byte prefix - assert!(!from_utf8(&[0xf0]).is_ok()); - assert!(!from_utf8(&[0xf0, 0x10]).is_ok()); - assert!(!from_utf8(&[0xf0, 0xff, 0x10]).is_ok()); - assert!(!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()); -} - -#[test] -fn utf8_char_counts() { - let strs = [("e", 1), ("é", 1), ("€", 1), ("\u{10000}", 1), ("eé€\u{10000}", 4)]; - let spread = if cfg!(miri) { 4 } else { 8 }; - let mut reps = [8, 64, 256, 512] - .iter() - .copied() - .flat_map(|n| n - spread..=n + spread) - .collect::>(); - if cfg!(not(miri)) { - reps.extend([1024, 1 << 16].iter().copied().flat_map(|n| n - spread..=n + spread)); - } - let counts = if cfg!(miri) { 0..1 } else { 0..8 }; - let padding = counts.map(|len| " ".repeat(len)).collect::>(); - - for repeat in reps { - for (tmpl_str, tmpl_char_count) in strs { - for pad_start in &padding { - for pad_end in &padding { - // Create a string with padding... - let with_padding = - format!("{}{}{}", pad_start, tmpl_str.repeat(repeat), pad_end); - // ...and then skip past that padding. This should ensure - // that we test several different alignments for both head - // and tail. - let si = pad_start.len(); - let ei = with_padding.len() - pad_end.len(); - let target = &with_padding[si..ei]; - - assert!(!target.starts_with(" ") && !target.ends_with(" ")); - let expected_count = tmpl_char_count * repeat; - assert_eq!( - expected_count, - target.chars().count(), - "wrong count for `{:?}.repeat({})` (padding: `{:?}`)", - tmpl_str, - repeat, - (pad_start.len(), pad_end.len()), - ); - } - } - } - } -} - -#[test] -fn floor_char_boundary() { - fn check_many(s: &str, arg: impl IntoIterator, ret: usize) { - for idx in arg { - assert_eq!( - s.floor_char_boundary(idx), - ret, - "{:?}.floor_char_boundary({:?}) != {:?}", - s, - idx, - ret - ); - } - } - - // edge case - check_many("", [0, 1, isize::MAX as usize, usize::MAX], 0); - - // basic check - check_many("x", [0], 0); - check_many("x", [1, isize::MAX as usize, usize::MAX], 1); - - // 1-byte chars - check_many("jp", [0], 0); - check_many("jp", [1], 1); - check_many("jp", 2..4, 2); - - // 2-byte chars - check_many("ĵƥ", 0..2, 0); - check_many("ĵƥ", 2..4, 2); - check_many("ĵƥ", 4..6, 4); - - // 3-byte chars - check_many("日本", 0..3, 0); - check_many("日本", 3..6, 3); - check_many("日本", 6..8, 6); - - // 4-byte chars - check_many("🇯🇵", 0..4, 0); - check_many("🇯🇵", 4..8, 4); - check_many("🇯🇵", 8..10, 8); -} - -#[test] -fn ceil_char_boundary() { - fn check_many(s: &str, arg: impl IntoIterator, ret: usize) { - for idx in arg { - assert_eq!( - s.ceil_char_boundary(idx), - ret, - "{:?}.ceil_char_boundary({:?}) != {:?}", - s, - idx, - ret - ); - } - } - - // edge case - check_many("", [0], 0); - - // basic check - check_many("x", [0], 0); - check_many("x", [1], 1); - - // 1-byte chars - check_many("jp", [0], 0); - check_many("jp", [1], 1); - check_many("jp", [2], 2); - - // 2-byte chars - check_many("ĵƥ", 0..=0, 0); - check_many("ĵƥ", 1..=2, 2); - check_many("ĵƥ", 3..=4, 4); - - // 3-byte chars - check_many("日本", 0..=0, 0); - check_many("日本", 1..=3, 3); - check_many("日本", 4..=6, 6); - - // 4-byte chars - check_many("🇯🇵", 0..=0, 0); - check_many("🇯🇵", 1..=4, 4); - check_many("🇯🇵", 5..=8, 8); - - // above len - check_many("hello", 5..=10, 5); -} diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs deleted file mode 100644 index d996c55f946..00000000000 --- a/library/alloc/tests/string.rs +++ /dev/null @@ -1,914 +0,0 @@ -use std::assert_matches::assert_matches; -use std::borrow::Cow; -use std::cell::Cell; -use std::collections::TryReserveErrorKind::*; -use std::ops::Bound::*; -use std::ops::{Bound, RangeBounds}; -use std::{panic, str}; - -pub trait IntoCow<'a, B: ?Sized> -where - B: ToOwned, -{ - fn into_cow(self) -> Cow<'a, B>; -} - -impl<'a> IntoCow<'a, str> for String { - fn into_cow(self) -> Cow<'a, str> { - Cow::Owned(self) - } -} - -impl<'a> IntoCow<'a, str> for &'a str { - fn into_cow(self) -> Cow<'a, str> { - Cow::Borrowed(self) - } -} - -#[test] -fn test_from_str() { - let owned: Option = "string".parse().ok(); - assert_eq!(owned.as_ref().map(|s| &**s), Some("string")); -} - -#[test] -fn test_from_cow_str() { - assert_eq!(String::from(Cow::Borrowed("string")), "string"); - assert_eq!(String::from(Cow::Owned(String::from("string"))), "string"); -} - -#[test] -fn test_unsized_to_string() { - let s: &str = "abc"; - let _: String = (*s).to_string(); -} - -#[test] -fn test_from_utf8() { - let xs = b"hello".to_vec(); - assert_eq!(String::from_utf8(xs).unwrap(), String::from("hello")); - - let xs = "ศไทย中华Việt Nam".as_bytes().to_vec(); - assert_eq!(String::from_utf8(xs).unwrap(), String::from("ศไทย中华Việt Nam")); - - let xs = b"hello\xFF".to_vec(); - let err = String::from_utf8(xs).unwrap_err(); - assert_eq!(err.as_bytes(), b"hello\xff"); - let err_clone = err.clone(); - assert_eq!(err, err_clone); - assert_eq!(err.into_bytes(), b"hello\xff".to_vec()); - assert_eq!(err_clone.utf8_error().valid_up_to(), 5); -} - -#[test] -fn test_from_utf8_lossy() { - let xs = b"hello"; - let ys: Cow<'_, str> = "hello".into_cow(); - assert_eq!(String::from_utf8_lossy(xs), ys); - - let xs = "ศไทย中华Việt Nam".as_bytes(); - let ys: Cow<'_, str> = "ศไทย中华Việt Nam".into_cow(); - assert_eq!(String::from_utf8_lossy(xs), ys); - - let xs = b"Hello\xC2 There\xFF Goodbye"; - assert_eq!( - String::from_utf8_lossy(xs), - String::from("Hello\u{FFFD} There\u{FFFD} Goodbye").into_cow() - ); - - let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; - assert_eq!( - String::from_utf8_lossy(xs), - String::from("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye").into_cow() - ); - - let xs = b"\xF5foo\xF5\x80bar"; - assert_eq!( - String::from_utf8_lossy(xs), - String::from("\u{FFFD}foo\u{FFFD}\u{FFFD}bar").into_cow() - ); - - let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz"; - assert_eq!( - String::from_utf8_lossy(xs), - String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}baz").into_cow() - ); - - let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz"; - assert_eq!( - String::from_utf8_lossy(xs), - String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}\u{FFFD}baz").into_cow() - ); - - let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar"; - assert_eq!( - String::from_utf8_lossy(xs), - String::from("\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}foo\u{10000}bar").into_cow() - ); - - // surrogates - let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar"; - assert_eq!( - String::from_utf8_lossy(xs), - String::from("\u{FFFD}\u{FFFD}\u{FFFD}foo\u{FFFD}\u{FFFD}\u{FFFD}bar").into_cow() - ); -} - -#[test] -fn test_fromutf8error_into_lossy() { - fn func(input: &[u8]) -> String { - String::from_utf8(input.to_owned()).unwrap_or_else(|e| e.into_utf8_lossy()) - } - - let xs = b"hello"; - let ys = "hello".to_owned(); - assert_eq!(func(xs), ys); - - let xs = "ศไทย中华Việt Nam".as_bytes(); - let ys = "ศไทย中华Việt Nam".to_owned(); - assert_eq!(func(xs), ys); - - let xs = b"Hello\xC2 There\xFF Goodbye"; - assert_eq!(func(xs), "Hello\u{FFFD} There\u{FFFD} Goodbye".to_owned()); - - let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; - assert_eq!(func(xs), "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye".to_owned()); - - let xs = b"\xF5foo\xF5\x80bar"; - assert_eq!(func(xs), "\u{FFFD}foo\u{FFFD}\u{FFFD}bar".to_owned()); - - let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz"; - assert_eq!(func(xs), "\u{FFFD}foo\u{FFFD}bar\u{FFFD}baz".to_owned()); - - let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz"; - assert_eq!(func(xs), "\u{FFFD}foo\u{FFFD}bar\u{FFFD}\u{FFFD}baz".to_owned()); - - let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar"; - assert_eq!(func(xs), "\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}foo\u{10000}bar".to_owned()); - - // surrogates - let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar"; - assert_eq!(func(xs), "\u{FFFD}\u{FFFD}\u{FFFD}foo\u{FFFD}\u{FFFD}\u{FFFD}bar".to_owned()); -} - -#[test] -fn test_from_utf16() { - let pairs = [ - ( - String::from("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"), - vec![ - 0xd800, 0xdf45, 0xd800, 0xdf3f, 0xd800, 0xdf3b, 0xd800, 0xdf46, 0xd800, 0xdf39, - 0xd800, 0xdf3b, 0xd800, 0xdf30, 0x000a, - ], - ), - ( - String::from("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"), - vec![ - 0xd801, 0xdc12, 0xd801, 0xdc49, 0xd801, 0xdc2e, 0xd801, 0xdc40, 0xd801, 0xdc32, - 0xd801, 0xdc4b, 0x0020, 0xd801, 0xdc0f, 0xd801, 0xdc32, 0xd801, 0xdc4d, 0x000a, - ], - ), - ( - String::from("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"), - vec![ - 0xd800, 0xdf00, 0xd800, 0xdf16, 0xd800, 0xdf0b, 0xd800, 0xdf04, 0xd800, 0xdf11, - 0xd800, 0xdf09, 0x00b7, 0xd800, 0xdf0c, 0xd800, 0xdf04, 0xd800, 0xdf15, 0xd800, - 0xdf04, 0xd800, 0xdf0b, 0xd800, 0xdf09, 0xd800, 0xdf11, 0x000a, - ], - ), - ( - String::from("𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n"), - vec![ - 0xd801, 0xdc8b, 0xd801, 0xdc98, 0xd801, 0xdc88, 0xd801, 0xdc91, 0xd801, 0xdc9b, - 0xd801, 0xdc92, 0x0020, 0xd801, 0xdc95, 0xd801, 0xdc93, 0x0020, 0xd801, 0xdc88, - 0xd801, 0xdc9a, 0xd801, 0xdc8d, 0x0020, 0xd801, 0xdc8f, 0xd801, 0xdc9c, 0xd801, - 0xdc92, 0xd801, 0xdc96, 0xd801, 0xdc86, 0x0020, 0xd801, 0xdc95, 0xd801, 0xdc86, - 0x000a, - ], - ), - // Issue #12318, even-numbered non-BMP planes - (String::from("\u{20000}"), vec![0xD840, 0xDC00]), - ]; - - for p in &pairs { - let (s, u) = (*p).clone(); - let s_as_utf16 = s.encode_utf16().collect::>(); - let u_as_string = String::from_utf16(&u).unwrap(); - - assert!(core::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); - assert_eq!(s_as_utf16, u); - - assert_eq!(u_as_string, s); - assert_eq!(String::from_utf16_lossy(&u), s); - - assert_eq!(String::from_utf16(&s_as_utf16).unwrap(), s); - assert_eq!(u_as_string.encode_utf16().collect::>(), u); - } -} - -#[test] -fn test_utf16_invalid() { - // completely positive cases tested above. - // lead + eof - assert!(String::from_utf16(&[0xD800]).is_err()); - // lead + lead - assert!(String::from_utf16(&[0xD800, 0xD800]).is_err()); - - // isolated trail - assert!(String::from_utf16(&[0x0061, 0xDC00]).is_err()); - - // general - assert!(String::from_utf16(&[0xD800, 0xd801, 0xdc8b, 0xD800]).is_err()); -} - -#[test] -fn test_from_utf16_lossy() { - // completely positive cases tested above. - // lead + eof - assert_eq!(String::from_utf16_lossy(&[0xD800]), String::from("\u{FFFD}")); - // lead + lead - assert_eq!(String::from_utf16_lossy(&[0xD800, 0xD800]), String::from("\u{FFFD}\u{FFFD}")); - - // isolated trail - assert_eq!(String::from_utf16_lossy(&[0x0061, 0xDC00]), String::from("a\u{FFFD}")); - - // general - assert_eq!( - String::from_utf16_lossy(&[0xD800, 0xd801, 0xdc8b, 0xD800]), - String::from("\u{FFFD}𐒋\u{FFFD}") - ); -} - -#[test] -fn test_push_bytes() { - let mut s = String::from("ABC"); - unsafe { - let mv = s.as_mut_vec(); - mv.extend_from_slice(&[b'D']); - } - assert_eq!(s, "ABCD"); -} - -#[test] -fn test_push_str() { - let mut s = String::new(); - s.push_str(""); - assert_eq!(&s[0..], ""); - s.push_str("abc"); - assert_eq!(&s[0..], "abc"); - s.push_str("ประเทศไทย中华Việt Nam"); - assert_eq!(&s[0..], "abcประเทศไทย中华Việt Nam"); -} - -#[test] -fn test_add_assign() { - let mut s = String::new(); - s += ""; - assert_eq!(s.as_str(), ""); - s += "abc"; - assert_eq!(s.as_str(), "abc"); - s += "ประเทศไทย中华Việt Nam"; - assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam"); -} - -#[test] -fn test_push() { - let mut data = String::from("ประเทศไทย中"); - data.push('华'); - data.push('b'); // 1 byte - data.push('¢'); // 2 byte - data.push('€'); // 3 byte - data.push('𤭢'); // 4 byte - assert_eq!(data, "ประเทศไทย中华b¢€𤭢"); -} - -#[test] -fn test_pop() { - let mut data = String::from("ประเทศไทย中华b¢€𤭢"); - assert_eq!(data.pop().unwrap(), '𤭢'); // 4 bytes - assert_eq!(data.pop().unwrap(), '€'); // 3 bytes - assert_eq!(data.pop().unwrap(), '¢'); // 2 bytes - assert_eq!(data.pop().unwrap(), 'b'); // 1 bytes - assert_eq!(data.pop().unwrap(), '华'); - assert_eq!(data, "ประเทศไทย中"); -} - -#[test] -fn test_split_off_empty() { - let orig = "Hello, world!"; - let mut split = String::from(orig); - let empty: String = split.split_off(orig.len()); - assert!(empty.is_empty()); -} - -#[test] -#[should_panic] -fn test_split_off_past_end() { - let orig = "Hello, world!"; - let mut split = String::from(orig); - let _ = split.split_off(orig.len() + 1); -} - -#[test] -#[should_panic] -fn test_split_off_mid_char() { - let mut shan = String::from("山"); - let _broken_mountain = shan.split_off(1); -} - -#[test] -fn test_split_off_ascii() { - let mut ab = String::from("ABCD"); - let orig_capacity = ab.capacity(); - let cd = ab.split_off(2); - assert_eq!(ab, "AB"); - assert_eq!(cd, "CD"); - assert_eq!(ab.capacity(), orig_capacity); -} - -#[test] -fn test_split_off_unicode() { - let mut nihon = String::from("日本語"); - let orig_capacity = nihon.capacity(); - let go = nihon.split_off("日本".len()); - assert_eq!(nihon, "日本"); - assert_eq!(go, "語"); - assert_eq!(nihon.capacity(), orig_capacity); -} - -#[test] -fn test_str_truncate() { - let mut s = String::from("12345"); - s.truncate(5); - assert_eq!(s, "12345"); - s.truncate(3); - assert_eq!(s, "123"); - s.truncate(0); - assert_eq!(s, ""); - - let mut s = String::from("12345"); - let p = s.as_ptr(); - s.truncate(3); - s.push_str("6"); - let p_ = s.as_ptr(); - assert_eq!(p_, p); -} - -#[test] -fn test_str_truncate_invalid_len() { - let mut s = String::from("12345"); - s.truncate(6); - assert_eq!(s, "12345"); -} - -#[test] -#[should_panic] -fn test_str_truncate_split_codepoint() { - let mut s = String::from("\u{FC}"); // ü - s.truncate(1); -} - -#[test] -fn test_str_clear() { - let mut s = String::from("12345"); - s.clear(); - assert_eq!(s.len(), 0); - assert_eq!(s, ""); -} - -#[test] -fn test_str_add() { - let a = String::from("12345"); - let b = a + "2"; - let b = b + "2"; - assert_eq!(b.len(), 7); - assert_eq!(b, "1234522"); -} - -#[test] -fn remove() { - let mut s = "ศไทย中华Việt Nam; foobar".to_string(); - assert_eq!(s.remove(0), 'ศ'); - assert_eq!(s.len(), 33); - assert_eq!(s, "ไทย中华Việt Nam; foobar"); - assert_eq!(s.remove(17), 'ệ'); - assert_eq!(s, "ไทย中华Vit Nam; foobar"); -} - -#[test] -#[should_panic] -fn remove_bad() { - "ศ".to_string().remove(1); -} - -#[test] -fn test_remove_matches() { - // test_single_pattern_occurrence - let mut s = "abc".to_string(); - s.remove_matches('b'); - assert_eq!(s, "ac"); - // repeat_test_single_pattern_occurrence - s.remove_matches('b'); - assert_eq!(s, "ac"); - - // test_single_character_pattern - let mut s = "abcb".to_string(); - s.remove_matches('b'); - assert_eq!(s, "ac"); - - // test_pattern_with_special_characters - let mut s = "ศไทย中华Việt Nam; foobarศ".to_string(); - s.remove_matches('ศ'); - assert_eq!(s, "ไทย中华Việt Nam; foobar"); - - // test_pattern_empty_text_and_pattern - let mut s = "".to_string(); - s.remove_matches(""); - assert_eq!(s, ""); - - // test_pattern_empty_text - let mut s = "".to_string(); - s.remove_matches("something"); - assert_eq!(s, ""); - - // test_empty_pattern - let mut s = "Testing with empty pattern.".to_string(); - s.remove_matches(""); - assert_eq!(s, "Testing with empty pattern."); - - // test_multiple_consecutive_patterns_1 - let mut s = "aaaaa".to_string(); - s.remove_matches('a'); - assert_eq!(s, ""); - - // test_multiple_consecutive_patterns_2 - let mut s = "Hello **world****today!**".to_string(); - s.remove_matches("**"); - assert_eq!(s, "Hello worldtoday!"); - - // test_case_insensitive_pattern - let mut s = "CASE ** SeNsItIvE ** PaTtErN.".to_string(); - s.remove_matches("sEnSiTiVe"); - assert_eq!(s, "CASE ** SeNsItIvE ** PaTtErN."); - - // test_pattern_with_digits - let mut s = "123 ** 456 ** 789".to_string(); - s.remove_matches("**"); - assert_eq!(s, "123 456 789"); - - // test_pattern_occurs_after_empty_string - let mut s = "abc X defXghi".to_string(); - s.remove_matches("X"); - assert_eq!(s, "abc defghi"); - - // test_large_pattern - let mut s = "aaaXbbbXcccXdddXeee".to_string(); - s.remove_matches("X"); - assert_eq!(s, "aaabbbcccdddeee"); - - // test_pattern_at_multiple_positions - let mut s = "Pattern ** found ** multiple ** times ** in ** text.".to_string(); - s.remove_matches("**"); - assert_eq!(s, "Pattern found multiple times in text."); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_retain() { - let mut s = String::from("α_β_γ"); - - s.retain(|_| true); - assert_eq!(s, "α_β_γ"); - - s.retain(|c| c != '_'); - assert_eq!(s, "αβγ"); - - s.retain(|c| c != 'β'); - assert_eq!(s, "αγ"); - - s.retain(|c| c == 'α'); - assert_eq!(s, "α"); - - s.retain(|_| false); - assert_eq!(s, ""); - - let mut s = String::from("0è0"); - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { - let mut count = 0; - s.retain(|_| { - count += 1; - match count { - 1 => false, - 2 => true, - _ => panic!(), - } - }); - })); - assert!(std::str::from_utf8(s.as_bytes()).is_ok()); -} - -#[test] -fn insert() { - let mut s = "foobar".to_string(); - s.insert(0, 'ệ'); - assert_eq!(s, "ệfoobar"); - s.insert(6, 'ย'); - assert_eq!(s, "ệfooยbar"); -} - -#[test] -#[should_panic] -fn insert_bad1() { - "".to_string().insert(1, 't'); -} -#[test] -#[should_panic] -fn insert_bad2() { - "ệ".to_string().insert(1, 't'); -} - -#[test] -fn test_slicing() { - let s = "foobar".to_string(); - assert_eq!("foobar", &s[..]); - assert_eq!("foo", &s[..3]); - assert_eq!("bar", &s[3..]); - assert_eq!("oob", &s[1..4]); -} - -#[test] -fn test_simple_types() { - assert_eq!(1.to_string(), "1"); - assert_eq!((-1).to_string(), "-1"); - assert_eq!(200.to_string(), "200"); - assert_eq!(2.to_string(), "2"); - assert_eq!(true.to_string(), "true"); - assert_eq!(false.to_string(), "false"); - assert_eq!(("hi".to_string()).to_string(), "hi"); -} - -#[test] -fn test_vectors() { - let x: Vec = vec![]; - assert_eq!(format!("{x:?}"), "[]"); - assert_eq!(format!("{:?}", vec![1]), "[1]"); - assert_eq!(format!("{:?}", vec![1, 2, 3]), "[1, 2, 3]"); - assert!(format!("{:?}", vec![vec![], vec![1], vec![1, 1]]) == "[[], [1], [1, 1]]"); -} - -#[test] -fn test_from_iterator() { - let s = "ศไทย中华Việt Nam".to_string(); - let t = "ศไทย中华"; - let u = "Việt Nam"; - - let a: String = s.chars().collect(); - assert_eq!(s, a); - - let mut b = t.to_string(); - b.extend(u.chars()); - assert_eq!(s, b); - - let c: String = [t, u].into_iter().collect(); - assert_eq!(s, c); - - let mut d = t.to_string(); - d.extend(vec![u]); - assert_eq!(s, d); -} - -#[test] -fn test_drain() { - let mut s = String::from("αβγ"); - assert_eq!(s.drain(2..4).collect::(), "β"); - assert_eq!(s, "αγ"); - - let mut t = String::from("abcd"); - t.drain(..0); - assert_eq!(t, "abcd"); - t.drain(..1); - assert_eq!(t, "bcd"); - t.drain(3..); - assert_eq!(t, "bcd"); - t.drain(..); - assert_eq!(t, ""); -} - -#[test] -#[should_panic] -fn test_drain_start_overflow() { - let mut s = String::from("abc"); - s.drain((Excluded(usize::MAX), Included(0))); -} - -#[test] -#[should_panic] -fn test_drain_end_overflow() { - let mut s = String::from("abc"); - s.drain((Included(0), Included(usize::MAX))); -} - -#[test] -fn test_replace_range() { - let mut s = "Hello, world!".to_owned(); - s.replace_range(7..12, "世界"); - assert_eq!(s, "Hello, 世界!"); -} - -#[test] -#[should_panic] -fn test_replace_range_char_boundary() { - let mut s = "Hello, 世界!".to_owned(); - s.replace_range(..8, ""); -} - -#[test] -fn test_replace_range_inclusive_range() { - let mut v = String::from("12345"); - v.replace_range(2..=3, "789"); - assert_eq!(v, "127895"); - v.replace_range(1..=2, "A"); - assert_eq!(v, "1A895"); -} - -#[test] -#[should_panic] -fn test_replace_range_out_of_bounds() { - let mut s = String::from("12345"); - s.replace_range(5..6, "789"); -} - -#[test] -#[should_panic] -fn test_replace_range_inclusive_out_of_bounds() { - let mut s = String::from("12345"); - s.replace_range(5..=5, "789"); -} - -#[test] -#[should_panic] -fn test_replace_range_start_overflow() { - let mut s = String::from("123"); - s.replace_range((Excluded(usize::MAX), Included(0)), ""); -} - -#[test] -#[should_panic] -fn test_replace_range_end_overflow() { - let mut s = String::from("456"); - s.replace_range((Included(0), Included(usize::MAX)), ""); -} - -#[test] -fn test_replace_range_empty() { - let mut s = String::from("12345"); - s.replace_range(1..2, ""); - assert_eq!(s, "1345"); -} - -#[test] -fn test_replace_range_unbounded() { - let mut s = String::from("12345"); - s.replace_range(.., ""); - assert_eq!(s, ""); -} - -#[test] -fn test_replace_range_evil_start_bound() { - struct EvilRange(Cell); - - impl RangeBounds for EvilRange { - fn start_bound(&self) -> Bound<&usize> { - Bound::Included(if self.0.get() { - &1 - } else { - self.0.set(true); - &0 - }) - } - fn end_bound(&self) -> Bound<&usize> { - Bound::Unbounded - } - } - - let mut s = String::from("🦀"); - s.replace_range(EvilRange(Cell::new(false)), ""); - assert_eq!(Ok(""), str::from_utf8(s.as_bytes())); -} - -#[test] -fn test_replace_range_evil_end_bound() { - struct EvilRange(Cell); - - impl RangeBounds for EvilRange { - fn start_bound(&self) -> Bound<&usize> { - Bound::Included(&0) - } - fn end_bound(&self) -> Bound<&usize> { - Bound::Excluded(if self.0.get() { - &3 - } else { - self.0.set(true); - &4 - }) - } - } - - let mut s = String::from("🦀"); - s.replace_range(EvilRange(Cell::new(false)), ""); - assert_eq!(Ok(""), str::from_utf8(s.as_bytes())); -} - -#[test] -fn test_extend_ref() { - let mut a = "foo".to_string(); - a.extend(&['b', 'a', 'r']); - - assert_eq!(&a, "foobar"); -} - -#[test] -fn test_into_boxed_str() { - let xs = String::from("hello my name is bob"); - let ys = xs.into_boxed_str(); - assert_eq!(&*ys, "hello my name is bob"); -} - -#[test] -fn test_reserve_exact() { - // This is all the same as test_reserve - - let mut s = String::new(); - assert_eq!(s.capacity(), 0); - - s.reserve_exact(2); - assert!(s.capacity() >= 2); - - for _i in 0..16 { - s.push('0'); - } - - assert!(s.capacity() >= 16); - s.reserve_exact(16); - assert!(s.capacity() >= 32); - - s.push('0'); - - s.reserve_exact(16); - assert!(s.capacity() >= 33) -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM -fn test_try_with_capacity() { - let string = String::try_with_capacity(1000).unwrap(); - assert_eq!(0, string.len()); - assert!(string.capacity() >= 1000 && string.capacity() <= isize::MAX as usize); - - assert!(String::try_with_capacity(usize::MAX).is_err()); -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM -fn test_try_reserve() { - // These are the interesting cases: - // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM) - // * > isize::MAX should always fail - // * On 16/32-bit should CapacityOverflow - // * On 64-bit should OOM - // * overflow may trigger when adding `len` to `cap` (in number of elements) - // * overflow may trigger when multiplying `new_cap` by size_of:: (to get bytes) - - const MAX_CAP: usize = isize::MAX as usize; - const MAX_USIZE: usize = usize::MAX; - - { - // Note: basic stuff is checked by test_reserve - let mut empty_string: String = String::new(); - - // Check isize::MAX doesn't count as an overflow - if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - // Play it again, frank! (just to be sure) - if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } - - { - // Same basic idea, but with non-zero len - let mut ten_bytes: String = String::from("0123456789"); - - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Should always overflow in the add-to-len - assert_matches!( - ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM -fn test_try_reserve_exact() { - // This is exactly the same as test_try_reserve with the method changed. - // See that test for comments. - - const MAX_CAP: usize = isize::MAX as usize; - const MAX_USIZE: usize = usize::MAX; - - { - let mut empty_string: String = String::new(); - - if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } - - { - let mut ten_bytes: String = String::from("0123456789"); - - if let Err(CapacityOverflow) = - ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = - ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } -} - -#[test] -fn test_from_char() { - assert_eq!(String::from('a'), 'a'.to_string()); - let s: String = 'x'.into(); - assert_eq!(s, 'x'.to_string()); -} - -#[test] -fn test_str_concat() { - let a: String = "hello".to_string(); - let b: String = "world".to_string(); - let s: String = format!("{a}{b}"); - assert_eq!(s.as_bytes()[9], 'd' as u8); -} diff --git a/library/alloc/tests/sync.rs b/library/alloc/tests/sync.rs deleted file mode 100644 index 6d3ab1b1d11..00000000000 --- a/library/alloc/tests/sync.rs +++ /dev/null @@ -1,720 +0,0 @@ -use alloc::sync::*; -use std::alloc::{AllocError, Allocator, Layout}; -use std::any::Any; -use std::clone::Clone; -use std::mem::MaybeUninit; -use std::option::Option::None; -use std::ptr::NonNull; -use std::sync::Mutex; -use std::sync::atomic::Ordering::*; -use std::sync::atomic::{self, AtomicUsize}; -use std::sync::mpsc::channel; -use std::thread; - -struct Canary(*mut AtomicUsize); - -impl Drop for Canary { - fn drop(&mut self) { - unsafe { - match *self { - Canary(c) => { - (*c).fetch_add(1, SeqCst); - } - } - } - } -} - -struct AllocCanary<'a>(&'a AtomicUsize); - -impl<'a> AllocCanary<'a> { - fn new(counter: &'a AtomicUsize) -> Self { - counter.fetch_add(1, SeqCst); - Self(counter) - } -} - -unsafe impl Allocator for AllocCanary<'_> { - fn allocate(&self, layout: Layout) -> Result, AllocError> { - std::alloc::Global.allocate(layout) - } - - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - unsafe { std::alloc::Global.deallocate(ptr, layout) } - } -} - -impl Clone for AllocCanary<'_> { - fn clone(&self) -> Self { - Self::new(self.0) - } -} - -impl Drop for AllocCanary<'_> { - fn drop(&mut self) { - self.0.fetch_sub(1, SeqCst); - } -} - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn manually_share_arc() { - let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let arc_v = Arc::new(v); - - let (tx, rx) = channel(); - - let _t = thread::spawn(move || { - let arc_v: Arc> = rx.recv().unwrap(); - assert_eq!((*arc_v)[3], 4); - }); - - tx.send(arc_v.clone()).unwrap(); - - assert_eq!((*arc_v)[2], 3); - assert_eq!((*arc_v)[4], 5); -} - -#[test] -fn test_arc_get_mut() { - let mut x = Arc::new(3); - *Arc::get_mut(&mut x).unwrap() = 4; - assert_eq!(*x, 4); - let y = x.clone(); - assert!(Arc::get_mut(&mut x).is_none()); - drop(y); - assert!(Arc::get_mut(&mut x).is_some()); - let _w = Arc::downgrade(&x); - assert!(Arc::get_mut(&mut x).is_none()); -} - -#[test] -fn weak_counts() { - assert_eq!(Weak::weak_count(&Weak::::new()), 0); - assert_eq!(Weak::strong_count(&Weak::::new()), 0); - - let a = Arc::new(0); - let w = Arc::downgrade(&a); - assert_eq!(Weak::strong_count(&w), 1); - assert_eq!(Weak::weak_count(&w), 1); - let w2 = w.clone(); - assert_eq!(Weak::strong_count(&w), 1); - assert_eq!(Weak::weak_count(&w), 2); - assert_eq!(Weak::strong_count(&w2), 1); - assert_eq!(Weak::weak_count(&w2), 2); - drop(w); - assert_eq!(Weak::strong_count(&w2), 1); - assert_eq!(Weak::weak_count(&w2), 1); - let a2 = a.clone(); - assert_eq!(Weak::strong_count(&w2), 2); - assert_eq!(Weak::weak_count(&w2), 1); - drop(a2); - drop(a); - assert_eq!(Weak::strong_count(&w2), 0); - assert_eq!(Weak::weak_count(&w2), 0); - drop(w2); -} - -#[test] -fn try_unwrap() { - let x = Arc::new(3); - assert_eq!(Arc::try_unwrap(x), Ok(3)); - let x = Arc::new(4); - let _y = x.clone(); - assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4))); - let x = Arc::new(5); - let _w = Arc::downgrade(&x); - assert_eq!(Arc::try_unwrap(x), Ok(5)); -} - -#[test] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads -fn into_inner() { - for _ in 0..100 - // ^ Increase chances of hitting potential race conditions - { - let x = Arc::new(3); - let y = Arc::clone(&x); - let r_thread = std::thread::spawn(|| Arc::into_inner(x)); - let s_thread = std::thread::spawn(|| Arc::into_inner(y)); - let r = r_thread.join().expect("r_thread panicked"); - let s = s_thread.join().expect("s_thread panicked"); - assert!( - matches!((r, s), (None, Some(3)) | (Some(3), None)), - "assertion failed: unexpected result `{:?}`\ - \n expected `(None, Some(3))` or `(Some(3), None)`", - (r, s), - ); - } - - let x = Arc::new(3); - assert_eq!(Arc::into_inner(x), Some(3)); - - let x = Arc::new(4); - let y = Arc::clone(&x); - assert_eq!(Arc::into_inner(x), None); - assert_eq!(Arc::into_inner(y), Some(4)); - - let x = Arc::new(5); - let _w = Arc::downgrade(&x); - assert_eq!(Arc::into_inner(x), Some(5)); -} - -#[test] -fn into_from_raw() { - let x = Arc::new(Box::new("hello")); - let y = x.clone(); - - let x_ptr = Arc::into_raw(x); - drop(y); - unsafe { - assert_eq!(**x_ptr, "hello"); - - let x = Arc::from_raw(x_ptr); - assert_eq!(**x, "hello"); - - assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello")); - } -} - -#[test] -fn test_into_from_raw_unsized() { - use std::fmt::Display; - use std::string::ToString; - - let arc: Arc = Arc::from("foo"); - - let ptr = Arc::into_raw(arc.clone()); - let arc2 = unsafe { Arc::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }, "foo"); - assert_eq!(arc, arc2); - - let arc: Arc = Arc::new(123); - - let ptr = Arc::into_raw(arc.clone()); - let arc2 = unsafe { Arc::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }.to_string(), "123"); - assert_eq!(arc2.to_string(), "123"); -} - -#[test] -fn into_from_weak_raw() { - let x = Arc::new(Box::new("hello")); - let y = Arc::downgrade(&x); - - let y_ptr = Weak::into_raw(y); - unsafe { - assert_eq!(**y_ptr, "hello"); - - let y = Weak::from_raw(y_ptr); - let y_up = Weak::upgrade(&y).unwrap(); - assert_eq!(**y_up, "hello"); - drop(y_up); - - assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello")); - } -} - -#[test] -fn test_into_from_weak_raw_unsized() { - use std::fmt::Display; - use std::string::ToString; - - let arc: Arc = Arc::from("foo"); - let weak: Weak = Arc::downgrade(&arc); - - let ptr = Weak::into_raw(weak.clone()); - let weak2 = unsafe { Weak::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }, "foo"); - assert!(weak.ptr_eq(&weak2)); - - let arc: Arc = Arc::new(123); - let weak: Weak = Arc::downgrade(&arc); - - let ptr = Weak::into_raw(weak.clone()); - let weak2 = unsafe { Weak::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }.to_string(), "123"); - assert!(weak.ptr_eq(&weak2)); -} - -#[test] -fn test_cowarc_clone_make_mut() { - let mut cow0 = Arc::new(75); - let mut cow1 = cow0.clone(); - let mut cow2 = cow1.clone(); - - assert!(75 == *Arc::make_mut(&mut cow0)); - assert!(75 == *Arc::make_mut(&mut cow1)); - assert!(75 == *Arc::make_mut(&mut cow2)); - - *Arc::make_mut(&mut cow0) += 1; - *Arc::make_mut(&mut cow1) += 2; - *Arc::make_mut(&mut cow2) += 3; - - assert!(76 == *cow0); - assert!(77 == *cow1); - assert!(78 == *cow2); - - // none should point to the same backing memory - assert!(*cow0 != *cow1); - assert!(*cow0 != *cow2); - assert!(*cow1 != *cow2); -} - -#[test] -fn test_cowarc_clone_unique2() { - let mut cow0 = Arc::new(75); - let cow1 = cow0.clone(); - let cow2 = cow1.clone(); - - assert!(75 == *cow0); - assert!(75 == *cow1); - assert!(75 == *cow2); - - *Arc::make_mut(&mut cow0) += 1; - assert!(76 == *cow0); - assert!(75 == *cow1); - assert!(75 == *cow2); - - // cow1 and cow2 should share the same contents - // cow0 should have a unique reference - assert!(*cow0 != *cow1); - assert!(*cow0 != *cow2); - assert!(*cow1 == *cow2); -} - -#[test] -fn test_cowarc_clone_weak() { - let mut cow0 = Arc::new(75); - let cow1_weak = Arc::downgrade(&cow0); - - assert!(75 == *cow0); - assert!(75 == *cow1_weak.upgrade().unwrap()); - - *Arc::make_mut(&mut cow0) += 1; - - assert!(76 == *cow0); - assert!(cow1_weak.upgrade().is_none()); -} - -#[test] -fn test_live() { - let x = Arc::new(5); - let y = Arc::downgrade(&x); - assert!(y.upgrade().is_some()); -} - -#[test] -fn test_dead() { - let x = Arc::new(5); - let y = Arc::downgrade(&x); - drop(x); - assert!(y.upgrade().is_none()); -} - -#[test] -fn weak_self_cyclic() { - struct Cycle { - x: Mutex>>, - } - - let a = Arc::new(Cycle { x: Mutex::new(None) }); - let b = Arc::downgrade(&a.clone()); - *a.x.lock().unwrap() = Some(b); - - // hopefully we don't double-free (or leak)... -} - -#[test] -fn drop_arc() { - let mut canary = AtomicUsize::new(0); - let x = Arc::new(Canary(&mut canary as *mut AtomicUsize)); - drop(x); - assert!(canary.load(Acquire) == 1); -} - -#[test] -fn drop_arc_weak() { - let mut canary = AtomicUsize::new(0); - let arc = Arc::new(Canary(&mut canary as *mut AtomicUsize)); - let arc_weak = Arc::downgrade(&arc); - assert!(canary.load(Acquire) == 0); - drop(arc); - assert!(canary.load(Acquire) == 1); - drop(arc_weak); -} - -#[test] -fn test_strong_count() { - let a = Arc::new(0); - assert!(Arc::strong_count(&a) == 1); - let w = Arc::downgrade(&a); - assert!(Arc::strong_count(&a) == 1); - let b = w.upgrade().expect(""); - assert!(Arc::strong_count(&b) == 2); - assert!(Arc::strong_count(&a) == 2); - drop(w); - drop(a); - assert!(Arc::strong_count(&b) == 1); - let c = b.clone(); - assert!(Arc::strong_count(&b) == 2); - assert!(Arc::strong_count(&c) == 2); -} - -#[test] -fn test_weak_count() { - let a = Arc::new(0); - assert!(Arc::strong_count(&a) == 1); - assert!(Arc::weak_count(&a) == 0); - let w = Arc::downgrade(&a); - assert!(Arc::strong_count(&a) == 1); - assert!(Arc::weak_count(&a) == 1); - let x = w.clone(); - assert!(Arc::weak_count(&a) == 2); - drop(w); - drop(x); - assert!(Arc::strong_count(&a) == 1); - assert!(Arc::weak_count(&a) == 0); - let c = a.clone(); - assert!(Arc::strong_count(&a) == 2); - assert!(Arc::weak_count(&a) == 0); - let d = Arc::downgrade(&c); - assert!(Arc::weak_count(&c) == 1); - assert!(Arc::strong_count(&c) == 2); - - drop(a); - drop(c); - drop(d); -} - -#[test] -fn show_arc() { - let a = Arc::new(5); - assert_eq!(format!("{a:?}"), "5"); -} - -// Make sure deriving works with Arc -#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)] -struct _Foo { - inner: Arc, -} - -#[test] -fn test_unsized() { - let x: Arc<[i32]> = Arc::new([1, 2, 3]); - assert_eq!(format!("{x:?}"), "[1, 2, 3]"); - let y = Arc::downgrade(&x.clone()); - drop(x); - assert!(y.upgrade().is_none()); -} - -#[test] -fn test_maybe_thin_unsized() { - // If/when custom thin DSTs exist, this test should be updated to use one - use std::ffi::CStr; - - let x: Arc = Arc::from(c"swordfish"); - assert_eq!(format!("{x:?}"), "\"swordfish\""); - let y: Weak = Arc::downgrade(&x); - drop(x); - - // At this point, the weak points to a dropped DST - assert!(y.upgrade().is_none()); - // But we still need to be able to get the alloc layout to drop. - // CStr has no drop glue, but custom DSTs might, and need to work. - drop(y); -} - -#[test] -fn test_from_owned() { - let foo = 123; - let foo_arc = Arc::from(foo); - assert!(123 == *foo_arc); -} - -#[test] -fn test_new_weak() { - let foo: Weak = Weak::new(); - assert!(foo.upgrade().is_none()); -} - -#[test] -fn test_ptr_eq() { - let five = Arc::new(5); - let same_five = five.clone(); - let other_five = Arc::new(5); - - assert!(Arc::ptr_eq(&five, &same_five)); - assert!(!Arc::ptr_eq(&five, &other_five)); -} - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn test_weak_count_locked() { - let mut a = Arc::new(atomic::AtomicBool::new(false)); - let a2 = a.clone(); - let t = thread::spawn(move || { - // Miri is too slow - let count = if cfg!(miri) { 1000 } else { 1000000 }; - for _i in 0..count { - Arc::get_mut(&mut a); - } - a.store(true, SeqCst); - }); - - while !a2.load(SeqCst) { - let n = Arc::weak_count(&a2); - assert!(n < 2, "bad weak count: {}", n); - #[cfg(miri)] // Miri's scheduler does not guarantee liveness, and thus needs this hint. - std::hint::spin_loop(); - } - t.join().unwrap(); -} - -#[test] -fn test_from_str() { - let r: Arc = Arc::from("foo"); - - assert_eq!(&r[..], "foo"); -} - -#[test] -fn test_copy_from_slice() { - let s: &[u32] = &[1, 2, 3]; - let r: Arc<[u32]> = Arc::from(s); - - assert_eq!(&r[..], [1, 2, 3]); -} - -#[test] -fn test_clone_from_slice() { - #[derive(Clone, Debug, Eq, PartialEq)] - struct X(u32); - - let s: &[X] = &[X(1), X(2), X(3)]; - let r: Arc<[X]> = Arc::from(s); - - assert_eq!(&r[..], s); -} - -#[test] -#[should_panic] -fn test_clone_from_slice_panic() { - use std::string::{String, ToString}; - - struct Fail(u32, String); - - impl Clone for Fail { - fn clone(&self) -> Fail { - if self.0 == 2 { - panic!(); - } - Fail(self.0, self.1.clone()) - } - } - - let s: &[Fail] = - &[Fail(0, "foo".to_string()), Fail(1, "bar".to_string()), Fail(2, "baz".to_string())]; - - // Should panic, but not cause memory corruption - let _r: Arc<[Fail]> = Arc::from(s); -} - -#[test] -fn test_from_box() { - let b: Box = Box::new(123); - let r: Arc = Arc::from(b); - - assert_eq!(*r, 123); -} - -#[test] -fn test_from_box_str() { - use std::string::String; - - let s = String::from("foo").into_boxed_str(); - let r: Arc = Arc::from(s); - - assert_eq!(&r[..], "foo"); -} - -#[test] -fn test_from_box_slice() { - let s = vec![1, 2, 3].into_boxed_slice(); - let r: Arc<[u32]> = Arc::from(s); - - assert_eq!(&r[..], [1, 2, 3]); -} - -#[test] -fn test_from_box_trait() { - use std::fmt::Display; - use std::string::ToString; - - let b: Box = Box::new(123); - let r: Arc = Arc::from(b); - - assert_eq!(r.to_string(), "123"); -} - -#[test] -fn test_from_box_trait_zero_sized() { - use std::fmt::Debug; - - let b: Box = Box::new(()); - let r: Arc = Arc::from(b); - - assert_eq!(format!("{r:?}"), "()"); -} - -#[test] -fn test_from_vec() { - let v = vec![1, 2, 3]; - let r: Arc<[u32]> = Arc::from(v); - - assert_eq!(&r[..], [1, 2, 3]); -} - -#[test] -fn test_downcast() { - use std::any::Any; - - let r1: Arc = Arc::new(i32::MAX); - let r2: Arc = Arc::new("abc"); - - assert!(r1.clone().downcast::().is_err()); - - let r1i32 = r1.downcast::(); - assert!(r1i32.is_ok()); - assert_eq!(r1i32.unwrap(), Arc::new(i32::MAX)); - - assert!(r2.clone().downcast::().is_err()); - - let r2str = r2.downcast::<&'static str>(); - assert!(r2str.is_ok()); - assert_eq!(r2str.unwrap(), Arc::new("abc")); -} - -#[test] -fn test_array_from_slice() { - let v = vec![1, 2, 3]; - let r: Arc<[u32]> = Arc::from(v); - - let a: Result, _> = r.clone().try_into(); - assert!(a.is_ok()); - - let a: Result, _> = r.clone().try_into(); - assert!(a.is_err()); -} - -#[test] -fn test_arc_cyclic_with_zero_refs() { - struct ZeroRefs { - inner: Weak, - } - let zero_refs = Arc::new_cyclic(|inner| { - assert_eq!(inner.strong_count(), 0); - assert!(inner.upgrade().is_none()); - ZeroRefs { inner: Weak::new() } - }); - - assert_eq!(Arc::strong_count(&zero_refs), 1); - assert_eq!(Arc::weak_count(&zero_refs), 0); - assert_eq!(zero_refs.inner.strong_count(), 0); - assert_eq!(zero_refs.inner.weak_count(), 0); -} - -#[test] -fn test_arc_new_cyclic_one_ref() { - struct OneRef { - inner: Weak, - } - let one_ref = Arc::new_cyclic(|inner| { - assert_eq!(inner.strong_count(), 0); - assert!(inner.upgrade().is_none()); - OneRef { inner: inner.clone() } - }); - - assert_eq!(Arc::strong_count(&one_ref), 1); - assert_eq!(Arc::weak_count(&one_ref), 1); - - let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap(); - assert!(Arc::ptr_eq(&one_ref, &one_ref2)); - - assert_eq!(Arc::strong_count(&one_ref), 2); - assert_eq!(Arc::weak_count(&one_ref), 1); -} - -#[test] -fn test_arc_cyclic_two_refs() { - struct TwoRefs { - inner1: Weak, - inner2: Weak, - } - let two_refs = Arc::new_cyclic(|inner| { - assert_eq!(inner.strong_count(), 0); - assert!(inner.upgrade().is_none()); - - let inner1 = inner.clone(); - let inner2 = inner1.clone(); - - TwoRefs { inner1, inner2 } - }); - - assert_eq!(Arc::strong_count(&two_refs), 1); - assert_eq!(Arc::weak_count(&two_refs), 2); - - let two_refs1 = Weak::upgrade(&two_refs.inner1).unwrap(); - assert!(Arc::ptr_eq(&two_refs, &two_refs1)); - - let two_refs2 = Weak::upgrade(&two_refs.inner2).unwrap(); - assert!(Arc::ptr_eq(&two_refs, &two_refs2)); - - assert_eq!(Arc::strong_count(&two_refs), 3); - assert_eq!(Arc::weak_count(&two_refs), 2); -} - -/// Test for Arc::drop bug (https://github.com/rust-lang/rust/issues/55005) -#[test] -#[cfg(miri)] // relies on Stacked Borrows in Miri -fn arc_drop_dereferenceable_race() { - // The bug seems to take up to 700 iterations to reproduce with most seeds (tested 0-9). - for _ in 0..750 { - let arc_1 = Arc::new(()); - let arc_2 = arc_1.clone(); - let thread = thread::spawn(|| drop(arc_2)); - // Spin a bit; makes the race more likely to appear - let mut i = 0; - while i < 256 { - i += 1; - } - drop(arc_1); - thread.join().unwrap(); - } -} - -#[test] -fn arc_doesnt_leak_allocator() { - let counter = AtomicUsize::new(0); - - { - let arc: Arc = Arc::new_in(5usize, AllocCanary::new(&counter)); - drop(arc.downcast::().unwrap()); - - let arc: Arc = Arc::new_in(5usize, AllocCanary::new(&counter)); - drop(unsafe { arc.downcast_unchecked::() }); - - let arc = Arc::new_in(MaybeUninit::::new(5usize), AllocCanary::new(&counter)); - drop(unsafe { arc.assume_init() }); - - let arc: Arc<[MaybeUninit], _> = - Arc::new_zeroed_slice_in(5, AllocCanary::new(&counter)); - drop(unsafe { arc.assume_init() }); - } - - assert_eq!(counter.load(SeqCst), 0); -} diff --git a/library/alloc/tests/task.rs b/library/alloc/tests/task.rs deleted file mode 100644 index 390dec14484..00000000000 --- a/library/alloc/tests/task.rs +++ /dev/null @@ -1,36 +0,0 @@ -use alloc::rc::Rc; -use alloc::sync::Arc; -use alloc::task::{LocalWake, Wake}; -use core::task::{LocalWaker, Waker}; - -#[test] -#[cfg_attr(miri, ignore)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail -fn test_waker_will_wake_clone() { - struct NoopWaker; - - impl Wake for NoopWaker { - fn wake(self: Arc) {} - } - - let waker = Waker::from(Arc::new(NoopWaker)); - let clone = waker.clone(); - - assert!(waker.will_wake(&clone)); - assert!(clone.will_wake(&waker)); -} - -#[test] -#[cfg_attr(miri, ignore)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail -fn test_local_waker_will_wake_clone() { - struct NoopWaker; - - impl LocalWake for NoopWaker { - fn wake(self: Rc) {} - } - - let waker = LocalWaker::from(Rc::new(NoopWaker)); - let clone = waker.clone(); - - assert!(waker.will_wake(&clone)); - assert!(clone.will_wake(&waker)); -} diff --git a/library/alloc/tests/testing/crash_test.rs b/library/alloc/tests/testing/crash_test.rs deleted file mode 100644 index 502fe6c10c6..00000000000 --- a/library/alloc/tests/testing/crash_test.rs +++ /dev/null @@ -1,80 +0,0 @@ -use std::cmp::Ordering; -use std::fmt::Debug; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering::SeqCst; - -/// A blueprint for crash test dummy instances that monitor drops. -/// Some instances may be configured to panic at some point. -/// -/// Crash test dummies are identified and ordered by an id, so they can be used -/// as keys in a BTreeMap. -#[derive(Debug)] -pub struct CrashTestDummy { - pub id: usize, - dropped: AtomicUsize, -} - -impl CrashTestDummy { - /// Creates a crash test dummy design. The `id` determines order and equality of instances. - pub fn new(id: usize) -> CrashTestDummy { - CrashTestDummy { id, dropped: AtomicUsize::new(0) } - } - - /// Creates an instance of a crash test dummy that records what events it experiences - /// and optionally panics. - pub fn spawn(&self, panic: Panic) -> Instance<'_> { - Instance { origin: self, panic } - } - - /// Returns how many times instances of the dummy have been dropped. - pub fn dropped(&self) -> usize { - self.dropped.load(SeqCst) - } -} - -#[derive(Debug)] -pub struct Instance<'a> { - origin: &'a CrashTestDummy, - panic: Panic, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Panic { - Never, - InDrop, -} - -impl Instance<'_> { - pub fn id(&self) -> usize { - self.origin.id - } -} - -impl Drop for Instance<'_> { - fn drop(&mut self) { - self.origin.dropped.fetch_add(1, SeqCst); - if self.panic == Panic::InDrop { - panic!("panic in `drop`"); - } - } -} - -impl PartialOrd for Instance<'_> { - fn partial_cmp(&self, other: &Self) -> Option { - self.id().partial_cmp(&other.id()) - } -} - -impl Ord for Instance<'_> { - fn cmp(&self, other: &Self) -> Ordering { - self.id().cmp(&other.id()) - } -} - -impl PartialEq for Instance<'_> { - fn eq(&self, other: &Self) -> bool { - self.id().eq(&other.id()) - } -} - -impl Eq for Instance<'_> {} diff --git a/library/alloc/tests/testing/mod.rs b/library/alloc/tests/testing/mod.rs deleted file mode 100644 index 0a3dd191dc8..00000000000 --- a/library/alloc/tests/testing/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod crash_test; diff --git a/library/alloc/tests/thin_box.rs b/library/alloc/tests/thin_box.rs deleted file mode 100644 index 4c46b614127..00000000000 --- a/library/alloc/tests/thin_box.rs +++ /dev/null @@ -1,261 +0,0 @@ -use core::fmt::Debug; -use std::boxed::ThinBox; - -#[test] -fn want_niche_optimization() { - fn uses_niche() -> bool { - size_of::<*const ()>() == size_of::>>() - } - - trait Tr {} - assert!(uses_niche::()); - assert!(uses_niche::<[i32]>()); - assert!(uses_niche::()); -} - -#[test] -fn want_thin() { - fn is_thin() -> bool { - size_of::<*const ()>() == size_of::>() - } - - trait Tr {} - assert!(is_thin::()); - assert!(is_thin::<[i32]>()); - assert!(is_thin::()); -} - -#[allow(dead_code)] -fn assert_covariance() { - fn thin_box<'new>(b: ThinBox<[&'static str]>) -> ThinBox<[&'new str]> { - b - } -} - -#[track_caller] -fn verify_aligned(ptr: *const T) { - // Use `black_box` to attempt to obscure the fact that we're calling this - // function on pointers that come from box/references, which the compiler - // would otherwise realize is impossible (because it would mean we've - // already executed UB). - // - // That is, we'd *like* it to be possible for the asserts in this function - // to detect brokenness in the ThinBox impl. - // - // It would probably be better if we instead had these as debug_asserts - // inside `ThinBox`, prior to the point where we do the UB. Anyway, in - // practice these checks are mostly just smoke-detectors for an extremely - // broken `ThinBox` impl, since it's an extremely subtle piece of code. - let ptr = core::hint::black_box(ptr); - assert!( - ptr.is_aligned() && !ptr.is_null(), - "misaligned ThinBox data; valid pointers to `{ty}` should be aligned to {align}: {ptr:p}", - ty = core::any::type_name::(), - align = align_of::(), - ); -} - -#[track_caller] -fn check_thin_sized(make: impl FnOnce() -> T) { - let value = make(); - let boxed = ThinBox::new(value.clone()); - let val = &*boxed; - verify_aligned(val as *const T); - assert_eq!(val, &value); -} - -#[track_caller] -fn check_thin_dyn(make: impl FnOnce() -> T) { - let value = make(); - let wanted_debug = format!("{value:?}"); - let boxed: ThinBox = ThinBox::new_unsize(value.clone()); - let val = &*boxed; - // wide reference -> wide pointer -> thin pointer - verify_aligned(val as *const dyn Debug as *const T); - let got_debug = format!("{val:?}"); - assert_eq!(wanted_debug, got_debug); -} - -macro_rules! define_test { - ( - @test_name: $testname:ident; - - $(#[$m:meta])* - struct $Type:ident($inner:ty); - - $($test_stmts:tt)* - ) => { - #[test] - fn $testname() { - use core::sync::atomic::{AtomicIsize, Ordering}; - // Define the type, and implement new/clone/drop in such a way that - // the number of live instances will be counted. - $(#[$m])* - #[derive(Debug, PartialEq)] - struct $Type { - _priv: $inner, - } - - impl Clone for $Type { - fn clone(&self) -> Self { - verify_aligned(self); - Self::new(self._priv.clone()) - } - } - - impl Drop for $Type { - fn drop(&mut self) { - verify_aligned(self); - Self::modify_live(-1); - } - } - - impl $Type { - fn new(i: $inner) -> Self { - Self::modify_live(1); - Self { _priv: i } - } - - fn modify_live(n: isize) -> isize { - static COUNTER: AtomicIsize = AtomicIsize::new(0); - COUNTER.fetch_add(n, Ordering::Relaxed) + n - } - - fn live_objects() -> isize { - Self::modify_live(0) - } - } - // Run the test statements - let _: () = { $($test_stmts)* }; - // Check that we didn't leak anything, or call drop too many times. - assert_eq!( - $Type::live_objects(), 0, - "Wrong number of drops of {}, `initializations - drops` should be 0.", - stringify!($Type), - ); - } - }; -} - -define_test! { - @test_name: align1zst; - struct Align1Zst(()); - - check_thin_sized(|| Align1Zst::new(())); - check_thin_dyn(|| Align1Zst::new(())); -} - -define_test! { - @test_name: align1small; - struct Align1Small(u8); - - check_thin_sized(|| Align1Small::new(50)); - check_thin_dyn(|| Align1Small::new(50)); -} - -define_test! { - @test_name: align1_size_not_pow2; - struct Align64NotPow2Size([u8; 79]); - - check_thin_sized(|| Align64NotPow2Size::new([100; 79])); - check_thin_dyn(|| Align64NotPow2Size::new([100; 79])); -} - -define_test! { - @test_name: align1big; - struct Align1Big([u8; 256]); - - check_thin_sized(|| Align1Big::new([5u8; 256])); - check_thin_dyn(|| Align1Big::new([5u8; 256])); -} - -// Note: `#[repr(align(2))]` is worth testing because -// - can have pointers which are misaligned, unlike align(1) -// - is still expected to have an alignment less than the alignment of a vtable. -define_test! { - @test_name: align2zst; - #[repr(align(2))] - struct Align2Zst(()); - - check_thin_sized(|| Align2Zst::new(())); - check_thin_dyn(|| Align2Zst::new(())); -} - -define_test! { - @test_name: align2small; - #[repr(align(2))] - struct Align2Small(u8); - - check_thin_sized(|| Align2Small::new(60)); - check_thin_dyn(|| Align2Small::new(60)); -} - -define_test! { - @test_name: align2full; - #[repr(align(2))] - struct Align2Full([u8; 2]); - check_thin_sized(|| Align2Full::new([3u8; 2])); - check_thin_dyn(|| Align2Full::new([3u8; 2])); -} - -define_test! { - @test_name: align2_size_not_pow2; - #[repr(align(2))] - struct Align2NotPower2Size([u8; 6]); - - check_thin_sized(|| Align2NotPower2Size::new([3; 6])); - check_thin_dyn(|| Align2NotPower2Size::new([3; 6])); -} - -define_test! { - @test_name: align2big; - #[repr(align(2))] - struct Align2Big([u8; 256]); - - check_thin_sized(|| Align2Big::new([5u8; 256])); - check_thin_dyn(|| Align2Big::new([5u8; 256])); -} - -define_test! { - @test_name: align64zst; - #[repr(align(64))] - struct Align64Zst(()); - - check_thin_sized(|| Align64Zst::new(())); - check_thin_dyn(|| Align64Zst::new(())); -} - -define_test! { - @test_name: align64small; - #[repr(align(64))] - struct Align64Small(u8); - - check_thin_sized(|| Align64Small::new(50)); - check_thin_dyn(|| Align64Small::new(50)); -} - -define_test! { - @test_name: align64med; - #[repr(align(64))] - struct Align64Med([u8; 64]); - check_thin_sized(|| Align64Med::new([10; 64])); - check_thin_dyn(|| Align64Med::new([10; 64])); -} - -define_test! { - @test_name: align64_size_not_pow2; - #[repr(align(64))] - struct Align64NotPow2Size([u8; 192]); - - check_thin_sized(|| Align64NotPow2Size::new([10; 192])); - check_thin_dyn(|| Align64NotPow2Size::new([10; 192])); -} - -define_test! { - @test_name: align64big; - #[repr(align(64))] - struct Align64Big([u8; 256]); - - check_thin_sized(|| Align64Big::new([10; 256])); - check_thin_dyn(|| Align64Big::new([10; 256])); -} diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs deleted file mode 100644 index f430d979fa8..00000000000 --- a/library/alloc/tests/vec.rs +++ /dev/null @@ -1,2750 +0,0 @@ -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#![allow(static_mut_refs)] - -use core::alloc::{Allocator, Layout}; -use core::num::NonZero; -use core::ptr::NonNull; -use core::{assert_eq, assert_ne}; -use std::alloc::System; -use std::assert_matches::assert_matches; -use std::borrow::Cow; -use std::cell::Cell; -use std::collections::TryReserveErrorKind::*; -use std::fmt::Debug; -use std::hint; -use std::iter::InPlaceIterable; -use std::mem::swap; -use std::ops::Bound::*; -use std::panic::{AssertUnwindSafe, catch_unwind}; -use std::rc::Rc; -use std::sync::atomic::{AtomicU32, Ordering}; -use std::vec::{Drain, IntoIter}; - -struct DropCounter<'a> { - count: &'a mut u32, -} - -impl Drop for DropCounter<'_> { - fn drop(&mut self) { - *self.count += 1; - } -} - -#[test] -fn test_small_vec_struct() { - assert_eq!(size_of::>(), size_of::() * 3); -} - -#[test] -fn test_double_drop() { - struct TwoVec { - x: Vec, - y: Vec, - } - - let (mut count_x, mut count_y) = (0, 0); - { - let mut tv = TwoVec { x: Vec::new(), y: Vec::new() }; - tv.x.push(DropCounter { count: &mut count_x }); - tv.y.push(DropCounter { count: &mut count_y }); - - // If Vec had a drop flag, here is where it would be zeroed. - // Instead, it should rely on its internal state to prevent - // doing anything significant when dropped multiple times. - drop(tv.x); - - // Here tv goes out of scope, tv.y should be dropped, but not tv.x. - } - - assert_eq!(count_x, 1); - assert_eq!(count_y, 1); -} - -#[test] -fn test_reserve() { - let mut v = Vec::new(); - assert_eq!(v.capacity(), 0); - - v.reserve(2); - assert!(v.capacity() >= 2); - - for i in 0..16 { - v.push(i); - } - - assert!(v.capacity() >= 16); - v.reserve(16); - assert!(v.capacity() >= 32); - - v.push(16); - - v.reserve(16); - assert!(v.capacity() >= 33) -} - -#[test] -fn test_zst_capacity() { - assert_eq!(Vec::<()>::new().capacity(), usize::MAX); -} - -#[test] -fn test_indexing() { - let v: Vec = vec![10, 20]; - assert_eq!(v[0], 10); - assert_eq!(v[1], 20); - let mut x: usize = 0; - assert_eq!(v[x], 10); - assert_eq!(v[x + 1], 20); - x = x + 1; - assert_eq!(v[x], 20); - assert_eq!(v[x - 1], 10); -} - -#[test] -fn test_debug_fmt() { - let vec1: Vec = vec![]; - assert_eq!("[]", format!("{:?}", vec1)); - - let vec2 = vec![0, 1]; - assert_eq!("[0, 1]", format!("{:?}", vec2)); - - let slice: &[isize] = &[4, 5]; - assert_eq!("[4, 5]", format!("{slice:?}")); -} - -#[test] -fn test_push() { - let mut v = vec![]; - v.push(1); - assert_eq!(v, [1]); - v.push(2); - assert_eq!(v, [1, 2]); - v.push(3); - assert_eq!(v, [1, 2, 3]); -} - -#[test] -fn test_extend() { - let mut v = Vec::new(); - let mut w = Vec::new(); - - v.extend(w.clone()); - assert_eq!(v, &[]); - - v.extend(0..3); - for i in 0..3 { - w.push(i) - } - - assert_eq!(v, w); - - v.extend(3..10); - for i in 3..10 { - w.push(i) - } - - assert_eq!(v, w); - - v.extend(w.clone()); // specializes to `append` - assert!(v.iter().eq(w.iter().chain(w.iter()))); - - // Zero sized types - #[derive(PartialEq, Debug)] - struct Foo; - - let mut a = Vec::new(); - let b = vec![Foo, Foo]; - - a.extend(b); - assert_eq!(a, &[Foo, Foo]); - - // Double drop - let mut count_x = 0; - { - let mut x = Vec::new(); - let y = vec![DropCounter { count: &mut count_x }]; - x.extend(y); - } - assert_eq!(count_x, 1); -} - -#[test] -fn test_extend_from_slice() { - let a: Vec = vec![1, 2, 3, 4, 5]; - let b: Vec = vec![6, 7, 8, 9, 0]; - - let mut v: Vec = a; - - v.extend_from_slice(&b); - - assert_eq!(v, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); -} - -#[test] -fn test_extend_ref() { - let mut v = vec![1, 2]; - v.extend(&[3, 4, 5]); - - assert_eq!(v.len(), 5); - assert_eq!(v, [1, 2, 3, 4, 5]); - - let w = vec![6, 7]; - v.extend(&w); - - assert_eq!(v.len(), 7); - assert_eq!(v, [1, 2, 3, 4, 5, 6, 7]); -} - -#[test] -fn test_slice_from_ref() { - let values = vec![1, 2, 3, 4, 5]; - let slice = &values[1..3]; - - assert_eq!(slice, [2, 3]); -} - -#[test] -fn test_slice_from_mut() { - let mut values = vec![1, 2, 3, 4, 5]; - { - let slice = &mut values[2..]; - assert!(slice == [3, 4, 5]); - for p in slice { - *p += 2; - } - } - - assert!(values == [1, 2, 5, 6, 7]); -} - -#[test] -fn test_slice_to_mut() { - let mut values = vec![1, 2, 3, 4, 5]; - { - let slice = &mut values[..2]; - assert!(slice == [1, 2]); - for p in slice { - *p += 1; - } - } - - assert!(values == [2, 3, 3, 4, 5]); -} - -#[test] -fn test_split_at_mut() { - let mut values = vec![1, 2, 3, 4, 5]; - { - let (left, right) = values.split_at_mut(2); - { - let left: &[_] = left; - assert!(&left[..left.len()] == &[1, 2]); - } - for p in left { - *p += 1; - } - - { - let right: &[_] = right; - assert!(&right[..right.len()] == &[3, 4, 5]); - } - for p in right { - *p += 2; - } - } - - assert_eq!(values, [2, 3, 5, 6, 7]); -} - -#[test] -fn test_clone() { - let v: Vec = vec![]; - let w = vec![1, 2, 3]; - - assert_eq!(v, v.clone()); - - let z = w.clone(); - assert_eq!(w, z); - // they should be disjoint in memory. - assert!(w.as_ptr() != z.as_ptr()) -} - -#[test] -fn test_clone_from() { - let mut v = vec![]; - let three: Vec> = vec![Box::new(1), Box::new(2), Box::new(3)]; - let two: Vec> = vec![Box::new(4), Box::new(5)]; - // zero, long - v.clone_from(&three); - assert_eq!(v, three); - - // equal - v.clone_from(&three); - assert_eq!(v, three); - - // long, short - v.clone_from(&two); - assert_eq!(v, two); - - // short, long - v.clone_from(&three); - assert_eq!(v, three) -} - -#[test] -fn test_retain() { - let mut vec = vec![1, 2, 3, 4]; - vec.retain(|&x| x % 2 == 0); - assert_eq!(vec, [2, 4]); -} - -#[test] -fn test_retain_predicate_order() { - for to_keep in [true, false] { - let mut number_of_executions = 0; - let mut vec = vec![1, 2, 3, 4]; - let mut next_expected = 1; - vec.retain(|&x| { - assert_eq!(next_expected, x); - next_expected += 1; - number_of_executions += 1; - to_keep - }); - assert_eq!(number_of_executions, 4); - } -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_retain_pred_panic_with_hole() { - let v = (0..5).map(Rc::new).collect::>(); - catch_unwind(AssertUnwindSafe(|| { - let mut v = v.clone(); - v.retain(|r| match **r { - 0 => true, - 1 => false, - 2 => true, - _ => panic!(), - }); - })) - .unwrap_err(); - // Everything is dropped when predicate panicked. - assert!(v.iter().all(|r| Rc::strong_count(r) == 1)); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_retain_pred_panic_no_hole() { - let v = (0..5).map(Rc::new).collect::>(); - catch_unwind(AssertUnwindSafe(|| { - let mut v = v.clone(); - v.retain(|r| match **r { - 0 | 1 | 2 => true, - _ => panic!(), - }); - })) - .unwrap_err(); - // Everything is dropped when predicate panicked. - assert!(v.iter().all(|r| Rc::strong_count(r) == 1)); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_retain_drop_panic() { - struct Wrap(Rc); - - impl Drop for Wrap { - fn drop(&mut self) { - if *self.0 == 3 { - panic!(); - } - } - } - - let v = (0..5).map(|x| Rc::new(x)).collect::>(); - catch_unwind(AssertUnwindSafe(|| { - let mut v = v.iter().map(|r| Wrap(r.clone())).collect::>(); - v.retain(|w| match *w.0 { - 0 => true, - 1 => false, - 2 => true, - 3 => false, // Drop panic. - _ => true, - }); - })) - .unwrap_err(); - // Other elements are dropped when `drop` of one element panicked. - // The panicked wrapper also has its Rc dropped. - assert!(v.iter().all(|r| Rc::strong_count(r) == 1)); -} - -#[test] -fn test_retain_maybeuninits() { - // This test aimed to be run under miri. - use core::mem::MaybeUninit; - let mut vec: Vec<_> = [1i32, 2, 3, 4].map(|v| MaybeUninit::new(vec![v])).into(); - vec.retain(|x| { - // SAFETY: Retain must visit every element of Vec in original order and exactly once. - // Our values is initialized at creation of Vec. - let v = unsafe { x.assume_init_ref()[0] }; - if v & 1 == 0 { - return true; - } - // SAFETY: Value is initialized. - // Value wouldn't be dropped by `Vec::retain` - // because `MaybeUninit` doesn't drop content. - drop(unsafe { x.assume_init_read() }); - false - }); - let vec: Vec = vec - .into_iter() - .map(|x| unsafe { - // SAFETY: All values dropped in retain predicate must be removed by `Vec::retain`. - // Remaining values are initialized. - x.assume_init()[0] - }) - .collect(); - assert_eq!(vec, [2, 4]); -} - -#[test] -fn test_dedup() { - fn case(a: Vec, b: Vec) { - let mut v = a; - v.dedup(); - assert_eq!(v, b); - } - case(vec![], vec![]); - case(vec![1], vec![1]); - case(vec![1, 1], vec![1]); - case(vec![1, 2, 3], vec![1, 2, 3]); - case(vec![1, 1, 2, 3], vec![1, 2, 3]); - case(vec![1, 2, 2, 3], vec![1, 2, 3]); - case(vec![1, 2, 3, 3], vec![1, 2, 3]); - case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]); -} - -#[test] -fn test_dedup_by_key() { - fn case(a: Vec, b: Vec) { - let mut v = a; - v.dedup_by_key(|i| *i / 10); - assert_eq!(v, b); - } - case(vec![], vec![]); - case(vec![10], vec![10]); - case(vec![10, 11], vec![10]); - case(vec![10, 20, 30], vec![10, 20, 30]); - case(vec![10, 11, 20, 30], vec![10, 20, 30]); - case(vec![10, 20, 21, 30], vec![10, 20, 30]); - case(vec![10, 20, 30, 31], vec![10, 20, 30]); - case(vec![10, 11, 20, 21, 22, 30, 31], vec![10, 20, 30]); -} - -#[test] -fn test_dedup_by() { - let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"]; - vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); - - assert_eq!(vec, ["foo", "bar", "baz", "bar"]); - - let mut vec = vec![("foo", 1), ("foo", 2), ("bar", 3), ("bar", 4), ("bar", 5)]; - vec.dedup_by(|a, b| { - a.0 == b.0 && { - b.1 += a.1; - true - } - }); - - assert_eq!(vec, [("foo", 3), ("bar", 12)]); -} - -#[test] -fn test_dedup_unique() { - let mut v0: Vec> = vec![Box::new(1), Box::new(1), Box::new(2), Box::new(3)]; - v0.dedup(); - let mut v1: Vec> = vec![Box::new(1), Box::new(2), Box::new(2), Box::new(3)]; - v1.dedup(); - let mut v2: Vec> = vec![Box::new(1), Box::new(2), Box::new(3), Box::new(3)]; - v2.dedup(); - // If the boxed pointers were leaked or otherwise misused, valgrind - // and/or rt should raise errors. -} - -#[test] -fn zero_sized_values() { - let mut v = Vec::new(); - assert_eq!(v.len(), 0); - v.push(()); - assert_eq!(v.len(), 1); - v.push(()); - assert_eq!(v.len(), 2); - assert_eq!(v.pop(), Some(())); - assert_eq!(v.pop(), Some(())); - assert_eq!(v.pop(), None); - - assert_eq!(v.iter().count(), 0); - v.push(()); - assert_eq!(v.iter().count(), 1); - v.push(()); - assert_eq!(v.iter().count(), 2); - - for &() in &v {} - - assert_eq!(v.iter_mut().count(), 2); - v.push(()); - assert_eq!(v.iter_mut().count(), 3); - v.push(()); - assert_eq!(v.iter_mut().count(), 4); - - for &mut () in &mut v {} - unsafe { - v.set_len(0); - } - assert_eq!(v.iter_mut().count(), 0); -} - -#[test] -fn test_partition() { - assert_eq!([].into_iter().partition(|x: &i32| *x < 3), (vec![], vec![])); - assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 4), (vec![1, 2, 3], vec![])); - assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 2), (vec![1], vec![2, 3])); - assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 0), (vec![], vec![1, 2, 3])); -} - -#[test] -fn test_zip_unzip() { - let z1 = vec![(1, 4), (2, 5), (3, 6)]; - - let (left, right): (Vec<_>, Vec<_>) = z1.iter().cloned().unzip(); - - assert_eq!((1, 4), (left[0], right[0])); - assert_eq!((2, 5), (left[1], right[1])); - assert_eq!((3, 6), (left[2], right[2])); -} - -#[test] -fn test_cmp() { - let x: &[isize] = &[1, 2, 3, 4, 5]; - let cmp: &[isize] = &[1, 2, 3, 4, 5]; - assert_eq!(&x[..], cmp); - let cmp: &[isize] = &[3, 4, 5]; - assert_eq!(&x[2..], cmp); - let cmp: &[isize] = &[1, 2, 3]; - assert_eq!(&x[..3], cmp); - let cmp: &[isize] = &[2, 3, 4]; - assert_eq!(&x[1..4], cmp); - - let x: Vec = vec![1, 2, 3, 4, 5]; - let cmp: &[isize] = &[1, 2, 3, 4, 5]; - assert_eq!(&x[..], cmp); - let cmp: &[isize] = &[3, 4, 5]; - assert_eq!(&x[2..], cmp); - let cmp: &[isize] = &[1, 2, 3]; - assert_eq!(&x[..3], cmp); - let cmp: &[isize] = &[2, 3, 4]; - assert_eq!(&x[1..4], cmp); -} - -#[test] -fn test_vec_truncate_drop() { - static mut DROPS: u32 = 0; - struct Elem(#[allow(dead_code)] i32); - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } - - let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)]; - assert_eq!(unsafe { DROPS }, 0); - v.truncate(3); - assert_eq!(unsafe { DROPS }, 2); - v.truncate(0); - assert_eq!(unsafe { DROPS }, 5); -} - -#[test] -#[should_panic] -fn test_vec_truncate_fail() { - struct BadElem(i32); - impl Drop for BadElem { - fn drop(&mut self) { - let BadElem(ref mut x) = *self; - if *x == 0xbadbeef { - panic!("BadElem panic: 0xbadbeef") - } - } - } - - let mut v = vec![BadElem(1), BadElem(2), BadElem(0xbadbeef), BadElem(4)]; - v.truncate(0); -} - -#[test] -fn test_index() { - let vec = vec![1, 2, 3]; - assert!(vec[1] == 2); -} - -#[test] -#[should_panic] -fn test_index_out_of_bounds() { - let vec = vec![1, 2, 3]; - let _ = vec[3]; -} - -#[test] -#[should_panic] -fn test_slice_out_of_bounds_1() { - let x = vec![1, 2, 3, 4, 5]; - let _ = &x[!0..]; -} - -#[test] -#[should_panic] -fn test_slice_out_of_bounds_2() { - let x = vec![1, 2, 3, 4, 5]; - let _ = &x[..6]; -} - -#[test] -#[should_panic] -fn test_slice_out_of_bounds_3() { - let x = vec![1, 2, 3, 4, 5]; - let _ = &x[!0..4]; -} - -#[test] -#[should_panic] -fn test_slice_out_of_bounds_4() { - let x = vec![1, 2, 3, 4, 5]; - let _ = &x[1..6]; -} - -#[test] -#[should_panic] -fn test_slice_out_of_bounds_5() { - let x = vec![1, 2, 3, 4, 5]; - let _ = &x[3..2]; -} - -#[test] -#[should_panic] -fn test_swap_remove_empty() { - let mut vec = Vec::::new(); - vec.swap_remove(0); -} - -#[test] -fn test_move_items() { - let vec = vec![1, 2, 3]; - let mut vec2 = vec![]; - for i in vec { - vec2.push(i); - } - assert_eq!(vec2, [1, 2, 3]); -} - -#[test] -fn test_move_items_reverse() { - let vec = vec![1, 2, 3]; - let mut vec2 = vec![]; - for i in vec.into_iter().rev() { - vec2.push(i); - } - assert_eq!(vec2, [3, 2, 1]); -} - -#[test] -fn test_move_items_zero_sized() { - let vec = vec![(), (), ()]; - let mut vec2 = vec![]; - for i in vec { - vec2.push(i); - } - assert_eq!(vec2, [(), (), ()]); -} - -#[test] -fn test_drain_empty_vec() { - let mut vec: Vec = vec![]; - let mut vec2: Vec = vec![]; - for i in vec.drain(..) { - vec2.push(i); - } - assert!(vec.is_empty()); - assert!(vec2.is_empty()); -} - -#[test] -fn test_drain_items() { - let mut vec = vec![1, 2, 3]; - let mut vec2 = vec![]; - for i in vec.drain(..) { - vec2.push(i); - } - assert_eq!(vec, []); - assert_eq!(vec2, [1, 2, 3]); -} - -#[test] -fn test_drain_items_reverse() { - let mut vec = vec![1, 2, 3]; - let mut vec2 = vec![]; - for i in vec.drain(..).rev() { - vec2.push(i); - } - assert_eq!(vec, []); - assert_eq!(vec2, [3, 2, 1]); -} - -#[test] -fn test_drain_items_zero_sized() { - let mut vec = vec![(), (), ()]; - let mut vec2 = vec![]; - for i in vec.drain(..) { - vec2.push(i); - } - assert_eq!(vec, []); - assert_eq!(vec2, [(), (), ()]); -} - -#[test] -#[should_panic] -fn test_drain_out_of_bounds() { - let mut v = vec![1, 2, 3, 4, 5]; - v.drain(5..6); -} - -#[test] -fn test_drain_range() { - let mut v = vec![1, 2, 3, 4, 5]; - for _ in v.drain(4..) {} - assert_eq!(v, &[1, 2, 3, 4]); - - let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect(); - for _ in v.drain(1..4) {} - assert_eq!(v, &[1.to_string(), 5.to_string()]); - - let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect(); - for _ in v.drain(1..4).rev() {} - assert_eq!(v, &[1.to_string(), 5.to_string()]); - - let mut v: Vec<_> = vec![(); 5]; - for _ in v.drain(1..4).rev() {} - assert_eq!(v, &[(), ()]); -} - -#[test] -fn test_drain_inclusive_range() { - let mut v = vec!['a', 'b', 'c', 'd', 'e']; - for _ in v.drain(1..=3) {} - assert_eq!(v, &['a', 'e']); - - let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect(); - for _ in v.drain(1..=5) {} - assert_eq!(v, &["0".to_string()]); - - let mut v: Vec = (0..=5).map(|x| x.to_string()).collect(); - for _ in v.drain(0..=5) {} - assert_eq!(v, Vec::::new()); - - let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect(); - for _ in v.drain(0..=3) {} - assert_eq!(v, &["4".to_string(), "5".to_string()]); - - let mut v: Vec<_> = (0..=1).map(|x| x.to_string()).collect(); - for _ in v.drain(..=0) {} - assert_eq!(v, &["1".to_string()]); -} - -#[test] -fn test_drain_max_vec_size() { - let mut v = Vec::<()>::with_capacity(usize::MAX); - unsafe { - v.set_len(usize::MAX); - } - for _ in v.drain(usize::MAX - 1..) {} - assert_eq!(v.len(), usize::MAX - 1); - - let mut v = Vec::<()>::with_capacity(usize::MAX); - unsafe { - v.set_len(usize::MAX); - } - for _ in v.drain(usize::MAX - 1..=usize::MAX - 1) {} - assert_eq!(v.len(), usize::MAX - 1); -} - -#[test] -#[should_panic] -fn test_drain_index_overflow() { - let mut v = Vec::<()>::with_capacity(usize::MAX); - unsafe { - v.set_len(usize::MAX); - } - v.drain(0..=usize::MAX); -} - -#[test] -#[should_panic] -fn test_drain_inclusive_out_of_bounds() { - let mut v = vec![1, 2, 3, 4, 5]; - v.drain(5..=5); -} - -#[test] -#[should_panic] -fn test_drain_start_overflow() { - let mut v = vec![1, 2, 3]; - v.drain((Excluded(usize::MAX), Included(0))); -} - -#[test] -#[should_panic] -fn test_drain_end_overflow() { - let mut v = vec![1, 2, 3]; - v.drain((Included(0), Included(usize::MAX))); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_drain_leak() { - static mut DROPS: i32 = 0; - - #[derive(Debug, PartialEq)] - struct D(u32, bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.1 { - panic!("panic in `drop`"); - } - } - } - - let mut v = vec![ - D(0, false), - D(1, false), - D(2, false), - D(3, false), - D(4, true), - D(5, false), - D(6, false), - ]; - - catch_unwind(AssertUnwindSafe(|| { - v.drain(2..=5); - })) - .ok(); - - assert_eq!(unsafe { DROPS }, 4); - assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]); -} - -#[test] -fn test_drain_keep_rest() { - let mut v = vec![0, 1, 2, 3, 4, 5, 6]; - let mut drain = v.drain(1..6); - assert_eq!(drain.next(), Some(1)); - assert_eq!(drain.next_back(), Some(5)); - assert_eq!(drain.next(), Some(2)); - - drain.keep_rest(); - assert_eq!(v, &[0, 3, 4, 6]); -} - -#[test] -fn test_drain_keep_rest_all() { - let mut v = vec![0, 1, 2, 3, 4, 5, 6]; - v.drain(1..6).keep_rest(); - assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]); -} - -#[test] -fn test_drain_keep_rest_none() { - let mut v = vec![0, 1, 2, 3, 4, 5, 6]; - let mut drain = v.drain(1..6); - - drain.by_ref().for_each(drop); - - drain.keep_rest(); - assert_eq!(v, &[0, 6]); -} - -#[test] -fn test_splice() { - let mut v = vec![1, 2, 3, 4, 5]; - let a = [10, 11, 12]; - v.splice(2..4, a); - assert_eq!(v, &[1, 2, 10, 11, 12, 5]); - v.splice(1..3, Some(20)); - assert_eq!(v, &[1, 20, 11, 12, 5]); -} - -#[test] -fn test_splice_inclusive_range() { - let mut v = vec![1, 2, 3, 4, 5]; - let a = [10, 11, 12]; - let t1: Vec<_> = v.splice(2..=3, a).collect(); - assert_eq!(v, &[1, 2, 10, 11, 12, 5]); - assert_eq!(t1, &[3, 4]); - let t2: Vec<_> = v.splice(1..=2, Some(20)).collect(); - assert_eq!(v, &[1, 20, 11, 12, 5]); - assert_eq!(t2, &[2, 10]); -} - -#[test] -#[should_panic] -fn test_splice_out_of_bounds() { - let mut v = vec![1, 2, 3, 4, 5]; - let a = [10, 11, 12]; - v.splice(5..6, a); -} - -#[test] -#[should_panic] -fn test_splice_inclusive_out_of_bounds() { - let mut v = vec![1, 2, 3, 4, 5]; - let a = [10, 11, 12]; - v.splice(5..=5, a); -} - -#[test] -fn test_splice_items_zero_sized() { - let mut vec = vec![(), (), ()]; - let vec2 = vec![]; - let t: Vec<_> = vec.splice(1..2, vec2.iter().cloned()).collect(); - assert_eq!(vec, &[(), ()]); - assert_eq!(t, &[()]); -} - -#[test] -fn test_splice_unbounded() { - let mut vec = vec![1, 2, 3, 4, 5]; - let t: Vec<_> = vec.splice(.., None).collect(); - assert_eq!(vec, &[]); - assert_eq!(t, &[1, 2, 3, 4, 5]); -} - -#[test] -fn test_splice_forget() { - let mut v = vec![1, 2, 3, 4, 5]; - let a = [10, 11, 12]; - std::mem::forget(v.splice(2..4, a)); - assert_eq!(v, &[1, 2]); -} - -#[test] -fn test_into_boxed_slice() { - let xs = vec![1, 2, 3]; - let ys = xs.into_boxed_slice(); - assert_eq!(&*ys, [1, 2, 3]); -} - -#[test] -fn test_append() { - let mut vec = vec![1, 2, 3]; - let mut vec2 = vec![4, 5, 6]; - vec.append(&mut vec2); - assert_eq!(vec, [1, 2, 3, 4, 5, 6]); - assert_eq!(vec2, []); -} - -#[test] -fn test_split_off() { - let mut vec = vec![1, 2, 3, 4, 5, 6]; - let orig_ptr = vec.as_ptr(); - let orig_capacity = vec.capacity(); - - let split_off = vec.split_off(4); - assert_eq!(vec, [1, 2, 3, 4]); - assert_eq!(split_off, [5, 6]); - assert_eq!(vec.capacity(), orig_capacity); - assert_eq!(vec.as_ptr(), orig_ptr); -} - -#[test] -fn test_split_off_take_all() { - // Allocate enough capacity that we can tell whether the split-off vector's - // capacity is based on its size, or (incorrectly) on the original capacity. - let mut vec = Vec::with_capacity(1000); - vec.extend([1, 2, 3, 4, 5, 6]); - let orig_ptr = vec.as_ptr(); - let orig_capacity = vec.capacity(); - - let split_off = vec.split_off(0); - assert_eq!(vec, []); - assert_eq!(split_off, [1, 2, 3, 4, 5, 6]); - assert_eq!(vec.capacity(), orig_capacity); - assert_eq!(vec.as_ptr(), orig_ptr); - - // The split-off vector should be newly-allocated, and should not have - // stolen the original vector's allocation. - assert!(split_off.capacity() < orig_capacity); - assert_ne!(split_off.as_ptr(), orig_ptr); -} - -#[test] -fn test_into_iter_as_slice() { - let vec = vec!['a', 'b', 'c']; - let mut into_iter = vec.into_iter(); - assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); - let _ = into_iter.next().unwrap(); - assert_eq!(into_iter.as_slice(), &['b', 'c']); - let _ = into_iter.next().unwrap(); - let _ = into_iter.next().unwrap(); - assert_eq!(into_iter.as_slice(), &[]); -} - -#[test] -fn test_into_iter_as_mut_slice() { - let vec = vec!['a', 'b', 'c']; - let mut into_iter = vec.into_iter(); - assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); - into_iter.as_mut_slice()[0] = 'x'; - into_iter.as_mut_slice()[1] = 'y'; - assert_eq!(into_iter.next().unwrap(), 'x'); - assert_eq!(into_iter.as_slice(), &['y', 'c']); -} - -#[test] -fn test_into_iter_debug() { - let vec = vec!['a', 'b', 'c']; - let into_iter = vec.into_iter(); - let debug = format!("{into_iter:?}"); - assert_eq!(debug, "IntoIter(['a', 'b', 'c'])"); -} - -#[test] -fn test_into_iter_count() { - assert_eq!([1, 2, 3].into_iter().count(), 3); -} - -#[test] -fn test_into_iter_next_chunk() { - let mut iter = b"lorem".to_vec().into_iter(); - - assert_eq!(iter.next_chunk().unwrap(), [b'l', b'o']); // N is inferred as 2 - assert_eq!(iter.next_chunk().unwrap(), [b'r', b'e', b'm']); // N is inferred as 3 - assert_eq!(iter.next_chunk::<4>().unwrap_err().as_slice(), &[]); // N is explicitly 4 -} - -#[test] -fn test_into_iter_clone() { - fn iter_equal>(it: I, slice: &[i32]) { - let v: Vec = it.collect(); - assert_eq!(&v[..], slice); - } - let mut it = [1, 2, 3].into_iter(); - iter_equal(it.clone(), &[1, 2, 3]); - assert_eq!(it.next(), Some(1)); - let mut it = it.rev(); - iter_equal(it.clone(), &[3, 2]); - assert_eq!(it.next(), Some(3)); - iter_equal(it.clone(), &[2]); - assert_eq!(it.next(), Some(2)); - iter_equal(it.clone(), &[]); - assert_eq!(it.next(), None); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_into_iter_leak() { - static mut DROPS: i32 = 0; - - struct D(bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.0 { - panic!("panic in `drop`"); - } - } - } - - let v = vec![D(false), D(true), D(false)]; - - catch_unwind(move || drop(v.into_iter())).ok(); - - assert_eq!(unsafe { DROPS }, 3); -} - -#[test] -fn test_into_iter_advance_by() { - let mut i = vec![1, 2, 3, 4, 5].into_iter(); - assert_eq!(i.advance_by(0), Ok(())); - assert_eq!(i.advance_back_by(0), Ok(())); - assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]); - - assert_eq!(i.advance_by(1), Ok(())); - assert_eq!(i.advance_back_by(1), Ok(())); - assert_eq!(i.as_slice(), [2, 3, 4]); - - assert_eq!(i.advance_back_by(usize::MAX), Err(NonZero::new(usize::MAX - 3).unwrap())); - - assert_eq!(i.advance_by(usize::MAX), Err(NonZero::new(usize::MAX).unwrap())); - - assert_eq!(i.advance_by(0), Ok(())); - assert_eq!(i.advance_back_by(0), Ok(())); - - assert_eq!(i.len(), 0); -} - -#[test] -fn test_into_iter_drop_allocator() { - struct ReferenceCountedAllocator<'a>(#[allow(dead_code)] DropCounter<'a>); - - unsafe impl Allocator for ReferenceCountedAllocator<'_> { - fn allocate(&self, layout: Layout) -> Result, core::alloc::AllocError> { - System.allocate(layout) - } - - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - // Safety: Invariants passed to caller. - unsafe { System.deallocate(ptr, layout) } - } - } - - let mut drop_count = 0; - - let allocator = ReferenceCountedAllocator(DropCounter { count: &mut drop_count }); - let _ = Vec::::new_in(allocator); - assert_eq!(drop_count, 1); - - let allocator = ReferenceCountedAllocator(DropCounter { count: &mut drop_count }); - let _ = Vec::::new_in(allocator).into_iter(); - assert_eq!(drop_count, 2); -} - -#[test] -fn test_into_iter_zst() { - #[derive(Debug, Clone)] - struct AlignedZstWithDrop([u64; 0]); - impl Drop for AlignedZstWithDrop { - fn drop(&mut self) { - let addr = self as *mut _ as usize; - assert!(hint::black_box(addr) % align_of::() == 0); - } - } - - const C: AlignedZstWithDrop = AlignedZstWithDrop([0u64; 0]); - - for _ in vec![C].into_iter() {} - for _ in vec![C; 5].into_iter().rev() {} - - let mut it = vec![C, C].into_iter(); - assert_eq!(it.advance_by(1), Ok(())); - drop(it); - - let mut it = vec![C, C].into_iter(); - it.next_chunk::<1>().unwrap(); - drop(it); - - let mut it = vec![C, C].into_iter(); - it.next_chunk::<4>().unwrap_err(); - drop(it); -} - -#[test] -fn test_from_iter_specialization() { - let src: Vec = vec![0usize; 1]; - let srcptr = src.as_ptr(); - let sink = src.into_iter().collect::>(); - let sinkptr = sink.as_ptr(); - assert_eq!(srcptr, sinkptr); -} - -#[test] -fn test_from_iter_partially_drained_in_place_specialization() { - let src: Vec = vec![0usize; 10]; - let srcptr = src.as_ptr(); - let mut iter = src.into_iter(); - iter.next(); - iter.next(); - let sink = iter.collect::>(); - let sinkptr = sink.as_ptr(); - assert_eq!(srcptr, sinkptr); -} - -#[test] -fn test_from_iter_specialization_with_iterator_adapters() { - fn assert_in_place_trait(_: &T) {} - let owned: Vec = vec![0usize; 256]; - let refd: Vec<&usize> = owned.iter().collect(); - let src: Vec<&&usize> = refd.iter().collect(); - let srcptr = src.as_ptr(); - let iter = src - .into_iter() - .copied() - .cloned() - .enumerate() - .map(|i| i.0 + i.1) - .zip(std::iter::repeat(1usize)) - .map(|(a, b)| a + b) - .map_while(Option::Some) - .skip(1) - .map(|e| if e != usize::MAX { Ok(NonZero::new(e)) } else { Err(()) }); - assert_in_place_trait(&iter); - let sink = iter.collect::, _>>().unwrap(); - let sinkptr = sink.as_ptr(); - assert_eq!(srcptr as *const usize, sinkptr as *const usize); -} - -#[test] -fn test_in_place_specialization_step_up_down() { - fn assert_in_place_trait(_: &T) {} - - let src = vec![0u8; 1024]; - let srcptr = src.as_ptr(); - let src_bytes = src.capacity(); - let iter = src.into_iter().array_chunks::<4>(); - assert_in_place_trait(&iter); - let sink = iter.collect::>(); - let sinkptr = sink.as_ptr(); - assert_eq!(srcptr.addr(), sinkptr.addr()); - assert_eq!(src_bytes, sink.capacity() * 4); - - let mut src: Vec = Vec::with_capacity(17); - let src_bytes = src.capacity(); - src.resize(8, 0u8); - let sink: Vec<[u8; 4]> = src.into_iter().array_chunks::<4>().collect(); - let sink_bytes = sink.capacity() * 4; - assert_ne!(src_bytes, sink_bytes); - assert_eq!(sink.len(), 2); - - let mut src: Vec<[u8; 3]> = Vec::with_capacity(17); - src.resize(8, [0; 3]); - let iter = src.into_iter().map(|[a, b, _]| [a, b]); - assert_in_place_trait(&iter); - let sink: Vec<[u8; 2]> = iter.collect(); - assert_eq!(sink.len(), 8); - assert!(sink.capacity() <= 25); -} - -#[test] -fn test_from_iter_specialization_head_tail_drop() { - let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect(); - let src: Vec<_> = drop_count.iter().cloned().collect(); - let srcptr = src.as_ptr(); - let iter = src.into_iter(); - let sink: Vec<_> = iter.skip(1).take(1).collect(); - let sinkptr = sink.as_ptr(); - assert_eq!(srcptr, sinkptr, "specialization was applied"); - assert_eq!(Rc::strong_count(&drop_count[0]), 1, "front was dropped"); - assert_eq!(Rc::strong_count(&drop_count[1]), 2, "one element was collected"); - assert_eq!(Rc::strong_count(&drop_count[2]), 1, "tail was dropped"); - assert_eq!(sink.len(), 1); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_from_iter_specialization_panic_during_iteration_drops() { - let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect(); - let src: Vec<_> = drop_count.iter().cloned().collect(); - let iter = src.into_iter(); - - let _ = std::panic::catch_unwind(AssertUnwindSafe(|| { - let _ = iter - .enumerate() - .filter_map(|(i, e)| { - if i == 1 { - std::panic!("aborting iteration"); - } - Some(e) - }) - .collect::>(); - })); - - assert!( - drop_count.iter().map(Rc::strong_count).all(|count| count == 1), - "all items were dropped once" - ); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#[allow(static_mut_refs)] -fn test_from_iter_specialization_panic_during_drop_doesnt_leak() { - static mut DROP_COUNTER_OLD: [usize; 5] = [0; 5]; - static mut DROP_COUNTER_NEW: [usize; 2] = [0; 2]; - - #[derive(Debug)] - struct Old(usize); - - impl Drop for Old { - fn drop(&mut self) { - unsafe { - DROP_COUNTER_OLD[self.0] += 1; - } - - if self.0 == 3 { - panic!(); - } - - println!("Dropped Old: {}", self.0); - } - } - - #[derive(Debug)] - struct New(usize); - - impl Drop for New { - fn drop(&mut self) { - unsafe { - DROP_COUNTER_NEW[self.0] += 1; - } - - println!("Dropped New: {}", self.0); - } - } - - let _ = std::panic::catch_unwind(AssertUnwindSafe(|| { - let v = vec![Old(0), Old(1), Old(2), Old(3), Old(4)]; - let _ = v.into_iter().map(|x| New(x.0)).take(2).collect::>(); - })); - - assert_eq!(unsafe { DROP_COUNTER_OLD[0] }, 1); - assert_eq!(unsafe { DROP_COUNTER_OLD[1] }, 1); - assert_eq!(unsafe { DROP_COUNTER_OLD[2] }, 1); - assert_eq!(unsafe { DROP_COUNTER_OLD[3] }, 1); - assert_eq!(unsafe { DROP_COUNTER_OLD[4] }, 1); - - assert_eq!(unsafe { DROP_COUNTER_NEW[0] }, 1); - assert_eq!(unsafe { DROP_COUNTER_NEW[1] }, 1); -} - -// regression test for issue #85322. Peekable previously implemented InPlaceIterable, -// but due to an interaction with IntoIter's current Clone implementation it failed to uphold -// the contract. -#[test] -fn test_collect_after_iterator_clone() { - let v = vec![0; 5]; - let mut i = v.into_iter().map(|i| i + 1).peekable(); - i.peek(); - let v = i.clone().collect::>(); - assert_eq!(v, [1, 1, 1, 1, 1]); - assert!(v.len() <= v.capacity()); -} - -// regression test for #135103, similar to the one above Flatten/FlatMap had an unsound InPlaceIterable -// implementation. -#[test] -fn test_flatten_clone() { - const S: String = String::new(); - - let v = vec![[S, "Hello World!".into()], [S, S]]; - let mut i = v.into_iter().flatten(); - let _ = i.next(); - let result: Vec = i.clone().collect(); - assert_eq!(result, ["Hello World!", "", ""]); -} - -#[test] -fn test_cow_from() { - let borrowed: &[_] = &["borrowed", "(slice)"]; - let owned = vec!["owned", "(vec)"]; - match (Cow::from(owned.clone()), Cow::from(borrowed)) { - (Cow::Owned(o), Cow::Borrowed(b)) => assert!(o == owned && b == borrowed), - _ => panic!("invalid `Cow::from`"), - } -} - -#[test] -fn test_from_cow() { - let borrowed: &[_] = &["borrowed", "(slice)"]; - let owned = vec!["owned", "(vec)"]; - assert_eq!(Vec::from(Cow::Borrowed(borrowed)), vec!["borrowed", "(slice)"]); - assert_eq!(Vec::from(Cow::Owned(owned)), vec!["owned", "(vec)"]); -} - -#[allow(dead_code)] -fn assert_covariance() { - fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { - d - } - fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> { - i - } -} - -#[test] -fn from_into_inner() { - let vec = vec![1, 2, 3]; - let ptr = vec.as_ptr(); - let vec = vec.into_iter().collect::>(); - assert_eq!(vec, [1, 2, 3]); - assert_eq!(vec.as_ptr(), ptr); - - let ptr = &vec[1] as *const _; - let mut it = vec.into_iter(); - it.next().unwrap(); - let vec = it.collect::>(); - assert_eq!(vec, [2, 3]); - assert!(ptr != vec.as_ptr()); -} - -#[test] -fn overaligned_allocations() { - #[repr(align(256))] - struct Foo(usize); - let mut v = vec![Foo(273)]; - for i in 0..0x1000 { - v.reserve_exact(i); - assert!(v[0].0 == 273); - assert!(v.as_ptr() as usize & 0xff == 0); - v.shrink_to_fit(); - assert!(v[0].0 == 273); - assert!(v.as_ptr() as usize & 0xff == 0); - } -} - -#[test] -fn extract_if_empty() { - let mut vec: Vec = vec![]; - - { - let mut iter = vec.extract_if(.., |_| true); - assert_eq!(iter.size_hint(), (0, Some(0))); - assert_eq!(iter.next(), None); - assert_eq!(iter.size_hint(), (0, Some(0))); - assert_eq!(iter.next(), None); - assert_eq!(iter.size_hint(), (0, Some(0))); - } - assert_eq!(vec.len(), 0); - assert_eq!(vec, vec![]); -} - -#[test] -fn extract_if_zst() { - let mut vec = vec![(), (), (), (), ()]; - let initial_len = vec.len(); - let mut count = 0; - { - let mut iter = vec.extract_if(.., |_| true); - assert_eq!(iter.size_hint(), (0, Some(initial_len))); - while let Some(_) = iter.next() { - count += 1; - assert_eq!(iter.size_hint(), (0, Some(initial_len - count))); - } - assert_eq!(iter.size_hint(), (0, Some(0))); - assert_eq!(iter.next(), None); - assert_eq!(iter.size_hint(), (0, Some(0))); - } - - assert_eq!(count, initial_len); - assert_eq!(vec.len(), 0); - assert_eq!(vec, vec![]); -} - -#[test] -fn extract_if_false() { - let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - - let initial_len = vec.len(); - let mut count = 0; - { - let mut iter = vec.extract_if(.., |_| false); - assert_eq!(iter.size_hint(), (0, Some(initial_len))); - for _ in iter.by_ref() { - count += 1; - } - assert_eq!(iter.size_hint(), (0, Some(0))); - assert_eq!(iter.next(), None); - assert_eq!(iter.size_hint(), (0, Some(0))); - } - - assert_eq!(count, 0); - assert_eq!(vec.len(), initial_len); - assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); -} - -#[test] -fn extract_if_true() { - let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - - let initial_len = vec.len(); - let mut count = 0; - { - let mut iter = vec.extract_if(.., |_| true); - assert_eq!(iter.size_hint(), (0, Some(initial_len))); - while let Some(_) = iter.next() { - count += 1; - assert_eq!(iter.size_hint(), (0, Some(initial_len - count))); - } - assert_eq!(iter.size_hint(), (0, Some(0))); - assert_eq!(iter.next(), None); - assert_eq!(iter.size_hint(), (0, Some(0))); - } - - assert_eq!(count, initial_len); - assert_eq!(vec.len(), 0); - assert_eq!(vec, vec![]); -} - -#[test] -fn extract_if_ranges() { - let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - - let mut count = 0; - let it = vec.extract_if(1..=3, |_| { - count += 1; - true - }); - assert_eq!(it.collect::>(), vec![1, 2, 3]); - assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]); - assert_eq!(count, 3); - - let it = vec.extract_if(1..=3, |_| false); - assert_eq!(it.collect::>(), vec![]); - assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]); -} - -#[test] -#[should_panic] -fn extract_if_out_of_bounds() { - let mut vec = vec![0, 1]; - let _ = vec.extract_if(5.., |_| true).for_each(drop); -} - -#[test] -fn extract_if_complex() { - { - // [+xxx++++++xxxxx++++x+x++] - let mut vec = vec![ - 1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, - 39, - ]; - - let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); - assert_eq!(removed.len(), 10); - assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); - - assert_eq!(vec.len(), 14); - assert_eq!(vec, vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]); - } - - { - // [xxx++++++xxxxx++++x+x++] - let mut vec = vec![ - 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39, - ]; - - let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); - assert_eq!(removed.len(), 10); - assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); - - assert_eq!(vec.len(), 13); - assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]); - } - - { - // [xxx++++++xxxxx++++x+x] - let mut vec = - vec![2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]; - - let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); - assert_eq!(removed.len(), 10); - assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); - - assert_eq!(vec.len(), 11); - assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]); - } - - { - // [xxxxxxxxxx+++++++++++] - let mut vec = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; - - let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); - assert_eq!(removed.len(), 10); - assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); - - assert_eq!(vec.len(), 10); - assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]); - } - - { - // [+++++++++++xxxxxxxxxx] - let mut vec = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; - - let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::>(); - assert_eq!(removed.len(), 10); - assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); - - assert_eq!(vec.len(), 10); - assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]); - } -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn extract_if_consumed_panic() { - use std::rc::Rc; - use std::sync::Mutex; - - struct Check { - index: usize, - drop_counts: Rc>>, - } - - impl Drop for Check { - fn drop(&mut self) { - self.drop_counts.lock().unwrap()[self.index] += 1; - println!("drop: {}", self.index); - } - } - - let check_count = 10; - let drop_counts = Rc::new(Mutex::new(vec![0_usize; check_count])); - let mut data: Vec = (0..check_count) - .map(|index| Check { index, drop_counts: Rc::clone(&drop_counts) }) - .collect(); - - let _ = std::panic::catch_unwind(move || { - let filter = |c: &mut Check| { - if c.index == 2 { - panic!("panic at index: {}", c.index); - } - // Verify that if the filter could panic again on another element - // that it would not cause a double panic and all elements of the - // vec would still be dropped exactly once. - if c.index == 4 { - panic!("panic at index: {}", c.index); - } - c.index < 6 - }; - let drain = data.extract_if(.., filter); - - // NOTE: The ExtractIf is explicitly consumed - drain.for_each(drop); - }); - - let drop_counts = drop_counts.lock().unwrap(); - assert_eq!(check_count, drop_counts.len()); - - for (index, count) in drop_counts.iter().cloned().enumerate() { - assert_eq!(1, count, "unexpected drop count at index: {} (count: {})", index, count); - } -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn extract_if_unconsumed_panic() { - use std::rc::Rc; - use std::sync::Mutex; - - struct Check { - index: usize, - drop_counts: Rc>>, - } - - impl Drop for Check { - fn drop(&mut self) { - self.drop_counts.lock().unwrap()[self.index] += 1; - println!("drop: {}", self.index); - } - } - - let check_count = 10; - let drop_counts = Rc::new(Mutex::new(vec![0_usize; check_count])); - let mut data: Vec = (0..check_count) - .map(|index| Check { index, drop_counts: Rc::clone(&drop_counts) }) - .collect(); - - let _ = std::panic::catch_unwind(move || { - let filter = |c: &mut Check| { - if c.index == 2 { - panic!("panic at index: {}", c.index); - } - // Verify that if the filter could panic again on another element - // that it would not cause a double panic and all elements of the - // vec would still be dropped exactly once. - if c.index == 4 { - panic!("panic at index: {}", c.index); - } - c.index < 6 - }; - let _drain = data.extract_if(.., filter); - - // NOTE: The ExtractIf is dropped without being consumed - }); - - let drop_counts = drop_counts.lock().unwrap(); - assert_eq!(check_count, drop_counts.len()); - - for (index, count) in drop_counts.iter().cloned().enumerate() { - assert_eq!(1, count, "unexpected drop count at index: {} (count: {})", index, count); - } -} - -#[test] -fn extract_if_unconsumed() { - let mut vec = vec![1, 2, 3, 4]; - let drain = vec.extract_if(.., |&mut x| x % 2 != 0); - drop(drain); - assert_eq!(vec, [1, 2, 3, 4]); -} - -#[test] -fn test_reserve_exact() { - // This is all the same as test_reserve - - let mut v = Vec::new(); - assert_eq!(v.capacity(), 0); - - v.reserve_exact(2); - assert!(v.capacity() >= 2); - - for i in 0..16 { - v.push(i); - } - - assert!(v.capacity() >= 16); - v.reserve_exact(16); - assert!(v.capacity() >= 32); - - v.push(16); - - v.reserve_exact(16); - assert!(v.capacity() >= 33) -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM -fn test_try_with_capacity() { - let mut vec: Vec = Vec::try_with_capacity(5).unwrap(); - assert_eq!(0, vec.len()); - assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4); - assert!(vec.spare_capacity_mut().len() >= 5); - - assert!(Vec::::try_with_capacity(isize::MAX as usize + 1).is_err()); -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM -fn test_try_reserve() { - // These are the interesting cases: - // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM) - // * > isize::MAX should always fail - // * On 16/32-bit should CapacityOverflow - // * On 64-bit should OOM - // * overflow may trigger when adding `len` to `cap` (in number of elements) - // * overflow may trigger when multiplying `new_cap` by size_of:: (to get bytes) - - const MAX_CAP: usize = isize::MAX as usize; - const MAX_USIZE: usize = usize::MAX; - - { - // Note: basic stuff is checked by test_reserve - let mut empty_bytes: Vec = Vec::new(); - - // Check isize::MAX doesn't count as an overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - // Play it again, frank! (just to be sure) - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } - - { - // Same basic idea, but with non-zero len - let mut ten_bytes: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Should always overflow in the add-to-len - assert_matches!( - ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } - - { - // Same basic idea, but with interesting type size - let mut ten_u32s: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Should fail in the mul-by-size - assert_matches!( - ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM -fn test_try_reserve_exact() { - // This is exactly the same as test_try_reserve with the method changed. - // See that test for comments. - - const MAX_CAP: usize = isize::MAX as usize; - const MAX_USIZE: usize = usize::MAX; - - { - let mut empty_bytes: Vec = Vec::new(); - - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } - - { - let mut ten_bytes: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - - if let Err(CapacityOverflow) = - ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = - ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } - - { - let mut ten_u32s: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - - if let Err(CapacityOverflow) = - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } -} - -#[test] -fn test_stable_pointers() { - /// Pull an element from the iterator, then drop it. - /// Useful to cover both the `next` and `drop` paths of an iterator. - fn next_then_drop(mut i: I) { - i.next().unwrap(); - drop(i); - } - - // Test that, if we reserved enough space, adding and removing elements does not - // invalidate references into the vector (such as `v0`). This test also - // runs in Miri, which would detect such problems. - // Note that this test does *not* constitute a stable guarantee that all these functions do not - // reallocate! Only what is explicitly documented at - // is stably guaranteed. - let mut v = Vec::with_capacity(128); - v.push(13); - - // Laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. - let v0 = &mut v[0]; - let v0 = unsafe { &mut *(v0 as *mut _) }; - // Now do a bunch of things and occasionally use `v0` again to assert it is still valid. - - // Pushing/inserting and popping/removing - v.push(1); - v.push(2); - v.insert(1, 1); - assert_eq!(*v0, 13); - v.remove(1); - v.pop().unwrap(); - assert_eq!(*v0, 13); - v.push(1); - v.swap_remove(1); - assert_eq!(v.len(), 2); - v.swap_remove(1); // swap_remove the last element - assert_eq!(*v0, 13); - - // Appending - v.append(&mut vec![27, 19]); - assert_eq!(*v0, 13); - - // Extending - v.extend_from_slice(&[1, 2]); - v.extend(&[1, 2]); // `slice::Iter` (with `T: Copy`) specialization - v.extend(vec![2, 3]); // `vec::IntoIter` specialization - v.extend(std::iter::once(3)); // `TrustedLen` specialization - v.extend(std::iter::empty::()); // `TrustedLen` specialization with empty iterator - v.extend(std::iter::once(3).filter(|_| true)); // base case - v.extend(std::iter::once(&3)); // `cloned` specialization - assert_eq!(*v0, 13); - - // Truncation - v.truncate(2); - assert_eq!(*v0, 13); - - // Resizing - v.resize_with(v.len() + 10, || 42); - assert_eq!(*v0, 13); - v.resize_with(2, || panic!()); - assert_eq!(*v0, 13); - - // No-op reservation - v.reserve(32); - v.reserve_exact(32); - assert_eq!(*v0, 13); - - // Partial draining - v.resize_with(10, || 42); - next_then_drop(v.drain(5..)); - assert_eq!(*v0, 13); - - // Splicing - v.resize_with(10, || 42); - next_then_drop(v.splice(5.., vec![1, 2, 3, 4, 5])); // empty tail after range - assert_eq!(*v0, 13); - next_then_drop(v.splice(5..8, vec![1])); // replacement is smaller than original range - assert_eq!(*v0, 13); - next_then_drop(v.splice(5..6, [1; 10].into_iter().filter(|_| true))); // lower bound not exact - assert_eq!(*v0, 13); - - // spare_capacity_mut - v.spare_capacity_mut(); - assert_eq!(*v0, 13); - - // Smoke test that would fire even outside Miri if an actual relocation happened. - // Also ensures the pointer is still writeable after all this. - *v0 -= 13; - assert_eq!(v[0], 0); -} - -// https://github.com/rust-lang/rust/pull/49496 introduced specialization based on: -// -// ``` -// unsafe impl IsZero for *mut T { -// fn is_zero(&self) -> bool { -// (*self).is_null() -// } -// } -// ``` -// -// … to call `RawVec::with_capacity_zeroed` for creating `Vec<*mut T>`, -// which is incorrect for fat pointers since `<*mut T>::is_null` only looks at the data component. -// That is, a fat pointer can be “null” without being made entirely of zero bits. -#[test] -fn vec_macro_repeating_null_raw_fat_pointer() { - let raw_dyn = &mut (|| ()) as &mut dyn Fn() as *mut dyn Fn(); - let vtable = dbg!(ptr_metadata(raw_dyn)); - let null_raw_dyn = ptr_from_raw_parts(std::ptr::null_mut(), vtable); - assert!(null_raw_dyn.is_null()); - - let vec = vec![null_raw_dyn; 1]; - dbg!(ptr_metadata(vec[0])); - assert!(std::ptr::eq(vec[0], null_raw_dyn)); - - // Polyfill for https://github.com/rust-lang/rfcs/pull/2580 - - fn ptr_metadata(ptr: *mut dyn Fn()) -> *mut () { - unsafe { std::mem::transmute::<*mut dyn Fn(), DynRepr>(ptr).vtable } - } - - fn ptr_from_raw_parts(data: *mut (), vtable: *mut ()) -> *mut dyn Fn() { - unsafe { std::mem::transmute::(DynRepr { data, vtable }) } - } - - #[repr(C)] - struct DynRepr { - data: *mut (), - vtable: *mut (), - } -} - -// This test will likely fail if you change the capacities used in -// `RawVec::grow_amortized`. -#[test] -fn test_push_growth_strategy() { - // If the element size is 1, we jump from 0 to 8, then double. - { - let mut v1: Vec = vec![]; - assert_eq!(v1.capacity(), 0); - - for _ in 0..8 { - v1.push(0); - assert_eq!(v1.capacity(), 8); - } - - for _ in 8..16 { - v1.push(0); - assert_eq!(v1.capacity(), 16); - } - - for _ in 16..32 { - v1.push(0); - assert_eq!(v1.capacity(), 32); - } - - for _ in 32..64 { - v1.push(0); - assert_eq!(v1.capacity(), 64); - } - } - - // If the element size is 2..=1024, we jump from 0 to 4, then double. - { - let mut v2: Vec = vec![]; - let mut v1024: Vec<[u8; 1024]> = vec![]; - assert_eq!(v2.capacity(), 0); - assert_eq!(v1024.capacity(), 0); - - for _ in 0..4 { - v2.push(0); - v1024.push([0; 1024]); - assert_eq!(v2.capacity(), 4); - assert_eq!(v1024.capacity(), 4); - } - - for _ in 4..8 { - v2.push(0); - v1024.push([0; 1024]); - assert_eq!(v2.capacity(), 8); - assert_eq!(v1024.capacity(), 8); - } - - for _ in 8..16 { - v2.push(0); - v1024.push([0; 1024]); - assert_eq!(v2.capacity(), 16); - assert_eq!(v1024.capacity(), 16); - } - - for _ in 16..32 { - v2.push(0); - v1024.push([0; 1024]); - assert_eq!(v2.capacity(), 32); - assert_eq!(v1024.capacity(), 32); - } - - for _ in 32..64 { - v2.push(0); - v1024.push([0; 1024]); - assert_eq!(v2.capacity(), 64); - assert_eq!(v1024.capacity(), 64); - } - } - - // If the element size is > 1024, we jump from 0 to 1, then double. - { - let mut v1025: Vec<[u8; 1025]> = vec![]; - assert_eq!(v1025.capacity(), 0); - - for _ in 0..1 { - v1025.push([0; 1025]); - assert_eq!(v1025.capacity(), 1); - } - - for _ in 1..2 { - v1025.push([0; 1025]); - assert_eq!(v1025.capacity(), 2); - } - - for _ in 2..4 { - v1025.push([0; 1025]); - assert_eq!(v1025.capacity(), 4); - } - - for _ in 4..8 { - v1025.push([0; 1025]); - assert_eq!(v1025.capacity(), 8); - } - - for _ in 8..16 { - v1025.push([0; 1025]); - assert_eq!(v1025.capacity(), 16); - } - - for _ in 16..32 { - v1025.push([0; 1025]); - assert_eq!(v1025.capacity(), 32); - } - - for _ in 32..64 { - v1025.push([0; 1025]); - assert_eq!(v1025.capacity(), 64); - } - } -} - -macro_rules! generate_assert_eq_vec_and_prim { - ($name:ident<$B:ident>($type:ty)) => { - fn $name + Debug, $B: Debug>(a: Vec, b: $type) { - assert!(a == b); - assert_eq!(a, b); - } - }; -} - -generate_assert_eq_vec_and_prim! { assert_eq_vec_and_slice (&[B]) } -generate_assert_eq_vec_and_prim! { assert_eq_vec_and_array_3([B; 3]) } - -#[test] -fn partialeq_vec_and_prim() { - assert_eq_vec_and_slice(vec![1, 2, 3], &[1, 2, 3]); - assert_eq_vec_and_array_3(vec![1, 2, 3], [1, 2, 3]); -} - -macro_rules! assert_partial_eq_valid { - ($a2:expr, $a3:expr; $b2:expr, $b3: expr) => { - assert!($a2 == $b2); - assert!($a2 != $b3); - assert!($a3 != $b2); - assert!($a3 == $b3); - assert_eq!($a2, $b2); - assert_ne!($a2, $b3); - assert_ne!($a3, $b2); - assert_eq!($a3, $b3); - }; -} - -#[test] -fn partialeq_vec_full() { - let vec2: Vec<_> = vec![1, 2]; - let vec3: Vec<_> = vec![1, 2, 3]; - let slice2: &[_] = &[1, 2]; - let slice3: &[_] = &[1, 2, 3]; - let slicemut2: &[_] = &mut [1, 2]; - let slicemut3: &[_] = &mut [1, 2, 3]; - let array2: [_; 2] = [1, 2]; - let array3: [_; 3] = [1, 2, 3]; - let arrayref2: &[_; 2] = &[1, 2]; - let arrayref3: &[_; 3] = &[1, 2, 3]; - - assert_partial_eq_valid!(vec2,vec3; vec2,vec3); - assert_partial_eq_valid!(vec2,vec3; slice2,slice3); - assert_partial_eq_valid!(vec2,vec3; slicemut2,slicemut3); - assert_partial_eq_valid!(slice2,slice3; vec2,vec3); - assert_partial_eq_valid!(slicemut2,slicemut3; vec2,vec3); - assert_partial_eq_valid!(vec2,vec3; array2,array3); - assert_partial_eq_valid!(vec2,vec3; arrayref2,arrayref3); - assert_partial_eq_valid!(vec2,vec3; arrayref2[..],arrayref3[..]); -} - -#[test] -fn test_vec_cycle() { - #[derive(Debug)] - struct C<'a> { - v: Vec>>>, - } - - impl<'a> C<'a> { - fn new() -> C<'a> { - C { v: Vec::new() } - } - } - - let mut c1 = C::new(); - let mut c2 = C::new(); - let mut c3 = C::new(); - - // Push - c1.v.push(Cell::new(None)); - c1.v.push(Cell::new(None)); - - c2.v.push(Cell::new(None)); - c2.v.push(Cell::new(None)); - - c3.v.push(Cell::new(None)); - c3.v.push(Cell::new(None)); - - // Set - c1.v[0].set(Some(&c2)); - c1.v[1].set(Some(&c3)); - - c2.v[0].set(Some(&c2)); - c2.v[1].set(Some(&c3)); - - c3.v[0].set(Some(&c1)); - c3.v[1].set(Some(&c2)); -} - -#[test] -fn test_vec_cycle_wrapped() { - struct Refs<'a> { - v: Vec>>>, - } - - struct C<'a> { - refs: Refs<'a>, - } - - impl<'a> Refs<'a> { - fn new() -> Refs<'a> { - Refs { v: Vec::new() } - } - } - - impl<'a> C<'a> { - fn new() -> C<'a> { - C { refs: Refs::new() } - } - } - - let mut c1 = C::new(); - let mut c2 = C::new(); - let mut c3 = C::new(); - - c1.refs.v.push(Cell::new(None)); - c1.refs.v.push(Cell::new(None)); - c2.refs.v.push(Cell::new(None)); - c2.refs.v.push(Cell::new(None)); - c3.refs.v.push(Cell::new(None)); - c3.refs.v.push(Cell::new(None)); - - c1.refs.v[0].set(Some(&c2)); - c1.refs.v[1].set(Some(&c3)); - c2.refs.v[0].set(Some(&c2)); - c2.refs.v[1].set(Some(&c3)); - c3.refs.v[0].set(Some(&c1)); - c3.refs.v[1].set(Some(&c2)); -} - -#[test] -fn test_zero_sized_capacity() { - for len in [0, 1, 2, 4, 8, 16, 32, 64, 128, 256] { - let v = Vec::<()>::with_capacity(len); - assert_eq!(v.len(), 0); - assert_eq!(v.capacity(), usize::MAX); - } -} - -#[test] -fn test_zero_sized_vec_push() { - const N: usize = 8; - - for len in 0..N { - let mut tester = Vec::with_capacity(len); - assert_eq!(tester.len(), 0); - assert!(tester.capacity() >= len); - for _ in 0..len { - tester.push(()); - } - assert_eq!(tester.len(), len); - assert_eq!(tester.iter().count(), len); - tester.clear(); - } -} - -#[test] -fn test_vec_macro_repeat() { - assert_eq!(vec![1; 3], vec![1, 1, 1]); - assert_eq!(vec![1; 2], vec![1, 1]); - assert_eq!(vec![1; 1], vec![1]); - assert_eq!(vec![1; 0], vec![]); - - // from_elem syntax (see RFC 832) - let el = Box::new(1); - let n = 3; - assert_eq!(vec![el; n], vec![Box::new(1), Box::new(1), Box::new(1)]); -} - -#[test] -fn test_vec_swap() { - let mut a: Vec = vec![0, 1, 2, 3, 4, 5, 6]; - a.swap(2, 4); - assert_eq!(a[2], 4); - assert_eq!(a[4], 2); - let mut n = 42; - swap(&mut n, &mut a[0]); - assert_eq!(a[0], 42); - assert_eq!(n, 0); -} - -#[test] -fn test_extend_from_within_spec() { - #[derive(Copy)] - struct CopyOnly; - - impl Clone for CopyOnly { - fn clone(&self) -> Self { - panic!("extend_from_within must use specialization on copy"); - } - } - - vec![CopyOnly, CopyOnly].extend_from_within(..); -} - -#[test] -fn test_extend_from_within_clone() { - let mut v = vec![String::from("sssss"), String::from("12334567890"), String::from("c")]; - v.extend_from_within(1..); - - assert_eq!(v, ["sssss", "12334567890", "c", "12334567890", "c"]); -} - -#[test] -fn test_extend_from_within_complete_rande() { - let mut v = vec![0, 1, 2, 3]; - v.extend_from_within(..); - - assert_eq!(v, [0, 1, 2, 3, 0, 1, 2, 3]); -} - -#[test] -fn test_extend_from_within_empty_rande() { - let mut v = vec![0, 1, 2, 3]; - v.extend_from_within(1..1); - - assert_eq!(v, [0, 1, 2, 3]); -} - -#[test] -#[should_panic] -fn test_extend_from_within_out_of_rande() { - let mut v = vec![0, 1]; - v.extend_from_within(..3); -} - -#[test] -fn test_extend_from_within_zst() { - let mut v = vec![(); 8]; - v.extend_from_within(3..7); - - assert_eq!(v, [(); 12]); -} - -#[test] -fn test_extend_from_within_empty_vec() { - let mut v = Vec::::new(); - v.extend_from_within(..); - - assert_eq!(v, []); -} - -#[test] -fn test_extend_from_within() { - let mut v = vec![String::from("a"), String::from("b"), String::from("c")]; - v.extend_from_within(1..=2); - v.extend_from_within(..=1); - - assert_eq!(v, ["a", "b", "c", "b", "c", "a", "b"]); -} - -#[test] -fn test_vec_dedup_by() { - let mut vec: Vec = vec![1, -1, 2, 3, 1, -5, 5, -2, 2]; - - vec.dedup_by(|a, b| a.abs() == b.abs()); - - assert_eq!(vec, [1, 2, 3, 1, -5, -2]); -} - -#[test] -fn test_vec_dedup_empty() { - let mut vec: Vec = Vec::new(); - - vec.dedup(); - - assert_eq!(vec, []); -} - -#[test] -fn test_vec_dedup_one() { - let mut vec = vec![12i32]; - - vec.dedup(); - - assert_eq!(vec, [12]); -} - -#[test] -fn test_vec_dedup_multiple_ident() { - let mut vec = vec![12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11]; - - vec.dedup(); - - assert_eq!(vec, [12, 11]); -} - -#[test] -fn test_vec_dedup_partialeq() { - #[derive(Debug)] - struct Foo(i32, #[allow(dead_code)] i32); - - impl PartialEq for Foo { - fn eq(&self, other: &Foo) -> bool { - self.0 == other.0 - } - } - - let mut vec = vec![Foo(0, 1), Foo(0, 5), Foo(1, 7), Foo(1, 9)]; - - vec.dedup(); - assert_eq!(vec, [Foo(0, 1), Foo(1, 7)]); -} - -#[test] -fn test_vec_dedup() { - let mut vec: Vec = Vec::with_capacity(8); - let mut template = vec.clone(); - - for x in 0u8..255u8 { - vec.clear(); - template.clear(); - - let iter = (0..8).map(move |bit| (x >> bit) & 1 == 1); - vec.extend(iter); - template.extend_from_slice(&vec); - - let (dedup, _) = template.partition_dedup(); - vec.dedup(); - - assert_eq!(vec, dedup); - } -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_vec_dedup_panicking() { - #[derive(Debug)] - struct Panic<'a> { - drop_counter: &'a Cell, - value: bool, - index: usize, - } - - impl<'a> PartialEq for Panic<'a> { - fn eq(&self, other: &Self) -> bool { - self.value == other.value - } - } - - impl<'a> Drop for Panic<'a> { - fn drop(&mut self) { - self.drop_counter.set(self.drop_counter.get() + 1); - if !std::thread::panicking() { - assert!(self.index != 4); - } - } - } - - let drop_counter = &Cell::new(0); - let expected = [ - Panic { drop_counter, value: false, index: 0 }, - Panic { drop_counter, value: false, index: 5 }, - Panic { drop_counter, value: true, index: 6 }, - Panic { drop_counter, value: true, index: 7 }, - ]; - let mut vec = vec![ - Panic { drop_counter, value: false, index: 0 }, - // these elements get deduplicated - Panic { drop_counter, value: false, index: 1 }, - Panic { drop_counter, value: false, index: 2 }, - Panic { drop_counter, value: false, index: 3 }, - Panic { drop_counter, value: false, index: 4 }, - // here it panics while dropping the item with index==4 - Panic { drop_counter, value: false, index: 5 }, - Panic { drop_counter, value: true, index: 6 }, - Panic { drop_counter, value: true, index: 7 }, - ]; - - let _ = catch_unwind(AssertUnwindSafe(|| vec.dedup())).unwrap_err(); - - assert_eq!(drop_counter.get(), 4); - - let ok = vec.iter().zip(expected.iter()).all(|(x, y)| x.index == y.index); - - if !ok { - panic!("expected: {expected:?}\ngot: {vec:?}\n"); - } -} - -// Regression test for issue #82533 -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_extend_from_within_panicking_clone() { - struct Panic<'dc> { - drop_count: &'dc AtomicU32, - aaaaa: bool, - } - - impl Clone for Panic<'_> { - fn clone(&self) -> Self { - if self.aaaaa { - panic!("panic! at the clone"); - } - - Self { ..*self } - } - } - - impl Drop for Panic<'_> { - fn drop(&mut self) { - self.drop_count.fetch_add(1, Ordering::SeqCst); - } - } - - let count = core::sync::atomic::AtomicU32::new(0); - let mut vec = vec![ - Panic { drop_count: &count, aaaaa: false }, - Panic { drop_count: &count, aaaaa: true }, - Panic { drop_count: &count, aaaaa: false }, - ]; - - // This should clone&append one Panic{..} at the end, and then panic while - // cloning second Panic{..}. This means that `Panic::drop` should be called - // 4 times (3 for items already in vector, 1 for just appended). - // - // Previously just appended item was leaked, making drop_count = 3, instead of 4. - std::panic::catch_unwind(move || vec.extend_from_within(..)).unwrap_err(); - - assert_eq!(count.load(Ordering::SeqCst), 4); -} - -#[test] -#[should_panic = "vec len overflow"] -fn test_into_flattened_size_overflow() { - let v = vec![[(); usize::MAX]; 2]; - let _ = v.into_flattened(); -} - -#[test] -fn test_box_zero_allocator() { - use core::alloc::AllocError; - use core::cell::RefCell; - use std::collections::HashSet; - - // Track ZST allocations and ensure that they all have a matching free. - struct ZstTracker { - state: RefCell<(HashSet, usize)>, - } - unsafe impl Allocator for ZstTracker { - fn allocate(&self, layout: Layout) -> Result, AllocError> { - let ptr = if layout.size() == 0 { - let mut state = self.state.borrow_mut(); - let addr = state.1; - assert!(state.0.insert(addr)); - state.1 += 1; - std::println!("allocating {addr}"); - std::ptr::without_provenance_mut(addr) - } else { - unsafe { std::alloc::alloc(layout) } - }; - Ok(NonNull::slice_from_raw_parts(NonNull::new(ptr).ok_or(AllocError)?, layout.size())) - } - - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - if layout.size() == 0 { - let addr = ptr.as_ptr() as usize; - let mut state = self.state.borrow_mut(); - std::println!("freeing {addr}"); - assert!(state.0.remove(&addr), "ZST free that wasn't allocated"); - } else { - unsafe { std::alloc::dealloc(ptr.as_ptr(), layout) } - } - } - } - - // Start the state at 100 to avoid returning null pointers. - let alloc = ZstTracker { state: RefCell::new((HashSet::new(), 100)) }; - - // Ensure that unsizing retains the same behavior. - { - let b1: Box<[u8; 0], &ZstTracker> = Box::new_in([], &alloc); - let b2: Box<[u8], &ZstTracker> = b1.clone(); - let _b3: Box<[u8], &ZstTracker> = b2.clone(); - } - - // Ensure that shrinking doesn't leak a ZST allocation. - { - let mut v1: Vec = Vec::with_capacity_in(100, &alloc); - v1.shrink_to_fit(); - } - - // Ensure that conversion to/from vec works. - { - let v1: Vec<(), &ZstTracker> = Vec::with_capacity_in(100, &alloc); - let _b1: Box<[()], &ZstTracker> = v1.into_boxed_slice(); - let b2: Box<[()], &ZstTracker> = Box::new_in([(), (), ()], &alloc); - let _v2: Vec<(), &ZstTracker> = b2.into(); - } - - // Ensure all ZSTs have been freed. - assert!(alloc.state.borrow().0.is_empty()); -} - -#[test] -fn test_vec_from_array_ref() { - assert_eq!(Vec::from(&[1, 2, 3]), vec![1, 2, 3]); -} - -#[test] -fn test_vec_from_array_mut_ref() { - assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]); -} - -#[test] -fn test_pop_if() { - let mut v = vec![1, 2, 3, 4]; - let pred = |x: &mut i32| *x % 2 == 0; - - assert_eq!(v.pop_if(pred), Some(4)); - assert_eq!(v, [1, 2, 3]); - - assert_eq!(v.pop_if(pred), None); - assert_eq!(v, [1, 2, 3]); -} - -#[test] -fn test_pop_if_empty() { - let mut v = Vec::::new(); - assert_eq!(v.pop_if(|_| true), None); - assert!(v.is_empty()); -} - -#[test] -fn test_pop_if_mutates() { - let mut v = vec![1]; - let pred = |x: &mut i32| { - *x += 1; - false - }; - assert_eq!(v.pop_if(pred), None); - assert_eq!(v, [2]); -} - -/// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments -/// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but -/// `vec.insert(usize::MAX, val)` once slipped by! -/// -/// All code that manipulates the collection types should be tested with "trivially wrong" args. -#[test] -fn max_dont_panic() { - let mut v = vec![0]; - let _ = v.get(usize::MAX); - v.shrink_to(usize::MAX); - v.truncate(usize::MAX); -} - -#[test] -#[should_panic] -fn max_insert() { - let mut v = vec![0]; - v.insert(usize::MAX, 1); -} - -#[test] -#[should_panic] -fn max_remove() { - let mut v = vec![0]; - v.remove(usize::MAX); -} - -#[test] -#[should_panic] -fn max_splice() { - let mut v = vec![0]; - v.splice(usize::MAX.., core::iter::once(1)); -} - -#[test] -#[should_panic] -fn max_swap_remove() { - let mut v = vec![0]; - v.swap_remove(usize::MAX); -} - -// Regression test for #135338 -#[test] -fn vec_null_ptr_roundtrip() { - let ptr = std::ptr::from_ref(&42); - let zero = ptr.with_addr(0); - let roundtripped = vec![zero; 1].pop().unwrap(); - let new = roundtripped.with_addr(ptr.addr()); - unsafe { new.read() }; -} diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs deleted file mode 100644 index 1b03c29e5bd..00000000000 --- a/library/alloc/tests/vec_deque.rs +++ /dev/null @@ -1,1865 +0,0 @@ -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#![allow(static_mut_refs)] - -use core::num::NonZero; -use std::assert_matches::assert_matches; -use std::collections::TryReserveErrorKind::*; -use std::collections::VecDeque; -use std::collections::vec_deque::Drain; -use std::fmt::Debug; -use std::ops::Bound::*; -use std::panic::{AssertUnwindSafe, catch_unwind}; - -use Taggy::*; -use Taggypar::*; - -use crate::hash; - -#[test] -fn test_simple() { - let mut d = VecDeque::new(); - assert_eq!(d.len(), 0); - d.push_front(17); - d.push_front(42); - d.push_back(137); - assert_eq!(d.len(), 3); - d.push_back(137); - assert_eq!(d.len(), 4); - assert_eq!(*d.front().unwrap(), 42); - assert_eq!(*d.back().unwrap(), 137); - let mut i = d.pop_front(); - assert_eq!(i, Some(42)); - i = d.pop_back(); - assert_eq!(i, Some(137)); - i = d.pop_back(); - assert_eq!(i, Some(137)); - i = d.pop_back(); - assert_eq!(i, Some(17)); - assert_eq!(d.len(), 0); - d.push_back(3); - assert_eq!(d.len(), 1); - d.push_front(2); - assert_eq!(d.len(), 2); - d.push_back(4); - assert_eq!(d.len(), 3); - d.push_front(1); - assert_eq!(d.len(), 4); - assert_eq!(d[0], 1); - assert_eq!(d[1], 2); - assert_eq!(d[2], 3); - assert_eq!(d[3], 4); -} - -fn test_parameterized(a: T, b: T, c: T, d: T) { - let mut deq = VecDeque::new(); - assert_eq!(deq.len(), 0); - deq.push_front(a.clone()); - deq.push_front(b.clone()); - deq.push_back(c.clone()); - assert_eq!(deq.len(), 3); - deq.push_back(d.clone()); - assert_eq!(deq.len(), 4); - assert_eq!((*deq.front().unwrap()).clone(), b.clone()); - assert_eq!((*deq.back().unwrap()).clone(), d.clone()); - assert_eq!(deq.pop_front().unwrap(), b.clone()); - assert_eq!(deq.pop_back().unwrap(), d.clone()); - assert_eq!(deq.pop_back().unwrap(), c.clone()); - assert_eq!(deq.pop_back().unwrap(), a.clone()); - assert_eq!(deq.len(), 0); - deq.push_back(c.clone()); - assert_eq!(deq.len(), 1); - deq.push_front(b.clone()); - assert_eq!(deq.len(), 2); - deq.push_back(d.clone()); - assert_eq!(deq.len(), 3); - deq.push_front(a.clone()); - assert_eq!(deq.len(), 4); - assert_eq!(deq[0].clone(), a.clone()); - assert_eq!(deq[1].clone(), b.clone()); - assert_eq!(deq[2].clone(), c.clone()); - assert_eq!(deq[3].clone(), d.clone()); -} - -#[test] -fn test_pop_if() { - let mut deq: VecDeque<_> = vec![0, 1, 2, 3, 4].into(); - let pred = |x: &mut i32| *x % 2 == 0; - - assert_eq!(deq.pop_front_if(pred), Some(0)); - assert_eq!(deq, [1, 2, 3, 4]); - - assert_eq!(deq.pop_front_if(pred), None); - assert_eq!(deq, [1, 2, 3, 4]); - - assert_eq!(deq.pop_back_if(pred), Some(4)); - assert_eq!(deq, [1, 2, 3]); - - assert_eq!(deq.pop_back_if(pred), None); - assert_eq!(deq, [1, 2, 3]); -} - -#[test] -fn test_pop_if_empty() { - let mut deq = VecDeque::::new(); - assert_eq!(deq.pop_front_if(|_| true), None); - assert_eq!(deq.pop_back_if(|_| true), None); - assert!(deq.is_empty()); -} - -#[test] -fn test_pop_if_mutates() { - let mut v: VecDeque<_> = vec![-1, 1].into(); - let pred = |x: &mut i32| { - *x *= 2; - false - }; - assert_eq!(v.pop_front_if(pred), None); - assert_eq!(v, [-2, 1]); - assert_eq!(v.pop_back_if(pred), None); - assert_eq!(v, [-2, 2]); -} - -#[test] -fn test_push_front_grow() { - let mut deq = VecDeque::new(); - for i in 0..66 { - deq.push_front(i); - } - assert_eq!(deq.len(), 66); - - for i in 0..66 { - assert_eq!(deq[i], 65 - i); - } - - let mut deq = VecDeque::new(); - for i in 0..66 { - deq.push_back(i); - } - - for i in 0..66 { - assert_eq!(deq[i], i); - } -} - -#[test] -fn test_index() { - let mut deq = VecDeque::new(); - for i in 1..4 { - deq.push_front(i); - } - assert_eq!(deq[1], 2); -} - -#[test] -#[should_panic] -fn test_index_out_of_bounds() { - let mut deq = VecDeque::new(); - for i in 1..4 { - deq.push_front(i); - } - deq[3]; -} - -#[test] -#[should_panic] -fn test_range_start_overflow() { - let deq = VecDeque::from(vec![1, 2, 3]); - deq.range((Included(0), Included(usize::MAX))); -} - -#[test] -#[should_panic] -fn test_range_end_overflow() { - let deq = VecDeque::from(vec![1, 2, 3]); - deq.range((Excluded(usize::MAX), Included(0))); -} - -#[derive(Clone, PartialEq, Debug)] -enum Taggy { - One(i32), - Two(i32, i32), - Three(i32, i32, i32), -} - -#[derive(Clone, PartialEq, Debug)] -enum Taggypar { - Onepar(T), - Twopar(T, T), - Threepar(T, T, T), -} - -#[derive(Clone, PartialEq, Debug)] -struct RecCy { - x: i32, - y: i32, - t: Taggy, -} - -#[test] -fn test_param_int() { - test_parameterized::(5, 72, 64, 175); -} - -#[test] -fn test_param_taggy() { - test_parameterized::(One(1), Two(1, 2), Three(1, 2, 3), Two(17, 42)); -} - -#[test] -fn test_param_taggypar() { - test_parameterized::>( - Onepar::(1), - Twopar::(1, 2), - Threepar::(1, 2, 3), - Twopar::(17, 42), - ); -} - -#[test] -fn test_param_reccy() { - let reccy1 = RecCy { x: 1, y: 2, t: One(1) }; - let reccy2 = RecCy { x: 345, y: 2, t: Two(1, 2) }; - let reccy3 = RecCy { x: 1, y: 777, t: Three(1, 2, 3) }; - let reccy4 = RecCy { x: 19, y: 252, t: Two(17, 42) }; - test_parameterized::(reccy1, reccy2, reccy3, reccy4); -} - -#[test] -fn test_with_capacity() { - let mut d = VecDeque::with_capacity(0); - d.push_back(1); - assert_eq!(d.len(), 1); - let mut d = VecDeque::with_capacity(50); - d.push_back(1); - assert_eq!(d.len(), 1); -} - -#[test] -fn test_with_capacity_non_power_two() { - let mut d3 = VecDeque::with_capacity(3); - d3.push_back(1); - - // X = None, | = lo - // [|1, X, X] - assert_eq!(d3.pop_front(), Some(1)); - // [X, |X, X] - assert_eq!(d3.front(), None); - - // [X, |3, X] - d3.push_back(3); - // [X, |3, 6] - d3.push_back(6); - // [X, X, |6] - assert_eq!(d3.pop_front(), Some(3)); - - // Pushing the lo past half way point to trigger - // the 'B' scenario for growth - // [9, X, |6] - d3.push_back(9); - // [9, 12, |6] - d3.push_back(12); - - d3.push_back(15); - // There used to be a bug here about how the - // VecDeque made growth assumptions about the - // underlying Vec which didn't hold and lead - // to corruption. - // (Vec grows to next power of two) - // good- [9, 12, 15, X, X, X, X, |6] - // bug- [15, 12, X, X, X, |6, X, X] - assert_eq!(d3.pop_front(), Some(6)); - - // Which leads us to the following state which - // would be a failure case. - // bug- [15, 12, X, X, X, X, |X, X] - assert_eq!(d3.front(), Some(&9)); -} - -#[test] -fn test_reserve_exact() { - let mut d = VecDeque::new(); - d.push_back(0); - d.reserve_exact(50); - assert!(d.capacity() >= 51); -} - -#[test] -fn test_reserve() { - let mut d = VecDeque::new(); - d.push_back(0); - d.reserve(50); - assert!(d.capacity() >= 51); -} - -#[test] -fn test_swap() { - let mut d: VecDeque<_> = (0..5).collect(); - d.pop_front(); - d.swap(0, 3); - assert_eq!(d.iter().cloned().collect::>(), [4, 2, 3, 1]); -} - -#[test] -fn test_iter() { - let mut d = VecDeque::new(); - assert_eq!(d.iter().next(), None); - assert_eq!(d.iter().size_hint(), (0, Some(0))); - - for i in 0..5 { - d.push_back(i); - } - { - let b: &[_] = &[&0, &1, &2, &3, &4]; - assert_eq!(d.iter().collect::>(), b); - } - - for i in 6..9 { - d.push_front(i); - } - { - let b: &[_] = &[&8, &7, &6, &0, &1, &2, &3, &4]; - assert_eq!(d.iter().collect::>(), b); - } - - let mut it = d.iter(); - let mut len = d.len(); - loop { - match it.next() { - None => break, - _ => { - len -= 1; - assert_eq!(it.size_hint(), (len, Some(len))) - } - } - } -} - -#[test] -fn test_rev_iter() { - let mut d = VecDeque::new(); - assert_eq!(d.iter().rev().next(), None); - - for i in 0..5 { - d.push_back(i); - } - { - let b: &[_] = &[&4, &3, &2, &1, &0]; - assert_eq!(d.iter().rev().collect::>(), b); - } - - for i in 6..9 { - d.push_front(i); - } - let b: &[_] = &[&4, &3, &2, &1, &0, &6, &7, &8]; - assert_eq!(d.iter().rev().collect::>(), b); -} - -#[test] -fn test_mut_rev_iter_wrap() { - let mut d = VecDeque::with_capacity(3); - assert!(d.iter_mut().rev().next().is_none()); - - d.push_back(1); - d.push_back(2); - d.push_back(3); - assert_eq!(d.pop_front(), Some(1)); - d.push_back(4); - - assert_eq!(d.iter_mut().rev().map(|x| *x).collect::>(), vec![4, 3, 2]); -} - -#[test] -fn test_mut_iter() { - let mut d = VecDeque::new(); - assert!(d.iter_mut().next().is_none()); - - for i in 0..3 { - d.push_front(i); - } - - for (i, elt) in d.iter_mut().enumerate() { - assert_eq!(*elt, 2 - i); - *elt = i; - } - - { - let mut it = d.iter_mut(); - assert_eq!(*it.next().unwrap(), 0); - assert_eq!(*it.next().unwrap(), 1); - assert_eq!(*it.next().unwrap(), 2); - assert!(it.next().is_none()); - } -} - -#[test] -fn test_mut_rev_iter() { - let mut d = VecDeque::new(); - assert!(d.iter_mut().rev().next().is_none()); - - for i in 0..3 { - d.push_front(i); - } - - for (i, elt) in d.iter_mut().rev().enumerate() { - assert_eq!(*elt, i); - *elt = i; - } - - { - let mut it = d.iter_mut().rev(); - assert_eq!(*it.next().unwrap(), 0); - assert_eq!(*it.next().unwrap(), 1); - assert_eq!(*it.next().unwrap(), 2); - assert!(it.next().is_none()); - } -} - -#[test] -fn test_into_iter() { - // Empty iter - { - let d: VecDeque = VecDeque::new(); - let mut iter = d.into_iter(); - - assert_eq!(iter.size_hint(), (0, Some(0))); - assert_eq!(iter.next(), None); - assert_eq!(iter.size_hint(), (0, Some(0))); - } - - // simple iter - { - let mut d = VecDeque::new(); - for i in 0..5 { - d.push_back(i); - } - - let b = vec![0, 1, 2, 3, 4]; - assert_eq!(d.into_iter().collect::>(), b); - } - - // wrapped iter - { - let mut d = VecDeque::new(); - for i in 0..5 { - d.push_back(i); - } - for i in 6..9 { - d.push_front(i); - } - - let b = vec![8, 7, 6, 0, 1, 2, 3, 4]; - assert_eq!(d.into_iter().collect::>(), b); - } - - // partially used - { - let mut d = VecDeque::new(); - for i in 0..5 { - d.push_back(i); - } - for i in 6..9 { - d.push_front(i); - } - - let mut it = d.into_iter(); - assert_eq!(it.size_hint(), (8, Some(8))); - assert_eq!(it.next(), Some(8)); - assert_eq!(it.size_hint(), (7, Some(7))); - assert_eq!(it.next_back(), Some(4)); - assert_eq!(it.size_hint(), (6, Some(6))); - assert_eq!(it.next(), Some(7)); - assert_eq!(it.size_hint(), (5, Some(5))); - } - - // advance_by - { - let mut d = VecDeque::new(); - for i in 0..=4 { - d.push_back(i); - } - for i in 6..=8 { - d.push_front(i); - } - - let mut it = d.into_iter(); - assert_eq!(it.advance_by(1), Ok(())); - assert_eq!(it.next(), Some(7)); - assert_eq!(it.advance_back_by(1), Ok(())); - assert_eq!(it.next_back(), Some(3)); - - let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter(); - assert_eq!(it.advance_by(10), Err(NonZero::new(5).unwrap())); - let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter(); - assert_eq!(it.advance_back_by(10), Err(NonZero::new(5).unwrap())); - } -} - -#[test] -fn test_drain() { - // Empty iter - { - let mut d: VecDeque = VecDeque::new(); - - { - let mut iter = d.drain(..); - - assert_eq!(iter.size_hint(), (0, Some(0))); - assert_eq!(iter.next(), None); - assert_eq!(iter.size_hint(), (0, Some(0))); - } - - assert!(d.is_empty()); - } - - // simple iter - { - let mut d = VecDeque::new(); - for i in 0..5 { - d.push_back(i); - } - - assert_eq!(d.drain(..).collect::>(), [0, 1, 2, 3, 4]); - assert!(d.is_empty()); - } - - // wrapped iter - { - let mut d = VecDeque::new(); - for i in 0..5 { - d.push_back(i); - } - for i in 6..9 { - d.push_front(i); - } - assert_eq!(d.drain(..).collect::>(), [8, 7, 6, 0, 1, 2, 3, 4]); - assert!(d.is_empty()); - } - - // partially used - { - let mut d: VecDeque<_> = VecDeque::new(); - for i in 0..5 { - d.push_back(i); - } - for i in 6..9 { - d.push_front(i); - } - - { - let mut it = d.drain(..); - assert_eq!(it.size_hint(), (8, Some(8))); - assert_eq!(it.next(), Some(8)); - assert_eq!(it.size_hint(), (7, Some(7))); - assert_eq!(it.next_back(), Some(4)); - assert_eq!(it.size_hint(), (6, Some(6))); - assert_eq!(it.next(), Some(7)); - assert_eq!(it.size_hint(), (5, Some(5))); - } - assert!(d.is_empty()); - } -} - -#[test] -fn test_from_iter() { - let v = vec![1, 2, 3, 4, 5, 6, 7]; - let deq: VecDeque<_> = v.iter().cloned().collect(); - let u: Vec<_> = deq.iter().cloned().collect(); - assert_eq!(u, v); - - let seq = (0..).step_by(2).take(256); - let deq: VecDeque<_> = seq.collect(); - for (i, &x) in deq.iter().enumerate() { - assert_eq!(2 * i, x); - } - assert_eq!(deq.len(), 256); -} - -#[test] -fn test_clone() { - let mut d = VecDeque::new(); - d.push_front(17); - d.push_front(42); - d.push_back(137); - d.push_back(137); - assert_eq!(d.len(), 4); - let mut e = d.clone(); - assert_eq!(e.len(), 4); - while !d.is_empty() { - assert_eq!(d.pop_back(), e.pop_back()); - } - assert_eq!(d.len(), 0); - assert_eq!(e.len(), 0); -} - -#[test] -fn test_eq() { - let mut d = VecDeque::new(); - assert!(d == VecDeque::with_capacity(0)); - d.push_front(137); - d.push_front(17); - d.push_front(42); - d.push_back(137); - let mut e = VecDeque::with_capacity(0); - e.push_back(42); - e.push_back(17); - e.push_back(137); - e.push_back(137); - assert!(&e == &d); - e.pop_back(); - e.push_back(0); - assert!(e != d); - e.clear(); - assert!(e == VecDeque::new()); -} - -#[test] -fn test_partial_eq_array() { - let d = VecDeque::::new(); - assert!(d == []); - - let mut d = VecDeque::new(); - d.push_front('a'); - assert!(d == ['a']); - - let mut d = VecDeque::new(); - d.push_back('a'); - assert!(d == ['a']); - - let mut d = VecDeque::new(); - d.push_back('a'); - d.push_back('b'); - assert!(d == ['a', 'b']); -} - -#[test] -fn test_hash() { - let mut x = VecDeque::new(); - let mut y = VecDeque::new(); - - x.push_back(1); - x.push_back(2); - x.push_back(3); - - y.push_back(0); - y.push_back(1); - y.pop_front(); - y.push_back(2); - y.push_back(3); - - assert!(hash(&x) == hash(&y)); -} - -#[test] -fn test_hash_after_rotation() { - // test that two deques hash equal even if elements are laid out differently - let len = 28; - let mut ring: VecDeque = (0..len as i32).collect(); - let orig = ring.clone(); - for _ in 0..ring.capacity() { - // shift values 1 step to the right by pop, sub one, push - ring.pop_front(); - for elt in &mut ring { - *elt -= 1; - } - ring.push_back(len - 1); - assert_eq!(hash(&orig), hash(&ring)); - assert_eq!(orig, ring); - assert_eq!(ring, orig); - } -} - -#[test] -fn test_eq_after_rotation() { - // test that two deques are equal even if elements are laid out differently - let len = 28; - let mut ring: VecDeque = (0..len as i32).collect(); - let mut shifted = ring.clone(); - for _ in 0..10 { - // shift values 1 step to the right by pop, sub one, push - ring.pop_front(); - for elt in &mut ring { - *elt -= 1; - } - ring.push_back(len - 1); - } - - // try every shift - for _ in 0..shifted.capacity() { - shifted.pop_front(); - for elt in &mut shifted { - *elt -= 1; - } - shifted.push_back(len - 1); - assert_eq!(shifted, ring); - assert_eq!(ring, shifted); - } -} - -#[test] -fn test_ord() { - let x = VecDeque::new(); - let mut y = VecDeque::new(); - y.push_back(1); - y.push_back(2); - y.push_back(3); - assert!(x < y); - assert!(y > x); - assert!(x <= x); - assert!(x >= x); -} - -#[test] -fn test_show() { - let ringbuf: VecDeque<_> = (0..10).collect(); - assert_eq!(format!("{ringbuf:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"); - - let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"].iter().cloned().collect(); - assert_eq!(format!("{ringbuf:?}"), "[\"just\", \"one\", \"test\", \"more\"]"); -} - -#[test] -fn test_drop() { - static mut DROPS: i32 = 0; - struct Elem; - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } - - let mut ring = VecDeque::new(); - ring.push_back(Elem); - ring.push_front(Elem); - ring.push_back(Elem); - ring.push_front(Elem); - drop(ring); - - assert_eq!(unsafe { DROPS }, 4); -} - -#[test] -fn test_drop_with_pop() { - static mut DROPS: i32 = 0; - struct Elem; - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } - - let mut ring = VecDeque::new(); - ring.push_back(Elem); - ring.push_front(Elem); - ring.push_back(Elem); - ring.push_front(Elem); - - drop(ring.pop_back()); - drop(ring.pop_front()); - assert_eq!(unsafe { DROPS }, 2); - - drop(ring); - assert_eq!(unsafe { DROPS }, 4); -} - -#[test] -fn test_drop_clear() { - static mut DROPS: i32 = 0; - struct Elem; - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } - - let mut ring = VecDeque::new(); - ring.push_back(Elem); - ring.push_front(Elem); - ring.push_back(Elem); - ring.push_front(Elem); - ring.clear(); - assert_eq!(unsafe { DROPS }, 4); - - drop(ring); - assert_eq!(unsafe { DROPS }, 4); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_drop_panic() { - static mut DROPS: i32 = 0; - - struct D(bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.0 { - panic!("panic in `drop`"); - } - } - } - - let mut q = VecDeque::new(); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_front(D(false)); - q.push_front(D(false)); - q.push_front(D(true)); - - catch_unwind(move || drop(q)).ok(); - - assert_eq!(unsafe { DROPS }, 8); -} - -#[test] -fn test_reserve_grow() { - // test growth path A - // [T o o H] -> [T o o H . . . . ] - let mut ring = VecDeque::with_capacity(4); - for i in 0..3 { - ring.push_back(i); - } - ring.reserve(7); - for i in 0..3 { - assert_eq!(ring.pop_front(), Some(i)); - } - - // test growth path B - // [H T o o] -> [. T o o H . . . ] - let mut ring = VecDeque::with_capacity(4); - for i in 0..1 { - ring.push_back(i); - assert_eq!(ring.pop_front(), Some(i)); - } - for i in 0..3 { - ring.push_back(i); - } - ring.reserve(7); - for i in 0..3 { - assert_eq!(ring.pop_front(), Some(i)); - } - - // test growth path C - // [o o H T] -> [o o H . . . . T ] - let mut ring = VecDeque::with_capacity(4); - for i in 0..3 { - ring.push_back(i); - assert_eq!(ring.pop_front(), Some(i)); - } - for i in 0..3 { - ring.push_back(i); - } - ring.reserve(7); - for i in 0..3 { - assert_eq!(ring.pop_front(), Some(i)); - } -} - -#[test] -fn test_get() { - let mut ring = VecDeque::new(); - ring.push_back(0); - assert_eq!(ring.get(0), Some(&0)); - assert_eq!(ring.get(1), None); - - ring.push_back(1); - assert_eq!(ring.get(0), Some(&0)); - assert_eq!(ring.get(1), Some(&1)); - assert_eq!(ring.get(2), None); - - ring.push_back(2); - assert_eq!(ring.get(0), Some(&0)); - assert_eq!(ring.get(1), Some(&1)); - assert_eq!(ring.get(2), Some(&2)); - assert_eq!(ring.get(3), None); - - assert_eq!(ring.pop_front(), Some(0)); - assert_eq!(ring.get(0), Some(&1)); - assert_eq!(ring.get(1), Some(&2)); - assert_eq!(ring.get(2), None); - - assert_eq!(ring.pop_front(), Some(1)); - assert_eq!(ring.get(0), Some(&2)); - assert_eq!(ring.get(1), None); - - assert_eq!(ring.pop_front(), Some(2)); - assert_eq!(ring.get(0), None); - assert_eq!(ring.get(1), None); -} - -#[test] -fn test_get_mut() { - let mut ring = VecDeque::new(); - for i in 0..3 { - ring.push_back(i); - } - - match ring.get_mut(1) { - Some(x) => *x = -1, - None => (), - }; - - assert_eq!(ring.get_mut(0), Some(&mut 0)); - assert_eq!(ring.get_mut(1), Some(&mut -1)); - assert_eq!(ring.get_mut(2), Some(&mut 2)); - assert_eq!(ring.get_mut(3), None); - - assert_eq!(ring.pop_front(), Some(0)); - assert_eq!(ring.get_mut(0), Some(&mut -1)); - assert_eq!(ring.get_mut(1), Some(&mut 2)); - assert_eq!(ring.get_mut(2), None); -} - -#[test] -fn test_front() { - let mut ring = VecDeque::new(); - ring.push_back(10); - ring.push_back(20); - assert_eq!(ring.front(), Some(&10)); - ring.pop_front(); - assert_eq!(ring.front(), Some(&20)); - ring.pop_front(); - assert_eq!(ring.front(), None); -} - -#[test] -fn test_as_slices() { - let mut ring: VecDeque = VecDeque::with_capacity(127); - let cap = ring.capacity() as i32; - let first = cap / 2; - let last = cap - first; - for i in 0..first { - ring.push_back(i); - - let (left, right) = ring.as_slices(); - let expected: Vec<_> = (0..=i).collect(); - assert_eq!(left, &expected[..]); - assert_eq!(right, []); - } - - for j in -last..0 { - ring.push_front(j); - let (left, right) = ring.as_slices(); - let expected_left: Vec<_> = (-last..=j).rev().collect(); - let expected_right: Vec<_> = (0..first).collect(); - assert_eq!(left, &expected_left[..]); - assert_eq!(right, &expected_right[..]); - } - - assert_eq!(ring.len() as i32, cap); - assert_eq!(ring.capacity() as i32, cap); -} - -#[test] -fn test_as_mut_slices() { - let mut ring: VecDeque = VecDeque::with_capacity(127); - let cap = ring.capacity() as i32; - let first = cap / 2; - let last = cap - first; - for i in 0..first { - ring.push_back(i); - - let (left, right) = ring.as_mut_slices(); - let expected: Vec<_> = (0..=i).collect(); - assert_eq!(left, &expected[..]); - assert_eq!(right, []); - } - - for j in -last..0 { - ring.push_front(j); - let (left, right) = ring.as_mut_slices(); - let expected_left: Vec<_> = (-last..=j).rev().collect(); - let expected_right: Vec<_> = (0..first).collect(); - assert_eq!(left, &expected_left[..]); - assert_eq!(right, &expected_right[..]); - } - - assert_eq!(ring.len() as i32, cap); - assert_eq!(ring.capacity() as i32, cap); -} - -#[test] -fn test_append() { - let mut a: VecDeque<_> = [1, 2, 3].into_iter().collect(); - let mut b: VecDeque<_> = [4, 5, 6].into_iter().collect(); - - // normal append - a.append(&mut b); - assert_eq!(a.iter().cloned().collect::>(), [1, 2, 3, 4, 5, 6]); - assert_eq!(b.iter().cloned().collect::>(), []); - - // append nothing to something - a.append(&mut b); - assert_eq!(a.iter().cloned().collect::>(), [1, 2, 3, 4, 5, 6]); - assert_eq!(b.iter().cloned().collect::>(), []); - - // append something to nothing - b.append(&mut a); - assert_eq!(b.iter().cloned().collect::>(), [1, 2, 3, 4, 5, 6]); - assert_eq!(a.iter().cloned().collect::>(), []); -} - -#[test] -fn test_append_permutations() { - fn construct_vec_deque( - push_back: usize, - pop_back: usize, - push_front: usize, - pop_front: usize, - ) -> VecDeque { - let mut out = VecDeque::new(); - for a in 0..push_back { - out.push_back(a); - } - for b in 0..push_front { - out.push_front(push_back + b); - } - for _ in 0..pop_back { - out.pop_back(); - } - for _ in 0..pop_front { - out.pop_front(); - } - out - } - - // Miri is too slow - let max = if cfg!(miri) { 3 } else { 5 }; - - // Many different permutations of both the `VecDeque` getting appended to - // and the one getting appended are generated to check `append`. - // This ensures all 6 code paths of `append` are tested. - for src_push_back in 0..max { - for src_push_front in 0..max { - // doesn't pop more values than are pushed - for src_pop_back in 0..(src_push_back + src_push_front) { - for src_pop_front in 0..(src_push_back + src_push_front - src_pop_back) { - let src = construct_vec_deque( - src_push_back, - src_pop_back, - src_push_front, - src_pop_front, - ); - - for dst_push_back in 0..max { - for dst_push_front in 0..max { - for dst_pop_back in 0..(dst_push_back + dst_push_front) { - for dst_pop_front in - 0..(dst_push_back + dst_push_front - dst_pop_back) - { - let mut dst = construct_vec_deque( - dst_push_back, - dst_pop_back, - dst_push_front, - dst_pop_front, - ); - let mut src = src.clone(); - - // Assert that appending `src` to `dst` gives the same order - // of values as iterating over both in sequence. - let correct = dst - .iter() - .chain(src.iter()) - .cloned() - .collect::>(); - dst.append(&mut src); - assert_eq!(dst, correct); - assert!(src.is_empty()); - } - } - } - } - } - } - } - } -} - -struct DropCounter<'a> { - count: &'a mut u32, -} - -impl Drop for DropCounter<'_> { - fn drop(&mut self) { - *self.count += 1; - } -} - -#[test] -fn test_append_double_drop() { - let (mut count_a, mut count_b) = (0, 0); - { - let mut a = VecDeque::new(); - let mut b = VecDeque::new(); - a.push_back(DropCounter { count: &mut count_a }); - b.push_back(DropCounter { count: &mut count_b }); - - a.append(&mut b); - } - assert_eq!(count_a, 1); - assert_eq!(count_b, 1); -} - -#[test] -#[should_panic] -fn test_append_zst_capacity_overflow() { - let mut v = Vec::with_capacity(usize::MAX); - // note: using resize instead of set_len here would - // be *extremely* slow in unoptimized builds. - // SAFETY: `v` has capacity `usize::MAX`, and no initialization - // is needed for empty tuples. - unsafe { v.set_len(usize::MAX) }; - let mut v = VecDeque::from(v); - let mut w = vec![()].into(); - v.append(&mut w); -} - -#[test] -fn test_retain() { - let mut buf = VecDeque::new(); - buf.extend(1..5); - buf.retain(|&x| x % 2 == 0); - let v: Vec<_> = buf.into_iter().collect(); - assert_eq!(&v[..], &[2, 4]); -} - -#[test] -fn test_extend_ref() { - let mut v = VecDeque::new(); - v.push_back(1); - v.extend(&[2, 3, 4]); - - assert_eq!(v.len(), 4); - assert_eq!(v[0], 1); - assert_eq!(v[1], 2); - assert_eq!(v[2], 3); - assert_eq!(v[3], 4); - - let mut w = VecDeque::new(); - w.push_back(5); - w.push_back(6); - v.extend(&w); - - assert_eq!(v.len(), 6); - assert_eq!(v[0], 1); - assert_eq!(v[1], 2); - assert_eq!(v[2], 3); - assert_eq!(v[3], 4); - assert_eq!(v[4], 5); - assert_eq!(v[5], 6); -} - -#[test] -fn test_contains() { - let mut v = VecDeque::new(); - v.extend(&[2, 3, 4]); - - assert!(v.contains(&3)); - assert!(!v.contains(&1)); - - v.clear(); - - assert!(!v.contains(&3)); -} - -#[allow(dead_code)] -fn assert_covariance() { - fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { - d - } -} - -#[test] -fn test_is_empty() { - let mut v = VecDeque::::new(); - assert!(v.is_empty()); - assert!(v.iter().is_empty()); - assert!(v.iter_mut().is_empty()); - v.extend(&[2, 3, 4]); - assert!(!v.is_empty()); - assert!(!v.iter().is_empty()); - assert!(!v.iter_mut().is_empty()); - while let Some(_) = v.pop_front() { - assert_eq!(v.is_empty(), v.len() == 0); - assert_eq!(v.iter().is_empty(), v.iter().len() == 0); - assert_eq!(v.iter_mut().is_empty(), v.iter_mut().len() == 0); - } - assert!(v.is_empty()); - assert!(v.iter().is_empty()); - assert!(v.iter_mut().is_empty()); - assert!(v.into_iter().is_empty()); -} - -#[test] -fn test_reserve_exact_2() { - // This is all the same as test_reserve - - let mut v = VecDeque::new(); - - v.reserve_exact(2); - assert!(v.capacity() >= 2); - - for i in 0..16 { - v.push_back(i); - } - - assert!(v.capacity() >= 16); - v.reserve_exact(16); - assert!(v.capacity() >= 32); - - v.push_back(16); - - v.reserve_exact(16); - assert!(v.capacity() >= 33) -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM -fn test_try_with_capacity() { - let vec: VecDeque = VecDeque::try_with_capacity(5).unwrap(); - assert_eq!(0, vec.len()); - assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4); - - assert!(VecDeque::::try_with_capacity(isize::MAX as usize + 1).is_err()); -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM -fn test_try_reserve() { - // These are the interesting cases: - // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM) - // * > isize::MAX should always fail - // * On 16/32-bit should CapacityOverflow - // * On 64-bit should OOM - // * overflow may trigger when adding `len` to `cap` (in number of elements) - // * overflow may trigger when multiplying `new_cap` by size_of:: (to get bytes) - - const MAX_CAP: usize = isize::MAX as usize; - const MAX_USIZE: usize = usize::MAX; - - { - // Note: basic stuff is checked by test_reserve - let mut empty_bytes: VecDeque = VecDeque::new(); - - // Check isize::MAX doesn't count as an overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - // Play it again, frank! (just to be sure) - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } - - { - // Same basic idea, but with non-zero len - let mut ten_bytes: VecDeque = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Should always overflow in the add-to-len - assert_matches!( - ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } - - { - // Same basic idea, but with interesting type size - let mut ten_u32s: VecDeque = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Should fail in the mul-by-size - assert_matches!( - ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM -fn test_try_reserve_exact() { - // This is exactly the same as test_try_reserve with the method changed. - // See that test for comments. - - const MAX_CAP: usize = isize::MAX as usize; - const MAX_USIZE: usize = usize::MAX; - - { - let mut empty_bytes: VecDeque = VecDeque::new(); - - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } - - { - let mut ten_bytes: VecDeque = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - - if let Err(CapacityOverflow) = - ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = - ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } - - { - let mut ten_u32s: VecDeque = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - - if let Err(CapacityOverflow) = - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - if let Err(CapacityOverflow) = - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) - { - panic!("isize::MAX shouldn't trigger an overflow!"); - } - - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } -} - -#[test] -fn test_rotate_nop() { - let mut v: VecDeque<_> = (0..10).collect(); - assert_unchanged(&v); - - v.rotate_left(0); - assert_unchanged(&v); - - v.rotate_left(10); - assert_unchanged(&v); - - v.rotate_right(0); - assert_unchanged(&v); - - v.rotate_right(10); - assert_unchanged(&v); - - v.rotate_left(3); - v.rotate_right(3); - assert_unchanged(&v); - - v.rotate_right(3); - v.rotate_left(3); - assert_unchanged(&v); - - v.rotate_left(6); - v.rotate_right(6); - assert_unchanged(&v); - - v.rotate_right(6); - v.rotate_left(6); - assert_unchanged(&v); - - v.rotate_left(3); - v.rotate_left(7); - assert_unchanged(&v); - - v.rotate_right(4); - v.rotate_right(6); - assert_unchanged(&v); - - v.rotate_left(1); - v.rotate_left(2); - v.rotate_left(3); - v.rotate_left(4); - assert_unchanged(&v); - - v.rotate_right(1); - v.rotate_right(2); - v.rotate_right(3); - v.rotate_right(4); - assert_unchanged(&v); - - fn assert_unchanged(v: &VecDeque) { - assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - } -} - -#[test] -fn test_rotate_left_parts() { - let mut v: VecDeque<_> = VecDeque::with_capacity(8); - v.extend(1..=7); - v.rotate_left(2); - assert_eq!(v.as_slices(), (&[3, 4, 5, 6, 7, 1][..], &[2][..])); - v.rotate_left(2); - assert_eq!(v.as_slices(), (&[5, 6, 7, 1][..], &[2, 3, 4][..])); - v.rotate_left(2); - assert_eq!(v.as_slices(), (&[7, 1][..], &[2, 3, 4, 5, 6][..])); - v.rotate_left(2); - assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7, 1][..], &[][..])); - v.rotate_left(2); - assert_eq!(v.as_slices(), (&[4, 5, 6, 7, 1, 2][..], &[3][..])); - v.rotate_left(2); - assert_eq!(v.as_slices(), (&[6, 7, 1, 2][..], &[3, 4, 5][..])); - v.rotate_left(2); - assert_eq!(v.as_slices(), (&[1, 2][..], &[3, 4, 5, 6, 7][..])); -} - -#[test] -fn test_rotate_right_parts() { - let mut v: VecDeque<_> = VecDeque::with_capacity(8); - v.extend(1..=7); - v.rotate_right(2); - assert_eq!(v.as_slices(), (&[6, 7][..], &[1, 2, 3, 4, 5][..])); - v.rotate_right(2); - assert_eq!(v.as_slices(), (&[4, 5, 6, 7][..], &[1, 2, 3][..])); - v.rotate_right(2); - assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7][..], &[1][..])); - v.rotate_right(2); - assert_eq!(v.as_slices(), (&[7, 1, 2, 3, 4, 5, 6][..], &[][..])); - v.rotate_right(2); - assert_eq!(v.as_slices(), (&[5, 6][..], &[7, 1, 2, 3, 4][..])); - v.rotate_right(2); - assert_eq!(v.as_slices(), (&[3, 4, 5, 6][..], &[7, 1, 2][..])); - v.rotate_right(2); - assert_eq!(v.as_slices(), (&[1, 2, 3, 4, 5, 6][..], &[7][..])); -} - -#[test] -fn test_rotate_left_random() { - let shifts = [ - 6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1, 4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11, 9, 4, 12, 3, - 12, 9, 11, 1, 7, 9, 7, 2, - ]; - let n = 12; - let mut v: VecDeque<_> = (0..n).collect(); - let mut total_shift = 0; - for shift in shifts.iter().cloned() { - v.rotate_left(shift); - total_shift += shift; - for i in 0..n { - assert_eq!(v[i], (i + total_shift) % n); - } - } -} - -#[test] -fn test_rotate_right_random() { - let shifts = [ - 6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1, 4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11, 9, 4, 12, 3, - 12, 9, 11, 1, 7, 9, 7, 2, - ]; - let n = 12; - let mut v: VecDeque<_> = (0..n).collect(); - let mut total_shift = 0; - for shift in shifts.iter().cloned() { - v.rotate_right(shift); - total_shift += shift; - for i in 0..n { - assert_eq!(v[(i + total_shift) % n], i); - } - } -} - -#[test] -fn test_try_fold_empty() { - assert_eq!(Some(0), VecDeque::::new().iter().try_fold(0, |_, _| None)); -} - -#[test] -fn test_try_fold_none() { - let v: VecDeque = (0..12).collect(); - assert_eq!(None, v.into_iter().try_fold(0, |a, b| if b < 11 { Some(a + b) } else { None })); -} - -#[test] -fn test_try_fold_ok() { - let v: VecDeque = (0..12).collect(); - assert_eq!(Ok::<_, ()>(66), v.into_iter().try_fold(0, |a, b| Ok(a + b))); -} - -#[test] -fn test_try_fold_unit() { - let v: VecDeque<()> = std::iter::repeat(()).take(42).collect(); - assert_eq!(Some(()), v.into_iter().try_fold((), |(), ()| Some(()))); -} - -#[test] -fn test_try_fold_unit_none() { - let v: std::collections::VecDeque<()> = [(); 10].iter().cloned().collect(); - let mut iter = v.into_iter(); - assert!(iter.try_fold((), |_, _| None).is_none()); - assert_eq!(iter.len(), 9); -} - -#[test] -fn test_try_fold_rotated() { - let mut v: VecDeque<_> = (0..12).collect(); - for n in 0..10 { - if n & 1 == 0 { - v.rotate_left(n); - } else { - v.rotate_right(n); - } - assert_eq!(Ok::<_, ()>(66), v.iter().try_fold(0, |a, b| Ok(a + b))); - } -} - -#[test] -fn test_try_fold_moves_iter() { - let v: VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect(); - let mut iter = v.into_iter(); - assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None); - assert_eq!(iter.next(), Some(&60)); -} - -#[test] -fn test_try_fold_exhaust_wrap() { - let mut v = VecDeque::with_capacity(7); - v.push_back(1); - v.push_back(1); - v.push_back(1); - v.pop_front(); - v.pop_front(); - let mut iter = v.iter(); - let _ = iter.try_fold(0, |_, _| Some(1)); - assert!(iter.is_empty()); -} - -#[test] -fn test_try_fold_wraparound() { - let mut v = VecDeque::with_capacity(8); - v.push_back(7); - v.push_back(8); - v.push_back(9); - v.push_front(2); - v.push_front(1); - let mut iter = v.iter(); - let _ = iter.find(|&&x| x == 2); - assert_eq!(Some(&7), iter.next()); -} - -#[test] -fn test_try_rfold_rotated() { - let mut v: VecDeque<_> = (0..12).collect(); - for n in 0..10 { - if n & 1 == 0 { - v.rotate_left(n); - } else { - v.rotate_right(n); - } - assert_eq!(Ok::<_, ()>(66), v.iter().try_rfold(0, |a, b| Ok(a + b))); - } -} - -#[test] -fn test_try_rfold_moves_iter() { - let v: VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect(); - let mut iter = v.into_iter(); - assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None); - assert_eq!(iter.next_back(), Some(&70)); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn truncate_leak() { - static mut DROPS: i32 = 0; - - struct D(bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.0 { - panic!("panic in `drop`"); - } - } - } - - let mut q = VecDeque::new(); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_front(D(true)); - q.push_front(D(false)); - q.push_front(D(false)); - - catch_unwind(AssertUnwindSafe(|| q.truncate(1))).ok(); - - assert_eq!(unsafe { DROPS }, 7); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_drain_leak() { - static mut DROPS: i32 = 0; - - #[derive(Debug, PartialEq)] - struct D(u32, bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.1 { - panic!("panic in `drop`"); - } - } - } - - let mut v = VecDeque::new(); - v.push_back(D(4, false)); - v.push_back(D(5, false)); - v.push_back(D(6, false)); - v.push_front(D(3, false)); - v.push_front(D(2, true)); - v.push_front(D(1, false)); - v.push_front(D(0, false)); - - catch_unwind(AssertUnwindSafe(|| { - v.drain(1..=4); - })) - .ok(); - - assert_eq!(unsafe { DROPS }, 4); - assert_eq!(v.len(), 3); - drop(v); - assert_eq!(unsafe { DROPS }, 7); -} - -#[test] -fn test_binary_search() { - // Contiguous (front only) search: - let deque: VecDeque<_> = vec![1, 2, 3, 5, 6].into(); - assert!(deque.as_slices().1.is_empty()); - assert_eq!(deque.binary_search(&3), Ok(2)); - assert_eq!(deque.binary_search(&4), Err(3)); - - // Split search (both front & back non-empty): - let mut deque: VecDeque<_> = vec![5, 6].into(); - deque.push_front(3); - deque.push_front(2); - deque.push_front(1); - deque.push_back(10); - assert!(!deque.as_slices().0.is_empty()); - assert!(!deque.as_slices().1.is_empty()); - assert_eq!(deque.binary_search(&0), Err(0)); - assert_eq!(deque.binary_search(&1), Ok(0)); - assert_eq!(deque.binary_search(&5), Ok(3)); - assert_eq!(deque.binary_search(&7), Err(5)); - assert_eq!(deque.binary_search(&20), Err(6)); -} - -#[test] -fn test_binary_search_by() { - let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into(); - - assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&3)), Ok(2)); - assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&4)), Err(3)); -} - -#[test] -fn test_binary_search_by_key() { - let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into(); - - assert_eq!(deque.binary_search_by_key(&3, |&(v,)| v), Ok(2)); - assert_eq!(deque.binary_search_by_key(&4, |&(v,)| v), Err(3)); -} - -#[test] -fn test_partition_point() { - // Contiguous (front only) search: - let deque: VecDeque<_> = vec![1, 2, 3, 5, 6].into(); - assert!(deque.as_slices().1.is_empty()); - assert_eq!(deque.partition_point(|&v| v <= 3), 3); - - // Split search (both front & back non-empty): - let mut deque: VecDeque<_> = vec![5, 6].into(); - deque.push_front(3); - deque.push_front(2); - deque.push_front(1); - deque.push_back(10); - assert!(!deque.as_slices().0.is_empty()); - assert!(!deque.as_slices().1.is_empty()); - assert_eq!(deque.partition_point(|&v| v <= 5), 4); -} - -#[test] -fn test_zero_sized_push() { - const N: usize = 8; - - // Zero sized type - struct Zst; - - // Test that for all possible sequences of push_front / push_back, - // we end up with a deque of the correct size - - for len in 0..N { - let mut tester = VecDeque::with_capacity(len); - assert_eq!(tester.len(), 0); - assert!(tester.capacity() >= len); - for case in 0..(1 << len) { - assert_eq!(tester.len(), 0); - for bit in 0..len { - if case & (1 << bit) != 0 { - tester.push_front(Zst); - } else { - tester.push_back(Zst); - } - } - assert_eq!(tester.len(), len); - assert_eq!(tester.iter().count(), len); - tester.clear(); - } - } -} - -#[test] -fn test_from_zero_sized_vec() { - let v = vec![(); 100]; - let queue = VecDeque::from(v); - assert_eq!(queue.len(), 100); -} - -#[test] -fn test_resize_keeps_reserved_space_from_item() { - let v = Vec::::with_capacity(1234); - let mut d = VecDeque::new(); - d.resize(1, v); - assert_eq!(d[0].capacity(), 1234); -} - -#[test] -fn test_collect_from_into_iter_keeps_allocation() { - let mut v = Vec::with_capacity(13); - v.extend(0..7); - check(v.as_ptr(), v.last().unwrap(), v.into_iter()); - - let mut v = VecDeque::with_capacity(13); - v.extend(0..7); - check(&v[0], &v[v.len() - 1], v.into_iter()); - - fn check(buf: *const i32, last: *const i32, mut it: impl Iterator) { - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next(), Some(1)); - - let mut v: VecDeque = it.collect(); - assert_eq!(v.capacity(), 13); - assert_eq!(v.as_slices().0.as_ptr(), buf.wrapping_add(2)); - assert_eq!(&v[v.len() - 1] as *const _, last); - - assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice())); - v.push_front(7); - assert_eq!(v.as_slices(), ([7, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); - v.push_front(8); - assert_eq!(v.as_slices(), ([8, 7, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); - - // Now that we've adding thing in place of the two that we removed from - // the front of the iterator, we're back to matching the buffer pointer. - assert_eq!(v.as_slices().0.as_ptr(), buf); - assert_eq!(&v[v.len() - 1] as *const _, last); - - v.push_front(9); - assert_eq!(v.as_slices(), ([9].as_slice(), [8, 7, 2, 3, 4, 5, 6].as_slice())); - assert_eq!(v.capacity(), 13); - } -} diff --git a/library/alloc/tests/vec_deque_alloc_error.rs b/library/alloc/tests/vec_deque_alloc_error.rs deleted file mode 100644 index 21a9118a05b..00000000000 --- a/library/alloc/tests/vec_deque_alloc_error.rs +++ /dev/null @@ -1,48 +0,0 @@ -#![feature(alloc_error_hook, allocator_api)] - -use std::alloc::{AllocError, Allocator, Layout, System, set_alloc_error_hook}; -use std::collections::VecDeque; -use std::panic::{AssertUnwindSafe, catch_unwind}; -use std::ptr::NonNull; - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_shrink_to_unwind() { - // This tests that `shrink_to` leaves the deque in a consistent state when - // the call to `RawVec::shrink_to_fit` unwinds. The code is adapted from #123369 - // but changed to hopefully not have any UB even if the test fails. - - struct BadAlloc; - - unsafe impl Allocator for BadAlloc { - fn allocate(&self, l: Layout) -> Result, AllocError> { - // We allocate zeroed here so that the whole buffer of the deque - // is always initialized. That way, even if the deque is left in - // an inconsistent state, no uninitialized memory should be accessed. - System.allocate_zeroed(l) - } - - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - unsafe { System.deallocate(ptr, layout) } - } - - unsafe fn shrink( - &self, - _ptr: NonNull, - _old_layout: Layout, - _new_layout: Layout, - ) -> Result, AllocError> { - Err(AllocError) - } - } - - set_alloc_error_hook(|_| panic!("alloc error")); - - let mut v = VecDeque::with_capacity_in(15, BadAlloc); - v.push_back(1); - v.push_front(2); - // This should unwind because it calls `BadAlloc::shrink` and then `handle_alloc_error` which unwinds. - assert!(catch_unwind(AssertUnwindSafe(|| v.shrink_to_fit())).is_err()); - // This should only pass if the deque is left in a consistent state. - assert_eq!(v, [2, 1]); -} diff --git a/library/alloctests/Cargo.toml b/library/alloctests/Cargo.toml new file mode 100644 index 00000000000..f1a783b1e22 --- /dev/null +++ b/library/alloctests/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "alloctests" +version = "0.0.0" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/rust.git" +description = "Tests for the Rust Allocation Library" +autotests = false +autobenches = false +edition = "2021" + +[lib] +path = "lib.rs" +test = false +bench = false + +[dev-dependencies] +rand = { version = "0.9.0", default-features = false, features = ["alloc"] } +rand_xorshift = "0.4.0" + +[[test]] +name = "alloctests" +path = "tests/lib.rs" + +[[test]] +name = "vec_deque_alloc_error" +path = "tests/vec_deque_alloc_error.rs" + +[[bench]] +name = "allocbenches" +path = "benches/lib.rs" +test = true + +[[bench]] +name = "vec_deque_append_bench" +path = "benches/vec_deque_append.rs" +harness = false + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + 'cfg(bootstrap)', + 'cfg(no_global_oom_handling)', + 'cfg(no_rc)', + 'cfg(no_sync)', + 'cfg(randomized_layouts)', +] diff --git a/library/alloctests/benches/binary_heap.rs b/library/alloctests/benches/binary_heap.rs new file mode 100644 index 00000000000..1b8f7f1c242 --- /dev/null +++ b/library/alloctests/benches/binary_heap.rs @@ -0,0 +1,91 @@ +use std::collections::BinaryHeap; + +use rand::seq::SliceRandom; +use test::{Bencher, black_box}; + +#[bench] +fn bench_find_smallest_1000(b: &mut Bencher) { + let mut rng = crate::bench_rng(); + let mut vec: Vec = (0..100_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| { + let mut iter = vec.iter().copied(); + let mut heap: BinaryHeap<_> = iter.by_ref().take(1000).collect(); + + for x in iter { + let mut max = heap.peek_mut().unwrap(); + // This comparison should be true only 1% of the time. + // Unnecessary `sift_down`s will degrade performance + if x < *max { + *max = x; + } + } + + heap + }) +} + +#[bench] +fn bench_peek_mut_deref_mut(b: &mut Bencher) { + let mut bheap = BinaryHeap::from(vec![42]); + let vec: Vec = (0..1_000_000).collect(); + + b.iter(|| { + let vec = black_box(&vec); + let mut peek_mut = bheap.peek_mut().unwrap(); + // The compiler shouldn't be able to optimize away the `sift_down` + // assignment in `PeekMut`'s `DerefMut` implementation since + // the loop might not run. + for &i in vec.iter() { + *peek_mut = i; + } + // Remove the already minimal overhead of the sift_down + std::mem::forget(peek_mut); + }) +} + +#[bench] +fn bench_from_vec(b: &mut Bencher) { + let mut rng = crate::bench_rng(); + let mut vec: Vec = (0..100_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| BinaryHeap::from(vec.clone())) +} + +#[bench] +fn bench_into_sorted_vec(b: &mut Bencher) { + let bheap: BinaryHeap = (0..10_000).collect(); + + b.iter(|| bheap.clone().into_sorted_vec()) +} + +#[bench] +fn bench_push(b: &mut Bencher) { + let mut bheap = BinaryHeap::with_capacity(50_000); + let mut rng = crate::bench_rng(); + let mut vec: Vec = (0..50_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| { + for &i in vec.iter() { + bheap.push(i); + } + black_box(&mut bheap); + bheap.clear(); + }) +} + +#[bench] +fn bench_pop(b: &mut Bencher) { + let mut bheap = BinaryHeap::with_capacity(10_000); + + b.iter(|| { + bheap.extend((0..10_000).rev()); + black_box(&mut bheap); + while let Some(elem) = bheap.pop() { + black_box(elem); + } + }) +} diff --git a/library/alloctests/benches/btree/map.rs b/library/alloctests/benches/btree/map.rs new file mode 100644 index 00000000000..20f02dc3a96 --- /dev/null +++ b/library/alloctests/benches/btree/map.rs @@ -0,0 +1,585 @@ +use std::collections::BTreeMap; +use std::ops::RangeBounds; + +use rand::Rng; +use rand::seq::SliceRandom; +use test::{Bencher, black_box}; + +macro_rules! map_insert_rand_bench { + ($name: ident, $n: expr, $map: ident) => { + #[bench] + pub fn $name(b: &mut Bencher) { + let n: u32 = $n; + let mut map = $map::new(); + // setup + let mut rng = crate::bench_rng(); + + for _ in 0..n { + let i = rng.random::() % n; + map.insert(i, i); + } + + // measure + b.iter(|| { + let k = rng.random::() % n; + map.insert(k, k); + map.remove(&k); + }); + black_box(map); + } + }; +} + +macro_rules! map_insert_seq_bench { + ($name: ident, $n: expr, $map: ident) => { + #[bench] + pub fn $name(b: &mut Bencher) { + let mut map = $map::new(); + let n: usize = $n; + // setup + for i in 0..n { + map.insert(i * 2, i * 2); + } + + // measure + let mut i = 1; + b.iter(|| { + map.insert(i, i); + map.remove(&i); + i = (i + 2) % n; + }); + black_box(map); + } + }; +} + +macro_rules! map_from_iter_rand_bench { + ($name: ident, $n: expr, $map: ident) => { + #[bench] + pub fn $name(b: &mut Bencher) { + let n: u32 = $n; + // setup + let mut rng = crate::bench_rng(); + let mut vec = Vec::with_capacity(n as usize); + + for _ in 0..n { + let i = rng.random::() % n; + vec.push((i, i)); + } + + // measure + b.iter(|| { + let map: $map<_, _> = vec.iter().copied().collect(); + black_box(map); + }); + } + }; +} + +macro_rules! map_from_iter_seq_bench { + ($name: ident, $n: expr, $map: ident) => { + #[bench] + pub fn $name(b: &mut Bencher) { + let n: usize = $n; + // setup + let mut vec = Vec::with_capacity(n); + + for i in 0..n { + vec.push((i, i)); + } + + // measure + b.iter(|| { + let map: $map<_, _> = vec.iter().copied().collect(); + black_box(map); + }); + } + }; +} + +macro_rules! map_find_rand_bench { + ($name: ident, $n: expr, $map: ident) => { + #[bench] + pub fn $name(b: &mut Bencher) { + let mut map = $map::new(); + let n: u32 = $n; + + // setup + let mut rng = crate::bench_rng(); + let mut keys: Vec<_> = (0..n).map(|_| rng.random::() % n).collect(); + + for &k in &keys { + map.insert(k, k); + } + + keys.shuffle(&mut rng); + + // measure + let mut i = 0u32; + b.iter(|| { + let t = map.get(&keys[i as usize]); + i = (i + 1) % n; + black_box(t); + }) + } + }; +} + +macro_rules! map_find_seq_bench { + ($name: ident, $n: expr, $map: ident) => { + #[bench] + pub fn $name(b: &mut Bencher) { + let mut map = $map::new(); + let n: usize = $n; + + // setup + for i in 0..n { + map.insert(i, i); + } + + // measure + let mut i = 0; + b.iter(|| { + let x = map.get(&i); + i = (i + 1) % n; + black_box(x); + }) + } + }; +} + +map_insert_rand_bench! {insert_rand_100, 100, BTreeMap} +map_insert_rand_bench! {insert_rand_10_000, 10_000, BTreeMap} + +map_insert_seq_bench! {insert_seq_100, 100, BTreeMap} +map_insert_seq_bench! {insert_seq_10_000, 10_000, BTreeMap} + +map_from_iter_rand_bench! {from_iter_rand_100, 100, BTreeMap} +map_from_iter_rand_bench! {from_iter_rand_10_000, 10_000, BTreeMap} + +map_from_iter_seq_bench! {from_iter_seq_100, 100, BTreeMap} +map_from_iter_seq_bench! {from_iter_seq_10_000, 10_000, BTreeMap} + +map_find_rand_bench! {find_rand_100, 100, BTreeMap} +map_find_rand_bench! {find_rand_10_000, 10_000, BTreeMap} + +map_find_seq_bench! {find_seq_100, 100, BTreeMap} +map_find_seq_bench! {find_seq_10_000, 10_000, BTreeMap} + +fn bench_iteration(b: &mut Bencher, size: i32) { + let mut map = BTreeMap::::new(); + let mut rng = crate::bench_rng(); + + for _ in 0..size { + map.insert(rng.random(), rng.random()); + } + + b.iter(|| { + for entry in &map { + black_box(entry); + } + }); +} + +#[bench] +pub fn iteration_20(b: &mut Bencher) { + bench_iteration(b, 20); +} + +#[bench] +pub fn iteration_1000(b: &mut Bencher) { + bench_iteration(b, 1000); +} + +#[bench] +pub fn iteration_100000(b: &mut Bencher) { + bench_iteration(b, 100000); +} + +fn bench_iteration_mut(b: &mut Bencher, size: i32) { + let mut map = BTreeMap::::new(); + let mut rng = crate::bench_rng(); + + for _ in 0..size { + map.insert(rng.random(), rng.random()); + } + + b.iter(|| { + for kv in map.iter_mut() { + black_box(kv); + } + }); +} + +#[bench] +pub fn iteration_mut_20(b: &mut Bencher) { + bench_iteration_mut(b, 20); +} + +#[bench] +pub fn iteration_mut_1000(b: &mut Bencher) { + bench_iteration_mut(b, 1000); +} + +#[bench] +pub fn iteration_mut_100000(b: &mut Bencher) { + bench_iteration_mut(b, 100000); +} + +fn bench_first_and_last_nightly(b: &mut Bencher, size: i32) { + let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); + b.iter(|| { + for _ in 0..10 { + black_box(map.first_key_value()); + black_box(map.last_key_value()); + } + }); +} + +fn bench_first_and_last_stable(b: &mut Bencher, size: i32) { + let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); + b.iter(|| { + for _ in 0..10 { + black_box(map.iter().next()); + black_box(map.iter().next_back()); + } + }); +} + +#[bench] +pub fn first_and_last_0_nightly(b: &mut Bencher) { + bench_first_and_last_nightly(b, 0); +} + +#[bench] +pub fn first_and_last_0_stable(b: &mut Bencher) { + bench_first_and_last_stable(b, 0); +} + +#[bench] +pub fn first_and_last_100_nightly(b: &mut Bencher) { + bench_first_and_last_nightly(b, 100); +} + +#[bench] +pub fn first_and_last_100_stable(b: &mut Bencher) { + bench_first_and_last_stable(b, 100); +} + +#[bench] +pub fn first_and_last_10k_nightly(b: &mut Bencher) { + bench_first_and_last_nightly(b, 10_000); +} + +#[bench] +pub fn first_and_last_10k_stable(b: &mut Bencher) { + bench_first_and_last_stable(b, 10_000); +} + +const BENCH_RANGE_SIZE: i32 = 145; +const BENCH_RANGE_COUNT: i32 = BENCH_RANGE_SIZE * (BENCH_RANGE_SIZE - 1) / 2; + +fn bench_range(b: &mut Bencher, f: F) +where + F: Fn(i32, i32) -> R, + R: RangeBounds, +{ + let map: BTreeMap<_, _> = (0..BENCH_RANGE_SIZE).map(|i| (i, i)).collect(); + b.iter(|| { + let mut c = 0; + for i in 0..BENCH_RANGE_SIZE { + for j in i + 1..BENCH_RANGE_SIZE { + let _ = black_box(map.range(f(i, j))); + c += 1; + } + } + debug_assert_eq!(c, BENCH_RANGE_COUNT); + }); +} + +#[bench] +pub fn range_included_excluded(b: &mut Bencher) { + bench_range(b, |i, j| i..j); +} + +#[bench] +pub fn range_included_included(b: &mut Bencher) { + bench_range(b, |i, j| i..=j); +} + +#[bench] +pub fn range_included_unbounded(b: &mut Bencher) { + bench_range(b, |i, _| i..); +} + +#[bench] +pub fn range_unbounded_unbounded(b: &mut Bencher) { + bench_range(b, |_, _| ..); +} + +fn bench_iter(b: &mut Bencher, repeats: i32, size: i32) { + let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); + b.iter(|| { + for _ in 0..repeats { + let _ = black_box(map.iter()); + } + }); +} + +/// Contrast range_unbounded_unbounded with `iter()`. +#[bench] +pub fn range_unbounded_vs_iter(b: &mut Bencher) { + bench_iter(b, BENCH_RANGE_COUNT, BENCH_RANGE_SIZE); +} + +#[bench] +pub fn iter_0(b: &mut Bencher) { + bench_iter(b, 1_000, 0); +} + +#[bench] +pub fn iter_1(b: &mut Bencher) { + bench_iter(b, 1_000, 1); +} + +#[bench] +pub fn iter_100(b: &mut Bencher) { + bench_iter(b, 1_000, 100); +} + +#[bench] +pub fn iter_10k(b: &mut Bencher) { + bench_iter(b, 1_000, 10_000); +} + +#[bench] +#[cfg_attr(target_os = "emscripten", ignore)] // hits an OOM +pub fn iter_1m(b: &mut Bencher) { + bench_iter(b, 1_000, 1_000_000); +} + +const FAT: usize = 256; + +// The returned map has small keys and values. +// Benchmarks on it have a counterpart in set.rs with the same keys and no values at all. +fn slim_map(n: usize) -> BTreeMap { + (0..n).map(|i| (i, i)).collect::>() +} + +// The returned map has small keys and large values. +fn fat_val_map(n: usize) -> BTreeMap { + (0..n).map(|i| (i, [i; FAT])).collect::>() +} + +#[bench] +pub fn clone_slim_100(b: &mut Bencher) { + let src = slim_map(100); + b.iter(|| src.clone()) +} + +#[bench] +pub fn clone_slim_100_and_clear(b: &mut Bencher) { + let src = slim_map(100); + b.iter(|| src.clone().clear()) +} + +#[bench] +pub fn clone_slim_100_and_drain_all(b: &mut Bencher) { + let src = slim_map(100); + b.iter(|| src.clone().extract_if(|_, _| true).count()) +} + +#[bench] +pub fn clone_slim_100_and_drain_half(b: &mut Bencher) { + let src = slim_map(100); + b.iter(|| { + let mut map = src.clone(); + assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 100 / 2); + assert_eq!(map.len(), 100 / 2); + }) +} + +#[bench] +pub fn clone_slim_100_and_into_iter(b: &mut Bencher) { + let src = slim_map(100); + b.iter(|| src.clone().into_iter().count()) +} + +#[bench] +pub fn clone_slim_100_and_pop_all(b: &mut Bencher) { + let src = slim_map(100); + b.iter(|| { + let mut map = src.clone(); + while map.pop_first().is_some() {} + map + }); +} + +#[bench] +pub fn clone_slim_100_and_remove_all(b: &mut Bencher) { + let src = slim_map(100); + b.iter(|| { + let mut map = src.clone(); + while let Some(elt) = map.iter().map(|(&i, _)| i).next() { + let v = map.remove(&elt); + debug_assert!(v.is_some()); + } + map + }); +} + +#[bench] +pub fn clone_slim_100_and_remove_half(b: &mut Bencher) { + let src = slim_map(100); + b.iter(|| { + let mut map = src.clone(); + for i in (0..100).step_by(2) { + let v = map.remove(&i); + debug_assert!(v.is_some()); + } + assert_eq!(map.len(), 100 / 2); + map + }) +} + +#[bench] +pub fn clone_slim_10k(b: &mut Bencher) { + let src = slim_map(10_000); + b.iter(|| src.clone()) +} + +#[bench] +pub fn clone_slim_10k_and_clear(b: &mut Bencher) { + let src = slim_map(10_000); + b.iter(|| src.clone().clear()) +} + +#[bench] +pub fn clone_slim_10k_and_drain_all(b: &mut Bencher) { + let src = slim_map(10_000); + b.iter(|| src.clone().extract_if(|_, _| true).count()) +} + +#[bench] +pub fn clone_slim_10k_and_drain_half(b: &mut Bencher) { + let src = slim_map(10_000); + b.iter(|| { + let mut map = src.clone(); + assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 10_000 / 2); + assert_eq!(map.len(), 10_000 / 2); + }) +} + +#[bench] +pub fn clone_slim_10k_and_into_iter(b: &mut Bencher) { + let src = slim_map(10_000); + b.iter(|| src.clone().into_iter().count()) +} + +#[bench] +pub fn clone_slim_10k_and_pop_all(b: &mut Bencher) { + let src = slim_map(10_000); + b.iter(|| { + let mut map = src.clone(); + while map.pop_first().is_some() {} + map + }); +} + +#[bench] +pub fn clone_slim_10k_and_remove_all(b: &mut Bencher) { + let src = slim_map(10_000); + b.iter(|| { + let mut map = src.clone(); + while let Some(elt) = map.iter().map(|(&i, _)| i).next() { + let v = map.remove(&elt); + debug_assert!(v.is_some()); + } + map + }); +} + +#[bench] +pub fn clone_slim_10k_and_remove_half(b: &mut Bencher) { + let src = slim_map(10_000); + b.iter(|| { + let mut map = src.clone(); + for i in (0..10_000).step_by(2) { + let v = map.remove(&i); + debug_assert!(v.is_some()); + } + assert_eq!(map.len(), 10_000 / 2); + map + }) +} + +#[bench] +pub fn clone_fat_val_100(b: &mut Bencher) { + let src = fat_val_map(100); + b.iter(|| src.clone()) +} + +#[bench] +pub fn clone_fat_val_100_and_clear(b: &mut Bencher) { + let src = fat_val_map(100); + b.iter(|| src.clone().clear()) +} + +#[bench] +pub fn clone_fat_val_100_and_drain_all(b: &mut Bencher) { + let src = fat_val_map(100); + b.iter(|| src.clone().extract_if(|_, _| true).count()) +} + +#[bench] +pub fn clone_fat_val_100_and_drain_half(b: &mut Bencher) { + let src = fat_val_map(100); + b.iter(|| { + let mut map = src.clone(); + assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 100 / 2); + assert_eq!(map.len(), 100 / 2); + }) +} + +#[bench] +pub fn clone_fat_val_100_and_into_iter(b: &mut Bencher) { + let src = fat_val_map(100); + b.iter(|| src.clone().into_iter().count()) +} + +#[bench] +pub fn clone_fat_val_100_and_pop_all(b: &mut Bencher) { + let src = fat_val_map(100); + b.iter(|| { + let mut map = src.clone(); + while map.pop_first().is_some() {} + map + }); +} + +#[bench] +pub fn clone_fat_val_100_and_remove_all(b: &mut Bencher) { + let src = fat_val_map(100); + b.iter(|| { + let mut map = src.clone(); + while let Some(elt) = map.iter().map(|(&i, _)| i).next() { + let v = map.remove(&elt); + debug_assert!(v.is_some()); + } + map + }); +} + +#[bench] +pub fn clone_fat_val_100_and_remove_half(b: &mut Bencher) { + let src = fat_val_map(100); + b.iter(|| { + let mut map = src.clone(); + for i in (0..100).step_by(2) { + let v = map.remove(&i); + debug_assert!(v.is_some()); + } + assert_eq!(map.len(), 100 / 2); + map + }) +} diff --git a/library/alloctests/benches/btree/mod.rs b/library/alloctests/benches/btree/mod.rs new file mode 100644 index 00000000000..095ca5dd2e2 --- /dev/null +++ b/library/alloctests/benches/btree/mod.rs @@ -0,0 +1,2 @@ +mod map; +mod set; diff --git a/library/alloctests/benches/btree/set.rs b/library/alloctests/benches/btree/set.rs new file mode 100644 index 00000000000..5aa395b4d52 --- /dev/null +++ b/library/alloctests/benches/btree/set.rs @@ -0,0 +1,224 @@ +use std::collections::BTreeSet; + +use rand::Rng; +use test::Bencher; + +fn random(n: u32) -> BTreeSet { + let mut rng = crate::bench_rng(); + let mut set = BTreeSet::new(); + while set.len() < n as usize { + set.insert(rng.random()); + } + assert_eq!(set.len(), n as usize); + set +} + +fn neg(n: usize) -> BTreeSet { + let set: BTreeSet = (-(n as i32)..=-1).collect(); + assert_eq!(set.len(), n); + set +} + +fn pos(n: usize) -> BTreeSet { + let set: BTreeSet = (1..=(n as i32)).collect(); + assert_eq!(set.len(), n); + set +} + +fn stagger(n1: usize, factor: usize) -> [BTreeSet; 2] { + let n2 = n1 * factor; + let mut sets = [BTreeSet::new(), BTreeSet::new()]; + for i in 0..(n1 + n2) { + let b = i % (factor + 1) != 0; + sets[b as usize].insert(i as u32); + } + assert_eq!(sets[0].len(), n1); + assert_eq!(sets[1].len(), n2); + sets +} + +macro_rules! set_bench { + ($name: ident, $set_func: ident, $result_func: ident, $sets: expr) => { + #[bench] + pub fn $name(b: &mut Bencher) { + // setup + let sets = $sets; + + // measure + b.iter(|| sets[0].$set_func(&sets[1]).$result_func()) + } + }; +} + +fn slim_set(n: usize) -> BTreeSet { + (0..n).collect::>() +} + +#[bench] +pub fn clone_100(b: &mut Bencher) { + let src = slim_set(100); + b.iter(|| src.clone()) +} + +#[bench] +pub fn clone_100_and_clear(b: &mut Bencher) { + let src = slim_set(100); + b.iter(|| src.clone().clear()) +} + +#[bench] +pub fn clone_100_and_drain_all(b: &mut Bencher) { + let src = slim_set(100); + b.iter(|| src.clone().extract_if(|_| true).count()) +} + +#[bench] +pub fn clone_100_and_drain_half(b: &mut Bencher) { + let src = slim_set(100); + b.iter(|| { + let mut set = src.clone(); + assert_eq!(set.extract_if(|i| i % 2 == 0).count(), 100 / 2); + assert_eq!(set.len(), 100 / 2); + }) +} + +#[bench] +pub fn clone_100_and_into_iter(b: &mut Bencher) { + let src = slim_set(100); + b.iter(|| src.clone().into_iter().count()) +} + +#[bench] +pub fn clone_100_and_pop_all(b: &mut Bencher) { + let src = slim_set(100); + b.iter(|| { + let mut set = src.clone(); + while set.pop_first().is_some() {} + set + }); +} + +#[bench] +pub fn clone_100_and_remove_all(b: &mut Bencher) { + let src = slim_set(100); + b.iter(|| { + let mut set = src.clone(); + while let Some(elt) = set.iter().copied().next() { + let ok = set.remove(&elt); + debug_assert!(ok); + } + set + }); +} + +#[bench] +pub fn clone_100_and_remove_half(b: &mut Bencher) { + let src = slim_set(100); + b.iter(|| { + let mut set = src.clone(); + for i in (0..100).step_by(2) { + let ok = set.remove(&i); + debug_assert!(ok); + } + assert_eq!(set.len(), 100 / 2); + set + }) +} + +#[bench] +pub fn clone_10k(b: &mut Bencher) { + let src = slim_set(10_000); + b.iter(|| src.clone()) +} + +#[bench] +pub fn clone_10k_and_clear(b: &mut Bencher) { + let src = slim_set(10_000); + b.iter(|| src.clone().clear()) +} + +#[bench] +pub fn clone_10k_and_drain_all(b: &mut Bencher) { + let src = slim_set(10_000); + b.iter(|| src.clone().extract_if(|_| true).count()) +} + +#[bench] +pub fn clone_10k_and_drain_half(b: &mut Bencher) { + let src = slim_set(10_000); + b.iter(|| { + let mut set = src.clone(); + assert_eq!(set.extract_if(|i| i % 2 == 0).count(), 10_000 / 2); + assert_eq!(set.len(), 10_000 / 2); + }) +} + +#[bench] +pub fn clone_10k_and_into_iter(b: &mut Bencher) { + let src = slim_set(10_000); + b.iter(|| src.clone().into_iter().count()) +} + +#[bench] +pub fn clone_10k_and_pop_all(b: &mut Bencher) { + let src = slim_set(10_000); + b.iter(|| { + let mut set = src.clone(); + while set.pop_first().is_some() {} + set + }); +} + +#[bench] +pub fn clone_10k_and_remove_all(b: &mut Bencher) { + let src = slim_set(10_000); + b.iter(|| { + let mut set = src.clone(); + while let Some(elt) = set.iter().copied().next() { + let ok = set.remove(&elt); + debug_assert!(ok); + } + set + }); +} + +#[bench] +pub fn clone_10k_and_remove_half(b: &mut Bencher) { + let src = slim_set(10_000); + b.iter(|| { + let mut set = src.clone(); + for i in (0..10_000).step_by(2) { + let ok = set.remove(&i); + debug_assert!(ok); + } + assert_eq!(set.len(), 10_000 / 2); + set + }) +} + +set_bench! {intersection_100_neg_vs_100_pos, intersection, count, [neg(100), pos(100)]} +set_bench! {intersection_100_neg_vs_10k_pos, intersection, count, [neg(100), pos(10_000)]} +set_bench! {intersection_100_pos_vs_100_neg, intersection, count, [pos(100), neg(100)]} +set_bench! {intersection_100_pos_vs_10k_neg, intersection, count, [pos(100), neg(10_000)]} +set_bench! {intersection_10k_neg_vs_100_pos, intersection, count, [neg(10_000), pos(100)]} +set_bench! {intersection_10k_neg_vs_10k_pos, intersection, count, [neg(10_000), pos(10_000)]} +set_bench! {intersection_10k_pos_vs_100_neg, intersection, count, [pos(10_000), neg(100)]} +set_bench! {intersection_10k_pos_vs_10k_neg, intersection, count, [pos(10_000), neg(10_000)]} +set_bench! {intersection_random_100_vs_100, intersection, count, [random(100), random(100)]} +set_bench! {intersection_random_100_vs_10k, intersection, count, [random(100), random(10_000)]} +set_bench! {intersection_random_10k_vs_100, intersection, count, [random(10_000), random(100)]} +set_bench! {intersection_random_10k_vs_10k, intersection, count, [random(10_000), random(10_000)]} +set_bench! {intersection_staggered_100_vs_100, intersection, count, stagger(100, 1)} +set_bench! {intersection_staggered_10k_vs_10k, intersection, count, stagger(10_000, 1)} +set_bench! {intersection_staggered_100_vs_10k, intersection, count, stagger(100, 100)} +set_bench! {difference_random_100_vs_100, difference, count, [random(100), random(100)]} +set_bench! {difference_random_100_vs_10k, difference, count, [random(100), random(10_000)]} +set_bench! {difference_random_10k_vs_100, difference, count, [random(10_000), random(100)]} +set_bench! {difference_random_10k_vs_10k, difference, count, [random(10_000), random(10_000)]} +set_bench! {difference_staggered_100_vs_100, difference, count, stagger(100, 1)} +set_bench! {difference_staggered_10k_vs_10k, difference, count, stagger(10_000, 1)} +set_bench! {difference_staggered_100_vs_10k, difference, count, stagger(100, 100)} +set_bench! {is_subset_100_vs_100, is_subset, clone, [pos(100), pos(100)]} +set_bench! {is_subset_100_vs_10k, is_subset, clone, [pos(100), pos(10_000)]} +set_bench! {is_subset_10k_vs_100, is_subset, clone, [pos(10_000), pos(100)]} +set_bench! {is_subset_10k_vs_10k, is_subset, clone, [pos(10_000), pos(10_000)]} diff --git a/library/alloctests/benches/lib.rs b/library/alloctests/benches/lib.rs new file mode 100644 index 00000000000..2633154318c --- /dev/null +++ b/library/alloctests/benches/lib.rs @@ -0,0 +1,28 @@ +// Disabling in Miri as these would take too long. +#![cfg(not(miri))] +#![feature(btree_extract_if)] +#![feature(iter_next_chunk)] +#![feature(repr_simd)] +#![feature(slice_partition_dedup)] +#![feature(strict_provenance_lints)] +#![feature(test)] +#![deny(fuzzy_provenance_casts)] + +extern crate test; + +mod binary_heap; +mod btree; +mod linked_list; +mod slice; +mod str; +mod string; +mod vec; +mod vec_deque; + +/// Returns a `rand::Rng` seeded with a consistent seed. +/// +/// This is done to avoid introducing nondeterminism in benchmark results. +fn bench_rng() -> rand_xorshift::XorShiftRng { + const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + rand::SeedableRng::from_seed(SEED) +} diff --git a/library/alloctests/benches/linked_list.rs b/library/alloctests/benches/linked_list.rs new file mode 100644 index 00000000000..b9322b6d4c3 --- /dev/null +++ b/library/alloctests/benches/linked_list.rs @@ -0,0 +1,78 @@ +use std::collections::LinkedList; + +use test::Bencher; + +#[bench] +fn bench_collect_into(b: &mut Bencher) { + let v = &[0; 64]; + b.iter(|| { + let _: LinkedList<_> = v.iter().cloned().collect(); + }) +} + +#[bench] +fn bench_push_front(b: &mut Bencher) { + let mut m: LinkedList<_> = LinkedList::new(); + b.iter(|| { + m.push_front(0); + }) +} + +#[bench] +fn bench_push_back(b: &mut Bencher) { + let mut m: LinkedList<_> = LinkedList::new(); + b.iter(|| { + m.push_back(0); + }) +} + +#[bench] +fn bench_push_back_pop_back(b: &mut Bencher) { + let mut m: LinkedList<_> = LinkedList::new(); + b.iter(|| { + m.push_back(0); + m.pop_back(); + }) +} + +#[bench] +fn bench_push_front_pop_front(b: &mut Bencher) { + let mut m: LinkedList<_> = LinkedList::new(); + b.iter(|| { + m.push_front(0); + m.pop_front(); + }) +} + +#[bench] +fn bench_iter(b: &mut Bencher) { + let v = &[0; 128]; + let m: LinkedList<_> = v.iter().cloned().collect(); + b.iter(|| { + assert!(m.iter().count() == 128); + }) +} +#[bench] +fn bench_iter_mut(b: &mut Bencher) { + let v = &[0; 128]; + let mut m: LinkedList<_> = v.iter().cloned().collect(); + b.iter(|| { + assert!(m.iter_mut().count() == 128); + }) +} +#[bench] +fn bench_iter_rev(b: &mut Bencher) { + let v = &[0; 128]; + let m: LinkedList<_> = v.iter().cloned().collect(); + b.iter(|| { + assert!(m.iter().rev().count() == 128); + }) +} +#[bench] +fn bench_iter_mut_rev(b: &mut Bencher) { + let v = &[0; 128]; + let mut m: LinkedList<_> = v.iter().cloned().collect(); + b.iter(|| { + assert!(m.iter_mut().rev().count() == 128); + }) +} diff --git a/library/alloctests/benches/slice.rs b/library/alloctests/benches/slice.rs new file mode 100644 index 00000000000..27b0e6fac0a --- /dev/null +++ b/library/alloctests/benches/slice.rs @@ -0,0 +1,390 @@ +use std::ptr; + +use rand::Rng; +use rand::distr::{Alphanumeric, SampleString, StandardUniform}; +use test::{Bencher, black_box}; + +#[bench] +fn iterator(b: &mut Bencher) { + // peculiar numbers to stop LLVM from optimising the summation + // out. + let v: Vec<_> = (0..100).map(|i| i ^ (i << 1) ^ (i >> 1)).collect(); + + b.iter(|| { + let mut sum = 0; + for x in &v { + sum += *x; + } + // sum == 11806, to stop dead code elimination. + if sum == 0 { + panic!() + } + }) +} + +#[bench] +fn mut_iterator(b: &mut Bencher) { + let mut v = vec![0; 100]; + + b.iter(|| { + let mut i = 0; + for x in &mut v { + *x = i; + i += 1; + } + }) +} + +#[bench] +fn concat(b: &mut Bencher) { + let xss: Vec> = (0..100).map(|i| (0..i).collect()).collect(); + b.iter(|| { + xss.concat(); + }); +} + +#[bench] +fn join(b: &mut Bencher) { + let xss: Vec> = (0..100).map(|i| (0..i).collect()).collect(); + b.iter(|| xss.join(&0)); +} + +#[bench] +fn push(b: &mut Bencher) { + let mut vec = Vec::::new(); + b.iter(|| { + vec.push(0); + black_box(&vec); + }); +} + +#[bench] +fn starts_with_same_vector(b: &mut Bencher) { + let vec: Vec<_> = (0..100).collect(); + b.iter(|| vec.starts_with(&vec)) +} + +#[bench] +fn starts_with_single_element(b: &mut Bencher) { + let vec: Vec<_> = vec![0]; + b.iter(|| vec.starts_with(&vec)) +} + +#[bench] +fn starts_with_diff_one_element_at_end(b: &mut Bencher) { + let vec: Vec<_> = (0..100).collect(); + let mut match_vec: Vec<_> = (0..99).collect(); + match_vec.push(0); + b.iter(|| vec.starts_with(&match_vec)) +} + +#[bench] +fn ends_with_same_vector(b: &mut Bencher) { + let vec: Vec<_> = (0..100).collect(); + b.iter(|| vec.ends_with(&vec)) +} + +#[bench] +fn ends_with_single_element(b: &mut Bencher) { + let vec: Vec<_> = vec![0]; + b.iter(|| vec.ends_with(&vec)) +} + +#[bench] +fn ends_with_diff_one_element_at_beginning(b: &mut Bencher) { + let vec: Vec<_> = (0..100).collect(); + let mut match_vec: Vec<_> = (0..100).collect(); + match_vec[0] = 200; + b.iter(|| vec.starts_with(&match_vec)) +} + +#[bench] +fn contains_last_element(b: &mut Bencher) { + let vec: Vec<_> = (0..100).collect(); + b.iter(|| vec.contains(&99)) +} + +#[bench] +fn zero_1kb_from_elem(b: &mut Bencher) { + b.iter(|| vec![0u8; 1024]); +} + +#[bench] +fn zero_1kb_set_memory(b: &mut Bencher) { + b.iter(|| { + let mut v = Vec::::with_capacity(1024); + unsafe { + let vp = v.as_mut_ptr(); + ptr::write_bytes(vp, 0, 1024); + v.set_len(1024); + } + v + }); +} + +#[bench] +fn zero_1kb_loop_set(b: &mut Bencher) { + b.iter(|| { + let mut v = Vec::::with_capacity(1024); + unsafe { + v.set_len(1024); + } + for i in 0..1024 { + v[i] = 0; + } + }); +} + +#[bench] +fn zero_1kb_mut_iter(b: &mut Bencher) { + b.iter(|| { + let mut v = Vec::::with_capacity(1024); + unsafe { + v.set_len(1024); + } + for x in &mut v { + *x = 0; + } + v + }); +} + +#[bench] +fn random_inserts(b: &mut Bencher) { + let mut rng = crate::bench_rng(); + b.iter(|| { + let mut v = vec![(0, 0); 30]; + for _ in 0..100 { + let l = v.len(); + v.insert(rng.random::() as usize % (l + 1), (1, 1)); + } + }) +} + +#[bench] +fn random_removes(b: &mut Bencher) { + let mut rng = crate::bench_rng(); + b.iter(|| { + let mut v = vec![(0, 0); 130]; + for _ in 0..100 { + let l = v.len(); + v.remove(rng.random::() as usize % l); + } + }) +} + +fn gen_ascending(len: usize) -> Vec { + (0..len as u64).collect() +} + +fn gen_descending(len: usize) -> Vec { + (0..len as u64).rev().collect() +} + +fn gen_random(len: usize) -> Vec { + let mut rng = crate::bench_rng(); + (&mut rng).sample_iter(&StandardUniform).take(len).collect() +} + +fn gen_random_bytes(len: usize) -> Vec { + let mut rng = crate::bench_rng(); + (&mut rng).sample_iter(&StandardUniform).take(len).collect() +} + +fn gen_mostly_ascending(len: usize) -> Vec { + let mut rng = crate::bench_rng(); + let mut v = gen_ascending(len); + for _ in (0usize..).take_while(|x| x * x <= len) { + let x = rng.random::() as usize % len; + let y = rng.random::() as usize % len; + v.swap(x, y); + } + v +} + +fn gen_mostly_descending(len: usize) -> Vec { + let mut rng = crate::bench_rng(); + let mut v = gen_descending(len); + for _ in (0usize..).take_while(|x| x * x <= len) { + let x = rng.random::() as usize % len; + let y = rng.random::() as usize % len; + v.swap(x, y); + } + v +} + +fn gen_strings(len: usize) -> Vec { + let mut rng = crate::bench_rng(); + let mut v = vec![]; + for _ in 0..len { + let n = rng.random::() % 20 + 1; + v.push(Alphanumeric.sample_string(&mut rng, n as usize)); + } + v +} + +fn gen_big_random(len: usize) -> Vec<[u64; 16]> { + let mut rng = crate::bench_rng(); + (&mut rng).sample_iter(&StandardUniform).map(|x| [x; 16]).take(len).collect() +} + +macro_rules! sort { + ($f:ident, $name:ident, $gen:expr, $len:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let v = $gen($len); + b.iter(|| v.clone().$f()); + b.bytes = $len * size_of_val(&$gen(1)[0]) as u64; + } + }; +} + +macro_rules! sort_strings { + ($f:ident, $name:ident, $gen:expr, $len:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let v = $gen($len); + let v = v.iter().map(|s| &**s).collect::>(); + b.iter(|| v.clone().$f()); + b.bytes = $len * size_of::<&str>() as u64; + } + }; +} + +macro_rules! sort_expensive { + ($f:ident, $name:ident, $gen:expr, $len:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let v = $gen($len); + b.iter(|| { + let mut v = v.clone(); + let mut count = 0; + v.$f(|a: &u64, b: &u64| { + count += 1; + if count % 1_000_000_000 == 0 { + panic!("should not happen"); + } + (*a as f64).cos().partial_cmp(&(*b as f64).cos()).unwrap() + }); + black_box(count); + }); + b.bytes = $len * size_of_val(&$gen(1)[0]) as u64; + } + }; +} + +macro_rules! sort_lexicographic { + ($f:ident, $name:ident, $gen:expr, $len:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let v = $gen($len); + b.iter(|| v.clone().$f(|x| x.to_string())); + b.bytes = $len * size_of_val(&$gen(1)[0]) as u64; + } + }; +} + +sort!(sort, sort_small_ascending, gen_ascending, 10); +sort!(sort, sort_small_descending, gen_descending, 10); +sort!(sort, sort_small_random, gen_random, 10); +sort!(sort, sort_small_big, gen_big_random, 10); +sort!(sort, sort_medium_random, gen_random, 100); +sort!(sort, sort_large_ascending, gen_ascending, 10000); +sort!(sort, sort_large_descending, gen_descending, 10000); +sort!(sort, sort_large_mostly_ascending, gen_mostly_ascending, 10000); +sort!(sort, sort_large_mostly_descending, gen_mostly_descending, 10000); +sort!(sort, sort_large_random, gen_random, 10000); +sort!(sort, sort_large_big, gen_big_random, 10000); +sort_strings!(sort, sort_large_strings, gen_strings, 10000); +sort_expensive!(sort_by, sort_large_expensive, gen_random, 10000); + +sort!(sort_unstable, sort_unstable_small_ascending, gen_ascending, 10); +sort!(sort_unstable, sort_unstable_small_descending, gen_descending, 10); +sort!(sort_unstable, sort_unstable_small_random, gen_random, 10); +sort!(sort_unstable, sort_unstable_small_big, gen_big_random, 10); +sort!(sort_unstable, sort_unstable_medium_random, gen_random, 100); +sort!(sort_unstable, sort_unstable_large_ascending, gen_ascending, 10000); +sort!(sort_unstable, sort_unstable_large_descending, gen_descending, 10000); +sort!(sort_unstable, sort_unstable_large_mostly_ascending, gen_mostly_ascending, 10000); +sort!(sort_unstable, sort_unstable_large_mostly_descending, gen_mostly_descending, 10000); +sort!(sort_unstable, sort_unstable_large_random, gen_random, 10000); +sort!(sort_unstable, sort_unstable_large_big, gen_big_random, 10000); +sort_strings!(sort_unstable, sort_unstable_large_strings, gen_strings, 10000); +sort_expensive!(sort_unstable_by, sort_unstable_large_expensive, gen_random, 10000); + +sort_lexicographic!(sort_by_key, sort_by_key_lexicographic, gen_random, 10000); +sort_lexicographic!(sort_unstable_by_key, sort_unstable_by_key_lexicographic, gen_random, 10000); +sort_lexicographic!(sort_by_cached_key, sort_by_cached_key_lexicographic, gen_random, 10000); + +macro_rules! reverse { + ($name:ident, $ty:ty, $f:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + // odd length and offset by 1 to be as unaligned as possible + let n = 0xFFFFF; + let mut v: Vec<_> = (0..1 + (n / size_of::<$ty>() as u64)).map($f).collect(); + b.iter(|| black_box(&mut v[1..]).reverse()); + b.bytes = n; + } + }; +} + +reverse!(reverse_u8, u8, |x| x as u8); +reverse!(reverse_u16, u16, |x| x as u16); +reverse!(reverse_u8x3, [u8; 3], |x| [x as u8, (x >> 8) as u8, (x >> 16) as u8]); +reverse!(reverse_u32, u32, |x| x as u32); +reverse!(reverse_u64, u64, |x| x as u64); +reverse!(reverse_u128, u128, |x| x as u128); +#[repr(simd)] +struct F64x4([f64; 4]); +reverse!(reverse_simd_f64x4, F64x4, |x| { + let x = x as f64; + F64x4([x, x, x, x]) +}); + +macro_rules! rotate { + ($name:ident, $gen:expr, $len:expr, $mid:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let size = size_of_val(&$gen(1)[0]); + let mut v = $gen($len * 8 / size); + b.iter(|| black_box(&mut v).rotate_left(($mid * 8 + size - 1) / size)); + b.bytes = (v.len() * size) as u64; + } + }; +} + +rotate!(rotate_tiny_by1, gen_random, 16, 1); +rotate!(rotate_tiny_half, gen_random, 16, 16 / 2); +rotate!(rotate_tiny_half_plus_one, gen_random, 16, 16 / 2 + 1); + +rotate!(rotate_medium_by1, gen_random, 9158, 1); +rotate!(rotate_medium_by727_u64, gen_random, 9158, 727); +rotate!(rotate_medium_by727_bytes, gen_random_bytes, 9158, 727); +rotate!(rotate_medium_by727_strings, gen_strings, 9158, 727); +rotate!(rotate_medium_half, gen_random, 9158, 9158 / 2); +rotate!(rotate_medium_half_plus_one, gen_random, 9158, 9158 / 2 + 1); + +// Intended to use more RAM than the machine has cache +#[cfg(not(target_os = "emscripten"))] // hits an OOM +rotate!(rotate_huge_by1, gen_random, 5 * 1024 * 1024, 1); +#[cfg(not(target_os = "emscripten"))] // hits an OOM +rotate!(rotate_huge_by9199_u64, gen_random, 5 * 1024 * 1024, 9199); +#[cfg(not(target_os = "emscripten"))] // hits an OOM +rotate!(rotate_huge_by9199_bytes, gen_random_bytes, 5 * 1024 * 1024, 9199); +#[cfg(not(target_os = "emscripten"))] // hits an OOM +rotate!(rotate_huge_by9199_strings, gen_strings, 5 * 1024 * 1024, 9199); +#[cfg(not(target_os = "emscripten"))] // hits an OOM +rotate!(rotate_huge_by9199_big, gen_big_random, 5 * 1024 * 1024, 9199); +#[cfg(not(target_os = "emscripten"))] // hits an OOM +rotate!(rotate_huge_by1234577_u64, gen_random, 5 * 1024 * 1024, 1234577); +#[cfg(not(target_os = "emscripten"))] // hits an OOM +rotate!(rotate_huge_by1234577_bytes, gen_random_bytes, 5 * 1024 * 1024, 1234577); +#[cfg(not(target_os = "emscripten"))] // hits an OOM +rotate!(rotate_huge_by1234577_strings, gen_strings, 5 * 1024 * 1024, 1234577); +#[cfg(not(target_os = "emscripten"))] // hits an OOM +rotate!(rotate_huge_by1234577_big, gen_big_random, 5 * 1024 * 1024, 1234577); +#[cfg(not(target_os = "emscripten"))] // hits an OOM +rotate!(rotate_huge_half, gen_random, 5 * 1024 * 1024, 5 * 1024 * 1024 / 2); +#[cfg(not(target_os = "emscripten"))] // hits an OOM +rotate!(rotate_huge_half_plus_one, gen_random, 5 * 1024 * 1024, 5 * 1024 * 1024 / 2 + 1); diff --git a/library/alloctests/benches/str.rs b/library/alloctests/benches/str.rs new file mode 100644 index 00000000000..98c7c5413ca --- /dev/null +++ b/library/alloctests/benches/str.rs @@ -0,0 +1,351 @@ +use test::{Bencher, black_box}; + +#[bench] +fn char_iterator(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + + b.iter(|| s.chars().count()); +} + +#[bench] +fn char_iterator_for(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + + b.iter(|| { + for ch in s.chars() { + black_box(ch); + } + }); +} + +#[bench] +fn char_iterator_ascii(b: &mut Bencher) { + let s = "Mary had a little lamb, Little lamb + Mary had a little lamb, Little lamb + Mary had a little lamb, Little lamb + Mary had a little lamb, Little lamb + Mary had a little lamb, Little lamb + Mary had a little lamb, Little lamb"; + + b.iter(|| s.chars().count()); +} + +#[bench] +fn char_iterator_rev(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + + b.iter(|| s.chars().rev().count()); +} + +#[bench] +fn char_iterator_rev_for(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + + b.iter(|| { + for ch in s.chars().rev() { + black_box(ch); + } + }); +} + +#[bench] +fn char_indicesator(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + let len = s.chars().count(); + + b.iter(|| assert_eq!(s.char_indices().count(), len)); +} + +#[bench] +fn char_indicesator_rev(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + let len = s.chars().count(); + + b.iter(|| assert_eq!(s.char_indices().rev().count(), len)); +} + +#[bench] +fn split_unicode_ascii(b: &mut Bencher) { + let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam"; + + b.iter(|| assert_eq!(s.split('V').count(), 3)); +} + +#[bench] +fn split_ascii(b: &mut Bencher) { + let s = "Mary had a little lamb, Little lamb, little-lamb."; + let len = s.split(' ').count(); + + b.iter(|| assert_eq!(s.split(' ').count(), len)); +} + +#[bench] +fn split_extern_fn(b: &mut Bencher) { + let s = "Mary had a little lamb, Little lamb, little-lamb."; + let len = s.split(' ').count(); + fn pred(c: char) -> bool { + c == ' ' + } + + b.iter(|| assert_eq!(s.split(pred).count(), len)); +} + +#[bench] +fn split_closure(b: &mut Bencher) { + let s = "Mary had a little lamb, Little lamb, little-lamb."; + let len = s.split(' ').count(); + + b.iter(|| assert_eq!(s.split(|c: char| c == ' ').count(), len)); +} + +#[bench] +fn split_slice(b: &mut Bencher) { + let s = "Mary had a little lamb, Little lamb, little-lamb."; + let len = s.split(' ').count(); + + let c: &[char] = &[' ']; + b.iter(|| assert_eq!(s.split(c).count(), len)); +} + +#[bench] +fn bench_join(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + let sep = "→"; + let v = vec![s, s, s, s, s, s, s, s, s, s]; + b.iter(|| { + assert_eq!(v.join(sep).len(), s.len() * 10 + sep.len() * 9); + }) +} + +#[bench] +fn bench_contains_short_short(b: &mut Bencher) { + let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + let needle = "sit"; + + b.bytes = haystack.len() as u64; + b.iter(|| { + assert!(black_box(haystack).contains(black_box(needle))); + }) +} + +static LONG_HAYSTACK: &str = "\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \ +ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \ +eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \ +sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \ +tempus vel, gravida nec quam. + +In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \ +sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \ +diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \ +lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \ +eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \ +interdum. Curabitur ut nisi justo. + +Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \ +mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \ +lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \ +est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \ +felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \ +ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \ +feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \ +Aliquam sit amet placerat lorem. + +Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \ +mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \ +Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \ +lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \ +suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \ +cursus accumsan. + +Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \ +feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \ +vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \ +leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \ +malesuada sollicitudin quam eu fermentum."; + +#[bench] +fn bench_contains_2b_repeated_long(b: &mut Bencher) { + let haystack = LONG_HAYSTACK; + let needle = "::"; + + b.bytes = haystack.len() as u64; + b.iter(|| { + assert!(!black_box(haystack).contains(black_box(needle))); + }) +} + +#[bench] +fn bench_contains_short_long(b: &mut Bencher) { + let haystack = LONG_HAYSTACK; + let needle = "english"; + + b.bytes = haystack.len() as u64; + b.iter(|| { + assert!(!black_box(haystack).contains(black_box(needle))); + }) +} + +#[bench] +fn bench_contains_16b_in_long(b: &mut Bencher) { + let haystack = LONG_HAYSTACK; + let needle = "english language"; + + b.bytes = haystack.len() as u64; + b.iter(|| { + assert!(!black_box(haystack).contains(black_box(needle))); + }) +} + +#[bench] +fn bench_contains_32b_in_long(b: &mut Bencher) { + let haystack = LONG_HAYSTACK; + let needle = "the english language sample text"; + + b.bytes = haystack.len() as u64; + b.iter(|| { + assert!(!black_box(haystack).contains(black_box(needle))); + }) +} + +#[bench] +fn bench_contains_bad_naive(b: &mut Bencher) { + let haystack = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + let needle = "aaaaaaaab"; + + b.bytes = haystack.len() as u64; + b.iter(|| { + assert!(!black_box(haystack).contains(black_box(needle))); + }) +} + +#[bench] +fn bench_contains_bad_simd(b: &mut Bencher) { + let haystack = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + let needle = "aaabaaaa"; + + b.bytes = haystack.len() as u64; + b.iter(|| { + assert!(!black_box(haystack).contains(black_box(needle))); + }) +} + +#[bench] +fn bench_contains_equal(b: &mut Bencher) { + let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + let needle = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + + b.bytes = haystack.len() as u64; + b.iter(|| { + assert!(black_box(haystack).contains(black_box(needle))); + }) +} + +macro_rules! make_test_inner { + ($s:ident, $code:expr, $name:ident, $str:expr, $iters:expr) => { + #[bench] + fn $name(bencher: &mut Bencher) { + let mut $s = $str; + black_box(&mut $s); + bencher.iter(|| { + for _ in 0..$iters { + black_box($code); + } + }); + } + }; +} + +macro_rules! make_test { + ($name:ident, $s:ident, $code:expr) => { + make_test!($name, $s, $code, 1); + }; + ($name:ident, $s:ident, $code:expr, $iters:expr) => { + mod $name { + use test::Bencher; + use test::black_box; + + // Short strings: 65 bytes each + make_test_inner!($s, $code, short_ascii, + "Mary had a little lamb, Little lamb Mary had a littl lamb, lamb!", $iters); + make_test_inner!($s, $code, short_mixed, + "ศไทย中华Việt Nam; Mary had a little lamb, Little lam!", $iters); + make_test_inner!($s, $code, short_pile_of_poo, + "💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩!", $iters); + make_test_inner!($s, $code, long_lorem_ipsum,"\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \ +ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \ +eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \ +sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \ +tempus vel, gravida nec quam. + +In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \ +sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \ +diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \ +lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \ +eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \ +interdum. Curabitur ut nisi justo. + +Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \ +mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \ +lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \ +est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \ +felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \ +ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \ +feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \ +Aliquam sit amet placerat lorem. + +Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \ +mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \ +Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \ +lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \ +suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \ +cursus accumsan. + +Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \ +feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \ +vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \ +leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \ +malesuada sollicitudin quam eu fermentum!", $iters); + } + } +} + +make_test!(chars_count, s, s.chars().count()); + +make_test!(contains_bang_str, s, s.contains("!")); +make_test!(contains_bang_char, s, s.contains('!')); + +make_test!(match_indices_a_str, s, s.match_indices("a").count()); + +make_test!(split_a_str, s, s.split("a").count()); + +make_test!(trim_ascii_char, s, { s.trim_matches(|c: char| c.is_ascii()) }); +make_test!(trim_start_ascii_char, s, { s.trim_start_matches(|c: char| c.is_ascii()) }); +make_test!(trim_end_ascii_char, s, { s.trim_end_matches(|c: char| c.is_ascii()) }); + +make_test!(find_underscore_char, s, s.find('_')); +make_test!(rfind_underscore_char, s, s.rfind('_')); +make_test!(find_underscore_str, s, s.find("_")); + +make_test!(find_zzz_char, s, s.find('\u{1F4A4}')); +make_test!(rfind_zzz_char, s, s.rfind('\u{1F4A4}')); +make_test!(find_zzz_str, s, s.find("\u{1F4A4}")); + +make_test!(starts_with_ascii_char, s, s.starts_with('/'), 1024); +make_test!(ends_with_ascii_char, s, s.ends_with('/'), 1024); +make_test!(starts_with_unichar, s, s.starts_with('\u{1F4A4}'), 1024); +make_test!(ends_with_unichar, s, s.ends_with('\u{1F4A4}'), 1024); +make_test!(starts_with_str, s, s.starts_with("💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩"), 1024); +make_test!(ends_with_str, s, s.ends_with("💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩"), 1024); + +make_test!(split_space_char, s, s.split(' ').count()); +make_test!(split_terminator_space_char, s, s.split_terminator(' ').count()); + +make_test!(splitn_space_char, s, s.splitn(10, ' ').count()); +make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count()); + +make_test!(split_space_str, s, s.split(" ").count()); +make_test!(split_ad_str, s, s.split("ad").count()); + +make_test!(to_lowercase, s, s.to_lowercase()); diff --git a/library/alloctests/benches/string.rs b/library/alloctests/benches/string.rs new file mode 100644 index 00000000000..3d79ab78c69 --- /dev/null +++ b/library/alloctests/benches/string.rs @@ -0,0 +1,165 @@ +use std::iter::repeat; + +use test::{Bencher, black_box}; + +#[bench] +fn bench_with_capacity(b: &mut Bencher) { + b.iter(|| String::with_capacity(100)); +} + +#[bench] +fn bench_push_str(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + b.iter(|| { + let mut r = String::new(); + r.push_str(s); + }); +} + +const REPETITIONS: u64 = 10_000; + +#[bench] +fn bench_push_str_one_byte(b: &mut Bencher) { + b.bytes = REPETITIONS; + b.iter(|| { + let mut r = String::new(); + for _ in 0..REPETITIONS { + r.push_str("a") + } + }); +} + +#[bench] +fn bench_push_char_one_byte(b: &mut Bencher) { + b.bytes = REPETITIONS; + b.iter(|| { + let mut r = String::new(); + for _ in 0..REPETITIONS { + r.push('a') + } + }); +} + +#[bench] +fn bench_push_char_two_bytes(b: &mut Bencher) { + b.bytes = REPETITIONS * 2; + b.iter(|| { + let mut r = String::new(); + for _ in 0..REPETITIONS { + r.push('â') + } + }); +} + +#[bench] +fn from_utf8_lossy_100_ascii(b: &mut Bencher) { + let s = b"Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; + + assert_eq!(100, s.len()); + b.iter(|| { + let _ = String::from_utf8_lossy(s); + }); +} + +#[bench] +fn from_utf8_lossy_100_multibyte(b: &mut Bencher) { + let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes(); + assert_eq!(100, s.len()); + b.iter(|| { + let _ = String::from_utf8_lossy(s); + }); +} + +#[bench] +fn from_utf8_lossy_invalid(b: &mut Bencher) { + let s = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; + b.iter(|| { + let _ = String::from_utf8_lossy(s); + }); +} + +#[bench] +fn from_utf8_lossy_100_invalid(b: &mut Bencher) { + let s = repeat(0xf5).take(100).collect::>(); + b.iter(|| { + let _ = String::from_utf8_lossy(&s); + }); +} + +#[bench] +fn bench_exact_size_shrink_to_fit(b: &mut Bencher) { + let s = "Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; + // ensure our operation produces an exact-size string before we benchmark it + let mut r = String::with_capacity(s.len()); + r.push_str(s); + assert_eq!(r.len(), r.capacity()); + b.iter(|| { + let mut r = String::with_capacity(s.len()); + r.push_str(s); + r.shrink_to_fit(); + r + }); +} + +#[bench] +fn bench_from_str(b: &mut Bencher) { + let s = "Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; + b.iter(|| String::from(s)) +} + +#[bench] +fn bench_from(b: &mut Bencher) { + let s = "Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; + b.iter(|| String::from(s)) +} + +#[bench] +fn bench_to_string(b: &mut Bencher) { + let s = "Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; + b.iter(|| s.to_string()) +} + +#[bench] +fn bench_insert_char_short(b: &mut Bencher) { + let s = "Hello, World!"; + b.iter(|| { + let mut x = String::from(s); + black_box(&mut x).insert(6, black_box(' ')); + x + }) +} + +#[bench] +fn bench_insert_char_long(b: &mut Bencher) { + let s = "Hello, World!"; + b.iter(|| { + let mut x = String::from(s); + black_box(&mut x).insert(6, black_box('❤')); + x + }) +} + +#[bench] +fn bench_insert_str_short(b: &mut Bencher) { + let s = "Hello, World!"; + b.iter(|| { + let mut x = String::from(s); + black_box(&mut x).insert_str(6, black_box(" ")); + x + }) +} + +#[bench] +fn bench_insert_str_long(b: &mut Bencher) { + let s = "Hello, World!"; + b.iter(|| { + let mut x = String::from(s); + black_box(&mut x).insert_str(6, black_box(" rustic ")); + x + }) +} diff --git a/library/alloctests/benches/vec.rs b/library/alloctests/benches/vec.rs new file mode 100644 index 00000000000..1dab71fa1f4 --- /dev/null +++ b/library/alloctests/benches/vec.rs @@ -0,0 +1,878 @@ +use std::iter::repeat; + +use rand::RngCore; +use test::{Bencher, black_box}; + +#[bench] +fn bench_new(b: &mut Bencher) { + b.iter(|| Vec::::new()) +} + +fn do_bench_with_capacity(b: &mut Bencher, src_len: usize) { + b.bytes = src_len as u64; + + b.iter(|| Vec::::with_capacity(src_len)) +} + +#[bench] +fn bench_with_capacity_0000(b: &mut Bencher) { + do_bench_with_capacity(b, 0) +} + +#[bench] +fn bench_with_capacity_0010(b: &mut Bencher) { + do_bench_with_capacity(b, 10) +} + +#[bench] +fn bench_with_capacity_0100(b: &mut Bencher) { + do_bench_with_capacity(b, 100) +} + +#[bench] +fn bench_with_capacity_1000(b: &mut Bencher) { + do_bench_with_capacity(b, 1000) +} + +fn do_bench_from_fn(b: &mut Bencher, src_len: usize) { + b.bytes = src_len as u64; + + b.iter(|| (0..src_len).collect::>()) +} + +#[bench] +fn bench_from_fn_0000(b: &mut Bencher) { + do_bench_from_fn(b, 0) +} + +#[bench] +fn bench_from_fn_0010(b: &mut Bencher) { + do_bench_from_fn(b, 10) +} + +#[bench] +fn bench_from_fn_0100(b: &mut Bencher) { + do_bench_from_fn(b, 100) +} + +#[bench] +fn bench_from_fn_1000(b: &mut Bencher) { + do_bench_from_fn(b, 1000) +} + +fn do_bench_from_elem(b: &mut Bencher, src_len: usize) { + b.bytes = src_len as u64; + + b.iter(|| repeat(5).take(src_len).collect::>()) +} + +#[bench] +fn bench_from_elem_0000(b: &mut Bencher) { + do_bench_from_elem(b, 0) +} + +#[bench] +fn bench_from_elem_0010(b: &mut Bencher) { + do_bench_from_elem(b, 10) +} + +#[bench] +fn bench_from_elem_0100(b: &mut Bencher) { + do_bench_from_elem(b, 100) +} + +#[bench] +fn bench_from_elem_1000(b: &mut Bencher) { + do_bench_from_elem(b, 1000) +} + +fn do_bench_from_slice(b: &mut Bencher, src_len: usize) { + let src: Vec<_> = FromIterator::from_iter(0..src_len); + + b.bytes = src_len as u64; + + b.iter(|| src.as_slice().to_vec()); +} + +#[bench] +fn bench_from_slice_0000(b: &mut Bencher) { + do_bench_from_slice(b, 0) +} + +#[bench] +fn bench_from_slice_0010(b: &mut Bencher) { + do_bench_from_slice(b, 10) +} + +#[bench] +fn bench_from_slice_0100(b: &mut Bencher) { + do_bench_from_slice(b, 100) +} + +#[bench] +fn bench_from_slice_1000(b: &mut Bencher) { + do_bench_from_slice(b, 1000) +} + +fn do_bench_from_iter(b: &mut Bencher, src_len: usize) { + let src: Vec<_> = FromIterator::from_iter(0..src_len); + + b.bytes = src_len as u64; + + b.iter(|| { + let dst: Vec<_> = FromIterator::from_iter(src.iter().cloned()); + dst + }); +} + +#[bench] +fn bench_from_iter_0000(b: &mut Bencher) { + do_bench_from_iter(b, 0) +} + +#[bench] +fn bench_from_iter_0010(b: &mut Bencher) { + do_bench_from_iter(b, 10) +} + +#[bench] +fn bench_from_iter_0100(b: &mut Bencher) { + do_bench_from_iter(b, 100) +} + +#[bench] +fn bench_from_iter_1000(b: &mut Bencher) { + do_bench_from_iter(b, 1000) +} + +fn do_bench_extend(b: &mut Bencher, dst_len: usize, src_len: usize) { + let dst: Vec<_> = FromIterator::from_iter(0..dst_len); + let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); + + b.bytes = src_len as u64; + + b.iter(|| { + let mut dst = dst.clone(); + dst.extend(src.clone()); + dst + }); +} + +#[bench] +fn bench_extend_0000_0000(b: &mut Bencher) { + do_bench_extend(b, 0, 0) +} + +#[bench] +fn bench_extend_0000_0010(b: &mut Bencher) { + do_bench_extend(b, 0, 10) +} + +#[bench] +fn bench_extend_0000_0100(b: &mut Bencher) { + do_bench_extend(b, 0, 100) +} + +#[bench] +fn bench_extend_0000_1000(b: &mut Bencher) { + do_bench_extend(b, 0, 1000) +} + +#[bench] +fn bench_extend_0010_0010(b: &mut Bencher) { + do_bench_extend(b, 10, 10) +} + +#[bench] +fn bench_extend_0100_0100(b: &mut Bencher) { + do_bench_extend(b, 100, 100) +} + +#[bench] +fn bench_extend_1000_1000(b: &mut Bencher) { + do_bench_extend(b, 1000, 1000) +} + +fn do_bench_extend_from_slice(b: &mut Bencher, dst_len: usize, src_len: usize) { + let dst: Vec<_> = FromIterator::from_iter(0..dst_len); + let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); + + b.bytes = src_len as u64; + + b.iter(|| { + let mut dst = dst.clone(); + dst.extend_from_slice(&src); + dst + }); +} + +#[bench] +fn bench_extend_recycle(b: &mut Bencher) { + let mut data = vec![0; 1000]; + + b.iter(|| { + let tmp = std::mem::take(&mut data); + let mut to_extend = black_box(Vec::new()); + to_extend.extend(tmp.into_iter()); + data = black_box(to_extend); + }); + + black_box(data); +} + +#[bench] +fn bench_extend_from_slice_0000_0000(b: &mut Bencher) { + do_bench_extend_from_slice(b, 0, 0) +} + +#[bench] +fn bench_extend_from_slice_0000_0010(b: &mut Bencher) { + do_bench_extend_from_slice(b, 0, 10) +} + +#[bench] +fn bench_extend_from_slice_0000_0100(b: &mut Bencher) { + do_bench_extend_from_slice(b, 0, 100) +} + +#[bench] +fn bench_extend_from_slice_0000_1000(b: &mut Bencher) { + do_bench_extend_from_slice(b, 0, 1000) +} + +#[bench] +fn bench_extend_from_slice_0010_0010(b: &mut Bencher) { + do_bench_extend_from_slice(b, 10, 10) +} + +#[bench] +fn bench_extend_from_slice_0100_0100(b: &mut Bencher) { + do_bench_extend_from_slice(b, 100, 100) +} + +#[bench] +fn bench_extend_from_slice_1000_1000(b: &mut Bencher) { + do_bench_extend_from_slice(b, 1000, 1000) +} + +fn do_bench_clone(b: &mut Bencher, src_len: usize) { + let src: Vec = FromIterator::from_iter(0..src_len); + + b.bytes = src_len as u64; + + b.iter(|| src.clone()); +} + +#[bench] +fn bench_clone_0000(b: &mut Bencher) { + do_bench_clone(b, 0) +} + +#[bench] +fn bench_clone_0010(b: &mut Bencher) { + do_bench_clone(b, 10) +} + +#[bench] +fn bench_clone_0100(b: &mut Bencher) { + do_bench_clone(b, 100) +} + +#[bench] +fn bench_clone_1000(b: &mut Bencher) { + do_bench_clone(b, 1000) +} + +fn do_bench_clone_from(b: &mut Bencher, times: usize, dst_len: usize, src_len: usize) { + let dst: Vec<_> = FromIterator::from_iter(0..src_len); + let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); + + b.bytes = (times * src_len) as u64; + + b.iter(|| { + let mut dst = dst.clone(); + + for _ in 0..times { + dst.clone_from(&src); + dst = black_box(dst); + } + dst + }); +} + +#[bench] +fn bench_clone_from_01_0000_0000(b: &mut Bencher) { + do_bench_clone_from(b, 1, 0, 0) +} + +#[bench] +fn bench_clone_from_01_0000_0010(b: &mut Bencher) { + do_bench_clone_from(b, 1, 0, 10) +} + +#[bench] +fn bench_clone_from_01_0000_0100(b: &mut Bencher) { + do_bench_clone_from(b, 1, 0, 100) +} + +#[bench] +fn bench_clone_from_01_0000_1000(b: &mut Bencher) { + do_bench_clone_from(b, 1, 0, 1000) +} + +#[bench] +fn bench_clone_from_01_0010_0010(b: &mut Bencher) { + do_bench_clone_from(b, 1, 10, 10) +} + +#[bench] +fn bench_clone_from_01_0100_0100(b: &mut Bencher) { + do_bench_clone_from(b, 1, 100, 100) +} + +#[bench] +fn bench_clone_from_01_1000_1000(b: &mut Bencher) { + do_bench_clone_from(b, 1, 1000, 1000) +} + +#[bench] +fn bench_clone_from_01_0010_0100(b: &mut Bencher) { + do_bench_clone_from(b, 1, 10, 100) +} + +#[bench] +fn bench_clone_from_01_0100_1000(b: &mut Bencher) { + do_bench_clone_from(b, 1, 100, 1000) +} + +#[bench] +fn bench_clone_from_01_0010_0000(b: &mut Bencher) { + do_bench_clone_from(b, 1, 10, 0) +} + +#[bench] +fn bench_clone_from_01_0100_0010(b: &mut Bencher) { + do_bench_clone_from(b, 1, 100, 10) +} + +#[bench] +fn bench_clone_from_01_1000_0100(b: &mut Bencher) { + do_bench_clone_from(b, 1, 1000, 100) +} + +#[bench] +fn bench_clone_from_10_0000_0000(b: &mut Bencher) { + do_bench_clone_from(b, 10, 0, 0) +} + +#[bench] +fn bench_clone_from_10_0000_0010(b: &mut Bencher) { + do_bench_clone_from(b, 10, 0, 10) +} + +#[bench] +fn bench_clone_from_10_0000_0100(b: &mut Bencher) { + do_bench_clone_from(b, 10, 0, 100) +} + +#[bench] +fn bench_clone_from_10_0000_1000(b: &mut Bencher) { + do_bench_clone_from(b, 10, 0, 1000) +} + +#[bench] +fn bench_clone_from_10_0010_0010(b: &mut Bencher) { + do_bench_clone_from(b, 10, 10, 10) +} + +#[bench] +fn bench_clone_from_10_0100_0100(b: &mut Bencher) { + do_bench_clone_from(b, 10, 100, 100) +} + +#[bench] +fn bench_clone_from_10_1000_1000(b: &mut Bencher) { + do_bench_clone_from(b, 10, 1000, 1000) +} + +#[bench] +fn bench_clone_from_10_0010_0100(b: &mut Bencher) { + do_bench_clone_from(b, 10, 10, 100) +} + +#[bench] +fn bench_clone_from_10_0100_1000(b: &mut Bencher) { + do_bench_clone_from(b, 10, 100, 1000) +} + +#[bench] +fn bench_clone_from_10_0010_0000(b: &mut Bencher) { + do_bench_clone_from(b, 10, 10, 0) +} + +#[bench] +fn bench_clone_from_10_0100_0010(b: &mut Bencher) { + do_bench_clone_from(b, 10, 100, 10) +} + +#[bench] +fn bench_clone_from_10_1000_0100(b: &mut Bencher) { + do_bench_clone_from(b, 10, 1000, 100) +} + +macro_rules! bench_in_place { + ($($fname:ident, $type:ty, $count:expr, $init:expr);*) => { + $( + #[bench] + fn $fname(b: &mut Bencher) { + b.iter(|| { + let src: Vec<$type> = black_box(vec![$init; $count]); + src.into_iter() + .enumerate() + .map(|(idx, e)| idx as $type ^ e) + .collect::>() + }); + } + )+ + }; +} + +bench_in_place![ + bench_in_place_xxu8_0010_i0, u8, 10, 0; + bench_in_place_xxu8_0100_i0, u8, 100, 0; + bench_in_place_xxu8_1000_i0, u8, 1000, 0; + bench_in_place_xxu8_0010_i1, u8, 10, 1; + bench_in_place_xxu8_0100_i1, u8, 100, 1; + bench_in_place_xxu8_1000_i1, u8, 1000, 1; + bench_in_place_xu32_0010_i0, u32, 10, 0; + bench_in_place_xu32_0100_i0, u32, 100, 0; + bench_in_place_xu32_1000_i0, u32, 1000, 0; + bench_in_place_xu32_0010_i1, u32, 10, 1; + bench_in_place_xu32_0100_i1, u32, 100, 1; + bench_in_place_xu32_1000_i1, u32, 1000, 1; + bench_in_place_u128_0010_i0, u128, 10, 0; + bench_in_place_u128_0100_i0, u128, 100, 0; + bench_in_place_u128_1000_i0, u128, 1000, 0; + bench_in_place_u128_0010_i1, u128, 10, 1; + bench_in_place_u128_0100_i1, u128, 100, 1; + bench_in_place_u128_1000_i1, u128, 1000, 1 +]; + +#[bench] +fn bench_in_place_recycle(b: &mut Bencher) { + let mut data = vec![0; 1000]; + + b.iter(|| { + let tmp = std::mem::take(&mut data); + data = black_box( + tmp.into_iter() + .enumerate() + .map(|(idx, e)| idx.wrapping_add(e)) + .fuse() + .collect::>(), + ); + }); +} + +#[bench] +fn bench_in_place_zip_recycle(b: &mut Bencher) { + let mut data = vec![0u8; 1000]; + let mut rng = crate::bench_rng(); + let mut subst = vec![0u8; 1000]; + rng.fill_bytes(&mut subst[..]); + + b.iter(|| { + let tmp = std::mem::take(&mut data); + let mangled = tmp + .into_iter() + .zip(subst.iter().copied()) + .enumerate() + .map(|(i, (d, s))| d.wrapping_add(i as u8) ^ s) + .collect::>(); + data = black_box(mangled); + }); +} + +#[bench] +fn bench_in_place_zip_iter_mut(b: &mut Bencher) { + let mut data = vec![0u8; 256]; + let mut rng = crate::bench_rng(); + let mut subst = vec![0u8; 1000]; + rng.fill_bytes(&mut subst[..]); + + b.iter(|| { + data.iter_mut().enumerate().for_each(|(i, d)| { + *d = d.wrapping_add(i as u8) ^ subst[i]; + }); + }); + + black_box(data); +} + +pub fn vec_cast(input: Vec) -> Vec { + input.into_iter().map(|e| unsafe { std::mem::transmute_copy(&e) }).collect() +} + +#[bench] +fn bench_transmute(b: &mut Bencher) { + let mut vec = vec![10u32; 100]; + b.bytes = 800; // 2 casts x 4 bytes x 100 + b.iter(|| { + let v = std::mem::take(&mut vec); + let v = black_box(vec_cast::(v)); + let v = black_box(vec_cast::(v)); + vec = v; + }); +} + +#[derive(Clone)] +struct Droppable(usize); + +impl Drop for Droppable { + fn drop(&mut self) { + black_box(self); + } +} + +#[bench] +fn bench_in_place_collect_droppable(b: &mut Bencher) { + let v: Vec = std::iter::repeat_with(|| Droppable(0)).take(1000).collect(); + b.iter(|| { + v.clone() + .into_iter() + .skip(100) + .enumerate() + .map(|(i, e)| Droppable(i ^ e.0)) + .collect::>() + }) +} + +// node.js gives out of memory error to use with length 1_100_000 +#[cfg(target_os = "emscripten")] +const LEN: usize = 4096; + +#[cfg(not(target_os = "emscripten"))] +const LEN: usize = 16384; + +#[bench] +fn bench_chain_collect(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| data.iter().cloned().chain([1]).collect::>()); +} + +#[bench] +fn bench_chain_chain_collect(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| data.iter().cloned().chain([1]).chain([2]).collect::>()); +} + +#[bench] +fn bench_nest_chain_chain_collect(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + data.iter().cloned().chain([1].iter().chain([2].iter()).cloned()).collect::>() + }); +} + +#[bench] +fn bench_range_map_collect(b: &mut Bencher) { + b.iter(|| (0..LEN).map(|_| u32::default()).collect::>()); +} + +#[bench] +fn bench_chain_extend_ref(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + let mut v = Vec::::with_capacity(data.len() + 1); + v.extend(data.iter().chain([1].iter())); + v + }); +} + +#[bench] +fn bench_chain_extend_value(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + let mut v = Vec::::with_capacity(data.len() + 1); + v.extend(data.iter().cloned().chain(Some(1))); + v + }); +} + +#[bench] +fn bench_rev_1(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + let mut v = Vec::::new(); + v.extend(data.iter().rev()); + v + }); +} + +#[bench] +fn bench_rev_2(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + let mut v = Vec::::with_capacity(data.len()); + v.extend(data.iter().rev()); + v + }); +} + +#[bench] +fn bench_map_regular(b: &mut Bencher) { + let data = black_box([(0, 0); LEN]); + b.iter(|| { + let mut v = Vec::::new(); + v.extend(data.iter().map(|t| t.1)); + v + }); +} + +#[bench] +fn bench_map_fast(b: &mut Bencher) { + let data = black_box([(0, 0); LEN]); + b.iter(|| { + let mut result: Vec = Vec::with_capacity(data.len()); + for i in 0..data.len() { + unsafe { + *result.as_mut_ptr().add(i) = data[i].0; + result.set_len(i); + } + } + result + }); +} + +fn random_sorted_fill(mut seed: u32, buf: &mut [u32]) { + let mask = if buf.len() < 8192 { + 0xFF + } else if buf.len() < 200_000 { + 0xFFFF + } else { + 0xFFFF_FFFF + }; + + for item in buf.iter_mut() { + seed ^= seed << 13; + seed ^= seed >> 17; + seed ^= seed << 5; + + *item = seed & mask; + } + + buf.sort(); +} + +// Measures performance of slice dedup impl. +// This was used to justify separate implementation of dedup for Vec. +// This algorithm was used for Vecs prior to Rust 1.52. +fn bench_dedup_slice_truncate(b: &mut Bencher, sz: usize) { + let mut template = vec![0u32; sz]; + b.bytes = size_of_val(template.as_slice()) as u64; + random_sorted_fill(0x43, &mut template); + + let mut vec = template.clone(); + b.iter(|| { + let vec = black_box(&mut vec); + let len = { + let (dedup, _) = vec.partition_dedup(); + dedup.len() + }; + vec.truncate(len); + + black_box(vec.first()); + let vec = black_box(vec); + vec.clear(); + vec.extend_from_slice(&template); + }); +} + +// Measures performance of Vec::dedup on random data. +fn bench_vec_dedup_random(b: &mut Bencher, sz: usize) { + let mut template = vec![0u32; sz]; + b.bytes = size_of_val(template.as_slice()) as u64; + random_sorted_fill(0x43, &mut template); + + let mut vec = template.clone(); + b.iter(|| { + let vec = black_box(&mut vec); + vec.dedup(); + black_box(vec.first()); + let vec = black_box(vec); + vec.clear(); + vec.extend_from_slice(&template); + }); +} + +// Measures performance of Vec::dedup when there is no items removed +fn bench_vec_dedup_none(b: &mut Bencher, sz: usize) { + let mut template = vec![0u32; sz]; + b.bytes = size_of_val(template.as_slice()) as u64; + template.chunks_exact_mut(2).for_each(|w| { + w[0] = black_box(0); + w[1] = black_box(5); + }); + + let mut vec = template.clone(); + b.iter(|| { + let vec = black_box(&mut vec); + vec.dedup(); + black_box(vec.first()); + // Unlike other benches of `dedup` + // this doesn't reinitialize vec + // because we measure how efficient dedup is + // when no memory written + }); +} + +// Measures performance of Vec::dedup when there is all items removed +fn bench_vec_dedup_all(b: &mut Bencher, sz: usize) { + let mut template = vec![0u32; sz]; + b.bytes = size_of_val(template.as_slice()) as u64; + template.iter_mut().for_each(|w| { + *w = black_box(0); + }); + + let mut vec = template.clone(); + b.iter(|| { + let vec = black_box(&mut vec); + vec.dedup(); + black_box(vec.first()); + let vec = black_box(vec); + vec.clear(); + vec.extend_from_slice(&template); + }); +} + +#[bench] +fn bench_dedup_slice_truncate_100(b: &mut Bencher) { + bench_dedup_slice_truncate(b, 100); +} +#[bench] +fn bench_dedup_random_100(b: &mut Bencher) { + bench_vec_dedup_random(b, 100); +} + +#[bench] +fn bench_dedup_none_100(b: &mut Bencher) { + bench_vec_dedup_none(b, 100); +} + +#[bench] +fn bench_dedup_all_100(b: &mut Bencher) { + bench_vec_dedup_all(b, 100); +} + +#[bench] +fn bench_dedup_slice_truncate_1000(b: &mut Bencher) { + bench_dedup_slice_truncate(b, 1000); +} +#[bench] +fn bench_dedup_random_1000(b: &mut Bencher) { + bench_vec_dedup_random(b, 1000); +} + +#[bench] +fn bench_dedup_none_1000(b: &mut Bencher) { + bench_vec_dedup_none(b, 1000); +} + +#[bench] +fn bench_dedup_all_1000(b: &mut Bencher) { + bench_vec_dedup_all(b, 1000); +} + +#[bench] +fn bench_dedup_slice_truncate_10000(b: &mut Bencher) { + bench_dedup_slice_truncate(b, 10000); +} +#[bench] +fn bench_dedup_random_10000(b: &mut Bencher) { + bench_vec_dedup_random(b, 10000); +} + +#[bench] +fn bench_dedup_none_10000(b: &mut Bencher) { + bench_vec_dedup_none(b, 10000); +} + +#[bench] +fn bench_dedup_all_10000(b: &mut Bencher) { + bench_vec_dedup_all(b, 10000); +} + +#[bench] +fn bench_dedup_slice_truncate_100000(b: &mut Bencher) { + bench_dedup_slice_truncate(b, 100000); +} +#[bench] +fn bench_dedup_random_100000(b: &mut Bencher) { + bench_vec_dedup_random(b, 100000); +} + +#[bench] +fn bench_dedup_none_100000(b: &mut Bencher) { + bench_vec_dedup_none(b, 100000); +} + +#[bench] +fn bench_dedup_all_100000(b: &mut Bencher) { + bench_vec_dedup_all(b, 100000); +} + +#[bench] +fn bench_flat_map_collect(b: &mut Bencher) { + let v = vec![777u32; 500000]; + b.iter(|| v.iter().flat_map(|color| color.rotate_left(8).to_be_bytes()).collect::>()); +} + +/// Reference benchmark that `retain` has to compete with. +#[bench] +fn bench_retain_iter_100000(b: &mut Bencher) { + let mut v = Vec::with_capacity(100000); + + b.iter(|| { + let mut tmp = std::mem::take(&mut v); + tmp.clear(); + tmp.extend(black_box(1..=100000)); + v = tmp.into_iter().filter(|x| x & 1 == 0).collect(); + }); +} + +#[bench] +fn bench_retain_100000(b: &mut Bencher) { + let mut v = Vec::with_capacity(100000); + + b.iter(|| { + v.clear(); + v.extend(black_box(1..=100000)); + v.retain(|x| x & 1 == 0) + }); +} + +#[bench] +fn bench_retain_whole_100000(b: &mut Bencher) { + let mut v = black_box(vec![826u32; 100000]); + b.iter(|| v.retain(|x| *x == 826u32)); +} + +#[bench] +fn bench_next_chunk(b: &mut Bencher) { + let v = vec![13u8; 2048]; + + b.iter(|| { + const CHUNK: usize = 8; + + let mut sum = [0u32; CHUNK]; + let mut iter = black_box(v.clone()).into_iter(); + + while let Ok(chunk) = iter.next_chunk::() { + for i in 0..CHUNK { + sum[i] += chunk[i] as u32; + } + } + + sum + }) +} diff --git a/library/alloctests/benches/vec_deque.rs b/library/alloctests/benches/vec_deque.rs new file mode 100644 index 00000000000..a56f8496963 --- /dev/null +++ b/library/alloctests/benches/vec_deque.rs @@ -0,0 +1,267 @@ +use std::collections::{VecDeque, vec_deque}; +use std::mem; + +use test::{Bencher, black_box}; + +#[bench] +fn bench_new(b: &mut Bencher) { + b.iter(|| { + let ring: VecDeque = VecDeque::new(); + black_box(ring); + }) +} + +#[bench] +fn bench_grow_1025(b: &mut Bencher) { + b.iter(|| { + let mut deq = VecDeque::new(); + for i in 0..1025 { + deq.push_front(i); + } + black_box(deq); + }) +} + +#[bench] +fn bench_iter_1000(b: &mut Bencher) { + let ring: VecDeque<_> = (0..1000).collect(); + + b.iter(|| { + let mut sum = 0; + for &i in &ring { + sum += i; + } + black_box(sum); + }) +} + +#[bench] +fn bench_mut_iter_1000(b: &mut Bencher) { + let mut ring: VecDeque<_> = (0..1000).collect(); + + b.iter(|| { + let mut sum = 0; + for i in &mut ring { + sum += *i; + } + black_box(sum); + }) +} + +#[bench] +fn bench_try_fold(b: &mut Bencher) { + let ring: VecDeque<_> = (0..1000).collect(); + + b.iter(|| black_box(ring.iter().try_fold(0, |a, b| Some(a + b)))) +} + +/// does the memory bookkeeping to reuse the buffer of the Vec between iterations. +/// `setup` must not modify its argument's length or capacity. `g` must not move out of its argument. +fn into_iter_helper< + T: Copy, + F: FnOnce(&mut VecDeque), + G: FnOnce(&mut vec_deque::IntoIter), +>( + v: &mut Vec, + setup: F, + g: G, +) { + let ptr = v.as_mut_ptr(); + let len = v.len(); + // ensure that the vec is full, to make sure that any wrapping from the deque doesn't + // access uninitialized memory. + assert_eq!(v.len(), v.capacity()); + + let mut deque = VecDeque::from(mem::take(v)); + setup(&mut deque); + + let mut it = deque.into_iter(); + g(&mut it); + + mem::forget(it); + + // SAFETY: the provided functions are not allowed to modify the allocation, so the buffer is still alive. + // len and capacity are accurate due to the above assertion. + // All the elements in the buffer are still valid, because of `T: Copy` which implies `T: !Drop`. + mem::forget(mem::replace(v, unsafe { Vec::from_raw_parts(ptr, len, len) })); +} + +#[bench] +fn bench_into_iter(b: &mut Bencher) { + let len = 1024; + // we reuse this allocation for every run + let mut vec: Vec = (0..len).collect(); + vec.shrink_to_fit(); + + b.iter(|| { + let mut sum = 0; + into_iter_helper( + &mut vec, + |_| {}, + |it| { + for i in it { + sum += i; + } + }, + ); + black_box(sum); + + let mut sum = 0; + // rotating a full deque doesn't move any memory. + into_iter_helper( + &mut vec, + |d| d.rotate_left(len / 2), + |it| { + for i in it { + sum += i; + } + }, + ); + black_box(sum); + }); +} + +#[bench] +fn bench_into_iter_fold(b: &mut Bencher) { + let len = 1024; + + // because `fold` takes ownership of the iterator, + // we can't prevent it from dropping the memory, + // so we have to bite the bullet and reallocate + // for every iteration. + b.iter(|| { + let deque: VecDeque = (0..len).collect(); + assert_eq!(deque.len(), deque.capacity()); + let sum = deque.into_iter().fold(0, |a, b| a + b); + black_box(sum); + + // rotating a full deque doesn't move any memory. + let mut deque: VecDeque = (0..len).collect(); + assert_eq!(deque.len(), deque.capacity()); + deque.rotate_left(len / 2); + let sum = deque.into_iter().fold(0, |a, b| a + b); + black_box(sum); + }); +} + +#[bench] +fn bench_into_iter_try_fold(b: &mut Bencher) { + let len = 1024; + // we reuse this allocation for every run + let mut vec: Vec = (0..len).collect(); + vec.shrink_to_fit(); + + // Iterator::any uses Iterator::try_fold under the hood + b.iter(|| { + let mut b = false; + into_iter_helper(&mut vec, |_| {}, |it| b = it.any(|i| i == len - 1)); + black_box(b); + + into_iter_helper(&mut vec, |d| d.rotate_left(len / 2), |it| b = it.any(|i| i == len - 1)); + black_box(b); + }); +} + +#[bench] +fn bench_into_iter_next_chunk(b: &mut Bencher) { + let len = 1024; + // we reuse this allocation for every run + let mut vec: Vec = (0..len).collect(); + vec.shrink_to_fit(); + + b.iter(|| { + let mut buf = [0; 64]; + into_iter_helper( + &mut vec, + |_| {}, + |it| { + while let Ok(a) = it.next_chunk() { + buf = a; + } + }, + ); + black_box(buf); + + into_iter_helper( + &mut vec, + |d| d.rotate_left(len / 2), + |it| { + while let Ok(a) = it.next_chunk() { + buf = a; + } + }, + ); + black_box(buf); + }); +} + +#[bench] +fn bench_from_array_1000(b: &mut Bencher) { + const N: usize = 1000; + let mut array: [usize; N] = [0; N]; + + for i in 0..N { + array[i] = i; + } + + b.iter(|| { + let deq: VecDeque<_> = array.into(); + black_box(deq); + }) +} + +#[bench] +fn bench_extend_bytes(b: &mut Bencher) { + let mut ring: VecDeque = VecDeque::with_capacity(1000); + let input: &[u8] = &[128; 512]; + + b.iter(|| { + ring.clear(); + ring.extend(black_box(input)); + }); +} + +#[bench] +fn bench_extend_vec(b: &mut Bencher) { + let mut ring: VecDeque = VecDeque::with_capacity(1000); + let input = vec![128; 512]; + + b.iter(|| { + ring.clear(); + + let input = input.clone(); + ring.extend(black_box(input)); + }); +} + +#[bench] +fn bench_extend_trustedlen(b: &mut Bencher) { + let mut ring: VecDeque = VecDeque::with_capacity(1000); + + b.iter(|| { + ring.clear(); + ring.extend(black_box(0..512)); + }); +} + +#[bench] +fn bench_extend_chained_trustedlen(b: &mut Bencher) { + let mut ring: VecDeque = VecDeque::with_capacity(1000); + + b.iter(|| { + ring.clear(); + ring.extend(black_box((0..256).chain(768..1024))); + }); +} + +#[bench] +fn bench_extend_chained_bytes(b: &mut Bencher) { + let mut ring: VecDeque = VecDeque::with_capacity(1000); + let input1: &[u16] = &[128; 256]; + let input2: &[u16] = &[255; 256]; + + b.iter(|| { + ring.clear(); + ring.extend(black_box(input1.iter().chain(input2.iter()))); + }); +} diff --git a/library/alloctests/benches/vec_deque_append.rs b/library/alloctests/benches/vec_deque_append.rs new file mode 100644 index 00000000000..7c805da9737 --- /dev/null +++ b/library/alloctests/benches/vec_deque_append.rs @@ -0,0 +1,40 @@ +use std::collections::VecDeque; +use std::time::Instant; + +const VECDEQUE_LEN: i32 = 100000; +const WARMUP_N: usize = 100; +const BENCH_N: usize = 1000; + +fn main() { + if cfg!(miri) { + // Don't benchmark Miri... + // (Due to bootstrap quirks, this gets picked up by `x.py miri library/alloc --no-doc`.) + return; + } + let a: VecDeque = (0..VECDEQUE_LEN).collect(); + let b: VecDeque = (0..VECDEQUE_LEN).collect(); + + for _ in 0..WARMUP_N { + let mut c = a.clone(); + let mut d = b.clone(); + c.append(&mut d); + } + + let mut durations = Vec::with_capacity(BENCH_N); + + for _ in 0..BENCH_N { + let mut c = a.clone(); + let mut d = b.clone(); + let before = Instant::now(); + c.append(&mut d); + let after = Instant::now(); + durations.push(after.duration_since(before)); + } + + let l = durations.len(); + durations.sort(); + + assert!(BENCH_N % 2 == 0); + let median = (durations[(l / 2) - 1] + durations[l / 2]) / 2; + println!("\ncustom-bench vec_deque_append {:?} ns/iter\n", median.as_nanos()); +} diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs new file mode 100644 index 00000000000..b49208cd4eb --- /dev/null +++ b/library/alloctests/lib.rs @@ -0,0 +1 @@ +// Intentionally left empty. diff --git a/library/alloctests/tests/alloc_test.rs b/library/alloctests/tests/alloc_test.rs new file mode 100644 index 00000000000..1e722d66795 --- /dev/null +++ b/library/alloctests/tests/alloc_test.rs @@ -0,0 +1,29 @@ +use alloc::alloc::*; +use alloc::boxed::Box; + +extern crate test; +use test::Bencher; + +#[test] +fn allocate_zeroed() { + unsafe { + let layout = Layout::from_size_align(1024, 1).unwrap(); + let ptr = + Global.allocate_zeroed(layout.clone()).unwrap_or_else(|_| handle_alloc_error(layout)); + + let mut i = ptr.as_non_null_ptr().as_ptr(); + let end = i.add(layout.size()); + while i < end { + assert_eq!(*i, 0); + i = i.add(1); + } + Global.deallocate(ptr.as_non_null_ptr(), layout); + } +} + +#[bench] +fn alloc_owned_small(b: &mut Bencher) { + b.iter(|| { + let _: Box<_> = Box::new(10); + }) +} diff --git a/library/alloctests/tests/arc.rs b/library/alloctests/tests/arc.rs new file mode 100644 index 00000000000..0baa50f439b --- /dev/null +++ b/library/alloctests/tests/arc.rs @@ -0,0 +1,278 @@ +use std::any::Any; +use std::cell::{Cell, RefCell}; +use std::iter::TrustedLen; +use std::sync::{Arc, Weak}; + +#[test] +fn uninhabited() { + enum Void {} + let mut a = Weak::::new(); + a = a.clone(); + assert!(a.upgrade().is_none()); + + let mut a: Weak = a; // Unsizing + a = a.clone(); + assert!(a.upgrade().is_none()); +} + +#[test] +fn slice() { + let a: Arc<[u32; 3]> = Arc::new([3, 2, 1]); + let a: Arc<[u32]> = a; // Unsizing + let b: Arc<[u32]> = Arc::from(&[3, 2, 1][..]); // Conversion + assert_eq!(a, b); + + // Exercise is_dangling() with a DST + let mut a = Arc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); +} + +#[test] +fn trait_object() { + let a: Arc = Arc::new(4); + let a: Arc = a; // Unsizing + + // Exercise is_dangling() with a DST + let mut a = Arc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); + + let mut b = Weak::::new(); + b = b.clone(); + assert!(b.upgrade().is_none()); + let mut b: Weak = b; // Unsizing + b = b.clone(); + assert!(b.upgrade().is_none()); +} + +#[test] +fn float_nan_ne() { + let x = Arc::new(f32::NAN); + assert!(x != x); + assert!(!(x == x)); +} + +#[test] +fn partial_eq() { + struct TestPEq(RefCell); + impl PartialEq for TestPEq { + fn eq(&self, other: &TestPEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Arc::new(TestPEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 4); +} + +#[test] +fn eq() { + #[derive(Eq)] + struct TestEq(RefCell); + impl PartialEq for TestEq { + fn eq(&self, other: &TestEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Arc::new(TestEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 0); +} + +// The test code below is identical to that in `rc.rs`. +// For better maintainability we therefore define this type alias. +type Rc = Arc; + +const SHARED_ITER_MAX: u16 = 100; + +fn assert_trusted_len(_: &I) {} + +#[test] +fn shared_from_iter_normal() { + // Exercise the base implementation for non-`TrustedLen` iterators. + { + // `Filter` is never `TrustedLen` since we don't + // know statically how many elements will be kept: + let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new); + + // Collecting into a `Vec` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. +} + +#[test] +fn shared_from_iter_trustedlen_normal() { + // Exercise the `TrustedLen` implementation under normal circumstances + // where `size_hint()` matches `(_, Some(exact_len))`. + { + let iter = (0..SHARED_ITER_MAX).map(Box::new); + assert_trusted_len(&iter); + + // Collecting into a `Vec` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + assert_eq!(size_of::>() * SHARED_ITER_MAX as usize, size_of_val(&*rc)); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. + + // Try a ZST to make sure it is handled well. + { + let iter = (0..SHARED_ITER_MAX).map(drop); + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + assert_eq!(0, size_of_val(&*rc)); + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } +} + +#[test] +#[should_panic = "I've almost got 99 problems."] +fn shared_from_iter_trustedlen_panic() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where `.next()` drops before the last iteration. + let iter = (0..SHARED_ITER_MAX).map(|val| match val { + 98 => panic!("I've almost got 99 problems."), + _ => Box::new(val), + }); + assert_trusted_len(&iter); + let _ = iter.collect::>(); + + panic!("I am unreachable."); +} + +#[test] +fn shared_from_iter_trustedlen_no_fuse() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner. + struct Iter(std::vec::IntoIter>>); + + unsafe impl TrustedLen for Iter {} + + impl Iterator for Iter { + fn size_hint(&self) -> (usize, Option) { + (2, Some(2)) + } + + type Item = Box; + + fn next(&mut self) -> Option { + self.0.next().flatten() + } + } + + let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))]; + let iter = Iter(vec.into_iter()); + assert_trusted_len(&iter); + assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::>()); +} + +#[test] +fn weak_may_dangle() { + fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> { + val.clone() + } + + // Without #[may_dangle] we get: + let mut val = Weak::new(); + hmm(&mut val); + // ~~~~~~~~ borrowed value does not live long enough + // + // `val` dropped here while still borrowed + // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak` +} + +/// Test that a panic from a destructor does not leak the allocation. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn panic_no_leak() { + use std::alloc::{AllocError, Allocator, Global, Layout}; + use std::panic::{AssertUnwindSafe, catch_unwind}; + use std::ptr::NonNull; + + struct AllocCount(Cell); + unsafe impl Allocator for AllocCount { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + self.0.set(self.0.get() + 1); + Global.allocate(layout) + } + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + self.0.set(self.0.get() - 1); + unsafe { Global.deallocate(ptr, layout) } + } + } + + struct PanicOnDrop; + impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("PanicOnDrop"); + } + } + + let alloc = AllocCount(Cell::new(0)); + let rc = Rc::new_in(PanicOnDrop, &alloc); + assert_eq!(alloc.0.get(), 1); + + let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); + assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); + assert_eq!(alloc.0.get(), 0); +} + +/// This is similar to the doc-test for `Arc::make_mut()`, but on an unsized type (slice). +#[test] +fn make_mut_unsized() { + use alloc::sync::Arc; + + let mut data: Arc<[i32]> = Arc::new([10, 20, 30]); + + Arc::make_mut(&mut data)[0] += 1; // Won't clone anything + let mut other_data = Arc::clone(&data); // Won't clone inner data + Arc::make_mut(&mut data)[1] += 1; // Clones inner data + Arc::make_mut(&mut data)[2] += 1; // Won't clone anything + Arc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything + + // Now `data` and `other_data` point to different allocations. + assert_eq!(*data, [11, 21, 31]); + assert_eq!(*other_data, [110, 20, 30]); +} + +#[allow(unused)] +mod pin_coerce_unsized { + use alloc::sync::Arc; + use core::pin::Pin; + + pub trait MyTrait {} + impl MyTrait for String {} + + // Pin coercion should work for Arc + pub fn pin_arc(arg: Pin>) -> Pin> { + arg + } +} diff --git a/library/alloctests/tests/autotraits.rs b/library/alloctests/tests/autotraits.rs new file mode 100644 index 00000000000..6b82deeac8a --- /dev/null +++ b/library/alloctests/tests/autotraits.rs @@ -0,0 +1,288 @@ +fn require_sync(_: T) {} +fn require_send_sync(_: T) {} + +struct NotSend(#[allow(dead_code)] *const ()); +unsafe impl Sync for NotSend {} + +#[test] +fn test_btree_map() { + // Tests of this form are prone to https://github.com/rust-lang/rust/issues/64552. + // + // In theory the async block's future would be Send if the value we hold + // across the await point is Send, and Sync if the value we hold across the + // await point is Sync. + // + // We test autotraits in this convoluted way, instead of a straightforward + // `require_send_sync::()`, because the interaction with + // coroutines exposes some current limitations in rustc's ability to prove a + // lifetime bound on the erased coroutine witness types. See the above link. + // + // A typical way this would surface in real code is: + // + // fn spawn(_: T) {} + // + // async fn f() { + // let map = BTreeMap::>::new(); + // for _ in &map { + // async {}.await; + // } + // } + // + // fn main() { + // spawn(f()); + // } + // + // where with some unintentionally overconstrained Send impls in alloc's + // internals, the future might incorrectly not be Send even though every + // single type involved in the program is Send and Sync. + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + // Testing like this would not catch all issues that the above form catches. + require_send_sync(None::>); + + require_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::< + alloc::collections::btree_map::ExtractIf<'_, &u32, &u32, fn(&&u32, &mut &u32) -> bool>, + >; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); +} + +#[test] +fn test_btree_set() { + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None:: bool>>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); +} + +#[test] +fn test_binary_heap() { + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); +} + +#[test] +fn test_linked_list() { + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + // FIXME + /* + require_send_sync(async { + let _v = + None:: bool>>; + async {}.await; + }); + */ + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); +} + +#[test] +fn test_vec_deque() { + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); +} diff --git a/library/alloctests/tests/borrow.rs b/library/alloctests/tests/borrow.rs new file mode 100644 index 00000000000..af7efb7d782 --- /dev/null +++ b/library/alloctests/tests/borrow.rs @@ -0,0 +1,60 @@ +use std::borrow::Cow; +use std::ffi::{CStr, OsStr}; +use std::path::Path; +use std::rc::Rc; +use std::sync::Arc; + +macro_rules! test_from_cow { + ($value:ident => $($ty:ty),+) => {$( + let borrowed = <$ty>::from(Cow::Borrowed($value)); + let owned = <$ty>::from(Cow::Owned($value.to_owned())); + assert_eq!($value, &*borrowed); + assert_eq!($value, &*owned); + )+}; + ($value:ident : & $ty:ty) => { + test_from_cow!($value => Box<$ty>, Rc<$ty>, Arc<$ty>); + } +} + +#[test] +fn test_from_cow_slice() { + let slice: &[i32] = &[1, 2, 3]; + test_from_cow!(slice: &[i32]); +} + +#[test] +fn test_from_cow_str() { + let string = "hello"; + test_from_cow!(string: &str); +} + +#[test] +fn test_from_cow_c_str() { + let string = CStr::from_bytes_with_nul(b"hello\0").unwrap(); + test_from_cow!(string: &CStr); +} + +#[test] +fn test_from_cow_os_str() { + let string = OsStr::new("hello"); + test_from_cow!(string: &OsStr); +} + +#[test] +fn test_from_cow_path() { + let path = Path::new("hello"); + test_from_cow!(path: &Path); +} + +#[test] +fn cow_const() { + // test that the methods of `Cow` are usable in a const context + + const COW: Cow<'_, str> = Cow::Borrowed("moo"); + + const IS_BORROWED: bool = COW.is_borrowed(); + assert!(IS_BORROWED); + + const IS_OWNED: bool = COW.is_owned(); + assert!(!IS_OWNED); +} diff --git a/library/alloctests/tests/boxed.rs b/library/alloctests/tests/boxed.rs new file mode 100644 index 00000000000..94389cf2de9 --- /dev/null +++ b/library/alloctests/tests/boxed.rs @@ -0,0 +1,258 @@ +use core::alloc::{AllocError, Allocator, Layout}; +use core::cell::Cell; +use core::mem::MaybeUninit; +use core::ptr::NonNull; + +#[test] +#[expect(dangling_pointers_from_temporaries)] +fn uninitialized_zero_size_box() { + assert_eq!( + &*Box::<()>::new_uninit() as *const _, + NonNull::>::dangling().as_ptr(), + ); + assert_eq!( + Box::<[()]>::new_uninit_slice(4).as_ptr(), + NonNull::>::dangling().as_ptr(), + ); + assert_eq!( + Box::<[String]>::new_uninit_slice(0).as_ptr(), + NonNull::>::dangling().as_ptr(), + ); +} + +#[derive(Clone, PartialEq, Eq, Debug)] +struct Dummy { + _data: u8, +} + +#[test] +fn box_clone_and_clone_from_equivalence() { + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let clone = control.clone(); + let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); + copy.clone_from(&control); + assert_eq!(control, clone); + assert_eq!(control, copy); + } +} + +/// This test might give a false positive in case the box reallocates, +/// but the allocator keeps the original pointer. +/// +/// On the other hand, it won't give a false negative: If it fails, then the +/// memory was definitely not reused. +#[test] +fn box_clone_from_ptr_stability() { + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); + let copy_raw = copy.as_ptr() as usize; + copy.clone_from(&control); + assert_eq!(copy.as_ptr() as usize, copy_raw); + } +} + +#[test] +fn box_deref_lval() { + let x = Box::new(Cell::new(5)); + x.set(1000); + assert_eq!(x.get(), 1000); +} + +/// Test that a panic from a destructor does not leak the allocation. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn panic_no_leak() { + use std::alloc::{AllocError, Allocator, Global, Layout}; + use std::panic::{AssertUnwindSafe, catch_unwind}; + use std::ptr::NonNull; + + struct AllocCount(Cell); + unsafe impl Allocator for AllocCount { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + self.0.set(self.0.get() + 1); + Global.allocate(layout) + } + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + self.0.set(self.0.get() - 1); + unsafe { Global.deallocate(ptr, layout) } + } + } + + struct PanicOnDrop { + _data: u8, + } + impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("PanicOnDrop"); + } + } + + let alloc = AllocCount(Cell::new(0)); + let b = Box::new_in(PanicOnDrop { _data: 42 }, &alloc); + assert_eq!(alloc.0.get(), 1); + + let panic_message = catch_unwind(AssertUnwindSafe(|| drop(b))).unwrap_err(); + assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); + assert_eq!(alloc.0.get(), 0); +} + +#[allow(unused)] +pub struct ConstAllocator; + +unsafe impl Allocator for ConstAllocator { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + match layout.size() { + 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), + _ => unsafe { + let ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); + Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8])) + }, + } + } + + unsafe fn deallocate(&self, _ptr: NonNull, layout: Layout) { + match layout.size() { + 0 => { /* do nothing */ } + _ => { /* do nothing too */ } + } + } + + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + let ptr = self.allocate(layout)?; + if layout.size() > 0 { + unsafe { + ptr.as_mut_ptr().write_bytes(0, layout.size()); + } + } + Ok(ptr) + } + + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" + ); + + let new_ptr = self.allocate(new_layout)?; + if new_layout.size() > 0 { + // Safety: `new_ptr` is valid for writes and `ptr` for reads of + // `old_layout.size()`, because `new_layout.size() >= + // old_layout.size()` (which is an invariant that must be upheld by + // callers). + unsafe { + new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size()); + } + // Safety: `ptr` is never used again is also an invariant which must + // be upheld by callers. + unsafe { + self.deallocate(ptr, old_layout); + } + } + Ok(new_ptr) + } + + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // Safety: Invariants of `grow_zeroed` and `grow` are the same, and must + // be enforced by callers. + let new_ptr = unsafe { self.grow(ptr, old_layout, new_layout)? }; + if new_layout.size() > 0 { + let old_size = old_layout.size(); + let new_size = new_layout.size(); + let raw_ptr = new_ptr.as_mut_ptr(); + // Safety: + // - `grow` returned Ok, so the returned pointer must be valid for + // `new_size` bytes + // - `new_size` must be larger than `old_size`, which is an + // invariant which must be upheld by callers. + unsafe { + raw_ptr.add(old_size).write_bytes(0, new_size - old_size); + } + } + Ok(new_ptr) + } + + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" + ); + + let new_ptr = self.allocate(new_layout)?; + if new_layout.size() > 0 { + // Safety: `new_ptr` and `ptr` are valid for reads/writes of + // `new_layout.size()` because of the invariants of shrink, which + // include `new_layout.size()` being smaller than (or equal to) + // `old_layout.size()`. + unsafe { + new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), new_layout.size()); + } + // Safety: `ptr` is never used again is also an invariant which must + // be upheld by callers. + unsafe { + self.deallocate(ptr, old_layout); + } + } + Ok(new_ptr) + } + + fn by_ref(&self) -> &Self + where + Self: Sized, + { + self + } +} + +#[allow(unused)] +mod pin_coerce_unsized { + use alloc::boxed::Box; + use core::pin::Pin; + + trait MyTrait { + fn action(&self) -> &str; + } + impl MyTrait for String { + fn action(&self) -> &str { + &*self + } + } + struct MyStruct; + impl MyTrait for MyStruct { + fn action(&self) -> &str { + "MyStruct" + } + } + + // Pin coercion should work for Box + fn pin_box(arg: Pin>) -> Pin> { + arg + } + + #[test] + fn pin_coerce_unsized_box() { + let my_string = "my string"; + let a_string = Box::pin(String::from(my_string)); + let pin_box_str = pin_box(a_string); + assert_eq!(pin_box_str.as_ref().action(), my_string); + let a_struct = Box::pin(MyStruct); + let pin_box_struct = pin_box(a_struct); + assert_eq!(pin_box_struct.as_ref().action(), "MyStruct"); + } +} diff --git a/library/alloctests/tests/btree_set_hash.rs b/library/alloctests/tests/btree_set_hash.rs new file mode 100644 index 00000000000..71a3a143209 --- /dev/null +++ b/library/alloctests/tests/btree_set_hash.rs @@ -0,0 +1,30 @@ +use std::collections::BTreeSet; + +use crate::hash; + +#[test] +fn test_hash() { + let mut x = BTreeSet::new(); + let mut y = BTreeSet::new(); + + x.insert(1); + x.insert(2); + x.insert(3); + + y.insert(3); + y.insert(2); + y.insert(1); + + assert_eq!(hash(&x), hash(&y)); +} + +#[test] +fn test_prefix_free() { + let x = BTreeSet::from([1, 2, 3]); + let y = BTreeSet::::new(); + + // If hashed by iteration alone, `(x, y)` and `(y, x)` would visit the same + // order of elements, resulting in the same hash. But now that we also hash + // the length, they get distinct sequences of hashed data. + assert_ne!(hash(&(&x, &y)), hash(&(&y, &x))); +} diff --git a/library/alloctests/tests/c_str.rs b/library/alloctests/tests/c_str.rs new file mode 100644 index 00000000000..4a581793956 --- /dev/null +++ b/library/alloctests/tests/c_str.rs @@ -0,0 +1,19 @@ +use std::borrow::Cow::{Borrowed, Owned}; +use std::ffi::CStr; +use std::os::raw::c_char; + +#[test] +fn to_str() { + let data = b"123\xE2\x80\xA6\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…")); + assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…")); + } + let data = b"123\xE2\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert!(CStr::from_ptr(ptr).to_str().is_err()); + assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::(format!("123\u{FFFD}"))); + } +} diff --git a/library/alloctests/tests/c_str2.rs b/library/alloctests/tests/c_str2.rs new file mode 100644 index 00000000000..0f4c27fa123 --- /dev/null +++ b/library/alloctests/tests/c_str2.rs @@ -0,0 +1,227 @@ +use alloc::ffi::CString; +use alloc::rc::Rc; +use alloc::sync::Arc; +use core::assert_matches::assert_matches; +use core::ffi::{CStr, FromBytesUntilNulError, c_char}; +#[allow(deprecated)] +use core::hash::SipHasher13 as DefaultHasher; +use core::hash::{Hash, Hasher}; + +#[test] +fn c_to_rust() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123"); + assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0"); + } +} + +#[test] +fn simple() { + let s = CString::new("1234").unwrap(); + assert_eq!(s.as_bytes(), b"1234"); + assert_eq!(s.as_bytes_with_nul(), b"1234\0"); +} + +#[test] +fn build_with_zero1() { + assert!(CString::new(&b"\0"[..]).is_err()); +} +#[test] +fn build_with_zero2() { + assert!(CString::new(vec![0]).is_err()); +} + +#[test] +fn formatted() { + let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); + assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); +} + +#[test] +fn borrowed() { + unsafe { + let s = CStr::from_ptr(b"12\0".as_ptr() as *const _); + assert_eq!(s.to_bytes(), b"12"); + assert_eq!(s.to_bytes_with_nul(), b"12\0"); + } +} + +#[test] +fn to_owned() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const c_char; + + let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; + assert_eq!(owned.as_bytes_with_nul(), data); +} + +#[test] +fn equal_hash() { + let data = b"123\xE2\xFA\xA6\0"; + let ptr = data.as_ptr() as *const c_char; + let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; + + #[allow(deprecated)] + let mut s = DefaultHasher::new(); + cstr.hash(&mut s); + let cstr_hash = s.finish(); + #[allow(deprecated)] + let mut s = DefaultHasher::new(); + CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s); + let cstring_hash = s.finish(); + + assert_eq!(cstr_hash, cstring_hash); +} + +#[test] +fn from_bytes_with_nul() { + let data = b"123\0"; + let cstr = CStr::from_bytes_with_nul(data); + assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..])); + let cstr = CStr::from_bytes_with_nul(data); + assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..])); + + unsafe { + let cstr = CStr::from_bytes_with_nul(data); + let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data); + assert_eq!(cstr, Ok(cstr_unchecked)); + } +} + +#[test] +fn from_bytes_with_nul_unterminated() { + let data = b"123"; + let cstr = CStr::from_bytes_with_nul(data); + assert!(cstr.is_err()); +} + +#[test] +fn from_bytes_with_nul_interior() { + let data = b"1\023\0"; + let cstr = CStr::from_bytes_with_nul(data); + assert!(cstr.is_err()); +} + +#[test] +fn cstr_from_bytes_until_nul() { + // Test an empty slice. This should fail because it + // does not contain a nul byte. + let b = b""; + assert_matches!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError { .. })); + + // Test a non-empty slice, that does not contain a nul byte. + let b = b"hello"; + assert_matches!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError { .. })); + + // Test an empty nul-terminated string + let b = b"\0"; + let r = CStr::from_bytes_until_nul(&b[..]).unwrap(); + assert_eq!(r.to_bytes(), b""); + + // Test a slice with the nul byte in the middle + let b = b"hello\0world!"; + let r = CStr::from_bytes_until_nul(&b[..]).unwrap(); + assert_eq!(r.to_bytes(), b"hello"); + + // Test a slice with the nul byte at the end + let b = b"hello\0"; + let r = CStr::from_bytes_until_nul(&b[..]).unwrap(); + assert_eq!(r.to_bytes(), b"hello"); + + // Test a slice with two nul bytes at the end + let b = b"hello\0\0"; + let r = CStr::from_bytes_until_nul(&b[..]).unwrap(); + assert_eq!(r.to_bytes(), b"hello"); + + // Test a slice containing lots of nul bytes + let b = b"\0\0\0\0"; + let r = CStr::from_bytes_until_nul(&b[..]).unwrap(); + assert_eq!(r.to_bytes(), b""); +} + +#[test] +fn into_boxed() { + let orig: &[u8] = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(orig).unwrap(); + let boxed: Box = Box::from(cstr); + let cstring = cstr.to_owned().into_boxed_c_str().into_c_string(); + assert_eq!(cstr, &*boxed); + assert_eq!(&*boxed, &*cstring); + assert_eq!(&*cstring, cstr); +} + +#[test] +fn boxed_default() { + let boxed = >::default(); + assert_eq!(boxed.to_bytes_with_nul(), &[0]); +} + +#[test] +fn test_c_str_clone_into() { + let mut c_string = c"lorem".to_owned(); + let c_ptr = c_string.as_ptr(); + let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap(); + c_str.clone_into(&mut c_string); + assert_eq!(c_str, c_string.as_c_str()); + // The exact same size shouldn't have needed to move its allocation + assert_eq!(c_ptr, c_string.as_ptr()); +} + +#[test] +fn into_rc() { + let orig: &[u8] = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(orig).unwrap(); + let rc: Rc = Rc::from(cstr); + let arc: Arc = Arc::from(cstr); + + assert_eq!(&*rc, cstr); + assert_eq!(&*arc, cstr); + + let rc2: Rc = Rc::from(cstr.to_owned()); + let arc2: Arc = Arc::from(cstr.to_owned()); + + assert_eq!(&*rc2, cstr); + assert_eq!(&*arc2, cstr); +} + +#[test] +fn cstr_const_constructor() { + const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") }; + + assert_eq!(CSTR.to_str().unwrap(), "Hello, world!"); +} + +#[test] +fn cstr_index_from() { + let original = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(original).unwrap(); + let result = CStr::from_bytes_with_nul(&original[7..]).unwrap(); + + assert_eq!(&cstr[7..], result); +} + +#[test] +#[should_panic] +fn cstr_index_from_empty() { + let original = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(original).unwrap(); + let _ = &cstr[original.len()..]; +} + +#[test] +fn c_string_from_empty_string() { + let original = ""; + let cstring = CString::new(original).unwrap(); + assert_eq!(original.as_bytes(), cstring.as_bytes()); + assert_eq!([b'\0'], cstring.as_bytes_with_nul()); +} + +#[test] +fn c_str_from_empty_string() { + let original = b"\0"; + let cstr = CStr::from_bytes_with_nul(original).unwrap(); + assert_eq!([] as [u8; 0], cstr.to_bytes()); + assert_eq!([b'\0'], cstr.to_bytes_with_nul()); +} diff --git a/library/alloctests/tests/collections/binary_heap.rs b/library/alloctests/tests/collections/binary_heap.rs new file mode 100644 index 00000000000..95f4c3e614f --- /dev/null +++ b/library/alloctests/tests/collections/binary_heap.rs @@ -0,0 +1,580 @@ +use alloc::boxed::Box; +use alloc::collections::binary_heap::*; +use std::iter::TrustedLen; +use std::mem; +use std::panic::{AssertUnwindSafe, catch_unwind}; + +use crate::testing::crash_test::{CrashTestDummy, Panic}; + +#[test] +fn test_iterator() { + let data = vec![5, 9, 3]; + let iterout = [9, 5, 3]; + let heap = BinaryHeap::from(data); + let mut i = 0; + for el in &heap { + assert_eq!(*el, iterout[i]); + i += 1; + } +} + +#[test] +fn test_iter_rev_cloned_collect() { + let data = vec![5, 9, 3]; + let iterout = vec![3, 5, 9]; + let pq = BinaryHeap::from(data); + + let v: Vec<_> = pq.iter().rev().cloned().collect(); + assert_eq!(v, iterout); +} + +#[test] +fn test_into_iter_collect() { + let data = vec![5, 9, 3]; + let iterout = vec![9, 5, 3]; + let pq = BinaryHeap::from(data); + + let v: Vec<_> = pq.into_iter().collect(); + assert_eq!(v, iterout); +} + +#[test] +fn test_into_iter_size_hint() { + let data = vec![5, 9]; + let pq = BinaryHeap::from(data); + + let mut it = pq.into_iter(); + + assert_eq!(it.size_hint(), (2, Some(2))); + assert_eq!(it.next(), Some(9)); + + assert_eq!(it.size_hint(), (1, Some(1))); + assert_eq!(it.next(), Some(5)); + + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next(), None); +} + +#[test] +fn test_into_iter_rev_collect() { + let data = vec![5, 9, 3]; + let iterout = vec![3, 5, 9]; + let pq = BinaryHeap::from(data); + + let v: Vec<_> = pq.into_iter().rev().collect(); + assert_eq!(v, iterout); +} + +#[test] +fn test_into_iter_sorted_collect() { + let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); + let it = heap.into_iter_sorted(); + let sorted = it.collect::>(); + assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]); +} + +#[test] +fn test_drain_sorted_collect() { + let mut heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); + let it = heap.drain_sorted(); + let sorted = it.collect::>(); + assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]); +} + +fn check_exact_size_iterator(len: usize, it: I) { + let mut it = it; + + for i in 0..it.len() { + let (lower, upper) = it.size_hint(); + assert_eq!(Some(lower), upper); + assert_eq!(lower, len - i); + assert_eq!(it.len(), len - i); + it.next(); + } + assert_eq!(it.len(), 0); + assert!(it.is_empty()); +} + +#[test] +fn test_exact_size_iterator() { + let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); + check_exact_size_iterator(heap.len(), heap.iter()); + check_exact_size_iterator(heap.len(), heap.clone().into_iter()); + check_exact_size_iterator(heap.len(), heap.clone().into_iter_sorted()); + check_exact_size_iterator(heap.len(), heap.clone().drain()); + check_exact_size_iterator(heap.len(), heap.clone().drain_sorted()); +} + +fn check_trusted_len(len: usize, it: I) { + let mut it = it; + for i in 0..len { + let (lower, upper) = it.size_hint(); + if upper.is_some() { + assert_eq!(Some(lower), upper); + assert_eq!(lower, len - i); + } + it.next(); + } +} + +#[test] +fn test_trusted_len() { + let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); + check_trusted_len(heap.len(), heap.clone().into_iter_sorted()); + check_trusted_len(heap.len(), heap.clone().drain_sorted()); +} + +#[test] +fn test_peek_and_pop() { + let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; + let mut sorted = data.clone(); + sorted.sort(); + let mut heap = BinaryHeap::from(data); + while !heap.is_empty() { + assert_eq!(heap.peek().unwrap(), sorted.last().unwrap()); + assert_eq!(heap.pop().unwrap(), sorted.pop().unwrap()); + } +} + +#[test] +fn test_peek_mut() { + let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; + let mut heap = BinaryHeap::from(data); + assert_eq!(heap.peek(), Some(&10)); + { + let mut top = heap.peek_mut().unwrap(); + *top -= 2; + } + assert_eq!(heap.peek(), Some(&9)); +} + +#[test] +fn test_peek_mut_leek() { + let data = vec![4, 2, 7]; + let mut heap = BinaryHeap::from(data); + let mut max = heap.peek_mut().unwrap(); + *max = -1; + + // The PeekMut object's Drop impl would have been responsible for moving the + // -1 out of the max position of the BinaryHeap, but we don't run it. + mem::forget(max); + + // Absent some mitigation like leak amplification, the -1 would incorrectly + // end up in the last position of the returned Vec, with the rest of the + // heap's original contents in front of it in sorted order. + let sorted_vec = heap.into_sorted_vec(); + assert!(sorted_vec.is_sorted(), "{:?}", sorted_vec); +} + +#[test] +fn test_peek_mut_pop() { + let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; + let mut heap = BinaryHeap::from(data); + assert_eq!(heap.peek(), Some(&10)); + { + let mut top = heap.peek_mut().unwrap(); + *top -= 2; + assert_eq!(PeekMut::pop(top), 8); + } + assert_eq!(heap.peek(), Some(&9)); +} + +#[test] +fn test_push() { + let mut heap = BinaryHeap::from(vec![2, 4, 9]); + assert_eq!(heap.len(), 3); + assert!(*heap.peek().unwrap() == 9); + heap.push(11); + assert_eq!(heap.len(), 4); + assert!(*heap.peek().unwrap() == 11); + heap.push(5); + assert_eq!(heap.len(), 5); + assert!(*heap.peek().unwrap() == 11); + heap.push(27); + assert_eq!(heap.len(), 6); + assert!(*heap.peek().unwrap() == 27); + heap.push(3); + assert_eq!(heap.len(), 7); + assert!(*heap.peek().unwrap() == 27); + heap.push(103); + assert_eq!(heap.len(), 8); + assert!(*heap.peek().unwrap() == 103); +} + +#[test] +fn test_push_unique() { + let mut heap = BinaryHeap::>::from(vec![Box::new(2), Box::new(4), Box::new(9)]); + assert_eq!(heap.len(), 3); + assert!(**heap.peek().unwrap() == 9); + heap.push(Box::new(11)); + assert_eq!(heap.len(), 4); + assert!(**heap.peek().unwrap() == 11); + heap.push(Box::new(5)); + assert_eq!(heap.len(), 5); + assert!(**heap.peek().unwrap() == 11); + heap.push(Box::new(27)); + assert_eq!(heap.len(), 6); + assert!(**heap.peek().unwrap() == 27); + heap.push(Box::new(3)); + assert_eq!(heap.len(), 7); + assert!(**heap.peek().unwrap() == 27); + heap.push(Box::new(103)); + assert_eq!(heap.len(), 8); + assert!(**heap.peek().unwrap() == 103); +} + +fn check_to_vec(mut data: Vec) { + let heap = BinaryHeap::from(data.clone()); + let mut v = heap.clone().into_vec(); + v.sort(); + data.sort(); + + assert_eq!(v, data); + assert_eq!(heap.into_sorted_vec(), data); +} + +#[test] +fn test_to_vec() { + check_to_vec(vec![]); + check_to_vec(vec![5]); + check_to_vec(vec![3, 2]); + check_to_vec(vec![2, 3]); + check_to_vec(vec![5, 1, 2]); + check_to_vec(vec![1, 100, 2, 3]); + check_to_vec(vec![1, 3, 5, 7, 9, 2, 4, 6, 8, 0]); + check_to_vec(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); + check_to_vec(vec![9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]); + check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + check_to_vec(vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]); + check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]); + check_to_vec(vec![5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]); +} + +#[test] +fn test_in_place_iterator_specialization() { + let src: Vec = vec![1, 2, 3]; + let src_ptr = src.as_ptr(); + let heap: BinaryHeap<_> = src.into_iter().map(std::convert::identity).collect(); + let heap_ptr = heap.iter().next().unwrap() as *const usize; + assert_eq!(src_ptr, heap_ptr); + let sink: Vec<_> = heap.into_iter().map(std::convert::identity).collect(); + let sink_ptr = sink.as_ptr(); + assert_eq!(heap_ptr, sink_ptr); +} + +#[test] +fn test_empty_pop() { + let mut heap = BinaryHeap::::new(); + assert!(heap.pop().is_none()); +} + +#[test] +fn test_empty_peek() { + let empty = BinaryHeap::::new(); + assert!(empty.peek().is_none()); +} + +#[test] +fn test_empty_peek_mut() { + let mut empty = BinaryHeap::::new(); + assert!(empty.peek_mut().is_none()); +} + +#[test] +fn test_from_iter() { + let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1]; + + let mut q: BinaryHeap<_> = xs.iter().rev().cloned().collect(); + + for &x in &xs { + assert_eq!(q.pop().unwrap(), x); + } +} + +#[test] +fn test_drain() { + let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect(); + + assert_eq!(q.drain().take(5).count(), 5); + + assert!(q.is_empty()); +} + +#[test] +fn test_drain_sorted() { + let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect(); + + assert_eq!(q.drain_sorted().take(5).collect::>(), vec![9, 8, 7, 6, 5]); + + assert!(q.is_empty()); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_drain_sorted_leak() { + let d0 = CrashTestDummy::new(0); + let d1 = CrashTestDummy::new(1); + let d2 = CrashTestDummy::new(2); + let d3 = CrashTestDummy::new(3); + let d4 = CrashTestDummy::new(4); + let d5 = CrashTestDummy::new(5); + let mut q = BinaryHeap::from(vec![ + d0.spawn(Panic::Never), + d1.spawn(Panic::Never), + d2.spawn(Panic::Never), + d3.spawn(Panic::InDrop), + d4.spawn(Panic::Never), + d5.spawn(Panic::Never), + ]); + + catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).unwrap_err(); + + assert_eq!(d0.dropped(), 1); + assert_eq!(d1.dropped(), 1); + assert_eq!(d2.dropped(), 1); + assert_eq!(d3.dropped(), 1); + assert_eq!(d4.dropped(), 1); + assert_eq!(d5.dropped(), 1); + assert!(q.is_empty()); +} + +#[test] +fn test_drain_forget() { + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); + let mut q = + BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]); + + catch_unwind(AssertUnwindSafe(|| { + let mut it = q.drain(); + it.next(); + mem::forget(it); + })) + .unwrap(); + // Behavior after leaking is explicitly unspecified and order is arbitrary, + // so it's fine if these start failing, but probably worth knowing. + assert!(q.is_empty()); + assert_eq!(a.dropped() + b.dropped() + c.dropped(), 1); + assert_eq!(a.dropped(), 0); + assert_eq!(b.dropped(), 0); + assert_eq!(c.dropped(), 1); + drop(q); + assert_eq!(a.dropped(), 0); + assert_eq!(b.dropped(), 0); + assert_eq!(c.dropped(), 1); +} + +#[test] +fn test_drain_sorted_forget() { + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); + let mut q = + BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]); + + catch_unwind(AssertUnwindSafe(|| { + let mut it = q.drain_sorted(); + it.next(); + mem::forget(it); + })) + .unwrap(); + // Behavior after leaking is explicitly unspecified, + // so it's fine if these start failing, but probably worth knowing. + assert_eq!(q.len(), 2); + assert_eq!(a.dropped(), 0); + assert_eq!(b.dropped(), 0); + assert_eq!(c.dropped(), 1); + drop(q); + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 1); + assert_eq!(c.dropped(), 1); +} + +#[test] +fn test_extend_ref() { + let mut a = BinaryHeap::new(); + a.push(1); + a.push(2); + + a.extend(&[3, 4, 5]); + + assert_eq!(a.len(), 5); + assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]); + + let mut a = BinaryHeap::new(); + a.push(1); + a.push(2); + let mut b = BinaryHeap::new(); + b.push(3); + b.push(4); + b.push(5); + + a.extend(&b); + + assert_eq!(a.len(), 5); + assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]); +} + +#[test] +fn test_append() { + let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]); + let mut b = BinaryHeap::from(vec![-20, 5, 43]); + + a.append(&mut b); + + assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]); + assert!(b.is_empty()); +} + +#[test] +fn test_append_to_empty() { + let mut a = BinaryHeap::new(); + let mut b = BinaryHeap::from(vec![-20, 5, 43]); + + a.append(&mut b); + + assert_eq!(a.into_sorted_vec(), [-20, 5, 43]); + assert!(b.is_empty()); +} + +#[test] +fn test_extend_specialization() { + let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]); + let b = BinaryHeap::from(vec![-20, 5, 43]); + + a.extend(b); + + assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]); +} + +#[allow(dead_code)] +fn assert_covariance() { + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { + d + } +} + +#[test] +fn test_retain() { + let mut a = BinaryHeap::from(vec![100, 10, 50, 1, 2, 20, 30]); + a.retain(|&x| x != 2); + + // Check that 20 moved into 10's place. + assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]); + + a.retain(|_| true); + + assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]); + + a.retain(|&x| x < 50); + + assert_eq!(a.clone().into_vec(), [30, 20, 10, 1]); + + a.retain(|_| false); + + assert!(a.is_empty()); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_retain_catch_unwind() { + let mut heap = BinaryHeap::from(vec![3, 1, 2]); + + // Removes the 3, then unwinds out of retain. + let _ = catch_unwind(AssertUnwindSafe(|| { + heap.retain(|e| { + if *e == 1 { + panic!(); + } + false + }); + })); + + // Naively this would be [1, 2] (an invalid heap) if BinaryHeap delegates to + // Vec's retain impl and then does not rebuild the heap after that unwinds. + assert_eq!(heap.into_vec(), [2, 1]); +} + +// old binaryheap failed this test +// +// Integrity means that all elements are present after a comparison panics, +// even if the order might not be correct. +// +// Destructors must be called exactly once per element. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn panic_safe() { + use std::cmp; + use std::panic::{self, AssertUnwindSafe}; + use std::sync::atomic::{AtomicUsize, Ordering}; + + use rand::seq::SliceRandom; + + static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); + + #[derive(Eq, PartialEq, Ord, Clone, Debug)] + struct PanicOrd(T, bool); + + impl Drop for PanicOrd { + fn drop(&mut self) { + // update global drop count + DROP_COUNTER.fetch_add(1, Ordering::SeqCst); + } + } + + impl PartialOrd for PanicOrd { + fn partial_cmp(&self, other: &Self) -> Option { + if self.1 || other.1 { + panic!("Panicking comparison"); + } + self.0.partial_cmp(&other.0) + } + } + let mut rng = crate::test_rng(); + const DATASZ: usize = 32; + // Miri is too slow + let ntest = if cfg!(miri) { 1 } else { 10 }; + + // don't use 0 in the data -- we want to catch the zeroed-out case. + let data = (1..=DATASZ).collect::>(); + + // since it's a fuzzy test, run several tries. + for _ in 0..ntest { + for i in 1..=DATASZ { + DROP_COUNTER.store(0, Ordering::SeqCst); + + let mut panic_ords: Vec<_> = + data.iter().filter(|&&x| x != i).map(|&x| PanicOrd(x, false)).collect(); + let panic_item = PanicOrd(i, true); + + // heapify the sane items + panic_ords.shuffle(&mut rng); + let mut heap = BinaryHeap::from(panic_ords); + let inner_data; + + { + // push the panicking item to the heap and catch the panic + let thread_result = { + let mut heap_ref = AssertUnwindSafe(&mut heap); + panic::catch_unwind(move || { + heap_ref.push(panic_item); + }) + }; + assert!(thread_result.is_err()); + + // Assert no elements were dropped + let drops = DROP_COUNTER.load(Ordering::SeqCst); + assert!(drops == 0, "Must not drop items. drops={}", drops); + inner_data = heap.clone().into_vec(); + drop(heap); + } + let drops = DROP_COUNTER.load(Ordering::SeqCst); + assert_eq!(drops, DATASZ); + + let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::>(); + data_sorted.sort(); + assert_eq!(data_sorted, data); + } + } +} diff --git a/library/alloctests/tests/collections/mod.rs b/library/alloctests/tests/collections/mod.rs new file mode 100644 index 00000000000..e73f3aaef8c --- /dev/null +++ b/library/alloctests/tests/collections/mod.rs @@ -0,0 +1 @@ +mod binary_heap; diff --git a/library/alloctests/tests/const_fns.rs b/library/alloctests/tests/const_fns.rs new file mode 100644 index 00000000000..4e7d7fc833e --- /dev/null +++ b/library/alloctests/tests/const_fns.rs @@ -0,0 +1,38 @@ +// Test const functions in the library + +pub const MY_VEC: Vec = Vec::new(); + +// FIXME(#110395) +// pub const MY_VEC2: Vec = Default::default(); + +pub const MY_STRING: String = String::new(); + +// pub const MY_STRING2: String = Default::default(); + +// pub const MY_BOXED_SLICE: Box<[usize]> = Default::default(); +// pub const MY_BOXED_STR: Box = Default::default(); + +use std::collections::{BTreeMap, BTreeSet}; + +pub const MY_BTREEMAP: BTreeMap = BTreeMap::new(); +pub const MAP: &'static BTreeMap = &MY_BTREEMAP; +pub const MAP_LEN: usize = MAP.len(); +pub const MAP_IS_EMPTY: bool = MAP.is_empty(); + +pub const MY_BTREESET: BTreeSet = BTreeSet::new(); +pub const SET: &'static BTreeSet = &MY_BTREESET; +pub const SET_LEN: usize = SET.len(); +pub const SET_IS_EMPTY: bool = SET.is_empty(); + +#[test] +fn test_const() { + assert_eq!(MY_VEC, /* MY_VEC */ vec![]); + assert_eq!(MY_STRING, /* MY_STRING2 */ String::default()); + + // assert_eq!(MY_VEC, *MY_BOXED_SLICE); + // assert_eq!(MY_STRING, *MY_BOXED_STR); + + assert_eq!(MAP_LEN, 0); + assert_eq!(SET_LEN, 0); + assert!(MAP_IS_EMPTY && SET_IS_EMPTY); +} diff --git a/library/alloctests/tests/cow_str.rs b/library/alloctests/tests/cow_str.rs new file mode 100644 index 00000000000..62a5c245a54 --- /dev/null +++ b/library/alloctests/tests/cow_str.rs @@ -0,0 +1,144 @@ +use std::borrow::Cow; + +// check that Cow<'a, str> implements addition +#[test] +fn check_cow_add_cow() { + let borrowed1 = Cow::Borrowed("Hello, "); + let borrowed2 = Cow::Borrowed("World!"); + let borrow_empty = Cow::Borrowed(""); + + let owned1: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); + let owned2: Cow<'_, str> = Cow::Owned(String::from("Rustaceans!")); + let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); + + assert_eq!("Hello, World!", borrowed1.clone() + borrowed2.clone()); + assert_eq!("Hello, Rustaceans!", borrowed1.clone() + owned2.clone()); + + assert_eq!("Hi, World!", owned1.clone() + borrowed2.clone()); + assert_eq!("Hi, Rustaceans!", owned1.clone() + owned2.clone()); + + if let Cow::Owned(_) = borrowed1.clone() + borrow_empty.clone() { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = borrow_empty.clone() + borrowed1.clone() { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = borrowed1.clone() + owned_empty.clone() { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = owned_empty.clone() + borrowed1.clone() { + panic!("Adding empty strings to a borrow should note allocate"); + } +} + +#[test] +fn check_cow_add_str() { + let borrowed = Cow::Borrowed("Hello, "); + let borrow_empty = Cow::Borrowed(""); + + let owned: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); + let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); + + assert_eq!("Hello, World!", borrowed.clone() + "World!"); + + assert_eq!("Hi, World!", owned.clone() + "World!"); + + if let Cow::Owned(_) = borrowed.clone() + "" { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = borrow_empty.clone() + "Hello, " { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = owned_empty.clone() + "Hello, " { + panic!("Adding empty strings to a borrow should note allocate"); + } +} + +#[test] +fn check_cow_add_assign_cow() { + let mut borrowed1 = Cow::Borrowed("Hello, "); + let borrowed2 = Cow::Borrowed("World!"); + let borrow_empty = Cow::Borrowed(""); + + let mut owned1: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); + let owned2: Cow<'_, str> = Cow::Owned(String::from("Rustaceans!")); + let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); + + let mut s = borrowed1.clone(); + s += borrow_empty.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrow_empty.clone(); + s += borrowed1.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrowed1.clone(); + s += owned_empty.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = owned_empty.clone(); + s += borrowed1.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + + owned1 += borrowed2; + borrowed1 += owned2; + + assert_eq!("Hi, World!", owned1); + assert_eq!("Hello, Rustaceans!", borrowed1); +} + +#[test] +fn check_cow_add_assign_str() { + let mut borrowed = Cow::Borrowed("Hello, "); + let borrow_empty = Cow::Borrowed(""); + + let mut owned: Cow<'_, str> = Cow::Owned(String::from("Hi, ")); + let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); + + let mut s = borrowed.clone(); + s += ""; + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrow_empty.clone(); + s += "World!"; + assert_eq!("World!", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = owned_empty.clone(); + s += "World!"; + assert_eq!("World!", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + + owned += "World!"; + borrowed += "World!"; + + assert_eq!("Hi, World!", owned); + assert_eq!("Hello, World!", borrowed); +} + +#[test] +fn check_cow_clone_from() { + let mut c1: Cow<'_, str> = Cow::Owned(String::with_capacity(25)); + let s: String = "hi".to_string(); + assert!(s.capacity() < 25); + let c2: Cow<'_, str> = Cow::Owned(s); + c1.clone_from(&c2); + assert!(c1.into_owned().capacity() >= 25); + let mut c3: Cow<'_, str> = Cow::Borrowed("bye"); + c3.clone_from(&c2); + assert_eq!(c2, c3); +} diff --git a/library/alloctests/tests/fmt.rs b/library/alloctests/tests/fmt.rs new file mode 100644 index 00000000000..c13074c53b7 --- /dev/null +++ b/library/alloctests/tests/fmt.rs @@ -0,0 +1,326 @@ +#![deny(warnings)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + +use std::cell::RefCell; +use std::fmt::{self, Write}; +use std::ptr; + +#[test] +fn test_format() { + let s = fmt::format(format_args!("Hello, {}!", "world")); + assert_eq!(s, "Hello, world!"); +} + +struct A; +struct B; +struct C; +struct D; + +impl fmt::LowerHex for A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("aloha") + } +} +impl fmt::UpperHex for B { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("adios") + } +} +impl fmt::Display for C { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad_integral(true, "☃", "123") + } +} +impl fmt::Binary for D { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("aa")?; + f.write_char('☃')?; + f.write_str("bb") + } +} + +macro_rules! t { + ($a:expr, $b:expr) => { + assert_eq!($a, $b) + }; +} + +#[test] +fn test_format_macro_interface() { + // Various edge cases without formats + t!(format!(""), ""); + t!(format!("hello"), "hello"); + t!(format!("hello {{"), "hello {"); + + // default formatters should work + t!(format!("{}", 1.0f32), "1"); + t!(format!("{}", 1.0f64), "1"); + t!(format!("{}", "a"), "a"); + t!(format!("{}", "a".to_string()), "a"); + t!(format!("{}", false), "false"); + t!(format!("{}", 'a'), "a"); + + // At least exercise all the formats + t!(format!("{}", true), "true"); + t!(format!("{}", '☃'), "☃"); + t!(format!("{}", 10), "10"); + t!(format!("{}", 10_usize), "10"); + t!(format!("{:?}", '☃'), "'☃'"); + t!(format!("{:?}", 10), "10"); + t!(format!("{:?}", 10_usize), "10"); + t!(format!("{:?}", "true"), "\"true\""); + t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\""); + t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), r#""foo\n\"bar\"\r\n'baz'\t\\qux\\""#); + t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), r#""foo\0bar\u{1}baz\u{7f}qux""#); + t!(format!("{:o}", 10_usize), "12"); + t!(format!("{:x}", 10_usize), "a"); + t!(format!("{:X}", 10_usize), "A"); + t!(format!("{}", "foo"), "foo"); + t!(format!("{}", "foo".to_string()), "foo"); + if cfg!(target_pointer_width = "32") { + t!(format!("{:#p}", ptr::without_provenance::(0x1234)), "0x00001234"); + t!(format!("{:#p}", ptr::without_provenance_mut::(0x1234)), "0x00001234"); + } else { + t!(format!("{:#p}", ptr::without_provenance::(0x1234)), "0x0000000000001234"); + t!(format!("{:#p}", ptr::without_provenance_mut::(0x1234)), "0x0000000000001234"); + } + t!(format!("{:p}", ptr::without_provenance::(0x1234)), "0x1234"); + t!(format!("{:p}", ptr::without_provenance_mut::(0x1234)), "0x1234"); + t!(format!("{A:x}"), "aloha"); + t!(format!("{B:X}"), "adios"); + t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); + t!(format!("{1} {0}", 0, 1), "1 0"); + t!(format!("{foo} {bar}", foo = 0, bar = 1), "0 1"); + t!(format!("{foo} {1} {bar} {0}", 0, 1, foo = 2, bar = 3), "2 1 3 0"); + t!(format!("{} {0}", "a"), "a a"); + t!(format!("{_foo}", _foo = 6usize), "6"); + t!(format!("{foo_bar}", foo_bar = 1), "1"); + t!(format!("{}", 5 + 5), "10"); + t!(format!("{C:#4}"), "☃123"); + t!(format!("{D:b}"), "aa☃bb"); + + let a: &dyn fmt::Debug = &1; + t!(format!("{a:?}"), "1"); + + // Formatting strings and their arguments + t!(format!("{}", "a"), "a"); + t!(format!("{:4}", "a"), "a "); + t!(format!("{:4}", "☃"), "☃ "); + t!(format!("{:>4}", "a"), " a"); + t!(format!("{:<4}", "a"), "a "); + t!(format!("{:^5}", "a"), " a "); + t!(format!("{:^5}", "aa"), " aa "); + t!(format!("{:^4}", "a"), " a "); + t!(format!("{:^4}", "aa"), " aa "); + t!(format!("{:.4}", "a"), "a"); + t!(format!("{:4.4}", "a"), "a "); + t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), " aaaa"); + t!(format!("{:2.4}", "aaaaa"), "aaaa"); + t!(format!("{:2.4}", "aaaa"), "aaaa"); + t!(format!("{:2.4}", "aaa"), "aaa"); + t!(format!("{:2.4}", "aa"), "aa"); + t!(format!("{:2.4}", "a"), "a "); + t!(format!("{:0>2}", "a"), "0a"); + t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); + t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4), "aaaa"); + t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4), "aaaa"); + t!(format!("{:1$}", "a", 4), "a "); + t!(format!("{1:0$}", 4, "a"), "a "); + t!(format!("{:a$}", "a", a = 4), "a "); + t!(format!("{:-#}", "a"), "a"); + t!(format!("{:+#}", "a"), "a"); + t!(format!("{:/^10.8}", "1234567890"), "/12345678/"); + + // Some float stuff + t!(format!("{:}", 1.0f32), "1"); + t!(format!("{:}", 1.0f64), "1"); + t!(format!("{:.3}", 1.0f64), "1.000"); + t!(format!("{:10.3}", 1.0f64), " 1.000"); + t!(format!("{:+10.3}", 1.0f64), " +1.000"); + t!(format!("{:+10.3}", -1.0f64), " -1.000"); + + t!(format!("{:e}", 1.2345e6f32), "1.2345e6"); + t!(format!("{:e}", 1.2345e6f64), "1.2345e6"); + t!(format!("{:E}", 1.2345e6f64), "1.2345E6"); + t!(format!("{:.3e}", 1.2345e6f64), "1.234e6"); + t!(format!("{:10.3e}", 1.2345e6f64), " 1.234e6"); + t!(format!("{:+10.3e}", 1.2345e6f64), " +1.234e6"); + t!(format!("{:+10.3e}", -1.2345e6f64), " -1.234e6"); + + // Float edge cases + t!(format!("{}", -0.0), "-0"); + t!(format!("{:?}", 0.0), "0.0"); + + // sign aware zero padding + t!(format!("{:<3}", 1), "1 "); + t!(format!("{:>3}", 1), " 1"); + t!(format!("{:^3}", 1), " 1 "); + t!(format!("{:03}", 1), "001"); + t!(format!("{:<03}", 1), "001"); + t!(format!("{:>03}", 1), "001"); + t!(format!("{:^03}", 1), "001"); + t!(format!("{:+03}", 1), "+01"); + t!(format!("{:<+03}", 1), "+01"); + t!(format!("{:>+03}", 1), "+01"); + t!(format!("{:^+03}", 1), "+01"); + t!(format!("{:#05x}", 1), "0x001"); + t!(format!("{:<#05x}", 1), "0x001"); + t!(format!("{:>#05x}", 1), "0x001"); + t!(format!("{:^#05x}", 1), "0x001"); + t!(format!("{:05}", 1.2), "001.2"); + t!(format!("{:<05}", 1.2), "001.2"); + t!(format!("{:>05}", 1.2), "001.2"); + t!(format!("{:^05}", 1.2), "001.2"); + t!(format!("{:05}", -1.2), "-01.2"); + t!(format!("{:<05}", -1.2), "-01.2"); + t!(format!("{:>05}", -1.2), "-01.2"); + t!(format!("{:^05}", -1.2), "-01.2"); + t!(format!("{:+05}", 1.2), "+01.2"); + t!(format!("{:<+05}", 1.2), "+01.2"); + t!(format!("{:>+05}", 1.2), "+01.2"); + t!(format!("{:^+05}", 1.2), "+01.2"); + + // Ergonomic format_args! + t!(format!("{0:x} {0:X}", 15), "f F"); + t!(format!("{0:x} {0:X} {}", 15), "f F 15"); + t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a = 15), "dDfEeF"); + t!(format!("{a:x} {a:X}", a = 15), "f F"); + + // And its edge cases + t!( + format!( + "{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}", + 4, + a = "abcdefg", + b = "hijklmn", + c = 3 + ), + "abcd hijk 4\nabc hij 3" + ); + t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a = "abcdef"), "abcd 4 efg"); + t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a = 2), "aa 2 0x2"); + + // Test that pointers don't get truncated. + { + let val = usize::MAX; + let exp = format!("{val:#x}"); + t!(format!("{:p}", std::ptr::without_provenance::(val)), exp); + } + + // Escaping + t!(format!("{{"), "{"); + t!(format!("}}"), "}"); + + // make sure that format! doesn't move out of local variables + let a = Box::new(3); + let _ = format!("{a}"); + let _ = format!("{a}"); + + // make sure that format! doesn't cause spurious unused-unsafe warnings when + // it's inside of an outer unsafe block + unsafe { + let a: isize = ::std::mem::transmute(3_usize); + let _ = format!("{a}"); + } + + // test that trailing commas are acceptable + let _ = format!("{}", "test",); + let _ = format!("{foo}", foo = "test",); +} + +// Basic test to make sure that we can invoke the `write!` macro with an +// fmt::Write instance. +#[test] +fn test_write() { + let mut buf = String::new(); + let _ = write!(&mut buf, "{}", 3); + { + let w = &mut buf; + let _ = write!(w, "{foo}", foo = 4); + let _ = write!(w, "{}", "hello"); + let _ = writeln!(w, "{}", "line"); + let _ = writeln!(w, "{foo}", foo = "bar"); + let _ = w.write_char('☃'); + let _ = w.write_str("str"); + } + + t!(buf, "34helloline\nbar\n☃str"); +} + +// Just make sure that the macros are defined, there's not really a lot that we +// can do with them just yet (to test the output) +#[test] +fn test_print() { + print!("hi"); + print!("{:?}", vec![0u8]); + println!("hello"); + println!("this is a {}", "test"); + println!("{foo}", foo = "bar"); +} + +// Just make sure that the macros are defined, there's not really a lot that we +// can do with them just yet (to test the output) +#[test] +fn test_format_args() { + let mut buf = String::new(); + { + let w = &mut buf; + let _ = write!(w, "{}", format_args!("{}", 1)); + let _ = write!(w, "{}", format_args!("test")); + let _ = write!(w, "{}", format_args!("{test}", test = 3)); + } + let s = buf; + t!(s, "1test3"); + + let s = fmt::format(format_args!("hello {}", "world")); + t!(s, "hello world"); + let s = format!("{}: {}", "args were", format_args!("hello {}", "world")); + t!(s, "args were: hello world"); +} + +#[test] +fn test_order() { + // Make sure format!() arguments are always evaluated in a left-to-right + // ordering + fn foo() -> isize { + static mut FOO: isize = 0; + unsafe { + FOO += 1; + FOO + } + } + assert_eq!( + format!("{} {} {a} {b} {} {c}", foo(), foo(), foo(), a = foo(), b = foo(), c = foo()), + "1 2 4 5 3 6".to_string() + ); +} + +#[test] +fn test_once() { + // Make sure each argument are evaluated only once even though it may be + // formatted multiple times + fn foo() -> isize { + static mut FOO: isize = 0; + unsafe { + FOO += 1; + FOO + } + } + assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a = foo()), "1 1 1 2 2 2".to_string()); +} + +#[test] +fn test_refcell() { + let refcell = RefCell::new(5); + assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }"); + let borrow = refcell.borrow_mut(); + assert_eq!(format!("{refcell:?}"), "RefCell { value: }"); + drop(borrow); + assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }"); +} diff --git a/library/alloctests/tests/heap.rs b/library/alloctests/tests/heap.rs new file mode 100644 index 00000000000..246b341eeb3 --- /dev/null +++ b/library/alloctests/tests/heap.rs @@ -0,0 +1,44 @@ +use std::alloc::{Allocator, Global, Layout, System}; + +/// Issue #45955 and #62251. +#[test] +fn alloc_system_overaligned_request() { + check_overalign_requests(System) +} + +#[test] +fn std_heap_overaligned_request() { + check_overalign_requests(Global) +} + +fn check_overalign_requests(allocator: T) { + for &align in &[4, 8, 16, 32] { + // less than and bigger than `MIN_ALIGN` + for &size in &[align / 2, align - 1] { + // size less than alignment + let iterations = 128; + unsafe { + let pointers: Vec<_> = (0..iterations) + .map(|_| { + allocator.allocate(Layout::from_size_align(size, align).unwrap()).unwrap() + }) + .collect(); + for &ptr in &pointers { + assert_eq!( + (ptr.as_non_null_ptr().as_ptr() as usize) % align, + 0, + "Got a pointer less aligned than requested" + ) + } + + // Clean up + for &ptr in &pointers { + allocator.deallocate( + ptr.as_non_null_ptr(), + Layout::from_size_align(size, align).unwrap(), + ) + } + } + } + } +} diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs new file mode 100644 index 00000000000..46c11ea150b --- /dev/null +++ b/library/alloctests/tests/lib.rs @@ -0,0 +1,107 @@ +#![feature(allocator_api)] +#![feature(alloc_layout_extra)] +#![feature(iter_array_chunks)] +#![feature(assert_matches)] +#![feature(btree_extract_if)] +#![feature(char_max_len)] +#![feature(cow_is_borrowed)] +#![feature(core_intrinsics)] +#![feature(downcast_unchecked)] +#![feature(exact_size_is_empty)] +#![feature(hashmap_internals)] +#![feature(linked_list_cursors)] +#![feature(map_try_insert)] +#![feature(pattern)] +#![feature(trusted_len)] +#![feature(try_reserve_kind)] +#![feature(try_with_capacity)] +#![feature(unboxed_closures)] +#![feature(binary_heap_into_iter_sorted)] +#![feature(binary_heap_drain_sorted)] +#![feature(slice_ptr_get)] +#![feature(inplace_iteration)] +#![feature(iter_advance_by)] +#![feature(iter_next_chunk)] +#![feature(round_char_boundary)] +#![feature(slice_partition_dedup)] +#![feature(string_from_utf8_lossy_owned)] +#![feature(string_remove_matches)] +#![feature(const_btree_len)] +#![feature(const_trait_impl)] +#![feature(panic_update_hook)] +#![feature(pointer_is_aligned_to)] +#![feature(test)] +#![feature(thin_box)] +#![feature(drain_keep_rest)] +#![feature(local_waker)] +#![feature(str_as_str)] +#![feature(strict_provenance_lints)] +#![feature(vec_deque_pop_if)] +#![feature(unique_rc_arc)] +#![feature(macro_metavar_expr_concat)] +#![allow(internal_features)] +#![deny(fuzzy_provenance_casts)] +#![deny(unsafe_op_in_unsafe_fn)] + +extern crate alloc; +extern crate test; + +use std::hash::{DefaultHasher, Hash, Hasher}; + +mod alloc_test; +mod arc; +mod autotraits; +mod borrow; +mod boxed; +mod btree_set_hash; +mod c_str; +mod c_str2; +mod collections; +mod const_fns; +mod cow_str; +mod fmt; +mod heap; +mod linked_list; +mod misc_tests; +mod rc; +mod slice; +mod sort; +mod str; +mod string; +mod sync; +mod task; +mod testing; +mod thin_box; +mod vec; +mod vec_deque; + +fn hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() +} + +/// Copied from `std::test_helpers::test_rng`, since these tests rely on the +/// seed not being the same for every RNG invocation too. +fn test_rng() -> rand_xorshift::XorShiftRng { + use std::hash::{BuildHasher, Hash, Hasher}; + let mut hasher = std::hash::RandomState::new().build_hasher(); + std::panic::Location::caller().hash(&mut hasher); + let hc64 = hasher.finish(); + let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); + let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); + rand::SeedableRng::from_seed(seed) +} + +#[test] +fn test_boxed_hasher() { + let ordinary_hash = hash(&5u32); + + let mut hasher_1 = Box::new(DefaultHasher::new()); + 5u32.hash(&mut hasher_1); + assert_eq!(ordinary_hash, hasher_1.finish()); + + let mut hasher_2 = Box::new(DefaultHasher::new()) as Box; + 5u32.hash(&mut hasher_2); + assert_eq!(ordinary_hash, hasher_2.finish()); +} diff --git a/library/alloctests/tests/linked_list.rs b/library/alloctests/tests/linked_list.rs new file mode 100644 index 00000000000..65b09cb00c4 --- /dev/null +++ b/library/alloctests/tests/linked_list.rs @@ -0,0 +1,21 @@ +use std::collections::LinkedList; + +#[test] +fn test_hash() { + use crate::hash; + + let mut x = LinkedList::new(); + let mut y = LinkedList::new(); + + assert!(hash(&x) == hash(&y)); + + x.push_back(1); + x.push_back(2); + x.push_back(3); + + y.push_front(3); + y.push_front(2); + y.push_front(1); + + assert!(hash(&x) == hash(&y)); +} diff --git a/library/alloctests/tests/misc_tests.rs b/library/alloctests/tests/misc_tests.rs new file mode 100644 index 00000000000..b95d11cb07e --- /dev/null +++ b/library/alloctests/tests/misc_tests.rs @@ -0,0 +1,140 @@ +//! Test for `boxed` mod. + +use core::any::Any; +use core::ops::Deref; +use std::boxed::Box; + +#[test] +fn test_owned_clone() { + let a = Box::new(5); + let b: Box = a.clone(); + assert!(a == b); +} + +#[derive(Debug, PartialEq, Eq)] +struct Test; + +#[test] +fn any_move() { + let a = Box::new(8) as Box; + let b = Box::new(Test) as Box; + + let a: Box = a.downcast::().unwrap(); + assert_eq!(*a, 8); + + let b: Box = b.downcast::().unwrap(); + assert_eq!(*b, Test); + + let a = Box::new(8) as Box; + let b = Box::new(Test) as Box; + + assert!(a.downcast::>().is_err()); + assert!(b.downcast::>().is_err()); +} + +#[test] +fn test_show() { + let a = Box::new(8) as Box; + let b = Box::new(Test) as Box; + let a_str = format!("{a:?}"); + let b_str = format!("{b:?}"); + assert_eq!(a_str, "Any { .. }"); + assert_eq!(b_str, "Any { .. }"); + + static EIGHT: usize = 8; + static TEST: Test = Test; + let a = &EIGHT as &dyn Any; + let b = &TEST as &dyn Any; + let s = format!("{a:?}"); + assert_eq!(s, "Any { .. }"); + let s = format!("{b:?}"); + assert_eq!(s, "Any { .. }"); +} + +#[test] +fn deref() { + fn homura>(_: T) {} + homura(Box::new(765)); +} + +#[test] +fn raw_sized() { + let x = Box::new(17); + let p = Box::into_raw(x); + unsafe { + assert_eq!(17, *p); + *p = 19; + let y = Box::from_raw(p); + assert_eq!(19, *y); + } +} + +#[test] +fn raw_trait() { + trait Foo { + fn get(&self) -> u32; + fn set(&mut self, value: u32); + } + + struct Bar(u32); + + impl Foo for Bar { + fn get(&self) -> u32 { + self.0 + } + + fn set(&mut self, value: u32) { + self.0 = value; + } + } + + let x: Box = Box::new(Bar(17)); + let p = Box::into_raw(x); + unsafe { + assert_eq!(17, (*p).get()); + (*p).set(19); + let y: Box = Box::from_raw(p); + assert_eq!(19, y.get()); + } +} + +#[test] +fn f64_slice() { + let slice: &[f64] = &[-1.0, 0.0, 1.0, f64::INFINITY]; + let boxed: Box<[f64]> = Box::from(slice); + assert_eq!(&*boxed, slice) +} + +#[test] +fn i64_slice() { + let slice: &[i64] = &[i64::MIN, -2, -1, 0, 1, 2, i64::MAX]; + let boxed: Box<[i64]> = Box::from(slice); + assert_eq!(&*boxed, slice) +} + +#[test] +fn str_slice() { + let s = "Hello, world!"; + let boxed: Box = Box::from(s); + assert_eq!(&*boxed, s) +} + +#[test] +fn boxed_slice_from_iter() { + let iter = 0..100; + let boxed: Box<[u32]> = iter.collect(); + assert_eq!(boxed.len(), 100); + assert_eq!(boxed[7], 7); +} + +#[test] +fn test_array_from_slice() { + let v = vec![1, 2, 3]; + let r: Box<[u32]> = v.into_boxed_slice(); + + let a: Result, _> = r.clone().try_into(); + assert!(a.is_ok()); + + let a: Result, _> = r.clone().try_into(); + assert!(a.is_err()); +} diff --git a/library/alloctests/tests/rc.rs b/library/alloctests/tests/rc.rs new file mode 100644 index 00000000000..9d82a7621a2 --- /dev/null +++ b/library/alloctests/tests/rc.rs @@ -0,0 +1,259 @@ +use std::any::Any; +use std::cell::{Cell, RefCell}; +use std::iter::TrustedLen; +use std::rc::{Rc, Weak}; + +#[test] +fn uninhabited() { + enum Void {} + let mut a = Weak::::new(); + a = a.clone(); + assert!(a.upgrade().is_none()); + + let mut a: Weak = a; // Unsizing + a = a.clone(); + assert!(a.upgrade().is_none()); +} + +#[test] +fn slice() { + let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]); + let a: Rc<[u32]> = a; // Unsizing + let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion + assert_eq!(a, b); + + // Exercise is_dangling() with a DST + let mut a = Rc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); +} + +#[test] +fn trait_object() { + let a: Rc = Rc::new(4); + let a: Rc = a; // Unsizing + + // Exercise is_dangling() with a DST + let mut a = Rc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); + + let mut b = Weak::::new(); + b = b.clone(); + assert!(b.upgrade().is_none()); + let mut b: Weak = b; // Unsizing + b = b.clone(); + assert!(b.upgrade().is_none()); +} + +#[test] +fn float_nan_ne() { + let x = Rc::new(f32::NAN); + assert!(x != x); + assert!(!(x == x)); +} + +#[test] +fn partial_eq() { + struct TestPEq(RefCell); + impl PartialEq for TestPEq { + fn eq(&self, other: &TestPEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Rc::new(TestPEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 4); +} + +#[test] +fn eq() { + #[derive(Eq)] + struct TestEq(RefCell); + impl PartialEq for TestEq { + fn eq(&self, other: &TestEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Rc::new(TestEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 0); +} + +const SHARED_ITER_MAX: u16 = 100; + +fn assert_trusted_len(_: &I) {} + +#[test] +fn shared_from_iter_normal() { + // Exercise the base implementation for non-`TrustedLen` iterators. + { + // `Filter` is never `TrustedLen` since we don't + // know statically how many elements will be kept: + let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new); + + // Collecting into a `Vec` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. +} + +#[test] +fn shared_from_iter_trustedlen_normal() { + // Exercise the `TrustedLen` implementation under normal circumstances + // where `size_hint()` matches `(_, Some(exact_len))`. + { + let iter = (0..SHARED_ITER_MAX).map(Box::new); + assert_trusted_len(&iter); + + // Collecting into a `Vec` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + assert_eq!(size_of::>() * SHARED_ITER_MAX as usize, size_of_val(&*rc)); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. + + // Try a ZST to make sure it is handled well. + { + let iter = (0..SHARED_ITER_MAX).map(drop); + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + assert_eq!(0, size_of_val(&*rc)); + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } +} + +#[test] +#[should_panic = "I've almost got 99 problems."] +fn shared_from_iter_trustedlen_panic() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where `.next()` drops before the last iteration. + let iter = (0..SHARED_ITER_MAX).map(|val| match val { + 98 => panic!("I've almost got 99 problems."), + _ => Box::new(val), + }); + assert_trusted_len(&iter); + let _ = iter.collect::>(); + + panic!("I am unreachable."); +} + +#[test] +fn shared_from_iter_trustedlen_no_fuse() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner. + struct Iter(std::vec::IntoIter>>); + + unsafe impl TrustedLen for Iter {} + + impl Iterator for Iter { + fn size_hint(&self) -> (usize, Option) { + (2, Some(2)) + } + + type Item = Box; + + fn next(&mut self) -> Option { + self.0.next().flatten() + } + } + + let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))]; + let iter = Iter(vec.into_iter()); + assert_trusted_len(&iter); + assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::>()); +} + +#[test] +fn weak_may_dangle() { + fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> { + val.clone() + } + + // Without #[may_dangle] we get: + let mut val = Weak::new(); + hmm(&mut val); + // ~~~~~~~~ borrowed value does not live long enough + // + // `val` dropped here while still borrowed + // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak` +} + +/// Test that a panic from a destructor does not leak the allocation. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn panic_no_leak() { + use std::alloc::{AllocError, Allocator, Global, Layout}; + use std::panic::{AssertUnwindSafe, catch_unwind}; + use std::ptr::NonNull; + + struct AllocCount(Cell); + unsafe impl Allocator for AllocCount { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + self.0.set(self.0.get() + 1); + Global.allocate(layout) + } + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + self.0.set(self.0.get() - 1); + unsafe { Global.deallocate(ptr, layout) } + } + } + + struct PanicOnDrop; + impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("PanicOnDrop"); + } + } + + let alloc = AllocCount(Cell::new(0)); + let rc = Rc::new_in(PanicOnDrop, &alloc); + assert_eq!(alloc.0.get(), 1); + + let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); + assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); + assert_eq!(alloc.0.get(), 0); +} + +#[allow(unused)] +mod pin_coerce_unsized { + use alloc::rc::{Rc, UniqueRc}; + use core::pin::Pin; + + pub trait MyTrait {} + impl MyTrait for String {} + + // Pin coercion should work for Rc + pub fn pin_rc(arg: Pin>) -> Pin> { + arg + } + pub fn pin_unique_rc(arg: Pin>) -> Pin> { + arg + } +} diff --git a/library/alloctests/tests/slice.rs b/library/alloctests/tests/slice.rs new file mode 100644 index 00000000000..2516563187f --- /dev/null +++ b/library/alloctests/tests/slice.rs @@ -0,0 +1,1668 @@ +use std::cmp::Ordering::{Equal, Greater, Less}; +use std::convert::identity; +use std::rc::Rc; +use std::{fmt, panic}; + +fn square(n: usize) -> usize { + n * n +} + +fn is_odd(n: &usize) -> bool { + *n % 2 == 1 +} + +#[test] +fn test_from_fn() { + // Test on-stack from_fn. + let mut v: Vec<_> = (0..3).map(square).collect(); + { + let v = v; + assert_eq!(v.len(), 3); + assert_eq!(v[0], 0); + assert_eq!(v[1], 1); + assert_eq!(v[2], 4); + } + + // Test on-heap from_fn. + v = (0..5).map(square).collect(); + { + let v = v; + assert_eq!(v.len(), 5); + assert_eq!(v[0], 0); + assert_eq!(v[1], 1); + assert_eq!(v[2], 4); + assert_eq!(v[3], 9); + assert_eq!(v[4], 16); + } +} + +#[test] +fn test_from_elem() { + // Test on-stack from_elem. + let mut v = vec![10, 10]; + { + let v = v; + assert_eq!(v.len(), 2); + assert_eq!(v[0], 10); + assert_eq!(v[1], 10); + } + + // Test on-heap from_elem. + v = vec![20; 6]; + { + let v = &v[..]; + assert_eq!(v[0], 20); + assert_eq!(v[1], 20); + assert_eq!(v[2], 20); + assert_eq!(v[3], 20); + assert_eq!(v[4], 20); + assert_eq!(v[5], 20); + } +} + +#[test] +fn test_is_empty() { + let xs: [i32; 0] = []; + assert!(xs.is_empty()); + assert!(![0].is_empty()); +} + +#[test] +fn test_len_divzero() { + type Z = [i8; 0]; + let v0: &[Z] = &[]; + let v1: &[Z] = &[[]]; + let v2: &[Z] = &[[], []]; + assert_eq!(size_of::(), 0); + assert_eq!(v0.len(), 0); + assert_eq!(v1.len(), 1); + assert_eq!(v2.len(), 2); +} + +#[test] +fn test_get() { + let mut a = vec![11]; + assert_eq!(a.get(1), None); + a = vec![11, 12]; + assert_eq!(a.get(1).unwrap(), &12); + a = vec![11, 12, 13]; + assert_eq!(a.get(1).unwrap(), &12); +} + +#[test] +fn test_first() { + let mut a = vec![]; + assert_eq!(a.first(), None); + a = vec![11]; + assert_eq!(a.first().unwrap(), &11); + a = vec![11, 12]; + assert_eq!(a.first().unwrap(), &11); +} + +#[test] +fn test_first_mut() { + let mut a = vec![]; + assert_eq!(a.first_mut(), None); + a = vec![11]; + assert_eq!(*a.first_mut().unwrap(), 11); + a = vec![11, 12]; + assert_eq!(*a.first_mut().unwrap(), 11); +} + +#[test] +fn test_split_first() { + let mut a = vec![11]; + let b: &[i32] = &[]; + assert!(b.split_first().is_none()); + assert_eq!(a.split_first(), Some((&11, b))); + a = vec![11, 12]; + let b: &[i32] = &[12]; + assert_eq!(a.split_first(), Some((&11, b))); +} + +#[test] +fn test_split_first_mut() { + let mut a = vec![11]; + let b: &mut [i32] = &mut []; + assert!(b.split_first_mut().is_none()); + assert!(a.split_first_mut() == Some((&mut 11, b))); + a = vec![11, 12]; + let b: &mut [_] = &mut [12]; + assert!(a.split_first_mut() == Some((&mut 11, b))); +} + +#[test] +fn test_split_last() { + let mut a = vec![11]; + let b: &[i32] = &[]; + assert!(b.split_last().is_none()); + assert_eq!(a.split_last(), Some((&11, b))); + a = vec![11, 12]; + let b: &[_] = &[11]; + assert_eq!(a.split_last(), Some((&12, b))); +} + +#[test] +fn test_split_last_mut() { + let mut a = vec![11]; + let b: &mut [i32] = &mut []; + assert!(b.split_last_mut().is_none()); + assert!(a.split_last_mut() == Some((&mut 11, b))); + + a = vec![11, 12]; + let b: &mut [_] = &mut [11]; + assert!(a.split_last_mut() == Some((&mut 12, b))); +} + +#[test] +fn test_last() { + let mut a = vec![]; + assert_eq!(a.last(), None); + a = vec![11]; + assert_eq!(a.last().unwrap(), &11); + a = vec![11, 12]; + assert_eq!(a.last().unwrap(), &12); +} + +#[test] +fn test_last_mut() { + let mut a = vec![]; + assert_eq!(a.last_mut(), None); + a = vec![11]; + assert_eq!(*a.last_mut().unwrap(), 11); + a = vec![11, 12]; + assert_eq!(*a.last_mut().unwrap(), 12); +} + +#[test] +fn test_slice() { + // Test fixed length vector. + let vec_fixed = [1, 2, 3, 4]; + let v_a = vec_fixed[1..vec_fixed.len()].to_vec(); + assert_eq!(v_a.len(), 3); + + assert_eq!(v_a[0], 2); + assert_eq!(v_a[1], 3); + assert_eq!(v_a[2], 4); + + // Test on stack. + let vec_stack: &[_] = &[1, 2, 3]; + let v_b = vec_stack[1..3].to_vec(); + assert_eq!(v_b.len(), 2); + + assert_eq!(v_b[0], 2); + assert_eq!(v_b[1], 3); + + // Test `Box<[T]>` + let vec_unique = vec![1, 2, 3, 4, 5, 6]; + let v_d = vec_unique[1..6].to_vec(); + assert_eq!(v_d.len(), 5); + + assert_eq!(v_d[0], 2); + assert_eq!(v_d[1], 3); + assert_eq!(v_d[2], 4); + assert_eq!(v_d[3], 5); + assert_eq!(v_d[4], 6); +} + +#[test] +fn test_slice_from() { + let vec: &[_] = &[1, 2, 3, 4]; + assert_eq!(&vec[..], vec); + let b: &[_] = &[3, 4]; + assert_eq!(&vec[2..], b); + let b: &[_] = &[]; + assert_eq!(&vec[4..], b); +} + +#[test] +fn test_slice_to() { + let vec: &[_] = &[1, 2, 3, 4]; + assert_eq!(&vec[..4], vec); + let b: &[_] = &[1, 2]; + assert_eq!(&vec[..2], b); + let b: &[_] = &[]; + assert_eq!(&vec[..0], b); +} + +#[test] +fn test_pop() { + let mut v = vec![5]; + let e = v.pop(); + assert_eq!(v.len(), 0); + assert_eq!(e, Some(5)); + let f = v.pop(); + assert_eq!(f, None); + let g = v.pop(); + assert_eq!(g, None); +} + +#[test] +fn test_swap_remove() { + let mut v = vec![1, 2, 3, 4, 5]; + let mut e = v.swap_remove(0); + assert_eq!(e, 1); + assert_eq!(v, [5, 2, 3, 4]); + e = v.swap_remove(3); + assert_eq!(e, 4); + assert_eq!(v, [5, 2, 3]); +} + +#[test] +#[should_panic] +fn test_swap_remove_fail() { + let mut v = vec![1]; + let _ = v.swap_remove(0); + let _ = v.swap_remove(0); +} + +#[test] +fn test_swap_remove_noncopyable() { + // Tests that we don't accidentally run destructors twice. + let mut v: Vec> = Vec::new(); + v.push(Box::new(0)); + v.push(Box::new(0)); + v.push(Box::new(0)); + let mut _e = v.swap_remove(0); + assert_eq!(v.len(), 2); + _e = v.swap_remove(1); + assert_eq!(v.len(), 1); + _e = v.swap_remove(0); + assert_eq!(v.len(), 0); +} + +#[test] +fn test_push() { + // Test on-stack push(). + let mut v = vec![]; + v.push(1); + assert_eq!(v.len(), 1); + assert_eq!(v[0], 1); + + // Test on-heap push(). + v.push(2); + assert_eq!(v.len(), 2); + assert_eq!(v[0], 1); + assert_eq!(v[1], 2); +} + +#[test] +fn test_truncate() { + let mut v: Vec> = vec![Box::new(6), Box::new(5), Box::new(4)]; + v.truncate(1); + let v = v; + assert_eq!(v.len(), 1); + assert_eq!(*(v[0]), 6); + // If the unsafe block didn't drop things properly, we blow up here. +} + +#[test] +fn test_clear() { + let mut v: Vec> = vec![Box::new(6), Box::new(5), Box::new(4)]; + v.clear(); + assert_eq!(v.len(), 0); + // If the unsafe block didn't drop things properly, we blow up here. +} + +#[test] +fn test_retain() { + let mut v = vec![1, 2, 3, 4, 5]; + v.retain(is_odd); + assert_eq!(v, [1, 3, 5]); +} + +#[test] +fn test_binary_search() { + assert_eq!([1, 2, 3, 4, 5].binary_search(&5).ok(), Some(4)); + assert_eq!([1, 2, 3, 4, 5].binary_search(&4).ok(), Some(3)); + assert_eq!([1, 2, 3, 4, 5].binary_search(&3).ok(), Some(2)); + assert_eq!([1, 2, 3, 4, 5].binary_search(&2).ok(), Some(1)); + assert_eq!([1, 2, 3, 4, 5].binary_search(&1).ok(), Some(0)); + + assert_eq!([2, 4, 6, 8, 10].binary_search(&1).ok(), None); + assert_eq!([2, 4, 6, 8, 10].binary_search(&5).ok(), None); + assert_eq!([2, 4, 6, 8, 10].binary_search(&4).ok(), Some(1)); + assert_eq!([2, 4, 6, 8, 10].binary_search(&10).ok(), Some(4)); + + assert_eq!([2, 4, 6, 8].binary_search(&1).ok(), None); + assert_eq!([2, 4, 6, 8].binary_search(&5).ok(), None); + assert_eq!([2, 4, 6, 8].binary_search(&4).ok(), Some(1)); + assert_eq!([2, 4, 6, 8].binary_search(&8).ok(), Some(3)); + + assert_eq!([2, 4, 6].binary_search(&1).ok(), None); + assert_eq!([2, 4, 6].binary_search(&5).ok(), None); + assert_eq!([2, 4, 6].binary_search(&4).ok(), Some(1)); + assert_eq!([2, 4, 6].binary_search(&6).ok(), Some(2)); + + assert_eq!([2, 4].binary_search(&1).ok(), None); + assert_eq!([2, 4].binary_search(&5).ok(), None); + assert_eq!([2, 4].binary_search(&2).ok(), Some(0)); + assert_eq!([2, 4].binary_search(&4).ok(), Some(1)); + + assert_eq!([2].binary_search(&1).ok(), None); + assert_eq!([2].binary_search(&5).ok(), None); + assert_eq!([2].binary_search(&2).ok(), Some(0)); + + assert_eq!([].binary_search(&1).ok(), None); + assert_eq!([].binary_search(&5).ok(), None); + + assert!([1, 1, 1, 1, 1].binary_search(&1).ok() != None); + assert!([1, 1, 1, 1, 2].binary_search(&1).ok() != None); + assert!([1, 1, 1, 2, 2].binary_search(&1).ok() != None); + assert!([1, 1, 2, 2, 2].binary_search(&1).ok() != None); + assert_eq!([1, 2, 2, 2, 2].binary_search(&1).ok(), Some(0)); + + assert_eq!([1, 2, 3, 4, 5].binary_search(&6).ok(), None); + assert_eq!([1, 2, 3, 4, 5].binary_search(&0).ok(), None); +} + +#[test] +fn test_reverse() { + let mut v = vec![10, 20]; + assert_eq!(v[0], 10); + assert_eq!(v[1], 20); + v.reverse(); + assert_eq!(v[0], 20); + assert_eq!(v[1], 10); + + let mut v3 = Vec::::new(); + v3.reverse(); + assert!(v3.is_empty()); + + // check the 1-byte-types path + let mut v = (-50..51i8).collect::>(); + v.reverse(); + assert_eq!(v, (-50..51i8).rev().collect::>()); + + // check the 2-byte-types path + let mut v = (-50..51i16).collect::>(); + v.reverse(); + assert_eq!(v, (-50..51i16).rev().collect::>()); +} + +#[test] +fn test_rotate_left() { + let expected: Vec<_> = (0..13).collect(); + let mut v = Vec::new(); + + // no-ops + v.clone_from(&expected); + v.rotate_left(0); + assert_eq!(v, expected); + v.rotate_left(expected.len()); + assert_eq!(v, expected); + let mut zst_array = [(), (), ()]; + zst_array.rotate_left(2); + + // happy path + v = (5..13).chain(0..5).collect(); + v.rotate_left(8); + assert_eq!(v, expected); + + let expected: Vec<_> = (0..1000).collect(); + + // small rotations in large slice, uses ptr::copy + v = (2..1000).chain(0..2).collect(); + v.rotate_left(998); + assert_eq!(v, expected); + v = (998..1000).chain(0..998).collect(); + v.rotate_left(2); + assert_eq!(v, expected); + + // non-small prime rotation, has a few rounds of swapping + v = (389..1000).chain(0..389).collect(); + v.rotate_left(1000 - 389); + assert_eq!(v, expected); +} + +#[test] +fn test_rotate_right() { + let expected: Vec<_> = (0..13).collect(); + let mut v = Vec::new(); + + // no-ops + v.clone_from(&expected); + v.rotate_right(0); + assert_eq!(v, expected); + v.rotate_right(expected.len()); + assert_eq!(v, expected); + let mut zst_array = [(), (), ()]; + zst_array.rotate_right(2); + + // happy path + v = (5..13).chain(0..5).collect(); + v.rotate_right(5); + assert_eq!(v, expected); + + let expected: Vec<_> = (0..1000).collect(); + + // small rotations in large slice, uses ptr::copy + v = (2..1000).chain(0..2).collect(); + v.rotate_right(2); + assert_eq!(v, expected); + v = (998..1000).chain(0..998).collect(); + v.rotate_right(998); + assert_eq!(v, expected); + + // non-small prime rotation, has a few rounds of swapping + v = (389..1000).chain(0..389).collect(); + v.rotate_right(389); + assert_eq!(v, expected); +} + +#[test] +fn test_concat() { + let v: [Vec; 0] = []; + let c = v.concat(); + assert_eq!(c, []); + let d = [vec![1], vec![2, 3]].concat(); + assert_eq!(d, [1, 2, 3]); + + let v: &[&[_]] = &[&[1], &[2, 3]]; + assert_eq!(v.join(&0), [1, 0, 2, 3]); + let v: &[&[_]] = &[&[1], &[2], &[3]]; + assert_eq!(v.join(&0), [1, 0, 2, 0, 3]); +} + +#[test] +fn test_join() { + let v: [Vec; 0] = []; + assert_eq!(v.join(&0), []); + assert_eq!([vec![1], vec![2, 3]].join(&0), [1, 0, 2, 3]); + assert_eq!([vec![1], vec![2], vec![3]].join(&0), [1, 0, 2, 0, 3]); + + let v: [&[_]; 2] = [&[1], &[2, 3]]; + assert_eq!(v.join(&0), [1, 0, 2, 3]); + let v: [&[_]; 3] = [&[1], &[2], &[3]]; + assert_eq!(v.join(&0), [1, 0, 2, 0, 3]); +} + +#[test] +fn test_join_nocopy() { + let v: [String; 0] = []; + assert_eq!(v.join(","), ""); + assert_eq!(["a".to_string(), "ab".into()].join(","), "a,ab"); + assert_eq!(["a".to_string(), "ab".into(), "abc".into()].join(","), "a,ab,abc"); + assert_eq!(["a".to_string(), "ab".into(), "".into()].join(","), "a,ab,"); +} + +#[test] +fn test_insert() { + let mut a = vec![1, 2, 4]; + a.insert(2, 3); + assert_eq!(a, [1, 2, 3, 4]); + + let mut a = vec![1, 2, 3]; + a.insert(0, 0); + assert_eq!(a, [0, 1, 2, 3]); + + let mut a = vec![1, 2, 3]; + a.insert(3, 4); + assert_eq!(a, [1, 2, 3, 4]); + + let mut a = vec![]; + a.insert(0, 1); + assert_eq!(a, [1]); +} + +#[test] +#[should_panic] +fn test_insert_oob() { + let mut a = vec![1, 2, 3]; + a.insert(4, 5); +} + +#[test] +fn test_remove() { + let mut a = vec![1, 2, 3, 4]; + + assert_eq!(a.remove(2), 3); + assert_eq!(a, [1, 2, 4]); + + assert_eq!(a.remove(2), 4); + assert_eq!(a, [1, 2]); + + assert_eq!(a.remove(0), 1); + assert_eq!(a, [2]); + + assert_eq!(a.remove(0), 2); + assert_eq!(a, []); +} + +#[test] +#[should_panic] +fn test_remove_fail() { + let mut a = vec![1]; + let _ = a.remove(0); + let _ = a.remove(0); +} + +#[test] +fn test_capacity() { + let mut v = vec![0]; + v.reserve_exact(10); + assert!(v.capacity() >= 11); +} + +#[test] +fn test_slice_2() { + let v = vec![1, 2, 3, 4, 5]; + let v = &v[1..3]; + assert_eq!(v.len(), 2); + assert_eq!(v[0], 2); + assert_eq!(v[1], 3); +} + +macro_rules! assert_order { + (Greater, $a:expr, $b:expr) => { + assert_eq!($a.cmp($b), Greater); + assert!($a > $b); + }; + (Less, $a:expr, $b:expr) => { + assert_eq!($a.cmp($b), Less); + assert!($a < $b); + }; + (Equal, $a:expr, $b:expr) => { + assert_eq!($a.cmp($b), Equal); + assert_eq!($a, $b); + }; +} + +#[test] +fn test_total_ord_u8() { + let c = &[1u8, 2, 3]; + assert_order!(Greater, &[1u8, 2, 3, 4][..], &c[..]); + let c = &[1u8, 2, 3, 4]; + assert_order!(Less, &[1u8, 2, 3][..], &c[..]); + let c = &[1u8, 2, 3, 6]; + assert_order!(Equal, &[1u8, 2, 3, 6][..], &c[..]); + let c = &[1u8, 2, 3, 4, 5, 6]; + assert_order!(Less, &[1u8, 2, 3, 4, 5, 5, 5, 5][..], &c[..]); + let c = &[1u8, 2, 3, 4]; + assert_order!(Greater, &[2u8, 2][..], &c[..]); +} + +#[test] +fn test_total_ord_i32() { + let c = &[1, 2, 3]; + assert_order!(Greater, &[1, 2, 3, 4][..], &c[..]); + let c = &[1, 2, 3, 4]; + assert_order!(Less, &[1, 2, 3][..], &c[..]); + let c = &[1, 2, 3, 6]; + assert_order!(Equal, &[1, 2, 3, 6][..], &c[..]); + let c = &[1, 2, 3, 4, 5, 6]; + assert_order!(Less, &[1, 2, 3, 4, 5, 5, 5, 5][..], &c[..]); + let c = &[1, 2, 3, 4]; + assert_order!(Greater, &[2, 2][..], &c[..]); +} + +#[test] +fn test_iterator() { + let xs = [1, 2, 5, 10, 11]; + let mut it = xs.iter(); + assert_eq!(it.size_hint(), (5, Some(5))); + assert_eq!(it.next().unwrap(), &1); + assert_eq!(it.size_hint(), (4, Some(4))); + assert_eq!(it.next().unwrap(), &2); + assert_eq!(it.size_hint(), (3, Some(3))); + assert_eq!(it.next().unwrap(), &5); + assert_eq!(it.size_hint(), (2, Some(2))); + assert_eq!(it.next().unwrap(), &10); + assert_eq!(it.size_hint(), (1, Some(1))); + assert_eq!(it.next().unwrap(), &11); + assert_eq!(it.size_hint(), (0, Some(0))); + assert!(it.next().is_none()); +} + +#[test] +fn test_iter_size_hints() { + let mut xs = [1, 2, 5, 10, 11]; + assert_eq!(xs.iter().size_hint(), (5, Some(5))); + assert_eq!(xs.iter_mut().size_hint(), (5, Some(5))); +} + +#[test] +fn test_iter_as_slice() { + let xs = [1, 2, 5, 10, 11]; + let mut iter = xs.iter(); + assert_eq!(iter.as_slice(), &[1, 2, 5, 10, 11]); + iter.next(); + assert_eq!(iter.as_slice(), &[2, 5, 10, 11]); +} + +#[test] +fn test_iter_as_ref() { + let xs = [1, 2, 5, 10, 11]; + let mut iter = xs.iter(); + assert_eq!(iter.as_ref(), &[1, 2, 5, 10, 11]); + iter.next(); + assert_eq!(iter.as_ref(), &[2, 5, 10, 11]); +} + +#[test] +fn test_iter_clone() { + let xs = [1, 2, 5]; + let mut it = xs.iter(); + it.next(); + let mut jt = it.clone(); + assert_eq!(it.next(), jt.next()); + assert_eq!(it.next(), jt.next()); + assert_eq!(it.next(), jt.next()); +} + +#[test] +fn test_iter_is_empty() { + let xs = [1, 2, 5, 10, 11]; + for i in 0..xs.len() { + for j in i..xs.len() { + assert_eq!(xs[i..j].iter().is_empty(), xs[i..j].is_empty()); + } + } +} + +#[test] +fn test_mut_iterator() { + let mut xs = [1, 2, 3, 4, 5]; + for x in &mut xs { + *x += 1; + } + assert!(xs == [2, 3, 4, 5, 6]) +} + +#[test] +fn test_rev_iterator() { + let xs = [1, 2, 5, 10, 11]; + let ys = [11, 10, 5, 2, 1]; + let mut i = 0; + for &x in xs.iter().rev() { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, 5); +} + +#[test] +fn test_mut_rev_iterator() { + let mut xs = [1, 2, 3, 4, 5]; + for (i, x) in xs.iter_mut().rev().enumerate() { + *x += i; + } + assert!(xs == [5, 5, 5, 5, 5]) +} + +#[test] +fn test_move_iterator() { + let xs = vec![1, 2, 3, 4, 5]; + assert_eq!(xs.into_iter().fold(0, |a: usize, b: usize| 10 * a + b), 12345); +} + +#[test] +fn test_move_rev_iterator() { + let xs = vec![1, 2, 3, 4, 5]; + assert_eq!(xs.into_iter().rev().fold(0, |a: usize, b: usize| 10 * a + b), 54321); +} + +#[test] +fn test_split_iterator() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1], &[3], &[5]]; + assert_eq!(xs.split(|x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[], &[2, 3, 4, 5]]; + assert_eq!(xs.split(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4], &[]]; + assert_eq!(xs.split(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[], &[], &[], &[], &[], &[]]; + assert_eq!(xs.split(|_| true).collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.split(|x| *x == 5).collect::>(), splits); +} + +#[test] +fn test_split_iterator_inclusive() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]]; + assert_eq!(xs.split_inclusive(|x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.split_inclusive(|_| true).collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.split_inclusive(|x| *x == 5).collect::>(), splits); +} + +#[test] +fn test_split_iterator_inclusive_reverse() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]]; + assert_eq!(xs.split_inclusive(|x| *x % 2 == 0).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]]; + assert_eq!(xs.split_inclusive(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.split_inclusive(|_| true).rev().collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::>(), splits); +} + +#[test] +fn test_split_iterator_mut_inclusive() { + let xs = &mut [1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.split_inclusive_mut(|_| true).collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::>(), splits); +} + +#[test] +fn test_split_iterator_mut_inclusive_reverse() { + let xs = &mut [1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]]; + assert_eq!(xs.split_inclusive_mut(|x| *x % 2 == 0).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.split_inclusive_mut(|_| true).rev().collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); +} + +#[test] +fn test_splitn_iterator() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[3, 4, 5]]; + assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[], &[], &[], &[4, 5]]; + assert_eq!(xs.splitn(4, |_| true).collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.splitn(2, |x| *x == 5).collect::>(), splits); +} + +#[test] +fn test_splitn_iterator_mut() { + let xs = &mut [1, 2, 3, 4, 5]; + + let splits: &[&mut [_]] = &[&mut [1, 2, 3, 4, 5]]; + assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::>(), splits); + let splits: &[&mut [_]] = &[&mut [1], &mut [3, 4, 5]]; + assert_eq!(xs.splitn_mut(2, |x| *x % 2 == 0).collect::>(), splits); + let splits: &[&mut [_]] = &[&mut [], &mut [], &mut [], &mut [4, 5]]; + assert_eq!(xs.splitn_mut(4, |_| true).collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&mut [i32]] = &[&mut []]; + assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::>(), splits); +} + +#[test] +fn test_rsplit_iterator() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[5], &[3], &[1]]; + assert_eq!(xs.split(|x| *x % 2 == 0).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[2, 3, 4, 5], &[]]; + assert_eq!(xs.split(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[], &[1, 2, 3, 4]]; + assert_eq!(xs.split(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split(|x| *x == 10).rev().collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.split(|x| *x == 5).rev().collect::>(), splits); +} + +#[test] +fn test_rsplitn_iterator() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[1, 2, 3]]; + assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[], &[], &[], &[1, 2]]; + assert_eq!(xs.rsplitn(4, |_| true).collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.rsplitn(2, |x| *x == 5).collect::>(), splits); + assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none()); +} + +#[test] +fn test_split_iterators_size_hint() { + #[derive(Copy, Clone)] + enum Bounds { + Lower, + Upper, + } + fn assert_tight_size_hints(mut it: impl Iterator, which: Bounds, ctx: impl fmt::Display) { + match which { + Bounds::Lower => { + let mut lower_bounds = vec![it.size_hint().0]; + while let Some(_) = it.next() { + lower_bounds.push(it.size_hint().0); + } + let target: Vec<_> = (0..lower_bounds.len()).rev().collect(); + assert_eq!(lower_bounds, target, "lower bounds incorrect or not tight: {}", ctx); + } + Bounds::Upper => { + let mut upper_bounds = vec![it.size_hint().1]; + while let Some(_) = it.next() { + upper_bounds.push(it.size_hint().1); + } + let target: Vec<_> = (0..upper_bounds.len()).map(Some).rev().collect(); + assert_eq!(upper_bounds, target, "upper bounds incorrect or not tight: {}", ctx); + } + } + } + + for len in 0..=2 { + let mut v: Vec = (0..len).collect(); + + // p: predicate, b: bound selection + for (p, b) in [ + // with a predicate always returning false, the split*-iterators + // become maximally short, so the size_hint lower bounds are tight + ((|_| false) as fn(&_) -> _, Bounds::Lower), + // with a predicate always returning true, the split*-iterators + // become maximally long, so the size_hint upper bounds are tight + ((|_| true) as fn(&_) -> _, Bounds::Upper), + ] { + use {assert_tight_size_hints as a, format_args as f}; + + a(v.split(p), b, "split"); + a(v.split_mut(p), b, "split_mut"); + a(v.split_inclusive(p), b, "split_inclusive"); + a(v.split_inclusive_mut(p), b, "split_inclusive_mut"); + a(v.rsplit(p), b, "rsplit"); + a(v.rsplit_mut(p), b, "rsplit_mut"); + + for n in 0..=3 { + a(v.splitn(n, p), b, f!("splitn, n = {n}")); + a(v.splitn_mut(n, p), b, f!("splitn_mut, n = {n}")); + a(v.rsplitn(n, p), b, f!("rsplitn, n = {n}")); + a(v.rsplitn_mut(n, p), b, f!("rsplitn_mut, n = {n}")); + } + } + } +} + +#[test] +fn test_windows_iterator() { + let v = &[1, 2, 3, 4]; + + let wins: &[&[_]] = &[&[1, 2], &[2, 3], &[3, 4]]; + assert_eq!(v.windows(2).collect::>(), wins); + + let wins: &[&[_]] = &[&[1, 2, 3], &[2, 3, 4]]; + assert_eq!(v.windows(3).collect::>(), wins); + assert!(v.windows(6).next().is_none()); + + let wins: &[&[_]] = &[&[3, 4], &[2, 3], &[1, 2]]; + assert_eq!(v.windows(2).rev().collect::>(), wins); +} + +#[test] +#[should_panic] +fn test_windows_iterator_0() { + let v = &[1, 2, 3, 4]; + let _it = v.windows(0); +} + +#[test] +fn test_chunks_iterator() { + let v = &[1, 2, 3, 4, 5]; + + assert_eq!(v.chunks(2).len(), 3); + + let chunks: &[&[_]] = &[&[1, 2], &[3, 4], &[5]]; + assert_eq!(v.chunks(2).collect::>(), chunks); + let chunks: &[&[_]] = &[&[1, 2, 3], &[4, 5]]; + assert_eq!(v.chunks(3).collect::>(), chunks); + let chunks: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(v.chunks(6).collect::>(), chunks); + + let chunks: &[&[_]] = &[&[5], &[3, 4], &[1, 2]]; + assert_eq!(v.chunks(2).rev().collect::>(), chunks); +} + +#[test] +#[should_panic] +fn test_chunks_iterator_0() { + let v = &[1, 2, 3, 4]; + let _it = v.chunks(0); +} + +#[test] +fn test_chunks_exact_iterator() { + let v = &[1, 2, 3, 4, 5]; + + assert_eq!(v.chunks_exact(2).len(), 2); + + let chunks: &[&[_]] = &[&[1, 2], &[3, 4]]; + assert_eq!(v.chunks_exact(2).collect::>(), chunks); + let chunks: &[&[_]] = &[&[1, 2, 3]]; + assert_eq!(v.chunks_exact(3).collect::>(), chunks); + let chunks: &[&[_]] = &[]; + assert_eq!(v.chunks_exact(6).collect::>(), chunks); + + let chunks: &[&[_]] = &[&[3, 4], &[1, 2]]; + assert_eq!(v.chunks_exact(2).rev().collect::>(), chunks); +} + +#[test] +#[should_panic] +fn test_chunks_exact_iterator_0() { + let v = &[1, 2, 3, 4]; + let _it = v.chunks_exact(0); +} + +#[test] +fn test_rchunks_iterator() { + let v = &[1, 2, 3, 4, 5]; + + assert_eq!(v.rchunks(2).len(), 3); + + let chunks: &[&[_]] = &[&[4, 5], &[2, 3], &[1]]; + assert_eq!(v.rchunks(2).collect::>(), chunks); + let chunks: &[&[_]] = &[&[3, 4, 5], &[1, 2]]; + assert_eq!(v.rchunks(3).collect::>(), chunks); + let chunks: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(v.rchunks(6).collect::>(), chunks); + + let chunks: &[&[_]] = &[&[1], &[2, 3], &[4, 5]]; + assert_eq!(v.rchunks(2).rev().collect::>(), chunks); +} + +#[test] +#[should_panic] +fn test_rchunks_iterator_0() { + let v = &[1, 2, 3, 4]; + let _it = v.rchunks(0); +} + +#[test] +fn test_rchunks_exact_iterator() { + let v = &[1, 2, 3, 4, 5]; + + assert_eq!(v.rchunks_exact(2).len(), 2); + + let chunks: &[&[_]] = &[&[4, 5], &[2, 3]]; + assert_eq!(v.rchunks_exact(2).collect::>(), chunks); + let chunks: &[&[_]] = &[&[3, 4, 5]]; + assert_eq!(v.rchunks_exact(3).collect::>(), chunks); + let chunks: &[&[_]] = &[]; + assert_eq!(v.rchunks_exact(6).collect::>(), chunks); + + let chunks: &[&[_]] = &[&[2, 3], &[4, 5]]; + assert_eq!(v.rchunks_exact(2).rev().collect::>(), chunks); +} + +#[test] +#[should_panic] +fn test_rchunks_exact_iterator_0() { + let v = &[1, 2, 3, 4]; + let _it = v.rchunks_exact(0); +} + +#[test] +fn test_reverse_part() { + let mut values = [1, 2, 3, 4, 5]; + values[1..4].reverse(); + assert!(values == [1, 4, 3, 2, 5]); +} + +#[test] +fn test_show() { + macro_rules! test_show_vec { + ($x:expr, $x_str:expr) => {{ + let (x, x_str) = ($x, $x_str); + assert_eq!(format!("{x:?}"), x_str); + assert_eq!(format!("{x:?}"), x_str); + }}; + } + let empty = Vec::::new(); + test_show_vec!(empty, "[]"); + test_show_vec!(vec![1], "[1]"); + test_show_vec!(vec![1, 2, 3], "[1, 2, 3]"); + test_show_vec!(vec![vec![], vec![1], vec![1, 1]], "[[], [1], [1, 1]]"); + + let empty_mut: &mut [i32] = &mut []; + test_show_vec!(empty_mut, "[]"); + let v = &mut [1]; + test_show_vec!(v, "[1]"); + let v = &mut [1, 2, 3]; + test_show_vec!(v, "[1, 2, 3]"); + let v: &mut [&mut [_]] = &mut [&mut [], &mut [1], &mut [1, 1]]; + test_show_vec!(v, "[[], [1], [1, 1]]"); +} + +#[test] +fn test_vec_default() { + macro_rules! t { + ($ty:ty) => {{ + let v: $ty = Default::default(); + assert!(v.is_empty()); + }}; + } + + t!(&[i32]); + t!(Vec); +} + +#[test] +#[should_panic] +fn test_overflow_does_not_cause_segfault() { + let mut v = vec![]; + v.reserve_exact(!0); + v.push(1); + v.push(2); +} + +#[test] +#[should_panic] +fn test_overflow_does_not_cause_segfault_managed() { + let mut v = vec![Rc::new(1)]; + v.reserve_exact(!0); + v.push(Rc::new(2)); +} + +#[test] +fn test_mut_split_at() { + let mut values = [1, 2, 3, 4, 5]; + { + let (left, right) = values.split_at_mut(2); + { + let left: &[_] = left; + assert!(left[..left.len()] == [1, 2]); + } + for p in left { + *p += 1; + } + + { + let right: &[_] = right; + assert!(right[..right.len()] == [3, 4, 5]); + } + for p in right { + *p += 2; + } + } + + assert!(values == [2, 3, 5, 6, 7]); +} + +#[derive(Clone, PartialEq)] +struct Foo; + +#[test] +fn test_iter_zero_sized() { + let mut v = vec![Foo, Foo, Foo]; + assert_eq!(v.len(), 3); + let mut cnt = 0; + + for f in &v { + assert!(*f == Foo); + cnt += 1; + } + assert_eq!(cnt, 3); + + for f in &v[1..3] { + assert!(*f == Foo); + cnt += 1; + } + assert_eq!(cnt, 5); + + for f in &mut v { + assert!(*f == Foo); + cnt += 1; + } + assert_eq!(cnt, 8); + + for f in v { + assert!(f == Foo); + cnt += 1; + } + assert_eq!(cnt, 11); + + let xs: [Foo; 3] = [Foo, Foo, Foo]; + cnt = 0; + for f in &xs { + assert!(*f == Foo); + cnt += 1; + } + assert!(cnt == 3); +} + +#[test] +fn test_shrink_to_fit() { + let mut xs = vec![0, 1, 2, 3]; + for i in 4..100 { + xs.push(i) + } + assert_eq!(xs.capacity(), 128); + xs.shrink_to_fit(); + assert_eq!(xs.capacity(), 100); + assert_eq!(xs, (0..100).collect::>()); +} + +#[test] +fn test_starts_with() { + assert!(b"foobar".starts_with(b"foo")); + assert!(!b"foobar".starts_with(b"oob")); + assert!(!b"foobar".starts_with(b"bar")); + assert!(!b"foo".starts_with(b"foobar")); + assert!(!b"bar".starts_with(b"foobar")); + assert!(b"foobar".starts_with(b"foobar")); + let empty: &[u8] = &[]; + assert!(empty.starts_with(empty)); + assert!(!empty.starts_with(b"foo")); + assert!(b"foobar".starts_with(empty)); +} + +#[test] +fn test_ends_with() { + assert!(b"foobar".ends_with(b"bar")); + assert!(!b"foobar".ends_with(b"oba")); + assert!(!b"foobar".ends_with(b"foo")); + assert!(!b"foo".ends_with(b"foobar")); + assert!(!b"bar".ends_with(b"foobar")); + assert!(b"foobar".ends_with(b"foobar")); + let empty: &[u8] = &[]; + assert!(empty.ends_with(empty)); + assert!(!empty.ends_with(b"foo")); + assert!(b"foobar".ends_with(empty)); +} + +#[test] +fn test_mut_split_iterator() { + let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0]; + assert_eq!(xs.split_mut(|x| *x == 0).count(), 6); + for slice in xs.split_mut(|x| *x == 0) { + slice.reverse(); + } + assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0]); + + let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0, 6, 7]; + for slice in xs.split_mut(|x| *x == 0).take(5) { + slice.reverse(); + } + assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0, 6, 7]); +} + +#[test] +fn test_mut_split_iterator_rev() { + let mut xs = [1, 2, 0, 3, 4, 0, 0, 5, 6, 0]; + for slice in xs.split_mut(|x| *x == 0).rev().take(4) { + slice.reverse(); + } + assert!(xs == [1, 2, 0, 4, 3, 0, 0, 6, 5, 0]); +} + +#[test] +fn test_get_mut() { + let mut v = [0, 1, 2]; + assert_eq!(v.get_mut(3), None); + v.get_mut(1).map(|e| *e = 7); + assert_eq!(v[1], 7); + let mut x = 2; + assert_eq!(v.get_mut(2), Some(&mut x)); +} + +#[test] +fn test_mut_chunks() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + assert_eq!(v.chunks_mut(3).len(), 3); + for (i, chunk) in v.chunks_mut(3).enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [0, 0, 0, 1, 1, 1, 2]; + assert_eq!(v, result); +} + +#[test] +fn test_mut_chunks_rev() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + for (i, chunk) in v.chunks_mut(3).rev().enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [2, 2, 2, 1, 1, 1, 0]; + assert_eq!(v, result); +} + +#[test] +#[should_panic] +fn test_mut_chunks_0() { + let mut v = [1, 2, 3, 4]; + let _it = v.chunks_mut(0); +} + +#[test] +fn test_mut_chunks_exact() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + assert_eq!(v.chunks_exact_mut(3).len(), 2); + for (i, chunk) in v.chunks_exact_mut(3).enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [0, 0, 0, 1, 1, 1, 6]; + assert_eq!(v, result); +} + +#[test] +fn test_mut_chunks_exact_rev() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + for (i, chunk) in v.chunks_exact_mut(3).rev().enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [1, 1, 1, 0, 0, 0, 6]; + assert_eq!(v, result); +} + +#[test] +#[should_panic] +fn test_mut_chunks_exact_0() { + let mut v = [1, 2, 3, 4]; + let _it = v.chunks_exact_mut(0); +} + +#[test] +fn test_mut_rchunks() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + assert_eq!(v.rchunks_mut(3).len(), 3); + for (i, chunk) in v.rchunks_mut(3).enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [2, 1, 1, 1, 0, 0, 0]; + assert_eq!(v, result); +} + +#[test] +fn test_mut_rchunks_rev() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + for (i, chunk) in v.rchunks_mut(3).rev().enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [0, 1, 1, 1, 2, 2, 2]; + assert_eq!(v, result); +} + +#[test] +#[should_panic] +fn test_mut_rchunks_0() { + let mut v = [1, 2, 3, 4]; + let _it = v.rchunks_mut(0); +} + +#[test] +fn test_mut_rchunks_exact() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + assert_eq!(v.rchunks_exact_mut(3).len(), 2); + for (i, chunk) in v.rchunks_exact_mut(3).enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [0, 1, 1, 1, 0, 0, 0]; + assert_eq!(v, result); +} + +#[test] +fn test_mut_rchunks_exact_rev() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + for (i, chunk) in v.rchunks_exact_mut(3).rev().enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [0, 0, 0, 0, 1, 1, 1]; + assert_eq!(v, result); +} + +#[test] +#[should_panic] +fn test_mut_rchunks_exact_0() { + let mut v = [1, 2, 3, 4]; + let _it = v.rchunks_exact_mut(0); +} + +#[test] +fn test_mut_last() { + let mut x = [1, 2, 3, 4, 5]; + let h = x.last_mut(); + assert_eq!(*h.unwrap(), 5); + + let y: &mut [i32] = &mut []; + assert!(y.last_mut().is_none()); +} + +#[test] +fn test_to_vec() { + let xs: Box<_> = Box::new([1, 2, 3]); + let ys = xs.to_vec(); + assert_eq!(ys, [1, 2, 3]); +} + +#[test] +fn test_in_place_iterator_specialization() { + let src: Box<[usize]> = Box::new([1, 2, 3]); + let src_ptr = src.as_ptr(); + let sink: Box<_> = src.into_vec().into_iter().map(std::convert::identity).collect(); + let sink_ptr = sink.as_ptr(); + assert_eq!(src_ptr, sink_ptr); +} + +#[test] +fn test_box_slice_clone() { + let data = vec![vec![0, 1], vec![0], vec![1]]; + let data2 = data.clone().into_boxed_slice().clone().to_vec(); + + assert_eq!(data, data2); +} + +#[test] +#[allow(unused_must_use)] // here, we care about the side effects of `.clone()` +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_box_slice_clone_panics() { + use std::sync::Arc; + use std::sync::atomic::{AtomicUsize, Ordering}; + + struct Canary { + count: Arc, + panics: bool, + } + + impl Drop for Canary { + fn drop(&mut self) { + self.count.fetch_add(1, Ordering::SeqCst); + } + } + + impl Clone for Canary { + fn clone(&self) -> Self { + if self.panics { + panic!() + } + + Canary { count: self.count.clone(), panics: self.panics } + } + } + + let drop_count = Arc::new(AtomicUsize::new(0)); + let canary = Canary { count: drop_count.clone(), panics: false }; + let panic = Canary { count: drop_count.clone(), panics: true }; + + std::panic::catch_unwind(move || { + // When xs is dropped, +5. + let xs = + vec![canary.clone(), canary.clone(), canary.clone(), panic, canary].into_boxed_slice(); + + // When panic is cloned, +3. + xs.clone(); + }) + .unwrap_err(); + + // Total = 8 + assert_eq!(drop_count.load(Ordering::SeqCst), 8); +} + +#[test] +fn test_copy_from_slice() { + let src = [0, 1, 2, 3, 4, 5]; + let mut dst = [0; 6]; + dst.copy_from_slice(&src); + assert_eq!(src, dst) +} + +#[test] +#[should_panic(expected = "source slice length (4) does not match destination slice length (5)")] +fn test_copy_from_slice_dst_longer() { + let src = [0, 1, 2, 3]; + let mut dst = [0; 5]; + dst.copy_from_slice(&src); +} + +#[test] +#[should_panic(expected = "source slice length (4) does not match destination slice length (3)")] +fn test_copy_from_slice_dst_shorter() { + let src = [0, 1, 2, 3]; + let mut dst = [0; 3]; + dst.copy_from_slice(&src); +} + +#[test] +fn repeat_generic_slice() { + assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]); + assert_eq!([1, 2, 3, 4].repeat(0), vec![]); + assert_eq!([1, 2, 3, 4].repeat(1), vec![1, 2, 3, 4]); + assert_eq!([1, 2, 3, 4].repeat(3), vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]); +} + +#[test] +#[allow(unreachable_patterns)] +fn subslice_patterns() { + // This test comprehensively checks the passing static and dynamic semantics + // of subslice patterns `..`, `x @ ..`, `ref x @ ..`, and `ref mut @ ..` + // in slice patterns `[$($pat), $(,)?]` . + + #[derive(PartialEq, Debug, Clone)] + struct N(u8); + + macro_rules! n { + ($($e:expr),* $(,)?) => { + [$(N($e)),*] + } + } + + macro_rules! c { + ($inp:expr, $typ:ty, $out:expr $(,)?) => { + assert_eq!($out, identity::<$typ>($inp)) + }; + } + + macro_rules! m { + ($e:expr, $p:pat => $b:expr) => { + match $e { + $p => $b, + _ => panic!(), + } + }; + } + + // == Slices == + + // Matching slices using `ref` patterns: + let mut v = vec![N(0), N(1), N(2), N(3), N(4)]; + let mut vc = (0..=4).collect::>(); + + let [..] = v[..]; // Always matches. + m!(v[..], [N(0), ref sub @ .., N(4)] => c!(sub, &[N], n![1, 2, 3])); + m!(v[..], [N(0), ref sub @ ..] => c!(sub, &[N], n![1, 2, 3, 4])); + m!(v[..], [ref sub @ .., N(4)] => c!(sub, &[N], n![0, 1, 2, 3])); + m!(v[..], [ref sub @ .., _, _, _, _, _] => c!(sub, &[N], &n![] as &[N])); + m!(v[..], [_, _, _, _, _, ref sub @ ..] => c!(sub, &[N], &n![] as &[N])); + m!(vc[..], [x, .., y] => c!((x, y), (u8, u8), (0, 4))); + + // Matching slices using `ref mut` patterns: + let [..] = v[..]; // Always matches. + m!(v[..], [N(0), ref mut sub @ .., N(4)] => c!(sub, &mut [N], n![1, 2, 3])); + m!(v[..], [N(0), ref mut sub @ ..] => c!(sub, &mut [N], n![1, 2, 3, 4])); + m!(v[..], [ref mut sub @ .., N(4)] => c!(sub, &mut [N], n![0, 1, 2, 3])); + m!(v[..], [ref mut sub @ .., _, _, _, _, _] => c!(sub, &mut [N], &mut n![] as &mut [N])); + m!(v[..], [_, _, _, _, _, ref mut sub @ ..] => c!(sub, &mut [N], &mut n![] as &mut [N])); + m!(vc[..], [x, .., y] => c!((x, y), (u8, u8), (0, 4))); + + // Matching slices using default binding modes (&): + let [..] = &v[..]; // Always matches. + m!(&v[..], [N(0), sub @ .., N(4)] => c!(sub, &[N], n![1, 2, 3])); + m!(&v[..], [N(0), sub @ ..] => c!(sub, &[N], n![1, 2, 3, 4])); + m!(&v[..], [sub @ .., N(4)] => c!(sub, &[N], n![0, 1, 2, 3])); + m!(&v[..], [sub @ .., _, _, _, _, _] => c!(sub, &[N], &n![] as &[N])); + m!(&v[..], [_, _, _, _, _, sub @ ..] => c!(sub, &[N], &n![] as &[N])); + m!(&vc[..], [x, .., y] => c!((x, y), (&u8, &u8), (&0, &4))); + + // Matching slices using default binding modes (&mut): + let [..] = &mut v[..]; // Always matches. + m!(&mut v[..], [N(0), sub @ .., N(4)] => c!(sub, &mut [N], n![1, 2, 3])); + m!(&mut v[..], [N(0), sub @ ..] => c!(sub, &mut [N], n![1, 2, 3, 4])); + m!(&mut v[..], [sub @ .., N(4)] => c!(sub, &mut [N], n![0, 1, 2, 3])); + m!(&mut v[..], [sub @ .., _, _, _, _, _] => c!(sub, &mut [N], &mut n![] as &mut [N])); + m!(&mut v[..], [_, _, _, _, _, sub @ ..] => c!(sub, &mut [N], &mut n![] as &mut [N])); + m!(&mut vc[..], [x, .., y] => c!((x, y), (&mut u8, &mut u8), (&mut 0, &mut 4))); + + // == Arrays == + let mut v = n![0, 1, 2, 3, 4]; + let vc = [0, 1, 2, 3, 4]; + + // Matching arrays by value: + m!(v.clone(), [N(0), sub @ .., N(4)] => c!(sub, [N; 3], n![1, 2, 3])); + m!(v.clone(), [N(0), sub @ ..] => c!(sub, [N; 4], n![1, 2, 3, 4])); + m!(v.clone(), [sub @ .., N(4)] => c!(sub, [N; 4], n![0, 1, 2, 3])); + m!(v.clone(), [sub @ .., _, _, _, _, _] => c!(sub, [N; 0], n![] as [N; 0])); + m!(v.clone(), [_, _, _, _, _, sub @ ..] => c!(sub, [N; 0], n![] as [N; 0])); + m!(v.clone(), [x, .., y] => c!((x, y), (N, N), (N(0), N(4)))); + m!(v.clone(), [..] => ()); + + // Matching arrays by ref patterns: + m!(v, [N(0), ref sub @ .., N(4)] => c!(sub, &[N; 3], &n![1, 2, 3])); + m!(v, [N(0), ref sub @ ..] => c!(sub, &[N; 4], &n![1, 2, 3, 4])); + m!(v, [ref sub @ .., N(4)] => c!(sub, &[N; 4], &n![0, 1, 2, 3])); + m!(v, [ref sub @ .., _, _, _, _, _] => c!(sub, &[N; 0], &n![] as &[N; 0])); + m!(v, [_, _, _, _, _, ref sub @ ..] => c!(sub, &[N; 0], &n![] as &[N; 0])); + m!(vc, [x, .., y] => c!((x, y), (u8, u8), (0, 4))); + + // Matching arrays by ref mut patterns: + m!(v, [N(0), ref mut sub @ .., N(4)] => c!(sub, &mut [N; 3], &mut n![1, 2, 3])); + m!(v, [N(0), ref mut sub @ ..] => c!(sub, &mut [N; 4], &mut n![1, 2, 3, 4])); + m!(v, [ref mut sub @ .., N(4)] => c!(sub, &mut [N; 4], &mut n![0, 1, 2, 3])); + m!(v, [ref mut sub @ .., _, _, _, _, _] => c!(sub, &mut [N; 0], &mut n![] as &mut [N; 0])); + m!(v, [_, _, _, _, _, ref mut sub @ ..] => c!(sub, &mut [N; 0], &mut n![] as &mut [N; 0])); + + // Matching arrays by default binding modes (&): + m!(&v, [N(0), sub @ .., N(4)] => c!(sub, &[N; 3], &n![1, 2, 3])); + m!(&v, [N(0), sub @ ..] => c!(sub, &[N; 4], &n![1, 2, 3, 4])); + m!(&v, [sub @ .., N(4)] => c!(sub, &[N; 4], &n![0, 1, 2, 3])); + m!(&v, [sub @ .., _, _, _, _, _] => c!(sub, &[N; 0], &n![] as &[N; 0])); + m!(&v, [_, _, _, _, _, sub @ ..] => c!(sub, &[N; 0], &n![] as &[N; 0])); + m!(&v, [..] => ()); + m!(&v, [x, .., y] => c!((x, y), (&N, &N), (&N(0), &N(4)))); + + // Matching arrays by default binding modes (&mut): + m!(&mut v, [N(0), sub @ .., N(4)] => c!(sub, &mut [N; 3], &mut n![1, 2, 3])); + m!(&mut v, [N(0), sub @ ..] => c!(sub, &mut [N; 4], &mut n![1, 2, 3, 4])); + m!(&mut v, [sub @ .., N(4)] => c!(sub, &mut [N; 4], &mut n![0, 1, 2, 3])); + m!(&mut v, [sub @ .., _, _, _, _, _] => c!(sub, &mut [N; 0], &mut n![] as &[N; 0])); + m!(&mut v, [_, _, _, _, _, sub @ ..] => c!(sub, &mut [N; 0], &mut n![] as &[N; 0])); + m!(&mut v, [..] => ()); + m!(&mut v, [x, .., y] => c!((x, y), (&mut N, &mut N), (&mut N(0), &mut N(4)))); +} + +#[test] +fn test_chunk_by() { + let slice = &[1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; + + 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(), Some(&[1][..])); + assert_eq!(iter.next(), Some(&[0][..])); + assert_eq!(iter.next(), None); + + let mut iter = slice.chunk_by(|a, b| a == b); + assert_eq!(iter.next_back(), Some(&[0][..])); + assert_eq!(iter.next_back(), Some(&[1][..])); + assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next_back(), Some(&[3, 3][..])); + assert_eq!(iter.next_back(), Some(&[1, 1, 1][..])); + assert_eq!(iter.next_back(), None); + + let mut iter = slice.chunk_by(|a, b| a == b); + assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + assert_eq!(iter.next_back(), Some(&[0][..])); + assert_eq!(iter.next(), Some(&[3, 3][..])); + assert_eq!(iter.next_back(), Some(&[1][..])); + assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next_back(), None); +} + +#[test] +fn test_chunk_by_mut() { + let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2, 1, 0]; + + 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(), Some(&mut [1][..])); + assert_eq!(iter.next(), Some(&mut [0][..])); + assert_eq!(iter.next(), None); + + let mut iter = slice.chunk_by_mut(|a, b| a == b); + assert_eq!(iter.next_back(), Some(&mut [0][..])); + assert_eq!(iter.next_back(), Some(&mut [1][..])); + assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..])); + assert_eq!(iter.next_back(), Some(&mut [3, 3][..])); + assert_eq!(iter.next_back(), Some(&mut [1, 1, 1][..])); + assert_eq!(iter.next_back(), None); + + let mut iter = slice.chunk_by_mut(|a, b| a == b); + assert_eq!(iter.next(), Some(&mut [1, 1, 1][..])); + assert_eq!(iter.next_back(), Some(&mut [0][..])); + assert_eq!(iter.next(), Some(&mut [3, 3][..])); + assert_eq!(iter.next_back(), Some(&mut [1][..])); + assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); + assert_eq!(iter.next_back(), None); +} diff --git a/library/alloctests/tests/sort/ffi_types.rs b/library/alloctests/tests/sort/ffi_types.rs new file mode 100644 index 00000000000..11515ea4769 --- /dev/null +++ b/library/alloctests/tests/sort/ffi_types.rs @@ -0,0 +1,82 @@ +use std::cmp::Ordering; + +// Very large stack value. +#[repr(C)] +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct FFIOneKibiByte { + values: [i64; 128], +} + +impl FFIOneKibiByte { + pub fn new(val: i32) -> Self { + let mut values = [0i64; 128]; + let mut val_i64 = val as i64; + + for elem in &mut values { + *elem = val_i64; + val_i64 = std::hint::black_box(val_i64 + 1); + } + Self { values } + } + + fn as_i64(&self) -> i64 { + self.values[11] + self.values[55] + self.values[77] + } +} + +impl PartialOrd for FFIOneKibiByte { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for FFIOneKibiByte { + fn cmp(&self, other: &Self) -> Ordering { + self.as_i64().cmp(&other.as_i64()) + } +} + +// 16 byte stack value, with more expensive comparison. +#[repr(C)] +#[derive(PartialEq, Debug, Clone, Copy)] +pub struct F128 { + x: f64, + y: f64, +} + +impl F128 { + pub fn new(val: i32) -> Self { + let val_f = (val as f64) + (i32::MAX as f64) + 10.0; + + let x = val_f + 0.1; + let y = val_f.log(4.1); + + assert!(y < x); + assert!(x.is_normal() && y.is_normal()); + + Self { x, y } + } +} + +// This is kind of hacky, but we know we only have normal comparable floats in there. +impl Eq for F128 {} + +impl PartialOrd for F128 { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +// Goal is similar code-gen between Rust and C++ +// - Rust https://godbolt.org/z/3YM3xenPP +// - C++ https://godbolt.org/z/178M6j1zz +impl Ord for F128 { + fn cmp(&self, other: &Self) -> Ordering { + // Simulate expensive comparison function. + let this_div = self.x / self.y; + let other_div = other.x / other.y; + + // SAFETY: We checked in the ctor that both are normal. + unsafe { this_div.partial_cmp(&other_div).unwrap_unchecked() } + } +} diff --git a/library/alloctests/tests/sort/known_good_stable_sort.rs b/library/alloctests/tests/sort/known_good_stable_sort.rs new file mode 100644 index 00000000000..2df89146253 --- /dev/null +++ b/library/alloctests/tests/sort/known_good_stable_sort.rs @@ -0,0 +1,192 @@ +// This module implements a known good stable sort implementation that helps provide better error +// messages when the correctness tests fail, we can't use the stdlib sort functions because we are +// testing them for correctness. +// +// Based on https://github.com/voultapher/tiny-sort-rs. + +use alloc::alloc::{Layout, alloc, dealloc}; +use std::ptr; + +/// Sort `v` preserving initial order of equal elements. +/// +/// - Guaranteed O(N * log(N)) worst case perf +/// - No adaptiveness +/// - Branch miss-prediction not affected by outcome of comparison function +/// - Uses `v.len()` auxiliary memory. +/// +/// If `T: Ord` does not implement a total order the resulting order is +/// unspecified. All original elements will remain in `v` and any possible modifications via +/// interior mutability will be observable. Same is true if `T: Ord` panics. +/// +/// Panics if allocating the auxiliary memory fails. +#[inline(always)] +pub fn sort(v: &mut [T]) { + stable_sort(v, |a, b| a.lt(b)) +} + +#[inline(always)] +fn stable_sort bool>(v: &mut [T], mut is_less: F) { + if size_of::() == 0 { + return; + } + + let len = v.len(); + + // Inline the check for len < 2. This happens a lot, instrumenting the Rust compiler suggests + // len < 2 accounts for 94% of its calls to `slice::sort`. + if len < 2 { + return; + } + + // SAFETY: We checked that len is > 0 and that T is not a ZST. + unsafe { + mergesort_main(v, &mut is_less); + } +} + +/// The core logic should not be inlined. +/// +/// SAFETY: The caller has to ensure that len is > 0 and that T is not a ZST. +#[inline(never)] +unsafe fn mergesort_main bool>(v: &mut [T], is_less: &mut F) { + // While it would be nice to have a merge implementation that only requires N / 2 auxiliary + // memory. Doing so would make the merge implementation significantly more complex and + + // SAFETY: See function safety description. + let buf = unsafe { BufGuard::new(v.len()) }; + + // SAFETY: `scratch` has space for `v.len()` writes. And does not alias `v`. + unsafe { + mergesort_core(v, buf.buf_ptr.as_ptr(), is_less); + } +} + +/// Tiny recursive top-down merge sort optimized for binary size. It has no adaptiveness whatsoever, +/// no run detection, etc. +/// +/// Buffer as pointed to by `scratch` must have space for `v.len()` writes. And must not alias `v`. +#[inline(always)] +unsafe fn mergesort_core bool>( + v: &mut [T], + scratch_ptr: *mut T, + is_less: &mut F, +) { + let len = v.len(); + + if len > 2 { + // SAFETY: `mid` is guaranteed in-bounds. And caller has to ensure that `scratch_ptr` can + // hold `v.len()` values. + unsafe { + let mid = len / 2; + // Sort the left half recursively. + mergesort_core(v.get_unchecked_mut(..mid), scratch_ptr, is_less); + // Sort the right half recursively. + mergesort_core(v.get_unchecked_mut(mid..), scratch_ptr, is_less); + // Combine the two halves. + merge(v, scratch_ptr, is_less, mid); + } + } else if len == 2 { + if is_less(&v[1], &v[0]) { + v.swap(0, 1); + } + } +} + +/// Branchless merge function. +/// +/// SAFETY: The caller must ensure that `scratch_ptr` is valid for `v.len()` writes. And that mid is +/// in-bounds. +#[inline(always)] +unsafe fn merge(v: &mut [T], scratch_ptr: *mut T, is_less: &mut F, mid: usize) +where + F: FnMut(&T, &T) -> bool, +{ + let len = v.len(); + debug_assert!(mid > 0 && mid < len); + + let len = v.len(); + + // Indexes to track the positions while merging. + let mut l = 0; + let mut r = mid; + + // SAFETY: No matter what the result of is_less is we check that l and r remain in-bounds and if + // is_less panics the original elements remain in `v`. + unsafe { + let arr_ptr = v.as_ptr(); + + for i in 0..len { + let left_ptr = arr_ptr.add(l); + let right_ptr = arr_ptr.add(r); + + let is_lt = !is_less(&*right_ptr, &*left_ptr); + let copy_ptr = if is_lt { left_ptr } else { right_ptr }; + ptr::copy_nonoverlapping(copy_ptr, scratch_ptr.add(i), 1); + + l += is_lt as usize; + r += !is_lt as usize; + + // As long as neither side is exhausted merge left and right elements. + if ((l == mid) as u8 + (r == len) as u8) != 0 { + break; + } + } + + // The left or right side is exhausted, drain the right side in one go. + let copy_ptr = if l == mid { arr_ptr.add(r) } else { arr_ptr.add(l) }; + let i = l + (r - mid); + ptr::copy_nonoverlapping(copy_ptr, scratch_ptr.add(i), len - i); + + // Now that scratch_ptr holds the full merged content, write it back on-top of v. + ptr::copy_nonoverlapping(scratch_ptr, v.as_mut_ptr(), len); + } +} + +// SAFETY: The caller has to ensure that Option is Some, UB otherwise. +unsafe fn unwrap_unchecked(opt_val: Option) -> T { + match opt_val { + Some(val) => val, + None => { + // SAFETY: See function safety description. + unsafe { + core::hint::unreachable_unchecked(); + } + } + } +} + +// Extremely basic versions of Vec. +// Their use is super limited and by having the code here, it allows reuse between the sort +// implementations. +struct BufGuard { + buf_ptr: ptr::NonNull, + capacity: usize, +} + +impl BufGuard { + // SAFETY: The caller has to ensure that len is not 0 and that T is not a ZST. + unsafe fn new(len: usize) -> Self { + debug_assert!(len > 0 && size_of::() > 0); + + // SAFETY: See function safety description. + let layout = unsafe { unwrap_unchecked(Layout::array::(len).ok()) }; + + // SAFETY: We checked that T is not a ZST. + let buf_ptr = unsafe { alloc(layout) as *mut T }; + + if buf_ptr.is_null() { + panic!("allocation failure"); + } + + Self { buf_ptr: ptr::NonNull::new(buf_ptr).unwrap(), capacity: len } + } +} + +impl Drop for BufGuard { + fn drop(&mut self) { + // SAFETY: We checked that T is not a ZST. + unsafe { + dealloc(self.buf_ptr.as_ptr() as *mut u8, Layout::array::(self.capacity).unwrap()); + } + } +} diff --git a/library/alloctests/tests/sort/mod.rs b/library/alloctests/tests/sort/mod.rs new file mode 100644 index 00000000000..0e2494ca9d3 --- /dev/null +++ b/library/alloctests/tests/sort/mod.rs @@ -0,0 +1,17 @@ +pub trait Sort { + fn name() -> String; + + fn sort(v: &mut [T]) + where + T: Ord; + + fn sort_by(v: &mut [T], compare: F) + where + F: FnMut(&T, &T) -> std::cmp::Ordering; +} + +mod ffi_types; +mod known_good_stable_sort; +mod patterns; +mod tests; +mod zipf; diff --git a/library/alloctests/tests/sort/patterns.rs b/library/alloctests/tests/sort/patterns.rs new file mode 100644 index 00000000000..0f1ec664d3d --- /dev/null +++ b/library/alloctests/tests/sort/patterns.rs @@ -0,0 +1,211 @@ +use std::env; +use std::str::FromStr; +use std::sync::OnceLock; + +use rand::distr::Uniform; +use rand::prelude::*; +use rand_xorshift::XorShiftRng; + +use crate::sort::zipf::ZipfDistribution; + +/// Provides a set of patterns useful for testing and benchmarking sorting algorithms. +/// Currently limited to i32 values. + +// --- Public --- + +pub fn random(len: usize) -> Vec { + // . + // : . : : + // :.:::.:: + + random_vec(len) +} + +pub fn random_uniform(len: usize, range: R) -> Vec +where + Uniform: TryFrom, +{ + // :.:.:.:: + + let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + + // Abstracting over ranges in Rust :( + let dist = Uniform::try_from(range).unwrap(); + (0..len).map(|_| dist.sample(&mut rng)).collect() +} + +pub fn random_zipf(len: usize, exponent: f64) -> Vec { + // https://en.wikipedia.org/wiki/Zipf's_law + + let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + + // Abstracting over ranges in Rust :( + let dist = ZipfDistribution::new(len, exponent).unwrap(); + (0..len).map(|_| dist.sample(&mut rng) as i32).collect() +} + +pub fn random_sorted(len: usize, sorted_percent: f64) -> Vec { + // .: + // .:::. : + // .::::::.:: + // [----][--] + // ^ ^ + // | | + // sorted | + // unsorted + + // Simulate pre-existing sorted slice, where len - sorted_percent are the new unsorted values + // and part of the overall distribution. + let mut v = random_vec(len); + let sorted_len = ((len as f64) * (sorted_percent / 100.0)).round() as usize; + + v[0..sorted_len].sort_unstable(); + + v +} + +pub fn all_equal(len: usize) -> Vec { + // ...... + // :::::: + + (0..len).map(|_| 66).collect::>() +} + +pub fn ascending(len: usize) -> Vec { + // .: + // .::: + // .::::: + + (0..len as i32).collect::>() +} + +pub fn descending(len: usize) -> Vec { + // :. + // :::. + // :::::. + + (0..len as i32).rev().collect::>() +} + +pub fn saw_mixed(len: usize, saw_count: usize) -> Vec { + // :. :. .::. .: + // :::.:::..::::::..::: + + if len == 0 { + return Vec::new(); + } + + let mut vals = random_vec(len); + let chunks_size = len / saw_count.max(1); + let saw_directions = random_uniform((len / chunks_size) + 1, 0..=1); + + for (i, chunk) in vals.chunks_mut(chunks_size).enumerate() { + if saw_directions[i] == 0 { + chunk.sort_unstable(); + } else if saw_directions[i] == 1 { + chunk.sort_unstable_by_key(|&e| std::cmp::Reverse(e)); + } else { + unreachable!(); + } + } + + vals +} + +pub fn saw_mixed_range(len: usize, range: std::ops::Range) -> Vec { + // :. + // :. :::. .::. .: + // :::.:::::..::::::..:.::: + + // ascending and descending randomly picked, with length in `range`. + + if len == 0 { + return Vec::new(); + } + + let mut vals = random_vec(len); + + let max_chunks = len / range.start; + let saw_directions = random_uniform(max_chunks + 1, 0..=1); + let chunk_sizes = random_uniform(max_chunks + 1, (range.start as i32)..(range.end as i32)); + + let mut i = 0; + let mut l = 0; + while l < len { + let chunk_size = chunk_sizes[i] as usize; + let chunk_end = std::cmp::min(l + chunk_size, len); + let chunk = &mut vals[l..chunk_end]; + + if saw_directions[i] == 0 { + chunk.sort_unstable(); + } else if saw_directions[i] == 1 { + chunk.sort_unstable_by_key(|&e| std::cmp::Reverse(e)); + } else { + unreachable!(); + } + + i += 1; + l += chunk_size; + } + + vals +} + +pub fn pipe_organ(len: usize) -> Vec { + // .:. + // .:::::. + + let mut vals = random_vec(len); + + let first_half = &mut vals[0..(len / 2)]; + first_half.sort_unstable(); + + let second_half = &mut vals[(len / 2)..len]; + second_half.sort_unstable_by_key(|&e| std::cmp::Reverse(e)); + + vals +} + +pub fn get_or_init_rand_seed() -> u64 { + *SEED_VALUE.get_or_init(|| { + env::var("OVERRIDE_SEED") + .ok() + .map(|seed| u64::from_str(&seed).unwrap()) + .unwrap_or_else(rand_root_seed) + }) +} + +// --- Private --- + +static SEED_VALUE: OnceLock = OnceLock::new(); + +#[cfg(not(miri))] +fn rand_root_seed() -> u64 { + // Other test code hashes `panic::Location::caller()` and constructs a seed from that, in these + // tests we want to have a fuzzer like exploration of the test space, if we used the same caller + // based construction we would always test the same. + // + // Instead we use the seconds since UNIX epoch / 10, given CI log output this value should be + // reasonably easy to re-construct. + + use std::time::{SystemTime, UNIX_EPOCH}; + + let epoch_seconds = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); + + epoch_seconds / 10 +} + +#[cfg(miri)] +fn rand_root_seed() -> u64 { + // Miri is usually run with isolation with gives us repeatability but also permutations based on + // other code that runs before. + use core::hash::{BuildHasher, Hash, Hasher}; + let mut hasher = std::hash::RandomState::new().build_hasher(); + core::panic::Location::caller().hash(&mut hasher); + hasher.finish() +} + +fn random_vec(len: usize) -> Vec { + let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + (0..len).map(|_| rng.random::()).collect() +} diff --git a/library/alloctests/tests/sort/tests.rs b/library/alloctests/tests/sort/tests.rs new file mode 100644 index 00000000000..d321f8df518 --- /dev/null +++ b/library/alloctests/tests/sort/tests.rs @@ -0,0 +1,1240 @@ +use std::cell::Cell; +use std::cmp::Ordering; +use std::fmt::Debug; +use std::panic::{self, AssertUnwindSafe}; +use std::rc::Rc; +use std::{env, fs}; + +use crate::sort::ffi_types::{F128, FFIOneKibiByte}; +use crate::sort::{Sort, known_good_stable_sort, patterns}; + +#[cfg(miri)] +const TEST_LENGTHS: &[usize] = &[2, 3, 4, 7, 10, 15, 20, 24, 33, 50, 100, 171, 300]; + +// node.js gives out of memory error to use with length 1_100_000 +#[cfg(all(not(miri), target_os = "emscripten"))] +const TEST_LENGTHS: &[usize] = &[ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 20, 24, 30, 32, 33, 35, 50, 100, 200, 500, 1_000, + 2_048, 5_000, 10_000, 100_000, +]; + +#[cfg(all(not(miri), not(target_os = "emscripten")))] +const TEST_LENGTHS: &[usize] = &[ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 20, 24, 30, 32, 33, 35, 50, 100, 200, 500, 1_000, + 2_048, 5_000, 10_000, 100_000, 1_100_000, +]; + +fn check_is_sorted(v: &mut [T]) { + let seed = patterns::get_or_init_rand_seed(); + + let is_small_test = v.len() <= 100; + let v_orig = v.to_vec(); + + ::sort(v); + + assert_eq!(v.len(), v_orig.len()); + + for window in v.windows(2) { + if window[0] > window[1] { + let mut known_good_sorted_vec = v_orig.clone(); + known_good_stable_sort::sort(known_good_sorted_vec.as_mut_slice()); + + if is_small_test { + eprintln!("Original: {:?}", v_orig); + eprintln!("Expected: {:?}", known_good_sorted_vec); + eprintln!("Got: {:?}", v); + } else { + if env::var("WRITE_LARGE_FAILURE").is_ok() { + // Large arrays output them as files. + let original_name = format!("original_{}.txt", seed); + let std_name = format!("known_good_sorted_{}.txt", seed); + let testsort_name = format!("{}_sorted_{}.txt", S::name(), seed); + + fs::write(&original_name, format!("{:?}", v_orig)).unwrap(); + fs::write(&std_name, format!("{:?}", known_good_sorted_vec)).unwrap(); + fs::write(&testsort_name, format!("{:?}", v)).unwrap(); + + eprintln!( + "Failed comparison, see files {original_name}, {std_name}, and {testsort_name}" + ); + } else { + eprintln!( + "Failed comparison, re-run with WRITE_LARGE_FAILURE env var set, to get output." + ); + } + } + + panic!("Test assertion failed!") + } + } +} + +fn test_is_sorted( + test_len: usize, + map_fn: impl Fn(i32) -> T, + pattern_fn: impl Fn(usize) -> Vec, +) { + let mut test_data: Vec = pattern_fn(test_len).into_iter().map(map_fn).collect(); + check_is_sorted::(test_data.as_mut_slice()); +} + +trait DynTrait: Debug { + fn get_val(&self) -> i32; +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +struct DynValA { + value: i32, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +struct DynValB { + value: u64, +} + +impl DynTrait for DynValA { + fn get_val(&self) -> i32 { + self.value + } +} +impl DynTrait for DynValB { + fn get_val(&self) -> i32 { + let bytes = self.value.to_ne_bytes(); + i32::from_ne_bytes([bytes[0], bytes[1], bytes[6], bytes[7]]) + } +} + +impl PartialOrd for dyn DynTrait { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for dyn DynTrait { + fn cmp(&self, other: &Self) -> Ordering { + self.get_val().cmp(&other.get_val()) + } +} + +impl PartialEq for dyn DynTrait { + fn eq(&self, other: &Self) -> bool { + self.get_val() == other.get_val() + } +} + +impl Eq for dyn DynTrait {} + +fn shift_i32_to_u32(val: i32) -> u32 { + (val as i64 + (i32::MAX as i64 + 1)) as u32 +} + +fn reverse_shift_i32_to_u32(val: u32) -> i32 { + (val as i64 - (i32::MAX as i64 + 1)) as i32 +} + +fn extend_i32_to_u64(val: i32) -> u64 { + // Extends the value into the 64 bit range, + // while preserving input order. + (shift_i32_to_u32(val) as u64) * i32::MAX as u64 +} + +fn extend_i32_to_u128(val: i32) -> u128 { + // Extends the value into the 64 bit range, + // while preserving input order. + (shift_i32_to_u32(val) as u128) * i64::MAX as u128 +} + +fn dyn_trait_from_i32(val: i32) -> Rc { + if val % 2 == 0 { + Rc::new(DynValA { value: val }) + } else { + Rc::new(DynValB { value: extend_i32_to_u64(val) }) + } +} + +fn i32_from_i32(val: i32) -> i32 { + val +} + +fn i32_from_i32_ref(val: &i32) -> i32 { + *val +} + +fn string_from_i32(val: i32) -> String { + format!("{:010}", shift_i32_to_u32(val)) +} + +fn i32_from_string(val: &String) -> i32 { + reverse_shift_i32_to_u32(val.parse::().unwrap()) +} + +fn cell_i32_from_i32(val: i32) -> Cell { + Cell::new(val) +} + +fn i32_from_cell_i32(val: &Cell) -> i32 { + val.get() +} + +fn calc_comps_required(v: &mut [T], mut cmp_fn: impl FnMut(&T, &T) -> Ordering) -> u32 { + let mut comp_counter = 0u32; + + ::sort_by(v, |a, b| { + comp_counter += 1; + + cmp_fn(a, b) + }); + + comp_counter +} + +#[derive(PartialEq, Eq, Debug, Clone)] +#[repr(C)] +struct CompCount { + val: i32, + comp_count: Cell, +} + +impl CompCount { + fn new(val: i32) -> Self { + Self { val, comp_count: Cell::new(0) } + } +} + +/// Generates $base_name_pattern_name_impl functions calling the test_fns for all test_len. +macro_rules! gen_sort_test_fns { + ( + $base_name:ident, + $test_fn:expr, + $test_lengths:expr, + [$(($pattern_name:ident, $pattern_fn:expr)),* $(,)?] $(,)? + ) => { + $(fn ${concat($base_name, _, $pattern_name, _impl)}() { + for test_len in $test_lengths { + $test_fn(*test_len, $pattern_fn); + } + })* + }; +} + +/// Generates $base_name_pattern_name_impl functions calling the test_fns for all test_len, +/// with a default set of patterns that can be extended by the caller. +macro_rules! gen_sort_test_fns_with_default_patterns { + ( + $base_name:ident, + $test_fn:expr, + $test_lengths:expr, + [$(($pattern_name:ident, $pattern_fn:expr)),* $(,)?] $(,)? + ) => { + gen_sort_test_fns!( + $base_name, + $test_fn, + $test_lengths, + [ + (random, patterns::random), + (random_z1, |len| patterns::random_zipf(len, 1.0)), + (random_d2, |len| patterns::random_uniform(len, 0..2)), + (random_d20, |len| patterns::random_uniform(len, 0..16)), + (random_s95, |len| patterns::random_sorted(len, 95.0)), + (ascending, patterns::ascending), + (descending, patterns::descending), + (saw_mixed, |len| patterns::saw_mixed( + len, + ((len as f64).log2().round()) as usize + )), + $(($pattern_name, $pattern_fn),)* + ] + ); + }; +} + +/// Generates $base_name_type_pattern_name_impl functions calling the test_fns for all test_len for +/// three types that cover the core specialization differences in the sort implementations, with a +/// default set of patterns that can be extended by the caller. +macro_rules! gen_sort_test_fns_with_default_patterns_3_ty { + ( + $base_name:ident, + $test_fn:ident, + [$(($pattern_name:ident, $pattern_fn:expr)),* $(,)?] $(,)? + ) => { + gen_sort_test_fns_with_default_patterns!( + ${concat($base_name, _i32)}, + |len, pattern_fn| $test_fn::(len, i32_from_i32, i32_from_i32_ref, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [$(($pattern_name, $pattern_fn),)*], + ); + + gen_sort_test_fns_with_default_patterns!( + ${concat($base_name, _cell_i32)}, + |len, pattern_fn| $test_fn::, S>(len, cell_i32_from_i32, i32_from_cell_i32, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 3], + [$(($pattern_name, $pattern_fn),)*], + ); + + gen_sort_test_fns_with_default_patterns!( + ${concat($base_name, _string)}, + |len, pattern_fn| $test_fn::(len, string_from_i32, i32_from_string, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 3], + [$(($pattern_name, $pattern_fn),)*], + ); + }; +} + +// --- TESTS --- + +pub fn basic_impl() { + check_is_sorted::(&mut []); + check_is_sorted::<(), S>(&mut []); + check_is_sorted::<(), S>(&mut [()]); + check_is_sorted::<(), S>(&mut [(), ()]); + check_is_sorted::<(), S>(&mut [(), (), ()]); + check_is_sorted::(&mut []); + check_is_sorted::(&mut [77]); + check_is_sorted::(&mut [2, 3]); + check_is_sorted::(&mut [2, 3, 6]); + check_is_sorted::(&mut [2, 3, 99, 6]); + check_is_sorted::(&mut [2, 7709, 400, 90932]); + check_is_sorted::(&mut [15, -1, 3, -1, -3, -1, 7]); +} + +fn fixed_seed_impl() { + let fixed_seed_a = patterns::get_or_init_rand_seed(); + let fixed_seed_b = patterns::get_or_init_rand_seed(); + + assert_eq!(fixed_seed_a, fixed_seed_b); +} + +fn fixed_seed_rand_vec_prefix_impl() { + let vec_rand_len_5 = patterns::random(5); + let vec_rand_len_7 = patterns::random(7); + + assert_eq!(vec_rand_len_5, vec_rand_len_7[..5]); +} + +fn int_edge_impl() { + // Ensure that the sort can handle integer edge cases. + check_is_sorted::(&mut [i32::MIN, i32::MAX]); + check_is_sorted::(&mut [i32::MAX, i32::MIN]); + check_is_sorted::(&mut [i32::MIN, 3]); + check_is_sorted::(&mut [i32::MIN, -3]); + check_is_sorted::(&mut [i32::MIN, -3, i32::MAX]); + check_is_sorted::(&mut [i32::MIN, -3, i32::MAX, i32::MIN, 5]); + check_is_sorted::(&mut [i32::MAX, 3, i32::MIN, 5, i32::MIN, -3, 60, 200, 50, 7, 10]); + + check_is_sorted::(&mut [u64::MIN, u64::MAX]); + check_is_sorted::(&mut [u64::MAX, u64::MIN]); + check_is_sorted::(&mut [u64::MIN, 3]); + check_is_sorted::(&mut [u64::MIN, u64::MAX - 3]); + check_is_sorted::(&mut [u64::MIN, u64::MAX - 3, u64::MAX]); + check_is_sorted::(&mut [u64::MIN, u64::MAX - 3, u64::MAX, u64::MIN, 5]); + check_is_sorted::(&mut [ + u64::MAX, + 3, + u64::MIN, + 5, + u64::MIN, + u64::MAX - 3, + 60, + 200, + 50, + 7, + 10, + ]); + + let mut large = patterns::random(TEST_LENGTHS[TEST_LENGTHS.len() - 2]); + large.push(i32::MAX); + large.push(i32::MIN); + large.push(i32::MAX); + check_is_sorted::(&mut large); +} + +fn sort_vs_sort_by_impl() { + // Ensure that sort and sort_by produce the same result. + let mut input_normal = [800, 3, -801, 5, -801, -3, 60, 200, 50, 7, 10]; + let expected = [-801, -801, -3, 3, 5, 7, 10, 50, 60, 200, 800]; + + let mut input_sort_by = input_normal.to_vec(); + + ::sort(&mut input_normal); + ::sort_by(&mut input_sort_by, |a, b| a.cmp(b)); + + assert_eq!(input_normal, expected); + assert_eq!(input_sort_by, expected); +} + +gen_sort_test_fns_with_default_patterns!( + correct_i32, + |len, pattern_fn| test_is_sorted::(len, |val| val, pattern_fn), + TEST_LENGTHS, + [ + (random_d4, |len| patterns::random_uniform(len, 0..4)), + (random_d8, |len| patterns::random_uniform(len, 0..8)), + (random_d311, |len| patterns::random_uniform(len, 0..311)), + (random_d1024, |len| patterns::random_uniform(len, 0..1024)), + (random_z1_03, |len| patterns::random_zipf(len, 1.03)), + (random_z2, |len| patterns::random_zipf(len, 2.0)), + (random_s50, |len| patterns::random_sorted(len, 50.0)), + (narrow, |len| patterns::random_uniform( + len, + 0..=(((len as f64).log2().round()) as i32) * 100 + )), + (all_equal, patterns::all_equal), + (saw_mixed_range, |len| patterns::saw_mixed_range(len, 20..50)), + (pipe_organ, patterns::pipe_organ), + ] +); + +gen_sort_test_fns_with_default_patterns!( + correct_u64, + |len, pattern_fn| test_is_sorted::(len, extend_i32_to_u64, pattern_fn), + TEST_LENGTHS, + [] +); + +gen_sort_test_fns_with_default_patterns!( + correct_u128, + |len, pattern_fn| test_is_sorted::(len, extend_i32_to_u128, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +gen_sort_test_fns_with_default_patterns!( + correct_cell_i32, + |len, pattern_fn| test_is_sorted::, S>(len, Cell::new, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +gen_sort_test_fns_with_default_patterns!( + correct_string, + |len, pattern_fn| test_is_sorted::( + len, + |val| format!("{:010}", shift_i32_to_u32(val)), + pattern_fn + ), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +gen_sort_test_fns_with_default_patterns!( + correct_f128, + |len, pattern_fn| test_is_sorted::(len, F128::new, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +gen_sort_test_fns_with_default_patterns!( + correct_1k, + |len, pattern_fn| test_is_sorted::(len, FFIOneKibiByte::new, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +// Dyn values are fat pointers, something the implementation might have overlooked. +gen_sort_test_fns_with_default_patterns!( + correct_dyn_val, + |len, pattern_fn| test_is_sorted::, S>(len, dyn_trait_from_i32, pattern_fn), + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +fn stability_legacy_impl() { + // This non pattern variant has proven to catch some bugs the pattern version of this function + // doesn't catch, so it remains in conjunction with the other one. + + if ::name().contains("unstable") { + // It would be great to mark the test as skipped, but that isn't possible as of now. + return; + } + + let large_range = if cfg!(miri) { 100..110 } else { 3000..3010 }; + let rounds = if cfg!(miri) { 1 } else { 10 }; + + let rand_vals = patterns::random_uniform(5_000, 0..=9); + let mut rand_idx = 0; + + for len in (2..55).chain(large_range) { + for _ in 0..rounds { + let mut counts = [0; 10]; + + // create a vector like [(6, 1), (5, 1), (6, 2), ...], + // where the first item of each tuple is random, but + // the second item represents which occurrence of that + // number this element is, i.e., the second elements + // will occur in sorted order. + let orig: Vec<_> = (0..len) + .map(|_| { + let n = rand_vals[rand_idx]; + rand_idx += 1; + if rand_idx >= rand_vals.len() { + rand_idx = 0; + } + + counts[n as usize] += 1; + i32_tup_as_u64((n, counts[n as usize])) + }) + .collect(); + + let mut v = orig.clone(); + // Only sort on the first element, so an unstable sort + // may mix up the counts. + ::sort_by(&mut v, |a_packed, b_packed| { + let a = i32_tup_from_u64(*a_packed).0; + let b = i32_tup_from_u64(*b_packed).0; + + a.cmp(&b) + }); + + // This comparison includes the count (the second item + // of the tuple), so elements with equal first items + // will need to be ordered with increasing + // counts... i.e., exactly asserting that this sort is + // stable. + assert!(v.windows(2).all(|w| i32_tup_from_u64(w[0]) <= i32_tup_from_u64(w[1]))); + } + } + + // For cpp_sorts that only support u64 we can pack the two i32 inside a u64. + fn i32_tup_as_u64(val: (i32, i32)) -> u64 { + let a_bytes = val.0.to_le_bytes(); + let b_bytes = val.1.to_le_bytes(); + + u64::from_le_bytes([a_bytes, b_bytes].concat().try_into().unwrap()) + } + + fn i32_tup_from_u64(val: u64) -> (i32, i32) { + let bytes = val.to_le_bytes(); + + let a = i32::from_le_bytes(bytes[0..4].try_into().unwrap()); + let b = i32::from_le_bytes(bytes[4..8].try_into().unwrap()); + + (a, b) + } +} + +fn stability_with_patterns( + len: usize, + type_into_fn: impl Fn(i32) -> T, + _type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec, +) { + if ::name().contains("unstable") { + // It would be great to mark the test as skipped, but that isn't possible as of now. + return; + } + + let pattern = pattern_fn(len); + + let mut counts = [0i32; 128]; + + // create a vector like [(6, 1), (5, 1), (6, 2), ...], + // where the first item of each tuple is random, but + // the second item represents which occurrence of that + // number this element is, i.e., the second elements + // will occur in sorted order. + let orig: Vec<_> = pattern + .iter() + .map(|val| { + let n = val.saturating_abs() % counts.len() as i32; + counts[n as usize] += 1; + (type_into_fn(n), counts[n as usize]) + }) + .collect(); + + let mut v = orig.clone(); + // Only sort on the first element, so an unstable sort + // may mix up the counts. + ::sort(&mut v); + + // This comparison includes the count (the second item + // of the tuple), so elements with equal first items + // will need to be ordered with increasing + // counts... i.e., exactly asserting that this sort is + // stable. + assert!(v.windows(2).all(|w| w[0] <= w[1])); +} + +gen_sort_test_fns_with_default_patterns_3_ty!(stability, stability_with_patterns, []); + +fn observable_is_less(len: usize, pattern_fn: fn(usize) -> Vec) { + // This test, tests that every is_less is actually observable. Ie. this can go wrong if a hole + // is created using temporary memory and, the whole is used as comparison but not copied back. + // + // If this is not upheld a custom type + comparison function could yield UB in otherwise safe + // code. Eg T == Mutex>> which replaces the pointer with none in the comparison + // function, which would not be observed in the original slice and would lead to a double free. + + let pattern = pattern_fn(len); + let mut test_input = pattern.into_iter().map(|val| CompCount::new(val)).collect::>(); + + let mut comp_count_global = 0; + + ::sort_by(&mut test_input, |a, b| { + a.comp_count.replace(a.comp_count.get() + 1); + b.comp_count.replace(b.comp_count.get() + 1); + comp_count_global += 1; + + a.val.cmp(&b.val) + }); + + let total_inner: u64 = test_input.iter().map(|c| c.comp_count.get() as u64).sum(); + + assert_eq!(total_inner, comp_count_global * 2); +} + +gen_sort_test_fns_with_default_patterns!( + observable_is_less, + observable_is_less::, + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +fn panic_retain_orig_set( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec, +) { + let mut test_data: Vec = pattern_fn(len).into_iter().map(type_into_fn).collect(); + + let sum_before: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); + + // Calculate a specific comparison that should panic. + // Ensure that it can be any of the possible comparisons and that it always panics. + let required_comps = calc_comps_required::(&mut test_data.clone(), |a, b| a.cmp(b)); + let panic_threshold = patterns::random_uniform(1, 1..=required_comps as i32)[0] as usize - 1; + + let mut comp_counter = 0; + + let res = panic::catch_unwind(AssertUnwindSafe(|| { + ::sort_by(&mut test_data, |a, b| { + if comp_counter == panic_threshold { + // Make the panic dependent on the test len and some random factor. We want to + // make sure that panicking may also happen when comparing elements a second + // time. + panic!(); + } + comp_counter += 1; + + a.cmp(b) + }); + })); + + assert!(res.is_err()); + + // If the sum before and after don't match, it means the set of elements hasn't remained the + // same. + let sum_after: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); + assert_eq!(sum_before, sum_after); +} + +gen_sort_test_fns_with_default_patterns_3_ty!(panic_retain_orig_set, panic_retain_orig_set, []); + +fn panic_observable_is_less(len: usize, pattern_fn: fn(usize) -> Vec) { + // This test, tests that every is_less is actually observable. Ie. this can go wrong if a hole + // is created using temporary memory and, the whole is used as comparison but not copied back. + // This property must also hold if the user provided comparison panics. + // + // If this is not upheld a custom type + comparison function could yield UB in otherwise safe + // code. Eg T == Mutex>> which replaces the pointer with none in the comparison + // function, which would not be observed in the original slice and would lead to a double free. + + let mut test_input = + pattern_fn(len).into_iter().map(|val| CompCount::new(val)).collect::>(); + + let sum_before: i64 = test_input.iter().map(|x| x.val as i64).sum(); + + // Calculate a specific comparison that should panic. + // Ensure that it can be any of the possible comparisons and that it always panics. + let required_comps = + calc_comps_required::(&mut test_input.clone(), |a, b| a.val.cmp(&b.val)); + + let panic_threshold = patterns::random_uniform(1, 1..=required_comps as i32)[0] as u64 - 1; + + let mut comp_count_global = 0; + + let res = panic::catch_unwind(AssertUnwindSafe(|| { + ::sort_by(&mut test_input, |a, b| { + if comp_count_global == panic_threshold { + // Make the panic dependent on the test len and some random factor. We want to + // make sure that panicking may also happen when comparing elements a second + // time. + panic!(); + } + + a.comp_count.replace(a.comp_count.get() + 1); + b.comp_count.replace(b.comp_count.get() + 1); + comp_count_global += 1; + + a.val.cmp(&b.val) + }); + })); + + assert!(res.is_err()); + + let total_inner: u64 = test_input.iter().map(|c| c.comp_count.get() as u64).sum(); + + assert_eq!(total_inner, comp_count_global * 2); + + // If the sum before and after don't match, it means the set of elements hasn't remained the + // same. + let sum_after: i64 = test_input.iter().map(|x| x.val as i64).sum(); + assert_eq!(sum_before, sum_after); +} + +gen_sort_test_fns_with_default_patterns!( + panic_observable_is_less, + panic_observable_is_less::, + &TEST_LENGTHS[..TEST_LENGTHS.len() - 2], + [] +); + +fn deterministic( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec, +) { + // A property similar to stability is deterministic output order. If the entire value is used as + // the comparison key a lack of determinism has no effect. But if only a part of the value is + // used as comparison key, a lack of determinism can manifest itself in the order of values + // considered equal by the comparison predicate. + // + // This test only tests that results are deterministic across runs, it does not test determinism + // on different platforms and with different toolchains. + + let mut test_input = + pattern_fn(len).into_iter().map(|val| type_into_fn(val)).collect::>(); + + let mut test_input_clone = test_input.clone(); + + let comparison_fn = |a: &T, b: &T| { + let a_i32 = type_from_fn(a); + let b_i32 = type_from_fn(b); + + let a_i32_key_space_reduced = a_i32 % 10_000; + let b_i32_key_space_reduced = b_i32 % 10_000; + + a_i32_key_space_reduced.cmp(&b_i32_key_space_reduced) + }; + + ::sort_by(&mut test_input, comparison_fn); + ::sort_by(&mut test_input_clone, comparison_fn); + + assert_eq!(test_input, test_input_clone); +} + +gen_sort_test_fns_with_default_patterns_3_ty!(deterministic, deterministic, []); + +fn self_cmp( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + _type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec, +) { + // It's possible for comparisons to run into problems if the values of `a` and `b` passed into + // the comparison function are the same reference. So this tests that they never are. + + let mut test_input = + pattern_fn(len).into_iter().map(|val| type_into_fn(val)).collect::>(); + + let comparison_fn = |a: &T, b: &T| { + assert_ne!(a as *const T as usize, b as *const T as usize); + a.cmp(b) + }; + + ::sort_by(&mut test_input, comparison_fn); + + // Check that the output is actually sorted and wasn't stopped by the assert. + for window in test_input.windows(2) { + assert!(window[0] <= window[1]); + } +} + +gen_sort_test_fns_with_default_patterns_3_ty!(self_cmp, self_cmp, []); + +fn violate_ord_retain_orig_set( + len: usize, + type_into_fn: impl Fn(i32) -> T + Copy, + type_from_fn: impl Fn(&T) -> i32, + pattern_fn: fn(usize) -> Vec, +) { + // A user may implement Ord incorrectly for a type or violate it by calling sort_by with a + // comparison function that violates Ord with the orderings it returns. Even under such + // circumstances the input must retain its original set of elements. + + // Ord implies a strict total order see https://en.wikipedia.org/wiki/Total_order. + + // Generating random numbers with miri is quite expensive. + let random_orderings_len = if cfg!(miri) { 200 } else { 10_000 }; + + // Make sure we get a good distribution of random orderings, that are repeatable with the seed. + // Just using random_uniform with the same len and range will always yield the same value. + let random_orderings = patterns::random_uniform(random_orderings_len, 0..2); + + let get_random_0_1_or_2 = |random_idx: &mut usize| { + let ridx = *random_idx; + *random_idx += 1; + if ridx + 1 == random_orderings.len() { + *random_idx = 0; + } + + random_orderings[ridx] as usize + }; + + let mut random_idx_a = 0; + let mut random_idx_b = 0; + let mut random_idx_c = 0; + + let mut last_element_a = -1; + let mut last_element_b = -1; + + let mut rand_counter_b = 0; + let mut rand_counter_c = 0; + + let mut streak_counter_a = 0; + let mut streak_counter_b = 0; + + // Examples, a = 3, b = 5, c = 9. + // Correct Ord -> 10010 | is_less(a, b) is_less(a, a) is_less(b, a) is_less(a, c) is_less(c, a) + let mut invalid_ord_comp_functions: Vec Ordering>> = vec![ + Box::new(|_a, _b| -> Ordering { + // random + // Eg. is_less(3, 5) == true, is_less(3, 5) == false + + let idx = get_random_0_1_or_2(&mut random_idx_a); + [Ordering::Less, Ordering::Equal, Ordering::Greater][idx] + }), + Box::new(|_a, _b| -> Ordering { + // everything is less -> 11111 + Ordering::Less + }), + Box::new(|_a, _b| -> Ordering { + // everything is equal -> 00000 + Ordering::Equal + }), + Box::new(|_a, _b| -> Ordering { + // everything is greater -> 00000 + // Eg. is_less(3, 5) == false, is_less(5, 3) == false, is_less(3, 3) == false + Ordering::Greater + }), + Box::new(|a, b| -> Ordering { + // equal means less else greater -> 01000 + if a == b { Ordering::Less } else { Ordering::Greater } + }), + Box::new(|a, b| -> Ordering { + // Transitive breaker. remember last element -> 10001 + let lea = last_element_a; + let leb = last_element_b; + + let a_as_i32 = type_from_fn(a); + let b_as_i32 = type_from_fn(b); + + last_element_a = a_as_i32; + last_element_b = b_as_i32; + + if a_as_i32 == lea && b_as_i32 != leb { b.cmp(a) } else { a.cmp(b) } + }), + Box::new(|a, b| -> Ordering { + // Sampled random 1% of comparisons are reversed. + rand_counter_b += get_random_0_1_or_2(&mut random_idx_b); + if rand_counter_b >= 100 { + rand_counter_b = 0; + b.cmp(a) + } else { + a.cmp(b) + } + }), + Box::new(|a, b| -> Ordering { + // Sampled random 33% of comparisons are reversed. + rand_counter_c += get_random_0_1_or_2(&mut random_idx_c); + if rand_counter_c >= 3 { + rand_counter_c = 0; + b.cmp(a) + } else { + a.cmp(b) + } + }), + Box::new(|a, b| -> Ordering { + // STREAK_LEN comparisons yield a.cmp(b) then STREAK_LEN comparisons less. This can + // discover bugs that neither, random Ord, or just Less or Greater can find. Because it + // can push a pointer further than expected. Random Ord will average out how far a + // comparison based pointer travels. Just Less or Greater will be caught by pattern + // analysis and never enter interesting code. + const STREAK_LEN: usize = 50; + + streak_counter_a += 1; + if streak_counter_a <= STREAK_LEN { + a.cmp(b) + } else { + if streak_counter_a == STREAK_LEN * 2 { + streak_counter_a = 0; + } + Ordering::Less + } + }), + Box::new(|a, b| -> Ordering { + // See above. + const STREAK_LEN: usize = 50; + + streak_counter_b += 1; + if streak_counter_b <= STREAK_LEN { + a.cmp(b) + } else { + if streak_counter_b == STREAK_LEN * 2 { + streak_counter_b = 0; + } + Ordering::Greater + } + }), + ]; + + for comp_func in &mut invalid_ord_comp_functions { + let mut test_data: Vec = pattern_fn(len).into_iter().map(type_into_fn).collect(); + let sum_before: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); + + // It's ok to panic on Ord violation or to complete. + // In both cases the original elements must still be present. + let _ = panic::catch_unwind(AssertUnwindSafe(|| { + ::sort_by(&mut test_data, &mut *comp_func); + })); + + // If the sum before and after don't match, it means the set of elements hasn't remained the + // same. + let sum_after: i64 = test_data.iter().map(|x| type_from_fn(x) as i64).sum(); + assert_eq!(sum_before, sum_after); + + if cfg!(miri) { + // This test is prohibitively expensive in miri, so only run one of the comparison + // functions. This test is not expected to yield direct UB, but rather surface potential + // UB by showing that the sum is different now. + break; + } + } +} + +gen_sort_test_fns_with_default_patterns_3_ty!( + violate_ord_retain_orig_set, + violate_ord_retain_orig_set, + [] +); + +macro_rules! instantiate_sort_test_inner { + ($sort_impl:ty, miri_yes, $test_fn_name:ident) => { + #[test] + fn $test_fn_name() { + $crate::sort::tests::$test_fn_name::<$sort_impl>(); + } + }; + ($sort_impl:ty, miri_no, $test_fn_name:ident) => { + #[test] + #[cfg_attr(miri, ignore)] + fn $test_fn_name() { + $crate::sort::tests::$test_fn_name::<$sort_impl>(); + } + }; +} + +// Using this construct allows us to get warnings for unused test functions. +macro_rules! define_instantiate_sort_tests { + ($([$miri_use:ident, $test_fn_name:ident]),*,) => { + $(pub fn $test_fn_name() { + ${concat($test_fn_name, _impl)}::(); + })* + + + macro_rules! instantiate_sort_tests_gen { + ($sort_impl:ty) => { + $( + instantiate_sort_test_inner!( + $sort_impl, + $miri_use, + $test_fn_name + ); + )* + } + } + }; +} + +// Some tests are not tested with miri to avoid prohibitively long test times. This leaves coverage +// holes, but the way they are selected should make for relatively small holes. Many properties that +// can lead to UB are tested directly, for example that the original set of elements is retained +// even when a panic occurs or Ord is implemented incorrectly. +define_instantiate_sort_tests!( + [miri_yes, basic], + [miri_yes, fixed_seed], + [miri_yes, fixed_seed_rand_vec_prefix], + [miri_yes, int_edge], + [miri_yes, sort_vs_sort_by], + [miri_yes, correct_i32_random], + [miri_yes, correct_i32_random_z1], + [miri_yes, correct_i32_random_d2], + [miri_yes, correct_i32_random_d20], + [miri_yes, correct_i32_random_s95], + [miri_yes, correct_i32_ascending], + [miri_yes, correct_i32_descending], + [miri_yes, correct_i32_saw_mixed], + [miri_no, correct_i32_random_d4], + [miri_no, correct_i32_random_d8], + [miri_no, correct_i32_random_d311], + [miri_no, correct_i32_random_d1024], + [miri_no, correct_i32_random_z1_03], + [miri_no, correct_i32_random_z2], + [miri_no, correct_i32_random_s50], + [miri_no, correct_i32_narrow], + [miri_no, correct_i32_all_equal], + [miri_no, correct_i32_saw_mixed_range], + [miri_yes, correct_i32_pipe_organ], + [miri_no, correct_u64_random], + [miri_yes, correct_u64_random_z1], + [miri_no, correct_u64_random_d2], + [miri_no, correct_u64_random_d20], + [miri_no, correct_u64_random_s95], + [miri_no, correct_u64_ascending], + [miri_no, correct_u64_descending], + [miri_no, correct_u64_saw_mixed], + [miri_no, correct_u128_random], + [miri_yes, correct_u128_random_z1], + [miri_no, correct_u128_random_d2], + [miri_no, correct_u128_random_d20], + [miri_no, correct_u128_random_s95], + [miri_no, correct_u128_ascending], + [miri_no, correct_u128_descending], + [miri_no, correct_u128_saw_mixed], + [miri_no, correct_cell_i32_random], + [miri_yes, correct_cell_i32_random_z1], + [miri_no, correct_cell_i32_random_d2], + [miri_no, correct_cell_i32_random_d20], + [miri_no, correct_cell_i32_random_s95], + [miri_no, correct_cell_i32_ascending], + [miri_no, correct_cell_i32_descending], + [miri_no, correct_cell_i32_saw_mixed], + [miri_no, correct_string_random], + [miri_yes, correct_string_random_z1], + [miri_no, correct_string_random_d2], + [miri_no, correct_string_random_d20], + [miri_no, correct_string_random_s95], + [miri_no, correct_string_ascending], + [miri_no, correct_string_descending], + [miri_no, correct_string_saw_mixed], + [miri_no, correct_f128_random], + [miri_yes, correct_f128_random_z1], + [miri_no, correct_f128_random_d2], + [miri_no, correct_f128_random_d20], + [miri_no, correct_f128_random_s95], + [miri_no, correct_f128_ascending], + [miri_no, correct_f128_descending], + [miri_no, correct_f128_saw_mixed], + [miri_no, correct_1k_random], + [miri_yes, correct_1k_random_z1], + [miri_no, correct_1k_random_d2], + [miri_no, correct_1k_random_d20], + [miri_no, correct_1k_random_s95], + [miri_no, correct_1k_ascending], + [miri_no, correct_1k_descending], + [miri_no, correct_1k_saw_mixed], + [miri_no, correct_dyn_val_random], + [miri_yes, correct_dyn_val_random_z1], + [miri_no, correct_dyn_val_random_d2], + [miri_no, correct_dyn_val_random_d20], + [miri_no, correct_dyn_val_random_s95], + [miri_no, correct_dyn_val_ascending], + [miri_no, correct_dyn_val_descending], + [miri_no, correct_dyn_val_saw_mixed], + [miri_no, stability_legacy], + [miri_no, stability_i32_random], + [miri_yes, stability_i32_random_z1], + [miri_no, stability_i32_random_d2], + [miri_no, stability_i32_random_d20], + [miri_no, stability_i32_random_s95], + [miri_no, stability_i32_ascending], + [miri_no, stability_i32_descending], + [miri_no, stability_i32_saw_mixed], + [miri_no, stability_cell_i32_random], + [miri_yes, stability_cell_i32_random_z1], + [miri_no, stability_cell_i32_random_d2], + [miri_no, stability_cell_i32_random_d20], + [miri_no, stability_cell_i32_random_s95], + [miri_no, stability_cell_i32_ascending], + [miri_no, stability_cell_i32_descending], + [miri_no, stability_cell_i32_saw_mixed], + [miri_no, stability_string_random], + [miri_yes, stability_string_random_z1], + [miri_no, stability_string_random_d2], + [miri_no, stability_string_random_d20], + [miri_no, stability_string_random_s95], + [miri_no, stability_string_ascending], + [miri_no, stability_string_descending], + [miri_no, stability_string_saw_mixed], + [miri_no, observable_is_less_random], + [miri_yes, observable_is_less_random_z1], + [miri_no, observable_is_less_random_d2], + [miri_no, observable_is_less_random_d20], + [miri_no, observable_is_less_random_s95], + [miri_no, observable_is_less_ascending], + [miri_no, observable_is_less_descending], + [miri_no, observable_is_less_saw_mixed], + [miri_no, panic_retain_orig_set_i32_random], + [miri_yes, panic_retain_orig_set_i32_random_z1], + [miri_no, panic_retain_orig_set_i32_random_d2], + [miri_no, panic_retain_orig_set_i32_random_d20], + [miri_no, panic_retain_orig_set_i32_random_s95], + [miri_no, panic_retain_orig_set_i32_ascending], + [miri_no, panic_retain_orig_set_i32_descending], + [miri_no, panic_retain_orig_set_i32_saw_mixed], + [miri_no, panic_retain_orig_set_cell_i32_random], + [miri_yes, panic_retain_orig_set_cell_i32_random_z1], + [miri_no, panic_retain_orig_set_cell_i32_random_d2], + [miri_no, panic_retain_orig_set_cell_i32_random_d20], + [miri_no, panic_retain_orig_set_cell_i32_random_s95], + [miri_no, panic_retain_orig_set_cell_i32_ascending], + [miri_no, panic_retain_orig_set_cell_i32_descending], + [miri_no, panic_retain_orig_set_cell_i32_saw_mixed], + [miri_no, panic_retain_orig_set_string_random], + [miri_yes, panic_retain_orig_set_string_random_z1], + [miri_no, panic_retain_orig_set_string_random_d2], + [miri_no, panic_retain_orig_set_string_random_d20], + [miri_no, panic_retain_orig_set_string_random_s95], + [miri_no, panic_retain_orig_set_string_ascending], + [miri_no, panic_retain_orig_set_string_descending], + [miri_no, panic_retain_orig_set_string_saw_mixed], + [miri_no, panic_observable_is_less_random], + [miri_yes, panic_observable_is_less_random_z1], + [miri_no, panic_observable_is_less_random_d2], + [miri_no, panic_observable_is_less_random_d20], + [miri_no, panic_observable_is_less_random_s95], + [miri_no, panic_observable_is_less_ascending], + [miri_no, panic_observable_is_less_descending], + [miri_no, panic_observable_is_less_saw_mixed], + [miri_no, deterministic_i32_random], + [miri_yes, deterministic_i32_random_z1], + [miri_no, deterministic_i32_random_d2], + [miri_no, deterministic_i32_random_d20], + [miri_no, deterministic_i32_random_s95], + [miri_no, deterministic_i32_ascending], + [miri_no, deterministic_i32_descending], + [miri_no, deterministic_i32_saw_mixed], + [miri_no, deterministic_cell_i32_random], + [miri_yes, deterministic_cell_i32_random_z1], + [miri_no, deterministic_cell_i32_random_d2], + [miri_no, deterministic_cell_i32_random_d20], + [miri_no, deterministic_cell_i32_random_s95], + [miri_no, deterministic_cell_i32_ascending], + [miri_no, deterministic_cell_i32_descending], + [miri_no, deterministic_cell_i32_saw_mixed], + [miri_no, deterministic_string_random], + [miri_yes, deterministic_string_random_z1], + [miri_no, deterministic_string_random_d2], + [miri_no, deterministic_string_random_d20], + [miri_no, deterministic_string_random_s95], + [miri_no, deterministic_string_ascending], + [miri_no, deterministic_string_descending], + [miri_no, deterministic_string_saw_mixed], + [miri_no, self_cmp_i32_random], + [miri_yes, self_cmp_i32_random_z1], + [miri_no, self_cmp_i32_random_d2], + [miri_no, self_cmp_i32_random_d20], + [miri_no, self_cmp_i32_random_s95], + [miri_no, self_cmp_i32_ascending], + [miri_no, self_cmp_i32_descending], + [miri_no, self_cmp_i32_saw_mixed], + [miri_no, self_cmp_cell_i32_random], + [miri_yes, self_cmp_cell_i32_random_z1], + [miri_no, self_cmp_cell_i32_random_d2], + [miri_no, self_cmp_cell_i32_random_d20], + [miri_no, self_cmp_cell_i32_random_s95], + [miri_no, self_cmp_cell_i32_ascending], + [miri_no, self_cmp_cell_i32_descending], + [miri_no, self_cmp_cell_i32_saw_mixed], + [miri_no, self_cmp_string_random], + [miri_yes, self_cmp_string_random_z1], + [miri_no, self_cmp_string_random_d2], + [miri_no, self_cmp_string_random_d20], + [miri_no, self_cmp_string_random_s95], + [miri_no, self_cmp_string_ascending], + [miri_no, self_cmp_string_descending], + [miri_no, self_cmp_string_saw_mixed], + [miri_no, violate_ord_retain_orig_set_i32_random], + [miri_yes, violate_ord_retain_orig_set_i32_random_z1], + [miri_no, violate_ord_retain_orig_set_i32_random_d2], + [miri_no, violate_ord_retain_orig_set_i32_random_d20], + [miri_no, violate_ord_retain_orig_set_i32_random_s95], + [miri_no, violate_ord_retain_orig_set_i32_ascending], + [miri_no, violate_ord_retain_orig_set_i32_descending], + [miri_no, violate_ord_retain_orig_set_i32_saw_mixed], + [miri_no, violate_ord_retain_orig_set_cell_i32_random], + [miri_yes, violate_ord_retain_orig_set_cell_i32_random_z1], + [miri_no, violate_ord_retain_orig_set_cell_i32_random_d2], + [miri_no, violate_ord_retain_orig_set_cell_i32_random_d20], + [miri_no, violate_ord_retain_orig_set_cell_i32_random_s95], + [miri_no, violate_ord_retain_orig_set_cell_i32_ascending], + [miri_no, violate_ord_retain_orig_set_cell_i32_descending], + [miri_no, violate_ord_retain_orig_set_cell_i32_saw_mixed], + [miri_no, violate_ord_retain_orig_set_string_random], + [miri_yes, violate_ord_retain_orig_set_string_random_z1], + [miri_no, violate_ord_retain_orig_set_string_random_d2], + [miri_no, violate_ord_retain_orig_set_string_random_d20], + [miri_no, violate_ord_retain_orig_set_string_random_s95], + [miri_no, violate_ord_retain_orig_set_string_ascending], + [miri_no, violate_ord_retain_orig_set_string_descending], + [miri_no, violate_ord_retain_orig_set_string_saw_mixed], +); + +macro_rules! instantiate_sort_tests { + ($sort_impl:ty) => { + instantiate_sort_tests_gen!($sort_impl); + }; +} + +mod unstable { + struct SortImpl {} + + impl crate::sort::Sort for SortImpl { + fn name() -> String { + "rust_std_unstable".into() + } + + fn sort(v: &mut [T]) + where + T: Ord, + { + v.sort_unstable(); + } + + fn sort_by(v: &mut [T], mut compare: F) + where + F: FnMut(&T, &T) -> std::cmp::Ordering, + { + v.sort_unstable_by(|a, b| compare(a, b)); + } + } + + instantiate_sort_tests!(SortImpl); +} + +mod stable { + struct SortImpl {} + + impl crate::sort::Sort for SortImpl { + fn name() -> String { + "rust_std_stable".into() + } + + fn sort(v: &mut [T]) + where + T: Ord, + { + v.sort(); + } + + fn sort_by(v: &mut [T], mut compare: F) + where + F: FnMut(&T, &T) -> std::cmp::Ordering, + { + v.sort_by(|a, b| compare(a, b)); + } + } + + instantiate_sort_tests!(SortImpl); +} diff --git a/library/alloctests/tests/sort/zipf.rs b/library/alloctests/tests/sort/zipf.rs new file mode 100644 index 00000000000..3dad2db521f --- /dev/null +++ b/library/alloctests/tests/sort/zipf.rs @@ -0,0 +1,208 @@ +// This module implements a Zipfian distribution generator. +// +// Based on https://github.com/jonhoo/rust-zipf. + +use rand::Rng; + +/// Random number generator that generates Zipf-distributed random numbers using rejection +/// inversion. +#[derive(Clone, Copy)] +pub struct ZipfDistribution { + /// Number of elements + num_elements: f64, + /// Exponent parameter of the distribution + exponent: f64, + /// `hIntegral(1.5) - 1}` + h_integral_x1: f64, + /// `hIntegral(num_elements + 0.5)}` + h_integral_num_elements: f64, + /// `2 - hIntegralInverse(hIntegral(2.5) - h(2)}` + s: f64, +} + +impl ZipfDistribution { + /// Creates a new [Zipf-distributed](https://en.wikipedia.org/wiki/Zipf's_law) + /// random number generator. + /// + /// Note that both the number of elements and the exponent must be greater than 0. + pub fn new(num_elements: usize, exponent: f64) -> Result { + if num_elements == 0 { + return Err(()); + } + if exponent <= 0f64 { + return Err(()); + } + + let z = ZipfDistribution { + num_elements: num_elements as f64, + exponent, + h_integral_x1: ZipfDistribution::h_integral(1.5, exponent) - 1f64, + h_integral_num_elements: ZipfDistribution::h_integral( + num_elements as f64 + 0.5, + exponent, + ), + s: 2f64 + - ZipfDistribution::h_integral_inv( + ZipfDistribution::h_integral(2.5, exponent) + - ZipfDistribution::h(2f64, exponent), + exponent, + ), + }; + + // populate cache + + Ok(z) + } +} + +impl ZipfDistribution { + fn next(&self, rng: &mut R) -> usize { + // The paper describes an algorithm for exponents larger than 1 (Algorithm ZRI). + // + // The original method uses + // H(x) = (v + x)^(1 - q) / (1 - q) + // as the integral of the hat function. + // + // This function is undefined for q = 1, which is the reason for the limitation of the + // exponent. + // + // If instead the integral function + // H(x) = ((v + x)^(1 - q) - 1) / (1 - q) + // is used, for which a meaningful limit exists for q = 1, the method works for all + // positive exponents. + // + // The following implementation uses v = 0 and generates integral number in the range [1, + // num_elements]. This is different to the original method where v is defined to + // be positive and numbers are taken from [0, i_max]. This explains why the implementation + // looks slightly different. + + let hnum = self.h_integral_num_elements; + + loop { + use std::cmp; + let u: f64 = hnum + rng.random::() * (self.h_integral_x1 - hnum); + // u is uniformly distributed in (h_integral_x1, h_integral_num_elements] + + let x: f64 = ZipfDistribution::h_integral_inv(u, self.exponent); + + // Limit k to the range [1, num_elements] if it would be outside + // due to numerical inaccuracies. + let k64 = x.max(1.0).min(self.num_elements); + // float -> integer rounds towards zero, so we add 0.5 + // to prevent bias towards k == 1 + let k = cmp::max(1, (k64 + 0.5) as usize); + + // Here, the distribution of k is given by: + // + // P(k = 1) = C * (hIntegral(1.5) - h_integral_x1) = C + // P(k = m) = C * (hIntegral(m + 1/2) - hIntegral(m - 1/2)) for m >= 2 + // + // where C = 1 / (h_integral_num_elements - h_integral_x1) + if k64 - x <= self.s + || u >= ZipfDistribution::h_integral(k64 + 0.5, self.exponent) + - ZipfDistribution::h(k64, self.exponent) + { + // Case k = 1: + // + // The right inequality is always true, because replacing k by 1 gives + // u >= hIntegral(1.5) - h(1) = h_integral_x1 and u is taken from + // (h_integral_x1, h_integral_num_elements]. + // + // Therefore, the acceptance rate for k = 1 is P(accepted | k = 1) = 1 + // and the probability that 1 is returned as random value is + // P(k = 1 and accepted) = P(accepted | k = 1) * P(k = 1) = C = C / 1^exponent + // + // Case k >= 2: + // + // The left inequality (k - x <= s) is just a short cut + // to avoid the more expensive evaluation of the right inequality + // (u >= hIntegral(k + 0.5) - h(k)) in many cases. + // + // If the left inequality is true, the right inequality is also true: + // Theorem 2 in the paper is valid for all positive exponents, because + // the requirements h'(x) = -exponent/x^(exponent + 1) < 0 and + // (-1/hInverse'(x))'' = (1+1/exponent) * x^(1/exponent-1) >= 0 + // are both fulfilled. + // Therefore, f(x) = x - hIntegralInverse(hIntegral(x + 0.5) - h(x)) + // is a non-decreasing function. If k - x <= s holds, + // k - x <= s + f(k) - f(2) is obviously also true which is equivalent to + // -x <= -hIntegralInverse(hIntegral(k + 0.5) - h(k)), + // -hIntegralInverse(u) <= -hIntegralInverse(hIntegral(k + 0.5) - h(k)), + // and finally u >= hIntegral(k + 0.5) - h(k). + // + // Hence, the right inequality determines the acceptance rate: + // P(accepted | k = m) = h(m) / (hIntegrated(m+1/2) - hIntegrated(m-1/2)) + // The probability that m is returned is given by + // P(k = m and accepted) = P(accepted | k = m) * P(k = m) + // = C * h(m) = C / m^exponent. + // + // In both cases the probabilities are proportional to the probability mass + // function of the Zipf distribution. + + return k; + } + } + } +} + +impl rand::distr::Distribution for ZipfDistribution { + fn sample(&self, rng: &mut R) -> usize { + self.next(rng) + } +} + +use std::fmt; +impl fmt::Debug for ZipfDistribution { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.debug_struct("ZipfDistribution") + .field("e", &self.exponent) + .field("n", &self.num_elements) + .finish() + } +} + +impl ZipfDistribution { + /// Computes `H(x)`, defined as + /// + /// - `(x^(1 - exponent) - 1) / (1 - exponent)`, if `exponent != 1` + /// - `log(x)`, if `exponent == 1` + /// + /// `H(x)` is an integral function of `h(x)`, the derivative of `H(x)` is `h(x)`. + fn h_integral(x: f64, exponent: f64) -> f64 { + let log_x = x.ln(); + helper2((1f64 - exponent) * log_x) * log_x + } + + /// Computes `h(x) = 1 / x^exponent` + fn h(x: f64, exponent: f64) -> f64 { + (-exponent * x.ln()).exp() + } + + /// The inverse function of `H(x)`. + /// Returns the `y` for which `H(y) = x`. + fn h_integral_inv(x: f64, exponent: f64) -> f64 { + let mut t: f64 = x * (1f64 - exponent); + if t < -1f64 { + // Limit value to the range [-1, +inf). + // t could be smaller than -1 in some rare cases due to numerical errors. + t = -1f64; + } + (helper1(t) * x).exp() + } +} + +/// Helper function that calculates `log(1 + x) / x`. +/// A Taylor series expansion is used, if x is close to 0. +fn helper1(x: f64) -> f64 { + if x.abs() > 1e-8 { x.ln_1p() / x } else { 1f64 - x * (0.5 - x * (1.0 / 3.0 - 0.25 * x)) } +} + +/// Helper function to calculate `(exp(x) - 1) / x`. +/// A Taylor series expansion is used, if x is close to 0. +fn helper2(x: f64) -> f64 { + if x.abs() > 1e-8 { + x.exp_m1() / x + } else { + 1f64 + x * 0.5 * (1f64 + x * 1.0 / 3.0 * (1f64 + 0.25 * x)) + } +} diff --git a/library/alloctests/tests/str.rs b/library/alloctests/tests/str.rs new file mode 100644 index 00000000000..906fa2d425e --- /dev/null +++ b/library/alloctests/tests/str.rs @@ -0,0 +1,2461 @@ +#![allow(invalid_from_utf8)] + +use std::assert_matches::assert_matches; +use std::borrow::Cow; +use std::char::MAX_LEN_UTF8; +use std::cmp::Ordering::{Equal, Greater, Less}; +use std::str::{from_utf8, from_utf8_unchecked}; + +#[test] +fn test_le() { + assert!("" <= ""); + assert!("" <= "foo"); + assert!("foo" <= "foo"); + assert_ne!("foo", "bar"); +} + +#[test] +fn test_find() { + assert_eq!("hello".find('l'), Some(2)); + assert_eq!("hello".find(|c: char| c == 'o'), Some(4)); + assert!("hello".find('x').is_none()); + assert!("hello".find(|c: char| c == 'x').is_none()); + assert_eq!("ประเทศไทย中华Việt Nam".find('华'), Some(30)); + assert_eq!("ประเทศไทย中华Việt Nam".find(|c: char| c == '华'), Some(30)); +} + +#[test] +fn test_rfind() { + assert_eq!("hello".rfind('l'), Some(3)); + assert_eq!("hello".rfind(|c: char| c == 'o'), Some(4)); + assert!("hello".rfind('x').is_none()); + assert!("hello".rfind(|c: char| c == 'x').is_none()); + assert_eq!("ประเทศไทย中华Việt Nam".rfind('华'), Some(30)); + assert_eq!("ประเทศไทย中华Việt Nam".rfind(|c: char| c == '华'), Some(30)); +} + +#[test] +fn test_collect() { + let empty = ""; + let s: String = empty.chars().collect(); + assert_eq!(empty, s); + let data = "ประเทศไทย中"; + let s: String = data.chars().collect(); + assert_eq!(data, s); +} + +#[test] +fn test_into_bytes() { + let data = String::from("asdf"); + let buf = data.into_bytes(); + assert_eq!(buf, b"asdf"); +} + +#[test] +fn test_find_str() { + // byte positions + assert_eq!("".find(""), Some(0)); + assert!("banana".find("apple pie").is_none()); + + let data = "abcabc"; + assert_eq!(data[0..6].find("ab"), Some(0)); + assert_eq!(data[2..6].find("ab"), Some(3 - 2)); + assert!(data[2..4].find("ab").is_none()); + + let string = "ประเทศไทย中华Việt Nam"; + let mut data = String::from(string); + data.push_str(string); + assert!(data.find("ไท华").is_none()); + assert_eq!(data[0..43].find(""), Some(0)); + assert_eq!(data[6..43].find(""), Some(6 - 6)); + + assert_eq!(data[0..43].find("ประ"), Some(0)); + assert_eq!(data[0..43].find("ทศไ"), Some(12)); + assert_eq!(data[0..43].find("ย中"), Some(24)); + assert_eq!(data[0..43].find("iệt"), Some(34)); + assert_eq!(data[0..43].find("Nam"), Some(40)); + + assert_eq!(data[43..86].find("ประ"), Some(43 - 43)); + assert_eq!(data[43..86].find("ทศไ"), Some(55 - 43)); + assert_eq!(data[43..86].find("ย中"), Some(67 - 43)); + assert_eq!(data[43..86].find("iệt"), Some(77 - 43)); + assert_eq!(data[43..86].find("Nam"), Some(83 - 43)); + + // find every substring -- assert that it finds it, or an earlier occurrence. + let string = "Việt Namacbaabcaabaaba"; + for (i, ci) in string.char_indices() { + let ip = i + ci.len_utf8(); + for j in string[ip..].char_indices().map(|(i, _)| i).chain(Some(string.len() - ip)) { + let pat = &string[i..ip + j]; + assert!(match string.find(pat) { + None => false, + Some(x) => x <= i, + }); + assert!(match string.rfind(pat) { + None => false, + Some(x) => x >= i, + }); + } + } +} + +fn s(x: &str) -> String { + x.to_string() +} + +macro_rules! test_concat { + ($expected: expr, $string: expr) => {{ + let s: String = $string.concat(); + assert_eq!($expected, s); + }}; +} + +#[test] +fn test_concat_for_different_types() { + test_concat!("ab", vec![s("a"), s("b")]); + test_concat!("ab", vec!["a", "b"]); +} + +#[test] +fn test_concat_for_different_lengths() { + let empty: &[&str] = &[]; + test_concat!("", empty); + test_concat!("a", ["a"]); + test_concat!("ab", ["a", "b"]); + test_concat!("abc", ["", "a", "bc"]); +} + +macro_rules! test_join { + ($expected: expr, $string: expr, $delim: expr) => {{ + let s = $string.join($delim); + assert_eq!($expected, s); + }}; +} + +#[test] +fn test_join_for_different_types() { + test_join!("a-b", ["a", "b"], "-"); + let hyphen = "-".to_string(); + test_join!("a-b", [s("a"), s("b")], &*hyphen); + test_join!("a-b", vec!["a", "b"], &*hyphen); + test_join!("a-b", &*vec!["a", "b"], "-"); + test_join!("a-b", vec![s("a"), s("b")], "-"); +} + +#[test] +fn test_join_for_different_lengths() { + let empty: &[&str] = &[]; + test_join!("", empty, "-"); + test_join!("a", ["a"], "-"); + test_join!("a-b", ["a", "b"], "-"); + test_join!("-a-bc", ["", "a", "bc"], "-"); +} + +// join has fast paths for small separators up to 4 bytes +// this tests the slow paths. +#[test] +fn test_join_for_different_lengths_with_long_separator() { + assert_eq!("~~~~~".len(), 15); + + let empty: &[&str] = &[]; + test_join!("", empty, "~~~~~"); + test_join!("a", ["a"], "~~~~~"); + test_join!("a~~~~~b", ["a", "b"], "~~~~~"); + test_join!("~~~~~a~~~~~bc", ["", "a", "bc"], "~~~~~"); +} + +#[test] +fn test_join_issue_80335() { + use core::borrow::Borrow; + use core::cell::Cell; + + struct WeirdBorrow { + state: Cell, + } + + impl Default for WeirdBorrow { + fn default() -> Self { + WeirdBorrow { state: Cell::new(false) } + } + } + + impl Borrow for WeirdBorrow { + fn borrow(&self) -> &str { + let state = self.state.get(); + if state { + "0" + } else { + self.state.set(true); + "123456" + } + } + } + + let arr: [WeirdBorrow; 3] = Default::default(); + test_join!("0-0-0", arr, "-"); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn test_unsafe_slice() { + assert_eq!("ab", unsafe { "abc".get_unchecked(0..2) }); + assert_eq!("bc", unsafe { "abc".get_unchecked(1..3) }); + assert_eq!("", unsafe { "abc".get_unchecked(1..1) }); + fn a_million_letter_a() -> String { + let mut i = 0; + let mut rs = String::new(); + while i < 100000 { + rs.push_str("aaaaaaaaaa"); + i += 1; + } + rs + } + fn half_a_million_letter_a() -> String { + let mut i = 0; + let mut rs = String::new(); + while i < 100000 { + rs.push_str("aaaaa"); + i += 1; + } + rs + } + let letters = a_million_letter_a(); + assert_eq!(half_a_million_letter_a(), unsafe { letters.get_unchecked(0..500000) }); +} + +#[test] +fn test_starts_with() { + assert!("".starts_with("")); + assert!("abc".starts_with("")); + assert!("abc".starts_with("a")); + assert!(!"a".starts_with("abc")); + assert!(!"".starts_with("abc")); + assert!(!"ödd".starts_with("-")); + assert!("ödd".starts_with("öd")); +} + +#[test] +fn test_ends_with() { + assert!("".ends_with("")); + assert!("abc".ends_with("")); + assert!("abc".ends_with("c")); + assert!(!"a".ends_with("abc")); + assert!(!"".ends_with("abc")); + assert!(!"ddö".ends_with("-")); + assert!("ddö".ends_with("dö")); +} + +#[test] +fn test_is_empty() { + assert!("".is_empty()); + assert!(!"a".is_empty()); +} + +#[test] +fn test_replacen() { + assert_eq!("".replacen('a', "b", 5), ""); + assert_eq!("acaaa".replacen("a", "b", 3), "bcbba"); + assert_eq!("aaaa".replacen("a", "b", 0), "aaaa"); + + let test = "test"; + assert_eq!(" test test ".replacen(test, "toast", 3), " toast toast "); + assert_eq!(" test test ".replacen(test, "toast", 0), " test test "); + assert_eq!(" test test ".replacen(test, "", 5), " "); + + assert_eq!("qwer123zxc789".replacen(char::is_numeric, "", 3), "qwerzxc789"); +} + +#[test] +fn test_replace() { + let a = "a"; + assert_eq!("".replace(a, "b"), ""); + assert_eq!("a".replace(a, "b"), "b"); + assert_eq!("ab".replace(a, "b"), "bb"); + let test = "test"; + assert_eq!(" test test ".replace(test, "toast"), " toast toast "); + assert_eq!(" test test ".replace(test, ""), " "); +} + +#[test] +fn test_replace_2a() { + let data = "ประเทศไทย中华"; + let repl = "دولة الكويت"; + + let a = "ประเ"; + let a2 = "دولة الكويتทศไทย中华"; + assert_eq!(data.replace(a, repl), a2); +} + +#[test] +fn test_replace_2b() { + let data = "ประเทศไทย中华"; + let repl = "دولة الكويت"; + + let b = "ะเ"; + let b2 = "ปรدولة الكويتทศไทย中华"; + assert_eq!(data.replace(b, repl), b2); +} + +#[test] +fn test_replace_2c() { + let data = "ประเทศไทย中华"; + let repl = "دولة الكويت"; + + let c = "中华"; + let c2 = "ประเทศไทยدولة الكويت"; + assert_eq!(data.replace(c, repl), c2); +} + +#[test] +fn test_replace_2d() { + let data = "ประเทศไทย中华"; + let repl = "دولة الكويت"; + + let d = "ไท华"; + assert_eq!(data.replace(d, repl), data); +} + +#[test] +fn test_replace_pattern() { + let data = "abcdαβγδabcdαβγδ"; + assert_eq!(data.replace("dαβ", "😺😺😺"), "abc😺😺😺γδabc😺😺😺γδ"); + assert_eq!(data.replace('γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ"); + assert_eq!(data.replace(&['a', 'γ'] as &[_], "😺😺😺"), "😺😺😺bcdαβ😺😺😺δ😺😺😺bcdαβ😺😺😺δ"); + assert_eq!(data.replace(|c| c == 'γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ"); +} + +// The current implementation of SliceIndex fails to handle methods +// orthogonally from range types; therefore, it is worth testing +// all of the indexing operations on each input. +mod slice_index { + // Test a slicing operation **that should succeed,** + // testing it on all of the indexing methods. + // + // This is not suitable for testing failure on invalid inputs. + macro_rules! assert_range_eq { + ($s:expr, $range:expr, $expected:expr) => { + let mut s: String = $s.to_owned(); + let mut expected: String = $expected.to_owned(); + { + let s: &str = &s; + let expected: &str = &expected; + + assert_eq!(&s[$range], expected, "(in assertion for: index)"); + assert_eq!(s.get($range), Some(expected), "(in assertion for: get)"); + unsafe { + assert_eq!( + s.get_unchecked($range), + expected, + "(in assertion for: get_unchecked)", + ); + } + } + { + let s: &mut str = &mut s; + let expected: &mut str = &mut expected; + + assert_eq!(&mut s[$range], expected, "(in assertion for: index_mut)",); + assert_eq!( + s.get_mut($range), + Some(&mut expected[..]), + "(in assertion for: get_mut)", + ); + unsafe { + assert_eq!( + s.get_unchecked_mut($range), + expected, + "(in assertion for: get_unchecked_mut)", + ); + } + } + }; + } + + // Make sure the macro can actually detect bugs, + // because if it can't, then what are we even doing here? + // + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method that panics, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "out of bounds")] + fn assert_range_eq_can_fail_by_panic() { + assert_range_eq!("abc", 0..5, "abc"); + } + + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method it calls, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "==")] + fn assert_range_eq_can_fail_by_inequality() { + assert_range_eq!("abc", 0..2, "abc"); + } + + // Generates test cases for bad index operations. + // + // This generates `should_panic` test cases for Index/IndexMut + // and `None` test cases for get/get_mut. + macro_rules! panic_cases { + ($( + in mod $case_name:ident { + data: $data:expr; + + // optional: + // + // a similar input for which DATA[input] succeeds, and the corresponding + // output str. This helps validate "critical points" where an input range + // straddles the boundary between valid and invalid. + // (such as the input `len..len`, which is just barely valid) + $( + good: data[$good:expr] == $output:expr; + )* + + bad: data[$bad:expr]; + message: $expect_msg:expr; // must be a literal + } + )*) => {$( + mod $case_name { + #[test] + fn pass() { + let mut v: String = $data.into(); + + $( assert_range_eq!(v, $good, $output); )* + + { + let v: &str = &v; + assert_eq!(v.get($bad), None, "(in None assertion for get)"); + } + + { + let v: &mut str = &mut v; + assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)"); + } + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_fail() { + let v: String = $data.into(); + let v: &str = &v; + let _v = &v[$bad]; + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_mut_fail() { + let mut v: String = $data.into(); + let v: &mut str = &mut v; + let _v = &mut v[$bad]; + } + } + )*}; + } + + #[test] + fn simple_ascii() { + assert_range_eq!("abc", .., "abc"); + + assert_range_eq!("abc", 0..2, "ab"); + assert_range_eq!("abc", 0..=1, "ab"); + assert_range_eq!("abc", ..2, "ab"); + assert_range_eq!("abc", ..=1, "ab"); + + assert_range_eq!("abc", 1..3, "bc"); + assert_range_eq!("abc", 1..=2, "bc"); + assert_range_eq!("abc", 1..1, ""); + assert_range_eq!("abc", 1..=0, ""); + } + + #[test] + fn simple_unicode() { + // 日本 + assert_range_eq!("\u{65e5}\u{672c}", .., "\u{65e5}\u{672c}"); + + assert_range_eq!("\u{65e5}\u{672c}", 0..3, "\u{65e5}"); + assert_range_eq!("\u{65e5}\u{672c}", 0..=2, "\u{65e5}"); + assert_range_eq!("\u{65e5}\u{672c}", ..3, "\u{65e5}"); + assert_range_eq!("\u{65e5}\u{672c}", ..=2, "\u{65e5}"); + + assert_range_eq!("\u{65e5}\u{672c}", 3..6, "\u{672c}"); + assert_range_eq!("\u{65e5}\u{672c}", 3..=5, "\u{672c}"); + assert_range_eq!("\u{65e5}\u{672c}", 3.., "\u{672c}"); + + let data = "ประเทศไทย中华"; + assert_range_eq!(data, 0..3, "ป"); + assert_range_eq!(data, 3..6, "ร"); + assert_range_eq!(data, 3..3, ""); + assert_range_eq!(data, 30..33, "华"); + + /*0: 中 + 3: 华 + 6: V + 7: i + 8: ệ + 11: t + 12: + 13: N + 14: a + 15: m */ + let ss = "中华Việt Nam"; + assert_range_eq!(ss, 3..6, "华"); + assert_range_eq!(ss, 6..16, "Việt Nam"); + assert_range_eq!(ss, 6..=15, "Việt Nam"); + assert_range_eq!(ss, 6.., "Việt Nam"); + + assert_range_eq!(ss, 0..3, "中"); + assert_range_eq!(ss, 3..7, "华V"); + assert_range_eq!(ss, 3..=6, "华V"); + assert_range_eq!(ss, 3..3, ""); + assert_range_eq!(ss, 3..=2, ""); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] // hits an OOM + #[cfg_attr(miri, ignore)] // Miri is too slow + fn simple_big() { + fn a_million_letter_x() -> String { + let mut i = 0; + let mut rs = String::new(); + while i < 100000 { + rs.push_str("华华华华华华华华华华"); + i += 1; + } + rs + } + fn half_a_million_letter_x() -> String { + let mut i = 0; + let mut rs = String::new(); + while i < 100000 { + rs.push_str("华华华华华"); + i += 1; + } + rs + } + let letters = a_million_letter_x(); + assert_range_eq!(letters, 0..3 * 500000, half_a_million_letter_x()); + } + + #[test] + #[should_panic] + fn test_slice_fail() { + let _ = &"中华Việt Nam"[0..2]; + } + + panic_cases! { + in mod rangefrom_len { + data: "abcdef"; + good: data[6..] == ""; + bad: data[7..]; + message: "out of bounds"; + } + + in mod rangeto_len { + data: "abcdef"; + good: data[..6] == "abcdef"; + bad: data[..7]; + message: "out of bounds"; + } + + in mod rangetoinclusive_len { + data: "abcdef"; + good: data[..=5] == "abcdef"; + bad: data[..=6]; + message: "out of bounds"; + } + + in mod rangeinclusive_len { + data: "abcdef"; + good: data[0..=5] == "abcdef"; + bad: data[0..=6]; + message: "out of bounds"; + } + + in mod range_len_len { + data: "abcdef"; + good: data[6..6] == ""; + bad: data[7..7]; + message: "out of bounds"; + } + + in mod rangeinclusive_len_len { + data: "abcdef"; + good: data[6..=5] == ""; + bad: data[7..=6]; + message: "out of bounds"; + } + } + + panic_cases! { + in mod rangeinclusive_exhausted { + data: "abcdef"; + + good: data[0..=5] == "abcdef"; + good: data[{ + let mut iter = 0..=5; + iter.by_ref().count(); // exhaust it + iter + }] == ""; + + // 0..=6 is out of bounds before exhaustion, so it + // stands to reason that it still would be after. + bad: data[{ + let mut iter = 0..=6; + iter.by_ref().count(); // exhaust it + iter + }]; + message: "out of bounds"; + } + } + + panic_cases! { + in mod range_neg_width { + data: "abcdef"; + good: data[4..4] == ""; + bad: data[4..3]; + message: "begin <= end (4 <= 3)"; + } + + in mod rangeinclusive_neg_width { + data: "abcdef"; + good: data[4..=3] == ""; + bad: data[4..=2]; + message: "begin <= end (4 <= 3)"; + } + } + + mod overflow { + panic_cases! { + in mod rangeinclusive { + data: "hello"; + // note: using 0 specifically ensures that the result of overflowing is 0..0, + // so that `get` doesn't simply return None for the wrong reason. + bad: data[0..=usize::MAX]; + message: "maximum usize"; + } + + in mod rangetoinclusive { + data: "hello"; + bad: data[..=usize::MAX]; + message: "maximum usize"; + } + } + } + + mod boundary { + const DATA: &str = "abcαβγ"; + + const BAD_START: usize = 4; + const GOOD_START: usize = 3; + const BAD_END: usize = 6; + const GOOD_END: usize = 7; + const BAD_END_INCL: usize = BAD_END - 1; + const GOOD_END_INCL: usize = GOOD_END - 1; + + // it is especially important to test all of the different range types here + // because some of the logic may be duplicated as part of micro-optimizations + // to dodge unicode boundary checks on half-ranges. + panic_cases! { + in mod range_1 { + data: super::DATA; + bad: data[super::BAD_START..super::GOOD_END]; + message: + "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + } + + in mod range_2 { + data: super::DATA; + bad: data[super::GOOD_START..super::BAD_END]; + message: + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + } + + in mod rangefrom { + data: super::DATA; + bad: data[super::BAD_START..]; + message: + "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + } + + in mod rangeto { + data: super::DATA; + bad: data[..super::BAD_END]; + message: + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + } + + in mod rangeinclusive_1 { + data: super::DATA; + bad: data[super::BAD_START..=super::GOOD_END_INCL]; + message: + "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + } + + in mod rangeinclusive_2 { + data: super::DATA; + bad: data[super::GOOD_START..=super::BAD_END_INCL]; + message: + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + } + + in mod rangetoinclusive { + data: super::DATA; + bad: data[..=super::BAD_END_INCL]; + message: + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + } + } + } + + const LOREM_PARAGRAPH: &str = "\ + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \ + sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \ + quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \ + nunc luctus, imperdiet mi. Integer fringilla non sem ut lacinia. Fusce varius \ + tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec tempus vel, \ + gravida nec quam."; + + // check the panic includes the prefix of the sliced string + #[test] + #[should_panic(expected = "byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")] + fn test_slice_fail_truncated_1() { + let _ = &LOREM_PARAGRAPH[..1024]; + } + // check the truncation in the panic message + #[test] + #[should_panic(expected = "luctus, im`[...]")] + fn test_slice_fail_truncated_2() { + let _ = &LOREM_PARAGRAPH[..1024]; + } +} + +#[test] +fn test_str_slice_rangetoinclusive_ok() { + let s = "abcαβγ"; + assert_eq!(&s[..=2], "abc"); + assert_eq!(&s[..=4], "abcα"); +} + +#[test] +#[should_panic] +fn test_str_slice_rangetoinclusive_notok() { + let s = "abcαβγ"; + let _ = &s[..=3]; +} + +#[test] +fn test_str_slicemut_rangetoinclusive_ok() { + let mut s = "abcαβγ".to_owned(); + let s: &mut str = &mut s; + assert_eq!(&mut s[..=2], "abc"); + assert_eq!(&mut s[..=4], "abcα"); +} + +#[test] +#[should_panic] +fn test_str_slicemut_rangetoinclusive_notok() { + let mut s = "abcαβγ".to_owned(); + let s: &mut str = &mut s; + let _ = &mut s[..=3]; +} + +#[test] +fn test_is_char_boundary() { + let s = "ศไทย中华Việt Nam β-release 🐱123"; + assert!(s.is_char_boundary(0)); + assert!(s.is_char_boundary(s.len())); + assert!(!s.is_char_boundary(s.len() + 1)); + for (i, ch) in s.char_indices() { + // ensure character locations are boundaries and continuation bytes are not + assert!(s.is_char_boundary(i), "{} is a char boundary in {:?}", i, s); + for j in 1..ch.len_utf8() { + assert!( + !s.is_char_boundary(i + j), + "{} should not be a char boundary in {:?}", + i + j, + s + ); + } + } +} + +#[test] +fn test_trim_start_matches() { + let v: &[char] = &[]; + assert_eq!(" *** foo *** ".trim_start_matches(v), " *** foo *** "); + let chars: &[char] = &['*', ' ']; + assert_eq!(" *** foo *** ".trim_start_matches(chars), "foo *** "); + assert_eq!(" *** *** ".trim_start_matches(chars), ""); + assert_eq!("foo *** ".trim_start_matches(chars), "foo *** "); + + assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11"); + let chars: &[char] = &['1', '2']; + assert_eq!("12foo1bar12".trim_start_matches(chars), "foo1bar12"); + assert_eq!("123foo1bar123".trim_start_matches(|c: char| c.is_numeric()), "foo1bar123"); +} + +#[test] +fn test_trim_end_matches() { + let v: &[char] = &[]; + assert_eq!(" *** foo *** ".trim_end_matches(v), " *** foo *** "); + let chars: &[char] = &['*', ' ']; + assert_eq!(" *** foo *** ".trim_end_matches(chars), " *** foo"); + assert_eq!(" *** *** ".trim_end_matches(chars), ""); + assert_eq!(" *** foo".trim_end_matches(chars), " *** foo"); + + assert_eq!("11foo1bar11".trim_end_matches('1'), "11foo1bar"); + let chars: &[char] = &['1', '2']; + assert_eq!("12foo1bar12".trim_end_matches(chars), "12foo1bar"); + assert_eq!("123foo1bar123".trim_end_matches(|c: char| c.is_numeric()), "123foo1bar"); +} + +#[test] +fn test_trim_matches() { + let v: &[char] = &[]; + assert_eq!(" *** foo *** ".trim_matches(v), " *** foo *** "); + let chars: &[char] = &['*', ' ']; + assert_eq!(" *** foo *** ".trim_matches(chars), "foo"); + assert_eq!(" *** *** ".trim_matches(chars), ""); + assert_eq!("foo".trim_matches(chars), "foo"); + + assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); + let chars: &[char] = &['1', '2']; + assert_eq!("12foo1bar12".trim_matches(chars), "foo1bar"); + assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar"); +} + +#[test] +fn test_trim_start() { + assert_eq!("".trim_start(), ""); + assert_eq!("a".trim_start(), "a"); + assert_eq!(" ".trim_start(), ""); + assert_eq!(" blah".trim_start(), "blah"); + assert_eq!(" \u{3000} wut".trim_start(), "wut"); + assert_eq!("hey ".trim_start(), "hey "); +} + +#[test] +fn test_trim_end() { + assert_eq!("".trim_end(), ""); + assert_eq!("a".trim_end(), "a"); + assert_eq!(" ".trim_end(), ""); + assert_eq!("blah ".trim_end(), "blah"); + assert_eq!("wut \u{3000} ".trim_end(), "wut"); + assert_eq!(" hey".trim_end(), " hey"); +} + +#[test] +fn test_trim() { + assert_eq!("".trim(), ""); + assert_eq!("a".trim(), "a"); + assert_eq!(" ".trim(), ""); + assert_eq!(" blah ".trim(), "blah"); + assert_eq!("\nwut \u{3000} ".trim(), "wut"); + assert_eq!(" hey dude ".trim(), "hey dude"); +} + +#[test] +fn test_is_whitespace() { + assert!("".chars().all(|c| c.is_whitespace())); + assert!(" ".chars().all(|c| c.is_whitespace())); + assert!("\u{2009}".chars().all(|c| c.is_whitespace())); // Thin space + assert!(" \n\t ".chars().all(|c| c.is_whitespace())); + assert!(!" _ ".chars().all(|c| c.is_whitespace())); +} + +#[test] +fn test_is_utf8() { + // deny overlong encodings + assert!(from_utf8(&[0xc0, 0x80]).is_err()); + assert!(from_utf8(&[0xc0, 0xae]).is_err()); + assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err()); + assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err()); + assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err()); + assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err()); + assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err()); + + // deny surrogates + assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err()); + assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err()); + + assert!(from_utf8(&[0xC2, 0x80]).is_ok()); + assert!(from_utf8(&[0xDF, 0xBF]).is_ok()); + assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok()); + assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok()); + assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok()); + assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok()); + assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok()); + assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok()); +} + +#[test] +fn test_const_is_utf8() { + const _: () = { + // deny overlong encodings + assert!(from_utf8(&[0xc0, 0x80]).is_err()); + assert!(from_utf8(&[0xc0, 0xae]).is_err()); + assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err()); + assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err()); + assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err()); + assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err()); + assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err()); + + // deny surrogates + assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err()); + assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err()); + + assert!(from_utf8(&[0xC2, 0x80]).is_ok()); + assert!(from_utf8(&[0xDF, 0xBF]).is_ok()); + assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok()); + assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok()); + assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok()); + assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok()); + assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok()); + assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok()); + }; +} + +#[test] +fn from_utf8_mostly_ascii() { + // deny invalid bytes embedded in long stretches of ascii + for i in 32..64 { + let mut data = [0; 128]; + data[i] = 0xC0; + assert!(from_utf8(&data).is_err()); + data[i] = 0xC2; + assert!(from_utf8(&data).is_err()); + } +} + +#[test] +fn const_from_utf8_mostly_ascii() { + const _: () = { + // deny invalid bytes embedded in long stretches of ascii + let mut i = 32; + while i < 64 { + let mut data = [0; 128]; + data[i] = 0xC0; + assert!(from_utf8(&data).is_err()); + data[i] = 0xC2; + assert!(from_utf8(&data).is_err()); + + i = i + 1; + } + }; +} + +#[test] +fn from_utf8_error() { + macro_rules! test { + ($input: expr, $expected_valid_up_to:pat, $expected_error_len:pat) => { + let error = from_utf8($input).unwrap_err(); + assert_matches!(error.valid_up_to(), $expected_valid_up_to); + assert_matches!(error.error_len(), $expected_error_len); + + const _: () = { + match from_utf8($input) { + Err(error) => { + let valid_up_to = error.valid_up_to(); + let error_len = error.error_len(); + + assert!(matches!(valid_up_to, $expected_valid_up_to)); + assert!(matches!(error_len, $expected_error_len)); + } + Ok(_) => unreachable!(), + } + }; + }; + } + test!(b"A\xC3\xA9 \xFF ", 4, Some(1)); + test!(b"A\xC3\xA9 \x80 ", 4, Some(1)); + test!(b"A\xC3\xA9 \xC1 ", 4, Some(1)); + test!(b"A\xC3\xA9 \xC1", 4, Some(1)); + test!(b"A\xC3\xA9 \xC2", 4, None); + test!(b"A\xC3\xA9 \xC2 ", 4, Some(1)); + test!(b"A\xC3\xA9 \xC2\xC0", 4, Some(1)); + test!(b"A\xC3\xA9 \xE0", 4, None); + test!(b"A\xC3\xA9 \xE0\x9F", 4, Some(1)); + test!(b"A\xC3\xA9 \xE0\xA0", 4, None); + test!(b"A\xC3\xA9 \xE0\xA0\xC0", 4, Some(2)); + test!(b"A\xC3\xA9 \xE0\xA0 ", 4, Some(2)); + test!(b"A\xC3\xA9 \xED\xA0\x80 ", 4, Some(1)); + test!(b"A\xC3\xA9 \xF1", 4, None); + test!(b"A\xC3\xA9 \xF1\x80", 4, None); + test!(b"A\xC3\xA9 \xF1\x80\x80", 4, None); + test!(b"A\xC3\xA9 \xF1 ", 4, Some(1)); + test!(b"A\xC3\xA9 \xF1\x80 ", 4, Some(2)); + test!(b"A\xC3\xA9 \xF1\x80\x80 ", 4, Some(3)); +} + +#[test] +fn test_as_bytes() { + // no null + let v = [ + 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142, + 86, 105, 225, 187, 135, 116, 32, 78, 97, 109, + ]; + let b: &[u8] = &[]; + assert_eq!("".as_bytes(), b); + assert_eq!("abc".as_bytes(), b"abc"); + assert_eq!("ศไทย中华Việt Nam".as_bytes(), v); +} + +#[test] +#[should_panic] +fn test_as_bytes_fail() { + // Don't double free. (I'm not sure if this exercises the + // original problem code path anymore.) + let s = String::from(""); + let _bytes = s.as_bytes(); + panic!(); +} + +#[test] +fn test_as_ptr() { + let buf = "hello".as_ptr(); + unsafe { + assert_eq!(*buf.add(0), b'h'); + assert_eq!(*buf.add(1), b'e'); + assert_eq!(*buf.add(2), b'l'); + assert_eq!(*buf.add(3), b'l'); + assert_eq!(*buf.add(4), b'o'); + } +} + +#[test] +fn vec_str_conversions() { + let s1: String = String::from("All mimsy were the borogoves"); + + let v: Vec = s1.as_bytes().to_vec(); + let s2: String = String::from(from_utf8(&v).unwrap()); + let mut i = 0; + let n1 = s1.len(); + let n2 = v.len(); + assert_eq!(n1, n2); + while i < n1 { + let a: u8 = s1.as_bytes()[i]; + let b: u8 = s2.as_bytes()[i]; + assert_eq!(a, b); + i += 1; + } +} + +#[test] +fn test_contains() { + assert!("abcde".contains("bcd")); + assert!("abcde".contains("abcd")); + assert!("abcde".contains("bcde")); + assert!("abcde".contains("")); + assert!("".contains("")); + assert!(!"abcde".contains("def")); + assert!(!"".contains("a")); + + let data = "ประเทศไทย中华Việt Nam"; + assert!(data.contains("ประเ")); + assert!(data.contains("ะเ")); + assert!(data.contains("中华")); + assert!(!data.contains("ไท华")); +} + +#[test] +fn test_contains_char() { + assert!("abc".contains('b')); + assert!("a".contains('a')); + assert!(!"abc".contains('d')); + assert!(!"".contains('a')); +} + +#[test] +fn test_split_at() { + let s = "ศไทย中华Việt Nam"; + for (index, _) in s.char_indices() { + let (a, b) = s.split_at(index); + assert_eq!(&s[..a.len()], a); + assert_eq!(&s[a.len()..], b); + } + let (a, b) = s.split_at(s.len()); + assert_eq!(a, s); + assert_eq!(b, ""); +} + +#[test] +fn test_split_at_mut() { + let mut s = "Hello World".to_string(); + { + let (a, b) = s.split_at_mut(5); + a.make_ascii_uppercase(); + b.make_ascii_lowercase(); + } + assert_eq!(s, "HELLO world"); +} + +#[test] +#[should_panic] +fn test_split_at_boundscheck() { + let s = "ศไทย中华Việt Nam"; + let _ = s.split_at(1); +} + +#[test] +fn test_escape_unicode() { + assert_eq!("abc".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{63}"); + assert_eq!("a c".escape_unicode().to_string(), "\\u{61}\\u{20}\\u{63}"); + assert_eq!("\r\n\t".escape_unicode().to_string(), "\\u{d}\\u{a}\\u{9}"); + assert_eq!("'\"\\".escape_unicode().to_string(), "\\u{27}\\u{22}\\u{5c}"); + assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode().to_string(), "\\u{0}\\u{1}\\u{fe}\\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_unicode().to_string(), "\\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_unicode().to_string(), "\\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{fb00}".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{fb00}"); + assert_eq!("\u{1d4ea}\r".escape_unicode().to_string(), "\\u{1d4ea}\\u{d}"); +} + +#[test] +fn test_escape_debug() { + // Note that there are subtleties with the number of backslashes + // on the left- and right-hand sides. In particular, Unicode code points + // are usually escaped with two backslashes on the right-hand side, as + // they are escaped. However, when the character is unescaped (e.g., for + // printable characters), only a single backslash appears (as the character + // itself appears in the debug string). + assert_eq!("abc".escape_debug().to_string(), "abc"); + assert_eq!("a c".escape_debug().to_string(), "a c"); + assert_eq!("éèê".escape_debug().to_string(), "éèê"); + assert_eq!("\0\r\n\t".escape_debug().to_string(), "\\0\\r\\n\\t"); + assert_eq!("'\"\\".escape_debug().to_string(), "\\'\\\"\\\\"); + assert_eq!("\u{7f}\u{ff}".escape_debug().to_string(), "\\u{7f}\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_debug().to_string(), "\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_debug().to_string(), "\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{200b}".escape_debug().to_string(), "ab\\u{200b}"); + assert_eq!("\u{10d4ea}\r".escape_debug().to_string(), "\\u{10d4ea}\\r"); + assert_eq!( + "\u{301}a\u{301}bé\u{e000}".escape_debug().to_string(), + "\\u{301}a\u{301}bé\\u{e000}" + ); +} + +#[test] +fn test_escape_default() { + assert_eq!("abc".escape_default().to_string(), "abc"); + assert_eq!("a c".escape_default().to_string(), "a c"); + assert_eq!("éèê".escape_default().to_string(), "\\u{e9}\\u{e8}\\u{ea}"); + assert_eq!("\r\n\t".escape_default().to_string(), "\\r\\n\\t"); + assert_eq!("'\"\\".escape_default().to_string(), "\\'\\\"\\\\"); + assert_eq!("\u{7f}\u{ff}".escape_default().to_string(), "\\u{7f}\\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_default().to_string(), "\\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_default().to_string(), "\\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{200b}".escape_default().to_string(), "ab\\u{200b}"); + assert_eq!("\u{10d4ea}\r".escape_default().to_string(), "\\u{10d4ea}\\r"); +} + +#[test] +fn test_total_ord() { + assert_eq!("1234".cmp("123"), Greater); + assert_eq!("123".cmp("1234"), Less); + assert_eq!("1234".cmp("1234"), Equal); + assert_eq!("12345555".cmp("123456"), Less); + assert_eq!("22".cmp("1234"), Greater); +} + +#[test] +fn test_iterator() { + let s = "ศไทย中华Việt Nam"; + let v = ['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm']; + + let mut pos = 0; + let it = s.chars(); + + for c in it { + assert_eq!(c, v[pos]); + pos += 1; + } + assert_eq!(pos, v.len()); + assert_eq!(s.chars().count(), v.len()); +} + +#[test] +fn test_iterator_advance() { + let s = "「赤錆」と呼ばれる鉄錆は、水の存在下での鉄の自然酸化によって生じる、オキシ水酸化鉄(III) 等の(含水)酸化物粒子の疎な凝集膜であるとみなせる。"; + let chars: Vec = s.chars().collect(); + let mut it = s.chars(); + it.advance_by(1).unwrap(); + assert_eq!(it.next(), Some(chars[1])); + it.advance_by(33).unwrap(); + assert_eq!(it.next(), Some(chars[35])); +} + +#[test] +fn test_rev_iterator() { + let s = "ศไทย中华Việt Nam"; + let v = ['m', 'a', 'N', ' ', 't', 'ệ', 'i', 'V', '华', '中', 'ย', 'ท', 'ไ', 'ศ']; + + let mut pos = 0; + let it = s.chars().rev(); + + for c in it { + assert_eq!(c, v[pos]); + pos += 1; + } + assert_eq!(pos, v.len()); +} + +#[test] +fn test_to_lowercase_rev_iterator() { + let s = "AÖßÜ💩ΣΤΙΓΜΑΣDžfiİ"; + let v = ['\u{307}', 'i', 'fi', 'dž', 'σ', 'α', 'μ', 'γ', 'ι', 'τ', 'σ', '💩', 'ü', 'ß', 'ö', 'a']; + + let mut pos = 0; + let it = s.chars().flat_map(|c| c.to_lowercase()).rev(); + + for c in it { + assert_eq!(c, v[pos]); + pos += 1; + } + assert_eq!(pos, v.len()); +} + +#[test] +fn test_to_uppercase_rev_iterator() { + let s = "aößü💩στιγμαςDžfiᾀ"; + let v = + ['Ι', 'Ἀ', 'I', 'F', 'DŽ', 'Σ', 'Α', 'Μ', 'Γ', 'Ι', 'Τ', 'Σ', '💩', 'Ü', 'S', 'S', 'Ö', 'A']; + + let mut pos = 0; + let it = s.chars().flat_map(|c| c.to_uppercase()).rev(); + + for c in it { + assert_eq!(c, v[pos]); + pos += 1; + } + assert_eq!(pos, v.len()); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn test_chars_decoding() { + let mut bytes = [0; MAX_LEN_UTF8]; + for c in (0..0x110000).filter_map(std::char::from_u32) { + let s = c.encode_utf8(&mut bytes); + if Some(c) != s.chars().next() { + panic!("character {:x}={} does not decode correctly", c as u32, c); + } + } +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn test_chars_rev_decoding() { + let mut bytes = [0; MAX_LEN_UTF8]; + for c in (0..0x110000).filter_map(std::char::from_u32) { + let s = c.encode_utf8(&mut bytes); + if Some(c) != s.chars().rev().next() { + panic!("character {:x}={} does not decode correctly", c as u32, c); + } + } +} + +#[test] +fn test_iterator_clone() { + let s = "ศไทย中华Việt Nam"; + let mut it = s.chars(); + it.next(); + assert!(it.clone().zip(it).all(|(x, y)| x == y)); +} + +#[test] +fn test_iterator_last() { + let s = "ศไทย中华Việt Nam"; + let mut it = s.chars(); + it.next(); + assert_eq!(it.last(), Some('m')); +} + +#[test] +fn test_chars_debug() { + let s = "ศไทย中华Việt Nam"; + let c = s.chars(); + assert_eq!( + format!("{c:?}"), + r#"Chars(['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'])"# + ); +} + +#[test] +fn test_bytesator() { + let s = "ศไทย中华Việt Nam"; + let v = [ + 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142, + 86, 105, 225, 187, 135, 116, 32, 78, 97, 109, + ]; + let mut pos = 0; + + for b in s.bytes() { + assert_eq!(b, v[pos]); + pos += 1; + } +} + +#[test] +fn test_bytes_revator() { + let s = "ศไทย中华Việt Nam"; + let v = [ + 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142, + 86, 105, 225, 187, 135, 116, 32, 78, 97, 109, + ]; + let mut pos = v.len(); + + for b in s.bytes().rev() { + pos -= 1; + assert_eq!(b, v[pos]); + } +} + +#[test] +fn test_bytesator_nth() { + let s = "ศไทย中华Việt Nam"; + let v = [ + 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142, + 86, 105, 225, 187, 135, 116, 32, 78, 97, 109, + ]; + + let mut b = s.bytes(); + assert_eq!(b.nth(2).unwrap(), v[2]); + assert_eq!(b.nth(10).unwrap(), v[10]); + assert_eq!(b.nth(200), None); +} + +#[test] +fn test_bytesator_count() { + let s = "ศไทย中华Việt Nam"; + + let b = s.bytes(); + assert_eq!(b.count(), 28) +} + +#[test] +fn test_bytesator_last() { + let s = "ศไทย中华Việt Nam"; + + let b = s.bytes(); + assert_eq!(b.last().unwrap(), 109) +} + +#[test] +fn test_char_indicesator() { + let s = "ศไทย中华Việt Nam"; + let p = [0, 3, 6, 9, 12, 15, 18, 19, 20, 23, 24, 25, 26, 27]; + let v = ['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm']; + + let mut pos = 0; + let it = s.char_indices(); + + for c in it { + assert_eq!(c, (p[pos], v[pos])); + pos += 1; + } + assert_eq!(pos, v.len()); + assert_eq!(pos, p.len()); +} + +#[test] +fn test_char_indices_revator() { + let s = "ศไทย中华Việt Nam"; + let p = [27, 26, 25, 24, 23, 20, 19, 18, 15, 12, 9, 6, 3, 0]; + let v = ['m', 'a', 'N', ' ', 't', 'ệ', 'i', 'V', '华', '中', 'ย', 'ท', 'ไ', 'ศ']; + + let mut pos = 0; + let it = s.char_indices().rev(); + + for c in it { + assert_eq!(c, (p[pos], v[pos])); + pos += 1; + } + assert_eq!(pos, v.len()); + assert_eq!(pos, p.len()); +} + +#[test] +fn test_char_indices_last() { + let s = "ศไทย中华Việt Nam"; + let mut it = s.char_indices(); + it.next(); + assert_eq!(it.last(), Some((27, 'm'))); +} + +#[test] +fn test_splitn_char_iterator() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.splitn(4, ' ').collect(); + assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]); + + let split: Vec<&str> = data.splitn(4, |c: char| c == ' ').collect(); + assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]); + + // Unicode + let split: Vec<&str> = data.splitn(4, 'ä').collect(); + assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]); + + let split: Vec<&str> = data.splitn(4, |c: char| c == 'ä').collect(); + assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]); +} + +#[test] +fn test_split_char_iterator_no_trailing() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.split('\n').collect(); + assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]); + + let split: Vec<&str> = data.split_terminator('\n').collect(); + assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]); +} + +#[test] +fn test_split_char_iterator_inclusive() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.split_inclusive('\n').collect(); + assert_eq!(split, ["\n", "Märy häd ä little lämb\n", "Little lämb\n"]); + + let uppercase_separated = "SheePSharKTurtlECaT"; + let mut first_char = true; + let split: Vec<&str> = uppercase_separated + .split_inclusive(|c: char| { + let split = !first_char && c.is_uppercase(); + first_char = split; + split + }) + .collect(); + assert_eq!(split, ["SheeP", "SharK", "TurtlE", "CaT"]); +} + +#[test] +fn test_split_char_iterator_inclusive_rev() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.split_inclusive('\n').rev().collect(); + assert_eq!(split, ["Little lämb\n", "Märy häd ä little lämb\n", "\n"]); + + // Note that the predicate is stateful and thus dependent + // on the iteration order. + // (A different predicate is needed for reverse iterator vs normal iterator.) + // Not sure if anything can be done though. + let uppercase_separated = "SheePSharKTurtlECaT"; + let mut term_char = true; + let split: Vec<&str> = uppercase_separated + .split_inclusive(|c: char| { + let split = term_char && c.is_uppercase(); + term_char = c.is_uppercase(); + split + }) + .rev() + .collect(); + assert_eq!(split, ["CaT", "TurtlE", "SharK", "SheeP"]); +} + +#[test] +fn test_rsplit() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.rsplit(' ').collect(); + assert_eq!(split, ["lämb\n", "lämb\nLittle", "little", "ä", "häd", "\nMäry"]); + + let split: Vec<&str> = data.rsplit("lämb").collect(); + assert_eq!(split, ["\n", "\nLittle ", "\nMäry häd ä little "]); + + let split: Vec<&str> = data.rsplit(|c: char| c == 'ä').collect(); + assert_eq!(split, ["mb\n", "mb\nLittle l", " little l", "d ", "ry h", "\nM"]); +} + +#[test] +fn test_rsplitn() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.rsplitn(2, ' ').collect(); + assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]); + + let split: Vec<&str> = data.rsplitn(2, "lämb").collect(); + assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]); + + let split: Vec<&str> = data.rsplitn(2, |c: char| c == 'ä').collect(); + assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]); +} + +#[test] +fn test_split_once() { + assert_eq!("".split_once("->"), None); + assert_eq!("-".split_once("->"), None); + assert_eq!("->".split_once("->"), Some(("", ""))); + assert_eq!("a->".split_once("->"), Some(("a", ""))); + assert_eq!("->b".split_once("->"), Some(("", "b"))); + assert_eq!("a->b".split_once("->"), Some(("a", "b"))); + assert_eq!("a->b->c".split_once("->"), Some(("a", "b->c"))); + assert_eq!("---".split_once("--"), Some(("", "-"))); +} + +#[test] +fn test_rsplit_once() { + assert_eq!("".rsplit_once("->"), None); + assert_eq!("-".rsplit_once("->"), None); + assert_eq!("->".rsplit_once("->"), Some(("", ""))); + assert_eq!("a->".rsplit_once("->"), Some(("a", ""))); + assert_eq!("->b".rsplit_once("->"), Some(("", "b"))); + assert_eq!("a->b".rsplit_once("->"), Some(("a", "b"))); + assert_eq!("a->b->c".rsplit_once("->"), Some(("a->b", "c"))); + assert_eq!("---".rsplit_once("--"), Some(("-", ""))); +} + +#[test] +fn test_split_whitespace() { + let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n"; + let words: Vec<&str> = data.split_whitespace().collect(); + assert_eq!(words, ["Märy", "häd", "ä", "little", "lämb", "Little", "lämb"]) +} + +#[test] +fn test_lines() { + fn t(data: &str, expected: &[&str]) { + let lines: Vec<&str> = data.lines().collect(); + assert_eq!(lines, expected); + } + t("", &[]); + t("\n", &[""]); + t("\n2nd", &["", "2nd"]); + t("\r\n", &[""]); + t("bare\r", &["bare\r"]); + t("bare\rcr", &["bare\rcr"]); + t("Text\n\r", &["Text", "\r"]); + t( + "\nMäry häd ä little lämb\n\r\nLittle lämb\n", + &["", "Märy häd ä little lämb", "", "Little lämb"], + ); + t( + "\r\nMäry häd ä little lämb\n\nLittle lämb", + &["", "Märy häd ä little lämb", "", "Little lämb"], + ); +} + +#[test] +fn test_splitator() { + fn t(s: &str, sep: &str, u: &[&str]) { + let v: Vec<&str> = s.split(sep).collect(); + assert_eq!(v, u); + } + t("--1233345--", "12345", &["--1233345--"]); + t("abc::hello::there", "::", &["abc", "hello", "there"]); + t("::hello::there", "::", &["", "hello", "there"]); + t("hello::there::", "::", &["hello", "there", ""]); + t("::hello::there::", "::", &["", "hello", "there", ""]); + t("ประเทศไทย中华Việt Nam", "中华", &["ประเทศไทย", "Việt Nam"]); + t("zzXXXzzYYYzz", "zz", &["", "XXX", "YYY", ""]); + t("zzXXXzYYYz", "XXX", &["zz", "zYYYz"]); + t(".XXX.YYY.", ".", &["", "XXX", "YYY", ""]); + t("", ".", &[""]); + t("zz", "zz", &["", ""]); + t("ok", "z", &["ok"]); + t("zzz", "zz", &["", "z"]); + t("zzzzz", "zz", &["", "", "z"]); +} + +#[test] +fn test_str_default() { + use std::default::Default; + + fn t>() { + let s: S = Default::default(); + assert_eq!(s.as_ref(), ""); + } + + t::<&str>(); + t::(); + t::<&mut str>(); +} + +#[test] +fn test_str_container() { + fn sum_len(v: &[&str]) -> usize { + v.iter().map(|x| x.len()).sum() + } + + let s = "01234"; + assert_eq!(5, sum_len(&["012", "", "34"])); + assert_eq!(5, sum_len(&["01", "2", "34", ""])); + assert_eq!(5, sum_len(&[s])); +} + +#[test] +fn test_str_from_utf8() { + let xs = b"hello"; + assert_eq!(from_utf8(xs), Ok("hello")); + + let xs = "ศไทย中华Việt Nam".as_bytes(); + assert_eq!(from_utf8(xs), Ok("ศไทย中华Việt Nam")); + + let xs = b"hello\xFF"; + assert!(from_utf8(xs).is_err()); +} + +#[test] +fn test_pattern_deref_forward() { + let data = "aabcdaa"; + assert!(data.contains("bcd")); + assert!(data.contains(&"bcd")); + assert!(data.contains(&"bcd".to_string())); +} + +#[test] +fn test_empty_match_indices() { + let data = "aä中!"; + let vec: Vec<_> = data.match_indices("").collect(); + assert_eq!(vec, [(0, ""), (1, ""), (3, ""), (6, ""), (7, "")]); +} + +#[test] +fn test_bool_from_str() { + assert_eq!("true".parse().ok(), Some(true)); + assert_eq!("false".parse().ok(), Some(false)); + assert_eq!("not even a boolean".parse::().ok(), None); +} + +fn check_contains_all_substrings(haystack: &str) { + let mut modified_needle = String::new(); + + for i in 0..haystack.len() { + // check different haystack lengths since we special-case short haystacks. + let haystack = &haystack[0..i]; + assert!(haystack.contains("")); + for j in 0..haystack.len() { + for k in j + 1..=haystack.len() { + let needle = &haystack[j..k]; + assert!(haystack.contains(needle)); + modified_needle.clear(); + modified_needle.push_str(needle); + modified_needle.replace_range(0..1, "\0"); + assert!(!haystack.contains(&modified_needle)); + + modified_needle.clear(); + modified_needle.push_str(needle); + modified_needle.replace_range(needle.len() - 1..needle.len(), "\0"); + assert!(!haystack.contains(&modified_needle)); + } + } + } +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn strslice_issue_16589() { + assert!("bananas".contains("nana")); + + // prior to the fix for #16589, x.contains("abcdabcd") returned false + // test all substrings for good measure + check_contains_all_substrings("012345678901234567890123456789bcdabcdabcd"); +} + +#[test] +fn strslice_issue_16878() { + assert!(!"1234567ah012345678901ah".contains("hah")); + assert!(!"00abc01234567890123456789abc".contains("bcabc")); +} + +#[test] +fn strslice_issue_104726() { + // Edge-case in the simd_contains impl. + // The first and last byte are the same so it backtracks by one byte + // which aligns with the end of the string. Previously incorrect offset calculations + // lead to out-of-bounds slicing. + #[rustfmt::skip] + let needle = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaba"; + let haystack = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"; + assert!(!haystack.contains(needle)); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn test_strslice_contains() { + let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'"; + check_contains_all_substrings(x); +} + +#[test] +fn test_rsplitn_char_iterator() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let mut split: Vec<&str> = data.rsplitn(4, ' ').collect(); + split.reverse(); + assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); + + let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect(); + split.reverse(); + assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); + + // Unicode + let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect(); + split.reverse(); + assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); + + let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect(); + split.reverse(); + assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); +} + +#[test] +fn test_split_char_iterator() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.split(' ').collect(); + assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); + + let mut rsplit: Vec<&str> = data.split(' ').rev().collect(); + rsplit.reverse(); + assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); + + let split: Vec<&str> = data.split(|c: char| c == ' ').collect(); + assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); + + let mut rsplit: Vec<&str> = data.split(|c: char| c == ' ').rev().collect(); + rsplit.reverse(); + assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); + + // Unicode + let split: Vec<&str> = data.split('ä').collect(); + assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); + + let mut rsplit: Vec<&str> = data.split('ä').rev().collect(); + rsplit.reverse(); + assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); + + let split: Vec<&str> = data.split(|c: char| c == 'ä').collect(); + assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); + + let mut rsplit: Vec<&str> = data.split(|c: char| c == 'ä').rev().collect(); + rsplit.reverse(); + assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); +} + +#[test] +fn test_rev_split_char_iterator_no_trailing() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let mut split: Vec<&str> = data.split('\n').rev().collect(); + split.reverse(); + assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]); + + let mut split: Vec<&str> = data.split_terminator('\n').rev().collect(); + split.reverse(); + assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]); +} + +#[test] +fn test_utf16_code_units() { + assert_eq!("é\u{1F4A9}".encode_utf16().collect::>(), [0xE9, 0xD83D, 0xDCA9]) +} + +#[test] +fn test_utf16_size_hint() { + assert_eq!("".encode_utf16().size_hint(), (0, Some(0))); + assert_eq!("123".encode_utf16().size_hint(), (1, Some(3))); + assert_eq!("1234".encode_utf16().size_hint(), (2, Some(4))); + assert_eq!("12345678".encode_utf16().size_hint(), (3, Some(8))); + + fn hint_vec(src: &str) -> Vec<(usize, Option)> { + let mut it = src.encode_utf16(); + let mut result = Vec::new(); + result.push(it.size_hint()); + while it.next().is_some() { + result.push(it.size_hint()) + } + result + } + + assert_eq!(hint_vec("12"), [(1, Some(2)), (1, Some(1)), (0, Some(0))]); + assert_eq!(hint_vec("\u{101234}"), [(2, Some(4)), (1, Some(1)), (0, Some(0))]); + assert_eq!(hint_vec("\u{101234}a"), [(2, Some(5)), (2, Some(2)), (1, Some(1)), (0, Some(0))]); +} + +#[test] +fn starts_with_in_unicode() { + assert!(!"├── Cargo.toml".starts_with("# ")); +} + +#[test] +fn starts_short_long() { + assert!(!"".starts_with("##")); + assert!(!"##".starts_with("####")); + assert!("####".starts_with("##")); + assert!(!"##ä".starts_with("####")); + assert!("####ä".starts_with("##")); + assert!(!"##".starts_with("####ä")); + assert!("##ä##".starts_with("##ä")); + + assert!("".starts_with("")); + assert!("ä".starts_with("")); + assert!("#ä".starts_with("")); + assert!("##ä".starts_with("")); + assert!("ä###".starts_with("")); + assert!("#ä##".starts_with("")); + assert!("##ä#".starts_with("")); +} + +#[test] +fn contains_weird_cases() { + assert!("* \t".contains(' ')); + assert!(!"* \t".contains('?')); + assert!(!"* \t".contains('\u{1F4A9}')); +} + +#[test] +fn trim_ws() { + assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t "); + assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a"); + assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t "); + assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a"); + assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()), "a"); + assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), ""); + assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), ""); + assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), ""); + assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), ""); + assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()), ""); +} + +#[test] +fn to_lowercase() { + assert_eq!("".to_lowercase(), ""); + assert_eq!("AÉDžaé ".to_lowercase(), "aédžaé "); + + // https://github.com/rust-lang/rust/issues/26035 + assert_eq!("ΑΣ".to_lowercase(), "ας"); + assert_eq!("Α'Σ".to_lowercase(), "α'ς"); + assert_eq!("Α''Σ".to_lowercase(), "α''ς"); + + assert_eq!("ΑΣ Α".to_lowercase(), "ας α"); + assert_eq!("Α'Σ Α".to_lowercase(), "α'ς α"); + assert_eq!("Α''Σ Α".to_lowercase(), "α''ς α"); + + assert_eq!("ΑΣ' Α".to_lowercase(), "ας' α"); + assert_eq!("ΑΣ'' Α".to_lowercase(), "ας'' α"); + + assert_eq!("Α'Σ' Α".to_lowercase(), "α'ς' α"); + assert_eq!("Α''Σ'' Α".to_lowercase(), "α''ς'' α"); + + assert_eq!("Α Σ".to_lowercase(), "α σ"); + assert_eq!("Α 'Σ".to_lowercase(), "α 'σ"); + assert_eq!("Α ''Σ".to_lowercase(), "α ''σ"); + + assert_eq!("Σ".to_lowercase(), "σ"); + assert_eq!("'Σ".to_lowercase(), "'σ"); + assert_eq!("''Σ".to_lowercase(), "''σ"); + + assert_eq!("ΑΣΑ".to_lowercase(), "ασα"); + assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α"); + assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α"); + + // https://github.com/rust-lang/rust/issues/124714 + // input lengths around the boundary of the chunk size used by the ascii prefix optimization + assert_eq!("abcdefghijklmnoΣ".to_lowercase(), "abcdefghijklmnoς"); + assert_eq!("abcdefghijklmnopΣ".to_lowercase(), "abcdefghijklmnopς"); + assert_eq!("abcdefghijklmnopqΣ".to_lowercase(), "abcdefghijklmnopqς"); + + // a really long string that has it's lowercase form + // even longer. this tests that implementations don't assume + // an incorrect upper bound on allocations + let upper = str::repeat("İ", 512); + let lower = str::repeat("i̇", 512); + assert_eq!(upper.to_lowercase(), lower); + + // a really long ascii-only string. + // This test that the ascii hot-path + // functions correctly + let upper = str::repeat("A", 511); + let lower = str::repeat("a", 511); + assert_eq!(upper.to_lowercase(), lower); +} + +#[test] +fn to_uppercase() { + assert_eq!("".to_uppercase(), ""); + assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ"); +} + +#[test] +fn test_into_string() { + // The only way to acquire a Box in the first place is through a String, so just + // test that we can round-trip between Box and String. + let string = String::from("Some text goes here"); + assert_eq!(string.clone().into_boxed_str().into_string(), string); +} + +#[test] +fn test_box_slice_clone() { + let data = String::from("hello HELLO hello HELLO yes YES 5 中ä华!!!"); + let data2 = data.clone().into_boxed_str().clone().into_string(); + + assert_eq!(data, data2); +} + +#[test] +fn test_cow_from() { + let borrowed = "borrowed"; + let owned = String::from("owned"); + match (Cow::from(owned.clone()), Cow::from(borrowed)) { + (Cow::Owned(o), Cow::Borrowed(b)) => assert!(o == owned && b == borrowed), + _ => panic!("invalid `Cow::from`"), + } +} + +#[test] +fn test_repeat() { + assert_eq!("".repeat(3), ""); + assert_eq!("abc".repeat(0), ""); + assert_eq!("α".repeat(3), "ααα"); +} + +mod pattern { + use std::str::pattern::SearchStep::{self, Done, Match, Reject}; + use std::str::pattern::{Pattern, ReverseSearcher, Searcher}; + + macro_rules! make_test { + ($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => { + #[allow(unused_imports)] + mod $name { + use std::str::pattern::SearchStep::{Match, Reject}; + use super::{cmp_search_to_vec}; + #[test] + fn fwd() { + cmp_search_to_vec(false, $p, $h, vec![$($e),*]); + } + #[test] + fn bwd() { + cmp_search_to_vec(true, $p, $h, vec![$($e),*]); + } + } + } + } + + fn cmp_search_to_vec