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
use crate::{
    fib::{Fiber, FiberState, RootFiber},
    thr::prelude::*,
};
use core::{
    ops::{Generator, GeneratorState},
    pin::Pin,
};

/// Fiber for [`Generator`].
///
/// Can be created with [`fib::new`](crate::fib::new).
pub struct FiberGen<G>(G)
where
    G: Generator;

impl<G> Fiber for FiberGen<G>
where
    G: Generator,
{
    type Input = ();
    type Return = G::Return;
    type Yield = G::Yield;

    #[inline]
    fn resume(self: Pin<&mut Self>, (): ()) -> FiberState<G::Yield, G::Return> {
        let gen = unsafe { self.map_unchecked_mut(|x| &mut x.0) };
        gen.resume(()).into()
    }
}

impl<G> RootFiber for FiberGen<G>
where
    G: Generator<Yield = (), Return = ()>,
    G: 'static,
{
    #[inline]
    fn advance(self: Pin<&mut Self>) -> bool {
        match self.resume(()) {
            FiberState::Yielded(()) => false,
            FiberState::Complete(()) => true,
        }
    }
}

impl<Y, R> From<GeneratorState<Y, R>> for FiberState<Y, R> {
    #[inline]
    fn from(state: GeneratorState<Y, R>) -> Self {
        match state {
            GeneratorState::Yielded(val) => FiberState::Yielded(val),
            GeneratorState::Complete(val) => FiberState::Complete(val),
        }
    }
}

/// Creates a fiber from the generator `gen`.
///
/// This type of fiber yields on each generator `yield`.
#[inline]
pub fn new<G>(gen: G) -> FiberGen<G>
where
    G: Generator,
{
    FiberGen(gen)
}

/// Extends [`ThrToken`](crate::thr::ThrToken) types with `add` and
/// `add_factory` methods.
pub trait ThrFiberGen: ThrToken {
    /// Adds a fiber for the generator `gen` to the fiber chain.
    #[inline]
    fn add<G>(self, gen: G)
    where
        G: Generator<Yield = (), Return = ()>,
        G: Send + 'static,
    {
        self.add_fib(new(gen))
    }

    /// Adds a fiber for the generator returned by `factory` to the fiber chain.
    ///
    /// This method is useful for non-`Send` fibers.
    #[inline]
    fn add_factory<C, G>(self, factory: C)
    where
        C: FnOnce() -> G + Send + 'static,
        G: Generator<Yield = (), Return = ()>,
        G: 'static,
    {
        self.add_fib_factory(|| new(factory()))
    }
}

impl<T: ThrToken> ThrFiberGen for T {}