User extensions problems with orphan-rule

⚓ rust    📅 2025-06-10    👤 surdeus    👁️ 2      

surdeus

To simplify i'll present a minimized version of my problem, for detail see here:

The detailed problem (click for more details)

What I want

I'm writing a crate that contains:

pub trait TraitA {}
pub struct StructA<T>(T);

And I would like the user to be able to write:

pub struct MyLocalType;
impl TraitA for StructA<MyLocalType> {}

Why I want it

In this case, StructA is a helper struct I provide to help implement another trait.
While we can write the following blanket implementation, I want the user to be able to specialise it.

impl<T> TraitA for StructA<T> {}

In our concrete example, the specialisation allows a x5 in performance.

The problem

The says that the orphan rule doesn't allow this:

error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
  --> test_orphan/src/lib.rs:2:1
   |
51 | impl<'a> TraitA for StructA<MyLocalType> {
   | ^^^^^^^^^^^^^^^^^^^-------------------------------
   |                              |
   |                              `StructA` is not defined in the current crate
   |
   = note: impl doesn't have any local type before any uncovered type parameters
   = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
   = note: define and implement a trait or new type instead

Why it happens

Looking at the rust reference I see the orphan rules defined as:

Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only if at least one of the following is true:

  • All of
    • At least one of the types T0..=Tn must be a local type. Let Ti be the first such type.
    • No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)

Here the problem is that T0, which in my case is StructA<MyLocalType>, is not a LocalType, as they are defined as:

LocalType

A struct, enum, or union which was defined in the current crate. This is not affected by applied type arguments. struct Foo is considered local, but Vec is not. LocalType is local. Type aliases do not affect locality.

Questions

1 - What's the reason why ForeignType<LocalType> is not local?
2 - What can I do to allow the user to write their specialised impl in an ergonomic way? I'd rather avoid having to write a new-type that wraps StructA<MyLocalType> and having to forward all traits

6 posts - 5 participants

Read full topic

🏷️ rust_feed