大佬们,我看了网上很多关于PhantomData的使用都是因为unsafe rust,但我不理解tower这个项目为什么这里必须要PhantomData,我把phantomData去掉编译器也不会报错。
use std::{
collections::VecDeque,
fmt,
marker::PhantomData,
task::{Context, Poll},
};
use tower_service::Service;
pub trait Picker<S, Req> {
fn pick(&mut self, r: &Req, services: &[S]) -> usize;
}
impl<S, F, Req> Picker<S, Req> for F
where
F: Fn(&Req, &[S]) -> usize,
{
fn pick(&mut self, r: &Req, services: &[S]) -> usize {
self(r, services)
}
}
pub struct Steer<S, F, Req> {
router: F,
services: Vec<S>,
not_ready: VecDeque<usize>,
_phantom: PhantomData<Req>,
}
impl<S, F, Req> Steer<S, F, Req> {
pub fn new(services: impl IntoIterator<Item = S>, router: F) -> Self {
let services: Vec<_> = services.into_iter().collect();
let not_ready: VecDeque<_> = services.iter().enumerate().map(|(i, _)| i).collect();
Self {
router,
services,
not_ready,
_phantom: PhantomData,
}
}
}
impl<S, Req, F> Service<Req> for Steer<S, F, Req>
where
S: Service<Req>,
F: Picker<S, Req>,
{
type Response = S::Response;
type Error = S::Error;
type Future = S::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
loop {
if self.not_ready.is_empty() {
return Poll::Ready(Ok(()));
} else {
if self.services[self.not_ready[0]]
.poll_ready(cx)?
.is_pending()
{
return Poll::Pending;
}
self.not_ready.pop_front();
}
}
}
fn call(&mut self, req: Req) -> Self::Future {
assert!(
self.not_ready.is_empty(),
"Steer must wait for all services to be ready. Did you forget to call poll_ready()?"
);
let idx = self.router.pick(&req, &self.services[..]);
let cl = &mut self.services[idx];
self.not_ready.push_back(idx);
cl.call(req)
}
}
impl<S, F, Req> Clone for Steer<S, F, Req>
where
S: Clone,
F: Clone,
{
fn clone(&self) -> Self {
Self {
router: self.router.clone(),
services: self.services.clone(),
not_ready: self.not_ready.clone(),
_phantom: PhantomData,
}
}
}
impl<S, F, Req> fmt::Debug for Steer<S, F, Req>
where
S: fmt::Debug,
F: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Self {
router,
services,
not_ready,
_phantom,
} = self;
f.debug_struct("Steer")
.field("router", router)
.field("services", services)
.field("not_ready", not_ready)
.finish()
}
}
1
共 11 条评论, 1 页
评论区
写评论和OwnerShip有关 参考 https://doc.rust-lang.org/nomicon/phantom-data.html https://learnku.com/docs/nomicon/2018/310-phantom-data/4721
wow 非常感谢
--
👇
fakeshadow: 这个我还真不是很清楚,看上去像是要让Req类型不妨碍auto trait的生成。例如
--
👇
Kotodian: ``` use std::{hash::Hash, future::Future, marker::PhantomData, pin::Pin, task::{Context, Poll}};
use pin_project_lite::pin_project;
use crate::discover::Discover; use tower_service::Service; use futures_core::ready;
use super::service::Balance;
pub struct MakeBalance<S, Req> { inner: S, _marker: PhantomData<fn(Req)>, }
impl<S, Req> MakeBalance<S, Req> { pub fn new(make_discover: S) -> Self { Self { inner: make_discover, _marker: PhantomData, } } }
impl<S, Target, Req> Service for MakeBalance<S, Req> where S: Service, S::Response: Discover, <S::Response as Discover>::Key: Hash, <S::Response as Discover>::Service: Service, <<S::Response as Discover>::Service as Service>::Error: Intocrate::BoxError, { type Response = Balance<S::Response, Req>; type Error = S::Error; type Future = MakeFuture<S::Future, Req>;
}
impl<S, Req> Clone for MakeBalance<S, Req> where S: Clone, { fn clone(&self) -> Self { Self { inner: self.inner.clone(), _marker: PhantomData, } } }
impl<S, Req> std::fmt::Debug for MakeBalance<S, Req> where S: std::fmt::Debug, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let Self { inner, _marker } = self; f.debug_struct("MakeBalance").field("inner", inner).finish() } }
pin_project! { pub struct MakeFuture<F, Req> { #[pin] inner: F, _marker: PhantomData<fn(Req)>, } }
impl<F, T, E, Req> Future for MakeFuture<F, Req> where F: Future<Output = Result<T, E>>, T: Discover, ::Key: Hash, <::Service as Service>::Error: Intocrate::BoxError, ::Service: Service, { type Output = Result<Balance<T, Req>, E>;
}
// 现在 trait Service {}
// 以前 trait Service { type Request; }
这个我还真不是很清楚,看上去像是要让Req类型不妨碍auto trait的生成。例如
--
👇
Kotodian: ``` use std::{hash::Hash, future::Future, marker::PhantomData, pin::Pin, task::{Context, Poll}};
use pin_project_lite::pin_project;
use crate::discover::Discover; use tower_service::Service; use futures_core::ready;
use super::service::Balance;
pub struct MakeBalance<S, Req> { inner: S, _marker: PhantomData<fn(Req)>, }
impl<S, Req> MakeBalance<S, Req> { pub fn new(make_discover: S) -> Self { Self { inner: make_discover, _marker: PhantomData, } } }
impl<S, Target, Req> Service for MakeBalance<S, Req> where S: Service, S::Response: Discover, <S::Response as Discover>::Key: Hash, <S::Response as Discover>::Service: Service, <<S::Response as Discover>::Service as Service>::Error: Intocrate::BoxError, { type Response = Balance<S::Response, Req>; type Error = S::Error; type Future = MakeFuture<S::Future, Req>;
}
impl<S, Req> Clone for MakeBalance<S, Req> where S: Clone, { fn clone(&self) -> Self { Self { inner: self.inner.clone(), _marker: PhantomData, } } }
impl<S, Req> std::fmt::Debug for MakeBalance<S, Req> where S: std::fmt::Debug, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let Self { inner, _marker } = self; f.debug_struct("MakeBalance").field("inner", inner).finish() } }
pin_project! { pub struct MakeFuture<F, Req> { #[pin] inner: F, _marker: PhantomData<fn(Req)>, } }
impl<F, T, E, Req> Future for MakeFuture<F, Req> where F: Future<Output = Result<T, E>>, T: Discover, ::Key: Hash, <::Service as Service>::Error: Intocrate::BoxError, ::Service: Service, { type Output = Result<Balance<T, Req>, E>;
}
// 现在 trait Service {}
// 以前 trait Service { type Request; }
那能问下这里为什么是用fn(Req)吗
--
👇
fakeshadow: 是Service trait的设计区别
以前的版本Service用关联类型来表示Request,导致泛型Req无法绑定到trait上,所以只能用phantomdata绑到impl的类型上
--
👇
Kotodian: 我先看下,就是想知道这是老的rust的问题吗
--
👇
fakeshadow: 看起来是refactor遗物.https://github.com/tower-rs/tower/pull/109
原来如此,谢谢
--
👇
fakeshadow: 是Service trait的设计区别
以前的版本Service用关联类型来表示Request,导致泛型Req无法绑定到trait上,所以只能用phantomdata绑到impl的类型上
--
👇
Kotodian: 我先看下,就是想知道这是老的rust的问题吗
--
👇
fakeshadow: 看起来是refactor遗物.https://github.com/tower-rs/tower/pull/109
是Service trait的设计区别
以前的版本Service用关联类型来表示Request,导致泛型Req无法绑定到trait上,所以只能用phantomdata绑到impl的类型上
--
👇
Kotodian: 我先看下,就是想知道这是老的rust的问题吗
--
👇
fakeshadow: 看起来是refactor遗物.https://github.com/tower-rs/tower/pull/109
https://doc.rust-lang.org/nomicon/phantom-data.html#generic-parameters-and-drop-checking
我先看下,就是想知道这是老的rust的问题吗
--
👇
fakeshadow: 看起来是refactor遗物.https://github.com/tower-rs/tower/pull/109
我的意思是全去掉
--
👇
Cupnfish: 没有啊,我去掉了之后:
看起来是refactor遗物.https://github.com/tower-rs/tower/pull/109
没有啊,我去掉了之后: