xso: extend the documentation overall
Sprinkling it with examples, adding more words to make things (hopefully) clearer, using a similar structure for different items etc. etc.
This commit is contained in:
parent
cffb5e7e65
commit
341d49fecf
2 changed files with 159 additions and 13 deletions
164
xso/src/lib.rs
164
xso/src/lib.rs
|
|
@ -342,6 +342,13 @@ impl AsXmlText for str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsXmlText for &str {
|
||||||
|
/// Return the borrowed string contents.
|
||||||
|
fn as_xml_text(&self) -> Result<Cow<'_, str>, self::error::Error> {
|
||||||
|
Ok(Cow::Borrowed(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: AsXmlText> AsXmlText for Box<T> {
|
impl<T: AsXmlText> AsXmlText for Box<T> {
|
||||||
/// Return the borrowed [`Box`] contents.
|
/// Return the borrowed [`Box`] contents.
|
||||||
fn as_xml_text(&self) -> Result<Cow<'_, str>, self::error::Error> {
|
fn as_xml_text(&self) -> Result<Cow<'_, str>, self::error::Error> {
|
||||||
|
|
@ -398,7 +405,7 @@ impl<T: AsXmlText> AsOptionalXmlText for Option<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Control how unknown attributes are handled.
|
/// # Control how unknown attributes are handled
|
||||||
///
|
///
|
||||||
/// The variants of this enum are referenced in the
|
/// The variants of this enum are referenced in the
|
||||||
/// `#[xml(on_unknown_attribute = ..)]` which can be used on structs and
|
/// `#[xml(on_unknown_attribute = ..)]` which can be used on structs and
|
||||||
|
|
@ -435,7 +442,7 @@ impl UnknownAttributePolicy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Control how unknown children are handled.
|
/// # Control how unknown child elements are handled
|
||||||
///
|
///
|
||||||
/// The variants of this enum are referenced in the
|
/// The variants of this enum are referenced in the
|
||||||
/// `#[xml(on_unknown_child = ..)]` which can be used on structs and
|
/// `#[xml(on_unknown_child = ..)]` which can be used on structs and
|
||||||
|
|
@ -472,8 +479,44 @@ impl UnknownChildPolicy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to transform a type implementing [`AsXml`] into another
|
/// # Transform a value into another value via XML
|
||||||
/// type which implements [`FromXml`].
|
///
|
||||||
|
/// This function takes `from`, converts it into XML using its [`AsXml`]
|
||||||
|
/// implementation and builds a `T` from it (without buffering the tree in
|
||||||
|
/// memory).
|
||||||
|
///
|
||||||
|
/// If conversion fails, a [`Error`][`crate::error::Error`] is returned. In
|
||||||
|
/// particular, if `T` expects a different element header than the header
|
||||||
|
/// provided by `from`,
|
||||||
|
/// [`Error::TypeMismatch`][`crate::error::Error::TypeMismatch`] is returned.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
#[cfg_attr(
|
||||||
|
not(all(feature = "std", feature = "macros")),
|
||||||
|
doc = "Because the std or macros feature was not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
|
||||||
|
)]
|
||||||
|
#[cfg_attr(all(feature = "std", feature = "macros"), doc = "\n```\n")]
|
||||||
|
/// # use xso::{AsXml, FromXml, transform};
|
||||||
|
/// #[derive(AsXml)]
|
||||||
|
/// #[xml(namespace = "urn:example", name = "foo")]
|
||||||
|
/// struct Source {
|
||||||
|
/// #[xml(attribute = "xml:lang")]
|
||||||
|
/// lang: &'static str,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[derive(FromXml, PartialEq, Debug)]
|
||||||
|
/// #[xml(namespace = "urn:example", name = "foo")]
|
||||||
|
/// struct Dest {
|
||||||
|
/// #[xml(lang)]
|
||||||
|
/// lang: Option<String>,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// Dest { lang: Some("en".to_owned()) },
|
||||||
|
/// transform(&Source { lang: "en" }).unwrap(),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
pub fn transform<T: FromXml, F: AsXml>(from: &F) -> Result<T, self::error::Error> {
|
pub fn transform<T: FromXml, F: AsXml>(from: &F) -> Result<T, self::error::Error> {
|
||||||
let mut languages = rxml::xml_lang::XmlLangStack::new();
|
let mut languages = rxml::xml_lang::XmlLangStack::new();
|
||||||
let mut iter = self::rxml_util::ItemToEvent::new(from.as_xml_iter()?);
|
let mut iter = self::rxml_util::ItemToEvent::new(from.as_xml_iter()?);
|
||||||
|
|
@ -568,8 +611,37 @@ pub fn try_from_element<T: FromXml>(
|
||||||
unreachable!("minidom::Element did not produce enough events to complete element")
|
unreachable!("minidom::Element did not produce enough events to complete element")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to parse a type implementing [`FromXml`] from a byte buffer
|
/// # Parse a value from a byte slice containing XML data
|
||||||
/// containing XML data.
|
///
|
||||||
|
/// This function parses the XML found in `buf`, assuming it contains a
|
||||||
|
/// complete XML document (with optional XML declaration) and builds a `T`
|
||||||
|
/// from it (without buffering the tree in memory).
|
||||||
|
///
|
||||||
|
/// If conversion fails, a [`Error`][`crate::error::Error`] is returned. In
|
||||||
|
/// particular, if `T` expects a different element header than the element
|
||||||
|
/// header at the root of the document in `bytes`,
|
||||||
|
/// [`Error::TypeMismatch`][`crate::error::Error::TypeMismatch`] is returned.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
#[cfg_attr(
|
||||||
|
not(feature = "macros"),
|
||||||
|
doc = "Because the macros feature was not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
|
||||||
|
)]
|
||||||
|
#[cfg_attr(feature = "macros", doc = "\n```\n")]
|
||||||
|
/// # use xso::{AsXml, FromXml, from_bytes};
|
||||||
|
/// #[derive(FromXml, PartialEq, Debug)]
|
||||||
|
/// #[xml(namespace = "urn:example", name = "foo")]
|
||||||
|
/// struct Foo {
|
||||||
|
/// #[xml(attribute)]
|
||||||
|
/// a: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// Foo { a: "some-value".to_owned() },
|
||||||
|
/// from_bytes(b"<foo xmlns='urn:example' a='some-value'/>").unwrap(),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
pub fn from_bytes<T: FromXml>(mut buf: &[u8]) -> Result<T, self::error::Error> {
|
pub fn from_bytes<T: FromXml>(mut buf: &[u8]) -> Result<T, self::error::Error> {
|
||||||
use rxml::{error::EndOrError, Parse};
|
use rxml::{error::EndOrError, Parse};
|
||||||
|
|
||||||
|
|
@ -649,7 +721,40 @@ fn read_start_event_io(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to parse a type implementing [`FromXml`] from a reader.
|
/// # Parse a value from a [`io::BufRead`][`std::io::BufRead`]
|
||||||
|
///
|
||||||
|
/// This function parses the XML found in `r`, assuming it contains a
|
||||||
|
/// complete XML document (with optional XML declaration) and builds a `T`
|
||||||
|
/// from it (without buffering the tree in memory).
|
||||||
|
///
|
||||||
|
/// If conversion fails, a [`Error`][`crate::error::Error`] is returned. In
|
||||||
|
/// particular, if `T` expects a different element header than the element
|
||||||
|
/// header at the root of the document in `r`,
|
||||||
|
/// [`Error::TypeMismatch`][`crate::error::Error::TypeMismatch`] is returned.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
#[cfg_attr(
|
||||||
|
not(feature = "macros"),
|
||||||
|
doc = "Because the macros feature was not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
|
||||||
|
)]
|
||||||
|
#[cfg_attr(feature = "macros", doc = "\n```\n")]
|
||||||
|
/// # use xso::{AsXml, FromXml, from_reader};
|
||||||
|
/// # use std::io::BufReader;
|
||||||
|
/// #[derive(FromXml, PartialEq, Debug)]
|
||||||
|
/// #[xml(namespace = "urn:example", name = "foo")]
|
||||||
|
/// struct Foo {
|
||||||
|
/// #[xml(attribute)]
|
||||||
|
/// a: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // let file = ..
|
||||||
|
/// # let file = &mut &b"<foo xmlns='urn:example' a='some-value'/>"[..];
|
||||||
|
/// assert_eq!(
|
||||||
|
/// Foo { a: "some-value".to_owned() },
|
||||||
|
/// from_reader(BufReader::new(file)).unwrap(),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn from_reader<T: FromXml, R: io::BufRead>(r: R) -> io::Result<T> {
|
pub fn from_reader<T: FromXml, R: io::BufRead>(r: R) -> io::Result<T> {
|
||||||
let mut reader = rxml::XmlLangTracker::wrap(rxml::Reader::new(r));
|
let mut reader = rxml::XmlLangTracker::wrap(rxml::Reader::new(r));
|
||||||
|
|
@ -682,7 +787,34 @@ pub fn from_reader<T: FromXml, R: io::BufRead>(r: R) -> io::Result<T> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to serialise a type implementing [`AsXml`] to a vector of bytes.
|
/// # Serialize a value to UTF-8-encoded XML
|
||||||
|
///
|
||||||
|
/// This function takes `xso`, converts it into XML using its [`AsXml`]
|
||||||
|
/// implementation and serialises the resulting XML events into a `Vec<u8>`.
|
||||||
|
///
|
||||||
|
/// If serialisation fails, an error is returned instead.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
#[cfg_attr(
|
||||||
|
not(feature = "macros"),
|
||||||
|
doc = "Because the macros feature was not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
|
||||||
|
)]
|
||||||
|
#[cfg_attr(feature = "macros", doc = "\n```\n")]
|
||||||
|
/// # use xso::{AsXml, FromXml, to_vec};
|
||||||
|
/// # use std::io::BufReader;
|
||||||
|
/// #[derive(AsXml, PartialEq, Debug)]
|
||||||
|
/// #[xml(namespace = "urn:example", name = "foo")]
|
||||||
|
/// struct Foo {
|
||||||
|
/// #[xml(attribute)]
|
||||||
|
/// a: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// b"<foo xmlns='urn:example' a='some-value'></foo>",
|
||||||
|
/// &to_vec(&Foo { a: "some-value".to_owned() }).unwrap()[..],
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
pub fn to_vec<T: AsXml>(xso: &T) -> Result<Vec<u8>, self::error::Error> {
|
pub fn to_vec<T: AsXml>(xso: &T) -> Result<Vec<u8>, self::error::Error> {
|
||||||
let iter = xso.as_xml_iter()?;
|
let iter = xso.as_xml_iter()?;
|
||||||
let mut writer = rxml::writer::Encoder::new();
|
let mut writer = rxml::writer::Encoder::new();
|
||||||
|
|
@ -694,10 +826,20 @@ pub fn to_vec<T: AsXml>(xso: &T) -> Result<Vec<u8>, self::error::Error> {
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if the string contains exclusively XML whitespace.
|
/// # Test if a string contains exclusively XML whitespace
|
||||||
///
|
///
|
||||||
/// XML whitespace is defined as U+0020 (space), U+0009 (tab), U+000a
|
/// This function returns true if `s` contains only XML whitespace. XML
|
||||||
/// (newline) and U+000d (carriage return).
|
/// whitespace is defined as U+0020 (space), U+0009 (tab), U+000a (newline)
|
||||||
|
/// and U+000d (carriage return), so this test is implemented on bytes instead
|
||||||
|
/// of codepoints for efficiency.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use xso::is_xml_whitespace;
|
||||||
|
/// assert!(is_xml_whitespace(" \t\r\n "));
|
||||||
|
/// assert!(!is_xml_whitespace(" hello "));
|
||||||
|
/// ```
|
||||||
pub fn is_xml_whitespace<T: AsRef<[u8]>>(s: T) -> bool {
|
pub fn is_xml_whitespace<T: AsRef<[u8]>>(s: T) -> bool {
|
||||||
s.as_ref()
|
s.as_ref()
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,13 @@ use alloc::borrow::{Cow, ToOwned};
|
||||||
|
|
||||||
use rxml::{parser::EventMetrics, AttrMap, Event, Namespace, NcName, NcNameStr, XmlVersion};
|
use rxml::{parser::EventMetrics, AttrMap, Event, Namespace, NcName, NcNameStr, XmlVersion};
|
||||||
|
|
||||||
/// An encodable item.
|
/// # Serialisable piece of XML
|
||||||
///
|
///
|
||||||
/// Unlike [`rxml::Item`], the contents of this item may either be owned or
|
/// This item represents a piece of an XML document which can be serialised
|
||||||
|
/// into bytes by converting it to an [`rxml::Item`] and then feeding it to a
|
||||||
|
/// [`rxml::Encoder`].
|
||||||
|
///
|
||||||
|
/// Unlike `rxml::Item`, the contents of this item may either be owned or
|
||||||
/// borrowed, individually. This enables the use in an [`crate::AsXml`] trait
|
/// borrowed, individually. This enables the use in an [`crate::AsXml`] trait
|
||||||
/// even if data needs to be generated during serialisation.
|
/// even if data needs to be generated during serialisation.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue