4

I have this custom type:

pub type Address = [u8; 32];

I tried implementing fmt::Display for this type:

impl fmt::Display for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let public_key = sr25519::Public::from_raw(self);
        let address = public_key.to_ss58check();
        write!(f,"{}",address)
    }
}

But I get this compile error:

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
   --> core/linix-primitives/src/lib.rs:122:1
    |
122 | impl fmt::Display for Address {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate

I understand that to implement a trait I need to have one of two: either the definition of a type locally or a definition of a trait locally.

Well, I already defined the type locally:

pub type Address = [u8; 32];

So why am I getting a compile error?

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Nulik
  • 6,748
  • 10
  • 60
  • 129

1 Answers1

6

The problem here is that the following does not declare a new type:

pub type Address = [u8; 32];

But instead a type alias, which is closer to a c-style typedef. This means that your code gets turned into the following:

impl fmt::Display for [u8; 32] {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let public_key = sr25519::Public::from_raw(self);
        let address = public_key.to_ss58check();
        write!(f,"{}",address)
    }
}

And here, [u8; 32] isn't a local type. What you probably want to do is use what is called the newtype pattern. You will probably want to add a #[repr] attribute to that if your type might have some padding.

Optimistic Peach
  • 3,862
  • 2
  • 18
  • 29
  • yeah, looks like `repr(transparent)` is what I need – Nulik Jun 13 '19 at 23:43
  • @Nulik ..or you could use the so called _newtype_ pattern, on which you can implement any kind of trait. – Peter Varo Jun 13 '19 at 23:50
  • hmm, `repr(transparrent)` is not working , I am getting this error: expected array of 32 elements, found struct `Address` – Nulik Jun 14 '19 at 01:12
  • 1
    *You will probably want to add a `#[repr(transparent)]` to that.* — this is bad advice to give. Almost no one will want to use a layout representation unless they are doing things like `mem::transmute`. For an example of the fallout of this recommendation, see [repr(transparent) does not allow a struct containing an array to be treated like an array](https://stackoverflow.com/q/56590513/155423). – Shepmaster Jun 14 '19 at 14:34
  • @hellow @shepmaster I added the recommended changes, I haven't touched c in a very long time, so I'd forgotten about `typedef`s. I recommended adding a `#[repr(transparent)]` because it seemed plausible at the time of writing that there might be padding, so I meant it to save some space, but I guess the compiler usually knows best. – Optimistic Peach Jun 14 '19 at 20:28