Skip to content

Commit 8adec1b

Browse files
committed
Introduce Itertools::owned() / Owned.
This is very similar to std’s `Iterator::clone()` / `Cloned`, but works on more types, such as `CStr` / `CString`.
1 parent 25c1eff commit 8adec1b

File tree

4 files changed

+84
-0
lines changed

4 files changed

+84
-0
lines changed

benches/specializations.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#![allow(unstable_name_collisions)]
22

3+
use std::ffi::CString;
4+
35
use criterion::black_box;
46
use criterion::BenchmarkId;
57
use itertools::Itertools;
@@ -666,4 +668,10 @@ bench_specializations! {
666668
}
667669
v.iter().copied().flatten_ok()
668670
}
671+
owned {
672+
{
673+
let v = black_box((0..1024).map(|_| CString::new("foo bar zoo").unwrap()).collect_vec());
674+
}
675+
v.iter().map(CString::as_c_str).owned()
676+
}
669677
}

src/adaptors/mod.rs

+50
Original file line numberDiff line numberDiff line change
@@ -1263,3 +1263,53 @@ where
12631263
F: FnMut(&mut I::Item),
12641264
{
12651265
}
1266+
1267+
/// An iterator adapter to transform borrowed items ([`ToOwned`]) into their owned counterparts.
1268+
///
1269+
/// See [`.owned()`](crate::Itertools::owned) for more information.
1270+
#[derive(Clone, Debug)]
1271+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
1272+
pub struct Owned<I> {
1273+
iter: I,
1274+
}
1275+
1276+
impl<'a, I, T> Iterator for Owned<I>
1277+
where
1278+
I: Iterator<Item = &'a T>,
1279+
T: 'a + ?Sized + ToOwned,
1280+
{
1281+
type Item = T::Owned;
1282+
1283+
fn next(&mut self) -> Option<Self::Item> {
1284+
self.iter.next().map(ToOwned::to_owned)
1285+
}
1286+
}
1287+
1288+
impl<'a, I, T> ExactSizeIterator for Owned<I>
1289+
where
1290+
I: ExactSizeIterator<Item = &'a T>,
1291+
T: 'a + ?Sized + ToOwned,
1292+
{
1293+
}
1294+
1295+
impl<'a, I, T> DoubleEndedIterator for Owned<I>
1296+
where
1297+
I: DoubleEndedIterator<Item = &'a T>,
1298+
T: 'a + ?Sized + ToOwned,
1299+
{
1300+
fn next_back(&mut self) -> Option<Self::Item> {
1301+
self.iter.next_back().map(ToOwned::to_owned)
1302+
}
1303+
}
1304+
1305+
impl<'a, I, T> FusedIterator for Owned<I>
1306+
where
1307+
I: FusedIterator<Item = &'a T>,
1308+
T: 'a + ?Sized + ToOwned,
1309+
{
1310+
}
1311+
1312+
/// Create a new `Owned` iterator.
1313+
pub fn owned<I>(iter: I) -> Owned<I> {
1314+
Owned { iter }
1315+
}

src/lib.rs

+12
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ extern crate core as std;
5757
#[cfg(feature = "use_alloc")]
5858
extern crate alloc;
5959

60+
use adaptors::Owned;
6061
#[cfg(feature = "use_alloc")]
6162
use alloc::{collections::VecDeque, string::String, vec::Vec};
6263

@@ -91,6 +92,8 @@ pub use std::iter as __std_iter;
9192
pub mod structs {
9293
#[cfg(feature = "use_alloc")]
9394
pub use crate::adaptors::MultiProduct;
95+
#[cfg(feature = "use_alloc")]
96+
pub use crate::adaptors::Owned;
9497
pub use crate::adaptors::{
9598
Batching, Coalesce, Dedup, DedupBy, DedupByWithCount, DedupWithCount, FilterMapOk,
9699
FilterOk, Interleave, InterleaveShortest, MapInto, MapOk, Positions, Product, PutBack,
@@ -4581,6 +4584,15 @@ pub trait Itertools: Iterator {
45814584
_ => Err(sh),
45824585
}
45834586
}
4587+
4588+
/// Create a new iterator that transforms borrowed items of an underlying iterator into their owned counterparts.
4589+
#[cfg(feature = "use_alloc")]
4590+
fn owned(self) -> Owned<Self>
4591+
where
4592+
Self: Sized,
4593+
{
4594+
adaptors::owned(self)
4595+
}
45844596
}
45854597

45864598
impl<T> Itertools for T where T: Iterator + ?Sized {}

tests/test_std.rs

+14
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use rand::{
2020
Rng, SeedableRng,
2121
};
2222
use rand::{seq::SliceRandom, thread_rng};
23+
use std::ffi::CString;
2324
use std::{cmp::min, fmt::Debug, marker::PhantomData};
2425

2526
#[test]
@@ -1567,3 +1568,16 @@ fn multiunzip() {
15671568
)
15681569
);
15691570
}
1571+
1572+
#[test]
1573+
fn owned() {
1574+
let owned = [
1575+
CString::new("foo").unwrap(),
1576+
CString::new("bar").unwrap(),
1577+
CString::new("").unwrap(),
1578+
CString::new("zoo").unwrap(),
1579+
];
1580+
let borrowed = owned.iter().map(CString::as_c_str);
1581+
let iter = borrowed.owned();
1582+
assert_eq!(iter.collect_array(), Some(owned));
1583+
}

0 commit comments

Comments
 (0)