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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
//! Implementation of [`At`](../trait.At.html) for some collections. //! __Requires the `collections` feature.__ //! //! The following traits are implemented: //! * `At<(), View=[T]> for Vec<T>`: the slice owned by the vector //! * `At<usize, View=T> for Vec<T>`: simple indexing //! * `At<range, View=Vec<T>> for Vec<T>`: subvector (its size can be changed); //! __Warning:__ access is O(n); consider passing to slices to get O(1) access //! * `At<&Q, View=V> for <Some>Map<K,V>`: access the value if it is present //! * `At<(K,V), View=V> for <Some>Map<K,V>`: ensure that the value is //! present (using the provided default) then access it //! * `AT<(K,V,M), View=V> for <Some>Map<K,V>`: if the value is present //! then preprocess it with a mutator `M`, otherwise insert the provided `V` //! * `AT<&Q, View=T> for <Some>Set<T>`: access the value if it is present //! * `AT<(T,()), View=T> for <Some>Set<T>`: ensure that the value is present //! then access it //! * `AT<(T,), View=<Some>Set<T>> for <Some>Set<T>`: ensure that the value //! is present //! //! Though in normal circumstances these implementations __do not__ panic //! there __exists__ a possibility of panicking. For example //! `At<range> for Vec<T>` splits vector into (at most) three parts //! then glues them back after the update. Every of these actions //! can panic on Out Of Memory. //! //! ## Vector accessors //! //! ``` //! # use smart_access::{ Cps }; //! let mut foo = vec![1,2,3]; //! //! assert!(foo.at(0).replace(4) == Some(1)); //! assert!(foo == vec![4,2,3]); //! //! assert!(foo.at(3).replace(0) == None); //! assert!(foo == vec![4,2,3]); //! //! assert!(foo.at(1..=2).replace(vec![5,6,7]) == Some(vec![2,3])); //! assert!(foo == vec![4,5,6,7]); //! //! // faster but less flexible //! // VVVVVV //! assert!(foo.at(()).at(1..=2).at(0).replace(8) == Some(5)); //! assert!(foo == vec![4,8,6,7]); //! ``` //! //! //! ## Map accessors //! //! Implemented for `HashMap` and `BTreeMap`: //! //! * `map.at(&k).access(f)` is equivalent to `map.get_mut(&k).map(|v| f(v))` //! * `map.at( (k,v) ).access(f)` is equivalent to `Some(f(map.entry(k).or_insert(v)))` //! * `map.at( (k,v,m) ).access(f)` is equivalent to `Some(f(self.entry(k).and_modify(m).or_insert(v)))` //! //! ``` //! # use smart_access::{ Cps }; //! # use hashbrown::HashMap; //! let mut hm = HashMap::<usize, usize>::new(); //! //! hm.at( (42, 1) ).touch(); //! //! let mut found = false; //! hm.at(&42).access(|x| { //! assert!(*x == 1); //! //! found = true; //! //! *x += 1; //! }); //! //! assert!(found); //! assert!(hm.get(&42) == Some(&2)); //! //! let mutator = |x: &mut _| { *x = 4; }; //! hm.at( (41, 3, &mutator) ).touch(); //! hm.at( (42, 3, &mutator) ).touch(); //! //! assert!(hm.get(&41) == Some(&3)); //! assert!(hm.get(&42) == Some(&4)); //! ``` //! //! //! ## Set accessors //! //! Implemented for `HashSet<T>` and `BTreeSet<T>`. //! //! Semantics differ from the `HashMap<T, ()>` and `BTreeMap<T, ()>` implementations: //! the `Map` ones _do not_ change the key, but the `Set` ones _do_ change. //! //! Compare: //! //! ``` //! # use hashbrown::{ HashMap, HashSet }; //! # use smart_access::Cps; //! let mut map = HashMap::<String,()>::new(); //! let mut set = HashSet::<String>::new(); //! //! map.at( ("Hello".to_string(), ()) ).touch(); //! set.at( ("Hello".to_string(), ()) ).touch(); //! //! map.at("Hello").access(|()| { /* We can do nothing here with the string... */ }); //! set.at("Hello").access(|hello| { *hello = "world".to_string(); } ); //! //! assert!(set == vec!["world".to_string()].into_iter().collect()); //! ``` //! //! Also a one-tuple accessor is available, allowing to chain insertions: //! //! ``` //! # use hashbrown::{ HashSet }; //! # use smart_access::Cps; //! let mut set = HashSet::new(); //! //! set.at( (2,) ).at( (3,) ).at( (5,) ).at( (7,) ).touch(); //! assert!(set == vec![2,3,5,7].into_iter().collect()); //! ``` mod vec; mod map; mod set; #[test] fn test_vec() { extern crate std; use std::vec; use std::prelude::v1::*; use crate::Cps; let mut foo = vec![1,2,3,4,5]; let update = |i| move |vec: &mut Vec<i32>| { vec.push(i); vec[0] }; assert!(foo.at(1..3).access(update(6)) == Some(2)); assert!(foo == vec![1,2,3,6,4,5]); assert!(foo.at(2..).access(update(7)) == Some(3)); assert!(foo == vec![1,2,3,6,4,5,7]); assert!(foo.at(..4).access(update(8)) == Some(1)); assert!(foo == vec![1,2,3,6,8,4,5,7]); assert!(foo.at(..).access(update(9)) == Some(1)); assert!(foo == vec![1,2,3,6,8,4,5,7,9]); assert!(foo.at(..=10).access(update(1)) == None); assert!(foo == vec![1,2,3,6,8,4,5,7,9]); assert!(foo.at(3..=4).access(update(0)) == Some(6)); assert!(foo == vec![1,2,3,6,8,0,4,5,7,9]); assert!(foo.at(4).replace(1) == Some(8)); assert!(foo == vec![1,2,3,6,1,0,4,5,7,9]); } #[test]#[cfg(feature="std_hashmap")] fn test_hash_map() { extern crate std; use std::prelude::v1::*; use std::collections::HashMap; use crate::Cps; let mut map = HashMap::<String,i32>::new(); map.at( ("foo".to_string(), 1) ).touch(); map.at( ("bar".to_string(), 2) ).touch(); map.at( ("baz".to_string(), 3) ).touch(); assert!(map.at("foo").replace(4) == Some(1)); assert!(map.at("quuz").replace(5) == None); let mut reference_map = HashMap::<String,i32>::new(); reference_map.entry("foo".to_string()).or_insert(4); reference_map.entry("bar".to_string()).or_insert(2); reference_map.entry("baz".to_string()).or_insert(3); assert!(map == reference_map); } #[test] fn test_btree_map() { extern crate std; use std::prelude::v1::*; use std::collections::BTreeMap; use crate::Cps; let mut map = BTreeMap::<String,i32>::new(); map.at( ("foo".to_string(), 1) ).touch(); map.at( ("bar".to_string(), 2) ).touch(); map.at( ("baz".to_string(), 3) ).touch(); assert!(map.at("foo").replace(4) == Some(1)); assert!(map.at("quuz").replace(5) == None); let mut reference_map = BTreeMap::<String,i32>::new(); reference_map.entry("foo".to_string()).or_insert(4); reference_map.entry("bar".to_string()).or_insert(2); reference_map.entry("baz".to_string()).or_insert(3); assert!(map == reference_map); }