1use std::borrow::Cow;
2
3use deser_core::__format::{MakeSink, deserialize_value, drive_value};
4use deser_core::de::{
5 self, ContentKey, Deserialize, DeserializeDriver, DuplicateKeys, LexicalRules,
6};
7use deser_core::{Atom, ContainerShape, Error, ErrorKind, Event, Order, Source, Text};
8use quick_xml::XmlVersion;
9use quick_xml::events::{BytesRef, BytesStart, Event as XmlEvent};
10use quick_xml::name::{QName, ResolveResult};
11use quick_xml::reader::NsReader;
12
13use crate::Names;
14use crate::mixed::WhitespaceDepths;
15use crate::root::{Declarations, RootData};
16
17#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct DeserializerConfig {
23 pub(crate) names: Names,
24 resolve_namespaces: bool,
25 duplicate_keys: DuplicateKeys,
26 track_locations: bool,
27}
28
29impl Default for DeserializerConfig {
30 fn default() -> DeserializerConfig {
31 DeserializerConfig::new()
32 }
33}
34
35impl DeserializerConfig {
36 pub const fn new() -> DeserializerConfig {
38 DeserializerConfig {
39 names: Names::new(),
40 resolve_namespaces: false,
41 duplicate_keys: DuplicateKeys::Error,
42 track_locations: true,
43 }
44 }
45
46 pub const fn attribute_prefix(mut self, prefix: &'static str) -> DeserializerConfig {
50 self.names.attribute_prefix = prefix;
51 self
52 }
53
54 pub const fn text_key(mut self, key: &'static str) -> DeserializerConfig {
59 self.names.text_key = key;
60 self
61 }
62
63 pub const fn namespaces(
98 mut self,
99 namespaces: &'static [(&'static str, &'static str)],
100 ) -> DeserializerConfig {
101 self.names.namespaces = namespaces;
102 self
103 }
104
105 pub const fn resolve_namespaces(mut self, yes: bool) -> DeserializerConfig {
151 self.resolve_namespaces = yes;
152 self
153 }
154
155 pub const fn duplicate_keys(mut self, policy: DuplicateKeys) -> DeserializerConfig {
163 self.duplicate_keys = policy;
164 self
165 }
166
167 pub const fn track_locations(mut self, yes: bool) -> DeserializerConfig {
174 self.track_locations = yes;
175 self
176 }
177
178 pub fn from_str<'de, T: Deserialize<'de>>(&self, s: &'de str) -> Result<T, Error> {
180 deserialize_value(|make_sink| self.drive_str(s, make_sink))
181 }
182
183 fn drive_str<'de>(
186 &self,
187 s: &'de str,
188 make_sink: &mut MakeSink<'_, '_, 'de>,
189 ) -> Result<(), Error> {
190 drive_value(&mut Deserializer::from_str_with_config(s, self), make_sink)
191 }
192
193 pub fn from_slice<'de, T: Deserialize<'de>>(&self, bytes: &'de [u8]) -> Result<T, Error> {
197 deserialize_value(|make_sink| self.drive_slice(bytes, make_sink))
198 }
199
200 fn drive_slice<'de>(
203 &self,
204 bytes: &'de [u8],
205 make_sink: &mut MakeSink<'_, '_, 'de>,
206 ) -> Result<(), Error> {
207 drive_value(
208 &mut Deserializer::from_slice_with_config(bytes, self),
209 make_sink,
210 )
211 }
212}
213
214pub fn from_str<'de, T: Deserialize<'de>>(s: &'de str) -> Result<T, Error> {
227 DeserializerConfig::new().from_str(s)
228}
229
230pub fn from_slice<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> Result<T, Error> {
232 DeserializerConfig::new().from_slice(bytes)
233}
234
235pub struct Deserializer<'a> {
237 input: &'a str,
238 error: Option<Error>,
239 config: DeserializerConfig,
240}
241
242impl<'a> Deserializer<'a> {
243 #[allow(clippy::should_implement_trait)]
245 pub fn from_str(input: &'a str) -> Deserializer<'a> {
246 Deserializer::from_str_with_config(input, &DeserializerConfig::new())
247 }
248
249 pub fn from_str_with_config(input: &'a str, config: &DeserializerConfig) -> Deserializer<'a> {
251 Deserializer {
252 input,
253 error: None,
254 config: config.clone(),
255 }
256 }
257
258 pub fn from_slice(input: &'a [u8]) -> Deserializer<'a> {
260 Deserializer::from_slice_with_config(input, &DeserializerConfig::new())
261 }
262
263 pub fn from_slice_with_config(
266 input: &'a [u8],
267 config: &DeserializerConfig,
268 ) -> Deserializer<'a> {
269 let input = input.strip_prefix(b"\xef\xbb\xbf").unwrap_or(input);
271 match std::str::from_utf8(input) {
272 Ok(input) => Deserializer::from_str_with_config(input, config),
273 Err(err) => Deserializer {
274 input: "",
275 error: Some(
276 Error::new(ErrorKind::Unexpected, "input is not valid UTF-8")
277 .with_offset(err.valid_up_to()),
278 ),
279 config: config.clone(),
280 },
281 }
282 }
283
284 pub fn deserialize<T: Deserialize<'a>>(&mut self) -> Result<T, Error> {
286 de::Deserializer::deserialize(self)
287 }
288
289 pub fn deserialize_with<T, F>(&mut self, setup: F) -> Result<T, Error>
294 where
295 T: Deserialize<'a>,
296 F: FnOnce(&mut DeserializeDriver<'_, 'a>),
297 {
298 de::Deserializer::deserialize_with(self, setup)
299 }
300
301 pub fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
307 if let Some(err) = self.error.take() {
308 return Err(err);
309 }
310 let state = driver.state_mut();
311 if self.config.track_locations {
312 Source::set(state, self.input);
313 }
314 self.config.duplicate_keys.set(state);
315 TEXT_RULES.set(state);
316 ContentKey(self.config.names.text_key).set(state);
319 *state.get_mut::<Names>() = self.config.names.clone();
320 Parser {
321 input: self.input,
322 config: &self.config,
323 reader: NsReader::from_str(self.input),
324 stack: Vec::new(),
325 root_done: false,
326 root: None,
327 declarations: None,
328 }
329 .run(driver)
330 .map_err(|err| err.resolve_position(self.input.as_bytes()))
331 }
332}
333
334impl<'a> de::Deserializer<'a> for Deserializer<'a> {
335 fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
336 Deserializer::drive(self, driver)
337 }
338}
339
340const TEXT_RULES: LexicalRules = LexicalRules::STRICT.with_empty_is_null(true);
346
347type Range = (usize, usize);
349
350enum PendingText<'a> {
352 None,
353 Borrowed(&'a str, Range),
354 Owned(String, Range),
355}
356
357impl<'a> PendingText<'a> {
358 fn push(&mut self, text: Cow<'a, str>, range: Range) {
359 *self = match (std::mem::replace(self, PendingText::None), text) {
360 (PendingText::None, Cow::Borrowed(text)) => PendingText::Borrowed(text, range),
361 (PendingText::None, Cow::Owned(text)) => PendingText::Owned(text, range),
362 (PendingText::Borrowed(prev, (start, _)), text) => {
363 PendingText::Owned(prev.to_string() + &text, (start, range.1))
364 }
365 (PendingText::Owned(mut prev, (start, _)), text) => {
366 prev.push_str(&text);
367 PendingText::Owned(prev, (start, range.1))
368 }
369 };
370 }
371
372 fn is_blank(&self) -> bool {
373 match self {
374 PendingText::None => true,
375 PendingText::Borrowed(text, _) => is_blank(text),
376 PendingText::Owned(text, _) => is_blank(text),
377 }
378 }
379
380 fn emit(self, driver: &mut DeserializeDriver<'_, 'a>, fallback: Range) -> Result<(), Error> {
382 match self {
383 PendingText::None => emit_at(driver, Atom::Lexical(Text::borrowed("")), fallback),
384 PendingText::Borrowed(text, range) => {
385 driver.state_mut().set_input_range(range.0, range.1);
386 driver.emit_borrowed(Atom::Lexical(Text::borrowed(text)))
387 }
388 PendingText::Owned(text, range) => {
389 emit_at(driver, Atom::Lexical(Text::owned(text)), range)
390 }
391 }
392 }
393}
394
395fn is_blank(text: &str) -> bool {
396 text.bytes()
397 .all(|b| matches!(b, b' ' | b'\t' | b'\n' | b'\r'))
398}
399
400struct Element<'a> {
402 is_map: bool,
404 text: PendingText<'a>,
405 start: Range,
407}
408
409struct Parser<'a, 'c> {
410 input: &'a str,
411 config: &'c DeserializerConfig,
412 reader: NsReader<&'a [u8]>,
413 stack: Vec<Element<'a>>,
414 root_done: bool,
415 root: Option<RootData>,
418 declarations: Option<Vec<(String, String)>>,
421}
422
423impl<'a> Parser<'a, '_> {
424 fn run(mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
425 loop {
426 let start = self.position();
427 let event = self
428 .reader
429 .read_event()
430 .map_err(|err| xml_error(err, self.reader.error_position() as usize))?;
431 let range = (start, self.position());
432 match event {
433 XmlEvent::Start(ref tag) => self.start(driver, tag, range)?,
434 XmlEvent::Empty(ref tag) => {
435 self.start(driver, tag, range)?;
436 self.end(driver, range)?;
437 }
438 XmlEvent::End(_) => self.end(driver, range)?,
439 XmlEvent::Text(text) => {
440 self.text(text.xml_content(XmlVersion::Implicit1_0), range)?
441 }
442 XmlEvent::CData(text) => {
443 self.text(text.xml_content(XmlVersion::Implicit1_0), range)?
444 }
445 XmlEvent::GeneralRef(reference) => {
446 let text = resolve_reference(&reference, start)?;
447 self.text(Cow::Owned(text.to_string()), range)?
448 }
449 XmlEvent::Decl(_)
450 | XmlEvent::PI(_)
451 | XmlEvent::Comment(_)
452 | XmlEvent::DocType(_) => {}
453 XmlEvent::Eof => {
454 if !self.stack.is_empty() {
455 return Err(Error::new(
456 ErrorKind::EndOfFile,
457 "unexpected end of input, an element is not closed",
458 )
459 .with_offset(start));
460 }
461 if !self.root_done {
462 return Err(
463 Error::new(ErrorKind::EndOfFile, "no root element").with_offset(start)
464 );
465 }
466 return Ok(());
467 }
468 }
469 }
470 }
471
472 fn position(&self) -> usize {
473 self.reader.buffer_position() as usize
474 }
475
476 fn make_map(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
478 if !self.stack.last().unwrap().is_map {
479 self.attach_element(driver);
480 let element = self.stack.last_mut().unwrap();
481 element.is_map = true;
482 emit_at(
483 driver,
484 Event::MapStart(
485 ContainerShape::new()
486 .with_order(Order::Significant)
487 .with_multimap(true),
488 ),
489 element.start,
490 )?;
491 }
492 self.flush_text(driver)
493 }
494
495 fn flush_text(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
497 let element = self.stack.last_mut().unwrap();
498 if matches!(element.text, PendingText::None)
501 || (element.text.is_blank() && !WhitespaceDepths::applies(driver.state()))
502 {
503 element.text = PendingText::None;
504 return Ok(());
505 }
506 let text = std::mem::replace(&mut element.text, PendingText::None);
507 let range = match text {
508 PendingText::Borrowed(_, range) | PendingText::Owned(_, range) => range,
509 PendingText::None => unreachable!(),
510 };
511 emit_at(
512 driver,
513 Atom::Lexical(Text::borrowed(self.config.names.text_key)),
514 range,
515 )?;
516 text.emit(driver, range)
517 }
518
519 fn start(
520 &mut self,
521 driver: &mut DeserializeDriver<'_, 'a>,
522 tag: &BytesStart<'a>,
523 range: Range,
524 ) -> Result<(), Error> {
525 if self.stack.is_empty() {
526 if self.root_done {
527 return Err(
528 Error::new(ErrorKind::Unexpected, "more than one root element")
529 .with_offset(range.0),
530 );
531 }
532 self.root = Some(self.root_data(tag, range.0)?);
533 } else {
534 self.make_map(driver)?;
535 let name = self.name(tag.name(), false, range.0)?;
536 emit_key(driver, name, range)?;
537 if tag.attributes_raw().contains("xmlns") {
540 let declarations = self.declarations(tag, false, range.0)?;
541 if !declarations.is_empty() {
542 self.declarations = Some(declarations);
543 }
544 }
545 }
546 self.stack.push(Element {
547 is_map: false,
548 text: PendingText::None,
549 start: range,
550 });
551
552 for attr in tag.attributes() {
553 let attr = attr.map_err(|err| {
554 Error::new(ErrorKind::Unexpected, format!("invalid attribute: {err}"))
555 .with_offset(range.0)
556 })?;
557 let raw = attr.key.as_ref();
558 if raw == "xmlns" || raw.starts_with("xmlns:") {
560 continue;
561 }
562 self.make_map(driver)?;
563 let name = self.name(attr.key, true, range.0)?;
564 emit_key(driver, name, range)?;
565 let value = attr
566 .normalized_value(XmlVersion::Implicit1_0)
567 .map_err(|err| xml_error(err, range.0))?;
568 match reborrow(self.input, &value) {
569 Some(value) => {
570 driver.state_mut().set_input_range(range.0, range.1);
571 driver.emit_borrowed(Atom::Lexical(Text::borrowed(value)))?;
572 }
573 None => emit_at(driver, Atom::Lexical(Text::borrowed(&value)), range)?,
574 }
575 }
576 Ok(())
577 }
578
579 fn root_data(&self, tag: &BytesStart<'a>, offset: usize) -> Result<RootData, Error> {
585 Ok(RootData {
586 name: Some(self.name(tag.name(), false, offset)?.into_owned()),
587 namespaces: self.declarations(tag, true, offset)?,
588 })
589 }
590
591 fn declarations(
598 &self,
599 tag: &BytesStart<'a>,
600 is_root: bool,
601 offset: usize,
602 ) -> Result<Vec<(String, String)>, Error> {
603 let mut namespaces: Vec<(String, String)> = Vec::new();
604 for attr in tag.attributes().flatten() {
606 let raw: &str = attr.key.as_ref();
607 let prefix = match raw.strip_prefix("xmlns") {
608 Some("") => "",
609 Some(rest) => match rest.strip_prefix(':') {
610 Some(prefix) => prefix,
611 None => continue,
612 },
613 None => continue,
614 };
615 let uri = attr
616 .normalized_value(XmlVersion::Implicit1_0)
617 .map_err(|err| xml_error(err, offset))?;
618 if uri.is_empty() && (is_root || !prefix.is_empty()) {
619 continue;
620 }
621 let prefix = match self.config.names.namespaces.iter().find(|(_, x)| *x == uri) {
622 Some((alias, _)) => alias,
623 None => prefix,
624 };
625 if !namespaces.iter().any(|(x, _)| x == prefix) {
626 namespaces.push((prefix.to_string(), uri.into_owned()));
627 }
628 }
629 Ok(namespaces)
630 }
631
632 fn attach_element(&mut self, driver: &mut DeserializeDriver<'_, 'a>) {
639 if let Some(root) = self.root.take() {
640 *driver.state_mut().event_mut::<RootData>() = root;
641 }
642 if let Some(declarations) = self.declarations.take() {
643 driver.state_mut().event_mut::<Declarations>().0 = declarations;
644 }
645 }
646
647 fn end(&mut self, driver: &mut DeserializeDriver<'_, 'a>, range: Range) -> Result<(), Error> {
648 if self.stack.last().unwrap().is_map {
649 self.flush_text(driver)?;
650 self.stack.pop();
651 emit_at(driver, Event::MapEnd, range)?;
652 WhitespaceDepths::prune(driver.state_mut());
653 } else {
654 self.attach_element(driver);
655 let element = self.stack.pop().unwrap();
656 element.text.emit(driver, element.start)?;
657 }
658 if self.stack.is_empty() {
659 self.root_done = true;
660 }
661 Ok(())
662 }
663
664 fn text(&mut self, text: Cow<'a, str>, range: Range) -> Result<(), Error> {
665 match self.stack.last_mut() {
666 Some(element) => {
667 element.text.push(text, range);
668 Ok(())
669 }
670 None if is_blank(&text) => Ok(()),
671 None => Err(
672 Error::new(ErrorKind::Unexpected, "text outside of the root element")
673 .with_offset(range.0),
674 ),
675 }
676 }
677
678 fn name(
680 &self,
681 name: QName<'_>,
682 is_attribute: bool,
683 offset: usize,
684 ) -> Result<Cow<'a, str>, Error> {
685 let names = &self.config.names;
686 let written: &str = name.as_ref();
687 let local_name = name.local_name();
688 let local: &str = local_name.as_ref();
689 let mut key = match self.namespace(name, is_attribute) {
690 Namespace::Alias("") => Cow::Owned(local.to_string()),
691 Namespace::Alias(alias) => Cow::Owned(format!("{alias}:{local}")),
692 Namespace::Uri(uri) => Cow::Owned(format!("{{{uri}}}{local}")),
693 Namespace::Unknown if self.config.resolve_namespaces => {
694 return Err(Error::new(
695 ErrorKind::Unexpected,
696 format!("the prefix of `{written}` is not declared"),
697 )
698 .with_offset(offset));
699 }
700 Namespace::Written | Namespace::Unknown => match reborrow(self.input, written) {
701 Some(written) => Cow::Borrowed(written),
702 None => Cow::Owned(written.to_string()),
703 },
704 };
705 if is_attribute && !names.attribute_prefix.is_empty() {
706 key = Cow::Owned(format!("{}{}", names.attribute_prefix, key));
707 }
708 Ok(key)
709 }
710
711 fn namespace(&self, name: QName<'_>, is_attribute: bool) -> Namespace {
713 let namespaces = self.config.names.namespaces;
714 let resolve = self.config.resolve_namespaces;
715 if namespaces.is_empty() && !resolve {
716 return Namespace::Written;
717 }
718 let resolver = self.reader.resolver();
719 let (ns, _) = if is_attribute {
720 resolver.resolve_attribute(name)
721 } else {
722 resolver.resolve_element(name)
723 };
724 match ns {
725 ResolveResult::Bound(ns) => {
726 let uri: &str = ns.as_ref();
727 if let Some((alias, _)) = namespaces.iter().find(|(_, x)| *x == uri) {
728 Namespace::Alias(alias)
729 } else if !resolve {
730 Namespace::Written
731 } else if uri == XML_NAMESPACE {
732 Namespace::Alias("xml")
733 } else {
734 Namespace::Uri(uri.to_string())
735 }
736 }
737 ResolveResult::Unbound => Namespace::Written,
738 ResolveResult::Unknown(_) => Namespace::Unknown,
739 }
740 }
741}
742
743pub(crate) const XML_NAMESPACE: &str = "http://www.w3.org/XML/1998/namespace";
745
746enum Namespace {
748 Written,
750 Alias(&'static str),
752 Uri(String),
754 Unknown,
756}
757
758fn reborrow<'a>(input: &'a str, text: &str) -> Option<&'a str> {
760 let start = (text.as_ptr() as usize).checked_sub(input.as_ptr() as usize)?;
761 let end = start.checked_add(text.len())?;
762 input
763 .get(start..end)
764 .filter(|x| x.as_ptr() == text.as_ptr())
765}
766
767fn resolve_reference(reference: &BytesRef<'_>, offset: usize) -> Result<char, Error> {
772 if let Some(c) = reference
773 .resolve_char_ref()
774 .map_err(|err| xml_error(err, offset))?
775 {
776 return Ok(c);
777 }
778 match &*reference.xml_content(XmlVersion::Implicit1_0) {
779 "lt" => Ok('<'),
780 "gt" => Ok('>'),
781 "amp" => Ok('&'),
782 "apos" => Ok('\''),
783 "quot" => Ok('"'),
784 name => Err(
785 Error::new(ErrorKind::Unexpected, format!("unknown entity `&{name};`"))
786 .with_offset(offset),
787 ),
788 }
789}
790
791fn xml_error(err: quick_xml::Error, offset: usize) -> Error {
792 Error::new(ErrorKind::Unexpected, format!("invalid XML: {err}")).with_offset(offset)
793}
794
795fn emit_key<'a>(
796 driver: &mut DeserializeDriver<'_, 'a>,
797 key: Cow<'a, str>,
798 range: Range,
799) -> Result<(), Error> {
800 driver.state_mut().set_input_range(range.0, range.1);
801 match key {
802 Cow::Borrowed(key) => driver.emit_borrowed(Atom::Lexical(Text::borrowed(key))),
803 Cow::Owned(key) => driver.emit(Atom::Lexical(Text::owned(key))),
804 }
805}
806
807fn emit_at<'e, E: Into<Event<'e>>>(
808 driver: &mut DeserializeDriver<'_, '_>,
809 event: E,
810 range: Range,
811) -> Result<(), Error> {
812 driver.state_mut().set_input_range(range.0, range.1);
813 driver.emit(event)
814}