Add ocs_doc_api: object-oriented CAD entity API (v2)

New crate crates/ocs_doc_api: object-centric facade (DocApi -> Document ->
collections -> typed handles), transport-agnostic wire layer (DocApiEnvelope =
single op | read-only query batch), per-op autocommit (no write transactions),
bulk ops with upfront-validation all-or-nothing, structured ApiError, and
build-time codegen (spec/entities.toml -> ops/query enums, api_reference.md,
binding_schema.json).

ocs_plugin_api: append-only PluginRequest::DocApiRequest / PluginResponse::
DocApiResponse (serde_bytes payload) + defaulted HostApi::doc_api_dispatch.

Host: DocApiBackend impl for HostSession (src/app/doc_api.rs) mapping to scene
primitives (solid_models lift-on-miss, register_prepared_solid_model, meshes
metrics), entity conversions (doc_api_convert.rs), HostSession accessors +
doc_api_dispatch override.

Tests: 592 host lib (incl. 7 DocApi integration tests: create/boolean/query,
unknown-id, transform-many all-or-nothing, query-batch cap, 2D/geometric/DWG
roundtrips), 8 crate unit tests. Examples + README/ARCHITECTURE/IMPLEMENTATION docs.
This commit is contained in:
Sebastian committed 2026-09-06 00:15:27 +02:00
1 parent 9129c85f97
commit e41086b058
44 files changed
+4837 -12

No files matched your search

+61
View File
@@ -0,0 +1,61 @@
//! Read queries — typed, transport-agnostic reads of entity state (plan §5).
//! The `Query` enum is GENERATED into `crate::gen` by `build.rs`; this module
//! re-exports it and holds the hand-written result DTOs.
use serde::{Deserialize, Serialize};
use crate::id::ObjectId;
use crate::revision::GeometryRevision;
pub use crate::gen::Query;
/// Axis-aligned bounding box (plain-data mirror of the kernel's non-serde `Aabb`).
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct Aabb {
pub min: [f64; 3],
pub max: [f64; 3],
}
impl Aabb {
pub fn overlaps(&self, other: &Aabb) -> bool {
(0..3).all(|i| self.min[i] <= other.max[i] && other.min[i] <= self.max[i])
}
}
/// A generic, untyped view of an entity returned by [`Query::GetEntity`].
/// Family-specific data lives in the typed construction specs; this carries
/// identity + kind + a coarse bounding box so any first-level entity is readable.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct EntityView {
pub id: ObjectId,
/// The acadrust `EntityType` variant name (e.g. "Solid3D", "Line").
pub kind: String,
pub bounds: Option<Aabb>,
}
/// The result of a single [`Query`] (one per query in a `Queries` batch).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum QueryResult {
Entity(EntityView),
Bounds(Aabb),
Centroid([f64; 3]),
Volume(f64),
/// Whether two entities' bounds overlap (two-phase conditional modelling).
Intersects(bool),
Revision(GeometryRevision),
}
/// Convenience: the query name for diagnostics.
impl crate::gen::Query {
pub fn query_name(&self) -> &'static str {
use crate::gen::Query::*;
match self {
GetEntity { .. } => "GetEntity",
GetBounds { .. } => "GetBounds",
GetCentroid { .. } => "GetCentroid",
GetVolume { .. } => "GetVolume",
GetIntersects { .. } => "GetIntersects",
GetGeometryRevision => "GetGeometryRevision",
}
}
}