I believe the general consensus is to reexport. If you do not then the applications that use your crate are "stuck" with your version of the 3rd party crate. If you reexport, then the application can use whatever version of the 3rd party crate they would like while your crate uses the version that it has been tested with.
Is this really the case?
I thought that types with the same name but from two different versions of a crate are actually distinct types and reexporting just gives them a distinct name too. And if this is the case there shouldn't be too much problems since you rarely have to name the type explicitely. Especially in my example, where you almost exclusively use it via traits.
Or am I misunderstanding something?
But now assuming that I do reexport, is there a consensus how to do so? Use a dedicated submodule or just reexport where it fits best?
Yes, if you don't have to name the type explicitly the application could use whatever version of the common crate it wants. But as soon as the application needs to name it, like passing it to another function for processing, or returning it, it needs to be named, and then the application is restricted to the same version.
I think reexporting is usually done where it fits best, but I haven't seen any consensus on this.