Adding to_* methods
Closed this issue · 4 comments
According to the Rust API Guidelines you can add to_* methods which take a borrow and produce an owned object, usually by Cloneing. It is at the moment unclear whether this functionality would be useful or desired.
Some notable examples from std:
fn to_owned(&self) -> String makes sense, a borrowed slice Cloned to an owned String: https://doc.rust-lang.org/std/primitive.str.html#method.to_owned
fn to_vec(&self) -> Vec<T> where T: Clone also makes sense, a borrowed slice to an owned Vec<T>: https://doc.rust-lang.org/std/primitive.slice.html#method.to_vec
fn to_str(&self) -> Option<&str> is interesting because it is also referenced by the guidelines above, but creates a reference, not an owned instance and almost seems like it should have been an as_* function: https://doc.rust-lang.org/std/path/struct.Path.html#method.to_str
I think the behavior exhibited by the first example is most desirable. I would probably make a new derive called EnumCloneGetters (or something), and just implement each to_* with the variant's .clone() method. However, as far as I'm aware, we will be unable to determine the traits of any variant at expansion-time, so we wouldn't automatically know what to skip. I think we may be able to get around this by allowing users to add attributes to members (similar to what serde does) to skip over them in cloning (if that makes sense). For example:
#[derive(EnumCloneGetters)]
enum MyEnum {
foo(String),
#[enum_methods(no_clone)]
bar(SomeOtherTypeThatIsntClone),
}is something we could probably get away with while remaining off nightly.
I think generating items of the second form is also doable - it would require some serious diving into the AST.
The last form is something that I don't think would be very useful, because we can already do if let MyEnum::Foo(x) = ... on enums, and we've already got EnumIsA to check if an enum matches a specific variant.
What do you think?
I'm not really familiar with what the limitations of quote/syn (and procedural macros in general) are, so it's hard for me to comment on this one.
Isn't EnumCloneGetters just a trait? If you wanted to require the enum to be fully clonable, couldn't you just make EnumCloneGetters a super trait containing Clone?
EnumCloneGetters is actually not a trait. derive procedural macros allow you to generate code for, well, anything. I'm just making separate impl blocks for the derived type.
However, the more I think about it, making an EnumCloneGetters marker trait may be useful in this context (where it has a super trait of Clone). We'd have to provide one with the library instead of generating one, but that may make for prettier error message.