gc_sequence/sequence_ext.rs
1use alloc::boxed::Box;
2use gc_arena::{Collect, MutationContext};
3
4use crate::{
5 flatten::Flatten,
6 map::{Map, MapWith},
7 then::{Then, ThenWith},
8 Sequence,
9};
10
11/// Extension trait for `Sequence` that provides useful combinator methods.
12pub trait SequenceExt<'gc>: Sized + Sequence<'gc> {
13 /// Map a function over result of this sequence.
14 ///
15 /// The given function is run in the same call to `Sequence::step` that produces the result of
16 /// this sequence.
17 fn map<F, R>(self, f: F) -> Map<Self, F>
18 where
19 F: 'static + FnOnce(Self::Output) -> R,
20 {
21 Map::new(self, f)
22 }
23
24 /// Equivalent to `SequencExt::map` but calls the function with a context parameter.
25 ///
26 /// The context parameter can be anything that implements `Collect`. It exists to allow
27 /// closures to manually close over variables that implement `Collect`, because there is no way
28 /// currently for closure types to automatically implement `Collect` and are thus required to be
29 /// 'static.
30 fn map_with<C, F, R>(self, c: C, f: F) -> MapWith<Self, C, F>
31 where
32 C: Collect,
33 F: 'static + FnOnce(C, Self::Output) -> R,
34 {
35 MapWith::new(self, c, f)
36 }
37
38 /// Execute a separate sequence step after this sequence completes.
39 ///
40 /// The given function is run in a separate `Sequence::step` call from the one that produces the
41 /// result of this sequence.
42 fn then<F, R>(self, f: F) -> Then<'gc, Self, F>
43 where
44 Self::Output: Collect,
45 F: 'static + FnOnce(MutationContext<'gc, '_>, Self::Output) -> R,
46 {
47 Then::new(self, f)
48 }
49
50 /// Equivalent to `SequenceExt::then` but calls the function with the given context parameter.
51 ///
52 /// The context parameter can be anything that implements `Collect`, it exists to allow closures
53 /// to manually close over variables that implement `Collect`, because there is no way currently
54 /// for closure types to automatically themselves implement `Collect` and are thus required to
55 /// be 'static.
56 fn then_with<C, F, R>(self, c: C, f: F) -> ThenWith<'gc, Self, C, F>
57 where
58 C: Collect,
59 Self::Output: Collect,
60 F: 'static + FnOnce(MutationContext<'gc, '_>, C, Self::Output) -> R,
61 {
62 ThenWith::new(self, c, f)
63 }
64
65 /// Call a function on the result of this sequence, producing a new sequence to run.
66 ///
67 /// The given function is run in a separate `Sequence::step` call to the one that produces a
68 /// result of this sequence, and the `Sequence` that this function results in is run in
69 /// additional separate `Sequence::step` calls.
70 fn chain<F, R>(self, f: F) -> Flatten<'gc, Then<'gc, Self, F>>
71 where
72 Self::Output: Collect,
73 F: 'static + FnOnce(MutationContext<'gc, '_>, Self::Output) -> R,
74 R: Sequence<'gc>,
75 {
76 Flatten::new(Then::new(self, f))
77 }
78
79 /// Equivalent to `SequenceExt::chain` but calls the function with the given context parameter.
80 ///
81 /// The context parameter can be anything that implements `Collect`, it exists to allow closures
82 /// to manually close over variables that implement `Collect`, because there is no way currently
83 /// for closure types to automatically themselves implement `Collect` and are thus required to
84 /// be 'static.
85 fn chain_with<C, F, R>(self, c: C, f: F) -> Flatten<'gc, ThenWith<'gc, Self, C, F>>
86 where
87 C: Collect,
88 Self::Output: Collect,
89 F: 'static + FnOnce(MutationContext<'gc, '_>, C, Self::Output) -> R,
90 R: Sequence<'gc>,
91 {
92 Flatten::new(ThenWith::new(self, c, f))
93 }
94
95 /// If this sequence results in another sequence, this combinator flattens them so that they are
96 /// executed one after another.
97 fn flatten(self) -> Flatten<'gc, Self>
98 where
99 Self::Output: Sequence<'gc>,
100 {
101 Flatten::new(self)
102 }
103
104 /// Turn this sequence into a boxed sequence type.
105 ///
106 /// The return type is a `dyn Sequence` because where you would need to produce a boxed sequence
107 /// you generally are doing this to purposefully forget what the particular sequence type is,
108 /// and doing this here eases type inference.
109 fn boxed(self) -> Box<dyn Sequence<'gc, Output = Self::Output> + 'gc>
110 where
111 Self: 'gc,
112 {
113 Box::new(self)
114 }
115}
116
117impl<'gc, T> SequenceExt<'gc> for T where T: Sequence<'gc> {}