I have some basic questions about how crates are supposed to work together in Rust, specifically if their public interfaces contain common, but not trivial data types. This question requires a bit of context, so I will start with an example to explain the scenario. After that I will get into the more abstract questions.
An example for such a common type would be an RGB color value:
Lets assume that there is a crate that I want to use that has public functions that take an RGB value, lets call this hypothetical crate
draw (no connection to the actual
draw crate). Because the authors of the
draw did not want to re-invent the wheel, they decided to use the type
rgb::RGBA from the
rgb crate in their interface for functions such as
set_color(...) and they publicly re-export this type in their crate as well.
Let's now suppose that I want to author a second crate that can be used together with
draw but also in other scenarios. My crate (in this example called
skycolor) has a public function called
get_sky_color() that returns the current color of the sky where the program is run. Because I do not want to reinvent the wheel, either, and because I want interoperability with
draw, I also use
rgb::RGBA in my public interface (as the return type of
Now (as far as I understand), there is a big problem: Since I do not own the
draw crate and other possible "consumers" of color values produced by
skycolor, I cannot control that
skycolor's version of the
rgb crate is the same as the one used in
draw. If someone wants to use
skycolor together with a newer version of
draw that references a newer version of
rgb, the code will not compile when you pass the return value of
set_color(...). Even worse: when someone wants to use
skycolor together with two crates (e.g.
rgb-crate, there is no way to have compatible interfaces!
- How should crates handle complex/composite data types in their interfaces? Should one use specialized crates such as the
rgbcrate for types or is it better when each crate defines their own types and the crate user is supposed to do conversion each time a value is passed from one crate to another?
- Should a crate, if it uses such a data-type-crate, publicly re-export the type? If yes, does this mean the actual source of the type is an implementation detail of the crate and therefore there cannot be interoperability between this crate and another one that uses the same type?
- Is there a clever way to make it possible that all crates in a project actually use the same version of a data-type-crate such as
rgb? If this is possible, then there would not be any compile time incompatibility (as long as the signature of the types themselves did not change).