-
Notifications
You must be signed in to change notification settings - Fork 602
Description
Name trait methods should return Cow<'static, str>.
I came across the Name trait and found it extremely useful, especially when printing debug information or handling encode/decode errors.
What bothers me is that the provided methods, full_name and type_url, always return a newly allocated String, even though their values are mostly, if not always, the same.
-
Cow<'static, str>
Always return a clone-on-write aroundstr.
This provides maximum flexibility for both us and the user, as it allows choosing whether the value is borrowed from a string literal (&'static str) or owned as a newly allocatedString:pub trait Name: Message { const NAME: &'static str; const PACKAGE: &'static str; fn full_name() -> Cow<'static, str> { if Self::PACKAGE.is_empty() { Cow::Borrowed(Self::NAME) } else { Cow::Owned(format!("{}.{}", Self::PACKAGE, Self::NAME)) } } fn type_url() -> Cow<'static, str> { Cow::Owned(format!("/{}", Self::full_name())) } }
However, since we control
prost-buildand it is almost always used, we can take advantage of this by having the generated code always return a borrowed value from a hardcoded string literal (this is already how it is implemented):impl Name for MyMessage { const NAME: &'static str = "MyMessage"; const PACKAGE: &'static str = "hello.world.v1"; fn full_name() -> Cow<'static, str> { Cow::Borrowed("hello.world.v1.MyMessage") } fn type_url() -> Cow<'static, str> { Cow::Borrowed("/hello.world.v1.MyMessage") } }
I understand this is a breaking change, but using
Cowis extremely helpful for avoiding unnecessary allocations. Moreover, sinceCowimplementsDerefand other useful traits, the migration should be mostly seamless (take this with a grain of salt 🧂). -
&'static str
A dream...
Always return a string literal.
The concatenation ofNAMEandPACKAGEconstants can be done using theconst_formatcrate or an ad-hoc solution.
Unfortunately, this solution cannot be used at the moment due to the following error: “can't useSelffrom outer item aconstis a separate item from the item that contains it” and other const trait features not been stabilized yet.pub trait Name: Message { const NAME: &'static str; const PACKAGE: &'static str; fn full_name() -> &'static str { if Self::PACKAGE.is_empty() { Self::NAME } else { const_format::formatcp!("{}.{}", Self::PACKAGE, Self::NAME) } } fn type_url() -> &'static str { const_format::formatcp!("/{}", Self::full_name()) } }