1

I am implementing the std::convert::From trait for a struct containing a Cow<str>. Is there a way to use the same implementation for all different kinds of integers (u8, u16, u32, usize and so on)?

use std::borrow::Cow;

pub struct Luhn<'a> {
    code: Cow<'a, str>,
}

I can easily implement code for all integers using a trait bound on the ToString trait, but then I cannot use a specific implementation for str and String - this way the benefits of Cow cannot be exploited. When I write specific implementations for str and String, I get a compile error:

error[E0119]: conflicting implementations of trait `std::convert::From<&str>` for type `Luhn<'_>`:
  --> src/lib.rs:23:1
   |
7  | impl<'a> From<&'a str> for Luhn<'a> {
   | ----------------------------------- first implementation here
...
23 | impl<'a, T: ToString> From<T> for Luhn<'a> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Luhn<'_>`

I understand that this is due to the fact that Rust does not offer function overloading. How could this be solved in an elegant way?

impl<'a> From<&'a str> for Luhn<'a> {
    fn from(input: &'a str) -> Self {
        Luhn {
            code: Cow::Borrowed(input),
        }
    }
}

impl<'a> From<String> for Luhn<'a> {
    fn from(input: String) -> Self {
        Luhn {
            code: Cow::Owned(input),
        }
    }
}

impl<'a, T: ToString> From<T> for Luhn<'a> {
    fn from(input: T) -> Self {
        Luhn {
            code: Cow::Owned(input.to_string()),
        }
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Lukas E.
  • 99
  • 1
  • 6

1 Answers1

2

Since &str and String both implement ToString, you can use the unstable specialization feature:

#![feature(specialization)]

use std::borrow::Cow;

pub struct Luhn<'a> {
    code: Cow<'a, str>,
}

impl<'a, T: ToString> From<T> for Luhn<'a> {
    default fn from(input: T) -> Self {
//  ^^^^^^^
        Luhn {
            code: Cow::Owned(input.to_string()),
        }
    }
}

impl<'a> From<&'a str> for Luhn<'a> {
    fn from(input: &'a str) -> Self {
        Luhn {
            code: Cow::Borrowed(input),
        }
    }
}

impl<'a> From<String> for Luhn<'a> {
    fn from(input: String) -> Self {
        Luhn {
            code: Cow::Owned(input),
        }
    }
}

That being said, you cannot implement Display for Luhn because you'd run into How is there a conflicting implementation of `From` when using a generic type?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Thanks very much! Besides this unstable feature there is no way to make use of maybe some special Cow property? Or a specific trait. – Lukas E. Sep 15 '18 at 07:01