Skip to content

Commit 9cdf930

Browse files
authored
feat: Adds external data support to deserialization process. (#116)
* feat(core)!: Adds external data support to deserialization. * Improved external data API for `xmlity-quick-xml`. * Changed from `Arc<ExternalData>` to `Rc<ExternalData>`. * `cargo clippy`
1 parent eb692a7 commit 9cdf930

File tree

7 files changed

+126
-62
lines changed

7 files changed

+126
-62
lines changed

xmlity-derive/src/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ impl FieldIdent {
3232
impl fmt::Display for FieldIdent {
3333
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3434
match self {
35-
FieldIdent::Named(ident) => write!(f, "{}", ident),
35+
FieldIdent::Named(ident) => write!(f, "{ident}"),
3636
FieldIdent::Indexed(index) => write!(f, "{}", index.index),
3737
}
3838
}

xmlity-quick-xml/src/de.rs

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// The [`xmlity::de::Deserializer`] implementation for the `quick-xml` crate.
22
///
33
/// This deserializer is based upon the [`quick_xml::NsReader`] with the same limits as the underlying reader, including requiring a `[u8]` backing.
4-
use std::{borrow::Cow, ops::Deref};
4+
use std::{borrow::Cow, collections::HashMap, ops::Deref, rc::Rc};
55

66
use quick_xml::{
77
events::{attributes::Attribute, BytesCData, BytesDecl, BytesPI, BytesStart, BytesText, Event},
@@ -11,7 +11,7 @@ use quick_xml::{
1111

1212
use xmlity::{
1313
de::{
14-
self, Error as _, NamespaceContext, Visitor, XmlCData, XmlComment, XmlDeclaration,
14+
self, DeserializeContext, Error as _, Visitor, XmlCData, XmlComment, XmlDeclaration,
1515
XmlDoctype, XmlProcessingInstruction, XmlText,
1616
},
1717
Deserialize, ExpandedName, LocalName, XmlNamespace,
@@ -202,6 +202,42 @@ impl<'i> Reader<'i> {
202202
}
203203
}
204204

205+
/// A struct to hold external data that can be used during deserialization.
206+
#[derive(Debug)]
207+
pub struct ExternalData {
208+
data: HashMap<core::any::TypeId, Box<dyn core::any::Any>>,
209+
}
210+
211+
impl ExternalData {
212+
/// Creates a new [`ExternalData`] instance.
213+
pub fn new() -> Self {
214+
Self {
215+
data: HashMap::new(),
216+
}
217+
}
218+
219+
/// Inserts data into the external data map.
220+
pub fn insert<T: 'static>(&mut self, data: T) {
221+
self.data.insert(
222+
core::any::TypeId::of::<T>(),
223+
Box::new(data) as Box<dyn core::any::Any>,
224+
);
225+
}
226+
227+
/// Retrieves data from the external data map.
228+
pub fn get<T: 'static>(&self) -> Option<&T> {
229+
self.data
230+
.get(&core::any::TypeId::of::<T>())
231+
.and_then(|data| data.downcast_ref::<T>())
232+
}
233+
}
234+
235+
impl Default for ExternalData {
236+
fn default() -> Self {
237+
Self::new()
238+
}
239+
}
240+
205241
/// The [`xmlity::Deserializer`] for the `quick-xml` crate.
206242
///
207243
/// This currently only supports an underlying reader of type `&[u8]` due to limitations in the `quick-xml` crate.
@@ -210,6 +246,7 @@ pub struct Deserializer<'i> {
210246
reader: Reader<'i>,
211247
// Limit depth
212248
limit_depth: i16,
249+
external_data: Option<Rc<ExternalData>>,
213250
}
214251

215252
impl<'i> From<NsReader<&'i [u8]>> for Deserializer<'i> {
@@ -230,9 +267,16 @@ impl<'i> Deserializer<'i> {
230267
Self {
231268
reader: Reader::new(reader),
232269
limit_depth: 0,
270+
external_data: None,
233271
}
234272
}
235273

274+
/// Set the external data for the deserializer.
275+
pub fn with_external_data(mut self, external_data: ExternalData) -> Self {
276+
self.external_data = Some(Rc::new(external_data));
277+
self
278+
}
279+
236280
fn read_until_end(&mut self) -> Result<(), Error> {
237281
while let Some(event) = self.next_event() {
238282
debug_assert!(!matches!(event, Event::Eof));
@@ -281,6 +325,7 @@ impl<'i> Deserializer<'i> {
281325
Self {
282326
reader: self.reader.clone(),
283327
limit_depth,
328+
external_data: self.external_data.clone(),
284329
}
285330
}
286331

@@ -315,7 +360,7 @@ impl<'r> ElementAccess<'_, 'r> {
315360

316361
const PLACEHOLDER_ELEMENT_NAME: &str = "a";
317362

318-
impl NamespaceContext for &Deserializer<'_> {
363+
impl DeserializeContext for &Deserializer<'_> {
319364
fn default_namespace(&self) -> Option<XmlNamespace<'_>> {
320365
let (_, namespace) = self
321366
.resolve_qname(QuickName(PLACEHOLDER_ELEMENT_NAME.as_bytes()), false)
@@ -332,6 +377,13 @@ impl NamespaceContext for &Deserializer<'_> {
332377

333378
namespace.map(XmlNamespace::into_owned)
334379
}
380+
381+
fn external_data<T>(&self) -> Option<&T>
382+
where
383+
T: core::any::Any,
384+
{
385+
self.external_data.as_ref().and_then(|data| data.get::<T>())
386+
}
335387
}
336388

337389
struct AttributeAccess<'a, 'v> {
@@ -367,7 +419,7 @@ struct TextDeserializer<'a, 'v> {
367419
}
368420

369421
impl<'de> de::XmlText<'de> for TextDeserializer<'_, 'de> {
370-
type NamespaceContext<'a>
422+
type DeserializeContext<'a>
371423
= &'a Deserializer<'a>
372424
where
373425
Self: 'a;
@@ -391,7 +443,7 @@ impl<'de> de::XmlText<'de> for TextDeserializer<'_, 'de> {
391443
std::str::from_utf8(self.value.as_ref()).unwrap()
392444
}
393445

394-
fn namespace_context(&self) -> Self::NamespaceContext<'_> {
446+
fn context(&self) -> Self::DeserializeContext<'_> {
395447
self.deserializer
396448
}
397449
}
@@ -617,7 +669,7 @@ impl<'de> de::AttributesAccess<'de> for ElementAccess<'_, 'de> {
617669

618670
impl<'a, 'de> de::ElementAccess<'de> for ElementAccess<'a, 'de> {
619671
type ChildrenAccess = SeqAccess<'a, 'de>;
620-
type NamespaceContext<'b>
672+
type DeserializeContext<'b>
621673
= &'b Deserializer<'de>
622674
where
623675
Self: 'b;
@@ -646,7 +698,7 @@ impl<'a, 'de> de::ElementAccess<'de> for ElementAccess<'a, 'de> {
646698
})
647699
}
648700

