Algebraic Effects System for Rust

Add support for obtaining tuples from context Has (#13)

authored by oeiuwq.com and committed by

GitHub 6b6beff7 35bcb90b

+608 -7
+4 -4
crates/field_macro/src/lib.rs
··· 2 2 use quote::quote; 3 3 use syn::{Data, DeriveInput, parse_macro_input}; 4 4 5 - #[proc_macro_derive(Field)] 6 - pub fn derive_field(input: TokenStream) -> TokenStream { 5 + #[proc_macro_derive(HasFields)] 6 + pub fn derive_has_fields(input: TokenStream) -> TokenStream { 7 7 let input = parse_macro_input!(input as DeriveInput); 8 8 let name = &input.ident; 9 9 let generics = &input.generics; ··· 11 11 12 12 let fields = match &input.data { 13 13 Data::Struct(data) => &data.fields, 14 - _ => panic!("Field derive macro only supports named structs"), 14 + _ => panic!("HasFields derive macro only supports named structs"), 15 15 }; 16 16 17 17 let mut impls = Vec::new(); 18 18 for field in fields { 19 19 let field_name = match &field.ident { 20 20 Some(ident) => ident, 21 - None => panic!("Field derive macro does not support unnamed or tuple fields"), 21 + None => panic!("HasFields derive macro does not support unnamed or tuple fields"), 22 22 }; 23 23 let field_ty = &field.ty; 24 24 impls.push(quote! {
+1 -1
crates/field_macro/tests/struct_field.rs
··· 2 2 3 3 #[test] 4 4 fn test_field_struct() { 5 - #[derive(Clone, Debug, PartialEq, fx_field::Field)] 5 + #[derive(Clone, Debug, PartialEq, fx_field::HasFields)] 6 6 struct Ctx { 7 7 a: u32, 8 8 b: &'static str,
+159
crates/fx/src/core/get_n.rs
··· 1 + use crate::core::has_put::Has; 2 + use crate::core::state::State; 3 + use crate::kernel::fx::Fx; 4 + 5 + impl<'f, S: Clone> State<'f, S> { 6 + pub fn get2<A, B>() -> Fx<'f, S, (A, B)> 7 + where 8 + S: Has<A> + Has<B> + 'f, 9 + A: Clone + 'f, 10 + B: Clone + 'f, 11 + { 12 + Self::get::<A>().map_m(|a: A| Self::get::<B>().map(|b: B| (a, b))) 13 + } 14 + pub fn get3<A, B, C>() -> Fx<'f, S, (A, B, C)> 15 + where 16 + S: Has<A> + Has<B> + Has<C> + 'f, 17 + A: Clone + 'f, 18 + B: Clone + 'f, 19 + C: Clone + 'f, 20 + { 21 + Self::get::<A>() 22 + .map_m(|a: A| Self::get::<B>().map_m(|b: B| Self::get::<C>().map(|c: C| (a, b, c)))) 23 + } 24 + pub fn get4<A, B, C, D>() -> Fx<'f, S, (A, B, C, D)> 25 + where 26 + S: Has<A> + Has<B> + Has<C> + Has<D> + 'f, 27 + A: Clone + 'f, 28 + B: Clone + 'f, 29 + C: Clone + 'f, 30 + D: Clone + 'f, 31 + { 32 + Self::get::<A>().map_m(|a: A| { 33 + Self::get::<B>().map_m(|b: B| { 34 + Self::get::<C>().map_m(|c: C| Self::get::<D>().map(|d: D| (a, b, c, d))) 35 + }) 36 + }) 37 + } 38 + pub fn get5<A, B, C, D, E>() -> Fx<'f, S, (A, B, C, D, E)> 39 + where 40 + S: Has<A> + Has<B> + Has<C> + Has<D> + Has<E> + 'f, 41 + A: Clone + 'f, 42 + B: Clone + 'f, 43 + C: Clone + 'f, 44 + D: Clone + 'f, 45 + E: Clone + 'f, 46 + { 47 + Self::get::<A>().map_m(|a: A| { 48 + Self::get::<B>().map_m(|b: B| { 49 + Self::get::<C>().map_m(|c: C| { 50 + Self::get::<D>().map_m(|d: D| Self::get::<E>().map(|e: E| (a, b, c, d, e))) 51 + }) 52 + }) 53 + }) 54 + } 55 + pub fn get6<A, B, C, D, E, F>() -> Fx<'f, S, (A, B, C, D, E, F)> 56 + where 57 + S: Has<A> + Has<B> + Has<C> + Has<D> + Has<E> + Has<F> + 'f, 58 + A: Clone + 'f, 59 + B: Clone + 'f, 60 + C: Clone + 'f, 61 + D: Clone + 'f, 62 + E: Clone + 'f, 63 + F: Clone + 'f, 64 + { 65 + Self::get::<A>().map_m(|a: A| { 66 + Self::get::<B>().map_m(|b: B| { 67 + Self::get::<C>().map_m(|c: C| { 68 + Self::get::<D>().map_m(|d: D| { 69 + Self::get::<E>() 70 + .map_m(|e: E| Self::get::<F>().map(|f: F| (a, b, c, d, e, f))) 71 + }) 72 + }) 73 + }) 74 + }) 75 + } 76 + pub fn get7<A, B, C, D, E, F, G>() -> Fx<'f, S, (A, B, C, D, E, F, G)> 77 + where 78 + S: Has<A> + Has<B> + Has<C> + Has<D> + Has<E> + Has<F> + Has<G> + 'f, 79 + A: Clone + 'f, 80 + B: Clone + 'f, 81 + C: Clone + 'f, 82 + D: Clone + 'f, 83 + E: Clone + 'f, 84 + F: Clone + 'f, 85 + G: Clone + 'f, 86 + { 87 + Self::get::<A>().map_m(|a: A| { 88 + Self::get::<B>().map_m(|b: B| { 89 + Self::get::<C>().map_m(|c: C| { 90 + Self::get::<D>().map_m(|d: D| { 91 + Self::get::<E>().map_m(|e: E| { 92 + Self::get::<F>() 93 + .map_m(|f: F| Self::get::<G>().map(|g: G| (a, b, c, d, e, f, g))) 94 + }) 95 + }) 96 + }) 97 + }) 98 + }) 99 + } 100 + pub fn get8<A, B, C, D, E, F, G, H>() -> Fx<'f, S, (A, B, C, D, E, F, G, H)> 101 + where 102 + S: Has<A> + Has<B> + Has<C> + Has<D> + Has<E> + Has<F> + Has<G> + Has<H> + 'f, 103 + A: Clone + 'f, 104 + B: Clone + 'f, 105 + C: Clone + 'f, 106 + D: Clone + 'f, 107 + E: Clone + 'f, 108 + F: Clone + 'f, 109 + G: Clone + 'f, 110 + H: Clone + 'f, 111 + { 112 + Self::get::<A>().map_m(|a: A| { 113 + Self::get::<B>().map_m(|b: B| { 114 + Self::get::<C>().map_m(|c: C| { 115 + Self::get::<D>().map_m(|d: D| { 116 + Self::get::<E>().map_m(|e: E| { 117 + Self::get::<F>().map_m(|f: F| { 118 + Self::get::<G>().map_m(|g: G| { 119 + Self::get::<H>().map(|h: H| (a, b, c, d, e, f, g, h)) 120 + }) 121 + }) 122 + }) 123 + }) 124 + }) 125 + }) 126 + }) 127 + } 128 + pub fn get9<A, B, C, D, E, F, G, H, I>() -> Fx<'f, S, (A, B, C, D, E, F, G, H, I)> 129 + where 130 + S: Has<A> + Has<B> + Has<C> + Has<D> + Has<E> + Has<F> + Has<G> + Has<H> + Has<I> + 'f, 131 + A: Clone + 'f, 132 + B: Clone + 'f, 133 + C: Clone + 'f, 134 + D: Clone + 'f, 135 + E: Clone + 'f, 136 + F: Clone + 'f, 137 + G: Clone + 'f, 138 + H: Clone + 'f, 139 + I: Clone + 'f, 140 + { 141 + Self::get::<A>().map_m(|a: A| { 142 + Self::get::<B>().map_m(|b: B| { 143 + Self::get::<C>().map_m(|c: C| { 144 + Self::get::<D>().map_m(|d: D| { 145 + Self::get::<E>().map_m(|e: E| { 146 + Self::get::<F>().map_m(|f: F| { 147 + Self::get::<G>().map_m(|g: G| { 148 + Self::get::<H>().map_m(|h: H| { 149 + Self::get::<I>().map(|i: I| (a, b, c, d, e, f, g, h, i)) 150 + }) 151 + }) 152 + }) 153 + }) 154 + }) 155 + }) 156 + }) 157 + }) 158 + } 159 + }
-1
crates/fx/src/core/has_put.rs
··· 30 30 } 31 31 32 32 impl<I, O> HasPut<I> for O where O: Has<I> + Put<I> {} 33 - 34 33 clone_trait_object!(<T> Has<T>);
+1
crates/fx/src/core/mod.rs
··· 4 4 pub(super) mod arrow; 5 5 pub(super) mod forall; 6 6 pub(super) mod fx; 7 + mod get_n; 7 8 pub(super) mod handler; 8 9 pub(super) mod has_put; 9 10 pub(super) mod lens;
+440
crates/fx/src/core/tests/get_n_test.rs
··· 1 + use crate::core::has_put::Has; 2 + use crate::core::state::State; 3 + 4 + // Common Ctx and Has impls for primitive tuple tests 5 + #[derive(Clone)] 6 + struct Ctx2 { 7 + a: u8, 8 + b: u16, 9 + } 10 + impl Has<u8> for Ctx2 { 11 + fn get(&self) -> &u8 { 12 + &self.a 13 + } 14 + } 15 + impl Has<u16> for Ctx2 { 16 + fn get(&self) -> &u16 { 17 + &self.b 18 + } 19 + } 20 + 21 + #[derive(Clone)] 22 + struct Ctx3 { 23 + a: u8, 24 + b: u16, 25 + c: u32, 26 + } 27 + impl Has<u8> for Ctx3 { 28 + fn get(&self) -> &u8 { 29 + &self.a 30 + } 31 + } 32 + impl Has<u16> for Ctx3 { 33 + fn get(&self) -> &u16 { 34 + &self.b 35 + } 36 + } 37 + impl Has<u32> for Ctx3 { 38 + fn get(&self) -> &u32 { 39 + &self.c 40 + } 41 + } 42 + 43 + #[derive(Clone)] 44 + struct Ctx4 { 45 + a: u8, 46 + b: u16, 47 + c: u32, 48 + d: u64, 49 + } 50 + impl Has<u8> for Ctx4 { 51 + fn get(&self) -> &u8 { 52 + &self.a 53 + } 54 + } 55 + impl Has<u16> for Ctx4 { 56 + fn get(&self) -> &u16 { 57 + &self.b 58 + } 59 + } 60 + impl Has<u32> for Ctx4 { 61 + fn get(&self) -> &u32 { 62 + &self.c 63 + } 64 + } 65 + impl Has<u64> for Ctx4 { 66 + fn get(&self) -> &u64 { 67 + &self.d 68 + } 69 + } 70 + 71 + #[derive(Clone)] 72 + struct Ctx5 { 73 + a: u8, 74 + b: u16, 75 + c: u32, 76 + d: u64, 77 + e: usize, 78 + } 79 + impl Has<u8> for Ctx5 { 80 + fn get(&self) -> &u8 { 81 + &self.a 82 + } 83 + } 84 + impl Has<u16> for Ctx5 { 85 + fn get(&self) -> &u16 { 86 + &self.b 87 + } 88 + } 89 + impl Has<u32> for Ctx5 { 90 + fn get(&self) -> &u32 { 91 + &self.c 92 + } 93 + } 94 + impl Has<u64> for Ctx5 { 95 + fn get(&self) -> &u64 { 96 + &self.d 97 + } 98 + } 99 + impl Has<usize> for Ctx5 { 100 + fn get(&self) -> &usize { 101 + &self.e 102 + } 103 + } 104 + 105 + #[derive(Clone)] 106 + struct Ctx6 { 107 + a: u8, 108 + b: u16, 109 + c: u32, 110 + d: u64, 111 + e: usize, 112 + f: i8, 113 + } 114 + impl Has<u8> for Ctx6 { 115 + fn get(&self) -> &u8 { 116 + &self.a 117 + } 118 + } 119 + impl Has<u16> for Ctx6 { 120 + fn get(&self) -> &u16 { 121 + &self.b 122 + } 123 + } 124 + impl Has<u32> for Ctx6 { 125 + fn get(&self) -> &u32 { 126 + &self.c 127 + } 128 + } 129 + impl Has<u64> for Ctx6 { 130 + fn get(&self) -> &u64 { 131 + &self.d 132 + } 133 + } 134 + impl Has<usize> for Ctx6 { 135 + fn get(&self) -> &usize { 136 + &self.e 137 + } 138 + } 139 + impl Has<i8> for Ctx6 { 140 + fn get(&self) -> &i8 { 141 + &self.f 142 + } 143 + } 144 + 145 + #[derive(Clone)] 146 + struct Ctx7 { 147 + a: u8, 148 + b: u16, 149 + c: u32, 150 + d: u64, 151 + e: usize, 152 + f: i8, 153 + g: i16, 154 + } 155 + impl Has<u8> for Ctx7 { 156 + fn get(&self) -> &u8 { 157 + &self.a 158 + } 159 + } 160 + impl Has<u16> for Ctx7 { 161 + fn get(&self) -> &u16 { 162 + &self.b 163 + } 164 + } 165 + impl Has<u32> for Ctx7 { 166 + fn get(&self) -> &u32 { 167 + &self.c 168 + } 169 + } 170 + impl Has<u64> for Ctx7 { 171 + fn get(&self) -> &u64 { 172 + &self.d 173 + } 174 + } 175 + impl Has<usize> for Ctx7 { 176 + fn get(&self) -> &usize { 177 + &self.e 178 + } 179 + } 180 + impl Has<i8> for Ctx7 { 181 + fn get(&self) -> &i8 { 182 + &self.f 183 + } 184 + } 185 + impl Has<i16> for Ctx7 { 186 + fn get(&self) -> &i16 { 187 + &self.g 188 + } 189 + } 190 + 191 + #[derive(Clone)] 192 + struct Ctx8 { 193 + a: u8, 194 + b: u16, 195 + c: u32, 196 + d: u64, 197 + e: usize, 198 + f: i8, 199 + g: i16, 200 + h: i32, 201 + } 202 + impl Has<u8> for Ctx8 { 203 + fn get(&self) -> &u8 { 204 + &self.a 205 + } 206 + } 207 + impl Has<u16> for Ctx8 { 208 + fn get(&self) -> &u16 { 209 + &self.b 210 + } 211 + } 212 + impl Has<u32> for Ctx8 { 213 + fn get(&self) -> &u32 { 214 + &self.c 215 + } 216 + } 217 + impl Has<u64> for Ctx8 { 218 + fn get(&self) -> &u64 { 219 + &self.d 220 + } 221 + } 222 + impl Has<usize> for Ctx8 { 223 + fn get(&self) -> &usize { 224 + &self.e 225 + } 226 + } 227 + impl Has<i8> for Ctx8 { 228 + fn get(&self) -> &i8 { 229 + &self.f 230 + } 231 + } 232 + impl Has<i16> for Ctx8 { 233 + fn get(&self) -> &i16 { 234 + &self.g 235 + } 236 + } 237 + impl Has<i32> for Ctx8 { 238 + fn get(&self) -> &i32 { 239 + &self.h 240 + } 241 + } 242 + 243 + #[derive(Clone)] 244 + struct Ctx9 { 245 + a: u8, 246 + b: u16, 247 + c: u32, 248 + d: u64, 249 + e: usize, 250 + f: i8, 251 + g: i16, 252 + h: i32, 253 + i: i64, 254 + } 255 + impl Has<u8> for Ctx9 { 256 + fn get(&self) -> &u8 { 257 + &self.a 258 + } 259 + } 260 + impl Has<u16> for Ctx9 { 261 + fn get(&self) -> &u16 { 262 + &self.b 263 + } 264 + } 265 + impl Has<u32> for Ctx9 { 266 + fn get(&self) -> &u32 { 267 + &self.c 268 + } 269 + } 270 + impl Has<u64> for Ctx9 { 271 + fn get(&self) -> &u64 { 272 + &self.d 273 + } 274 + } 275 + impl Has<usize> for Ctx9 { 276 + fn get(&self) -> &usize { 277 + &self.e 278 + } 279 + } 280 + impl Has<i8> for Ctx9 { 281 + fn get(&self) -> &i8 { 282 + &self.f 283 + } 284 + } 285 + impl Has<i16> for Ctx9 { 286 + fn get(&self) -> &i16 { 287 + &self.g 288 + } 289 + } 290 + impl Has<i32> for Ctx9 { 291 + fn get(&self) -> &i32 { 292 + &self.h 293 + } 294 + } 295 + impl Has<i64> for Ctx9 { 296 + fn get(&self) -> &i64 { 297 + &self.i 298 + } 299 + } 300 + 301 + #[test] 302 + fn get2_extracts_tuple_from_context() { 303 + #[derive(Clone, Debug, PartialEq)] 304 + struct Foo(&'static str); 305 + #[derive(Clone, Debug, PartialEq)] 306 + struct Bar(u8); 307 + #[derive(Clone)] 308 + struct Ctx { 309 + foo: Foo, 310 + bar: Bar, 311 + } 312 + impl Has<Foo> for Ctx { 313 + fn get(&self) -> &Foo { 314 + &self.foo 315 + } 316 + } 317 + impl Has<Bar> for Ctx { 318 + fn get(&self) -> &Bar { 319 + &self.bar 320 + } 321 + } 322 + let ctx = Ctx { 323 + foo: Foo("hi"), 324 + bar: Bar(42), 325 + }; 326 + let fx = State::<Ctx>::get2::<Foo, Bar>(); 327 + let (foo, bar) = fx.provide(ctx.clone()).eval(); 328 + assert_eq!(foo, Foo("hi")); 329 + assert_eq!(bar, Bar(42)); 330 + } 331 + 332 + #[test] 333 + fn get2_works_with_primitives() { 334 + let ctx = Ctx2 { a: 7, b: 99 }; 335 + let fx = State::<Ctx2>::get2::<u8, u16>(); 336 + let (a, b) = fx.provide(ctx.clone()).eval(); 337 + assert_eq!(a, 7); 338 + assert_eq!(b, 99); 339 + } 340 + 341 + #[test] 342 + fn get3_extracts_tuple() { 343 + let ctx = Ctx3 { a: 1, b: 2, c: 3 }; 344 + let fx = State::<Ctx3>::get3::<u8, u16, u32>(); 345 + let (a, b, c) = fx.provide(ctx.clone()).eval(); 346 + assert_eq!((a, b, c), (1, 2, 3)); 347 + } 348 + 349 + #[test] 350 + fn get4_extracts_tuple() { 351 + let ctx = Ctx4 { 352 + a: 1, 353 + b: 2, 354 + c: 3, 355 + d: 4, 356 + }; 357 + let fx = State::<Ctx4>::get4::<u8, u16, u32, u64>(); 358 + let (a, b, c, d) = fx.provide(ctx.clone()).eval(); 359 + assert_eq!((a, b, c, d), (1, 2, 3, 4)); 360 + } 361 + 362 + #[test] 363 + fn get5_extracts_tuple() { 364 + let ctx = Ctx5 { 365 + a: 1, 366 + b: 2, 367 + c: 3, 368 + d: 4, 369 + e: 5, 370 + }; 371 + let fx = State::<Ctx5>::get5::<u8, u16, u32, u64, usize>(); 372 + let (a, b, c, d, e) = fx.provide(ctx.clone()).eval(); 373 + assert_eq!((a, b, c, d, e), (1, 2, 3, 4, 5)); 374 + } 375 + 376 + #[test] 377 + fn get6_extracts_tuple() { 378 + let ctx = Ctx6 { 379 + a: 1, 380 + b: 2, 381 + c: 3, 382 + d: 4, 383 + e: 5, 384 + f: 6, 385 + }; 386 + let fx = State::<Ctx6>::get6::<u8, u16, u32, u64, usize, i8>(); 387 + let (a, b, c, d, e, f) = fx.provide(ctx.clone()).eval(); 388 + assert_eq!((a, b, c, d, e, f), (1, 2, 3, 4, 5, 6)); 389 + } 390 + 391 + #[test] 392 + fn get7_extracts_tuple() { 393 + let ctx = Ctx7 { 394 + a: 1, 395 + b: 2, 396 + c: 3, 397 + d: 4, 398 + e: 5, 399 + f: 6, 400 + g: 7, 401 + }; 402 + let fx = State::<Ctx7>::get7::<u8, u16, u32, u64, usize, i8, i16>(); 403 + let (a, b, c, d, e, f, g) = fx.provide(ctx.clone()).eval(); 404 + assert_eq!((a, b, c, d, e, f, g), (1, 2, 3, 4, 5, 6, 7)); 405 + } 406 + 407 + #[test] 408 + fn get8_extracts_tuple() { 409 + let ctx = Ctx8 { 410 + a: 1, 411 + b: 2, 412 + c: 3, 413 + d: 4, 414 + e: 5, 415 + f: 6, 416 + g: 7, 417 + h: 8, 418 + }; 419 + let fx = State::<Ctx8>::get8::<u8, u16, u32, u64, usize, i8, i16, i32>(); 420 + let (a, b, c, d, e, f, g, h) = fx.provide(ctx.clone()).eval(); 421 + assert_eq!((a, b, c, d, e, f, g, h), (1, 2, 3, 4, 5, 6, 7, 8)); 422 + } 423 + 424 + #[test] 425 + fn get9_extracts_tuple() { 426 + let ctx = Ctx9 { 427 + a: 1, 428 + b: 2, 429 + c: 3, 430 + d: 4, 431 + e: 5, 432 + f: 6, 433 + g: 7, 434 + h: 8, 435 + i: 9, 436 + }; 437 + let fx = State::<Ctx9>::get9::<u8, u16, u32, u64, usize, i8, i16, i32, i64>(); 438 + let (a, b, c, d, e, f, g, h, i) = fx.provide(ctx.clone()).eval(); 439 + assert_eq!((a, b, c, d, e, f, g, h, i), (1, 2, 3, 4, 5, 6, 7, 8, 9)); 440 + }
+2
crates/fx/src/core/tests/mod.rs
··· 16 16 mod handler_test; 17 17 mod pair_test; 18 18 mod provide_test; 19 + 20 + mod get_n_test;
+1 -1
crates/integration/tests/field_macro_test.rs
··· 5 5 struct A(u8); 6 6 #[derive(Clone, Debug, PartialEq)] 7 7 struct B(u8); 8 - #[derive(Clone, Debug, PartialEq, fx_field::Field)] 8 + #[derive(Clone, Debug, PartialEq, fx_field::HasFields)] 9 9 struct Ctx { 10 10 a: A, 11 11 b: B,