smart_access/iter_mut.rs
1//! Support for arbitrary mutating iterators.
2//! __Requires `iter_mut`.__
3//!
4//! This module requires the `alloc` feature:
5//! our [`Cps`](../trait.Cps.html) values are _affine_ traversals,
6//! thus they must have
7//! all the iteration results simultaneously, which in turn requires
8//! allocating memory at runtime.
9//!
10//! This module depends on the [`multiref`](https://crates.io/crates/multiref/)
11//! crate. The [`Slice`](struct.Slice.html) type is re-exported
12//! from `multiref`. You can read [the docs](https://docs.rs/multiref/)
13//! or simply use the `At` impls for `Slice` (they are the same as
14//! for normal slices).
15//!
16//! ## An example
17//!
18//! ```
19//! use smart_access::{ Cps, iter_mut::Bounds };
20//! use std::collections::BTreeMap;
21//!
22//! let mut map = BTreeMap::<i32, BTreeMap::<&'static str, i32>>::new();
23//!
24//! map.at( (1, BTreeMap::new()) ).access(|inner| {
25//! inner.insert("a", 2);
26//! inner.insert("b", 3);
27//! inner.insert("c", 4);
28//! });
29//!
30//! map.at( (5, BTreeMap::new()) ).access(|inner| {
31//! inner.insert("a", 6);
32//! inner.insert("b", 7);
33//! });
34//!
35//! map.at( (8, BTreeMap::new()) ).access(|inner| {
36//! inner.insert("a", 9);
37//! inner.insert("x", 10);
38//! });
39//!
40//! // Hurrah!!! CPS without callback hell!
41//! map.range_mut(5..).map(|(_,v)| v).at(Bounds(..)).at(1).at("a").replace(11);
42//!
43//! assert!(map.at(&8).at("a").get_clone() == Some(11));
44//!
45//! // And now enter batches (and another level of callbacks,
46//! // but still unlike a typical pyramidal callback hell):
47//! map.range_mut(..=5).map(|(_,v)| v).at(Bounds(..)).batch_ct()
48//! .add(|x, _| x.at(0).at("c").replace(12))
49//! .add(|x, _| x.at(0).at("a").replace(13))
50//! .add(|x, _| x.at(1).at("b").replace(14))
51//! .run();
52//!
53//! assert!(map.at(&1).at("c").get_clone() == Some(12));
54//! assert!(map.at(&1).at("a").get_clone() == Some(13));
55//! assert!(map.at(&5).at("b").get_clone() == Some(14));
56//! ```
57//!
58//! ## Usage
59//!
60//! Any `Iterator` (exactly `Iterator`, __not__ `IntoIterator`)
61//! has `At<Bounds<R>>` implemented for every type `R` of `usize`-indexed ranges.
62//!
63//! For example, to access the three elements of a `BTreeMap` with
64//! the smallest keys, you can write
65//! ```
66//! # use std::collections::BTreeMap;
67//! # use smart_access::{ Cps, iter_mut::Bounds };
68//! # let mut map = BTreeMap::<i32,i32>::new();
69//! # let result =
70//! map.iter_mut().map(|kv| kv.1).at(Bounds(..3)).access( |xs| { /* do something */ } );
71//! # assert!(result == None);
72//! ```
73//!
74//! But the main usecase is to allow indices denoting complex places. Suppose
75//! that you want to describe a place
76//! “every third element of an array”.
77//!
78//! It can be done with the following code
79//!
80//! ```
81//! # use smart_access::{ At, Cps, iter_mut::{ Bounds, Slice } };
82//! struct EveryThird;
83//!
84//! impl<T> At<EveryThird> for [T] {
85//! type View = Slice<T>; // there must be Slice<T> instead of [T]
86//!
87//! fn access_at<R, F>(&mut self, _: EveryThird, f: F) -> Option<R> where
88//! F: FnOnce(&mut Slice<T>) -> R
89//! {
90//! self.chunks_mut(3)
91//! .map(|x| unsafe { x.get_unchecked_mut(0) })
92//! .access_at(Bounds(..), f) // the key part
93//! }
94//! }
95//!
96//! // And now the following is possible:
97//! let mut foo = vec![ vec![1, 2, 3, 4], vec![5, 6, 7] ];
98//!
99//! foo.at(0).at(()).at(EveryThird).access(|slice| {
100//! for x in slice.as_mut() { **x = 8; }
101//! });
102//! assert!(foo == vec![vec![8, 2, 3, 8], vec![5, 6, 7]]);
103//! ```
104
105pub use multiref::Slice;
106mod multiref_impls;
107
108use crate::At;
109
110
111use alloc::vec::Vec;
112
113
114/// A newtype-wrapper around slice bounds.
115#[repr(transparent)]#[derive(Debug,Copy,Clone)]
116pub struct Bounds<B>(pub B);
117
118impl<'a, I, B, V> At<Bounds<B>> for I where
119 I: Iterator<Item=&'a mut V>,
120 [&'a mut V]: At<B, View = [&'a mut V]>,
121 V: 'a + ?Sized,
122{
123 type View = Slice<V>;
124
125 fn access_at<R, F>(&mut self, i: Bounds<B>, f: F) -> Option<R> where
126 F: FnOnce(&mut Slice<V>) -> R
127 {
128 let mut ref_vec = self.collect::<Vec<_>>();
129 // TODO: a more efficient implementation:
130 // O( len(range) ) instead of O( len(collection) )
131
132 (&mut ref_vec[..]).access_at(i.0, |subslice| {
133 f(Slice::new_mut(subslice))
134 })
135 }
136}