Skip to main content

chargrid_common/control_flow/
boxed.rs

1pub use crate::control_flow::LoopControl;
2use crate::{
3    align::Alignment,
4    border::BorderStyle,
5    control_flow::{
6        Lens, OrClickOut, OrClose, OrEscape, OrEscapeOrClickOut, OrEscapeOrStart, unboxed,
7    },
8    pad_by::Padding,
9};
10pub use chargrid_core::app;
11use chargrid_core::{
12    BoxedComponent, Component, Ctx, Event, FrameBuffer, ICoord, Rgba32, Style, Tint, UCoord, input,
13};
14use std::time::Duration;
15
16/// A component which exposes additional methods for sequencing control flow operations. For
17/// components which notionally yield a single value of type `T` (e.g. a menu from which a single
18/// selection may be made), the convention is to have their `CF` yield a result of `Option<T>`.
19/// In such a case, a value of `None` will be yielded in response to all input until the component
20/// "completes" (e.g. in the menu example, until the selection is made), at which point `Some(...)`
21/// will be yielded containing a value representing the result of the component. In these cases,
22/// unless specified otherwise, it's considered unspecified behaviour to present a completed
23/// component with input events.
24pub struct CF<O, S>(unboxed::CF<BoxedComponent<O, S>>);
25
26/// Build a new `CF` from an existing component
27pub fn cf<C: 'static + Component>(component: C) -> CF<C::Output, C::State>
28where
29    C::State: Sized,
30{
31    CF(unboxed::cf(BoxedComponent(Box::new(component))))
32}
33
34impl<O, S> From<BoxedComponent<O, S>> for CF<O, S> {
35    fn from(boxed_component: BoxedComponent<O, S>) -> Self {
36        CF(unboxed::cf(boxed_component))
37    }
38}
39
40impl<O, S> Component for CF<O, S> {
41    type Output = O;
42    type State = S;
43    fn render(&self, state: &Self::State, ctx: Ctx, fb: &mut FrameBuffer) {
44        self.0.render(state, ctx, fb);
45    }
46    fn update(&mut self, state: &mut Self::State, ctx: Ctx, event: Event) -> Self::Output {
47        self.0.update(state, ctx, event)
48    }
49    fn size(&self, state: &Self::State, ctx: Ctx) -> UCoord {
50        self.0.size(state, ctx)
51    }
52}
53
54impl<O: 'static, S: 'static> CF<O, S> {
55    /// Change the expected `State` of `self` by applying a `Lens`.
56    pub fn lens_state<S_, L>(self, lens: L) -> CF<O, S_>
57    where
58        S_: 'static,
59        L: 'static + Lens<Input = S_, Output = S>,
60    {
61        self.0.lens_state(lens).boxed()
62    }
63
64    /// Convenience method to change the result type to an option whose
65    /// value is `Some(<existing value>)`
66    pub fn some(self) -> CF<Option<O>, S> {
67        self.0.some().boxed()
68    }
69
70    /// Convenience method to change the result type to an option whose
71    /// value is `None`
72    pub fn none(self) -> CF<Option<O>, S> {
73        self.0.none().boxed()
74    }
75
76    /// Returns a new `CF` with identical behaviour to `self`, but which
77    /// is rendered over a passive component `background` with a given
78    /// `Tint` applied when rendered (`self` is rendered as normal)
79    pub fn overlay_tint<D: 'static + Component<State = S>, T: 'static + Tint>(
80        self,
81        background: D,
82        tint: T,
83        depth_delta: i8,
84    ) -> Self {
85        self.0.overlay_tint(background, tint, depth_delta).boxed()
86    }
87
88    /// Returns a new `CF` with identical behaviour to `self`, but which
89    /// is rendered over a passive component `background`
90    pub fn overlay<D: 'static + Component<State = S>>(
91        self,
92        background: D,
93        depth_delta: i8,
94    ) -> Self {
95        self.0.overlay(background, depth_delta).boxed()
96    }
97
98    /// Returns a new `CF` with identical behaviour to `self` but the
99    /// frame is cleared before rendering. Useful as the outer-most layer
100    /// of an application
101    pub fn clear_each_frame(self) -> Self {
102        self.0.clear_each_frame().boxed()
103    }
104
105    /// Returns a new `CF` with identical behaviour to `self` but whose
106    /// background has been filled in with a given colour
107    pub fn fill(self, background: Rgba32) -> Self {
108        self.0.fill(background).boxed()
109    }
110
111    /// Returns a new `CF` with identical behaviour to `self` but with
112    /// a border of specified style
113    pub fn border(self, style: BorderStyle) -> Self {
114        self.0.border(style).boxed()
115    }
116
117    /// Returns a new `CF` with identical behaviour to `self` but
118    /// padded to a given size
119    pub fn pad_to(self, size: UCoord) -> Self {
120        self.0.pad_to(size).boxed()
121    }
122
123    /// Returns a new `CF` with identical behaviour to `self` but
124    /// padded by a given size
125    pub fn pad_by(self, padding: Padding) -> Self {
126        self.0.pad_by(padding).boxed()
127    }
128
129    /// Returns a new `CF` with identical behaviour to `self` but
130    /// with a specified alignment
131    pub fn align(self, alignment: Alignment) -> Self {
132        self.0.align(alignment).boxed()
133    }
134
135    /// Returns a new `CF` with identical behaviour to `self` but
136    /// centered within its parent component
137    pub fn centre(self) -> Self {
138        self.0.centre().boxed()
139    }
140
141    /// Returns a new `CF` with identical behaviour to `self` but
142    /// with a specified offset applied when rendsering
143    pub fn add_offset(self, offset: ICoord) -> Self {
144        self.0.add_offset(offset).boxed()
145    }
146
147    /// Returns a new `CF` with identical behaviour to `self` but
148    /// with a specified horizontal offset
149    pub fn add_x(self, x: i32) -> Self {
150        self.0.add_x(x).boxed()
151    }
152
153    /// Returns a new `CF` with identical behaviour to `self` but
154    /// with a specified vertical offset
155    pub fn add_y(self, y: i32) -> Self {
156        self.0.add_y(y).boxed()
157    }
158
159    /// Returns a new `CF` with identical behaviour to `self` but
160    /// whose size has been overridden to a specific value
161    pub fn set_size(self, size: UCoord) -> Self {
162        self.0.set_size(size).boxed()
163    }
164
165    /// Returns a new `CF` with identical behaviour to `self` but
166    /// whose width has been overridden to a specific value
167    pub fn set_width(self, width: u32) -> Self {
168        self.0.set_width(width).boxed()
169    }
170
171    /// Returns a new `CF` with identical behaviour to `self` but
172    /// whose height has been overridden to a specific value
173    pub fn set_height(self, height: u32) -> Self {
174        self.0.set_height(height).boxed()
175    }
176
177    /// Returns a new `CF` with identical behaviour to `self` but
178    /// whose size is bounded by some minimum size
179    pub fn bound_size(self, size: UCoord) -> Self {
180        self.0.bound_size(size).boxed()
181    }
182
183    /// Returns a new `CF` with identical behaviour to `self` but
184    /// whose width is bounded by some minimum width
185    pub fn bound_width(self, width: u32) -> Self {
186        self.0.bound_width(width).boxed()
187    }
188
189    /// Returns a new `CF` with identical behaviour to `self` but
190    /// whose height is bounded by some minimum height
191    pub fn bound_height(self, height: u32) -> Self {
192        self.0.bound_height(height).boxed()
193    }
194
195    /// Returns a new `CF` with identical behaviour to `self` but
196    /// with an additional component rendered on top with a specified
197    /// padding. Useful for adding title text to components
198    pub fn with_title_vertical<T: 'static + Component<State = S>>(
199        self,
200        title: T,
201        padding: i32,
202    ) -> Self {
203        self.0.with_title_vertical(title, padding).boxed()
204    }
205
206    /// Returns a new `CF` with identical behaviour to `self` but
207    /// with an additional component rendered to the left with a specified
208    /// padding. Useful for adding labels to fields.
209    pub fn with_title_horizontal<T: 'static + Component<State = S>>(
210        self,
211        title: T,
212        padding: i32,
213    ) -> Self {
214        self.0.with_title_horizontal(title, padding).boxed()
215    }
216}
217
218impl<O: 'static, S: 'static> CF<O, S> {
219    /// Internalizes the expected `State` of a `CF` to a given value, and
220    /// produces a new `CF` expecting no external state (ie. it expects `()`
221    /// as its external state). The specified value will be presented as the
222    /// `State` to the callee.
223    pub fn with_state(self, state: S) -> CF<O, ()> {
224        self.0.with_state(state).boxed()
225    }
226}
227
228impl<S: 'static> CF<(), S> {
229    /// Takes a `CF` which yields no value, and creates a new `CF` which renders the same,
230    /// but which yields `None` until a specified `Duration` has passed, at which point it
231    /// yields `Some(())`
232    pub fn delay(self, duration: Duration) -> CF<Option<()>, S> {
233        self.0.delay(duration).boxed()
234    }
235
236    /// Takes a `CF` which yields no value, and creates a new `CF` which renders the same,
237    /// but which yields `None` until a key is pressed, at which point it yields `Some(())`
238    pub fn press_any_key(self) -> CF<Option<()>, S> {
239        self.0.press_any_key().boxed()
240    }
241}
242
243impl<T: 'static, S: 'static> CF<Option<T>, S> {
244    /// Creates a `CF` which behaves the same as `self` until `self` completes, at which point a
245    /// given function is invoked on `self` and the result of `self` completing. An example of when
246    /// this is necessary is a menu from which a single selection can be made, but which preserves
247    /// the most-recently highlighted entry the next time it is opened. One could store the state
248    /// representing the currently-highlighted entry in the menu component itself, and have the
249    /// menu yield the selection when the component completes. Since `f` is invoked on the
250    /// component as well as its result, it's free to leak the component through its return value
251    /// so the menu can be re-invoked with its internal state preserved. This is only valid for
252    /// components which may complete multiple times, of which `chargrid_common::menu::MenuCF` is
253    /// an example.
254    pub fn and_then_persistent<U, D, F>(self, f: F) -> CF<Option<U>, S>
255    where
256        D: 'static + Component<Output = Option<U>, State = S>,
257        F: 'static + FnOnce(Self, T) -> D,
258    {
259        self.0.and_then_persistent(|a, b| f(a.into(), b)).boxed()
260    }
261
262    /// Invoke a function `f` on the result of `self` when it completes. The given function returns
263    /// a new component which replaces `self`. Use to sequence multiple components one after the
264    /// other.
265    pub fn and_then<U, D, F>(self, f: F) -> CF<Option<U>, S>
266    where
267        D: 'static + Component<Output = Option<U>, State = S>,
268        F: 'static + FnOnce(T) -> D,
269    {
270        self.0.and_then(f).boxed()
271    }
272
273    /// Invoke a function `f` on the result of `self` when it completes. The given function returns
274    /// a new component which replaces `self`. Use to sequence multiple components one after the
275    /// other. Unlike with `and_then`, the given function is also passed a mutable reference to the
276    /// state.
277    pub fn and_then_side_effect<U, D, F>(self, f: F) -> CF<Option<U>, S>
278    where
279        D: 'static + Component<Output = Option<U>, State = S>,
280        F: 'static + FnOnce(T, &mut S) -> D,
281    {
282        self.0.and_then_side_effect(f).boxed()
283    }
284
285    /// Invoke a function `f` after `self` completes, ignoring the result. The given function
286    /// returns a new component which replaces `self`.
287    pub fn then<U, D, F>(self, f: F) -> CF<Option<U>, S>
288    where
289        D: 'static + Component<Output = Option<U>, State = S>,
290        F: 'static + FnOnce() -> D,
291    {
292        self.0.then(f).boxed()
293    }
294
295    /// Invoke a function `f` after `self` completes, ignoring the result. The given function
296    /// returns a new component which replaces `self`. Unlike with `then`, the given function is
297    /// also passed a mutable reference to the state.
298    pub fn then_side_effect<U, D, F>(self, f: F) -> CF<Option<U>, S>
299    where
300        D: 'static + Component<Output = Option<U>, State = S>,
301        F: 'static + FnOnce(&mut S) -> D,
302    {
303        self.0.then_side_effect(f).boxed()
304    }
305
306    /// Invoke a function `f` on a mutable reference to the external state, after `self` completes.
307    /// The behaviour of `self` is otherwise unchanged.
308    pub fn side_effect<F>(self, f: F) -> CF<Option<T>, S>
309    where
310        F: 'static + FnOnce(&mut S),
311    {
312        self.0.side_effect(f).boxed()
313    }
314
315    /// Creates a new `CF` which invokes a given function `f` on the result of `self`, yielding the
316    /// result
317    pub fn map<U, F>(self, f: F) -> CF<Option<U>, S>
318    where
319        F: 'static + FnOnce(T) -> U,
320    {
321        self.0.map(f).boxed()
322    }
323
324    /// Creates a new `CF` which invokes a given function `f` after `self` completes (ignoring ites
325    /// result), yielding the result of `f`
326    pub fn map_val<U, F>(self, f: F) -> CF<Option<U>, S>
327    where
328        F: 'static + FnOnce() -> U,
329    {
330        self.0.map_val(f).boxed()
331    }
332
333    /// Creates a new `CF` which invokes a given function `f` on the result of `self`, yielding the
334    /// result. Unlike with `map`, the given function is also passed a mutable reference to the
335    /// external state.
336    pub fn map_side_effect<U, F>(self, f: F) -> CF<Option<U>, S>
337    where
338        F: 'static + FnOnce(T, &mut S) -> U,
339    {
340        self.0.map_side_effect(f).boxed()
341    }
342
343    /// Creates a new `CF` which may be interrupted by the user pressing the escape key
344    pub fn catch_escape(self) -> CF<Option<OrEscape<T>>, S> {
345        self.0.catch_escape().boxed()
346    }
347
348    /// Creates a new `CF` which may be interrupted by the user pressing the escape key or the
349    /// start button on a gamepad
350    pub fn catch_escape_or_start(self) -> CF<Option<OrEscapeOrStart<T>>, S> {
351        self.0.catch_escape_or_start().boxed()
352    }
353
354    /// Creates a new `CF` which may be interrupted by the user clicking outside the component
355    pub fn catch_click_out(self) -> CF<Option<OrClickOut<T>>, S> {
356        self.0.catch_click_out().boxed()
357    }
358
359    /// Creates a new `CF` which may be interrupted by the user clicking outside the component or
360    /// pressing escape
361    pub fn catch_escape_or_click_out(self) -> CF<Option<OrEscapeOrClickOut<T>>, S> {
362        self.0.catch_escape_or_click_out().boxed()
363    }
364
365    /// Applies a common policy for interracting with menus. Intercepts the escape and "east"
366    /// gamepad button (the right-most symbol button on most gamepads) and yields
367    /// `Some(Err(Close))` in response, and intercepts the "start" gamepad button and injects a
368    /// "return" keypress in its place.
369    pub fn menu_harness(self) -> CF<Option<OrClose<T>>, S> {
370        self.0.menu_harness().boxed()
371    }
372
373    /// Prevents `Event::Peek` events from propagating to `self`
374    pub fn no_peek(self) -> CF<Option<T>, S> {
375        self.0.no_peek().boxed()
376    }
377
378    /// Creates a new `CF` with the same behaviour as `self` but whose yielded result is replaced
379    /// with a given result
380    pub fn replace<U: 'static>(self, value: U) -> CF<Option<U>, S> {
381        self.0.replace(value).boxed()
382    }
383
384    /// Convenience combinator for use in a loop context (e.g. in the argument to `repeat`).
385    /// Creates a new `CF` which behaves the same as `self` but whose result is wrapped in
386    /// `LoopControl::Continue`
387    pub fn continue_<Br: 'static>(self) -> CF<Option<LoopControl<T, Br>>, S> {
388        self.0.continue_().boxed()
389    }
390
391    /// Convenience combinator for use in a loop context (e.g. in the argument to `repeat`).
392    /// Creates a new `CF` which behaves the same as `self` but whose result is wrapped in
393    /// `LoopControl::Break`
394    pub fn break_<Co: 'static>(self) -> CF<Option<LoopControl<Co, T>>, S> {
395        self.0.break_().boxed()
396    }
397
398    /// Convenience combinator for use in a loop context (e.g. in the argument to `repeat`).
399    /// Creates a new `CF` which behaves the same as `self` but whose result is replaced by
400    /// `LoopControl::Continue(value)`
401    pub fn continue_with<Br: 'static, U: 'static>(
402        self,
403        value: U,
404    ) -> CF<Option<LoopControl<U, Br>>, S> {
405        self.0.continue_with(value).boxed()
406    }
407
408    /// Convenience combinator for use in a loop context (e.g. in the argument to `repeat`).
409    /// Creates a new `CF` which behaves the same as `self` but whose result is replaced by
410    /// `LoopControl::Break(value)`
411    pub fn break_with<Co: 'static, U: 'static>(
412        self,
413        value: U,
414    ) -> CF<Option<LoopControl<Co, U>>, S> {
415        self.0.break_with(value).boxed()
416    }
417
418    /// For components which may complete multiple times (e.g. menus) this combinator repeatedly
419    /// invokes the component, and calls the provided function `f` on some accumulator value, and
420    /// the result of the component. The provided function returns a `LoopControl` which determines
421    /// whether to continue repeating.
422    pub fn repeat<A, O, F>(self, init: A, f: F) -> CF<Option<O>, S>
423    where
424        A: 'static,
425        O: 'static,
426        F: 'static + FnMut(A, T) -> CF<Option<LoopControl<A, O>>, S>,
427    {
428        loop_((self, f, init), |(self_, mut f, acc)| {
429            self_.and_then_persistent(|self_, entry| {
430                f(acc, entry).map(|loop_control| loop_control.map_continue(|c| (self_, f, c)))
431            })
432        })
433    }
434
435    /// For components which may complete multiple times (e.g. menus) this combinator repeatedly
436    /// invokes the component, and calls the provided function `f` on the result of the component.
437    /// The provided function returns a `LoopControl` which determines whether to continue
438    /// repeating.
439    pub fn repeat_unit<O, F>(self, mut f: F) -> CF<Option<O>, S>
440    where
441        O: 'static,
442        F: 'static + FnMut(T) -> CF<Option<LoopControl<(), O>>, S>,
443    {
444        self.repeat((), move |(), entry| f(entry))
445    }
446
447    /// Prevent a component from receiving any events.
448    pub fn pause(self) -> CF<Option<T>, S> {
449        self.0.pause().boxed()
450    }
451
452    /// Call a given function on each tick of the component.
453    pub fn on_each_tick<F: FnMut() + 'static>(self, f: F) -> Self {
454        self.0.on_each_tick(f).boxed()
455    }
456
457    /// Call a given function on the state on each tick of the component.
458    pub fn on_each_tick_with_state<F: FnMut(&mut S) + 'static>(self, f: F) -> Self {
459        self.0.on_each_tick_with_state(f).boxed()
460    }
461
462    /// Call a function on the state when the window is closed.
463    pub fn on_exit_with_state<F: FnMut(&mut S) + 'static>(self, f: F) -> Self {
464        self.0.on_exit_with_state(f).boxed()
465    }
466}
467
468impl<O: 'static> CF<O, ()> {
469    /// For components that don't depend on external state, this combinator creates a new `CF` that
470    /// accepts any state.
471    pub fn ignore_state<S: 'static>(self) -> CF<O, S> {
472        self.0.ignore_state().boxed()
473    }
474}
475
476impl<S: 'static> CF<(), S> {
477    /// For components that yield `()`, creates a new `CF` that claims to yield `Option<T>` for any
478    /// `T`, but which always yields `None`.
479    pub fn ignore_output<O: 'static>(self) -> CF<Option<O>, S> {
480        self.0.ignore_output().boxed()
481    }
482}
483
484impl<S: 'static> CF<app::Output, S> {
485    /// Yields `Some(app::Exit)` when a window closed event is received. This typically annotates
486    /// the outside of an application so that application doesn't need to deal with window close
487    /// events.
488    pub fn exit_on_close(self) -> Self {
489        self.0.exit_on_close().boxed()
490    }
491}
492
493/// Convenience type alias for most applications. There is no external state, and the yielded
494/// result is an app control flow signal (typically whether the application wishes to exit).
495pub type App = CF<app::Output, ()>;
496
497/// Creates a `CF` which always yields clones of a given value
498pub fn val<S: 'static, T: 'static + Clone>(t: T) -> CF<Option<T>, S> {
499    unboxed::val(t).boxed()
500}
501
502/// Creates a `CF` which yields a given value once. Should not be ticked multiple times
503pub fn val_once<S: 'static, T: 'static>(t: T) -> CF<Option<T>, S> {
504    unboxed::val_once(t).boxed()
505}
506
507/// Creates a `CF` which yields a given value once, wrapped in `LoopControl::Break`. Should not be
508/// ticked multiple times
509pub fn break_<S: 'static, T: 'static, Co: 'static>(t: T) -> CF<Option<LoopControl<Co, T>>, S> {
510    val_once(t).break_()
511}
512
513/// Creates a `CF` which yields a given value once, wrapped in `LoopControl::Continue`. Should not
514/// be ticked multiple times
515pub fn continue_<S: 'static, T: 'static, Br: 'static>(t: T) -> CF<Option<LoopControl<T, Br>>, S> {
516    val_once(t).continue_()
517}
518
519/// Creates a new `CF` which never completes
520pub fn never<S: 'static, T: 'static>() -> CF<Option<T>, S> {
521    unboxed::never().boxed()
522}
523
524/// Repeatedly invoke the component-producing function `f` on the result of the component produced
525/// by `f`'s its previous invocation. The external state of the components produced by `f` is
526/// passed in as the `state` argument, and the component returned by `loop_state` expects no
527/// external state.
528pub fn loop_state<S, Co, Br, C, F>(state: S, init: Co, f: F) -> CF<Option<Br>, ()>
529where
530    S: 'static,
531    C::State: Sized,
532    C: 'static + Component<Output = Option<LoopControl<Co, Br>>, State = S>,
533    F: 'static + FnMut(Co) -> C,
534{
535    unboxed::loop_state(state, init, f).boxed()
536}
537
538/// Repeatedly invoke the component-producing function `f` on the result of the component produced
539/// by `f`'s its previous invocation.
540pub fn loop_<Co, Br, C, F>(init: Co, f: F) -> CF<Option<Br>, C::State>
541where
542    C::State: Sized,
543    C: 'static + Component<Output = Option<LoopControl<Co, Br>>>,
544    F: 'static + FnMut(Co) -> C,
545{
546    unboxed::loop_(init, f).boxed()
547}
548
549/// Repeatedly invoke the component-producing function `f` until its produced component yields
550/// `LoopControl::Break`.
551pub fn loop_unit<Br, C, F>(f: F) -> CF<Option<Br>, C::State>
552where
553    C::State: Sized,
554    C: 'static + Component<Output = Option<LoopControl<(), Br>>>,
555    F: 'static + FnMut() -> C,
556{
557    unboxed::loop_unit(f).boxed()
558}
559
560/// Repeatedly invoke the component-producing function `f` until its produced component yields
561/// `LoopControl::Break`. The provided function is also passed a mutable reference to a state.
562pub fn loop_mut<Co, Br, T, C, F>(init: Co, value: T, f: F) -> CF<Option<Br>, C::State>
563where
564    T: 'static,
565    C::State: Sized,
566    C: 'static + Component<Output = Option<LoopControl<Co, Br>>>,
567    F: 'static + FnMut(Co, &mut T) -> C,
568{
569    unboxed::loop_mut(init, value, f).boxed()
570}
571
572pub fn on_state<S, T, F>(f: F) -> CF<Option<T>, S>
573where
574    S: 'static,
575    T: 'static,
576    F: 'static + FnOnce(&mut S) -> T,
577{
578    unboxed::on_state(f).boxed()
579}
580
581pub fn on_state_then<C, F>(f: F) -> CF<C::Output, C::State>
582where
583    C: 'static + Component,
584    C::State: Sized,
585    F: 'static + FnOnce(&mut C::State) -> C,
586{
587    unboxed::on_state_then(f).boxed()
588}
589
590pub fn render<F: 'static + Fn(Ctx, &mut FrameBuffer)>(f: F) -> CF<(), ()> {
591    unboxed::render(f).boxed()
592}
593
594pub fn render_state<S: 'static, F: 'static + Fn(&S, Ctx, &mut FrameBuffer)>(f: F) -> CF<(), S> {
595    unboxed::render_state(f).boxed()
596}
597
598pub fn unit<S: 'static>() -> CF<(), S> {
599    unboxed::unit().boxed()
600}
601
602pub fn many<I, S, C>(iterable: I) -> CF<(), S>
603where
604    I: 'static,
605    S: 'static,
606    C: 'static + Component<State = S>,
607    for<'a> &'a I: IntoIterator<Item = &'a C>,
608    for<'a> &'a mut I: IntoIterator<Item = &'a mut C>,
609{
610    unboxed::many(iterable).boxed()
611}
612
613pub fn styled_string<S: 'static>(string: String, style: Style) -> CF<(), S> {
614    unboxed::styled_string(string, style).boxed()
615}
616
617pub fn on_input<F, T, S>(f: F) -> CF<Option<T>, S>
618where
619    F: 'static + FnMut(input::Input) -> Option<T>,
620    S: 'static,
621{
622    unboxed::on_input(f).boxed()
623}
624
625pub fn on_input_state<F, T, S>(f: F) -> CF<Option<T>, S>
626where
627    F: 'static + FnMut(input::Input, &mut S) -> Option<T>,
628    S: 'static,
629{
630    unboxed::on_input_state(f).boxed()
631}