From 03555ce8bd8973a69389eec6cb3013f6f7564eb3 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Wed, 13 May 2026 23:02:54 +0300 Subject: [PATCH] chore: expose lib target + open-path profiling examples Examples can't import from a bin-only crate, so add a thin lib.rs that re-exports the existing modules. Used by the new examples that helped diagnose the freeze fixed in the previous commit. - examples/time_open: times parse / purge / cache / first-wires phases - examples/inspect_insert: lists Insert blocks with sub-entity counts - examples/find_raster: dumps RasterImage path + dimensions Co-Authored-By: Claude Opus 4.7 --- examples/find_raster.rs | 14 ++++++ examples/inspect_insert.rs | 43 +++++++++++++++++++ examples/time_open.rs | 87 ++++++++++++++++++++++++++++++++++++++ src/lib.rs | 10 +++++ 4 files changed, 154 insertions(+) create mode 100644 examples/find_raster.rs create mode 100644 examples/inspect_insert.rs create mode 100644 examples/time_open.rs create mode 100644 src/lib.rs diff --git a/examples/find_raster.rs b/examples/find_raster.rs new file mode 100644 index 000000000..af01c082f --- /dev/null +++ b/examples/find_raster.rs @@ -0,0 +1,14 @@ +use acadrust::entities::EntityType; +use acadrust::io::dwg::DwgReader; +fn main() -> Result<(), Box> { + let path = std::env::args().nth(1).unwrap(); + let doc = DwgReader::from_file(&path)?.read()?; + for e in doc.entities() { + if let EntityType::RasterImage(img) = e { + println!("file_path: {}", img.file_path); + println!("size: {} x {}", img.size.x, img.size.y); + if let Ok(meta) = std::fs::metadata(&img.file_path) { println!("disk size: {} bytes", meta.len()); } + } + } + Ok(()) +} diff --git a/examples/inspect_insert.rs b/examples/inspect_insert.rs new file mode 100644 index 000000000..e36437c2a --- /dev/null +++ b/examples/inspect_insert.rs @@ -0,0 +1,43 @@ +// Lists every Insert in the doc (after xref resolve) with sub-entity counts. +// cargo run --release --example inspect_insert -- +use acadrust::entities::EntityType; +use acadrust::io::dwg::DwgReader; + +fn main() -> Result<(), Box> { + let path = std::env::args().nth(1).unwrap(); + let mut doc = DwgReader::from_file(&path)?.read()?; + if let Some(base) = std::path::Path::new(&path).parent() { + let infos = H7CAD::io::xref::resolve_xrefs(&mut doc, base); + for i in &infos { + println!("XREF: {} -> {:?}", i.name, i.status); + } + } + println!("total entities: {}", doc.entities().count()); + + let inserts: Vec<_> = doc + .entities() + .filter_map(|e| if let EntityType::Insert(i) = e { Some(i.clone()) } else { None }) + .collect(); + println!("total inserts: {}", inserts.len()); + + let mut by_block: std::collections::HashMap = std::collections::HashMap::new(); + for i in &inserts { + *by_block.entry(i.block_name.clone()).or_insert(0) += 1; + } + let mut by_block: Vec<_> = by_block.into_iter().collect(); + by_block.sort_by(|a, b| b.1.cmp(&a.1)); + + println!("\ninserts grouped by block_name:"); + for (name, n) in &by_block { + let sub_count = inserts.iter().find(|i| &i.block_name == name) + .map(|i| i.explode_from_document(&doc).len()) + .unwrap_or(0); + let nested = doc.block_records.get(name) + .map(|br| br.entity_handles.iter() + .filter(|h| matches!(doc.get_entity(**h), Some(EntityType::Insert(_)))) + .count()) + .unwrap_or(0); + println!(" {:>4} × {} (sub={}, nested-inserts={})", n, name, sub_count, nested); + } + Ok(()) +} diff --git a/examples/time_open.rs b/examples/time_open.rs new file mode 100644 index 000000000..bba5940ee --- /dev/null +++ b/examples/time_open.rs @@ -0,0 +1,87 @@ +// Times each open phase: parse / purge / derived caches. +// Run with: cargo run --release --example time_open -- + +use acadrust::entities::EntityType; +use std::env; +use std::path::Path; +use std::time::Instant; +use H7CAD::io::{load_file, purge_corrupt_entities}; +use H7CAD::scene::{build_derived_caches, Scene}; + +fn main() -> Result<(), Box> { + let path = env::args().nth(1).ok_or("usage: time_open ")?; + + let t0 = Instant::now(); + let mut doc = load_file(Path::new(&path))?; + let parse_ms = t0.elapsed().as_millis(); + + let t1 = Instant::now(); + let dropped = purge_corrupt_entities(&mut doc); + let purge_ms = t1.elapsed().as_millis(); + + let t2 = Instant::now(); + let caches = build_derived_caches(&doc); + let caches_ms = t2.elapsed().as_millis(); + + let mut counts = std::collections::HashMap::<&'static str, usize>::new(); + let mut total = 0usize; + for e in doc.entities() { + total += 1; + let tag: &'static str = match e { + EntityType::Line(_) => "Line", + EntityType::Arc(_) => "Arc", + EntityType::Circle(_) => "Circle", + EntityType::LwPolyline(_) => "LwPolyline", + EntityType::Polyline2D(_) => "Polyline2D", + EntityType::Polyline3D(_) => "Polyline3D", + EntityType::Polyline(_) => "Polyline", + EntityType::Hatch(_) => "Hatch", + EntityType::Solid(_) => "Solid", + EntityType::RasterImage(_) => "RasterImage", + EntityType::Solid3D(_) => "Solid3D", + EntityType::Region(_) => "Region", + EntityType::Body(_) => "Body", + EntityType::Text(_) => "Text", + EntityType::MText(_) => "MText", + EntityType::Insert(_) => "Insert", + EntityType::Dimension(_) => "Dimension", + EntityType::Spline(_) => "Spline", + EntityType::Ellipse(_) => "Ellipse", + _ => "_other", + }; + *counts.entry(tag).or_insert(0) += 1; + } + let mut counts: Vec<_> = counts.into_iter().collect(); + counts.sort_by(|a, b| b.1.cmp(&a.1)); + + // Set up a Scene as the UI thread does and time first wire tessellation. + let mut scene = Scene::new(); + scene.document = doc; + scene.world_offset = caches.world_offset; + scene.local_extent_max = caches.local_extent_max; + scene.hatches = caches.hatches.clone(); + scene.images = caches.images.clone(); + scene.meshes = caches.meshes.clone(); + scene.bump_geometry(); + scene.current_layout = "Model".to_string(); + H7CAD::linetypes::populate_document(&mut scene.document); + + let t3 = Instant::now(); + let wires = scene.entity_wires(); + let wires_ms = t3.elapsed().as_millis(); + + println!("file: {}", path); + println!("parse: {} ms", parse_ms); + println!("purge: {} ms (dropped {})", purge_ms, dropped); + println!("derived caches: {} ms", caches_ms); + println!("first wires: {} ms ({} wires)", wires_ms, wires.len()); + println!(" hatches: {}", caches.hatches.len()); + println!(" images: {}", caches.images.len()); + println!(" meshes: {}", caches.meshes.len()); + println!(); + println!("entities: {}", total); + for (tag, n) in counts.iter().take(20) { + println!(" {:>14} {}", tag, n); + } + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..91c50225f --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,10 @@ +pub mod app; +pub mod command; +pub mod entities; +pub mod io; +pub mod linetypes; +pub mod modules; +pub mod patterns; +pub mod scene; +pub mod snap; +pub mod ui;