Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions score/mw/com/impl/rust/com-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<!--
Copyright (c) 2026 Contributors to the Eclipse Foundation

See the NOTICE file(s) distributed with this work for additional
information regarding copyright ownership.

This program and the accompanying materials are made available under the
terms of the Apache License Version 2.0 which is available at
https://www.apache.org/licenses/LICENSE-2.0

SPDX-License-Identifier: Apache-2.0
-->
# Rust COM API

## Overview

The **COM API** is a Rust API for service-oriented inter-process communication (IPC) in the `mw::com` ecosystem.
It provides a clean, type-safe way for Rust applications to **offer** and **consume** services using a publish/subscribe event model.

Application code is written against a runtime-agnostic set of concepts (traits and types). At build or deployment time you select a concrete runtime implementation (for example a production runtime, or a mock runtime for tests) without rewriting business logic.

For internal architecture and implementation details, see [com_api_high_level_design_detail.md](../doc/com_api_high_level_design_detail.md)

### What This API Is For

- **Build service providers and consumers in Rust** using a common service-oriented model.
- **Keep business logic stable** while the underlying runtime implementation can differ (production vs. test).
- **Make IPC explicit**: offering, publishing, discovering, subscribing, and reading samples are all deliberate operations.

### Conceptual Architecture

At a high level, applications interact with the COM API concepts (Runtime, Producer/Consumer, Publisher/Subscriber). A concrete runtime implementation connects those concepts to the underlying communication technology using an FFI (Foreign Function Interface) layer that bridges the underlying C++ COM API to Rust.

![COM API Architecture Layers](../doc/com_api_architecture_layers.svg)

If you’re interested in the detailed layering, module boundaries, and trait hierarchy, see [com_api_high_level_design_detail.md](../doc/com_api_high_level_design_detail.md).

## How It Works

### Service-Oriented Communication Model

The Rust COM API wraps the underlying C++ COM API and exposes a **publish/subscribe** model through type-safe Rust traits and abstractions.
A service is a logical entity with a well-known interface (a set of events and data types) and a location (an `InstanceSpecifier` path like `/vehicle/speed`).

Communication always flows in one direction for a given event: a **Producer** writes data, and one or more **Consumers** receive it.
Rust's traits provide compile-time guarantees and type safety, ensuring both sides only need to agree on the interface definition without knowing about each other at compile time.

### Core Concepts

| Concept | What it means in practice |
|---------|--------------------------|
| **Runtime** | The entry point for creating producers and discovering services. |
| **Producer** | The provider side: offers a service instance and publishes events. |
| **Consumer** | The user side: discovers a service instance and subscribes to its events. |
| **Service discovery** | Finds currently available service instances (availability can change over time). |
| **Publisher / Subscriber** | Typed endpoints for sending (`Publisher<T>`) and receiving (`Subscriber<T>`) event data. |
| **Subscription** | A `Subscription<T>` represents an event stream. |
| **Sample** | `Sample<T>` values are immutable snapshots you read from it. |
| **SampleContainer** | Container for reading samples from the event stream. |
| **InstanceSpecifier** | Path-like service address (e.g. `/vehicle/speed`). |

## Getting Started

```
Producer side Consumer side
───────────────────── ─────────────────────
Create runtime Create runtime
Create producer for an instance Find available instances
Offer service instance Create consumer for an instance
Publish events Subscribe and receive samples
```

### Example Application

See [basic-consumer-producer.rs](../../../example/com-api-example/basic-consumer-producer.rs) for a complete working example demonstrating the producer/consumer workflow.

## Further Reading

- [com_api_high_level_design_detail.md](../doc/com_api_high_level_design_detail.md) — internal architecture, layer details, trait reference, and module structure
- [user_facing_api_examples.md](../doc/user_facing_api_examples.md) — user-facing API examples and usage patterns
- **com_api_concept** crate — detailed trait definitions and API documentation (Runtime, Producer, Consumer, etc.)
- **com_api** crate — public re-exports for user-side consumption
109 changes: 109 additions & 0 deletions score/mw/com/impl/rust/com-api/com-api/com_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,115 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

