-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support deserializing types that borrow data in from_str
#505
Changes from 1 commit
86f251c
44563c2
8bfba74
d742abe
5b9b6d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,9 +38,9 @@ | |
/// assert_eq!(config.owner.name, "Lisa"); | ||
/// ``` | ||
#[cfg(feature = "parse")] | ||
pub fn from_str<T>(s: &'_ str) -> Result<T, Error> | ||
pub fn from_str<'a, T>(s: &'a str) -> Result<T, Error> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change should be reflected in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done! |
||
where | ||
T: serde::de::DeserializeOwned, | ||
T: serde::de::Deserialize<'a>, | ||
Comment on lines
+41
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This changes the trait bounds from a more general one to a more specific one which is a breaking change There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the review! 😄 Isn't it the reverse, though?
|
||
{ | ||
T::deserialize(Deserializer::new(s)) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a test for borrowed data to ensure this works.
If it does work, then more investigation is needed because it shouldn't according to the serde docs.
&str
gets parsed into owned types and then we deserialize that.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just added the test in 44563c2, thanks!
I think that the tested code works because
String
s, being an owned type, have a implicit'static
lifetime bound (they can live indefinitely long until dropped).Cow
s support storing owned data, so a valid lifetime for aCow
that either stores owned data or static strings isCow<'static, str>
. Due to lifetime coercion, a'static
lifetime can be used whenever a shorter lifetime is expected, such as'de
in this case: the lifetime of the serialized data source.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that sufficient if the user explicitly declared the field as
borrow
?What about if the user isn't using
Cow
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is. I've pushed a commit that adds that attribute to the field to show that it works too.
When using
&'a str
in the newborrowed_data
test, aTomlError
is returned with messageinvalid type: string "bar", expected a borrowed string
, which makes sense, because the deserializer does not borrow strings, and it can't move the owned string it deserializes to a reference in the struct.However, this is not a new error condition: it can already be reproduced by using
T::deserialize(toml::de::Deserializer::new(s))
.Morally, I see some value in accepting these kind of structs from users: TOML may just be one of several formats they want to (de)serialize it from, and other formats properly support zero-copy deserialization. Newcomers to serde are very unlikely to mess around with zero-copy deserialization anyway.
Edit: I think it may be useful to point out that serde's author approved these "magical"
Cow
properties on several obscure issues on its repo: serde-rs/serde-rs.github.io#46, serde-rs/serde-rs.github.io#57. Logically, ifCow
s are meant to support maybe owned, maybe borrowed data, their lifetime must not be'static
, but somehow derived from the deserializer lifetime, so structs that contain them and want to take advantage of this cannot implementDeserializeOwned
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, this isn't a morality discussion.
Second, we are shifting a compile time error into a runtime error for the easy path while, as you pointed out, a workaround is available for those that want to borrow. In API design, we should be emphasizing the safe path with the easy path while ideally still supporting the unsafe route. The current solutions fits that to a T. I don't know why the serde docs make the recommendation they do but in this case, I see it being useful.
I'm going to go ahead and close this and ask any further discussion to happen in the appropriate issue (#490).