649-
fn namespace_context(&self) -> Self::NamespaceContext<'_> {
701+
fn context(&self) -> Self::DeserializeContext<'_> {
650702
self.deserializer()
651703
}
652704
}
@@ -757,7 +809,7 @@ impl<'a, T> DataWithD<'a, T> {
757809
}
758810

759811
impl<'de> XmlText<'de> for DataWithD<'_, BytesText<'de>> {
760-
type NamespaceContext<'a>
812+
type DeserializeContext<'a>
761813
= &'a Deserializer<'a>
762814
where
763815
Self: 'a;
@@ -781,13 +833,13 @@ impl<'de> XmlText<'de> for DataWithD<'_, BytesText<'de>> {
781833
std::str::from_utf8(self.data.deref()).unwrap()
782834
}
783835

784-
fn namespace_context(&self) -> Self::NamespaceContext<'_> {
836+
fn context(&self) -> Self::DeserializeContext<'_> {
785837
self.deserializer
786838
}
787839
}
788840

789841
impl<'de> XmlCData<'de> for DataWithD<'_, BytesCData<'de>> {
790-
type NamespaceContext<'a>
842+
type DeserializeContext<'a>
791843
= &'a Deserializer<'a>
792844
where
793845
Self: 'a;
@@ -811,13 +863,13 @@ impl<'de> XmlCData<'de> for DataWithD<'_, BytesCData<'de>> {
811863
std::str::from_utf8(self.data.deref()).unwrap()
812864
}
813865

814-
fn namespace_context(&self) -> Self::NamespaceContext<'_> {
866+
fn context(&self) -> Self::DeserializeContext<'_> {
815867
self.deserializer
816868
}
817869
}
818870

