0

Explicitly using String::from in the following code works, but how can I make it automatically use From<OsStringWrap<'a>> trait without explicitly using String::from?

use serde::Serialize; // 1.0.115

struct OsStringWrap<'a>(&'a std::ffi::OsString);
impl<'a> From<OsStringWrap<'a>> for String {
    fn from(s: OsStringWrap) -> String {
        s.0.to_string_lossy().to_string()
    }
}

pub fn insert<T: Serialize + ?Sized, S: Into<String>>(_key: S, _value: &T) {}

fn main() {
    for (key, value) in std::env::vars_os() {
        // HOW-TO: auto use From<OsStringWrap<'a>> trait
        // without explicit `String::from` like below?
        /*
            insert(OsStringWrap(&key), &OsStringWrap(&value))
        */

        // below using `String::from` to make it explicitly
        // but want to find a way to make it shorter
        insert(OsStringWrap(&key), &String::from(OsStringWrap(&value)))
    }
}

Playground, and the insert method is a real case from tera

James Yang
  • 476
  • 5
  • 6
  • [Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?](https://stackoverflow.com/q/40006219/155423). This also applied for `OsString` / `&OsStr`. – Shepmaster Oct 01 '20 at 01:55
  • Why does this code use `Serialize`? That doesn't seem important to the question. – Shepmaster Oct 01 '20 at 01:56
  • @Shepmaster the `insert` method is a real case from [tera](https://docs.rs/tera/1.5.0/tera/struct.Context.html#method.insert) – James Yang Oct 01 '20 at 12:33
  • So you have a function that requests a `T: Serialize`... and rather than implementing `Serialize` for `OsStringWrap` you are converting it to a `String` first... and you want the `String`-conversion to be automatic? Seems roundabout. Why not just implement `Serialize`? – trent Oct 01 '20 at 13:15

1 Answers1

1

Your request as currently phrased is impossible. Your insert function accepts a generic type, so nothing exists to tell the compiler what type should be converted to. This tiny example is equivalent:

fn demo<T>(_: T) {}

fn main() {
    demo(true.into());
}

Since the compiler can not know what concrete type to pick to convert to, the programmer must specify it.

You could potentially change your function to accept anything that can be turned into a String (e.g. T: Into<String>) or be referenced as a &str (e.g. T: AsRef<str>).

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366