Wrapped struct not inheriting default implementation

I have a struct Vehicle and another WrappedVehicle(Vehicle). Vehicle has a default implementation with new() and get_wheel_description(&self). Given that WrappedVehicle is derived from Vehicle, how do I get impl Vehicle {....} to also work for WrappedVehicle.

Sample code (playgroud):

struct Vehicle {
    name: String,
    wheels: u8,
}


impl Vehicle {
    pub fn new(name: String, wheels: u8) -> Vehicle {
        Vehicle{name, wheels}
    }
    
    pub fn get_wheel_description(&self) -> String {
        match self.wheels {
            1 => String::from("Unicycle"),
            2 => String::from("Two wheeler"),
            3 => String::from("Tum Tum"),
            4 => String::from("Four wheeler"),
            _ => String::from("4+ wheels"),
        }
    }
}

struct WrappedVehicle(Vehicle);


pub fn main() {
    // This passes because of impl Vehicle
    let v = Vehicle::new(String::from("Car"), 4);
    println!("{:?}, Name: {}", v.get_wheel_description(), v.name);
    
    // This fails because impl Vehicle does not extend to WrappedVehicle
    let w = WrappedVehicle::new(String::from("Trailer"), 18);
    println!("{:?}, Name: {}", w.get_wheel_description(), w.name);
}

It seems counter-intuitive that the default impl Vehicle {} for Vehicle does not automatically apply to WrappedVehicle.

EDIT: The code sample above is more of a reprex. I am trying to wrap Decimal (rust_decimal crate) into a custom type to override it's default serde serializer in order to get a custom representation of serialized decimal number.

What you're looking for is a Deref implementation and a DerefMut implementation. This allows you to extend the type under your object. But that's not really all that idiomatic, instead you should provide a few functions in your newtype to expose the object it contains, or just implement a trait for the old type.

1 Like

Can’t you customize Decimal serde serialization without a wrapper type? Eg using custom serialization functions.

But, even if you need/want to go the wrapper way, don’t wrap it until the very end, right before you need to serializer. Work with Decimal for the bulk of your app, and only wrap/unwrap at the serialization edge.

Because they're different types and may have different guarantees. For example, Box<T> is a wrapper type over *mut T but doesn't have methods like .cast() or .offset() which exist on ptr type.

1 Like

Compiler (rightly) complains of conflicting implementation for impl serde::Serialize for Decimal. The conflict is between my local implementation and the default one provided by the library.

Yup, but there’re ways around it, eg https://serde.rs/remote-derive.html

Esoteric stuff for a newbie here, going to play around with it to see if it helps. Thanks!