//! The **COM API** is a Rust API for service-oriented inter-process communication (IPC) in the `mw::com` ecosystem.
//!
//! Build service **providers** and **consumers** using a publish/subscribe model.
//! Application business logic is written against the runtime-agnostic traits re-exported here, the concrete
//! runtime (e.g. [`LolaRuntimeBuilderImpl`] for production, [`MockRuntimeBuilderImpl`] for tests)
//! is selected at initialisation time without changing application code.
//!
//! # Design Principles
//! The COM API follows these core design principles:
//! - **Builder Pattern**: All complex objects use the builder pattern for type-safe construction
//! - **Zero-Copy Communication**: Supports efficient data transmission using pre-allocated, position-independent memory
//! - **No Heap Allocation During Runtime**: Heap memory is allowed only during initialization phase, runtime operations use pre-allocated chunks
//! - **Type Safety**: Derives type information from interface descriptions to prevent misuse
//! - **Runtime Agnostic**: The API does not enforce the necessity for internal threads or executors
//!
//! # Core concepts
//!
//! | Type | Role |
//! |------|------|
//! | [`RuntimeBuilder`] / [`Runtime`] | Entry point; creates producers and drives service discovery. |
//! | [`Producer`] / [`OfferedProducer`] | Provider side: offers a service instance and holds [`Publisher`]s. |
//! | [`Consumer`] | User side: connects to a discovered instance and holds [`Subscriber`]s. |
//! | [`ServiceDiscovery`] | Finds available service instances; availability can change over time. |
//! | [`Publisher<T>`] / [`Subscriber<T>`] | Typed send / receive endpoints for one event. |
//! | [`Subscription<T>`] | Represents an active event stream. |
//! | [`Sample<T>`] | `Sample<T>` values are immutable snapshots you read from it. |
//! | [`SampleContainer`] | Container for reading samples from the event stream. |
//! | [`InstanceSpecifier`] | Path-like service address (e.g. `/vehicle/speed`). |
//!
//! # Important constraints
//! - **Fixed capacity**: after initialization, subscription queues and sample containers are fixed-size.
//! During initialization, capacity is fully dynamic.
//! - **Explicit lifetimes**: dropping an [`OfferedProducer`] withdraws the service, samples must
//! not outlive their source.
//! - **Sample lifetimes**: samples are valid only until the subscription instance is valid.
//! - **LoLa note**: [`FindServiceSpecifier::Any`] is not yet supported — use `Specific` only.
//!
//! # Quick Start
//!
//! ## Producer (Service Provider)
//! ```ignore
//! use com_api::*;
//! use std::path::Path;
//!
//! // 1. Initialize runtime with configuration
//! let mut builder = LolaRuntimeBuilderImpl::new();
//! builder.load_config(Path::new("etc/mw_com_config.json"));
//! let runtime = builder.build()?;
//!
//! // 2. Create producer with builder pattern
//! let spec = InstanceSpecifier::new("/vehicle/speed")?;
//! let producer = runtime.producer_builder::<VehicleInterface>(spec).build()?;
//!
//! // 3. Offer service to make it discoverable
//! let offered = producer.offer()?;
//!
//! // 4. Publish events using typed publisher and zero-copy samples
//! let sample = offered.left_tire.allocate()?;
//! let sample = sample.write(Tire { pressure: 33.0 });
//! sample.send()?;
//!
//! // 5. Withdraw service when done
//! let _producer = offered.unoffer()?;
//! ```
//!
//! ## Consumer (Service Client)
//! ```ignore
//! use com_api::*;
//! use std::path::Path;
//!
//! // 1. Initialize runtime
//! let mut builder = LolaRuntimeBuilderImpl::new();
//! builder.load_config(Path::new("etc/mw_com_config.json"));
//! let runtime = builder.build()?;
//!
//! // 2. Discover service instance
//! let spec = InstanceSpecifier::new("/vehicle/speed")?;
//! let discovery = runtime.find_service::<VehicleInterface>(
//! FindServiceSpecifier::Specific(spec)
//! );
//! let instances = discovery.get_available_instances()?;
//!
//! // 3. Create consumer from discovered instance
//! let consumer = instances.into_iter()
//! .next()
//! .ok_or(Error::Fail)?
//! .build()?;
//!
//! // 4. Subscribe to events with fixed-capacity buffer
//! let subscription = consumer.left_tire.subscribe(3)?;
//! let mut container = SampleContainer::new(3);
//!
//! // 5. Poll for events (non-blocking)
//! match subscription.try_receive(&mut container, 3) {
//! Ok(n) if n > 0 => {
//! while let Some(sample) = container.pop_front() {
//! println!("Tire pressure: {}", sample.pressure);
//! }
//! }
//! _ => { /* No samples available */ }
//! }
//!
//! // 6. Or wait asynchronously for events
//! let n = subscription.receive(&mut container, 1, 3).await?;
//! ```
//! # Further reading
//! - `com_api_concept` crate — trait definitions and full API documentation
//! - `doc/com_api_high_level_design_detail.md` — internal architecture and layer details

pub use com_api_runtime_lola::LolaRuntimeImpl;
pub use com_api_runtime_lola::RuntimeBuilderImpl as LolaRuntimeBuilderImpl;
pub use com_api_runtime_mock::MockRuntimeImpl;
Expand Down
Loading
Loading