-
Notifications
You must be signed in to change notification settings - Fork 190
Support spans when deserializing serde structures #239
Conversation
Note: I'm also pushing it through the build system to check for 1.15 compatibility. Initial builds are probably gonna break. |
Would it be possible to support spans in a map key? |
Cargo.toml
Outdated
@@ -20,7 +20,7 @@ travis-ci = { repository = "alexcrichton/toml-rs" } | |||
|
|||
[dependencies] | |||
serde = "1.0" | |||
serde_derive = "1.0" |
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.
Looks like you wrote out the Deserialize impl so this is no longer used.
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.
Fixed, thanks!
src/spanned.rs
Outdated
{ | ||
let start = visitor.next_key::<StartKey>()?; | ||
|
||
if start.is_none() { |
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 would recommend cutting out the key_deserialize
macro and using:
if visitor.next_key()? != Some(START) {
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.
Fixed, thanks!
src/de.rs
Outdated
K: de::DeserializeSeed<'de>, | ||
{ | ||
if self.start.is_some() { | ||
seed.deserialize(spanned::START.into_deserializer()).map(Some) |
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.
This needs to be:
use serde::de::value::BorrowedStrDeserializer;
seed.deserialize(BorrowedStrDeserializer::new(spanned::START)).map(Some)
in order for my other comment to work.
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.
Fixed, thanks!
Regarding Generally I address this by distinguishing between the key of a structure and its span, like: |
I would expect |
"foo = [0, 1, 2, 3, 4]", | ||
"[0, 1, 2, 3, 4]" | ||
); | ||
// datetime |
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 tried an actual Datetime
but it seems to get the wrong span. Is this a tokenizer issue?
good::<Datetime>("foo = 1997-09-09T09:09:09Z", "1997-09-09T09:09:09Z");
---- test_spanned_field stdout ----
thread 'test_spanned_field' panicked at 'assertion failed: `(left == right)`
left: `26`,
right: `19`', tests/spanned.rs:20:9
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.
Good catch! Probably a case of the deserializer not combining the spans. will check it out.
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.
Fixed in 2b40d54, thanks!
I half-agree with this, but it becomes awkward when trying to implement and use: https://play.rust-lang.org/?gist=5a444c2ed6fd2322594658920b9eef12&version=stable&mode=debug (possibly my impl-skills are not strong enough, so please take a stab at this). But if I have a map which includes spans, I'd want to be able to:
Note: One approach that satisfies this is to use |
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.
Looks good to me, thanks so much!
src/lib.rs
Outdated
@@ -169,3 +169,7 @@ mod tokens; | |||
|
|||
#[doc(hidden)] | |||
pub mod macros; | |||
|
|||
pub mod spanned; |
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.
Could this module start out private and only export the Spanned
type below?
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.
Will do. Thanks.
src/spanned.rs
Outdated
/// The end range (exclusive). | ||
pub end: usize, | ||
/// The spanned value. | ||
pub value: T, |
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.
Instead of public fields could these be accessed through methods perhaps? That way we could tweak the representation here later in the future and/or do other fancy things with struct layout
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.
These are the set of methods I'm fiddling with right now:
impl<T> Spanned<T> {
fn start(&self) -> usize { .. }
fn end(&self) -> usize { .. }
fn span(&self) -> (usize, usize) { .. }
fn borrow(&self) -> &T { .. }
fn take(self) -> T { .. }
}
Got any opinions on this?
src/spanned.rs
Outdated
} | ||
|
||
/// Take the inner value. | ||
pub fn take(self) -> T { |
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.
For consistency with libstd, mind naming this into_inner
? I think we may want to go ahead and add methods like get_ref
and get_mut
here as well
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.
Done, thanks!
This PR introduces Spanned based on the previous POC by @dtolnay.
Internally we deserialize spans as "intermediate structs" with special naming conventions, which communicates to the
Deserializer
that it should emit a Map with similarly special names that we can pick up.This PR contains a couple of changes:
Spanned<T>
type that can be used in structs to encapsulate spans.datetime
andspanned
.eat_spanned
andexpect_spanned
toTokenizer
to correctly parse tables and arrays.I'm unsure it is complete, the infrastructure needed to support Datetime permeates more of the deserialize infrastructure, but I haven't been able to decipher why yet. Any feedback is appreciated.
Future work
Ironically this doesn't help me with my original problem, but it's a fair step down the road. I use
toml::Value
in a similar way thatCargo
uses it to permit more flexible decoding than is afforded through databinding. Introducing spans into the existingtoml::Value
would not be a backwards compatible change, so the only alternative I see is to have separate types (e.g.toml::SpannedValue
) which contains the necessary spans. Suggestions are welcome.