use super::Balance; use crate::discover::Discover; use futures_core::ready; use pin_project_lite::pin_project; use std::hash::Hash; use std::marker::PhantomData; use std::{ fmt, future::Future, pin::Pin, task::{Context, Poll}, }; use tower_service::Service; /// Constructs load balancers over dynamic service sets produced by a wrapped "inner" service. /// /// This is effectively an implementation of [`MakeService`] except that it forwards the service /// descriptors (`Target`) to an inner service (`S`), and expects that service to produce a /// service set in the form of a [`Discover`]. It then wraps the service set in a [`Balance`] /// before returning it as the "made" service. /// /// See the [module-level documentation](crate::balance) for details on load balancing. /// /// [`MakeService`]: crate::MakeService /// [`Discover`]: crate::discover::Discover /// [`Balance`]: crate::balance::p2c::Balance pub struct MakeBalance { inner: S, _marker: PhantomData, } pin_project! { /// A [`Balance`] in the making. /// /// [`Balance`]: crate::balance::p2c::Balance pub struct MakeFuture { #[pin] inner: F, _marker: PhantomData, } } impl MakeBalance { /// Build balancers using operating system entropy. pub fn new(make_discover: S) -> Self { Self { inner: make_discover, _marker: PhantomData, } } } impl Clone for MakeBalance where S: Clone, { fn clone(&self) -> Self { Self { inner: self.inner.clone(), _marker: PhantomData, } } } impl Service for MakeBalance where S: Service, S::Response: Discover, ::Key: Hash, ::Service: Service, <::Service as Service>::Error: Into, { type Response = Balance; type Error = S::Error; type Future = MakeFuture; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.inner.poll_ready(cx) } fn call(&mut self, target: Target) -> Self::Future { MakeFuture { inner: self.inner.call(target), _marker: PhantomData, } } } impl fmt::Debug for MakeBalance where S: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let Self { inner, _marker } = self; f.debug_struct("MakeBalance").field("inner", inner).finish() } } impl Future for MakeFuture where F: Future>, T: Discover, ::Key: Hash, ::Service: Service, <::Service as Service>::Error: Into, { type Output = Result, E>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); let inner = ready!(this.inner.poll(cx))?; let svc = Balance::new(inner); Poll::Ready(Ok(svc)) } } impl fmt::Debug for MakeFuture where F: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let Self { inner, _marker } = self; f.debug_struct("MakeFuture").field("inner", inner).finish() } }