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]]
name = "acadrust"
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 = [
"ahash 0.8.12",
"anyhow",
@ -93,6 +93,7 @@ dependencies = [
"ryu",
"serde",
"thiserror 1.0.69",
"web-time",
]
[[package]]

View file

@ -91,7 +91,7 @@ windows-sys = { version = "0.61", features = ["Win32_UI_Shell", "Win32_UI_Window
[patch.crates-io]
# 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]
# 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,
is_dxf: bool,
) -> usize {
if !is_dxf && target_version == doc.version {
return 0;
}
let mut n = doc
.objects
.values()
.filter(|o| {
matches!(
o,
acadrust::objects::ObjectType::Unknown { raw_dwg_data: Some(_), .. }
)
.filter(|object| match object {
acadrust::objects::ObjectType::Unknown {
raw_dxf_codes,
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();
for e in doc.entities() {
if matches!(
e,
acadrust::EntityType::Unknown(_)
| acadrust::EntityType::SectionSymbol(_)
| acadrust::EntityType::ViewBorder(_)
) {
let dropped = match e {
acadrust::EntityType::Unknown(entity) => {
if is_dxf {
entity.raw_dxf_codes.is_none()
} 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;
}
}