819871
impl<'de> XmlComment<'de> for DataWithD<'_, BytesText<'de>> {
820-
type NamespaceContext<'a>
872+
type DeserializeContext<'a>
821873
= &'a Deserializer<'a>
822874
where
823875
Self: 'a;
@@ -830,7 +882,7 @@ impl<'de> XmlComment<'de> for DataWithD<'_, BytesText<'de>> {
830882
self.data.deref()
831883
}
832884

833-
fn namespace_context(&self) -> Self::NamespaceContext<'_> {
885+
fn context(&self) -> Self::DeserializeContext<'_> {
834886
self.deserializer
835887
}
836888
}
@@ -862,7 +914,7 @@ impl<'a> TryFrom<&'a BytesDecl<'a>> for ClearedByteDecl<'a> {
862914
}
863915

864916
impl XmlDeclaration for DataWithD<'_, ClearedByteDecl<'_>> {
865-
type NamespaceContext<'a>
917+
type DeserializeContext<'a>
866918
= &'a Deserializer<'a>
867919
where
868920
Self: 'a;
@@ -879,13 +931,13 @@ impl XmlDeclaration for DataWithD<'_, ClearedByteDecl<'_>> {
879931
self.data.standalone.as_deref()
880932
}
881933

882-
fn namespace_context(&self) -> Self::NamespaceContext<'_> {
934+
fn context(&self) -> Self::DeserializeContext<'_> {
883935
self.deserializer
884936
}
885937
}
886938

887939
impl XmlProcessingInstruction for DataWithD<'_, BytesPI<'_>> {
888-
type NamespaceContext<'a>
940+
type DeserializeContext<'a>
889941
= &'a Deserializer<'a>
890942
where
891943
Self: 'a;
@@ -898,13 +950,13 @@ impl XmlProcessingInstruction for DataWithD<'_, BytesPI<'_>> {
898950
self.data.content()
899951
}
900952

901-
fn namespace_context(&self) -> Self::NamespaceContext<'_> {
953+
fn context(&self) -> Self::DeserializeContext<'_> {
902954
self.deserializer
903955
}
904956
}
905957

906958
impl<'de> XmlDoctype<'de> for DataWithD<'_, BytesText<'de>> {
907-
type NamespaceContext<'a>
959+
type DeserializeContext<'a>
908960
= &'a Deserializer<'a>
909961
where
910962
Self: 'a;
@@ -917,7 +969,7 @@ impl<'de> XmlDoctype<'de> for DataWithD<'_, BytesText<'de>> {
917969
self.data.deref()
918970
}
919971

920-
fn namespace_context(&self) -> Self::NamespaceContext<'_> {
972+
fn context(&self) -> Self::DeserializeContext<'_> {
921973
self.deserializer
922974
}
923975
}

xmlity-quick-xml/src/ser.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub enum Error {
3737

3838
impl xmlity::ser::Error for Error {
3939
fn unexpected_serialize(unexpected: ser::Unexpected) -> Self {
40-
Error::Custom(format!("Unexpected serialize: {:?}", unexpected))
40+
Error::Custom(format!("Unexpected serialize: {unexpected:?}"))
4141
}
4242

4343
fn custom<T: ToString>(msg: T) -> Self {

xmlity-quick-xml/tests/elements/namespace_access.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use xmlity::de::NamespaceContext;
1+
use xmlity::de::DeserializeContext;
22

33
use crate::define_deserialize_test;
44
use xmlity::XmlNamespace;
@@ -24,7 +24,7 @@ impl<'de> Deserialize<'de> for InternalReference {
2424
})?;
2525

2626
let namespace = value
27-
.namespace_context()
27+
.context()
2828
.resolve_prefix(prefix.as_ref())
2929
.ok_or_else(|| E::custom(format!("Prefix {prefix:?} is not defined")))?
3030
.into_owned();
@@ -72,7 +72,7 @@ impl<'de> Deserialize<'de> for DefaultNamespace {
7272
V: xmlity::de::XmlText<'de>,
7373
{
7474
let namespace = value
75-
.namespace_context()
75+
.context()
7676
.default_namespace()
7777
.map(XmlNamespace::into_owned);
7878

0 commit comments

Comments
 (0)