'Sized' for trait object


#1

I need to implement some kind of mixins into crypto of base struct Keyfile, which are HdwalletCrypto & CoreCrypto. But Box doesn’t allow Sized trait.
What is the proper way to achieve my goal?
Or should I just create enum with both variant, and handle dispatch manualy whenever needed?

#[derive(Clone, Debug, Eq)]
pub struct KeyFile {
    pub address: Address,

    /// UUID v4
    pub uuid: Uuid,

    ///
    pub crypto: Box<Crypto>,
}

pub trait Crypto: Debug + Clone + Eq {}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HdwalletCrypto {
    pub cipher: String,
    pub hardware: String,
    pub hd_path: String,
} 

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CoreCrypto {
    pub cipher: Cipher,
    pub cipher_text: Vec<u8>,
    pub cipher_params: CipherParams,
    pub kdf: Kdf,
    pub kdfparams_dklen: usize,
    pub kdfparams_salt: Salt,
    pub mac: Mac,
}

impl Crypto for HdwalletCrypto {};
impl Crypto for CoreCrypto {};

#2

Depending on how you need to use it, you have (at least) two choices: You can either use the Crypto type as a a bound on a generic type, instead of boxing it:

pub struct KeyFile<T: Crypto> {
    ...
    pub crypto: T,
}

Or, if you need to use both HdwalletCrypt and CoreCrypto in the same context (a Vec that contains both kinds, for instance), then you should create an enum, as you suggested. Though I would keep the details of the enum private, if possible, implementing Crypto for the enum itself, where the methods (if they exist) dispatch to the appropriate variant.


#3

Only single context. I mean just one or either inside Keyfile struct. Thanks


#4

You could remove Size restriction.

pub trait Crypto: Debug + Eq {
  fn crypto_clone(&self) -> Box<Crypto> // {Box::new(self.clone())}
}

Then implement KeyFile clone manually.


#5

Forget to mention that it is forbidden to use Self in supertrait for trait object, Eq need to use Self. So we ended up with a @cliff solution, right?


#6

Right. Is there a reason you wanted a trait object here to begin with?


#7

Just forget about Sized stuff for Trait objects. Still new with Rust, and was confused how to handle this right.
There are lots of info on the network, but it’s mostly fragmented - hard to get full perspective about OOP in Rust (if one can say so).


#8

Gotcha. Yeah, Rust isn’t an OO language although if you squint there are cases where it resembles one. In general, the language leans heavily towards static typing/dispatch, rather than dynamic. Traits are more like strongly typed templates (I’m simplifying here) rather than interfaces/abstract classes in OO languages. You can get dynamic dispatch (via trait objects), but it’s limited compared to OO, as you can see here with the restrictions on what traits can be turned into objects.

That said, you can usually model your stuff with static typing since Rust has a great static type system. You’ll very likely get better runtime performance as well.