From 784001fac793b0343fa2449c838a85193683122a Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Tue, 14 Mar 2023 16:29:10 -0700 Subject: [PATCH] Move `try_collect` into its own trait (#8) --- Cargo.lock | 2 +- Cargo.toml | 2 +- build.ps1 | 25 +++++++++++++++------- src/collect.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 34 ++++++++---------------------- src/tests.rs | 2 +- 6 files changed, 86 insertions(+), 36 deletions(-) create mode 100644 src/collect.rs diff --git a/Cargo.lock b/Cargo.lock index fb6e2de..3446c22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,4 +4,4 @@ version = 3 [[package]] name = "fallible_vec" -version = "0.1.0" +version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index b234f6d..5360576 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "fallible_vec" description = "Fallible allocation functions for the Rust standard library's `Vec` type." -version = "0.1.0" +version = "0.2.0" edition = "2021" license-file = "LICENSE" repository = "https://github.com/microsoft/rust_fallible_vec" diff --git a/build.ps1 b/build.ps1 index 9a2fe91..2f0fbd9 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,6 +1,13 @@ Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' +function Invoke-CheckExitCode([scriptblock]$ScriptBlock) { + & $ScriptBlock + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } +} + function Invoke-WithEnvironment([System.Collections.IDictionary] $Environment, [scriptblock]$ScriptBlock) { try { # Set the environment. @@ -29,18 +36,18 @@ Invoke-WithEnvironment ` # # Run tests # - cargo test --locked + Invoke-CheckExitCode { cargo test --locked } # # Lint and check formatting. # - cargo clippy --locked -- -D warnings - cargo fmt --check + Invoke-CheckExitCode { cargo clippy --locked -- -D warnings } + Invoke-CheckExitCode { cargo fmt --check } # # Check docs # - cargo doc --locked + Invoke-CheckExitCode { cargo doc --locked } # # Verify that we can build with #[cfg(no_global_oom_handling)] enabled. @@ -63,10 +70,12 @@ Invoke-WithEnvironment ` # in the standard library. 'env:RUSTFLAGS' = '--cfg no_global_oom_handling'; } ` - -ScriptBlock { cargo build --locked -Z build-std=core,alloc --target $target } + -ScriptBlock { + Invoke-CheckExitCode { cargo build --locked -Z build-std=core,alloc --target $target } + } } # Run tests under miri -rustup toolchain install nightly --component miri -cargo +nightly miri setup -cargo +nightly miri test +Invoke-CheckExitCode { rustup toolchain install nightly --component miri } +Invoke-CheckExitCode { cargo +nightly miri setup } +Invoke-CheckExitCode { cargo +nightly miri test } diff --git a/src/collect.rs b/src/collect.rs new file mode 100644 index 0000000..46ea109 --- /dev/null +++ b/src/collect.rs @@ -0,0 +1,57 @@ +use crate::FallibleVec; +use alloc::{collections::TryReserveError, vec::Vec}; +use core::alloc::Allocator; + +/// Fallible allocations equivalents for [`Iterator::collect`]. +pub trait TryCollect { + /// Attempts to collect items from an iterator into a vector with the provided + /// allocator. + /// + /// # Examples + /// + /// ``` + /// # #![feature(allocator_api)] + /// # #[macro_use] extern crate fallible_vec; + /// use fallible_vec::*; + /// use std::alloc::System; + /// + /// let doubled = [1, 2, 3, 4, 5].map(|i| i * 2); + /// let vec = doubled.try_collect_in(System)?; + /// assert_eq!(vec, [2, 4, 6, 8, 10]); + /// # Ok::<(), std::collections::TryReserveError>(()) + /// ``` + fn try_collect_in(self, alloc: A) -> Result, TryReserveError>; + + /// Attempts to collect items from an iterator into a vector. + /// + /// # Examples + /// + /// ``` + /// # #![feature(allocator_api)] + /// # #[macro_use] extern crate fallible_vec; + /// use fallible_vec::*; + /// + /// let doubled = [1, 2, 3, 4, 5].map(|i| i * 2); + /// let vec = doubled.try_collect()?; + /// assert_eq!(vec, [2, 4, 6, 8, 10]); + /// # Ok::<(), std::collections::TryReserveError>(()) + /// ``` + fn try_collect(self) -> Result, TryReserveError>; +} + +impl TryCollect for I +where + I: IntoIterator, +{ + fn try_collect_in(self, alloc: A) -> Result, TryReserveError> { + let mut vec = Vec::new_in(alloc); + vec.try_extend(self.into_iter())?; + Ok(vec) + } + + fn try_collect(self) -> Result, TryReserveError> { + let mut vec = Vec::new(); + vec.try_extend(self.into_iter())?; + Ok(vec) + } +} diff --git a/src/lib.rs b/src/lib.rs index 1433c16..b8bef2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,20 +46,22 @@ #![deny(unsafe_op_in_unsafe_fn)] extern crate alloc; +mod collect; mod set_len_on_drop; +use alloc::{ + collections::{TryReserveError, TryReserveErrorKind}, + vec::Vec, +}; use core::{ alloc::Allocator, ops::{Range, RangeBounds}, slice, }; - -use alloc::{ - collections::{TryReserveError, TryReserveErrorKind}, - vec::Vec, -}; use set_len_on_drop::SetLenOnDrop; +pub use collect::TryCollect; + // These are defined so that the try_vec! and try_vec_in! macros can refer to // these types in a consistent way: even if the consuming crate doesn't use // `no_std` and `extern crate alloc`. @@ -68,7 +70,7 @@ pub mod alloc_usings { pub use alloc::{alloc::Layout, boxed::Box, collections::TryReserveError, vec::Vec}; } -/// Methods available for all `Vec` instantiations. +/// Fallible allocation methods for [`Vec`]. pub trait FallibleVec: Sized { /// Extends the `Vec` using the items from the given iterator. /// @@ -430,7 +432,7 @@ impl FallibleVec for Vec { } // Gather up the remainder and copy those as well. - let remainder = try_collect_in(replace_with, alloc)?; + let remainder = replace_with.try_collect_in(alloc)?; if !remainder.is_empty() { move_tail(self, index, remainder.len())?; // Don't need to use `SetLenOnDrop` here since we're enumerating @@ -670,24 +672,6 @@ pub fn try_with_capacity(size: usize) -> Result, TryReserveError> { Ok(vec) } -/// Attempts to collect items from an iterator into a vector with the provided -/// allocator. -pub fn try_collect_in( - iter: impl Iterator, - alloc: A, -) -> Result, TryReserveError> { - let mut vec = Vec::new_in(alloc); - vec.try_extend(iter)?; - Ok(vec) -} - -/// Attempts to collect items from an iterator into a vector. -pub fn try_collect(iter: impl Iterator) -> Result, TryReserveError> { - let mut vec = Vec::new(); - vec.try_extend(iter)?; - Ok(vec) -} - #[doc(hidden)] pub fn try_new_repeat_item_in( item: T, diff --git a/src/tests.rs b/src/tests.rs index 5d58303..f4bdd6b 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -142,7 +142,7 @@ fn test_collect_after_iterator_clone() { let v = try_vec_in![0; 5 => Global].unwrap(); let mut i = v.into_iter().map(|i| i + 1).peekable(); i.peek(); - let v = try_collect_in(i.clone(), Global).unwrap(); + let v = i.clone().try_collect().unwrap(); assert_eq!(v, [1, 1, 1, 1, 1]); assert!(v.len() <= v.capacity()); }