Open Ixrec opened 6 years ago
I just noticed that withoutboats thinks mutually exclusive traits are part of the solution (or at least he did back in 2016). That seems significant.
One possibility for "solving" this diesel-chrono type of issue is the notion of "friend" crates.
// Crate t containing Trait T
// (nothing new/special required)
// Crate u containing trait U
// (nothing new/special required)
// Crate s providing structs that need impls for u::U and t::T
// main.rs/lib.rs
// (nothing new/special required)
// Make the 'baz' module's private (no visibility spec) (not pub(self), pub(nofriend), pub(super), pub(in ...mod)) items publicized to friends
pub(friend) mod baz;
...
// foo.rs (module foo)
// if nothing is designated as pub(friend) then the "friend" visible items are the same as the "pub" visible items
// no changes to this module in that case
// foo/bar.rs (module foo::bar)
// even though this module isn't pub(friend) items within it (including structs, enums, Trait impls, fns, Inheren Methods, and sub-modules) can be pub(friend)
pub(friend) struct FooBarYep {
// struct private elements are made "friend" accessible too
}
pub(friend) impl for FooBarYep {
...
}
pub(friend) fn FooBarYepProcessor( p : FooBarYep ) {
}
// not accessible to friends
struct FooBarNope {
}
// ...etc...
// baz.rs (module baz)
// nothing special needed here as the entire 'baz' module has been publicized to friends, so, if anything needs special access by a friend, it has it
// this is accessible to friends
struct Bazup {
// all private/pub members of this accessible to friends
}
// however, if something should be "true private" (even hidden from friends, it can be declared as "pub(self)" or "pub(nofriend)"
// not accessible to friends
pub(self) struct Bazzit {
}
pub(nofriend) struct Bazout {
}
// accessible to friends
struct Bazme {
x : i32; // accessible to friends (because the mod has been "friended")
pub(self) y: i32; // not accessible to friends, only accessible within the Baz mod
pub(nofriend) z: i32; // not accessible to friends, true private even though the module was friended
pub t : i32; // also accessible to friends
pub(super) u : i32; // not accessible to friends
pub(friend) v : i32; // accessible to friends (lint warning for unneeded pub(friend)
pub(self,friend) v : 32; // only accessible to self and friends
}
// accessible to friends, but, has a lint warning for unneeded pub(friend)
pub(friend) Bazyou {
...
}
// main-friends.rs/lib-friends.rs (declare friend crates)
friend friend-t-impl-s-Sy impl (::t::T) for ::crate::{Baz,Foo::Bar} // provide impls of Trait T of crate t by friend crate friend-t-impl-s-Sy
friend friend-t-impl-s-Sy impl (::t::T2) for ::crate::{Baz,Foo::Bar} // provide impls of Trait T2 of crate t by friend crate friend-t-impl-s-Sy
//// friend friend-t-impl-s-Sy impl (::t::T,::t::T2) for ::crate::{Baz,Foo::Bar}
friend friend-u-impl-s-Sy impl (::u::U) for ::crate::{Baz,Foo::Bar} // provide impls of Trait U of crate u by friend crate friend-u-impl-s-Sy
// Crate friend-t-impl-s-Sy containing impls for Trait T from t for types Sy subset(a) of Sx of crate s
use ::t::T;
use ::u::U;
use ::s::friend::Baz;
use ::s::friend::Foo::Bar;
pub timpl {
impl T for Baz::Bazup {
...
}
impl T for Bar::FooBarYep {
...
}
// Not permitted
//impl T for Bar::FooBarNope {
// ...
//}
}
// Crate friend-u-impl-s-Sz containing impls for Trait U from u for types Sz subset(b) of Sx of crate s
// similar for u::U as for t::T above
// Crate u that uses Sy from s and wants to use the impls of T for Sy from s provided by friend-t-impl-s-Sy and for Sz from s provided by frient-t-impl-s-Sz
use ::t::T;
use ::u::U;
use ::s::Bar::FooBarYep;
use ::friend-t-impl-s-Sy::timpl;
// have impl of T for FooBarYep provided by friend-t-imp-s-Sy crate here
serde-json
is another example. While it's the defacto standard crate for json types(and quite satisfactory), it is biased for serde
usages, and not a neutral representation crate as it should be.
serde-xml
is in similar situation (And might be even worse).
I've got two features in the js_int crate, serde
and rocket_04
, that only serve to add trait implementations. I would argue that the latter would make a bit more sense in its own crate (the former less so because serde feels pretty 'fundamental').
I've got two use cases from my projects: speedy + glam and chrono / index_vec + bitcode. The latter one currently has some escape hatch (where bitcode just allows deferring to serde), but the former one is really annoying as glam is being used all over the project and new typing it is just a very big deal (currently using git subtree on glam instead).
Sometimes, there's an
impl
that probably should exist, and client code probably should not have to provide it via a newtype, but neither the type's crate or the trait's crate is a good home for it. But we still want there to be a single, quasi-"official" home for these impls. As far as I know, Rust has no good answer for this case today.This issue is for gathering examples of such use cases, and possibly discussing what a targeted solution for it might look like.
The only example I'm currently aware of is a hypothetical
diesel-chrono
crate.