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
use crate::{Change, Discover};
use futures_core::{ready, TryStream};
use pin_project::pin_project;
use std::hash::Hash;
use std::{
    pin::Pin,
    task::{Context, Poll},
};
use tower_service::Service;

/// Dynamic service discovery based on a stream of service changes.
#[pin_project]
#[derive(Debug)]
pub struct ServiceStream<S> {
    #[pin]
    inner: S,
}

impl<S> ServiceStream<S> {
    #[allow(missing_docs)]
    pub fn new<K, Svc, Request>(services: S) -> Self
    where
        S: TryStream<Ok = Change<K, Svc>>,
        K: Hash + Eq,
        Svc: Service<Request>,
    {
        ServiceStream { inner: services }
    }
}

impl<S, K, Svc> Discover for ServiceStream<S>
where
    K: Hash + Eq,
    S: TryStream<Ok = Change<K, Svc>>,
{
    type Key = K;
    type Service = Svc;
    type Error = S::Error;

    fn poll_discover(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<Change<Self::Key, Self::Service>, Self::Error>> {
        match ready!(self.project().inner.try_poll_next(cx)).transpose()? {
            Some(c) => Poll::Ready(Ok(c)),
            None => {
                // there are no more service changes coming
                Poll::Pending
            }
        }
    }
}