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 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
//! # Overview //! //! `lens-rs` is a lens library for Rust, just like the package [`lens`](https://hackage.haskell.org/package/lens) for Haskell, //! but here are no weird operators, grotesque symbols and confusing types. //! Not only can `lens-rs` get/set for fields of struct, but also variants of enum and items of collection. //! It unifies the way to access to/construct with different nested substructures, providing Rusty-APIs. //! //! //! //! ## Before use //! //! Add the following in your Cargo.toml //! //! ```toml //! [dependencies] //! lens-rs = "0.3" //! //! [package.metadata.inwelling] //! lens-rs_generator = true //! ``` //! //! Add the following in your .rs files //! //! ```rust //! use lens_rs::*; //! ``` //! //! //! ## Usage //! //! ## Access substructures //! //! visit field in struct: //! //! ```rust //! let mut x = Foo { a: String::from(".a in Foo"), b: 0 }; //! assert_eq!(x.view_ref(optics!(a)), ".a in Foo"); //! //! *x.view_mut(optics!(b)) += 1; //! assert_eq!(x.view_ref(optics!(b)), &1) //! ``` //! //! visit variant in enum: //! //! ```rust //! let mut x = Ok(0); //! *x.preview_ref(optics!(Ok))? += 1; //! assert_eq!(x.preview_ref(optics!(Ok))?, &1); //! assert_eq!(x.preview_ref(optics!(Err)), None); //! ``` //! //! visit items in collection: //! //! ```rust //! let mut x = vec![1, 2, 3]; //! x.traverse_mut(optics!(_mapped)).into_iter().for_each(|x| *x += 1); //! assert_eq!(x.traverse_ref(optics!(_mapped)), vec![&2, &3, &4]); //! assert_eq!(x.view_ref(optics!([1])), &3); //! ``` //! //! build a structure: //! //! ```rust //! let x = Review::review(optics!(Ok.Some), 1); //! assert_eq!(x, Ok(Some(1))); //! ``` //! //! ## Compose optics //! //! macro `optics!()` and `Optics![]` is to compose optics: //! //! ```rust //! let optics: Optics![_1.a.Some._mapped.[1]] = optics!(_1.a.Some._mapped.[1]); //! //! let x = (0, Foo { //! a: Some(vec![vec![1,2], vec![3,4]]), //! b: () //! }); //! //! assert_eq!(x.traverse(optics), vec![2, 4]); //! ``` //! //! ## Derive Optics //! //! Derive Lens for fields to use `.view_xx()`. (derive(Optic) is necessary) //! //! ```rust //! #[derive(Lens)] //! struct Foo<A, B> { //! #[optic] //! a: A, // generate optics::a //! #[optic] //! b: B, // generate optics::b //! } //! //! #[derive(Lens)] //! struct Tuple<A, B>(#[optic] A, #[optic] B); //! // use optics::_0 or optics::_1 to access it //! ``` //! //! Derive Review/Prism for variants to use `Review::review`/`.preview_xx()`: //! //! ```rust //! #[derive(Review, Prism)] //! enum Either<L, R> { //! #[optic] //! Left(L), // generate optics::Left //! #[optic] //! Right(R), // generate optics::Right //! } //! ``` //! //! Control the mutability: //! //! ```rust //! #[derive(Debug, Lens)] //! struct Bar<C>{ //! #[optic(ref)] //! a: String, // can only take the immutable ref of .a by optics::a //! #[optic(mut)] //! b: i32, // can take the mutable ref of .b by optics::b //! #[optic] //! c: C // can move .c out by by optics::c //! } //! ``` //! //! ## A little row polymorphism //! //! restrict a type has some fields: //! //! ```rust //! fn with_field_a<T>(t: &T) -> &str //! where //! T: LensRef<Optics![a], String>, // T must have field a //! { //! t.view_ref(optics!(a)) //! } //! //! fn may_has_c<T>(t: T) -> Option<i32> //! where //! T: PrismRef<Optics![c], i32>, // T may have field c //! { //! Some(*t.preview_ref(optics!(c))?) //! } //! //! let foo = Foo { //! a: "this is Foo".to_string(), //! b: (), //! }; //! let bar = Bar { //! a: "this is Bar".to_string(), //! c: 0, //! }; //! //! assert_eq!(with_field_a(&foo), "this is Foo"); //! assert_eq!(with_field_a(&bar), "this is Bar"); //! //! assert_eq!(may_has_c(foo), None); //! assert_eq!(may_has_c(bar), Some(0)); //! assert_eq!(may_has_c(Left(0)), None); //! assert_eq!(may_has_c((1, 2, 3)), None); //! ``` //! //! ## Play with structx //! //! Now, `Lens` has implemented for [`structx`](https://crates.io/crates/structx) //! //! Add the following in your Cargo.toml //! //! ```toml //! [dependencies] //! lens-rs = { version = "0.3", features = [ "structx" ] } //! structx = { version = "0.1", features = [ "lens-rs" ] } //! //! [package.metadata.inwelling] //! lens-rs_generator = true //! structx = true //! ``` //! //! Enjoy it! //! //! ```rust //! use structx::*; //! use lens_rs::*; //! let s1 = structx! { height: 1, width: 2 }; //! let s2 = structx! { height: 3, length: 4 }; //! assert_eq!(s1.view_ref(optics!(height)), &1); //! assert_eq!(s2.view_ref(optics!(height)), &3); //! //! assert_eq!(s1.preview_ref(optics!(width)), Some(&2)); //! assert_eq!(s2.preview_ref(optics!(width)), None); //! ``` //! //! # Limitations //! //! * can't derive `Lens` for enum. //! * can't derive `Prism` and `Review` for the variant has more than one argument or has named field. //! //! # License //! //! Under Apache License 2.0 or MIT License, at your will. /// definitions of optics (including generated optic) pub mod optics; /// definitions of optics traits pub mod traits; pub use traits::{lens::*, prism::*, review::*, traversal::*}; /// build-in optics pub use optics::{ _both, _box, _ix, _mapped, _mut, _ref, _0, _1, _10, _11, _12, _13, _14, _15, _16, _2, _3, _4, _5, _6, _7, _8, _9, __, }; /// derive macro pub use lens_rs_derive::{Lens, Prism, Review}; /// macro to compose optics /// /// ```rust /// let optics: Optics![a.Some.[0]._0] = optics!(a.Some.[0]._0); /// // equivalent to optics!(lens_rs::optics::a.lens_rs::optics::Some.[0].lens_rs::optics::_0) /// // the default optics path is `lens_rs::optics`. /// ``` pub use lens_rs_derive::{optics, Optics};