Skip to content

Commit

Permalink
Move try_collect into its own trait (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
dpaoliello authored Mar 14, 2023
1 parent 8fe3741 commit 784001f
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 36 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
25 changes: 17 additions & 8 deletions build.ps1
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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 }
57 changes: 57 additions & 0 deletions src/collect.rs
Original file line number Diff line number Diff line change
@@ -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<T> {
/// 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<A: Allocator>(self, alloc: A) -> Result<Vec<T, A>, 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<Vec<T>, TryReserveError>;
}

impl<T, I> TryCollect<T> for I
where
I: IntoIterator<Item = T>,
{
fn try_collect_in<A: Allocator>(self, alloc: A) -> Result<Vec<T, A>, TryReserveError> {
let mut vec = Vec::new_in(alloc);
vec.try_extend(self.into_iter())?;
Ok(vec)
}

fn try_collect(self) -> Result<Vec<T>, TryReserveError> {
let mut vec = Vec::new();
vec.try_extend(self.into_iter())?;
Ok(vec)
}
}
34 changes: 9 additions & 25 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand All @@ -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<T, A: Allocator>: Sized {
/// Extends the `Vec` using the items from the given iterator.
///
Expand Down Expand Up @@ -430,7 +432,7 @@ impl<T, A: Allocator> FallibleVec<T, A> for Vec<T, A> {
}

// 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
Expand Down Expand Up @@ -670,24 +672,6 @@ pub fn try_with_capacity<T>(size: usize) -> Result<Vec<T>, TryReserveError> {
Ok(vec)
}

/// Attempts to collect items from an iterator into a vector with the provided
/// allocator.
pub fn try_collect_in<T, A: Allocator>(
iter: impl Iterator<Item = T>,
alloc: A,
) -> Result<Vec<T, A>, 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<T>(iter: impl Iterator<Item = T>) -> Result<Vec<T>, TryReserveError> {
let mut vec = Vec::new();
vec.try_extend(iter)?;
Ok(vec)
}

#[doc(hidden)]
pub fn try_new_repeat_item_in<T: Clone, A: Allocator>(
item: T,
Expand Down
2 changes: 1 addition & 1 deletion src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down

0 comments on commit 784001f

Please sign in to comment.