forked from 1b-agent/opencadstudio-upstream
Support Color in the Python adapter generator; map Leader.override_color
Color converts as {'kind': ByLayer|None|ByBlock|Index|Rgb, 'value': ...}.
Leader.override_color is now writable; neither DWG nor DXF stores it, which
is recorded as a fourth persistence blocker with a canary assertion.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
1 parent
6b4c86fd7a
commit
22f9c20fe8
8 files changed
+73
-9
No files matched your search
@@ -110,7 +110,7 @@ const BUILTIN: &[&str] = &[
|
||||
];
|
||||
/// Types with their own hand-written conversion helpers in `ocs_module.rs`
|
||||
/// (`vector3_to_py`/`py_to_vector3`, etc.) rather than generated ones.
|
||||
const SPECIAL: &[&str] = &["Vector3", "Vector2", "Handle"];
|
||||
const SPECIAL: &[&str] = &["Vector3", "Vector2", "Handle", "Color"];
|
||||
|
||||
enum Classify {
|
||||
/// A C-like enum: every variant is a unit variant. Represented in Python
|
||||
@@ -289,6 +289,7 @@ fn default_expr(type_id: &str) -> String {
|
||||
"Vector3" => "acadrust::types::Vector3::ZERO".to_string(),
|
||||
"Vector2" => "acadrust::types::Vector2::ZERO".to_string(),
|
||||
"Handle" => "acadrust::Handle::new(0)".to_string(),
|
||||
"Color" => "acadrust::types::Color::ByLayer".to_string(),
|
||||
other => format!("default_{}()", snake_case(other)),
|
||||
}
|
||||
}
|
||||
@@ -309,6 +310,7 @@ fn leaf_to_py(registry: &TypeRegistry, type_id: &str, item_expr: &str) -> String
|
||||
"Vector3" => format!("vector3_to_py_dict(vm, {item_expr})"),
|
||||
"Vector2" => format!("vector2_to_py(vm, {item_expr})"),
|
||||
"Handle" => format!("Ok(vm.new_pyobj({parenthesized}.value()))"),
|
||||
"Color" => format!("color_to_py_dict(vm, {item_expr})"),
|
||||
other => {
|
||||
let info = get(registry, other)
|
||||
.unwrap_or_else(|| panic!("type {other} missing from registry"));
|
||||
@@ -333,6 +335,7 @@ fn leaf_from_py(registry: &TypeRegistry, type_id: &str, value_expr: &str) -> Str
|
||||
"Vector3" => format!("py_to_vector3_dict({value_expr}, vm)"),
|
||||
"Vector2" => format!("py_to_vector2({value_expr}, vm)"),
|
||||
"Handle" => format!("{value_expr}.try_into_value::<u64>(vm).map(acadrust::Handle::new)"),
|
||||
"Color" => format!("py_to_color_dict({value_expr}, vm)"),
|
||||
other => {
|
||||
let info = get(registry, other)
|
||||
.unwrap_or_else(|| panic!("type {other} missing from registry"));
|
||||
|
||||
@@ -262,11 +262,7 @@
|
||||
"dwg_unknown_bit3": { "exclude": true },
|
||||
"dwg_unknown_bit4": { "exclude": true },
|
||||
"dwg_unknown_bit5": { "exclude": true },
|
||||
"dwg_unknown_short1": { "exclude": true },
|
||||
"override_color": {
|
||||
"exclude": true,
|
||||
"_comment": "Color is a multi-payload tagged enum the generator cannot express yet. It stays snapshot-readable and is preserved untouched by Python edits."
|
||||
}
|
||||
"dwg_unknown_short1": { "exclude": true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3131,6 +3131,63 @@ mod ocs {
|
||||
}
|
||||
}
|
||||
|
||||
/// `Color` as `{"kind": "ByLayer" | "None" | "ByBlock"}`,
|
||||
/// `{"kind": "Index", "value": n}` or
|
||||
/// `{"kind": "Rgb", "value": {"r": .., "g": .., "b": ..}}`.
|
||||
fn color_to_py_dict(vm: &VirtualMachine, color: &acadrust::types::Color) -> PyResult<PyObjectRef> {
|
||||
use acadrust::types::Color;
|
||||
let dict = vm.ctx.new_dict();
|
||||
match color {
|
||||
Color::ByLayer => dict.set_item("kind", vm.new_pyobj("ByLayer"), vm)?,
|
||||
Color::None => dict.set_item("kind", vm.new_pyobj("None"), vm)?,
|
||||
Color::ByBlock => dict.set_item("kind", vm.new_pyobj("ByBlock"), vm)?,
|
||||
Color::Index(index) => {
|
||||
dict.set_item("kind", vm.new_pyobj("Index"), vm)?;
|
||||
dict.set_item("value", vm.new_pyobj(i64::from(*index)), vm)?;
|
||||
}
|
||||
Color::Rgb { r, g, b } => {
|
||||
dict.set_item("kind", vm.new_pyobj("Rgb"), vm)?;
|
||||
let rgb = vm.ctx.new_dict();
|
||||
rgb.set_item("r", vm.new_pyobj(i64::from(*r)), vm)?;
|
||||
rgb.set_item("g", vm.new_pyobj(i64::from(*g)), vm)?;
|
||||
rgb.set_item("b", vm.new_pyobj(i64::from(*b)), vm)?;
|
||||
dict.set_item("value", PyObjectRef::from(rgb), vm)?;
|
||||
}
|
||||
}
|
||||
Ok(dict.into())
|
||||
}
|
||||
|
||||
fn py_to_color_dict(value: PyObjectRef, vm: &VirtualMachine) -> PyResult<acadrust::types::Color> {
|
||||
use acadrust::types::Color;
|
||||
let dict = value.try_into_value::<rustpython_vm::builtins::PyDictRef>(vm)?;
|
||||
let kind = dict.get_item("kind", vm)?.try_into_value::<String>(vm)?;
|
||||
let byte = |v: PyObjectRef, what: &str| -> PyResult<u8> {
|
||||
let n = v.try_into_value::<i64>(vm)?;
|
||||
u8::try_from(n).map_err(|_| vm.new_value_error(format!("Color {what} must be 0..=255")))
|
||||
};
|
||||
Ok(match kind.as_str() {
|
||||
"ByLayer" => Color::ByLayer,
|
||||
"None" => Color::None,
|
||||
"ByBlock" => Color::ByBlock,
|
||||
"Index" => {
|
||||
let index = byte(dict.get_item("value", vm)?, "index")?;
|
||||
if index == 0 {
|
||||
return Err(vm.new_value_error("Color index must be 1..=255; use ByBlock for 0".to_owned()));
|
||||
}
|
||||
Color::Index(index)
|
||||
}
|
||||
"Rgb" => {
|
||||
let rgb = dict.get_item("value", vm)?.try_into_value::<rustpython_vm::builtins::PyDictRef>(vm)?;
|
||||
Color::Rgb {
|
||||
r: byte(rgb.get_item("r", vm)?, "r")?,
|
||||
g: byte(rgb.get_item("g", vm)?, "g")?,
|
||||
b: byte(rgb.get_item("b", vm)?, "b")?,
|
||||
}
|
||||
}
|
||||
other => return Err(vm.new_value_error(format!("ocs: unsupported Color kind: {other}"))),
|
||||
})
|
||||
}
|
||||
|
||||
/// Accept a Python int or float; `try_into_value::<f64>` rejects ints.
|
||||
fn py_number_to_f64(value: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> {
|
||||
Ok(value.try_float(vm)?.to_f64())
|
||||
|
||||
Reference in new issue
Block a user