forked from 1b-agent/opencadstudio-upstream
Add nested attribute entity host support
This commit is contained in:
1 parent
5ef7000b67
commit
cf2a923568
6 files changed
+2509
-541
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -3,6 +3,27 @@
|
||||
use crate::host::HostApi;
|
||||
use crate::ipc::protocol::{PluginRequest, PluginResponse};
|
||||
|
||||
fn addressable_document_snapshot(host: &dyn HostApi) -> acadrust::CadDocument {
|
||||
let mut snapshot = host.document().clone();
|
||||
let attributes = host
|
||||
.document()
|
||||
.entities()
|
||||
.filter_map(|entity| match entity {
|
||||
acadrust::EntityType::Insert(insert) => Some(insert.attributes.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.flatten()
|
||||
.map(acadrust::EntityType::AttributeEntity)
|
||||
.collect::<Vec<_>>();
|
||||
for attribute in attributes {
|
||||
// Attribute entities remain canonical children of INSERT in the host
|
||||
// document. The IPC snapshot also indexes them by handle so plugin
|
||||
// document models can address a child exactly like any other entity.
|
||||
let _ = snapshot.add_entity(attribute);
|
||||
}
|
||||
snapshot
|
||||
}
|
||||
|
||||
/// Apply one plugin request to the host's `HostApi` implementation.
|
||||
///
|
||||
/// `on_start_interactive` is called when the plugin starts an interactive
|
||||
@@ -54,7 +75,7 @@ pub fn handle_plugin_request(
|
||||
on_start_interactive(command_id);
|
||||
PluginResponse::Ok
|
||||
}
|
||||
DocumentSnapshot => PluginResponse::Document(Box::new(host.document().clone())),
|
||||
DocumentSnapshot => PluginResponse::Document(Box::new(addressable_document_snapshot(host))),
|
||||
OpenDocumentView => match host.document_view() {
|
||||
Some(info) => PluginResponse::DocumentView {
|
||||
path: info.path,
|
||||
@@ -77,9 +98,7 @@ pub fn handle_plugin_request(
|
||||
DocumentPath { tab_id } => PluginResponse::DocumentPath(
|
||||
host.document_path(tab_id).map(|path| path.into_os_string()),
|
||||
),
|
||||
GetSystemVariable { name } => {
|
||||
PluginResponse::SystemVariable(host.system_variable(&name))
|
||||
}
|
||||
GetSystemVariable { name } => PluginResponse::SystemVariable(host.system_variable(&name)),
|
||||
SetSystemVariable { name, value } => {
|
||||
PluginResponse::SystemVariableResult(host.set_system_variable(&name, value))
|
||||
}
|
||||
|
||||
@@ -83,13 +83,19 @@ impl<T: SnapshotData> DocumentSnapshotStore<T> {
|
||||
/// page.
|
||||
pub fn new(tab_id: u64, segment_size: usize) -> io::Result<Self> {
|
||||
let segment_size = segment_size.checked_next_multiple_of(4096).ok_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "snapshot segment size overflow")
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"snapshot segment size overflow",
|
||||
)
|
||||
})?;
|
||||
let total = segment_size
|
||||
.checked_mul(2)
|
||||
.and_then(|segments| CONTROL_SIZE.checked_add(segments))
|
||||
.ok_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "snapshot mapping size overflow")
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"snapshot mapping size overflow",
|
||||
)
|
||||
})?;
|
||||
if total > MAX_SNAPSHOT_SIZE {
|
||||
return Err(io::Error::new(
|
||||
@@ -245,7 +251,10 @@ impl<T: SnapshotData> SharedDocumentReader<T> {
|
||||
));
|
||||
}
|
||||
let file_len = usize::try_from(file_len).map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidData, "snapshot file size is unsupported")
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"snapshot file size is unsupported",
|
||||
)
|
||||
})?;
|
||||
let mmap = unsafe { MmapOptions::new().len(file_len).map(&file)? };
|
||||
let segment_size = (file_len - CONTROL_SIZE) / 2;
|
||||
@@ -543,10 +552,22 @@ pub struct DocumentViewDataV4 {
|
||||
|
||||
impl From<&CadDocument> for DocumentViewDataV4 {
|
||||
fn from(doc: &CadDocument) -> Self {
|
||||
let mut entities: Vec<_> = doc.entities().map(EntityViewV4::from).collect();
|
||||
// ATTRIB records live inside their owning INSERT in CadDocument rather
|
||||
// than in the flat entity index. Flatten them into the plugin snapshot
|
||||
// as addressable entities while keeping the INSERT's canonical nested
|
||||
// copy intact for rendering and file serialization.
|
||||
for entity in doc.entities() {
|
||||
if let EntityType::Insert(insert) = entity {
|
||||
entities.extend(insert.attributes.iter().map(|attribute| {
|
||||
EntityViewV4::from(&EntityType::AttributeEntity(attribute.clone()))
|
||||
}));
|
||||
}
|
||||
}
|
||||
Self {
|
||||
layers: doc.layers.iter().map(LayerView::from).collect(),
|
||||
app_ids: doc.app_ids.iter().map(AppIdView::from).collect(),
|
||||
entities: doc.entities().map(EntityViewV4::from).collect(),
|
||||
entities,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -721,7 +742,10 @@ mod tests {
|
||||
|
||||
let archived = reader.archived().unwrap();
|
||||
let entity = &archived.entities[0];
|
||||
assert_eq!(entity.handle, doc.entities().next().unwrap().common().handle.value());
|
||||
assert_eq!(
|
||||
entity.handle,
|
||||
doc.entities().next().unwrap().common().handle.value()
|
||||
);
|
||||
let decoded: EntityType = bincode::deserialize(&entity.data).expect("bincode decode");
|
||||
assert!(matches!(decoded, EntityType::Point(_)));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user