Skip to content

Commit 933b92e

Browse files
committed
arrray::try_map
1 parent bbcaed0 commit 933b92e

File tree

11 files changed

+66
-11
lines changed

11 files changed

+66
-11
lines changed

library/core/src/array/mod.rs

+56-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::convert::{Infallible, TryFrom};
1212
use crate::fmt;
1313
use crate::hash::{self, Hash};
1414
use crate::marker::Unsize;
15-
use crate::ops::{Index, IndexMut};
15+
use crate::ops::{Index, IndexMut, Try};
1616
use crate::slice::{Iter, IterMut};
1717

1818
mod iter;
@@ -463,6 +463,61 @@ impl<T, const N: usize> [T; N] {
463463
unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) }
464464
}
465465

466+
/// A fallible function `f` applied to each element on array `self` in order to return an array the same size as `self` or the first error encountered.
467+
///
468+
/// # Examples
469+
///
470+
/// ```
471+
/// #![feature(array_try_map)]
472+
/// #![feature(array_map)]
473+
/// let a = ["1", "2", "3"];
474+
/// let b = a.try_map(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
475+
/// assert_eq!(b, [2, 3, 4]);
476+
///
477+
/// let a = ["1", "2a", "3"];
478+
/// let b = a.try_map(|v| v.parse::<u32>());
479+
/// assert!(b.is_err());
480+
/// ```
481+
#[unstable(feature = "array_try_map", issue = "75243")]
482+
pub fn try_map<F, R, E, U>(self, mut f: F) -> Result<[U; N], E>
483+
where
484+
F: FnMut(T) -> R,
485+
R: Try<Ok = U, Error = E>,
486+
{
487+
use crate::mem::MaybeUninit;
488+
struct Guard<T, const N: usize> {
489+
dst: *mut T,
490+
initialized: usize,
491+
}
492+
493+
impl<T, const N: usize> Drop for Guard<T, N> {
494+
fn drop(&mut self) {
495+
debug_assert!(self.initialized <= N);
496+
497+
let initialized_part =
498+
crate::ptr::slice_from_raw_parts_mut(self.dst, self.initialized);
499+
// SAFETY: this raw slice will contain only initialized objects
500+
// that's why, it is allowed to drop it.
501+
unsafe {
502+
crate::ptr::drop_in_place(initialized_part);
503+
}
504+
}
505+
}
506+
let mut dst = MaybeUninit::uninit_array::<N>();
507+
let mut guard: Guard<U, N> =
508+
Guard { dst: MaybeUninit::slice_as_mut_ptr(&mut dst), initialized: 0 };
509+
for (src, dst) in IntoIter::new(self).zip(&mut dst) {
510+
dst.write(f(src)?);
511+
guard.initialized += 1;
512+
}
513+
// FIXME: Convert to crate::mem::transmute once it works with generics.
514+
// unsafe { crate::mem::transmute::<[MaybeUninit<U>; N], [U; N]>(dst) }
515+
crate::mem::forget(guard);
516+
// SAFETY: At this point we've properly initialized the whole array
517+
// and we just need to cast it to the correct type.
518+
unsafe { Ok(crate::mem::transmute_copy::<_, [U; N]>(&dst)) }
519+
}
520+
466521
/// 'Zips up' two arrays into a single array of pairs.
467522
///
468523
/// `zip()` returns a new array where every element is a tuple where the

src/doc/book

Submodule book updated 217 files

src/tools/cargo

Submodule cargo updated 74 files

src/tools/rustfmt

Submodule rustfmt updated 55 files

0 commit comments

Comments
 (0)