Expand description
This crate provides source locations (line and column) for deser.
Formats publish the byte range in the input of every event they emit
into the State (see State::input_range) and, if location tracking
is requested, the source these ranges refer to (see Source).
This crate resolves the ranges into lines and columns with a
SourceMap (see Locations) and types can pick them up while they
are deserialized. The simplest way to do that is the Spanned
wrapper. Location tracking is requested with
TrackLocations in the context of the
deserialization:
use deser::{Context, Deserialize, TrackLocations};
use deser_location::Spanned;
#[derive(Deserialize)]
struct Config {
name: String,
workers: Spanned<u32>,
}
let input = "{\n \"name\": \"web\",\n \"workers\": 0\n}";
let json = deser_json::DeserializerConfig::builder()
.context(Context::with(TrackLocations(true)))
.build();
let config: Config = json.from_str(input).unwrap();
if config.workers.value == 0 {
let span = config.workers.span.unwrap();
assert_eq!(span.to_string(), "3:14-3:15");
}§Implementing Location Support in Formats
Formats do not depend on this crate. They publish the byte range of
every event with State::set_input_range before they emit it and set
the Source if locations are requested. The source map is built when
a consumer asks for a location for the first time:
use deser::de::DeserializeDriver;
use deser::Source;
use deser::Event;
use deser_location::Spanned;
let input = "true";
let mut out = None::<Spanned<bool>>;
{
let mut driver = DeserializeDriver::new(&mut out);
Source(input.into()).set(driver.state_mut());
driver.state_mut().set_input_range(0, 4);
driver.emit(Event::from(true)).unwrap();
}
let span = out.unwrap().span.unwrap();
assert_eq!((span.start.line, span.start.column), (1, 1));
assert_eq!((span.end.line, span.end.column), (1, 5));§Buffering
Values that are internally buffered with a
Recording (as some enum representations do)
retain their locations when they are replayed as recordings capture the
input range of every event.