fix(api): strengthen crate-level and high-impact API docs (#13)
* docs(api): strengthen crate and high-impact rustdoc * fix(readme): update stale crate version references
This commit is contained in:
parent
2aada9a247
commit
22f168017a
12
README.md
12
README.md
|
|
@ -8,7 +8,7 @@ Maintainer workflow: see `CONTRIBUTIONS.md`.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Alpha. `v0.1.1` released.
|
Alpha. `v0.3.0` released.
|
||||||
|
|
||||||
- Async API (default): implemented and usable.
|
- Async API (default): implemented and usable.
|
||||||
- Sync/blocking wrapper API (`feature = "blocking"`): implemented with full async parity.
|
- Sync/blocking wrapper API (`feature = "blocking"`): implemented with full async parity.
|
||||||
|
|
@ -23,7 +23,7 @@ Alpha. `v0.1.1` released.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
kicad-ipc-rs = "0.1.1"
|
kicad-ipc-rs = "0.3.0"
|
||||||
tokio = { version = "1", features = ["macros", "rt"] }
|
tokio = { version = "1", features = ["macros", "rt"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ Enable the `blocking` feature and use `KiCadClientBlocking` for synchronous call
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
kicad-ipc-rs = { version = "0.1.1", features = ["blocking"] }
|
kicad-ipc-rs = { version = "0.3.0", features = ["blocking"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
|
@ -226,3 +226,9 @@ Legend:
|
||||||
- Expand runtime + integration testing coverage.
|
- Expand runtime + integration testing coverage.
|
||||||
- Set up CI to run checks/tests on commits and PRs.
|
- Set up CI to run checks/tests on commits and PRs.
|
||||||
- Continue API hardening/docs/examples for stable `1.0` path.
|
- Continue API hardening/docs/examples for stable `1.0` path.
|
||||||
|
|
||||||
|
## Future Work: Public Surface + Docs
|
||||||
|
|
||||||
|
- This crate is still in alpha, and some lower-level modules currently remain public for advanced/debugging workflows.
|
||||||
|
- `#![warn(missing_docs)]` is enabled; high-impact user APIs are documented first, and remaining warnings are being burned down incrementally.
|
||||||
|
- As usage data accumulates, internal surfaces (`commands`, `envelope`, transport/proto-adjacent helpers) may be narrowed or made `pub(crate)` where possible without breaking user workflows.
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,10 @@ const PCB_OBJECT_TYPES: [PcbObjectTypeCode; 18] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
/// Async IPC client for communicating with a running KiCad instance.
|
||||||
|
///
|
||||||
|
/// Create with [`KiCadClient::connect`] for defaults or [`KiCadClient::builder`]
|
||||||
|
/// to override socket path, timeout, token, or client name.
|
||||||
pub struct KiCadClient {
|
pub struct KiCadClient {
|
||||||
inner: Arc<ClientInner>,
|
inner: Arc<ClientInner>,
|
||||||
}
|
}
|
||||||
|
|
@ -234,11 +238,19 @@ struct ClientConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
/// Builder for [`KiCadClient`].
|
||||||
|
///
|
||||||
|
/// Defaults:
|
||||||
|
/// - timeout: `3s`
|
||||||
|
/// - socket path: `KICAD_API_SOCKET` env var, then platform default
|
||||||
|
/// - token: `KICAD_API_TOKEN` env var, then empty
|
||||||
|
/// - client name: autogenerated
|
||||||
pub struct ClientBuilder {
|
pub struct ClientBuilder {
|
||||||
config: ClientConfig,
|
config: ClientConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientBuilder {
|
impl ClientBuilder {
|
||||||
|
/// Creates a builder with sensible defaults for local KiCad IPC usage.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
config: ClientConfig {
|
config: ClientConfig {
|
||||||
|
|
@ -250,26 +262,39 @@ impl ClientBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets per-request timeout used by the IPC transport.
|
||||||
pub fn timeout(mut self, timeout: Duration) -> Self {
|
pub fn timeout(mut self, timeout: Duration) -> Self {
|
||||||
self.config.timeout = timeout;
|
self.config.timeout = timeout;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets explicit KiCad IPC socket URI/path.
|
||||||
|
///
|
||||||
|
/// If unset, the builder resolves from environment/defaults.
|
||||||
pub fn socket_path(mut self, socket_path: impl Into<String>) -> Self {
|
pub fn socket_path(mut self, socket_path: impl Into<String>) -> Self {
|
||||||
self.config.socket_uri = Some(socket_path.into());
|
self.config.socket_uri = Some(socket_path.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the IPC authentication token.
|
||||||
|
///
|
||||||
|
/// If unset, the builder uses `KICAD_API_TOKEN` when present.
|
||||||
pub fn token(mut self, token: impl Into<String>) -> Self {
|
pub fn token(mut self, token: impl Into<String>) -> Self {
|
||||||
self.config.token = Some(token.into());
|
self.config.token = Some(token.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the client name reported to KiCad.
|
||||||
pub fn client_name(mut self, client_name: impl Into<String>) -> Self {
|
pub fn client_name(mut self, client_name: impl Into<String>) -> Self {
|
||||||
self.config.client_name = Some(client_name.into());
|
self.config.client_name = Some(client_name.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Connects to KiCad IPC with the configured options.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Returns [`KiCadError`] when socket discovery, connection, or transport
|
||||||
|
/// initialization fails.
|
||||||
pub async fn connect(self) -> Result<KiCadClient, KiCadError> {
|
pub async fn connect(self) -> Result<KiCadClient, KiCadError> {
|
||||||
let socket_uri = resolve_socket_uri(self.config.socket_uri.as_deref());
|
let socket_uri = resolve_socket_uri(self.config.socket_uri.as_deref());
|
||||||
if is_missing_ipc_socket(&socket_uri) {
|
if is_missing_ipc_socket(&socket_uri) {
|
||||||
|
|
@ -306,28 +331,34 @@ impl Default for ClientBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KiCadClient {
|
impl KiCadClient {
|
||||||
|
/// Returns a configurable builder for creating a [`KiCadClient`].
|
||||||
pub fn builder() -> ClientBuilder {
|
pub fn builder() -> ClientBuilder {
|
||||||
ClientBuilder::new()
|
ClientBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Connects with default builder settings.
|
||||||
pub async fn connect() -> Result<Self, KiCadError> {
|
pub async fn connect() -> Result<Self, KiCadError> {
|
||||||
ClientBuilder::new().connect().await
|
ClientBuilder::new().connect().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns configured per-request timeout.
|
||||||
pub fn timeout(&self) -> Duration {
|
pub fn timeout(&self) -> Duration {
|
||||||
self.inner.timeout
|
self.inner.timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns resolved KiCad IPC socket URI/path.
|
||||||
pub fn socket_uri(&self) -> &str {
|
pub fn socket_uri(&self) -> &str {
|
||||||
&self.inner.socket_uri
|
&self.inner.socket_uri
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sends a health-check request to KiCad.
|
||||||
pub async fn ping(&self) -> Result<(), KiCadError> {
|
pub async fn ping(&self) -> Result<(), KiCadError> {
|
||||||
let command = envelope::pack_any(&common_commands::Ping {}, CMD_PING);
|
let command = envelope::pack_any(&common_commands::Ping {}, CMD_PING);
|
||||||
self.send_command(command).await?;
|
self.send_command(command).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Requests KiCad to refresh a specific editor frame.
|
||||||
pub async fn refresh_editor(&self, frame: EditorFrameType) -> Result<(), KiCadError> {
|
pub async fn refresh_editor(&self, frame: EditorFrameType) -> Result<(), KiCadError> {
|
||||||
let command = envelope::pack_any(
|
let command = envelope::pack_any(
|
||||||
&common_commands::RefreshEditor {
|
&common_commands::RefreshEditor {
|
||||||
|
|
@ -352,6 +383,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_RUN_ACTION_RESPONSE)
|
response_payload_as_any(response, RES_RUN_ACTION_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Runs a KiCad action by action name and returns mapped status.
|
||||||
pub async fn run_action(
|
pub async fn run_action(
|
||||||
&self,
|
&self,
|
||||||
action: impl Into<String>,
|
action: impl Into<String>,
|
||||||
|
|
@ -362,6 +394,7 @@ impl KiCadClient {
|
||||||
Ok(map_run_action_status(response.status))
|
Ok(map_run_action_status(response.status))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Queries KiCad version info for the connected instance.
|
||||||
pub async fn get_version(&self) -> Result<VersionInfo, KiCadError> {
|
pub async fn get_version(&self) -> Result<VersionInfo, KiCadError> {
|
||||||
let command = envelope::pack_any(&common_commands::GetVersion {}, CMD_GET_VERSION);
|
let command = envelope::pack_any(&common_commands::GetVersion {}, CMD_GET_VERSION);
|
||||||
let response = self.send_command(command).await?;
|
let response = self.send_command(command).await?;
|
||||||
|
|
@ -394,6 +427,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_PATH_RESPONSE)
|
response_payload_as_any(response, RES_PATH_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves a KiCad binary path by binary name.
|
||||||
pub async fn get_kicad_binary_path(
|
pub async fn get_kicad_binary_path(
|
||||||
&self,
|
&self,
|
||||||
binary_name: impl Into<String>,
|
binary_name: impl Into<String>,
|
||||||
|
|
@ -416,6 +450,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_STRING_RESPONSE)
|
response_payload_as_any(response, RES_STRING_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves plugin settings path for a plugin identifier.
|
||||||
pub async fn get_plugin_settings_path(
|
pub async fn get_plugin_settings_path(
|
||||||
&self,
|
&self,
|
||||||
identifier: impl Into<String>,
|
identifier: impl Into<String>,
|
||||||
|
|
@ -425,6 +460,7 @@ impl KiCadClient {
|
||||||
Ok(response.response)
|
Ok(response.response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lists open KiCad documents of the requested type.
|
||||||
pub async fn get_open_documents(
|
pub async fn get_open_documents(
|
||||||
&self,
|
&self,
|
||||||
document_type: DocumentType,
|
document_type: DocumentType,
|
||||||
|
|
@ -455,6 +491,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_NET_CLASSES_RESPONSE)
|
response_payload_as_any(response, RES_NET_CLASSES_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads project net classes from the current project context.
|
||||||
pub async fn get_net_classes(&self) -> Result<Vec<NetClassInfo>, KiCadError> {
|
pub async fn get_net_classes(&self) -> Result<Vec<NetClassInfo>, KiCadError> {
|
||||||
let payload = self.get_net_classes_raw().await?;
|
let payload = self.get_net_classes_raw().await?;
|
||||||
let response: common_commands::NetClassesResponse =
|
let response: common_commands::NetClassesResponse =
|
||||||
|
|
@ -487,6 +524,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_PROTOBUF_EMPTY)
|
response_payload_as_any(response, RES_PROTOBUF_EMPTY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replaces or merges project net classes, then returns current classes.
|
||||||
pub async fn set_net_classes(
|
pub async fn set_net_classes(
|
||||||
&self,
|
&self,
|
||||||
net_classes: Vec<NetClassInfo>,
|
net_classes: Vec<NetClassInfo>,
|
||||||
|
|
@ -506,6 +544,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_TEXT_VARIABLES)
|
response_payload_as_any(response, RES_TEXT_VARIABLES)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads project text variables.
|
||||||
pub async fn get_text_variables(&self) -> Result<BTreeMap<String, String>, KiCadError> {
|
pub async fn get_text_variables(&self) -> Result<BTreeMap<String, String>, KiCadError> {
|
||||||
let payload = self.get_text_variables_raw().await?;
|
let payload = self.get_text_variables_raw().await?;
|
||||||
let response: common_project::TextVariables = decode_any(&payload, RES_TEXT_VARIABLES)?;
|
let response: common_project::TextVariables = decode_any(&payload, RES_TEXT_VARIABLES)?;
|
||||||
|
|
@ -530,6 +569,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_PROTOBUF_EMPTY)
|
response_payload_as_any(response, RES_PROTOBUF_EMPTY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replaces or merges project text variables, then returns current values.
|
||||||
pub async fn set_text_variables(
|
pub async fn set_text_variables(
|
||||||
&self,
|
&self,
|
||||||
variables: BTreeMap<String, String>,
|
variables: BTreeMap<String, String>,
|
||||||
|
|
@ -553,6 +593,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_EXPAND_TEXT_VARIABLES_RESPONSE)
|
response_payload_as_any(response, RES_EXPAND_TEXT_VARIABLES_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Expands `${VAR}`-style text variables using current project context.
|
||||||
pub async fn expand_text_variables(
|
pub async fn expand_text_variables(
|
||||||
&self,
|
&self,
|
||||||
text: Vec<String>,
|
text: Vec<String>,
|
||||||
|
|
@ -576,6 +617,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_BOX2)
|
response_payload_as_any(response, RES_BOX2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes rendered text extents in nanometer units.
|
||||||
pub async fn get_text_extents(&self, text: TextSpec) -> Result<TextExtents, KiCadError> {
|
pub async fn get_text_extents(&self, text: TextSpec) -> Result<TextExtents, KiCadError> {
|
||||||
let payload = self.get_text_extents_raw(text).await?;
|
let payload = self.get_text_extents_raw(text).await?;
|
||||||
let response: common_types::Box2 = decode_any(&payload, RES_BOX2)?;
|
let response: common_types::Box2 = decode_any(&payload, RES_BOX2)?;
|
||||||
|
|
@ -609,6 +651,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_GET_TEXT_AS_SHAPES_RESPONSE)
|
response_payload_as_any(response, RES_GET_TEXT_AS_SHAPES_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts text/textbox specs into drawable shape geometry.
|
||||||
pub async fn get_text_as_shapes(
|
pub async fn get_text_as_shapes(
|
||||||
&self,
|
&self,
|
||||||
text: Vec<TextObjectSpec>,
|
text: Vec<TextObjectSpec>,
|
||||||
|
|
@ -624,11 +667,15 @@ impl KiCadClient {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the current PCB project's path.
|
||||||
|
///
|
||||||
|
/// Fails if no PCB is open or if multiple project paths are present.
|
||||||
pub async fn get_current_project_path(&self) -> Result<PathBuf, KiCadError> {
|
pub async fn get_current_project_path(&self) -> Result<PathBuf, KiCadError> {
|
||||||
let docs = self.get_open_documents(DocumentType::Pcb).await?;
|
let docs = self.get_open_documents(DocumentType::Pcb).await?;
|
||||||
select_single_project_path(&docs)
|
select_single_project_path(&docs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` when at least one PCB document is open in KiCad.
|
||||||
pub async fn has_open_board(&self) -> Result<bool, KiCadError> {
|
pub async fn has_open_board(&self) -> Result<bool, KiCadError> {
|
||||||
let docs = self.get_open_documents(DocumentType::Pcb).await?;
|
let docs = self.get_open_documents(DocumentType::Pcb).await?;
|
||||||
Ok(!docs.is_empty())
|
Ok(!docs.is_empty())
|
||||||
|
|
@ -642,6 +689,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_BEGIN_COMMIT_RESPONSE)
|
response_payload_as_any(response, RES_BEGIN_COMMIT_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Starts a KiCad commit session used for grouped board edits.
|
||||||
pub async fn begin_commit(&self) -> Result<CommitSession, KiCadError> {
|
pub async fn begin_commit(&self) -> Result<CommitSession, KiCadError> {
|
||||||
let payload = self.begin_commit_raw().await?;
|
let payload = self.begin_commit_raw().await?;
|
||||||
let response: common_commands::BeginCommitResponse =
|
let response: common_commands::BeginCommitResponse =
|
||||||
|
|
@ -672,6 +720,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_END_COMMIT_RESPONSE)
|
response_payload_as_any(response, RES_END_COMMIT_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finalizes a commit session, either committing or dropping staged changes.
|
||||||
pub async fn end_commit(
|
pub async fn end_commit(
|
||||||
&self,
|
&self,
|
||||||
session: CommitSession,
|
session: CommitSession,
|
||||||
|
|
@ -699,6 +748,9 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_CREATE_ITEMS_RESPONSE)
|
response_payload_as_any(response, RES_CREATE_ITEMS_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates items in the active PCB document.
|
||||||
|
///
|
||||||
|
/// Returns created items as raw protobuf `Any` payloads.
|
||||||
pub async fn create_items(
|
pub async fn create_items(
|
||||||
&self,
|
&self,
|
||||||
items: Vec<prost_types::Any>,
|
items: Vec<prost_types::Any>,
|
||||||
|
|
@ -736,6 +788,9 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_UPDATE_ITEMS_RESPONSE)
|
response_payload_as_any(response, RES_UPDATE_ITEMS_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates existing items in the active PCB document.
|
||||||
|
///
|
||||||
|
/// Returns updated items as raw protobuf `Any` payloads.
|
||||||
pub async fn update_items(
|
pub async fn update_items(
|
||||||
&self,
|
&self,
|
||||||
items: Vec<prost_types::Any>,
|
items: Vec<prost_types::Any>,
|
||||||
|
|
@ -775,6 +830,9 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_DELETE_ITEMS_RESPONSE)
|
response_payload_as_any(response, RES_DELETE_ITEMS_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deletes items by id from the active PCB document.
|
||||||
|
///
|
||||||
|
/// Returns ids of items deleted by KiCad.
|
||||||
pub async fn delete_items(&self, item_ids: Vec<String>) -> Result<Vec<String>, KiCadError> {
|
pub async fn delete_items(&self, item_ids: Vec<String>) -> Result<Vec<String>, KiCadError> {
|
||||||
let payload = self.delete_items_raw(item_ids).await?;
|
let payload = self.delete_items_raw(item_ids).await?;
|
||||||
let response: common_commands::DeleteItemsResponse =
|
let response: common_commands::DeleteItemsResponse =
|
||||||
|
|
@ -836,6 +894,7 @@ impl KiCadClient {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns nets from the active PCB document.
|
||||||
pub async fn get_nets(&self) -> Result<Vec<BoardNet>, KiCadError> {
|
pub async fn get_nets(&self) -> Result<Vec<BoardNet>, KiCadError> {
|
||||||
let board = self.current_board_document_proto().await?;
|
let board = self.current_board_document_proto().await?;
|
||||||
let command = board_commands::GetNets {
|
let command = board_commands::GetNets {
|
||||||
|
|
@ -981,6 +1040,7 @@ impl KiCadClient {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a compact summary of the current PCB selection.
|
||||||
pub async fn get_selection_summary(&self) -> Result<SelectionSummary, KiCadError> {
|
pub async fn get_selection_summary(&self) -> Result<SelectionSummary, KiCadError> {
|
||||||
let document = self.current_board_document_proto().await?;
|
let document = self.current_board_document_proto().await?;
|
||||||
let command = common_commands::GetSelection {
|
let command = common_commands::GetSelection {
|
||||||
|
|
@ -1023,6 +1083,7 @@ impl KiCadClient {
|
||||||
summarize_item_details(items)
|
summarize_item_details(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the current selection as decoded typed PCB items.
|
||||||
pub async fn get_selection(&self) -> Result<Vec<PcbItem>, KiCadError> {
|
pub async fn get_selection(&self) -> Result<Vec<PcbItem>, KiCadError> {
|
||||||
let items = self.get_selection_raw().await?;
|
let items = self.get_selection_raw().await?;
|
||||||
decode_pcb_items(items)
|
decode_pcb_items(items)
|
||||||
|
|
@ -1154,10 +1215,12 @@ impl KiCadClient {
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns known KiCad PCB object type codes handled by this crate.
|
||||||
pub fn pcb_object_type_codes() -> &'static [PcbObjectTypeCode] {
|
pub fn pcb_object_type_codes() -> &'static [PcbObjectTypeCode] {
|
||||||
&PCB_OBJECT_TYPES
|
&PCB_OBJECT_TYPES
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves a human-readable object type name from a KiCad object type code.
|
||||||
pub fn pcb_object_type_name(type_code: i32) -> Option<&'static str> {
|
pub fn pcb_object_type_name(type_code: i32) -> Option<&'static str> {
|
||||||
PCB_OBJECT_TYPES
|
PCB_OBJECT_TYPES
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -1165,6 +1228,7 @@ impl KiCadClient {
|
||||||
.map(|entry| entry.name)
|
.map(|entry| entry.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Formats a raw protobuf PCB item payload for debugging/logging.
|
||||||
pub fn debug_any_item(item: &prost_types::Any) -> Result<String, KiCadError> {
|
pub fn debug_any_item(item: &prost_types::Any) -> Result<String, KiCadError> {
|
||||||
any_to_pretty_debug(item)
|
any_to_pretty_debug(item)
|
||||||
}
|
}
|
||||||
|
|
@ -1184,6 +1248,7 @@ impl KiCadClient {
|
||||||
summarize_item_details(items)
|
summarize_item_details(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetches and decodes items by KiCad object type codes.
|
||||||
pub async fn get_items_by_type_codes(
|
pub async fn get_items_by_type_codes(
|
||||||
&self,
|
&self,
|
||||||
type_codes: Vec<i32>,
|
type_codes: Vec<i32>,
|
||||||
|
|
@ -1216,6 +1281,7 @@ impl KiCadClient {
|
||||||
Ok(rows)
|
Ok(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetches all known PCB item kinds and decodes each bucket.
|
||||||
pub async fn get_all_pcb_items(
|
pub async fn get_all_pcb_items(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<Vec<(PcbObjectTypeCode, Vec<PcbItem>)>, KiCadError> {
|
) -> Result<Vec<(PcbObjectTypeCode, Vec<PcbItem>)>, KiCadError> {
|
||||||
|
|
@ -1537,6 +1603,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_BOARD_STACKUP_RESPONSE)
|
response_payload_as_any(response, RES_BOARD_STACKUP_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads board stackup from the active PCB document.
|
||||||
pub async fn get_board_stackup(&self) -> Result<BoardStackup, KiCadError> {
|
pub async fn get_board_stackup(&self) -> Result<BoardStackup, KiCadError> {
|
||||||
let payload = self.get_board_stackup_raw().await?;
|
let payload = self.get_board_stackup_raw().await?;
|
||||||
let response: board_commands::BoardStackupResponse =
|
let response: board_commands::BoardStackupResponse =
|
||||||
|
|
@ -1560,6 +1627,7 @@ impl KiCadClient {
|
||||||
response_payload_as_any(response, RES_BOARD_STACKUP_RESPONSE)
|
response_payload_as_any(response, RES_BOARD_STACKUP_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Writes a board stackup and returns KiCad's resulting stackup state.
|
||||||
pub async fn update_board_stackup(
|
pub async fn update_board_stackup(
|
||||||
&self,
|
&self,
|
||||||
stackup: BoardStackup,
|
stackup: BoardStackup,
|
||||||
|
|
@ -1660,6 +1728,7 @@ impl KiCadClient {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads title block metadata from the active PCB document.
|
||||||
pub async fn get_title_block_info(&self) -> Result<TitleBlockInfo, KiCadError> {
|
pub async fn get_title_block_info(&self) -> Result<TitleBlockInfo, KiCadError> {
|
||||||
let command = common_commands::GetTitleBlockInfo {
|
let command = common_commands::GetTitleBlockInfo {
|
||||||
document: Some(self.current_board_document_proto().await?),
|
document: Some(self.current_board_document_proto().await?),
|
||||||
|
|
@ -1760,6 +1829,7 @@ impl KiCadClient {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes the active PCB document to KiCad's string format.
|
||||||
pub async fn get_board_as_string(&self) -> Result<String, KiCadError> {
|
pub async fn get_board_as_string(&self) -> Result<String, KiCadError> {
|
||||||
let command = common_commands::SaveDocumentToString {
|
let command = common_commands::SaveDocumentToString {
|
||||||
document: Some(self.current_board_document_proto().await?),
|
document: Some(self.current_board_document_proto().await?),
|
||||||
|
|
@ -1773,6 +1843,7 @@ impl KiCadClient {
|
||||||
Ok(payload.contents)
|
Ok(payload.contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes current selection to KiCad's string format.
|
||||||
pub async fn get_selection_as_string(&self) -> Result<String, KiCadError> {
|
pub async fn get_selection_as_string(&self) -> Result<String, KiCadError> {
|
||||||
let command = common_commands::SaveSelectionToString {};
|
let command = common_commands::SaveSelectionToString {};
|
||||||
|
|
||||||
|
|
@ -1819,6 +1890,7 @@ impl KiCadClient {
|
||||||
summarize_item_details(items)
|
summarize_item_details(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetches and decodes items by KiCad item id.
|
||||||
pub async fn get_items_by_id(&self, item_ids: Vec<String>) -> Result<Vec<PcbItem>, KiCadError> {
|
pub async fn get_items_by_id(&self, item_ids: Vec<String>) -> Result<Vec<PcbItem>, KiCadError> {
|
||||||
let items = self.get_items_by_id_raw(item_ids).await?;
|
let items = self.get_items_by_id_raw(item_ids).await?;
|
||||||
decode_pcb_items(items)
|
decode_pcb_items(items)
|
||||||
|
|
|
||||||
21
src/error.rs
21
src/error.rs
|
|
@ -3,67 +3,88 @@ use std::time::Duration;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
/// Error type returned by `kicad-ipc-rs` operations.
|
||||||
pub enum KiCadError {
|
pub enum KiCadError {
|
||||||
|
/// Invalid local configuration or user input before IPC dispatch.
|
||||||
#[error("invalid configuration: {reason}")]
|
#[error("invalid configuration: {reason}")]
|
||||||
Config { reason: String },
|
Config { reason: String },
|
||||||
|
|
||||||
|
/// KiCad IPC socket could not be found at connect time.
|
||||||
#[error("KiCad IPC socket not available at `{socket_uri}`. Open KiCad and open a project/board first.")]
|
#[error("KiCad IPC socket not available at `{socket_uri}`. Open KiCad and open a project/board first.")]
|
||||||
SocketUnavailable { socket_uri: String },
|
SocketUnavailable { socket_uri: String },
|
||||||
|
|
||||||
|
/// IPC connection failed.
|
||||||
#[error("connection failed for `{socket_uri}`: {reason}")]
|
#[error("connection failed for `{socket_uri}`: {reason}")]
|
||||||
Connection { socket_uri: String, reason: String },
|
Connection { socket_uri: String, reason: String },
|
||||||
|
|
||||||
|
/// Transport send path failed.
|
||||||
#[error("transport send failed: {reason}")]
|
#[error("transport send failed: {reason}")]
|
||||||
TransportSend { reason: String },
|
TransportSend { reason: String },
|
||||||
|
|
||||||
|
/// Transport receive path failed.
|
||||||
#[error("transport receive failed: {reason}")]
|
#[error("transport receive failed: {reason}")]
|
||||||
TransportReceive { reason: String },
|
TransportReceive { reason: String },
|
||||||
|
|
||||||
|
/// Background transport task has stopped.
|
||||||
#[error("transport task is unavailable")]
|
#[error("transport task is unavailable")]
|
||||||
TransportClosed,
|
TransportClosed,
|
||||||
|
|
||||||
|
/// Request exceeded configured timeout.
|
||||||
#[error("request timed out after {timeout:?}")]
|
#[error("request timed out after {timeout:?}")]
|
||||||
Timeout { timeout: Duration },
|
Timeout { timeout: Duration },
|
||||||
|
|
||||||
|
/// KiCad returned a non-success API status.
|
||||||
#[error("API status error `{code}`: {message}")]
|
#[error("API status error `{code}`: {message}")]
|
||||||
ApiStatus { code: String, message: String },
|
ApiStatus { code: String, message: String },
|
||||||
|
|
||||||
|
/// KiCad returned a non-success per-item status.
|
||||||
#[error("item request status error `{code}`")]
|
#[error("item request status error `{code}`")]
|
||||||
ItemStatus { code: String },
|
ItemStatus { code: String },
|
||||||
|
|
||||||
|
/// Response payload content was malformed or inconsistent.
|
||||||
#[error("invalid API response: {reason}")]
|
#[error("invalid API response: {reason}")]
|
||||||
InvalidResponse { reason: String },
|
InvalidResponse { reason: String },
|
||||||
|
|
||||||
|
/// Response payload was missing when required.
|
||||||
#[error("API response missing payload for `{expected_type_url}`")]
|
#[error("API response missing payload for `{expected_type_url}`")]
|
||||||
MissingPayload { expected_type_url: String },
|
MissingPayload { expected_type_url: String },
|
||||||
|
|
||||||
|
/// Response payload type did not match expected protobuf type URL.
|
||||||
#[error("unexpected payload type; expected `{expected_type_url}`, got `{actual_type_url}`")]
|
#[error("unexpected payload type; expected `{expected_type_url}`, got `{actual_type_url}`")]
|
||||||
UnexpectedPayloadType {
|
UnexpectedPayloadType {
|
||||||
expected_type_url: String,
|
expected_type_url: String,
|
||||||
actual_type_url: String,
|
actual_type_url: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Protobuf encoding failed.
|
||||||
#[error("protobuf encode failed: {0}")]
|
#[error("protobuf encode failed: {0}")]
|
||||||
ProtobufEncode(String),
|
ProtobufEncode(String),
|
||||||
|
|
||||||
|
/// Protobuf decoding failed.
|
||||||
#[error("protobuf decode failed: {0}")]
|
#[error("protobuf decode failed: {0}")]
|
||||||
ProtobufDecode(String),
|
ProtobufDecode(String),
|
||||||
|
|
||||||
|
/// Blocking runtime worker join failed.
|
||||||
#[error("runtime task join failed: {0}")]
|
#[error("runtime task join failed: {0}")]
|
||||||
RuntimeJoin(String),
|
RuntimeJoin(String),
|
||||||
|
|
||||||
|
/// Blocking runtime worker is unavailable.
|
||||||
#[error("blocking runtime is unavailable")]
|
#[error("blocking runtime is unavailable")]
|
||||||
BlockingRuntimeClosed,
|
BlockingRuntimeClosed,
|
||||||
|
|
||||||
|
/// Internal mutex poisoning detected.
|
||||||
#[error("mutex poisoned")]
|
#[error("mutex poisoned")]
|
||||||
InternalPoisoned,
|
InternalPoisoned,
|
||||||
|
|
||||||
|
/// Operation requires an open PCB document.
|
||||||
#[error("no open PCB document found; open a board in KiCad first")]
|
#[error("no open PCB document found; open a board in KiCad first")]
|
||||||
BoardNotOpen,
|
BoardNotOpen,
|
||||||
|
|
||||||
|
/// Multiple project paths were detected where a single path was required.
|
||||||
#[error("multiple project paths found across open PCB docs: {paths:?}")]
|
#[error("multiple project paths found across open PCB docs: {paths:?}")]
|
||||||
AmbiguousProjectPath { paths: Vec<String> },
|
AmbiguousProjectPath { paths: Vec<String> },
|
||||||
|
|
||||||
|
/// Multiple open PCB docs prevent choosing an implicit board context.
|
||||||
#[error("multiple PCB documents are open; unable to choose one board context: {boards:?}")]
|
#[error("multiple PCB documents are open; unable to choose one board context: {boards:?}")]
|
||||||
AmbiguousBoardSelection { boards: Vec<String> },
|
AmbiguousBoardSelection { boards: Vec<String> },
|
||||||
}
|
}
|
||||||
|
|
|
||||||
66
src/lib.rs
66
src/lib.rs
|
|
@ -1,20 +1,82 @@
|
||||||
//! Async-first Rust bindings for the KiCad IPC API.
|
//! # KiCad IPC RS
|
||||||
//!
|
//!
|
||||||
//! Layering:
|
//! **Async-first, pure-Rust IPC bindings for KiCad's official API.**
|
||||||
|
//! Production-focused Rust API surface, typed models, and a blocking wrapper for sync callers.
|
||||||
|
//!
|
||||||
|
//! ## Why this crate?
|
||||||
|
//!
|
||||||
|
//! | Capability | `kicad-ipc-rs` | Official Python bindings (`kicad-python`) | Official Rust bindings (`kicad-rs`) |
|
||||||
|
//! | --- | --- | --- | --- |
|
||||||
|
//! | Rust-native client API | ✅ Yes | ❌ Python package | ⚠️ Development preview |
|
||||||
|
//! | Async-first API design | ✅ `KiCadClient` | ⚠️ App-managed event-loop model | ⚠️ Development preview |
|
||||||
|
//! | Blocking support for sync apps | ✅ `feature = "blocking"` | ✅ Native Python sync usage | ⚠️ Development preview |
|
||||||
|
//! | Wrapped KiCad command coverage (current proto snapshot) | ✅ 56/56 command wrappers | Unknown | Unknown |
|
||||||
|
//! | Maintainer focus | ✅ This crate is actively maintained for Rust users | ✅ Official KiCad Python package | ⚠️ Preview status |
|
||||||
|
//!
|
||||||
|
//! Evidence and references:
|
||||||
|
//! - `kicad-python` package: <https://gitlab.com/kicad/code/kicad-python>
|
||||||
|
//! - `kicad-rs` package (states "development preview with no docs yet"): <https://gitlab.com/kicad/code/kicad-rs>
|
||||||
|
//! - Coverage matrix and runtime notes: <https://github.com/Milind220/kicad-ipc-rs#kicad-v10-rc11-api-completion-matrix>
|
||||||
|
//!
|
||||||
|
//! ## Quickstart (async)
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! use kicad_ipc_rs::KiCadClient;
|
||||||
|
//!
|
||||||
|
//! #[tokio::main(flavor = "current_thread")]
|
||||||
|
//! async fn main() -> Result<(), kicad_ipc_rs::KiCadError> {
|
||||||
|
//! let client = KiCadClient::connect().await?;
|
||||||
|
//! client.ping().await?;
|
||||||
|
//! let version = client.get_version().await?;
|
||||||
|
//! println!("KiCad: {}", version.full_version);
|
||||||
|
//! Ok(())
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Quickstart (blocking)
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! # #[cfg(feature = "blocking")]
|
||||||
|
//! # fn run() -> Result<(), kicad_ipc_rs::KiCadError> {
|
||||||
|
//! use kicad_ipc_rs::KiCadClientBlocking;
|
||||||
|
//! let client = KiCadClientBlocking::connect()?;
|
||||||
|
//! let version = client.get_version()?;
|
||||||
|
//! println!("KiCad: {}", version.full_version);
|
||||||
|
//! # Ok(())
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Architecture layers:
|
||||||
//! - transport
|
//! - transport
|
||||||
//! - envelope
|
//! - envelope
|
||||||
//! - command builders
|
//! - command builders
|
||||||
//! - high-level client
|
//! - high-level client
|
||||||
|
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
/// High-level async client and request/response convenience methods.
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
/// Low-level command payload builders.
|
||||||
|
///
|
||||||
|
/// This module is public for advanced integrations and debugging, but most users
|
||||||
|
/// should prefer [`crate::client::KiCadClient`] methods.
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
|
/// Envelope helpers for command/response packing and unpacking.
|
||||||
|
///
|
||||||
|
/// This is primarily an advanced/internal surface.
|
||||||
pub mod envelope;
|
pub mod envelope;
|
||||||
|
/// Error types returned by this crate.
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod kicad_api_version;
|
mod kicad_api_version;
|
||||||
|
/// Stable data models used by typed client APIs.
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
/// IPC transport implementation details.
|
||||||
|
///
|
||||||
|
/// Most applications should not need to use this module directly.
|
||||||
pub mod transport;
|
pub mod transport;
|
||||||
|
|
||||||
#[cfg(feature = "blocking")]
|
#[cfg(feature = "blocking")]
|
||||||
|
/// Blocking wrapper over the async client.
|
||||||
pub mod blocking;
|
pub mod blocking;
|
||||||
|
|
||||||
pub(crate) mod proto;
|
pub(crate) mod proto;
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,38 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// KiCad net descriptor.
|
||||||
pub struct BoardNet {
|
pub struct BoardNet {
|
||||||
|
/// Numeric net code.
|
||||||
pub code: i32,
|
pub code: i32,
|
||||||
|
/// Net name.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Board layer descriptor.
|
||||||
pub struct BoardLayerInfo {
|
pub struct BoardLayerInfo {
|
||||||
|
/// KiCad layer id.
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
|
/// Human-readable layer name.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Enabled layer set for a board.
|
||||||
pub struct BoardEnabledLayers {
|
pub struct BoardEnabledLayers {
|
||||||
|
/// Number of copper layers configured in the board stack.
|
||||||
pub copper_layer_count: u32,
|
pub copper_layer_count: u32,
|
||||||
|
/// Enabled board layers.
|
||||||
pub layers: Vec<BoardLayerInfo>,
|
pub layers: Vec<BoardLayerInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
/// Board origin kind.
|
||||||
pub enum BoardOriginKind {
|
pub enum BoardOriginKind {
|
||||||
|
/// Grid origin.
|
||||||
Grid,
|
Grid,
|
||||||
|
/// Drill/place origin.
|
||||||
Drill,
|
Drill,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,43 +60,66 @@ impl std::fmt::Display for BoardOriginKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
/// 2D coordinate in nanometer units.
|
||||||
pub struct Vector2Nm {
|
pub struct Vector2Nm {
|
||||||
|
/// X coordinate in nm.
|
||||||
pub x_nm: i64,
|
pub x_nm: i64,
|
||||||
|
/// Y coordinate in nm.
|
||||||
pub y_nm: i64,
|
pub y_nm: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Pad-to-net lookup row derived from footprint items.
|
||||||
pub struct PadNetEntry {
|
pub struct PadNetEntry {
|
||||||
|
/// Footprint reference (e.g. `U1`) when available.
|
||||||
pub footprint_reference: Option<String>,
|
pub footprint_reference: Option<String>,
|
||||||
|
/// Footprint id when available.
|
||||||
pub footprint_id: Option<String>,
|
pub footprint_id: Option<String>,
|
||||||
|
/// Pad item id when available.
|
||||||
pub pad_id: Option<String>,
|
pub pad_id: Option<String>,
|
||||||
|
/// Pad number/text as shown in KiCad.
|
||||||
pub pad_number: String,
|
pub pad_number: String,
|
||||||
|
/// Net code when connected.
|
||||||
pub net_code: Option<i32>,
|
pub net_code: Option<i32>,
|
||||||
|
/// Net name when connected.
|
||||||
pub net_name: Option<String>,
|
pub net_name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
/// Arc geometry in nanometer units.
|
||||||
pub struct ArcStartMidEndNm {
|
pub struct ArcStartMidEndNm {
|
||||||
|
/// Arc start point.
|
||||||
pub start: Vector2Nm,
|
pub start: Vector2Nm,
|
||||||
|
/// Arc midpoint.
|
||||||
pub mid: Vector2Nm,
|
pub mid: Vector2Nm,
|
||||||
|
/// Arc end point.
|
||||||
pub end: Vector2Nm,
|
pub end: Vector2Nm,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
/// Polyline node geometry.
|
||||||
pub enum PolyLineNodeGeometryNm {
|
pub enum PolyLineNodeGeometryNm {
|
||||||
|
/// Straight segment point.
|
||||||
Point(Vector2Nm),
|
Point(Vector2Nm),
|
||||||
|
/// Arc segment node.
|
||||||
Arc(ArcStartMidEndNm),
|
Arc(ArcStartMidEndNm),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Polyline geometry.
|
||||||
pub struct PolyLineNm {
|
pub struct PolyLineNm {
|
||||||
|
/// Ordered geometry nodes.
|
||||||
pub nodes: Vec<PolyLineNodeGeometryNm>,
|
pub nodes: Vec<PolyLineNodeGeometryNm>,
|
||||||
|
/// Whether last node closes back to first.
|
||||||
pub closed: bool,
|
pub closed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Polygon with optional interior holes.
|
||||||
pub struct PolygonWithHolesNm {
|
pub struct PolygonWithHolesNm {
|
||||||
|
/// Outer outline polygon.
|
||||||
pub outline: Option<PolyLineNm>,
|
pub outline: Option<PolyLineNm>,
|
||||||
|
/// Interior holes.
|
||||||
pub holes: Vec<PolyLineNm>,
|
pub holes: Vec<PolyLineNm>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,34 @@ use crate::model::board::{ColorRgba, PolygonWithHolesNm, Vector2Nm};
|
||||||
use crate::proto::kiapi::common::types as common_types;
|
use crate::proto::kiapi::common::types as common_types;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// KiCad semantic version returned by `GetVersion`.
|
||||||
pub struct VersionInfo {
|
pub struct VersionInfo {
|
||||||
|
/// Major version component.
|
||||||
pub major: u32,
|
pub major: u32,
|
||||||
|
/// Minor version component.
|
||||||
pub minor: u32,
|
pub minor: u32,
|
||||||
|
/// Patch version component.
|
||||||
pub patch: u32,
|
pub patch: u32,
|
||||||
|
/// Full KiCad version string (includes prerelease/build details).
|
||||||
pub full_version: String,
|
pub full_version: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
/// KiCad top-level frame/editor targets used by API commands.
|
||||||
pub enum EditorFrameType {
|
pub enum EditorFrameType {
|
||||||
|
/// KiCad project manager frame.
|
||||||
ProjectManager,
|
ProjectManager,
|
||||||
|
/// Schematic editor frame.
|
||||||
SchematicEditor,
|
SchematicEditor,
|
||||||
|
/// PCB editor frame.
|
||||||
PcbEditor,
|
PcbEditor,
|
||||||
|
/// Spice simulator frame.
|
||||||
SpiceSimulator,
|
SpiceSimulator,
|
||||||
|
/// Symbol editor frame.
|
||||||
SymbolEditor,
|
SymbolEditor,
|
||||||
|
/// Footprint editor frame.
|
||||||
FootprintEditor,
|
FootprintEditor,
|
||||||
|
/// Drawing-sheet editor frame.
|
||||||
DrawingSheetEditor,
|
DrawingSheetEditor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,12 +85,19 @@ impl FromStr for EditorFrameType {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
/// KiCad document type selector used by document-scoped APIs.
|
||||||
pub enum DocumentType {
|
pub enum DocumentType {
|
||||||
|
/// Schematic document.
|
||||||
Schematic,
|
Schematic,
|
||||||
|
/// Symbol document.
|
||||||
Symbol,
|
Symbol,
|
||||||
|
/// PCB document.
|
||||||
Pcb,
|
Pcb,
|
||||||
|
/// Footprint document.
|
||||||
Footprint,
|
Footprint,
|
||||||
|
/// Drawing-sheet document.
|
||||||
DrawingSheet,
|
DrawingSheet,
|
||||||
|
/// Project-level document.
|
||||||
Project,
|
Project,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,59 +161,89 @@ impl FromStr for DocumentType {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Minimal project information attached to open-document responses.
|
||||||
pub struct ProjectInfo {
|
pub struct ProjectInfo {
|
||||||
|
/// Project display name, if provided by KiCad.
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
/// Project filesystem path, if available.
|
||||||
pub path: Option<PathBuf>,
|
pub path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Descriptor for an open KiCad document.
|
||||||
pub struct DocumentSpecifier {
|
pub struct DocumentSpecifier {
|
||||||
|
/// KiCad document type.
|
||||||
pub document_type: DocumentType,
|
pub document_type: DocumentType,
|
||||||
|
/// Board filename when relevant.
|
||||||
pub board_filename: Option<String>,
|
pub board_filename: Option<String>,
|
||||||
|
/// Owning project metadata.
|
||||||
pub project: ProjectInfo,
|
pub project: ProjectInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Count of selected items for a specific protobuf type URL.
|
||||||
pub struct SelectionTypeCount {
|
pub struct SelectionTypeCount {
|
||||||
|
/// Protobuf type URL for the selected item type.
|
||||||
pub type_url: String,
|
pub type_url: String,
|
||||||
|
/// Number of selected items of this type.
|
||||||
pub count: usize,
|
pub count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Summary of current selection composition.
|
||||||
pub struct SelectionSummary {
|
pub struct SelectionSummary {
|
||||||
|
/// Total selected item count.
|
||||||
pub total_items: usize,
|
pub total_items: usize,
|
||||||
|
/// Per-type counts by protobuf type URL.
|
||||||
pub type_url_counts: Vec<SelectionTypeCount>,
|
pub type_url_counts: Vec<SelectionTypeCount>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Human/debug-friendly selection entry detail.
|
||||||
pub struct SelectionItemDetail {
|
pub struct SelectionItemDetail {
|
||||||
|
/// Protobuf type URL.
|
||||||
pub type_url: String,
|
pub type_url: String,
|
||||||
|
/// Decoded/debug string detail.
|
||||||
pub detail: String,
|
pub detail: String,
|
||||||
|
/// Raw payload length in bytes.
|
||||||
pub raw_len: usize,
|
pub raw_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Opaque commit session identifier returned by `begin_commit`.
|
||||||
pub struct CommitSession {
|
pub struct CommitSession {
|
||||||
|
/// KiCad commit session id.
|
||||||
pub id: String,
|
pub id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
/// Final action to apply when ending a commit session.
|
||||||
pub enum CommitAction {
|
pub enum CommitAction {
|
||||||
|
/// Persist commit changes.
|
||||||
Commit,
|
Commit,
|
||||||
|
/// Discard commit changes.
|
||||||
Drop,
|
Drop,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
/// Status result returned by `run_action`.
|
||||||
pub enum RunActionStatus {
|
pub enum RunActionStatus {
|
||||||
|
/// Action succeeded.
|
||||||
Ok,
|
Ok,
|
||||||
|
/// Action name or payload was invalid.
|
||||||
Invalid,
|
Invalid,
|
||||||
|
/// Target editor frame was not open.
|
||||||
FrameNotOpen,
|
FrameNotOpen,
|
||||||
|
/// Unrecognized status code from KiCad.
|
||||||
Unknown(i32),
|
Unknown(i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
/// Merge strategy for map-like update APIs.
|
||||||
pub enum MapMergeMode {
|
pub enum MapMergeMode {
|
||||||
|
/// Merge provided entries into existing map.
|
||||||
Merge,
|
Merge,
|
||||||
|
/// Replace existing map with provided entries.
|
||||||
Replace,
|
Replace,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -244,11 +294,17 @@ impl FromStr for CommitAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
/// Title block fields from the active document.
|
||||||
pub struct TitleBlockInfo {
|
pub struct TitleBlockInfo {
|
||||||
|
/// Title block title.
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
/// Title block date.
|
||||||
pub date: String,
|
pub date: String,
|
||||||
|
/// Revision string.
|
||||||
pub revision: String,
|
pub revision: String,
|
||||||
|
/// Company field.
|
||||||
pub company: String,
|
pub company: String,
|
||||||
|
/// Non-empty comment fields.
|
||||||
pub comments: Vec<String>,
|
pub comments: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue