Rust in Everything
基于 tower 0.5.3

util:组合子

tower::util 由 util feature 打开,这一部分讲其中的「胶水」:它们自己不占资源、不限流,只负责把服务造出来、接起来、改个形状。读它们仍然问两个问题:poll_ready 动了没有(就绪主线),call 返回的 future 换成了什么类型(请求主线)。答案几乎都是「poll_ready 原样转发,future 换一个不装箱的类型」,例外正是值得看的地方。

  1. service_fn 与 map 一族:service_fn 永远就绪;map_request、map_response、map_err、map_result、then、and_then、map_future 各改哪一段,poll_ready 的错误由谁转换;它们的 future 类型都不装箱,有的直接沿用内层的类型,有的是包着 futures_util 类型的 newtype。
  2. 类型擦除:分支返回不同的中间件栈时,编译器报什么错,BoxService 怎么修;BoxService 靠 SyncWrapper 得到 Sync;UnsyncBoxService、BoxCloneService、BoxCloneSyncService 对内层的要求和自身的 Send / Sync / Clone;代价是每个请求一次堆分配;BoxLayer 一族。
  3. Either 与 FutureService:Either 不装箱地二选一,要求两边响应和错误类型相同;FutureService 先在 poll_ready 里把「造服务的 future」驱动完,再把就绪查询交给造出来的服务。
flowchart TB
  fnode["闭包"] -->|service_fn| svc[一个服务]
  svc -->|"map_* / then / and_then"| shaped[改了形状的服务]
  shaped -->|"boxed / boxed_clone"| boxed["BoxService:类型擦除"]
  shaped -->|"Either::Left / Right"| either[两种服务之一]
  fut["造服务的 future"] -->|FutureService| svc

ServiceExt 里和调用有关的 ready、oneshot、call_all 不在这里,见 ServiceExt 与 Oneshot;option_layer 怎么用 Either 见 ServiceBuilder。

💬 关联讨论

发起讨论
加载中...