Skip to content

Commit 630e904

Browse files
authored
Merge pull request #5 from orxfun/object-safe-iterables
obj-safe module and object safe collections and iterables are defined
2 parents f41e037 + 74d8b60 commit 630e904

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+2560
-218
lines changed

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "orx-iterable"
3-
version = "1.0.4"
3+
version = "1.1.0"
44
edition = "2021"
55
authors = ["orxfun <[email protected]>"]
66
description = "Defines and implements Iterable, Collection and CollectionMut traits to represent types that can be iterated over multiple times."
@@ -15,3 +15,7 @@ orx-self-or = "1.0"
1515
[dev-dependencies]
1616
arrayvec = { version = "0.7.6", default-features = false }
1717
smallvec = { version = "1.13.2", default-features = false }
18+
19+
[features]
20+
default = ["std"]
21+
std = []

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Not all iterables are collections storing elements. For instance, a *Range* is i
1515

1616
> More general immutable iterable trait `Iterable` is defined and implemented for collections and cloneable iterators, and it is open for custom iterables.
1717
18+
In addition, **object safe variants** of these traits, `IterableObj`, `CollectionObj` and `CollectionMutObj` are provided, please see section E for details.
19+
1820
## A. Collection and CollectionMut
1921

2022
The core method of the Collection trait is `iter(&self)` which returns an iterator yielding shared references; i.e., `&Item`.
@@ -491,6 +493,43 @@ assert_eq!(numbers.iter().collect::<Vec<_>>(), [&5, &8, &4, &3]);
491493
</details>
492494
<br />
493495

496+
## E. Object Safe Iterables and Collections
497+
498+
You may refer to the rust book for an introduction of [trait objects](https://doc.rust-lang.org/book/ch17-02-trait-objects.html).
499+
500+
The requirement can be demonstrated with the following example. Assume that we have a type, say `Repo`, which needs to hold a String collection, say `names`. We want to allow for different collections. We can achieve this by making our type generic over the collection type; i.e., `C: Collection`. Then, our type becomes `Repo<C>`. This has the advantage of monomorphization which would give us zero cost abstraction.
501+
502+
```rust
503+
use orx_iterable::*;
504+
505+
struct Repo<C: Collection<Item = String>> {
506+
names: C,
507+
}
508+
```
509+
510+
However, this is a more complex type than only `Repo` (the complexity can get out of hand if we have, for instance, four collections in our repo). We can achieve the simpler type by making our collection a trait object, adding an indirection such as `Box` or `Rc` and using it as our field. In this case, our code will use dynamic dispatch which is slower. Sometimes the difference is negligible in our application. If we prefer simplicity in this tradeoff, we can use the trait object approach.
511+
512+
However, we cannot use the `Iterable`, `Collection` or `CollectionMut` traits, because trait objects have certain restrictions. For this purpose, object safe variants `IterableObj`, `CollectionObj` and `CollectionMutObj` are introduced. These object safe variants have `boxed_iter` and `boxed_iter_mut` methods returning iterators in a box, rather than *iter* and *iter_mut*.
513+
514+
The conditions to implement these variants are identical to the original traits. Therefore, if a type implements `Collection` it also implements `CollectionObj`, and vice versa.
515+
516+
Now we can achieve our simpler `Repo` type.
517+
518+
```rust
519+
use orx_iterable::obj_safe::*;
520+
521+
struct Repo {
522+
names: Box<dyn CollectionObj<Item = String>>,
523+
}
524+
```
525+
526+
In order to use object safe iterables and collections please add `--features std` if default features are not used, and use `use orx_iterable::{*, obj_safe::*}` to import dependencies rather than `use orx_iterable::*`.
527+
528+
For a comparison of both generic and trait object approaches, please see the examples:
529+
530+
* [tests/fields_of_generic_iterables.rs](https://github.com/orxfun/orx-iterable/blob/main/tests/fields_of_generic_iterables.rs)
531+
* [tests/fields_of_iterable_objects.rs](https://github.com/orxfun/orx-iterable/blob/main/tests/fields_of_iterable_objects.rs)
532+
494533
## Contributing
495534

496535
Contributions are welcome! If you notice an error, have a question or think something could be improved, please open an [issue](https://github.com/orxfun/orx-iterable/issues/new) or create a PR.

examples/stats.rs

Lines changed: 0 additions & 134 deletions
This file was deleted.

src/collection.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,8 @@ where
361361
{
362362
type Item = <X as IntoIterator>::Item;
363363

364-
type Iterable<'i> = &'i X
364+
type Iterable<'i>
365+
= &'i X
365366
where
366367
Self: 'i;
367368

src/collection_mut.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,8 @@ where
382382
for<'a> &'a X: IntoIterator<Item = &'a <X as IntoIterator>::Item>,
383383
for<'a> &'a mut X: IntoIterator<Item = &'a mut <X as IntoIterator>::Item>,
384384
{
385-
type IterMut<'i> = <&'i mut X as IntoIterator>::IntoIter
385+
type IterMut<'i>
386+
= <&'i mut X as IntoIterator>::IntoIter
386387
where
387388
Self: 'i;
388389

src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
)]
1313
#![no_std]
1414

15+
#[cfg(any(test, feature = "std"))]
16+
extern crate std;
17+
1518
mod collection;
1619
mod collection_mut;
1720
mod iterable;
@@ -20,9 +23,13 @@ mod producing_iterables;
2023
pub mod sources;
2124
/// Module defining transformations among iterables.
2225
pub mod transformations;
26+
27+
/// Object safe variants of Iterable, Collection and CollectionMut traits.
28+
#[cfg(feature = "std")]
29+
pub mod obj_safe;
30+
2331
pub use collection::Collection;
2432
pub use collection_mut::CollectionMut;
2533
pub use iterable::Iterable;
26-
2734
pub use sources::{empty, empty_col, once, once_col, repeat, repeat_n};
2835
pub use transformations::IntoCloningIterable;

src/obj_safe/collection_mut_obj.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use crate::obj_safe::collection_obj::CollectionObj;
2+
use std::boxed::Box;
3+
4+
/// In addition to [`boxed_iter`], a `CollectionMutObj` provides the [`boxed_iter_mut`] method which returns a boxed
5+
/// iterator over mutable references of elements of the collection.
6+
///
7+
/// It is the object safe counterpart of [`CollectionMut`] trait which can conveniently be made into a trait object.
8+
///
9+
/// Note that for collections, `CollectionMutObj` is implicitly implemented and readily available.
10+
/// Please refer to [`CollectionMut`] documentation for details of automatic implementations.
11+
///
12+
/// In order to use object safe iterables and collections please add `--features std` and use
13+
/// `use orx_iterable::{*, obj_safe::*}` to import dependencies rather than `use orx_iterable::*`.
14+
///
15+
/// [`Iterable`]: crate::Iterable
16+
/// [`Item`]: crate::obj_safe::CollectionMutObj::Item
17+
/// [`boxed_iter`]: crate::obj_safe::CollectionObj::boxed_iter
18+
/// [`boxed_iter_mut`]: crate::obj_safe::CollectionMutObj::boxed_iter_mut
19+
/// [`CollectionMut`]: crate::CollectionMut
20+
///
21+
/// # Examples
22+
///
23+
/// ```
24+
/// use orx_iterable::obj_safe::*;
25+
/// use arrayvec::ArrayVec;
26+
/// use smallvec::{smallvec, SmallVec};
27+
/// use std::collections::{LinkedList, VecDeque};
28+
///
29+
/// /// first computes sum, and then adds it to each of the elements
30+
/// fn increment_by_sum(numbers: &mut dyn CollectionMutObj<Item = i32>) {
31+
/// let sum: i32 = numbers.boxed_iter().sum();
32+
///
33+
/// for x in numbers.boxed_iter_mut() {
34+
/// *x += sum;
35+
/// }
36+
/// }
37+
///
38+
/// // example collections that automatically implement CollectionMut
39+
///
40+
/// let mut x = [1, 2, 3];
41+
/// increment_by_sum(&mut x);
42+
/// assert_eq!(x, [7, 8, 9]);
43+
///
44+
/// let mut x = vec![1, 2, 3];
45+
/// increment_by_sum(&mut x);
46+
///
47+
/// let mut x = LinkedList::from_iter([1, 2, 3]);
48+
/// increment_by_sum(&mut x);
49+
///
50+
/// let mut x = VecDeque::from_iter([1, 2, 3]);
51+
/// increment_by_sum(&mut x);
52+
///
53+
/// let mut x: SmallVec<[_; 128]> = smallvec![3, 5, 7];
54+
/// increment_by_sum(&mut x);
55+
///
56+
/// let mut x = ArrayVec::<_, 16>::new();
57+
/// x.extend([3, 5, 7]);
58+
/// increment_by_sum(&mut x);
59+
/// ```
60+
pub trait CollectionMutObj: CollectionObj {
61+
/// Creates a new iterator in a box yielding mutable references to the elements of the collection; i.e.,
62+
/// type of elements is `&mut Item`.
63+
fn boxed_iter_mut(&mut self) -> Box<dyn Iterator<Item = &mut Self::Item> + '_>;
64+
}
65+
66+
impl<X> CollectionMutObj for X
67+
where
68+
X: IntoIterator,
69+
for<'a> &'a X: IntoIterator<Item = &'a <X as IntoIterator>::Item>,
70+
for<'a> &'a mut X: IntoIterator<Item = &'a mut <X as IntoIterator>::Item>,
71+
{
72+
fn boxed_iter_mut(&mut self) -> Box<dyn Iterator<Item = &mut Self::Item> + '_> {
73+
Box::new(<&mut X as IntoIterator>::into_iter(self))
74+
}
75+
}

0 commit comments

Comments
 (0)