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

pub use multiref::Slice;
mod multiref_impls;

use crate::At;


use alloc::vec::Vec;


/// A newtype-wrapper around slice bounds.
#[repr(transparent)]#[derive(Debug,Copy,Clone)]
pub struct Bounds<B>(pub B);

impl<'a, I, B, V> At<Bounds<B>> for I where
    I: Iterator<Item=&'a mut V>,
    [&'a mut V]: At<B, View = [&'a mut V]>,
    V: 'a + ?Sized,
{
    type View = Slice<V>;

    fn access_at<R, F>(&mut self, i: Bounds<B>, f: F) -> Option<R> where
        F: FnOnce(&mut Slice<V>) -> R
    {
        let mut ref_vec = self.collect::<Vec<_>>();
        // TODO: a more efficient implementation: 
        // O( len(range) ) instead of O( len(collection) )

        (&mut ref_vec[..]).access_at(i.0, |subslice| {
            f(Slice::new_mut(subslice))
        })
    }
}