use super::super::error; use super::Balance; use crate::discover::Discover; use futures_core::ready; use pin_project::pin_project; use rand::{rngs::SmallRng, SeedableRng}; use std::marker::PhantomData; use std::{ future::Future, pin::Pin, task::{Context, Poll}, }; use tower_service::Service; /// Makes `Balancer`s given an inner service that makes `Discover`s. #[derive(Clone, Debug)] pub struct BalanceMake { inner: S, rng: SmallRng, _marker: PhantomData, } /// Makes a balancer instance. #[pin_project] #[derive(Debug)] pub struct MakeFuture { #[pin] inner: F, rng: SmallRng, _marker: PhantomData, } impl BalanceMake { pub(crate) fn new(inner: S, rng: SmallRng) -> Self { Self { inner, rng, _marker: PhantomData, } } /// Initializes a P2C load balancer from the OS's entropy source. pub fn from_entropy(make_discover: S) -> Self { Self::new(make_discover, SmallRng::from_entropy()) } } impl Service for BalanceMake where S: Service, S::Response: Discover, ::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), rng: self.rng.clone(), _marker: PhantomData, } } } impl Future for MakeFuture where F: Future>, T: Discover, ::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, this.rng.clone()); Poll::Ready(Ok(svc)) } }