fix(io): prevent lossy Save As

Use the verified acadifc round-trip fixes and warn for every unsupported object or entity the selected format would drop.
This commit is contained in:
Hakan Seven 2026-07-25 23:02:05 +03:00
commit a22681e751
3 changed files with 64 additions and 16 deletions

3
Cargo.lock generated
View file

@ -75,7 +75,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
[[package]] [[package]]
name = "acadrust" name = "acadrust"
version = "0.4.0" version = "0.4.0"
source = "git+https://github.com/OpenAEC-Foundation/acadifc.git?rev=bee1a58#bee1a5857d444a32b67f98e6babc1ad6483f6865" source = "git+https://github.com/OpenAEC-Foundation/acadifc.git?rev=59e0224#59e0224c35c294218aae362492c7ed30685b106a"
dependencies = [ dependencies = [
"ahash 0.8.12", "ahash 0.8.12",
"anyhow", "anyhow",
@ -93,6 +93,7 @@ dependencies = [
"ryu", "ryu",
"serde", "serde",
"thiserror 1.0.69", "thiserror 1.0.69",
"web-time",
] ]
[[package]] [[package]]

View file

@ -91,7 +91,7 @@ windows-sys = { version = "0.61", features = ["Win32_UI_Shell", "Win32_UI_Window
[patch.crates-io] [patch.crates-io]
# Track the verified DWG round-trip, I/O, and unified PERF fixes. # Track the verified DWG round-trip, I/O, and unified PERF fixes.
acadrust = { git = "https://github.com/OpenAEC-Foundation/acadifc.git", rev = "bee1a58" } acadrust = { git = "https://github.com/OpenAEC-Foundation/acadifc.git", rev = "59e0224" }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
# Native enables the plugin host runtime (out-of-process plugins). # Native enables the plugin host runtime (out-of-process plugins).

View file

@ -477,26 +477,73 @@ pub fn dropped_on_save_count(
target_version: acadrust::DxfVersion, target_version: acadrust::DxfVersion,
is_dxf: bool, is_dxf: bool,
) -> usize { ) -> usize {
if !is_dxf && target_version == doc.version {
return 0;
}
let mut n = doc let mut n = doc
.objects .objects
.values() .values()
.filter(|o| { .filter(|object| match object {
matches!( acadrust::objects::ObjectType::Unknown {
o, raw_dxf_codes,
acadrust::objects::ObjectType::Unknown { raw_dwg_data: Some(_), .. } raw_dwg_data,
) raw_dwg_version,
..
} => {
if is_dxf {
raw_dxf_codes.is_none()
} else {
raw_dwg_data.is_none()
|| raw_dwg_version.is_some_and(|source| source != target_version)
}
}
acadrust::objects::ObjectType::GeoData(_)
| acadrust::objects::ObjectType::VisualStyle(_)
| acadrust::objects::ObjectType::Material(_)
| acadrust::objects::ObjectType::TableStyle(_) => !is_dxf,
_ => false,
}) })
.count(); .count();
for e in doc.entities() { for e in doc.entities() {
if matches!( let dropped = match e {
e, acadrust::EntityType::Unknown(entity) => {
acadrust::EntityType::Unknown(_) if is_dxf {
| acadrust::EntityType::SectionSymbol(_) entity.raw_dxf_codes.is_none()
| acadrust::EntityType::ViewBorder(_) } else {
) { entity.raw_dwg_data.is_none()
|| entity
.dwg_source_version
.is_some_and(|source| source != target_version)
}
}
acadrust::EntityType::Surface(entity) => {
is_dxf
|| entity.raw_dwg_data.is_none()
|| entity
.dwg_source_version
.is_some_and(|source| source != target_version)
}
acadrust::EntityType::Light(entity) => {
is_dxf
|| entity.raw_dwg_data.is_none()
|| entity
.dwg_source_version
.is_some_and(|source| source != target_version)
}
acadrust::EntityType::SectionSymbol(entity) => {
is_dxf
|| entity.raw_dwg_data.is_none()
|| entity
.dwg_source_version
.is_some_and(|source| source != target_version)
}
acadrust::EntityType::ViewBorder(entity) => {
is_dxf
|| entity.raw_dwg_data.is_none()
|| entity
.dwg_source_version
.is_some_and(|source| source != target_version)
}
_ => false,
};
if dropped {
n += 1; n += 1;
} }
} }