0

I'm attempting to write a streaming, pipelined server with a non-default tick() method in the transport. I thought this would do it:

use std::io;

use mio::net::TcpListener;
use tokio_core::reactor::PollEvented;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::{Framed, Encoder, Decoder};
use tokio_proto::streaming::pipeline::Transport;

use codec::PacketCodec;

type GearmanIO = PollEvented<TcpListener>;
type GearmanFramed = Framed<GearmanIO, PacketCodec>;

impl Transport for GearmanFramed {
    fn tick(&mut self) {
        trace!("tick!");
    }

    fn cancel(&mut self) -> io::Result<()> {
        trace!("cancel!");
    }
}

But, trying to build this file yields this:

error[E0119]: conflicting implementations of trait `tokio_proto::streaming::pipeline::Transport` for type `tokio_io::codec::Framed<tokio_core::reactor::PollEvented<mio::net::TcpListener>, codec::PacketCodec>`:
  --> src/transport.rs:14:1
   |
14 | / impl Transport for GearmanFramed
15 | | {
16 | |     fn tick(&mut self) {
17 | |         trace!("tick!");
...  |
22 | |     }
23 | | }
   | |_^
   |
   = note: conflicting implementation in crate `tokio_proto`

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
  --> src/transport.rs:14:1
   |
14 | / impl Transport for GearmanFramed
15 | | {
16 | |     fn tick(&mut self) {
17 | |         trace!("tick!");
...  |
22 | |     }
23 | | }
   | |_^ impl doesn't use types inside crate
   |
   = note: the impl does not reference any types defined in this crate
   = note: define and implement a trait or new type instead

I would have expected that the specific nature of GearmanFramed would allow me to implement the Transport trait due to "specialization", but this one is still conflicting with the default, which is here:

use tokio_io as new_io;

// ...

impl<T, C> Transport for new_io::codec::Framed<T,C>
    where T: new_io::AsyncRead + new_io::AsyncWrite + 'static,
          C: new_io::codec::Encoder<Error=io::Error> +
                new_io::codec::Decoder<Error=io::Error> + 'static,
{}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
SpamapS
  • 1,087
  • 9
  • 15
  • FYI, some meta information: This is code from 'rustygear', a rewrite of 'gearmand' in Rust that I've been working on to teach myself rust. I'm currently refactoring it to use tokio since my mio code is super lame. You can track the tokio refactor here if you're interested: https://github.com/SpamapS/rustygear/tree/tokio – SpamapS Jun 17 '17 at 00:07
  • I asked a more generic version of this question here https://stackoverflow.com/questions/44600646/how-does-trait-specialization-actually-work – SpamapS Jun 17 '17 at 04:07

1 Answers1

0

So after a few days of struggling, I figured this out. The answer is to use a newtype to surround Framed, thus avoiding the default implementation.

use std::io;

use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::{Framed, Encoder, Decoder};
use tokio_proto::streaming::pipeline::Transport;
use futures::{Poll, Sink, StartSend, Stream};

use codec::PacketCodec;

pub struct GearmanFramed<T>(pub Framed<T, PacketCodec>);

impl<T> Transport for GearmanFramed<T>
    where T: AsyncRead + AsyncWrite + 'static
{
    fn tick(&mut self) {
        trace!("tick!");
    }

    fn cancel(&mut self) -> io::Result<()> {
        trace!("cancel!");
        Ok(())
    }
}

impl<T> Stream for GearmanFramed<T>
    where T: AsyncRead
{
    type Item = <PacketCodec as Decoder>::Item;
    type Error = <PacketCodec as Decoder>::Error;
    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        self.0.poll()
    }
}

impl<T> Sink for GearmanFramed<T>
    where T: AsyncWrite
{
    type SinkItem = <PacketCodec as Encoder>::Item;
    type SinkError = <PacketCodec as Encoder>::Error;
    fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
        self.0.start_send(item)
    }
    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        self.0.poll_complete()
    }
    fn close(&mut self) -> Poll<(), Self::SinkError> {
        self.0.close()
    }
}
SpamapS
  • 1,087
  • 9
  • 15