1use std::borrow::Cow;
2
3use deser_core::Text;
4use deser_core::de::{self, Deserialize, DeserializeDriver, deserialize_value};
5use deser_core::ext::ExtValue;
6use deser_core::hints::Layout;
7use deser_core::{Atom, ContainerShape, Error, ErrorKind, Event, Source, TrackLocations};
8
9use crate::document::{Document, Item, Span, TableKind, Value};
10use crate::parser::{ROOT, parse};
11
12#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct DeserializerConfig {
34 context: deser_core::Context,
35}
36
37impl Default for DeserializerConfig {
38 fn default() -> DeserializerConfig {
39 DeserializerConfig::new()
40 }
41}
42
43impl DeserializerConfig {
44 pub const fn new() -> DeserializerConfig {
46 DeserializerConfig {
47 context: deser_core::Context::new(),
48 }
49 }
50
51 pub const fn builder() -> DeserializerConfigBuilder {
53 DeserializerConfigBuilder::new()
54 }
55
56 pub const fn into_builder(self) -> DeserializerConfigBuilder {
58 DeserializerConfigBuilder { value: self }
59 }
60
61 pub fn set_context(&mut self, context: deser_core::Context) {
69 self.context = context;
70 }
71
72 pub(crate) fn without_context(&self) -> DeserializerConfig {
75 let mut config = self.clone();
76 config.context = deser_core::Context::default();
77 config
78 }
79
80 pub fn context(&self) -> &deser_core::Context {
82 &self.context
83 }
84
85 pub fn from_str<'de, T: Deserialize<'de>>(&self, s: &'de str) -> Result<T, Error> {
89 deserialize_value(|driver| self.drive_str(s, driver))
90 }
91
92 fn drive_str<'de>(
95 &self,
96 s: &'de str,
97 driver: &mut DeserializeDriver<'_, 'de>,
98 ) -> Result<(), Error> {
99 de::Deserializer::drive(
100 &mut Deserializer::from_str_with_config(s, self.clone()),
101 driver,
102 )
103 }
104
105 pub fn from_slice<'de, T: Deserialize<'de>>(&self, bytes: &'de [u8]) -> Result<T, Error> {
109 deserialize_value(|driver| self.drive_slice(bytes, driver))
110 }
111
112 fn drive_slice<'de>(
115 &self,
116 bytes: &'de [u8],
117 driver: &mut DeserializeDriver<'_, 'de>,
118 ) -> Result<(), Error> {
119 de::Deserializer::drive(
120 &mut Deserializer::from_slice_with_config(bytes, self.clone()),
121 driver,
122 )
123 }
124}
125
126#[derive(Debug, Clone)]
130#[must_use]
131pub struct DeserializerConfigBuilder {
132 value: DeserializerConfig,
133}
134
135impl DeserializerConfigBuilder {
136 pub const fn new() -> DeserializerConfigBuilder {
138 DeserializerConfigBuilder {
139 value: DeserializerConfig::new(),
140 }
141 }
142
143 pub fn context(mut self, context: deser_core::Context) -> DeserializerConfigBuilder {
147 self.value.set_context(context);
148 self
149 }
150
151 pub const fn build(self) -> DeserializerConfig {
153 let value = unsafe { core::ptr::read(&self.value) };
157 core::mem::forget(self);
158 value
159 }
160}
161
162impl Default for DeserializerConfigBuilder {
163 fn default() -> DeserializerConfigBuilder {
164 DeserializerConfigBuilder::new()
165 }
166}
167
168pub struct Deserializer<'a> {
189 input: &'a str,
190 error: Option<Error>,
192 config: DeserializerConfig,
193}
194
195impl<'a> Deserializer<'a> {
196 #[allow(clippy::should_implement_trait)]
198 pub fn from_str(input: &'a str) -> Deserializer<'a> {
199 Deserializer::from_str_with_config(input, DeserializerConfig::new())
200 }
201
202 pub fn from_str_with_config(input: &'a str, config: DeserializerConfig) -> Deserializer<'a> {
204 Deserializer {
205 input,
206 error: None,
207 config,
208 }
209 }
210
211 pub fn from_slice(input: &'a [u8]) -> Deserializer<'a> {
215 Deserializer::from_slice_with_config(input, DeserializerConfig::new())
216 }
217
218 pub fn from_slice_with_config(input: &'a [u8], config: DeserializerConfig) -> Deserializer<'a> {
223 match str_from_utf8(input) {
224 Ok(input) => Deserializer::from_str_with_config(input, config),
225 Err(err) => Deserializer {
226 input: "",
227 error: Some(err),
228 config,
229 },
230 }
231 }
232
233 pub fn config(&self) -> &DeserializerConfig {
235 &self.config
236 }
237
238 pub fn deserialize<T: Deserialize<'a>>(&mut self) -> Result<T, Error> {
243 de::Deserializer::deserialize(self)
244 }
245
246 pub fn deserialize_with<T, F>(&mut self, setup: F) -> Result<T, Error>
251 where
252 T: Deserialize<'a>,
253 F: FnOnce(&mut DeserializeDriver<'_, 'a>),
254 {
255 de::Deserializer::deserialize_with(self, setup)
256 }
257
258 pub fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
270 if !self.config.context.is_empty() {
271 driver.set_default_context(self.config.context.clone());
272 }
273 if let Some(err) = self.error.take() {
274 return Err(err);
275 }
276 let doc = parse(self.input)?;
277
278 if TrackLocations::of(driver.state()) {
279 Source(self.input.into()).set(driver.state_mut());
280 }
281 emit(&doc, driver).map_err(|mut err| {
282 err.resolve_position(self.input.as_bytes());
283 err
284 })
285 }
286}
287
288impl<'a> de::Deserializer<'a> for Deserializer<'a> {
289 fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
290 Deserializer::drive(self, driver)
291 }
292}
293
294#[inline(always)]
296fn emit_at<'e, E: Into<Event<'e>>>(
297 driver: &mut DeserializeDriver<'_, '_>,
298 event: E,
299 span: Span,
300) -> Result<(), Error> {
301 driver.state_mut().set_input_range(span.start, span.end);
302 driver.emit(event)
303}
304
305#[allow(clippy::ptr_arg)]
308#[inline(always)]
309fn emit_str<'a>(
310 driver: &mut DeserializeDriver<'_, 'a>,
311 value: &Cow<'a, str>,
312 span: Span,
313) -> Result<(), Error> {
314 driver.state_mut().set_input_range(span.start, span.end);
315 match *value {
316 Cow::Borrowed(value) => driver.emit_borrowed(value),
317 Cow::Owned(ref value) => driver.emit(value.as_str()),
318 }
319}
320
321#[allow(clippy::ptr_arg)]
327fn emit_key<'a>(
328 driver: &mut DeserializeDriver<'_, 'a>,
329 key: &Cow<'a, str>,
330 span: Span,
331) -> Result<(), Error> {
332 driver.state_mut().set_input_range(span.start, span.end);
333 match *key {
334 Cow::Borrowed(key) => driver.emit_borrowed(Atom::Lexical(Text::borrowed(key))),
335 Cow::Owned(ref key) => driver.emit(Atom::Lexical(Text::borrowed(key.as_str()))),
336 }
337}
338
339enum Frame {
341 Table(usize, usize),
342 Array(usize, usize),
343}
344
345fn emit<'a>(doc: &Document<'a>, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
347 let mut stack = vec![Frame::Table(ROOT, 0)];
348 let shape = ContainerShape::with_len(doc.tables[ROOT].entries.len());
349 emit_at(driver, Event::MapStart(shape), doc.tables[ROOT].span)?;
350
351 while let Some(frame) = stack.last_mut() {
352 let item: &Item = match *frame {
353 Frame::Table(id, ref mut index) => {
354 let table = &doc.tables[id];
355 match table.entries.get(*index) {
356 Some(entry) => {
357 *index += 1;
358 emit_key(driver, &entry.key, entry.key_span)?;
359 &entry.item
360 }
361 None => {
362 stack.pop();
363 emit_at(driver, Event::MapEnd, table.span)?;
364 continue;
365 }
366 }
367 }
368 Frame::Array(id, ref mut index) => {
369 let array = &doc.arrays[id];
370 match array.items.get(*index) {
371 Some(item) => {
372 *index += 1;
373 item
374 }
375 None => {
376 stack.pop();
377 emit_at(driver, Event::SeqEnd, array.span)?;
378 continue;
379 }
380 }
381 }
382 };
383
384 match item.value {
385 Value::Table(id) => {
386 let table = &doc.tables[id];
387 if table.kind == TableKind::Inline {
390 Layout::Compact.set(driver.state_mut());
391 }
392 let shape = ContainerShape::with_len(table.entries.len());
393 emit_at(driver, Event::MapStart(shape), table.span)?;
394 stack.push(Frame::Table(id, 0));
395 }
396 Value::Array(id) => {
397 let array = &doc.arrays[id];
398 if !array.of_tables
400 && array
401 .items
402 .first()
403 .is_some_and(|x| matches!(x.value, Value::Table(_)))
404 {
405 Layout::Compact.set(driver.state_mut());
406 }
407 let shape = ContainerShape::with_len(array.items.len());
408 emit_at(driver, Event::SeqStart(shape), array.span)?;
409 stack.push(Frame::Array(id, 0));
410 }
411 Value::Str(ref value) => emit_str(driver, value, item.span)?,
412 ref scalar => {
413 let atom = match *scalar {
414 Value::Int(value) if value >= 0 => Atom::U64(value as u64),
415 Value::Int(value) => Atom::I64(value),
416 Value::UInt(value) => Atom::U64(value),
417 Value::Float(value) => Atom::F64(value),
418 Value::Bool(value) => Atom::Bool(value),
419 Value::Datetime(ref value) => Atom::Ext(ExtValue::borrowed(value)),
420 Value::Str(_) | Value::Table(_) | Value::Array(_) => unreachable!(),
421 Value::Float32(_) | Value::FloatText(_) => {
422 unreachable!("only used when serializing")
423 }
424 };
425 emit_at(driver, atom, item.span)?;
426 }
427 }
428 }
429
430 Ok(())
431}
432
433fn str_from_utf8(bytes: &[u8]) -> Result<&str, Error> {
434 #[cfg(feature = "speedups")]
435 {
436 if simdutf8::basic::from_utf8(bytes).is_ok() {
437 return Ok(unsafe { std::str::from_utf8_unchecked(bytes) });
439 }
440 }
441 std::str::from_utf8(bytes)
442 .map_err(|err| Error::with_offset(ErrorKind::Syntax, "invalid UTF-8", err.valid_up_to()))
443}
444
445pub fn from_str<'de, T: Deserialize<'de>>(s: &'de str) -> Result<T, Error> {
452 DeserializerConfig::new().from_str(s)
453}
454
455pub fn from_slice<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> Result<T, Error> {
460 DeserializerConfig::new().from_slice(bytes)
461}