xml-stinks 0.1.0

Powerful & easy manual XML deserialization using quick-xml
Documentation
use std::convert::Infallible;
use std::error::Error;
use std::fmt::Debug;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;

use xml_stinks::deserializer::buffered::Buffered as BufferedDeserializer;
use xml_stinks::deserializer::{Deserializer, Error as DeserializerError, IgnoreEnd};
use xml_stinks::tagged::TagStart;
use xml_stinks::{impl_from_deserializer_error, DeserializeTagged};

const MANIFEST_DIR: &str = std::env!("CARGO_MANIFEST_DIR");

fn main() -> Result<(), Box<dyn Error>>
{
    let data_file = Path::new(MANIFEST_DIR).join("examples/data.xml");

    let reader = BufReader::new(File::open(data_file)?);

    let mut deserializer = BufferedDeserializer::new(reader);

    // Skip the <?xml version="1.0" encoding="UTF-8"?>
    deserializer.skip_to_tag_start("data")?;

    let data = deserializer.de_tag::<Data>("data", IgnoreEnd::No)?;

    println!("The following data was deserialized:\n");

    println!("Greeting: {}", data.greeting);
    println!("Something: {}", data.something);
    println!("Favorite food: {}", data.favorites.food);
    println!("Favorite color: {}", data.favorites.color);

    Ok(())
}

#[derive(Debug)]
struct Data
{
    greeting: String,
    something: String,
    favorites: Favorites,
}

impl DeserializeTagged for Data
{
    type Error = DataError;

    fn deserialize<TDeserializer: Deserializer>(
        _start: &TagStart,
        deserializer: &mut TDeserializer,
    ) -> Result<Self, Self::Error>
    {
        let greeting_a = deserializer.de_text()?;

        let something =
            deserializer.de_tag_with("something", IgnoreEnd::No, |_, deserializer| {
                deserializer.de_text()
            })?;

        let greeting_b = deserializer.de_text()?;

        let favorites = deserializer.de_tag::<Favorites>("favorites", IgnoreEnd::No)?;

        Ok(Self {
            greeting: format!("{greeting_a} {greeting_b}"),
            something,
            favorites,
        })
    }
}

#[derive(Debug, thiserror::Error)]
enum DataError
{
    #[error("Invalid favorites")]
    InvalidFavorites(#[from] FavoritesError),

    #[error(transparent)]
    DeserializerFailed(#[from] DeserializerError<Infallible>),
}

impl_from_deserializer_error!(DataError);

#[derive(Debug)]
struct Favorites
{
    food: String,
    color: String,
}

impl DeserializeTagged for Favorites
{
    type Error = FavoritesError;

    fn deserialize<TDeserializer: Deserializer>(
        _start: &TagStart,
        deserializer: &mut TDeserializer,
    ) -> Result<Self, Self::Error>
    {
        let food =
            deserializer.de_tag_with("food", IgnoreEnd::No, |_, deserializer| {
                deserializer.de_text()
            })?;

        let color =
            deserializer.de_tag_with("color", IgnoreEnd::No, |_, deserializer| {
                deserializer.de_text()
            })?;

        Ok(Self { food, color })
    }
}

#[derive(Debug, thiserror::Error)]
enum FavoritesError
{
    #[error(transparent)]
    DeserializerFailed(#[from] DeserializerError<Infallible>),
}

impl_from_deserializer_error!(FavoritesError);