Implement #[xml(flag)] meta
This commit is contained in:
parent
4eff6303dc
commit
727e57b756
10 changed files with 423 additions and 2 deletions
|
|
@ -27,7 +27,8 @@ assert_eq!(foo, Foo);
|
|||
2. [`child` meta](#child-meta)
|
||||
3. [`element` meta](#element-meta)
|
||||
4. [`extract` meta](#extract-meta)
|
||||
5. [`text` meta](#text-meta)
|
||||
5. [`flag` meta](#flag-meta)
|
||||
6. [`text` meta](#text-meta)
|
||||
|
||||
## Attributes
|
||||
|
||||
|
|
@ -557,6 +558,47 @@ assert_eq!(foo, Foo {
|
|||
});
|
||||
```
|
||||
|
||||
### `flag` meta
|
||||
|
||||
The `flag` meta causes the field to be mapped to a single, optional child element. Absence of the child is equivalent to the value `false`, presence
|
||||
of the child element is equivalent to the value `true`.
|
||||
|
||||
The following keys can be used inside the `#[xml(flag(..))]` meta:
|
||||
|
||||
| Key | Value type | Description |
|
||||
| --- | --- | --- |
|
||||
| `namespace` | *string literal* or *path* | The optional namespace of the XML attribute to match. If it is a *path*, it must point at a `&'static str`. |
|
||||
| `name` | *string literal* or *path* | The name of the XML attribute to match. If it is a *path*, it must point at a `&'static NcNameStr`. |
|
||||
|
||||
The field on which the `flag` meta is used must be of type `bool`.
|
||||
|
||||
If `namespace` is not set, it defaults to the namespace of the surrounding
|
||||
container. If `name` is not set, it defaults to the field's name, if available.
|
||||
If `name` is not set and the field is unnamed, a compile-time error is raised.
|
||||
|
||||
When parsing, any contents within the child element generate a parse error.
|
||||
|
||||
#### Example
|
||||
```rust
|
||||
# use xso::FromXml;
|
||||
#[derive(FromXml, Debug, PartialEq)]
|
||||
#[xml(namespace = "urn:example", name = "foo")]
|
||||
struct Foo {
|
||||
#[xml(flag(name = "flag"))]
|
||||
flag: bool,
|
||||
};
|
||||
|
||||
let foo: Foo = xso::from_bytes(b"<foo xmlns='urn:example'><flag/></foo>").unwrap();
|
||||
assert_eq!(foo, Foo {
|
||||
flag: true,
|
||||
});
|
||||
|
||||
let foo: Foo = xso::from_bytes(b"<foo xmlns='urn:example'/>").unwrap();
|
||||
assert_eq!(foo, Foo {
|
||||
flag: false,
|
||||
});
|
||||
```
|
||||
|
||||
### `text` meta
|
||||
|
||||
The `text` meta causes the field to be mapped to the text content of the
|
||||
|
|
|
|||
|
|
@ -269,6 +269,58 @@ impl FromEventsBuilder for Discard {
|
|||
}
|
||||
}
|
||||
|
||||
/// Builder which discards the contents (or raises on unexpected contents).
|
||||
///
|
||||
/// This builder is only to be used from within the proc macros and is not
|
||||
/// stable, public API.
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "macros")]
|
||||
pub struct EmptyBuilder {
|
||||
childerr: &'static str,
|
||||
texterr: &'static str,
|
||||
}
|
||||
|
||||
#[cfg(feature = "macros")]
|
||||
impl FromEventsBuilder for EmptyBuilder {
|
||||
type Output = ();
|
||||
|
||||
fn feed(&mut self, ev: rxml::Event) -> Result<Option<Self::Output>, Error> {
|
||||
match ev {
|
||||
rxml::Event::EndElement(..) => Ok(Some(())),
|
||||
rxml::Event::StartElement(..) => Err(Error::Other(self.childerr)),
|
||||
rxml::Event::Text(..) => Err(Error::Other(self.texterr)),
|
||||
_ => Err(Error::Other(
|
||||
"unexpected content in supposed-to-be-empty element",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Precursor struct for [`EmptyBuilder`].
|
||||
///
|
||||
/// This struct is only to be used from within the proc macros and is not
|
||||
/// stable, public API.
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "macros")]
|
||||
pub struct Empty {
|
||||
pub attributeerr: &'static str,
|
||||
pub childerr: &'static str,
|
||||
pub texterr: &'static str,
|
||||
}
|
||||
|
||||
#[cfg(feature = "macros")]
|
||||
impl Empty {
|
||||
pub fn start(self, attr: rxml::AttrMap) -> Result<EmptyBuilder, Error> {
|
||||
if attr.len() > 0 {
|
||||
return Err(Error::Other(self.attributeerr));
|
||||
}
|
||||
Ok(EmptyBuilder {
|
||||
childerr: self.childerr,
|
||||
texterr: self.texterr,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -39,10 +39,23 @@ mod rxml_util;
|
|||
pub mod text;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "macros")]
|
||||
pub mod exports {
|
||||
#[cfg(feature = "minidom")]
|
||||
pub use minidom;
|
||||
pub use rxml;
|
||||
|
||||
/// The built-in `bool` type.
|
||||
///
|
||||
/// This is re-exported for use by macros in cases where we cannot rely on
|
||||
/// people not having done `type bool = str` or some similar shenanigans.
|
||||
pub type CoreBool = bool;
|
||||
|
||||
/// The built-in `u8` type.
|
||||
///
|
||||
/// This is re-exported for use by macros in cases where we cannot rely on
|
||||
/// people not having done `type u8 = str` or some similar shenanigans.
|
||||
pub type CoreU8 = u8;
|
||||
}
|
||||
|
||||
use alloc::{
|
||||
|
|
|
|||
Loading…
Reference in a new issue