diff --git a/Cargo.lock b/Cargo.lock index 6deb7eb93..a1983e88b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3886,7 +3886,7 @@ dependencies = [ [[package]] name = "ocs_plugin_api" -version = "0.2.0" +version = "0.2.1" dependencies = [ "acadrust", "bincode", diff --git a/crates/ocs_plugin_api/Cargo.toml b/crates/ocs_plugin_api/Cargo.toml index fb3a0f1a6..3d0f7b422 100644 --- a/crates/ocs_plugin_api/Cargo.toml +++ b/crates/ocs_plugin_api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ocs_plugin_api" -version = "0.2.0" +version = "0.2.1" edition = "2021" description = "Stable, dependency-free contract for Open CAD Studio add-on packages: plugin manifest, version handshake, and ribbon/CadModule types." license = "GPL-3.0-only" diff --git a/crates/ocs_plugin_api/build.rs b/crates/ocs_plugin_api/build.rs index 867318fd0..d818a0dd6 100644 --- a/crates/ocs_plugin_api/build.rs +++ b/crates/ocs_plugin_api/build.rs @@ -57,13 +57,40 @@ fn generate_type_registry(out_dir: &Path) { ("Color", trace::), ("Layer", trace::), ("XDataValue", trace::), + ("XRecord", trace::), + ("XRecordEntry", trace::), + ("XRecordValue", trace::), + ( + "XRecordValueType", + trace::, + ), + ("XRecordSection", trace::), + ( + "DictionaryCloningFlags", + trace::, + ), + ( + "KnownXRecordKind", + trace::, + ), + ( + "ProxyObjectReference", + trace::, + ), + ( + "ProxyReferenceKind", + trace::, + ), ]; for (name, f) in types { f(&mut tracer, &samples); // serde-reflection accumulates named types as it traces; we only need // to ensure the seed types are recorded even if a nested trace fails. - eprintln!("[ocs_plugin_api build] traced type registry entry: {}", name); + eprintln!( + "[ocs_plugin_api build] traced type registry entry: {}", + name + ); } let traced = tracer @@ -80,7 +107,10 @@ where { let name = std::any::type_name::(); if let Err(e) = tracer.trace_type::(samples) { - eprintln!("[ocs_plugin_api build] warning: tracing {} failed: {}", name, e); + eprintln!( + "[ocs_plugin_api build] warning: tracing {} failed: {}", + name, e + ); } } @@ -94,8 +124,14 @@ fn add_enum_samples(tracer: &mut Tracer, samples: &mut Samples) { let _ = tracer.trace_value(samples, &acadrust::LineWeight::Value(0)); let _ = tracer.trace_value(samples, &acadrust::entities::SmoothSurfaceType::None); - let _ = tracer.trace_value(samples, &acadrust::entities::SmoothSurfaceType::QuadraticBSpline); - let _ = tracer.trace_value(samples, &acadrust::entities::SmoothSurfaceType::CubicBSpline); + let _ = tracer.trace_value( + samples, + &acadrust::entities::SmoothSurfaceType::QuadraticBSpline, + ); + let _ = tracer.trace_value( + samples, + &acadrust::entities::SmoothSurfaceType::CubicBSpline, + ); let _ = tracer.trace_value(samples, &acadrust::entities::SmoothSurfaceType::Bezier); let _ = tracer.trace_value(samples, &acadrust::entities::AttachmentPoint::TopLeft); @@ -116,19 +152,84 @@ fn add_enum_samples(tracer: &mut Tracer, samples: &mut Samples) { let _ = tracer.trace_value(samples, &acadrust::entities::LineSpacingStyle::Exactly); let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::String(String::new())); - let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::ControlString(String::new())); - let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::LayerName(String::new())); - let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::BinaryData(Vec::new())); - let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::Handle(acadrust::Handle::default())); - let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::Point3D(acadrust::Vector3::default())); - let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::Position3D(acadrust::Vector3::default())); - let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::Displacement3D(acadrust::Vector3::default())); - let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::Direction3D(acadrust::Vector3::default())); + let _ = tracer.trace_value( + samples, + &acadrust::xdata::XDataValue::ControlString(String::new()), + ); + let _ = tracer.trace_value( + samples, + &acadrust::xdata::XDataValue::LayerName(String::new()), + ); + let _ = tracer.trace_value( + samples, + &acadrust::xdata::XDataValue::BinaryData(Vec::new()), + ); + let _ = tracer.trace_value( + samples, + &acadrust::xdata::XDataValue::Handle(acadrust::Handle::default()), + ); + let _ = tracer.trace_value( + samples, + &acadrust::xdata::XDataValue::Point3D(acadrust::Vector3::default()), + ); + let _ = tracer.trace_value( + samples, + &acadrust::xdata::XDataValue::Position3D(acadrust::Vector3::default()), + ); + let _ = tracer.trace_value( + samples, + &acadrust::xdata::XDataValue::Displacement3D(acadrust::Vector3::default()), + ); + let _ = tracer.trace_value( + samples, + &acadrust::xdata::XDataValue::Direction3D(acadrust::Vector3::default()), + ); let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::Real(0.0)); let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::Distance(0.0)); let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::ScaleFactor(0.0)); let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::Integer16(0)); let _ = tracer.trace_value(samples, &acadrust::xdata::XDataValue::Integer32(0)); + + // XRecord value variants + let _ = tracer.trace_value( + samples, + &acadrust::objects::XRecordValue::String(String::new()), + ); + let _ = tracer.trace_value(samples, &acadrust::objects::XRecordValue::Double(0.0)); + let _ = tracer.trace_value(samples, &acadrust::objects::XRecordValue::Int16(0)); + let _ = tracer.trace_value(samples, &acadrust::objects::XRecordValue::Int32(0)); + let _ = tracer.trace_value(samples, &acadrust::objects::XRecordValue::Int64(0)); + let _ = tracer.trace_value(samples, &acadrust::objects::XRecordValue::Byte(0)); + let _ = tracer.trace_value(samples, &acadrust::objects::XRecordValue::Bool(false)); + let _ = tracer.trace_value( + samples, + &acadrust::objects::XRecordValue::Handle(acadrust::Handle::default()), + ); + let _ = tracer.trace_value( + samples, + &acadrust::objects::XRecordValue::Point3D(0.0, 0.0, 0.0), + ); + let _ = tracer.trace_value(samples, &acadrust::objects::XRecordValue::Chunk(Vec::new())); + + // Proxy reference kinds pulled in by XRecord.object_references + let _ = tracer.trace_value(samples, &acadrust::objects::ProxyReferenceKind::Undefined); + let _ = tracer.trace_value( + samples, + &acadrust::objects::ProxyReferenceKind::SoftOwnership, + ); + let _ = tracer.trace_value( + samples, + &acadrust::objects::ProxyReferenceKind::HardOwnership, + ); + let _ = tracer.trace_value(samples, &acadrust::objects::ProxyReferenceKind::SoftPointer); + let _ = tracer.trace_value(samples, &acadrust::objects::ProxyReferenceKind::HardPointer); + + // KnownXRecordKind variants + let _ = tracer.trace_value( + samples, + &acadrust::objects::KnownXRecordKind::LayerViewportAlphaOverride, + ); + let _ = tracer.trace_value(samples, &acadrust::objects::KnownXRecordKind::Unknown); } fn map_to_custom_schema(traced: &Registry) -> TypeRegistry { diff --git a/crates/ocs_plugin_api/src/host.rs b/crates/ocs_plugin_api/src/host.rs index 3cecde5d3..4046b22b9 100644 --- a/crates/ocs_plugin_api/src/host.rs +++ b/crates/ocs_plugin_api/src/host.rs @@ -23,8 +23,12 @@ use crate::ribbon::CadModule; // so out-of-tree plugins can use them without adding their own acadrust // dependency (which would risk an ABI-mismatching version). pub use acadrust; +pub use acadrust::objects::{ + DictionaryCloningFlags, KnownXRecordKind, ProxyObjectReference, ProxyReferenceKind, XRecord, + XRecordEntry, XRecordSection, XRecordValue, XRecordValueType, +}; +pub use acadrust::xdata::{ExtendedDataRecord, XDataValue}; pub use acadrust::{CadDocument, EntityType, Handle}; -pub use acadrust::xdata::ExtendedDataRecord; use crate::ipc::protocol::{PluginRequest, PluginResponse}; diff --git a/crates/ocs_plugin_api/src/ipc/protocol.rs b/crates/ocs_plugin_api/src/ipc/protocol.rs index 812e91ebd..c20cad1b2 100644 --- a/crates/ocs_plugin_api/src/ipc/protocol.rs +++ b/crates/ocs_plugin_api/src/ipc/protocol.rs @@ -21,7 +21,7 @@ use crate::host::{CommandSource, CommandStep}; use crate::manifest::ApiVersion; use crate::ribbon::owned::{OwnedPluginManifest, OwnedRibbonGroup}; -pub use acadrust::xdata::ExtendedDataRecord; +pub use acadrust::xdata::{ExtendedDataRecord, XDataValue}; pub use acadrust::{CadDocument, EntityType, Handle}; /// Events the host forwards to an active plugin `InteractiveCommand`. diff --git a/crates/ocs_plugin_api/src/type_registry.rs b/crates/ocs_plugin_api/src/type_registry.rs index ce55abce8..0517d4dc5 100644 --- a/crates/ocs_plugin_api/src/type_registry.rs +++ b/crates/ocs_plugin_api/src/type_registry.rs @@ -38,10 +38,25 @@ mod tests { #[test] fn embedded_type_registry_contains_expected_acadrust_types() { - let registry: TypeRegistry = - serde_json::from_str(get_embedded_type_registry_json()).expect("valid TypeRegistry JSON"); + let registry: TypeRegistry = serde_json::from_str(get_embedded_type_registry_json()) + .expect("valid TypeRegistry JSON"); - for name in ["Point", "Line", "Circle", "MText", "EntityCommon"] { + for name in [ + "Point", + "Line", + "Circle", + "MText", + "EntityCommon", + "XRecord", + "XRecordEntry", + "XRecordValue", + "XRecordValueType", + "XRecordSection", + "DictionaryCloningFlags", + "KnownXRecordKind", + "ProxyObjectReference", + "ProxyReferenceKind", + ] { assert!( registry.types.contains_key(&TypeId::new(name)), "registry should contain {}", @@ -52,8 +67,8 @@ mod tests { #[test] fn embedded_type_registry_mtext_is_struct_with_expected_fields() { - let registry: TypeRegistry = - serde_json::from_str(get_embedded_type_registry_json()).expect("valid TypeRegistry JSON"); + let registry: TypeRegistry = serde_json::from_str(get_embedded_type_registry_json()) + .expect("valid TypeRegistry JSON"); let mtext = registry .types @@ -79,8 +94,8 @@ mod tests { #[test] fn embedded_type_registry_point_is_struct_with_expected_fields() { - let registry: TypeRegistry = - serde_json::from_str(get_embedded_type_registry_json()).expect("valid TypeRegistry JSON"); + let registry: TypeRegistry = serde_json::from_str(get_embedded_type_registry_json()) + .expect("valid TypeRegistry JSON"); let point = registry .types @@ -107,8 +122,8 @@ mod tests { #[test] fn embedded_type_registry_does_not_contain_entity_type() { - let registry: TypeRegistry = - serde_json::from_str(get_embedded_type_registry_json()).expect("valid TypeRegistry JSON"); + let registry: TypeRegistry = serde_json::from_str(get_embedded_type_registry_json()) + .expect("valid TypeRegistry JSON"); assert!( !registry.types.contains_key(&TypeId::new("EntityType")), "EntityType should not be in the allow-list registry" @@ -120,4 +135,62 @@ mod tests { let id = TypeId::new("Point"); assert_eq!(id.as_str(), "Point"); } + + #[test] + fn embedded_type_registry_xrecord_is_struct_with_expected_fields() { + let registry: TypeRegistry = serde_json::from_str(get_embedded_type_registry_json()) + .expect("valid TypeRegistry JSON"); + + let xrecord = registry + .types + .get(&TypeId::new("XRecord")) + .expect("XRecord in registry"); + assert_eq!(xrecord.kind, TypeKind::Struct); + + let field_names: Vec<&str> = xrecord.fields.iter().map(|f| f.name.as_str()).collect(); + for expected in [ + "handle", + "owner", + "reactors", + "xdictionary_handle", + "name", + "cloning_flags", + "entries", + "object_references", + "preserve_object_reference_stream", + "entries_complete", + "raw_data", + "raw_dwg_handle_bits", + ] { + assert!( + field_names.contains(&expected), + "XRecord should have field {}", + expected + ); + } + } + + #[test] + fn embedded_type_registry_xrecord_value_is_enum_with_expected_variants() { + let registry: TypeRegistry = serde_json::from_str(get_embedded_type_registry_json()) + .expect("valid TypeRegistry JSON"); + + let value = registry + .types + .get(&TypeId::new("XRecordValue")) + .expect("XRecordValue in registry"); + assert_eq!(value.kind, TypeKind::Enum); + + let variant_names: Vec<&str> = value.variants.iter().map(|v| v.name.as_str()).collect(); + for expected in [ + "String", "Double", "Int16", "Int32", "Int64", "Byte", "Bool", "Handle", "Point3D", + "Chunk", + ] { + assert!( + variant_names.contains(&expected), + "XRecordValue should have variant {}", + expected + ); + } + } }