Brian
Brian

Reputation: 179

Implement std::convert::From on type from another crate

I have an external geometry crate that defines a rectangle struct made of floats and an external sdl2 crate that defines a rectangle struct made of integers.

The following code is how I would expect to convert a geometry::Rect to an sdl2::SdlRect using the std::convert::From trait:

extern crate geometry;
extern crate sdl2;

fn main() {
    let geo_rect = geometry::Rect::default();
    let sdl_rect = sdl2::SdlRect::from(geo_rect);
}

impl From<geometry::Rect> for sdl2::SdlRect {
    fn from (rect: geometry::Rect) -> sdl2::SdlRect {
        sdl2::SdlRect {
            x: rect.x as i32,
            y: rect.y as i32,
            w: rect.w as i32,
            h: rect.h as i32,
        }
    }
}

Unfortunately, this doesn't compile because either the trait I'm implementing or the struct it's being implemented for must come from the current crate. The only solution I've found that works is to define a MyFrom trait that mirrors the functionality of the std::convert::From trait:

extern crate geometry;
extern crate sdl2;

fn main() {
    let geo_rect = geometry::Rect::default();
    let sdl_rect = sdl2::SdlRect::my_from(geo_rect);
}

pub trait MyFrom<T> {
    fn my_from(T) -> Self;
}

impl MyFrom<geometry::Rect> for sdl2::SdlRect {
    fn my_from (rect: geometry::Rect) -> sdl2::SdlRect {
        sdl2::SdlRect {
            x: rect.x as i32,
            y: rect.y as i32,
            w: rect.w as i32,
            h: rect.h as i32,
        }
    }
}

I'm not particularly happy with this solution because knowing when to call my_from instead of from will get confusing down the line. Is there another way for me to solve this using more idiomatic Rust?

Upvotes: 3

Views: 1855

Answers (1)

starblue
starblue

Reputation: 56752

Better define your own rectangle type that wraps an externally defined rectangle, and use the standard From trait.

This is one possible use of the newtype pattern.

Upvotes: 3

Related Questions