woab 0.9.0

Widgets on Actors Bridge - a GUI microframework for combining GTK with Actix
use quick_xml::Reader;

#[doc(hidden)] // for internal use by #[derive(Factories)]
pub fn dissect_builder_xml(
    buf_read: impl std::io::BufRead,
    targets: &mut [Vec<u8>],
    id_to_idx: impl Fn(&str) -> Option<usize>,
) -> Result<(), crate::Error> {
    let mut reader = Reader::from_reader(buf_read);
    let mut buf = Vec::new();

    struct WriteContext<'a> {
        writer: quick_xml::Writer<std::io::Cursor<&'a mut std::vec::Vec<u8>>>,
        prev_idx: Option<usize>,
        nesting: usize,
    }

    let mut contexts = targets
        .iter_mut()
        .map(|target| WriteContext {
            writer: quick_xml::Writer::new(std::io::Cursor::new(target)),
            prev_idx: None,
            nesting: 0,
        })
        .collect::<Vec<_>>();

    let mut context_idx = None;
    let mut current_nesting = 0;

    fn write_event(
        contexts: &mut [WriteContext],
        idx: Option<usize>,
        event: quick_xml::events::Event,
    ) -> Result<(), crate::Error> {
        if let Some(idx) = idx {
            contexts[idx].writer.write_event(event)?;
        } else {
            for context in contexts.iter_mut() {
                context.writer.write_event(event.clone())?;
            }
        }
        Ok(())
    }

    loop {
        match reader.read_event_into(&mut buf)? {
            quick_xml::events::Event::Start(e) => {
                current_nesting += 1;
                if e.name().0 == b"object" {
                    let new_idx = e.attributes().find_map(|attr| {
                        let attr = attr.ok()?;
                        if attr.key.0 != b"id" {
                            return None;
                        }
                        let id = std::str::from_utf8(&attr.value).ok()?;
                        id_to_idx(id)
                    });
                    if let Some(new_idx) = new_idx {
                        contexts[new_idx].prev_idx = context_idx;
                        assert!(contexts[new_idx].nesting == 0);
                        contexts[new_idx].nesting = current_nesting;
                        context_idx = Some(new_idx);
                    }
                }
                write_event(&mut contexts, context_idx, quick_xml::events::Event::Start(e))?;
            }
            e @ quick_xml::events::Event::End(_) => {
                write_event(&mut contexts, context_idx, e)?;
                if let Some(idx) = context_idx {
                    if current_nesting == contexts[idx].nesting {
                        context_idx = contexts[idx].prev_idx;
                        contexts[idx].prev_idx = None;
                        contexts[idx].nesting = 0;
                    }
                }
                current_nesting -= 1;
            }
            quick_xml::events::Event::Eof => break,
            e => write_event(&mut contexts, context_idx, e)?,
        }
    }
    Ok(())
}