Fix the custom derive (#689)

* Fix the custom derive

* Concern
This commit is contained in:
Pierre Krieger
2018-11-27 16:10:34 +01:00
committed by GitHub
parent 45114aef46
commit e12795d1e6
3 changed files with 40 additions and 28 deletions

View File

@ -51,16 +51,16 @@ impl<TProto1, TProto2> ProtocolsHandlerSelect<TProto1, TProto2> {
}
}
impl<TSubstream, TProto1, TProto2, TProto1Out, TProto2Out>
impl<TSubstream, TProto1, TProto2>
ProtocolsHandler for ProtocolsHandlerSelect<TProto1, TProto2>
where
TProto1: ProtocolsHandler<Substream = TSubstream>,
TProto2: ProtocolsHandler<Substream = TSubstream>,
TSubstream: AsyncRead + AsyncWrite,
TProto1::InboundProtocol: InboundUpgrade<TSubstream, Output = TProto1Out>,
TProto2::InboundProtocol: InboundUpgrade<TSubstream, Output = TProto2Out>,
TProto1::OutboundProtocol: OutboundUpgrade<TSubstream, Output = TProto1Out>,
TProto2::OutboundProtocol: OutboundUpgrade<TSubstream, Output = TProto2Out>
TProto1::InboundProtocol: InboundUpgrade<TSubstream>,
TProto2::InboundProtocol: InboundUpgrade<TSubstream>,
TProto1::OutboundProtocol: OutboundUpgrade<TSubstream>,
TProto2::OutboundProtocol: OutboundUpgrade<TSubstream>
{
type InEvent = EitherOutput<TProto1::InEvent, TProto2::InEvent>;
type OutEvent = EitherOutput<TProto1::OutEvent, TProto2::OutEvent>;

View File

@ -68,41 +68,26 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
quote!{#n}
};
let output_types = {
let mut start = 1;
// Avoid collisions.
while ast.generics.type_params().any(|tp| tp.ident.to_string() == format!("TOut{}", start)) {
start += 1;
}
data_struct.fields.iter()
.filter(|x| !is_ignored(x))
.enumerate()
.map(move |(i, _)| Ident::new(&format!("TOut{}", start + i), name.span()))
.collect::<Vec<_>>()
};
// Build the generics.
let impl_generics = {
let tp = ast.generics.type_params();
let lf = ast.generics.lifetimes();
let cst = ast.generics.const_params();
let out = output_types.clone();
quote!{<#(#lf,)* #(#tp,)* #(#cst,)* #substream_generic, #(#out),*>}
quote!{<#(#lf,)* #(#tp,)* #(#cst,)* #substream_generic>}
};
// Build the `where ...` clause of the trait implementation.
let where_clause = {
let mut additional = data_struct.fields.iter()
.filter(|x| !is_ignored(x))
.zip(output_types)
.flat_map(|(field, out)| {
.flat_map(|field| {
let ty = &field.ty;
vec![
quote!{#ty: #trait_to_impl},
quote!{<#ty as #trait_to_impl>::ProtocolsHandler: #protocols_handler<Substream = #substream_generic>},
// Note: this bound is required because of https://github.com/rust-lang/rust/issues/55697
quote!{<<#ty as #trait_to_impl>::ProtocolsHandler as #protocols_handler>::InboundProtocol: ::libp2p::core::InboundUpgrade<#substream_generic, Output = #out>},
quote!{<<#ty as #trait_to_impl>::ProtocolsHandler as #protocols_handler>::OutboundProtocol: ::libp2p::core::OutboundUpgrade<#substream_generic, Output = #out>},
quote!{<<#ty as #trait_to_impl>::ProtocolsHandler as #protocols_handler>::InboundProtocol: ::libp2p::core::InboundUpgrade<#substream_generic>},
quote!{<<#ty as #trait_to_impl>::ProtocolsHandler as #protocols_handler>::OutboundProtocol: ::libp2p::core::OutboundUpgrade<#substream_generic>},
]
})
.collect::<Vec<_>>();

View File

@ -21,6 +21,10 @@
#[macro_use]
extern crate libp2p;
/// Small utility to check that a type implements `NetworkBehaviour`.
#[allow(dead_code)]
fn require_net_behaviour<T: libp2p::core::swarm::NetworkBehaviour>() {}
// TODO: doesn't compile
/*#[test]
fn empty() {
@ -36,6 +40,10 @@ fn one_field() {
struct Foo<TSubstream> {
ping: libp2p::ping::PeriodicPingBehaviour<TSubstream>,
}
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
require_net_behaviour::<Foo<TSubstream>>();
}
}
#[test]
@ -55,29 +63,36 @@ fn three_fields() {
struct Foo<TSubstream> {
ping_dialer: libp2p::ping::PeriodicPingBehaviour<TSubstream>,
ping_listener: libp2p::ping::PingListenBehaviour<TSubstream>,
identify: libp2p::identify::PeriodicIdentification<TSubstream>,
identify: libp2p::identify::PeriodicIdentifyBehaviour<TSubstream>,
#[behaviour(ignore)]
foo: String,
}
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
require_net_behaviour::<Foo<TSubstream>>();
}
}
#[test]
fn event_handler() {
#[allow(dead_code)]
#[derive(NetworkBehaviour)]
// TODO: remove the generics requirements once identify no longer requires them
struct Foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite + Send + Sync + 'static> {
struct Foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite> {
#[behaviour(handler = "foo")]
identify: libp2p::identify::PeriodicIdentifyBehaviour<TSubstream>,
}
impl<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite + Send + Sync + 'static> Foo<TSubstream> {
impl<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite> Foo<TSubstream> {
// TODO: for some reason, the parameter cannot be `PeriodicIdentifyBehaviourEvent` or we
// get a compilation error ; figure out why or open an issue to Rust
fn foo(&mut self, ev: <libp2p::identify::PeriodicIdentifyBehaviour<TSubstream> as libp2p::core::swarm::NetworkBehaviour>::OutEvent) {
let libp2p::identify::PeriodicIdentifyBehaviourEvent::Identified { .. } = ev;
}
}
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
require_net_behaviour::<Foo<TSubstream>>();
}
}
#[test]
@ -93,6 +108,10 @@ fn custom_polling() {
impl<TSubstream> Foo<TSubstream> {
fn foo<T>(&mut self) -> libp2p::futures::Async<libp2p::core::swarm::NetworkBehaviourAction<T, ()>> { libp2p::futures::Async::NotReady }
}
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
require_net_behaviour::<Foo<TSubstream>>();
}
}
#[test]
@ -104,6 +123,10 @@ fn custom_event_no_polling() {
ping: libp2p::ping::PeriodicPingBehaviour<TSubstream>,
identify: libp2p::identify::PeriodicIdentifyBehaviour<TSubstream>,
}
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
require_net_behaviour::<Foo<TSubstream>>();
}
}
#[test]
@ -119,4 +142,8 @@ fn custom_event_and_polling() {
impl<TSubstream> Foo<TSubstream> {
fn foo<T>(&mut self) -> libp2p::futures::Async<libp2p::core::swarm::NetworkBehaviourAction<T, String>> { libp2p::futures::Async::NotReady }
}
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
require_net_behaviour::<Foo<TSubstream>>();
}
}