Creating my own string type

I need to have methods that can take &str, std::string::String and my own string type, rust_fb::string::String. Previously I was able to get AsRef<str> parameters, however I wasn't able to directly pass my own string type to my functions, which end up with a special method to convert my string type to std::string::String and finally to &str. This is what the problem looks like:

use rust_fb::string::String;

fn f<S: AsRef<str>>(_s: S) {
}

f(my_own_string_type.to_std_string().as_ref());

In reality, there'll be methods like concat, which should be able to receive any of the above string types.

Implementing AsRef in different ways just doesn't work. For example, instead of a function taking AsRef<str>, I could write a function taking AsRef<rust_fb::string::String>, but the problem is... lifetime.

impl AsRef<std::string::String> for String {
    fn as_ref(&self) -> &std::string::String {
        &self.chars().collect::<std::string::String>()
    }
}

What's the best way to accept my custom string (rust_fb::string::String), std::string::String and &str in, say, a function like concat?

This is the full source: https://github.com/matheusdiasdesouzads/rust-fb/blob/master/src/string.rs

Update (1)

Just to advice I can't dereference to &str because that'd make available methods that return &str (e.g., slicing returns &str) or that use Rust's existing regex support. Furthermore, my string type doesn't store any kind of std::string::String or Box<str>, it's a bit Python-based, thus it uses either latin-1, UCS-2 or UCS-4 in representation.

If your custom string type can implement Deref<Target=str>, you can just write functions taking &str to get that. (example from the std)

2 Likes

Unfortunately I can't expose API using &str, because many of its methods return &str, and I also want to implement methods using my own regular expression implementation.

So I'm just trying:

impl AsRef<String> for &str {
    fn as_ref(&self) -> &String {
        &String::from(self.as_ref())
    }
}

And I get:

temporary value created here
rustc E0515
string.rs(522, 9): original diagnostic
cannot return reference to temporary value
returns a reference to data owned by the current function
rustc E0515
string.rs(522, 10): temporary value created here

Is it impossible to achieve what I want? I want to directly receive my custom string type, and implicitly convert &str and &std::string::String to it with AsRef<rust_fb::string::String>.

Whatever you want to borrow has to live somewhere already (returning a reference to a temporary would cause a dangling reference). So if your own type doesn't contain a T, then you can't1 return a &T.


1: of course, there are ways to technucally do that, e.g. always returning the same reference to a static, or leaking memory and returning a reference to a leaked heap-allocated value. But those are not reasonably what you want.

1 Like

I'd say the typical approaches in this situation (excluding AsRef which you can't use here) are

  1. Implement conversions (using From) from String and &str to rust_fb::string::String and take s: impl Into<rust_fb::string::String>. Then inside the function you can immediately convert the argument into your own string type and work with it from there.
  2. Create a trait that has functions for the operations that you want to do and implement the trait for all three. You could either make concat generic, or even make concat a method for this custom trait.

Any AsRef<Something> based approach is generally not going to work if the types you want to use don't all contain a Something.

2 Likes

Hmm, using traits might be the only solution then as you said.