Skip to content

Commit e97f28b

Browse files
committed
Add serde_spanned::Spanned deserialization
Provide deserialization of serde_spanned::Spanned<T>, which tracks the position of the value in the original JSON document.
1 parent cd55b5a commit e97f28b

File tree

6 files changed

+249
-3
lines changed

6 files changed

+249
-3
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ itoa = "1.0"
1717
memchr = { version = "2", default-features = false }
1818
ryu = "1.0"
1919
serde = { version = "1.0.194", default-features = false }
20+
serde_spanned = { version = "0.6.8", features = ["serde"], optional = true }
2021

2122
[dev-dependencies]
2223
automod = "1.0.11"
@@ -89,3 +90,7 @@ raw_value = []
8990
# overflow the stack after deserialization has completed, including, but not
9091
# limited to, Display and Debug and Drop impls.
9192
unbounded_depth = []
93+
94+
# Provide deserialization of serde_spanned::Spanned<T>, which tracks the position
95+
# of the value in the original JSON document
96+
spanned = ["serde_spanned"]

src/de.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ where
6767
disable_recursion_limit: false,
6868
}
6969
}
70+
71+
#[cfg(feature = "spanned")]
72+
pub(crate) fn byte_offset(&self) -> usize {
73+
self.read.byte_offset()
74+
}
7075
}
7176

7277
#[cfg(feature = "std")]
@@ -1817,20 +1822,28 @@ impl<'de, R: Read<'de>> de::Deserializer<'de> for &mut Deserializer<R> {
18171822

