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> {}