discover: polish crate (#194)

This commit is contained in:
Carl Lerche 2019-03-14 13:11:53 -07:00 committed by GitHub
parent acda5a75b9
commit f8d88427aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 117 additions and 113 deletions

View File

@ -0,0 +1,13 @@
use std::error::Error;
use std::fmt;
#[derive(Debug)]
pub enum Never {}
impl fmt::Display for Never {
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
match *self {}
}
}
impl Error for Never {}

View File

@ -9,13 +9,15 @@
extern crate futures;
extern crate tower_service;
use futures::{Async, Poll, Stream};
use tower_service::Service;
mod error;
mod list;
mod stream;
use std::fmt;
pub use crate::list::ServiceList;
pub use crate::stream::ServiceStream;
use futures::Poll;
use std::hash::Hash;
use std::iter::{Enumerate, IntoIterator};
use std::marker::PhantomData;
/// Provide a uniform set of services able to satisfy a request.
///
@ -41,111 +43,3 @@ pub enum Change<K, V> {
Insert(K, V),
Remove(K),
}
/// Static service discovery based on a predetermined list of services.
///
/// `List` is created with an initial list of services. The discovery process
/// will yield this list once and do nothing after.
pub struct List<T>
where
T: IntoIterator,
{
inner: Enumerate<T::IntoIter>,
}
// ===== impl List =====
impl<T, U> List<T>
where
T: IntoIterator<Item = U>,
{
pub fn new<Request>(services: T) -> List<T>
where
U: Service<Request>,
{
List {
inner: services.into_iter().enumerate(),
}
}
}
impl<T, U> Discover for List<T>
where
T: IntoIterator<Item = U>,
{
type Key = usize;
type Service = U;
type Error = Never;
fn poll(&mut self) -> Poll<Change<Self::Key, Self::Service>, Self::Error> {
match self.inner.next() {
Some((i, service)) => Ok(Change::Insert(i, service).into()),
None => Ok(Async::NotReady),
}
}
}
/// Dynamic service discovery based on a stream of service changes.
pub struct Services<S, K, Svc> {
inner: futures::stream::Fuse<S>,
_marker_k: PhantomData<K>,
_marker_v: PhantomData<Svc>,
}
// ===== impl Services =====
impl<S, K, Svc> Services<S, K, Svc>
where
S: Stream<Item = Change<K, Svc>>,
{
pub fn new<Request>(services: S) -> Self
where
Svc: Service<Request>,
{
Services {
inner: services.fuse(),
_marker_k: PhantomData,
_marker_v: PhantomData,
}
}
}
impl<S, K, Svc> Discover for Services<S, K, Svc>
where
K: Hash + Eq,
S: Stream<Item = Change<K, Svc>>,
{
type Key = K;
type Service = Svc;
type Error = S::Error;
fn poll(&mut self) -> Poll<Change<Self::Key, Self::Service>, Self::Error> {
match try_ready!(self.inner.poll()) {
Some(c) => Ok(Async::Ready(c)),
None => {
// there are no more service changes coming
Ok(Async::NotReady)
}
}
}
}
#[doc(hidden)]
#[derive(Debug)]
pub enum Never {}
impl fmt::Display for Never {
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
match *self {}
}
}
impl std::error::Error for Never {}
// check that List can be directly over collections
#[cfg(test)]
#[allow(dead_code)]
type ListVecTest<T> = List<Vec<T>>;
#[cfg(test)]
#[allow(dead_code)]
type ListVecIterTest<T> = List<::std::vec::IntoIter<T>>;

View File

@ -0,0 +1,55 @@
use crate::error::Never;
use crate::{Change, Discover};
use futures::{Async, Poll};
use std::iter::{Enumerate, IntoIterator};
use tower_service::Service;
/// Static service discovery based on a predetermined list of services.
///
/// `ServiceList` is created with an initial list of services. The discovery
/// process will yield this list once and do nothing after.
pub struct ServiceList<T>
where
T: IntoIterator,
{
inner: Enumerate<T::IntoIter>,
}
impl<T, U> ServiceList<T>
where
T: IntoIterator<Item = U>,
{
pub fn new<Request>(services: T) -> ServiceList<T>
where
U: Service<Request>,
{
ServiceList {
inner: services.into_iter().enumerate(),
}
}
}
impl<T, U> Discover for ServiceList<T>
where
T: IntoIterator<Item = U>,
{
type Key = usize;
type Service = U;
type Error = Never;
fn poll(&mut self) -> Poll<Change<Self::Key, Self::Service>, Self::Error> {
match self.inner.next() {
Some((i, service)) => Ok(Change::Insert(i, service).into()),
None => Ok(Async::NotReady),
}
}
}
// check that List can be directly over collections
#[cfg(test)]
#[allow(dead_code)]
type ListVecTest<T> = ServiceList<Vec<T>>;
#[cfg(test)]
#[allow(dead_code)]
type ListVecIterTest<T> = ServiceList<::std::vec::IntoIter<T>>;

View File

@ -0,0 +1,42 @@
use crate::{Change, Discover};
use futures::{Async, Poll, Stream};
use std::hash::Hash;
use tower_service::Service;
/// Dynamic service discovery based on a stream of service changes.
pub struct ServiceStream<S> {
inner: futures::stream::Fuse<S>,
}
impl<S> ServiceStream<S> {
pub fn new<K, Svc, Request>(services: S) -> Self
where
S: Stream<Item = Change<K, Svc>>,
K: Hash + Eq,
Svc: Service<Request>,
{
ServiceStream {
inner: services.fuse(),
}
}
}
impl<S, K, Svc> Discover for ServiceStream<S>
where
K: Hash + Eq,
S: Stream<Item = Change<K, Svc>>,
{
type Key = K;
type Service = Svc;
type Error = S::Error;
fn poll(&mut self) -> Poll<Change<Self::Key, Self::Service>, Self::Error> {
match try_ready!(self.inner.poll()) {
Some(c) => Ok(Async::Ready(c)),
None => {
// there are no more service changes coming
Ok(Async::NotReady)
}
}
}
}