Large STEP imports: no more multi-minute hang, shared STEP text, cancel and progress (#925)

This commit is contained in:
bherbruck authored and GitHub committed 2026-10-14 05:01:12 -04:00
1 parent dfbf7dd6a8
commit 2f91338d3d
18 files changed
+525 -45

No files matched your search

+5 -5
View File
@@ -568,7 +568,7 @@ fn read_document<R: Read + Seek>(reader: &mut PackageReader<R>) -> Result<Docume
if !step.is_empty() {
return Err(invalid("ambiguous embedded STEP and blob"));
}
*step = std::str::from_utf8(reader.blob(value, "step_blob", "step")?).map_err(invalid)?.to_owned();
*step = std::str::from_utf8(reader.blob(value, "step_blob", "step")?).map_err(invalid)?.into();
}
FeatureKind::MeshImport { meshes, .. } => {
for (index, mesh) in meshes.iter_mut().enumerate() {
@@ -640,7 +640,7 @@ mod tests {
fn seekable_preview_defers_large_source_blob_until_document_read() {
let mut doc = Document::new("Deferred source");
let step = "ISO-10303-21;".repeat(200_000);
doc.add_feature(FeatureKind::Import { file: "large.step".into(), step: step.clone(), components: Vec::new() }, None).unwrap();
doc.add_feature(FeatureKind::Import { file: "large.step".into(), step: step.clone().into(), components: Vec::new() }, None).unwrap();
let preview = DesignPreview { meshes: vec![mesh()] };
let bytes = write_design_container_with_preview(&doc, DesignCompression::Fast, Some(&preview)).unwrap();
let count = std::rc::Rc::new(std::cell::Cell::new(0));
@@ -699,7 +699,7 @@ mod tests {
fn native_cache_round_trip_and_preview_defer_original_sources() {
let mut doc = Document::new("Native cache");
let step = "ISO-10303-21;".repeat(200_000);
doc.add_feature(FeatureKind::Import { file: "large.step".into(), step: step.clone(), components: Vec::new() }, None).unwrap();
doc.add_feature(FeatureKind::Import { file: "large.step".into(), step: step.clone().into(), components: Vec::new() }, None).unwrap();
let bodies = native_geometry();
let bytes = write_design_container_with_cache(&doc, DesignCompression::Fast, None, Some(&bodies)).unwrap();
let entries = parts(&bytes);
@@ -868,7 +868,7 @@ mod tests {
png.extend(150u32.to_be_bytes());
let mut doc = Document::from_json(&document().to_json()).unwrap();
if let FeatureKind::Import { step, .. } = &mut doc.features[0].kind {
*step = "source data".repeat(250_000);
*step = "source data".repeat(250_000).into();
}
let bytes = write_design_container_with_thumbnail(&doc, DesignCompression::Fast, None, None, Some(&png)).unwrap();
let count = std::rc::Rc::new(std::cell::Cell::new(0));
@@ -1157,7 +1157,7 @@ mod tests {
.collect();
let step = solidcraft_kernel::step_export(&bodies.iter().collect::<Vec<_>>(), "SolidCraft storage benchmark").unwrap();
let mut doc = Document::new("Generated STEP benchmark");
doc.add_feature(FeatureKind::Import { file: "generated.step".into(), step, components: Vec::new() }, None).unwrap();
doc.add_feature(FeatureKind::Import { file: "generated.step".into(), step: step.into(), components: Vec::new() }, None).unwrap();
measure_storage(&doc, "step");
}
+5 -1
View File
@@ -95,6 +95,9 @@ pub struct StepFeature {
/// Body names from the file (solid names, else product names).
pub body_names: Vec<String>,
pub warnings: Vec<String>,
/// The file as read. Hold it until the feature has been evaluated: the timeline then reuses
/// it instead of reading the file again (it is freed with the last holder).
pub import: std::sync::Arc<solidcraft_kernel::StepImport>,
}
/// Read STEP bytes (`file` is the source file name) into an Import base feature. The file is
@@ -125,8 +128,9 @@ pub fn step_import_feature(bytes: &[u8], file: &str) -> Result<StepFeature> {
Ok(StepFeature {
name,
body_names: imp.bodies.iter().map(|b| b.name.clone()).collect(),
kind: solidcraft_doc::FeatureKind::Import { file: file_name, step: text, components: imp.tree.clone() },
kind: solidcraft_doc::FeatureKind::Import { file: file_name, step: text.into(), components: imp.tree.clone() },
warnings: iges_warnings.into_iter().chain(imp.warnings.iter().cloned()).collect(),
import: imp,
})
}