Generally speaking, the orphan rule can be described as:
*You can only implement a trait for a type if either the trait or the type is defined in your own crate.medium
Normally, this rule prevents any type from having traits implemented for them outside the crate. For example, it would be impossible to implement a Display trait for f32 or String outside the std. However, the From trait seems to be an exception to this rule.
For example:
///Stores the Amount of used Entitys of this kind
#[derive(Resource, Default, Clone, From)]
pub struct Count(pub usize);
impl From<Count> for usize {
fn from(val: Count) -> Self {
val.0
}
}
example
Dosen't produce compiler Errors anymore. Why exactly is that? There are another Traits, that can do that?
So, If I've understand it correctly, Not the FromTrait itself is an exception of this rule. It's special kind of type signagure GenericTrait<LocalType> for ForeignType is. Why is that? According to the standard library, it's type signature is:
The only requirement is the 'Sized' trait. However, the Sized trait only requires that the size of the type is known at compile time1. Therefore, this does seem to be a Rust language feature. I mean, there is no LocalToForeign Trait, isn't it? Or is it, because the f32 has a blanket implementation for the From trait?2 Therefore it wouldn't break this rule, because it's already implented this way. On the other hand, this wouldn't make this kind of implementations possible for every Type, isn't it?
Then you can see that the impl satisfies the condition for which it is allowed:
Ti = T1 = Count is a local type
No uncovered type parameter P1..=Pn appears in T0..=Ti (simply because there are no type parameters P1..=Pn)
If you want a more intuitive explanation why this specific impl is allowed, it's because the only way it could conflict was if the crate that defined From or usize wrote a impl<T: Trait> From<T> for usize or impl<T: Trait, U: Trait2> From<T> for U. In both cases your crate can "see" that impl and detect the conflict, so if it cannot see any conflicts then your impl must be valid.
And this is also why adding a blanket implementation where one didn't exist before is a major breaking change: if you added the impl when it didn't exist, and then later upstream added the blanket impl, that would introduce a conflict and break your crate.
What about upstream adding non-blanket impls? That is not a major breaking change. Consider that your dependencies cannot name your local type directly (as that would be a circular dependency), so neither the crate that owns GenericTrait not the crate that owns ForeignType can directly (i.e.without generics) write:
impl GenericTrait<LocalType> for ForeignType
So if you do write the implementation, any non-blanket implementations they add in the future won't cause an overlap with your crate.