18181823
fn deserialize_struct<V>(
18191824
self,
1820-
_name: &'static str,
1821-
_fields: &'static [&'static str],
1825+
name: &'static str,
1826+
fields: &'static [&'static str],
18221827
visitor: V,
18231828
) -> Result<V::Value>
18241829
where
18251830
V: de::Visitor<'de>,
18261831
{
1832+
let _ = name;
1833+
let _ = fields;
1834+
18271835
let peek = match tri!(self.parse_whitespace()) {
18281836
Some(b) => b,
18291837
None => {
18301838
return Err(self.peek_error(ErrorCode::EofWhileParsingValue));
18311839
}
18321840
};
18331841

1842+
#[cfg(feature = "spanned")]
1843+
if serde_spanned::__unstable::is_spanned(name, fields) {
1844+
return visitor.visit_map(crate::spanned::SpannedDeserializer::new(self));
1845+
}
1846+
18341847
let value = match peek {
18351848
b'[' => {
18361849
check_recursion! {

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,3 +436,6 @@ mod read;
436436

437437
#[cfg(feature = "raw_value")]
438438
mod raw;
439+
440+
#[cfg(feature = "spanned")]
441+
pub(crate) mod spanned;

src/spanned.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use crate::de::{Deserializer, Read};
2+
use serde::de::value::BorrowedStrDeserializer;
3+
use serde::de::IntoDeserializer as _;
4+
5+
pub(crate) enum SpannedDeserializer<'d, R> {
6+
Start {
7+
value_deserializer: &'d mut Deserializer<R>,
8+
},
9+
Value {
10+
value_deserializer: &'d mut Deserializer<R>,
11+
},
12+
End {
13+
end_pos: usize,
14+
},
15+
Done,
16+
}
17+
18+
impl<'d, R> SpannedDeserializer<'d, R> {
19+
pub fn new(value_deserializer: &'d mut Deserializer<R>) -> Self {
20+
Self::Start { value_deserializer }
21+
}
22+
}
23+
24+
impl<'d, 'de, R> serde::de::MapAccess<'de> for SpannedDeserializer<'d, R>
25+
where
26+
R: Read<'de>,
27+
{
28+
type Error = <&'d mut Deserializer<R> as serde::de::Deserializer<'de>>::Error;
29+
30+
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
31+
where
32+
K: serde::de::DeserializeSeed<'de>,
33+
{
34+
let key = match self {
35+
Self::Start { .. } => serde_spanned::__unstable::START_FIELD,
36+
Self::End { .. } => serde_spanned::__unstable::END_FIELD,
37+
Self::Value { .. } => serde_spanned::__unstable::VALUE_FIELD,
38+
Self::Done => return Ok(None),
39+
};
40+
41+
seed.deserialize(BorrowedStrDeserializer::new(key))
42+
.map(Some)
43+
}
44+
45+
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
46+
where
47+
V: serde::de::DeserializeSeed<'de>,
48+
{
49+
match self {
50+
Self::Start { .. } => {
51+
let prev = std::mem::replace(self, Self::Done);
52+
let Self::Start { value_deserializer } = prev else {
53+
unreachable!()
54+
};
55+
56+
let start = value_deserializer.byte_offset();
57+
*self = Self::Value { value_deserializer };
58+
seed.deserialize(start.into_deserializer())
59+
}
60+
61+
Self::Value { .. } => {
62+
let prev = std::mem::replace(self, Self::Done);
63+
let Self::Value { value_deserializer } = prev else {
64+
unreachable!()
65+
};
66+
67+
let val = seed.deserialize(&mut *value_deserializer);
68+
*self = Self::End {
69+
end_pos: value_deserializer.byte_offset(),
70+
};
71+
val
72+
}
73+
74+
Self::End { .. } => {
75+
let prev = std::mem::replace(self, Self::Done);
76+
let Self::End { end_pos } = prev else {
77+
unreachable!()
78+
};
79+
seed.deserialize(end_pos.into_deserializer())
80+
}
81+
82+
Self::Done => {
83+
panic!("should not get here");
84+
}
85+
}
86+
}
87+
}

tests/crate/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ float_roundtrip = ["serde_json/float_roundtrip"]
2020
arbitrary_precision = ["serde_json/arbitrary_precision"]
2121
raw_value = ["serde_json/raw_value"]
2222
unbounded_depth = ["serde_json/unbounded_depth"]
23+
serde_spanned = ["serde_json/serde_spanned"]

tests/test.rs

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use serde_json::{
3333
to_vec, Deserializer, Number, Value,
3434
};
3535
use std::collections::BTreeMap;
36-
#[cfg(feature = "raw_value")]
36+
#[cfg(any(feature = "raw_value", feature = "spanned"))]
3737
use std::collections::HashMap;
3838
use std::fmt::{self, Debug};
3939
use std::hash::BuildHasher;
@@ -43,6 +43,8 @@ use std::io;
4343
use std::iter;
4444
use std::marker::PhantomData;
4545
use std::mem;
46+
#[cfg(feature = "spanned")]
47+
use std::ops::Range;
4648
use std::str::FromStr;
4749
use std::{f32, f64};
4850

@@ -2558,3 +2560,138 @@ fn test_control_character_search() {
25582560
"control character (\\u0000-\\u001F) found while parsing a string at line 1 column 2",
25592561
)]);
25602562
}
2563+
2564+
#[cfg(feature = "spanned")]
2565+
fn format_span(json: &str, span: Range<usize>) -> String {
2566+
format!(
2567+
"{}\n{}{}",
2568+
json,
2569+
" ".repeat(span.start),
2570+
"^".repeat(span.end - span.start)
2571+
)
2572+
}
2573+
2574+
#[cfg(feature = "spanned")]
2575+
#[track_caller]
2576+
fn assert_span_eq(json: &str, expected: Range<usize>, actual: Range<usize>) {
2577+
let expected_str = format_span(json, expected.clone());
2578+
let actual_str = format_span(json, actual.clone());
2579+
2580+
assert_eq!(
2581+
expected, actual,
2582+
"Expected span:\n{}\nActual span:\n{}",
2583+
expected_str, actual_str
2584+
);
2585+
}
2586+
2587+
#[cfg(feature = "spanned")]
2588+
#[test]
2589+
fn test_spanned_string() {
2590+
use serde_spanned::Spanned;
2591+
2592+
#[derive(Deserialize)]
2593+
struct SpannedStruct {
2594+
field: Spanned<String>,
2595+
}
2596+
2597+
let json = r#"{"field": "value"}"#;
2598+
let result: SpannedStruct = serde_json::from_str(json).unwrap();
2599+
assert_eq!(result.field.as_ref(), "value");
2600+
assert_span_eq(json, result.field.span(), 10..17);
2601+
}
2602+
2603+
#[cfg(feature = "spanned")]
2604+
#[test]
2605+
fn test_spanned_number() {
2606+
use serde_spanned::Spanned;
2607+
2608+
#[derive(Deserialize)]
2609+
struct SpannedStruct {
2610+
field: Spanned<f64>,
2611+
}
2612+
2613+
let json = r#"{"field": -2.718e28}"#;
2614+
let result: SpannedStruct = serde_json::from_str(json).unwrap();
2615+
assert_eq!(*result.field.as_ref(), -2.718e28);
2616+
assert_span_eq(json, result.field.span(), 10..19);
2617+
}
2618+
2619+
#[cfg(feature = "spanned")]
2620+
#[test]
2621+
fn test_spanned_whole_array() {
2622+
use serde_spanned::Spanned;
2623+
2624+
#[derive(Deserialize)]
2625+
struct SpannedStruct {
2626+
field: Spanned<Vec<i32>>,
2627+
}
2628+
2629+
let json = r#"{"field": [1, 2, 3, 4]}"#;
2630+
let result: SpannedStruct = serde_json::from_str(json).unwrap();
2631+
assert_eq!(result.field.as_ref(), &[1, 2, 3, 4]);
2632+
assert_span_eq(json, result.field.span(), 10..22);
2633+
}
2634+
2635+
#[cfg(feature = "spanned")]
2636+
#[test]
2637+
fn test_spanned_array_items() {
2638+
use serde_spanned::Spanned;
2639+
2640+
#[derive(Deserialize)]
2641+
struct SpannedStruct {
2642+
field: Vec<Spanned<i32>>,
2643+
}
2644+
2645+
let json = r#"{"field": [1, 2, 3, 4]}"#;
2646+
let result: SpannedStruct = serde_json::from_str(json).unwrap();
2647+
assert_eq!(result.field.len(), 4);
2648+
2649+
assert_eq!(*result.field[0].as_ref(), 1);
2650+
assert_span_eq(json, result.field[0].span(), 11..12);
2651+
2652+
assert_eq!(*result.field[1].as_ref(), 2);
2653+
assert_span_eq(json, result.field[1].span(), 14..15);
2654+
2655+
assert_eq!(*result.field[2].as_ref(), 3);
2656+
assert_span_eq(json, result.field[2].span(), 17..18);
2657+
2658+
assert_eq!(*result.field[3].as_ref(), 4);
2659+
assert_span_eq(json, result.field[3].span(), 20..21);
2660+
}
2661+
2662+
#[cfg(feature = "spanned")]
2663+
#[test]
2664+
fn test_spanned_whole_map() {
2665+
use serde_spanned::Spanned;
2666+
2667+
#[derive(Deserialize)]
2668+
struct SpannedStruct {
2669+
field: Spanned<HashMap<i32, String>>,
2670+
}
2671+
2672+
let json = r#"{"field": {"1": "one", "2": "two"}}"#;
2673+
let result: SpannedStruct = serde_json::from_str(json).unwrap();
2674+
assert_span_eq(json, result.field.span(), 10..34);
2675+
let mut map = result.field.into_inner();
2676+
let one = map.remove(&1).unwrap();
2677+
assert_eq!(one, "one");
2678+
let two = map.remove(&2).unwrap();
2679+
assert_eq!(two, "two");
2680+
assert!(map.is_empty());
2681+
}
2682+
2683+
#[cfg(feature = "spanned")]
2684+
#[test]
2685+
fn test_spanned_whitespace() {
2686+
use serde_spanned::Spanned;
2687+
2688+
#[derive(Deserialize)]
2689+
struct SpannedStruct {
2690+
field: Spanned<f64>,
2691+
}
2692+
2693+
let json = r#"{"field": -2.718e28 }"#;
2694+
let result: SpannedStruct = serde_json::from_str(json).unwrap();
2695+
assert_eq!(*result.field.as_ref(), -2.718e28);
2696+
assert_span_eq(json, result.field.span(), 15..24);
2697+
}

0 commit comments

Comments
 (0)