Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to specialize on a static lifetime?

I want to specialize &'static str from &'a str:

use std::borrow::Cow;

struct MyString {
    inner: Cow<'static, str>,
}

impl From<&'static str> for MyString {
    fn from(x: &'static str) -> Self {
        MyString {
            inner: Cow::Borrowed(x),
        }
    }
}

impl<T: Into<String>> From<T> for MyString {
    fn from(x: T) -> Self {
        MyString {
            inner: Cow::Owned(x.into()),
        }
    }
}

fn main() {
    match MyString::from("foo").inner {
        Cow::Borrowed(..) => (),
        _ => {
            panic!();
        }
    }

    let s = String::from("bar");
    match MyString::from(s.as_ref()).inner {
        Cow::Owned(..) => (),
        _ => {
            panic!();
        }
    }

    match MyString::from(String::from("qux")).inner {
        Cow::Owned(..) => (),
        _ => {
            panic!();
        }
    }
}

The gist is that MyString stores a statically-allocated string literal as a &'static str and all other strings as a String. This allows MyString to avoid having a lifetime parameter—i.e., MyString<'a>, which is critical for my API, all while allowing the caller to pass in any kind of string and have MyString automatically do the correct thing.

The problem is that the code doesn't compile:

error[E0119]: conflicting implementations of trait `std::convert::From<&'static str>` for type `MyString`:
  --> src/main.rs:15:1
   |
7  | impl From<&'static str> for MyString {
   | ------------------------------------ first implementation here
...
15 | impl<T: Into<String>> From<T> for MyString {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyString`

Is there any trick that allows me to do what I want? If not, is lifetime specialization something that Rust will ever support?

like image 748
Craig M. Brandenburg Avatar asked May 05 '16 14:05

Craig M. Brandenburg


1 Answers

Rust 1.51.0 does not have specialization of any kind. If I'm reading the specialization RFC correctly, then lifetime specialization will not be supported even when the RFC is implemented:

A hard constraint in the design of the trait system is that dispatch cannot depend on lifetime information. In particular, we both cannot, and should not allow specialization based on lifetimes:

  • We can't, because when the compiler goes to actually generate code ("trans"), lifetime information has been erased -- so we'd have no idea what specializations would soundly apply.

  • We shouldn't, because lifetime inference is subtle and would often lead to counterintuitive results. For example, you could easily fail to get 'static even if it applies, because inference is choosing the smallest lifetime that matches the other constraints.

(Emphasis mine)

There's some examples further in the link that indicate some of the concrete issues.

I recommend using a Cow to handle the "owned or borrowed" case.

like image 53
Shepmaster Avatar answered Sep 22 '22 04:09

Shepmaster