xso: add support for post-deserialization callback
This commit is contained in:
parent
da219d4fed
commit
8e81c41f59
8 changed files with 193 additions and 1 deletions
|
|
@ -2299,3 +2299,140 @@ fn discard_text_absent_roundtrip() {
|
||||||
};
|
};
|
||||||
roundtrip_full::<DiscardText>("<foo xmlns='urn:example:ns1'/>");
|
roundtrip_full::<DiscardText>("<foo xmlns='urn:example:ns1'/>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn transform_test_struct(
|
||||||
|
v: &mut DeserializeCallback,
|
||||||
|
) -> ::core::result::Result<(), ::xso::error::Error> {
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use core::{
|
||||||
|
option::Option::{None, Some},
|
||||||
|
result::Result::{Err, Ok},
|
||||||
|
};
|
||||||
|
use xso::error::Error;
|
||||||
|
if v.outcome == 0 {
|
||||||
|
return Err(Error::Other("saw outcome == 0"));
|
||||||
|
}
|
||||||
|
if v.outcome == 1 {
|
||||||
|
v.outcome = 0;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
||||||
|
#[xml(namespace = NS1, name = "foo", deserialize_callback = transform_test_struct)]
|
||||||
|
struct DeserializeCallback {
|
||||||
|
#[xml(attribute)]
|
||||||
|
outcome: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_callback_roundtrip() {
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use core::{
|
||||||
|
option::Option::{None, Some},
|
||||||
|
result::Result::{Err, Ok},
|
||||||
|
};
|
||||||
|
roundtrip_full::<DeserializeCallback>("<foo xmlns='urn:example:ns1' outcome='2'/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_callback_can_mutate() {
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use core::{
|
||||||
|
option::Option::{None, Some},
|
||||||
|
result::Result::{Err, Ok},
|
||||||
|
};
|
||||||
|
match parse_str::<DeserializeCallback>("<foo xmlns='urn:example:ns1' outcome='1'/>") {
|
||||||
|
Ok(DeserializeCallback { outcome }) => {
|
||||||
|
assert_eq!(outcome, 0);
|
||||||
|
}
|
||||||
|
other => panic!("unexpected result: {:?}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_callback_can_fail() {
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use core::{
|
||||||
|
option::Option::{None, Some},
|
||||||
|
result::Result::{Err, Ok},
|
||||||
|
};
|
||||||
|
match parse_str::<DeserializeCallback>("<foo xmlns='urn:example:ns1' outcome='0'/>") {
|
||||||
|
Err(xso::error::FromElementError::Invalid(xso::error::Error::Other(e))) => {
|
||||||
|
assert_eq!(e, "saw outcome == 0");
|
||||||
|
}
|
||||||
|
other => panic!("unexpected result: {:?}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform_test_enum(
|
||||||
|
v: &mut DeserializeCallbackEnum,
|
||||||
|
) -> ::core::result::Result<(), ::xso::error::Error> {
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use core::{
|
||||||
|
option::Option::{None, Some},
|
||||||
|
result::Result::{Err, Ok},
|
||||||
|
};
|
||||||
|
use xso::error::Error;
|
||||||
|
match v {
|
||||||
|
DeserializeCallbackEnum::Foo { ref mut outcome } => {
|
||||||
|
if *outcome == 0 {
|
||||||
|
return Err(Error::Other("saw outcome == 0"));
|
||||||
|
}
|
||||||
|
if *outcome == 1 {
|
||||||
|
*outcome = 0;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
||||||
|
#[xml(namespace = NS1, deserialize_callback = transform_test_enum)]
|
||||||
|
enum DeserializeCallbackEnum {
|
||||||
|
#[xml(name = "foo")]
|
||||||
|
Foo {
|
||||||
|
#[xml(attribute)]
|
||||||
|
outcome: u32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn enum_deserialize_callback_roundtrip() {
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use core::{
|
||||||
|
option::Option::{None, Some},
|
||||||
|
result::Result::{Err, Ok},
|
||||||
|
};
|
||||||
|
roundtrip_full::<DeserializeCallbackEnum>("<foo xmlns='urn:example:ns1' outcome='2'/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn enum_deserialize_callback_can_mutate() {
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use core::{
|
||||||
|
option::Option::{None, Some},
|
||||||
|
result::Result::{Err, Ok},
|
||||||
|
};
|
||||||
|
match parse_str::<DeserializeCallbackEnum>("<foo xmlns='urn:example:ns1' outcome='1'/>") {
|
||||||
|
Ok(DeserializeCallbackEnum::Foo { outcome }) => {
|
||||||
|
assert_eq!(outcome, 0);
|
||||||
|
}
|
||||||
|
other => panic!("unexpected result: {:?}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn enum_deserialize_callback_can_fail() {
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use core::{
|
||||||
|
option::Option::{None, Some},
|
||||||
|
result::Result::{Err, Ok},
|
||||||
|
};
|
||||||
|
match parse_str::<DeserializeCallbackEnum>("<foo xmlns='urn:example:ns1' outcome='0'/>") {
|
||||||
|
Err(xso::error::FromElementError::Invalid(xso::error::Error::Other(e))) => {
|
||||||
|
assert_eq!(e, "saw outcome == 0");
|
||||||
|
}
|
||||||
|
other => panic!("unexpected result: {:?}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ impl NameVariant {
|
||||||
on_unknown_child,
|
on_unknown_child,
|
||||||
transparent,
|
transparent,
|
||||||
discard,
|
discard,
|
||||||
|
deserialize_callback,
|
||||||
} = XmlCompoundMeta::parse_from_attributes(&decl.attrs)?;
|
} = XmlCompoundMeta::parse_from_attributes(&decl.attrs)?;
|
||||||
|
|
||||||
reject_key!(debug flag not on "enum variants" only on "enums and structs");
|
reject_key!(debug flag not on "enum variants" only on "enums and structs");
|
||||||
|
|
@ -58,6 +59,7 @@ impl NameVariant {
|
||||||
reject_key!(builder not on "enum variants" only on "enums and structs");
|
reject_key!(builder not on "enum variants" only on "enums and structs");
|
||||||
reject_key!(iterator not on "enum variants" only on "enums and structs");
|
reject_key!(iterator not on "enum variants" only on "enums and structs");
|
||||||
reject_key!(transparent flag not on "named enum variants" only on "structs");
|
reject_key!(transparent flag not on "named enum variants" only on "structs");
|
||||||
|
reject_key!(deserialize_callback not on "enum variants" only on "enums and structs");
|
||||||
|
|
||||||
let Some(name) = name else {
|
let Some(name) = name else {
|
||||||
return Err(Error::new(meta_span, "`name` is required on enum variants"));
|
return Err(Error::new(meta_span, "`name` is required on enum variants"));
|
||||||
|
|
@ -278,12 +280,14 @@ impl DynamicVariant {
|
||||||
on_unknown_child: _, // used by StructInner
|
on_unknown_child: _, // used by StructInner
|
||||||
transparent: _, // used by StructInner
|
transparent: _, // used by StructInner
|
||||||
discard: _, // used by StructInner
|
discard: _, // used by StructInner
|
||||||
|
ref deserialize_callback,
|
||||||
} = meta;
|
} = meta;
|
||||||
|
|
||||||
reject_key!(debug flag not on "enum variants" only on "enums and structs");
|
reject_key!(debug flag not on "enum variants" only on "enums and structs");
|
||||||
reject_key!(exhaustive flag not on "enum variants" only on "enums");
|
reject_key!(exhaustive flag not on "enum variants" only on "enums");
|
||||||
reject_key!(builder not on "enum variants" only on "enums and structs");
|
reject_key!(builder not on "enum variants" only on "enums and structs");
|
||||||
reject_key!(iterator not on "enum variants" only on "enums and structs");
|
reject_key!(iterator not on "enum variants" only on "enums and structs");
|
||||||
|
reject_key!(deserialize_callback not on "enum variants" only on "enums and structs");
|
||||||
|
|
||||||
let inner = StructInner::new(meta, &variant.fields)?;
|
let inner = StructInner::new(meta, &variant.fields)?;
|
||||||
Ok(Self { ident, inner })
|
Ok(Self { ident, inner })
|
||||||
|
|
@ -395,6 +399,7 @@ impl EnumInner {
|
||||||
on_unknown_child,
|
on_unknown_child,
|
||||||
transparent,
|
transparent,
|
||||||
discard,
|
discard,
|
||||||
|
deserialize_callback,
|
||||||
} = meta;
|
} = meta;
|
||||||
|
|
||||||
// These must've been cleared by the caller. Because these being set
|
// These must've been cleared by the caller. Because these being set
|
||||||
|
|
@ -403,6 +408,7 @@ impl EnumInner {
|
||||||
assert!(builder.is_none());
|
assert!(builder.is_none());
|
||||||
assert!(iterator.is_none());
|
assert!(iterator.is_none());
|
||||||
assert!(!debug.is_set());
|
assert!(!debug.is_set());
|
||||||
|
assert!(deserialize_callback.is_none());
|
||||||
|
|
||||||
reject_key!(name not on "enums" only on "their variants");
|
reject_key!(name not on "enums" only on "their variants");
|
||||||
reject_key!(transparent flag not on "enums" only on "structs");
|
reject_key!(transparent flag not on "enums" only on "structs");
|
||||||
|
|
@ -476,6 +482,9 @@ pub(crate) struct EnumDef {
|
||||||
|
|
||||||
/// Flag whether debug mode is enabled.
|
/// Flag whether debug mode is enabled.
|
||||||
debug: bool,
|
debug: bool,
|
||||||
|
|
||||||
|
/// Optional validator function to call.
|
||||||
|
deserialize_callback: Option<Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumDef {
|
impl EnumDef {
|
||||||
|
|
@ -496,6 +505,7 @@ impl EnumDef {
|
||||||
};
|
};
|
||||||
|
|
||||||
let debug = meta.debug.take().is_set();
|
let debug = meta.debug.take().is_set();
|
||||||
|
let deserialize_callback = meta.deserialize_callback.take();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: EnumInner::new(meta, variant_iter)?,
|
inner: EnumInner::new(meta, variant_iter)?,
|
||||||
|
|
@ -503,6 +513,7 @@ impl EnumDef {
|
||||||
builder_ty_ident,
|
builder_ty_ident,
|
||||||
item_iter_ty_ident,
|
item_iter_ty_ident,
|
||||||
debug,
|
debug,
|
||||||
|
deserialize_callback,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -530,6 +541,7 @@ impl ItemDef for EnumDef {
|
||||||
path: target_ty_ident.clone().into(),
|
path: target_ty_ident.clone().into(),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
|
self.deserialize_callback.as_ref(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(FromXmlParts {
|
Ok(FromXmlParts {
|
||||||
|
|
|
||||||
|
|
@ -303,6 +303,7 @@ impl ExtractDef {
|
||||||
&from_xml_builder_ty_ident,
|
&from_xml_builder_ty_ident,
|
||||||
&state_ty_ident,
|
&state_ty_ident,
|
||||||
&self.parts.to_tuple_ty().into(),
|
&self.parts.to_tuple_ty().into(),
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
let from_xml_builder_ty = ty_from_ident(from_xml_builder_ty_ident.clone()).into();
|
let from_xml_builder_ty = ty_from_ident(from_xml_builder_ty_ident.clone()).into();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -447,6 +447,9 @@ pub(crate) struct XmlCompoundMeta {
|
||||||
|
|
||||||
/// Items to discard.
|
/// Items to discard.
|
||||||
pub(crate) discard: Vec<DiscardSpec>,
|
pub(crate) discard: Vec<DiscardSpec>,
|
||||||
|
|
||||||
|
/// The value assigned to `deserialize_callback` inside `#[xml(..)]`, if any.
|
||||||
|
pub(crate) deserialize_callback: Option<Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XmlCompoundMeta {
|
impl XmlCompoundMeta {
|
||||||
|
|
@ -464,6 +467,7 @@ impl XmlCompoundMeta {
|
||||||
let mut exhaustive = Flag::Absent;
|
let mut exhaustive = Flag::Absent;
|
||||||
let mut transparent = Flag::Absent;
|
let mut transparent = Flag::Absent;
|
||||||
let mut discard = Vec::new();
|
let mut discard = Vec::new();
|
||||||
|
let mut deserialize_callback = None;
|
||||||
|
|
||||||
attr.parse_nested_meta(|meta| {
|
attr.parse_nested_meta(|meta| {
|
||||||
if meta.path.is_ident("debug") {
|
if meta.path.is_ident("debug") {
|
||||||
|
|
@ -520,6 +524,15 @@ impl XmlCompoundMeta {
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else if meta.path.is_ident("deserialize_callback") {
|
||||||
|
if deserialize_callback.is_some() {
|
||||||
|
return Err(Error::new_spanned(
|
||||||
|
meta.path,
|
||||||
|
"duplicate `deserialize_callback` key",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
deserialize_callback = Some(meta.value()?.parse()?);
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
match qname.parse_incremental_from_meta(meta)? {
|
match qname.parse_incremental_from_meta(meta)? {
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
|
|
@ -539,6 +552,7 @@ impl XmlCompoundMeta {
|
||||||
exhaustive,
|
exhaustive,
|
||||||
transparent,
|
transparent,
|
||||||
discard,
|
discard,
|
||||||
|
deserialize_callback,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -456,6 +456,7 @@ impl FromEventsStateMachine {
|
||||||
builder_ty_ident: &Ident,
|
builder_ty_ident: &Ident,
|
||||||
state_ty_ident: &Ident,
|
state_ty_ident: &Ident,
|
||||||
output_ty: &Type,
|
output_ty: &Type,
|
||||||
|
validate_fn: Option<&Path>,
|
||||||
) -> Result<TokenStream> {
|
) -> Result<TokenStream> {
|
||||||
let Self {
|
let Self {
|
||||||
defs,
|
defs,
|
||||||
|
|
@ -488,6 +489,18 @@ impl FromEventsStateMachine {
|
||||||
|
|
||||||
let docstr = format!("Build a {0} from XML events.\n\nThis type is generated using the [`macro@xso::FromXml`] derive macro and implements [`xso::FromEventsBuilder`] for {0}.", output_ty_ref);
|
let docstr = format!("Build a {0} from XML events.\n\nThis type is generated using the [`macro@xso::FromXml`] derive macro and implements [`xso::FromEventsBuilder`] for {0}.", output_ty_ref);
|
||||||
|
|
||||||
|
let validate_call = match validate_fn {
|
||||||
|
None => quote! {
|
||||||
|
// needed to avoid unused_mut warning.
|
||||||
|
let _ = &mut value;
|
||||||
|
},
|
||||||
|
Some(validate_fn) => {
|
||||||
|
quote! {
|
||||||
|
#validate_fn(&mut value)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#defs
|
#defs
|
||||||
|
|
||||||
|
|
@ -529,7 +542,10 @@ impl FromEventsStateMachine {
|
||||||
fn feed(&mut self, ev: ::xso::exports::rxml::Event) -> ::core::result::Result<::core::option::Option<Self::Output>, ::xso::error::Error> {
|
fn feed(&mut self, ev: ::xso::exports::rxml::Event) -> ::core::result::Result<::core::option::Option<Self::Output>, ::xso::error::Error> {
|
||||||
let inner = self.0.take().expect("feed called after completion");
|
let inner = self.0.take().expect("feed called after completion");
|
||||||
match inner.advance(ev)? {
|
match inner.advance(ev)? {
|
||||||
::core::ops::ControlFlow::Continue(value) => ::core::result::Result::Ok(::core::option::Option::Some(value)),
|
::core::ops::ControlFlow::Continue(mut value) => {
|
||||||
|
#validate_call
|
||||||
|
::core::result::Result::Ok(::core::option::Option::Some(value))
|
||||||
|
}
|
||||||
::core::ops::ControlFlow::Break(st) => {
|
::core::ops::ControlFlow::Break(st) => {
|
||||||
self.0 = ::core::option::Option::Some(st);
|
self.0 = ::core::option::Option::Some(st);
|
||||||
::core::result::Result::Ok(::core::option::Option::None)
|
::core::result::Result::Ok(::core::option::Option::None)
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ impl StructInner {
|
||||||
on_unknown_child,
|
on_unknown_child,
|
||||||
transparent,
|
transparent,
|
||||||
discard,
|
discard,
|
||||||
|
deserialize_callback,
|
||||||
} = meta;
|
} = meta;
|
||||||
|
|
||||||
// These must've been cleared by the caller. Because these being set
|
// These must've been cleared by the caller. Because these being set
|
||||||
|
|
@ -81,6 +82,7 @@ impl StructInner {
|
||||||
assert!(builder.is_none());
|
assert!(builder.is_none());
|
||||||
assert!(iterator.is_none());
|
assert!(iterator.is_none());
|
||||||
assert!(!debug.is_set());
|
assert!(!debug.is_set());
|
||||||
|
assert!(deserialize_callback.is_none());
|
||||||
|
|
||||||
reject_key!(exhaustive flag not on "structs" only on "enums");
|
reject_key!(exhaustive flag not on "structs" only on "enums");
|
||||||
|
|
||||||
|
|
@ -322,6 +324,9 @@ pub(crate) struct StructDef {
|
||||||
|
|
||||||
/// The matching logic and contents of the struct.
|
/// The matching logic and contents of the struct.
|
||||||
inner: StructInner,
|
inner: StructInner,
|
||||||
|
|
||||||
|
/// Optional validator function to call.
|
||||||
|
deserialize_callback: Option<Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructDef {
|
impl StructDef {
|
||||||
|
|
@ -338,6 +343,7 @@ impl StructDef {
|
||||||
};
|
};
|
||||||
|
|
||||||
let debug = meta.debug.take();
|
let debug = meta.debug.take();
|
||||||
|
let deserialize_callback = meta.deserialize_callback.take();
|
||||||
|
|
||||||
let inner = StructInner::new(meta, fields)?;
|
let inner = StructInner::new(meta, fields)?;
|
||||||
|
|
||||||
|
|
@ -347,6 +353,7 @@ impl StructDef {
|
||||||
builder_ty_ident,
|
builder_ty_ident,
|
||||||
item_iter_ty_ident,
|
item_iter_ty_ident,
|
||||||
debug: debug.is_set(),
|
debug: debug.is_set(),
|
||||||
|
deserialize_callback,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -379,6 +386,7 @@ impl ItemDef for StructDef {
|
||||||
path: target_ty_ident.clone().into(),
|
path: target_ty_ident.clone().into(),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
|
self.deserialize_callback.as_ref(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(FromXmlParts {
|
Ok(FromXmlParts {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ Version NEXT:
|
||||||
parsing (!552).
|
parsing (!552).
|
||||||
- Implement `AsXml` and `FromXml` for serde_json::Value` behind
|
- Implement `AsXml` and `FromXml` for serde_json::Value` behind
|
||||||
`serde_json` feature.
|
`serde_json` feature.
|
||||||
|
- Support for a post-deserialization callback function call. (!553)
|
||||||
* Changes
|
* Changes
|
||||||
- Generated AsXml iterator and FromXml builder types are now
|
- Generated AsXml iterator and FromXml builder types are now
|
||||||
doc(hidden), to not clutter hand-written documentation with auto
|
doc(hidden), to not clutter hand-written documentation with auto
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ The following keys are defined on structs:
|
||||||
| `on_unknown_attribute` | optional *ident* | Name of an [`UnknownAttributePolicy`] member, controlling how unknown attributes are handled. |
|
| `on_unknown_attribute` | optional *ident* | Name of an [`UnknownAttributePolicy`] member, controlling how unknown attributes are handled. |
|
||||||
| `on_unknown_child` | optional *ident* | Name of an [`UnknownChildPolicy`] member, controlling how unknown children are handled. |
|
| `on_unknown_child` | optional *ident* | Name of an [`UnknownChildPolicy`] member, controlling how unknown children are handled. |
|
||||||
| `discard` | optional *nested* | Contains field specifications of content to ignore. See below for details. |
|
| `discard` | optional *nested* | Contains field specifications of content to ignore. See below for details. |
|
||||||
|
| `deserialize_callback` | optional *path* | Path to a `fn(&mut T) -> Result<(), Error>` which is called on the deserialized struct after deserialization. |
|
||||||
|
|
||||||
Note that the `name` value must be a valid XML element name, without colons.
|
Note that the `name` value must be a valid XML element name, without colons.
|
||||||
The namespace prefix, if any, is assigned automatically at serialisation time
|
The namespace prefix, if any, is assigned automatically at serialisation time
|
||||||
|
|
@ -142,6 +143,7 @@ The following keys are defined on name-switched enums:
|
||||||
| `iterator` | optional *ident* | The name to use for the generated iterator type. |
|
| `iterator` | optional *ident* | The name to use for the generated iterator type. |
|
||||||
| `exhaustive` | *flag* | If present, the enum considers itself authoritative for its namespace; unknown elements within the namespace are rejected instead of treated as mismatch. |
|
| `exhaustive` | *flag* | If present, the enum considers itself authoritative for its namespace; unknown elements within the namespace are rejected instead of treated as mismatch. |
|
||||||
| `discard` | optional *nested* | Contains field specifications of content to ignore. See the struct meta docs for details. |
|
| `discard` | optional *nested* | Contains field specifications of content to ignore. See the struct meta docs for details. |
|
||||||
|
| `deserialize_callback` | optional *path* | Path to a `fn(&mut T) -> Result<(), Error>` which is called on the deserialized enum after deserialization. |
|
||||||
|
|
||||||
All variants of a name-switched enum live within the same namespace and are
|
All variants of a name-switched enum live within the same namespace and are
|
||||||
distinguished exclusively by their XML name within that namespace. The
|
distinguished exclusively by their XML name within that namespace. The
|
||||||
|
|
@ -211,6 +213,7 @@ The following keys are defined on dynamic enums:
|
||||||
| `builder` | optional *ident* | The name to use for the generated builder type. |
|
| `builder` | optional *ident* | The name to use for the generated builder type. |
|
||||||
| `iterator` | optional *ident* | The name to use for the generated iterator type. |
|
| `iterator` | optional *ident* | The name to use for the generated iterator type. |
|
||||||
| `discard` | optional *nested* | Contains field specifications of content to ignore. See the struct meta docs for details. |
|
| `discard` | optional *nested* | Contains field specifications of content to ignore. See the struct meta docs for details. |
|
||||||
|
| `deserialize_callback` | optional *path* | Path to a `fn(&mut T) -> Result<(), Error>` which is called on the deserialized enum after deserialization. |
|
||||||
|
|
||||||
For details on `builder` and `iterator`, see the [Struct meta](#struct-meta)
|
For details on `builder` and `iterator`, see the [Struct meta](#struct-meta)
|
||||||
documentation above.
|
documentation above.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue