use crate::{mark_initialized, uninit_buf};
pub trait UnarrayArrayExt<T, const N: usize> {
fn map_result<S, E>(self, f: impl FnMut(T) -> Result<S, E>) -> Result<[S; N], E>;
fn map_option<S>(self, f: impl FnMut(T) -> Option<S>) -> Option<[S; N]>;
}
impl<T, const N: usize> UnarrayArrayExt<T, N> for [T; N] {
fn map_result<S, E>(self, mut f: impl FnMut(T) -> Result<S, E>) -> Result<[S; N], E> {
let mut result = uninit_buf();
for (item, slot) in IntoIterator::into_iter(self).zip(&mut result) {
match f(item) {
Ok(s) => slot.write(s),
Err(e) => return Err(e),
};
}
Ok(unsafe { mark_initialized(result) })
}
fn map_option<S>(self, mut f: impl FnMut(T) -> Option<S>) -> Option<[S; N]> {
let actual_f = |t: T| -> Result<S, ()> { f(t).ok_or(()) };
let result: Result<[S; N], ()> = UnarrayArrayExt::map_result(self, actual_f);
match result {
Ok(result) => Some(result),
Err(()) => None,
}
}
}
#[cfg(test)]
mod tests {
use core::convert::TryInto;
use super::UnarrayArrayExt;
use crate::testing::array_strategy;
use proptest::prelude::*;
use test_strategy::proptest;
#[test]
fn test_map_option() {
let array = [1, 2, 3];
let result = array.map_option(|i| Some(i * 2)).unwrap();
assert_eq!(result, [2, 4, 6]);
}
#[test]
#[should_panic]
fn test_map_option_panic() {
let array = [1, 2, 3];
array.map_option(|i| {
if i > 2 {
panic!();
}
Some(i)
});
}
#[test]
fn test_map_result() {
let array = [1, 2, 3];
let result: Result<_, ()> = array.map_result(|i| Ok(i * 2));
assert_eq!(result.unwrap(), [2, 4, 6]);
}
#[test]
#[should_panic]
fn test_map_result_panic() {
let array = [1, 2, 3];
let _ = array.map_result(|i| -> Result<i32, ()> {
if i > 2 {
panic!();
}
Ok(i)
});
}
const LEN: usize = 100;
#[proptest]
#[cfg_attr(miri, ignore)]
fn proptest_option_map(#[strategy(array_strategy::<LEN>())] array: [String; LEN]) {
let expected = array.iter().map(|s| s.len()).collect::<Vec<_>>();
let expected: [usize; LEN] = expected.try_into().unwrap();
let result = array.map_option(|s| Some(s.len()));
prop_assert_eq!(expected, result.unwrap());
}
#[proptest]
#[cfg_attr(miri, ignore)]
fn proptest_result_map(#[strategy(array_strategy::<LEN>())] array: [String; LEN]) {
let expected = array.iter().map(|s| s.len()).collect::<Vec<_>>();
let expected: [usize; LEN] = expected.try_into().unwrap();
let result: Result<_, ()> = array.map_result(|s| Ok(s.len()));
prop_assert_eq!(expected, result.unwrap());
}
}