0

I've been trying to get this code to compile


pub trait Packet: PacketSerializer + ProtocolToID + Default {
    fn serialize_with_id(&self, ver: &ProtocolVersion) -> Box<ByteBuf>;
    fn deserialize_gen(buf: &mut ByteBuf) -> Box<Self>;
}

impl<T: PacketSerializer + ProtocolToID + PacketHandler + Default> Packet for T
{
    fn serialize_with_id(&self, ver: &ProtocolVersion) -> Box<ByteBuf> {
        let mut buf = Box::new(ByteBuf::new());
        buf.write_var_int(self.resolve_id(ver));
        self.serialize(&mut buf, &ver);
        buf
    }

    fn deserialize_gen(buf: &mut ByteBuf) -> Box<T> {
        let mut p: T = Default::default();
        p.deserialize(buf);
        Box::new(p)
    }
}

pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn Packet> {
    Box::new(clientbound::SetCompression { threshold: 256 })
}

specifically invoke_packet_handler is supposed to return a Box<dyn Packet>

According to the docs, this should work https://doc.rust-lang.org/rust-by-example/trait/dyn.html if you "statically" define the trait so the compiler can see it.

I get the following error at runtime

error[E0038]: the trait `Packet` cannot be made into an object
  --> src/serialize/packet.rs:43:61
   |
43 | pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn Packet> {
   |                                                             ^^^^^^^^^^^^^^^ `Packet` cannot be made into an object

I'm assuming this is because of the implementation for Packet? It's generic on every type that implements PacketSerializer, ProtocolToID, PacketHandler and Default

However,


pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn PacketHandler> {
    Box::new(clientbound::SetCompression { threshold: 256 })
}

does compile if I specify a single trait

ripzyzz
  • 1
  • 1
  • Please include a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example), there are many types without a definition in your code which makes it impossible to compile. – apilat Aug 21 '21 at 20:08
  • 3
    From the error message, it seems that this error is related to [object safety](https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md) - you cannot create a value of `dyn Packet` because `Packet` contains a method with no `&self` parameter (in your case `deserialize_gen`) – apilat Aug 21 '21 at 20:11
  • Awesome thanks! That was definitely one of the issues. I read up on object safety and it turns out another issue is that the `Default` trait isn't object safe because it returns self and the compiler can't determine the size for various implementations (and it doesn't have a concrete type) – ripzyzz Aug 22 '21 at 19:04
  • Note that if your trait is not object-safe, you can still use trait objects. You can create a helper trait that is object-safe, and provide a blanket implementation of the helper trait for all types that implement the original (non-object-safe) trait. [This answer](https://stackoverflow.com/a/64840069/1600898) shows how to use the `Hash` trait (non-object-safe because its titular method is generic) to create type-erased behavior through an intermediate object-safe trait. – user4815162342 Aug 23 '21 at 13:33

0 Answers0