diff --git a/Cargo.lock b/Cargo.lock index f0660a6..dfec57f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,6 +55,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "aligned-vec" version = "0.6.4" @@ -3419,6 +3425,30 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "ouroboros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.103", +] + [[package]] name = "overload" version = "0.1.1" @@ -3784,6 +3814,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", + "version_check", + "yansi", +] + [[package]] name = "profiling" version = "1.0.16" @@ -5600,6 +5643,7 @@ dependencies = [ "image", "log", "lru", + "ouroboros", "resvg", "roxmltree 0.20.0", "rustc-hash 2.1.1", @@ -6372,6 +6416,12 @@ dependencies = [ "hashlink", ] +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "yansi-term" version = "0.1.2" diff --git a/wgui/Cargo.toml b/wgui/Cargo.toml index 4d5d3a7..46ec4a3 100644 --- a/wgui/Cargo.toml +++ b/wgui/Cargo.toml @@ -17,6 +17,7 @@ image = { version = "0.25.6", default-features = false, features = [ ] } log = { workspace = true } lru = "0.14.0" +ouroboros = "0.18.5" resvg = { version = "0.45.1", default-features = false } roxmltree = "0.20.0" rustc-hash = "2.1.1" diff --git a/wgui/src/parser.rs b/wgui/src/parser.rs index 61e0f94..4384c5b 100644 --- a/wgui/src/parser.rs +++ b/wgui/src/parser.rs @@ -5,6 +5,7 @@ use std::{ rc::Rc, }; +use ouroboros::self_referencing; use taffy::{ AlignContent, AlignItems, AlignSelf, BoxSizing, Display, FlexDirection, FlexWrap, JustifyContent, JustifySelf, Overflow, @@ -29,8 +30,17 @@ use crate::{ type VarMap = HashMap, Rc>; +#[self_referencing] +struct XmlDocument { + xml: String, + + #[borrows(xml)] + #[covariant] + doc: roxmltree::Document<'this>, +} + struct Template { - doc: Rc>, + doc: Rc, node: roxmltree::NodeId, parameters: HashMap, Rc>, } @@ -58,8 +68,7 @@ struct ParserContext<'a> { struct ParserFile<'a> { path: PathBuf, - _xml: Rc>, - document: Rc>, + document: Rc, ctx: Rc>>, } @@ -806,7 +815,6 @@ fn parse_children<'a>( }; let file = ParserFile { - _xml: file._xml.clone(), ctx: file.ctx.clone(), document: template.doc.clone(), path: file.path.clone(), @@ -815,6 +823,7 @@ fn parse_children<'a>( let doc = template.doc.clone(); let template_node = doc + .borrow_doc() .get_node(template.node) .ok_or(anyhow::anyhow!("template node invalid"))?; @@ -849,12 +858,9 @@ pub fn parse_from_assets( Ok(result) } -fn assets_path_to_xml( - assets: &mut Box, - path: &Path, -) -> anyhow::Result> { +fn assets_path_to_xml(assets: &mut Box, path: &Path) -> anyhow::Result { let data = assets.load_from_path(&path.to_string_lossy())?; - Ok(Rc::from(String::from_utf8(data)?)) + Ok(String::from_utf8(data)?) } fn get_doc_from_path<'a>( @@ -862,24 +868,19 @@ fn get_doc_from_path<'a>( ctx: &mut ParserContext, path: &Path, ) -> anyhow::Result> { - let opt = roxmltree::ParsingOptions { - allow_dtd: true, - ..Default::default() - }; - - let xml_string = assets_path_to_xml(&mut ctx.layout.assets, path)?; - - let xml = Rc::new(::clone(&xml_string).into_boxed_str()); - - let xml_ref: &'static str = Box::leak(Box::new(Rc::clone(&xml))); - - let document = Rc::new(roxmltree::Document::parse_with_options(xml_ref, opt)?); + let xml = assets_path_to_xml(&mut ctx.layout.assets, path)?; + let document = XmlDocument::new(xml, |xml| { + let opt = roxmltree::ParsingOptions { + allow_dtd: true, + ..Default::default() + }; + roxmltree::Document::parse_with_options(xml, opt).unwrap() + }); let file = ParserFile { ctx: ctx_rc.clone(), path: PathBuf::from(path), - document, - _xml: xml, + document: Rc::new(document), }; Ok(file) @@ -890,7 +891,7 @@ fn parse_document_root( ctx: &mut ParserContext, parent_id: WidgetID, ) -> anyhow::Result<()> { - let root = file.document.root(); + let root = file.document.borrow_doc().root(); let tag_layout = require_tag_by_name(&root, "layout")?; for child_node in tag_layout.children() {