From 924b6732159e7461fb81b009a4fdb4ad8b813462 Mon Sep 17 00:00:00 2001 From: bharatgoswami Date: Fri, 14 Nov 2025 14:43:13 +0530 Subject: [PATCH 1/5] Rust::com Runtime independent design for Rust APIs * Primary APIs moved to Runtime traits * Add generic compatibilty for Vehicle Consumer and Producer * Added Provider and Consumer InstanceInfo --- README.md | 17 ++- com-api/com-api-concept/src/lib.rs | 138 +++++++++++++++--- com-api/com-api-runtime-lola/src/lib.rs | 115 ++++++++++++--- com-api/com-api-runtime-mock/src/lib.rs | 114 ++++++++++++--- com-api/com-api/src/lib.rs | 2 +- com-api/examples/basic-consumer-producer.rs | 122 ++++++---------- .../com-api-gen/com-api-gen-lola/src/lib.rs | 73 +++++---- .../com-api-gen/com-api-gen-mock/src/lib.rs | 71 ++++----- com-api/examples/com-api-gen/src/lib.rs | 4 +- 9 files changed, 430 insertions(+), 226 deletions(-) diff --git a/README.md b/README.md index 9454f5b..21b6b2b 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,25 @@ Examples can be built from examples directory by passing desired IPC adapter as For mock build: ``` -inc_mw_com/com-api$ cargo run --example basic-consumer-producer --features "mock" +inc_mw_com$ cargo build --example basic-consumer-producer --features "mock" ``` For LoLa build: ``` +inc_mw_com/com-api$ cargo build --example basic-consumer-producer --features "lola" +``` + +For mock test: +``` +inc_mw_com$ cargo test --test basic-consumer-producer-test --features "mock" +``` + +For mock Build and Run: +``` +inc_mw_com/com-api$ cargo run --example basic-consumer-producer --features "mock" +``` + +For LoLa Build and Run: +``` inc_mw_com/com-api$ cargo run --example basic-consumer-producer --features "lola" ``` diff --git a/com-api/com-api-concept/src/lib.rs b/com-api/com-api-concept/src/lib.rs index 2f39c8d..7b73e08 100644 --- a/com-api/com-api-concept/src/lib.rs +++ b/com-api/com-api-concept/src/lib.rs @@ -12,7 +12,7 @@ //! This crate defines the concepts and traits of the COM API. It does not provide any concrete //! implementations. It is meant to be used as a common interface for different implementations //! of the COM API, e.g., for different IPC backends. -//! +//! //! # API Design principles //! //! - We stick to the builder pattern down to a single service (TODO: Should this be introduced to the C++ API?) @@ -46,6 +46,7 @@ use std::collections::VecDeque; use std::fmt::Debug; +use std::future::Future; use std::ops::{Deref, DerefMut}; use std::path::Path; @@ -68,8 +69,27 @@ pub trait Builder { /// This represents the com implementation and acts as a root for all types and objects provided by /// the implementation. +// +// Associated types: +// * ProviderInfo - Information about a producer instance required to pass to different traits/types/methods +// * ConsumerInfo - Information about a consumer instance required to pass to different traits/types/methods pub trait Runtime { - type Sample<'a, T: Reloc + Send + std::fmt::Debug + 'a>: Sample; + type ServiceDiscovery: ServiceDiscovery; + type Subscriber: Subscriber; + type ProducerBuilder>: ProducerBuilder; + type Publisher: Publisher; + type ProviderInfo: Send + Clone; + type ConsumerInfo: Send + Clone; + + fn find_service( + &self, + _instance_specifier: InstanceSpecifier, + ) -> Self::ServiceDiscovery; + + fn producer_builder>( + &self, + instance_specifier: InstanceSpecifier, + ) -> Self::ProducerBuilder; } pub trait RuntimeBuilder: Builder @@ -79,8 +99,58 @@ where fn load_config(&mut self, config: &Path) -> &mut Self; } +/// Technology independent description of a service instance "location" +/// +/// The string shall describe where to find a certain instance of a service. Each level shall look +/// like this +/// :my/path/to/service_name +#[derive(Clone)] pub struct InstanceSpecifier { - pub specifier: String, + specifier: Option, +} + +impl InstanceSpecifier { + /// Instance specifier that will match any instance. This can be used to find all + /// instances of a certain interface during service discovery. + pub const MATCH_ANY: Self = InstanceSpecifier { specifier: None }; + + fn check_str(_service_name: &str) -> bool { + // For now, accept any non-empty string as a valid service name + // In a real implementation, this might validate the format + true + } + + /// Create a new instance specifier, using the string-like input as the path to the + /// instance. + /// + /// The returned instance specifier will only match if the instance exactly matches the given + /// string. + pub fn new(service_name: impl AsRef) -> Result { + let service_name = service_name.as_ref(); + if Self::check_str(service_name) { + Ok(Self { + specifier: Some(service_name.to_string()), + }) + } else { + Err(Error::Fail) + } + } +} + +impl TryFrom<&str> for InstanceSpecifier { + type Error = Error; + fn try_from(s: &str) -> Result { + Self::new(s) + } +} + +impl AsRef for InstanceSpecifier { + fn as_ref(&self) -> &str { + self.specifier + .as_ref() + .map(String::as_str) + .unwrap_or("[ANY]") + } } /// This trait shall ensure that we can safely use an instance of the implementing type across @@ -160,32 +230,61 @@ where /// /// This corresponds to `MaybeUninit::write`. fn write(self, value: T) -> Self::SampleMut; + + /// Get a mutable pointer to the internal maybe uninitialized `T`. + /// + /// The caller has to make sure to initialize the data in the buffer. + /// Reading from the received pointer before initialization is undefined behavior. + fn as_mut_ptr(&mut self) -> *mut T; } -pub trait Interface {} +pub trait Interface { + type Consumer: Consumer; + type Producer: Producer; +} -pub trait OfferedProducer { +#[must_use = "if a service is offered it will be unoffered and dropped immediately, causing unexpected behavior in the system"] +pub trait OfferedProducer { type Interface: Interface; - type Producer: Producer; + type Producer: Producer; fn unoffer(self) -> Self::Producer; } -pub trait Producer { +pub trait Producer { type Interface: Interface; - type OfferedProducer: OfferedProducer; + type OfferedProducer: OfferedProducer; fn offer(self) -> Result; } -pub trait Consumer {} +pub trait Publisher +where + T: Reloc + Send, +{ + type SampleMaybeUninit<'a>: SampleMaybeUninit + 'a + where + Self: 'a; + + fn allocate<'a>(&'a self) -> Result>; + + fn send(&self, value: T) -> Result<()> { + let sample = self.allocate()?; + let init_sample = sample.write(value); + init_sample.send() + } +} + +pub trait Consumer { + fn new(instance_info: R::ConsumerInfo) -> Self; +} -pub trait ProducerBuilder>: +pub trait ProducerBuilder, R: Runtime + ?Sized>: Builder

{ } -pub trait ServiceDiscovery { +pub trait ServiceDiscovery { type ConsumerBuilder: ConsumerBuilder; type ServiceEnumerator: IntoIterator; @@ -193,15 +292,18 @@ pub trait ServiceDiscovery { // TODO: Provide an async stream for newly available services / ServiceDescriptors } -pub trait ConsumerDescriptor { +pub trait ConsumerDescriptor { fn get_instance_id(&self) -> usize; // TODO: Turn return type into separate type } -pub trait ConsumerBuilder: ConsumerDescriptor {} - -pub trait Subscriber { - type Subscription: Subscription; +pub trait ConsumerBuilder: + ConsumerDescriptor + Builder> +{ +} +pub trait Subscriber { + type Subscription: Subscription; + fn new(identifier: &str, instance_info: R::ConsumerInfo) -> Self; fn subscribe(self, max_num_samples: usize) -> Result; } @@ -251,8 +353,8 @@ impl SampleContainer { } } -pub trait Subscription { - type Subscriber: Subscriber; +pub trait Subscription { + type Subscriber: Subscriber; type Sample<'a>: Sample where Self: 'a; diff --git a/com-api/com-api-runtime-lola/src/lib.rs b/com-api/com-api-runtime-lola/src/lib.rs index 4a21ba5..b4680f5 100644 --- a/com-api/com-api-runtime-lola/src/lib.rs +++ b/com-api/com-api-runtime-lola/src/lib.rs @@ -16,6 +16,7 @@ use std::cmp::Ordering; use std::collections::VecDeque; +use std::future::Future; use std::marker::PhantomData; use std::mem::MaybeUninit; use std::ops::{Deref, DerefMut}; @@ -23,32 +24,46 @@ use std::path::Path; use std::sync::atomic::AtomicUsize; use com_api_concept::{ - Builder, ConsumerBuilder, ConsumerDescriptor, InstanceSpecifier, Interface, Reloc, Runtime, - SampleContainer, ServiceDiscovery, Subscriber, Subscription, + Builder, Consumer,ConsumerBuilder, ConsumerDescriptor, InstanceSpecifier, Interface, Reloc, Runtime, + SampleContainer, ServiceDiscovery, Subscriber, Subscription, Producer, ProducerBuilder, Result, }; pub struct LolaRuntimeImpl {} -impl Runtime for LolaRuntimeImpl { - type Sample<'a, T: Reloc + Send + 'a + std::fmt::Debug> = Sample<'a, T>; +// Note: LolaProviderInfo is currently unused but will be utilized +// with the Producer::offer() method in future implementations. +#[derive(Clone)] +pub struct LolaProviderInfo { + instance_specifier: InstanceSpecifier, +} + +#[derive(Clone)] +pub struct LolaConsumerInfo { + instance_specifier: InstanceSpecifier, } -impl LolaRuntimeImpl { - // TODO: Any chance that these can be moved to a trait so that this becomes more testable? - // If yes, this trait is certainly located here since - pub fn find_service( +impl Runtime for LolaRuntimeImpl { + type ServiceDiscovery = SampleConsumerDiscovery; + type Subscriber = SubscribableImpl; + type ProducerBuilder> = SampleProducerBuilder; + type Publisher = Publisher; + // TODO: Integrate with Producer::offer() method implementation + type ProviderInfo = LolaProviderInfo; + type ConsumerInfo = LolaConsumerInfo; + + fn find_service( &self, _instance_specifier: InstanceSpecifier, - ) -> SampleConsumerDiscovery { + ) -> Self::ServiceDiscovery { SampleConsumerDiscovery { _interface: PhantomData, } } - pub fn producer_builder( + fn producer_builder>( &self, instance_specifier: InstanceSpecifier, - ) -> SampleProducerBuilder { + ) -> Self::ProducerBuilder { SampleProducerBuilder::new(self, instance_specifier) } } @@ -147,7 +162,7 @@ where T: Reloc, { data: T, - _lifetime: PhantomData<&'a T>, + lifetime: PhantomData<&'a T>, } impl<'a, T> com_api_concept::SampleMut for SampleMut<'a, T> @@ -190,7 +205,7 @@ where T: Reloc + Send, { data: MaybeUninit, - _lifetime: PhantomData<&'a T>, + lifetime: PhantomData<&'a T>, } impl<'a, T> com_api_concept::SampleMaybeUninit for SampleMaybeUninit<'a, T> @@ -202,31 +217,48 @@ where fn write(self, val: T) -> SampleMut<'a, T> { SampleMut { data: val, - _lifetime: PhantomData, + lifetime: PhantomData, } } - unsafe fn assume_init(self) -> SampleMut<'a, T> { + fn as_mut_ptr(&mut self) -> *mut T { + self.data.as_mut_ptr() + } + + unsafe fn assume_init(self) -> SampleMut<'a, T> { SampleMut { data: unsafe { self.data.assume_init() }, - _lifetime: PhantomData, + lifetime: PhantomData, } } + } pub struct SubscribableImpl { - _data: PhantomData, + identifier: String, + instance_info: Option, + data: PhantomData, } impl Default for SubscribableImpl { fn default() -> Self { - Self { _data: PhantomData } + Self { + identifier: String::new(), + instance_info: None, + data: PhantomData, + } } } -impl Subscriber for SubscribableImpl { +impl Subscriber for SubscribableImpl { type Subscription = SubscriberImpl; - + fn new(identifier: &str, instance_info: LolaConsumerInfo) -> Self { + Self { + identifier: identifier.to_string(), + instance_info: Some(instance_info), + data: PhantomData, + } + } fn subscribe(self, _max_num_samples: usize) -> com_api_concept::Result { Ok(SubscriberImpl::new()) } @@ -255,7 +287,7 @@ where } } -impl Subscription for SubscriberImpl +impl Subscription for SubscriberImpl where T: Reloc + Send, { @@ -308,11 +340,18 @@ where pub fn new() -> Self { Self { _data: PhantomData } } +} - pub fn allocate<'a>(&'a self) -> com_api_concept::Result> { +impl com_api_concept::Publisher for Publisher +where + T: Reloc + Send, +{ + type SampleMaybeUninit<'a> = SampleMaybeUninit<'a, T> where Self: 'a; + + fn allocate<'a>(&'a self) -> com_api_concept::Result> { Ok(SampleMaybeUninit { data: MaybeUninit::uninit(), - _lifetime: PhantomData, + lifetime: PhantomData, }) } } @@ -341,6 +380,17 @@ where } } +impl ConsumerBuilder for SampleConsumerBuilder {} + +impl Builder> for SampleConsumerBuilder { + fn build(self) -> com_api_concept::Result> { + let instance_info = LolaConsumerInfo { + instance_specifier: self.instance_specifier.clone(), + }; + Ok(Consumer::new(instance_info)) + } +} + pub struct SampleProducerBuilder { instance_specifier: InstanceSpecifier, _interface: PhantomData, @@ -355,6 +405,15 @@ impl SampleProducerBuilder { } } +impl> ProducerBuilder for SampleProducerBuilder {} + +impl> Builder

for SampleProducerBuilder { + fn build(self) -> Result

{ + todo!() + } +} + + pub struct SampleConsumerDescriptor { _interface: PhantomData, } @@ -408,7 +467,7 @@ impl RuntimeBuilderImpl { #[cfg(test)] mod test { - use com_api_concept::{SampleContainer, Subscription}; + use com_api_concept::{Publisher, SampleContainer, SampleMaybeUninit, SampleMut, Subscription}; #[test] fn receive_stuff() { @@ -449,4 +508,12 @@ mod test { } }) } + + #[test] + fn send_stuff() { + let test_publisher = super::Publisher::::new(); + let sample = test_publisher.allocate().expect("Couldn't allocate sample"); + let sample = sample.write(42); + sample.send().expect("Send failed for sample"); + } } diff --git a/com-api/com-api-runtime-mock/src/lib.rs b/com-api/com-api-runtime-mock/src/lib.rs index ce2d49d..9ed974e 100644 --- a/com-api/com-api-runtime-mock/src/lib.rs +++ b/com-api/com-api-runtime-mock/src/lib.rs @@ -18,6 +18,7 @@ use std::cmp::Ordering; use std::collections::VecDeque; +use std::future::Future; use std::marker::PhantomData; use std::mem::MaybeUninit; use std::ops::{Deref, DerefMut}; @@ -25,32 +26,46 @@ use std::path::Path; use std::sync::atomic::AtomicUsize; use com_api_concept::{ - Builder, ConsumerBuilder, ConsumerDescriptor, InstanceSpecifier, Interface, Reloc, Runtime, - SampleContainer, ServiceDiscovery, Subscriber, Subscription, + Builder, Consumer, ConsumerBuilder, ConsumerDescriptor, InstanceSpecifier, Interface, Reloc, Runtime, + SampleContainer, ServiceDiscovery, Subscriber, Subscription, Producer, ProducerBuilder, Result, }; pub struct MockRuntimeImpl {} -impl Runtime for MockRuntimeImpl { - type Sample<'a, T: Reloc + Send + 'a + std::fmt::Debug> = Sample<'a, T>; +// Note: ProviderInfo is currently unused but will be utilized +// with the Producer::offer() method in future implementations. +#[derive(Clone)] +pub struct MockProviderInfo { + instance_specifier: InstanceSpecifier, +} + +#[derive(Clone)] +pub struct MockConsumerInfo { + instance_specifier: InstanceSpecifier, } -impl MockRuntimeImpl { - // TODO: Any chance that these can be moved to a trait so that this becomes more testable? - // If yes, this trait is certainly located here since - pub fn find_service( +impl Runtime for MockRuntimeImpl { + type ServiceDiscovery = SampleConsumerDiscovery; + type Subscriber = SubscribableImpl; + type ProducerBuilder> = SampleProducerBuilder; + type Publisher = Publisher; + // TODO: Integrate with Producer::offer() method implementation + type ProviderInfo = MockProviderInfo; + type ConsumerInfo = MockConsumerInfo; + + fn find_service( &self, _instance_specifier: InstanceSpecifier, - ) -> SampleConsumerDiscovery { + ) -> Self::ServiceDiscovery { SampleConsumerDiscovery { _interface: PhantomData, } } - pub fn producer_builder( + fn producer_builder>( &self, instance_specifier: InstanceSpecifier, - ) -> SampleProducerBuilder { + ) -> Self::ProducerBuilder { SampleProducerBuilder::new(self, instance_specifier) } } @@ -149,7 +164,7 @@ where T: Reloc, { data: T, - _lifetime: PhantomData<&'a T>, + lifetime: PhantomData<&'a T>, } impl<'a, T> com_api_concept::SampleMut for SampleMut<'a, T> @@ -192,7 +207,7 @@ where T: Reloc + Send, { data: MaybeUninit, - _lifetime: PhantomData<&'a T>, + lifetime: PhantomData<&'a T>, } impl<'a, T> com_api_concept::SampleMaybeUninit for SampleMaybeUninit<'a, T> @@ -204,31 +219,47 @@ where fn write(self, val: T) -> SampleMut<'a, T> { SampleMut { data: val, - _lifetime: PhantomData, + lifetime: PhantomData, } } - unsafe fn assume_init(self) -> SampleMut<'a, T> { + fn as_mut_ptr(&mut self) -> *mut T { + self.data.as_mut_ptr() + } + + unsafe fn assume_init(self) -> SampleMut<'a, T> { SampleMut { data: unsafe { self.data.assume_init() }, - _lifetime: PhantomData, + lifetime: PhantomData, } } } pub struct SubscribableImpl { - _data: PhantomData, + identifier: String, + instance_info: Option, + data: PhantomData, } impl Default for SubscribableImpl { fn default() -> Self { - Self { _data: PhantomData } + Self { + identifier: String::new(), + instance_info: None, + data: PhantomData, + } } } -impl Subscriber for SubscribableImpl { +impl Subscriber for SubscribableImpl { type Subscription = SubscriberImpl; - + fn new(identifier: &str, instance_info: MockConsumerInfo) -> Self { + Self { + identifier: identifier.to_string(), + instance_info: Some(instance_info), + data: PhantomData, + } + } fn subscribe(self, _max_num_samples: usize) -> com_api_concept::Result { Ok(SubscriberImpl::new()) } @@ -257,7 +288,7 @@ where } } -impl Subscription for SubscriberImpl +impl Subscription for SubscriberImpl where T: Reloc + Send, { @@ -310,11 +341,18 @@ where pub fn new() -> Self { Self { _data: PhantomData } } +} - pub fn allocate<'a>(&'a self) -> com_api_concept::Result> { +impl com_api_concept::Publisher for Publisher +where + T: Reloc + Send, +{ + type SampleMaybeUninit<'a> = SampleMaybeUninit<'a, T> where Self: 'a; + + fn allocate<'a>(&'a self) -> com_api_concept::Result> { Ok(SampleMaybeUninit { data: MaybeUninit::uninit(), - _lifetime: PhantomData, + lifetime: PhantomData, }) } } @@ -357,6 +395,14 @@ impl SampleProducerBuilder { } } +impl> ProducerBuilder for SampleProducerBuilder {} + +impl> Builder

for SampleProducerBuilder { + fn build(self) -> Result

{ + todo!() + } +} + pub struct SampleConsumerDescriptor { _interface: PhantomData, } @@ -380,6 +426,18 @@ impl ConsumerDescriptor for SampleConsumerBuilder } } +impl ConsumerBuilder for SampleConsumerBuilder {} + +impl Builder> for SampleConsumerBuilder { + fn build(self) -> com_api_concept::Result> { + let instance_info = MockConsumerInfo { + instance_specifier: self.instance_specifier.clone(), + }; + + Ok(Consumer::new(instance_info)) + } +} + pub struct RuntimeBuilderImpl {} impl Builder for RuntimeBuilderImpl { @@ -410,7 +468,7 @@ impl RuntimeBuilderImpl { #[cfg(test)] mod test { - use com_api_concept::{SampleContainer, Subscription}; + use com_api_concept::{Publisher, SampleContainer, SampleMaybeUninit, SampleMut, Subscription}; #[test] fn receive_stuff() { @@ -451,4 +509,12 @@ mod test { } }) } + + #[test] + fn send_stuff() { + let test_publisher = super::Publisher::::new(); + let sample = test_publisher.allocate().expect("Couldn't allocate sample"); + let sample = sample.write(42); + sample.send().expect("Send failed for sample"); + } } diff --git a/com-api/com-api/src/lib.rs b/com-api/com-api/src/lib.rs index 6924002..7fb370c 100644 --- a/com-api/com-api/src/lib.rs +++ b/com-api/com-api/src/lib.rs @@ -29,6 +29,6 @@ pub use com_api_runtime_lola::LolaRuntimeImpl; pub use com_api_concept::{ Builder, Consumer, ConsumerBuilder, ConsumerDescriptor, InstanceSpecifier, Interface, - OfferedProducer, Producer, ProducerBuilder, Reloc, Result, SampleContainer, SampleMaybeUninit, + OfferedProducer, Producer, ProducerBuilder, Publisher, Reloc, Runtime, Result, SampleContainer, SampleMaybeUninit, SampleMut, ServiceDiscovery, Subscriber, Subscription, }; diff --git a/com-api/examples/basic-consumer-producer.rs b/com-api/examples/basic-consumer-producer.rs index dd05b16..2d6e79c 100644 --- a/com-api/examples/basic-consumer-producer.rs +++ b/com-api/examples/basic-consumer-producer.rs @@ -12,51 +12,58 @@ use com_api::*; use com_api_gen::*; -fn main() { - let runtime_builder = RuntimeBuilderImpl::new(); - let runtime = Builder::::build(runtime_builder).unwrap(); - let producer_builder = runtime.producer_builder::(InstanceSpecifier { - specifier: "My/Funk/ServiceName".to_string(), - }); - let producer = producer_builder.build().unwrap(); - let offered_producer = producer.offer().unwrap(); - - // Business logic - let uninit_sample = offered_producer.left_tire.allocate().unwrap(); - let sample = uninit_sample.write(Tire {}); - sample.send().unwrap(); - - // Create service discovery - let consumer_discovery = runtime.find_service::(InstanceSpecifier { - specifier: "My/Funk/ServiceName".to_string(), - }); - let available_service_instances = consumer_discovery.get_available_instances().unwrap(); - - // Create consumer from first discovered service - let consumer_builder = available_service_instances - .into_iter() - .find(|desc| desc.get_instance_id() == 42) - .unwrap(); - let consumer = consumer_builder.build().unwrap(); - + fn use_vehicle_interface(consumer: VehicleConsumer) + { // Subscribe to one event let subscribed = consumer.left_tire.subscribe(3).unwrap(); // Create sample buffer to be used during receive let mut sample_buf = SampleContainer::new(); for _ in 0..10 { - let uninit_sample = offered_producer.left_tire.allocate().unwrap(); - let sample = uninit_sample.write(Tire {}); - sample.send().unwrap(); match subscribed.try_receive(&mut sample_buf, 1) { Ok(0) => panic!("No sample received"), Ok(x) => { let sample = sample_buf.pop_front().unwrap(); - println!("{} sample received: sample[0] = {:?}", x, *sample) + println!("{} samples received: sample[0] = {:?}", x, *sample) } Err(e) => panic!("{:?}", e), } } + + } + +fn use_consumer(runtime: &R) +{ + // Create service discovery + let consumer_discovery = runtime.find_service::(InstanceSpecifier::new("My/Funk/ServiceName").unwrap()); + let available_service_instances = consumer_discovery.get_available_instances().unwrap(); + + // Create consumer from first discovered service + let consumer_builder = available_service_instances + .into_iter() + .find(|desc| desc.get_instance_id() == 42) + .unwrap(); + let consumer = consumer_builder.build().unwrap(); + use_vehicle_interface(consumer); +} + +fn use_producer(runtime: &R) +{ + let producer_builder = runtime.producer_builder::>(InstanceSpecifier::new("My/Funk/ServiceName").unwrap()); + let producer = producer_builder.build().unwrap(); + let offered_producer = producer.offer().unwrap(); + + // Business logic + let uninit_sample = offered_producer.left_tire.allocate().unwrap(); + let sample = uninit_sample.write(Tire {}); + sample.send().unwrap(); +} + +fn main() { + let runtime_builder = RuntimeBuilderImpl::new(); + let runtime = Builder::::build(runtime_builder).unwrap(); + use_producer(&runtime); + use_consumer(&runtime); } #[cfg(test)] @@ -67,56 +74,19 @@ mod test { fn create_producer() { // Factory let runtime_builder = RuntimeBuilderImpl::new(); - let runtime = runtime_builder.build().unwrap(); - let producer_builder = runtime.producer_builder::(InstanceSpecifier { - specifier: "My/Funk/ServiceName".to_string(), - }); - let producer = producer_builder.build().unwrap(); - let offered_producer = producer.offer().unwrap(); - - // Business logic - let uninit_sample = offered_producer.left_tire.allocate().unwrap(); - let sample = uninit_sample.write(Tire {}); - sample.send().unwrap(); + let runtime = Builder::::build(runtime_builder).unwrap(); + use_producer(&runtime); + } #[test] fn create_consumer() { - // Create runtime let runtime_builder = RuntimeBuilderImpl::new(); - let runtime = runtime_builder.build().unwrap(); - - // Create service discovery - let consumer_discovery = runtime.find_service::(InstanceSpecifier { - specifier: "My/Funk/ServiceName".to_string(), - }); - let available_service_instances = consumer_discovery.get_available_instances().unwrap(); - - // Create consumer from first discovered service - let consumer_builder = available_service_instances - .into_iter() - .find(|desc| desc.get_instance_id() == 42) - .unwrap(); - let consumer = consumer_builder.build().unwrap(); - - // Subscribe to one event - let subscribed = consumer.left_tire.subscribe(3).unwrap(); - - // Create sample buffer to be used during receive - let mut sample_buf = SampleContainer::new(); - for _ in 0..10 { - match subscribed.try_receive(&mut sample_buf, 1) { - Ok(0) => panic!("No sample received"), - Ok(x) => { - let sample = sample_buf.pop_front().unwrap(); - println!("{} samples received: sample[0] = {:?}", x, *sample) - } - Err(e) => panic!("{:?}", e), - } - } + let runtime = Builder::::build(runtime_builder).unwrap(); + use_consumer(&runtime); } - async fn async_data_processor_fn(subscribed: impl Subscription) { + async fn async_data_processor_fn(subscribed: impl Subscription) { let mut buffer = SampleContainer::new(); for _ in 0..10 { match subscribed.receive(&mut buffer, 1, 1).await { @@ -138,9 +108,7 @@ mod test { let runtime_builder = RuntimeBuilderImpl::new(); let runtime = runtime_builder.build().unwrap(); - let consumer_discovery = runtime.find_service::(InstanceSpecifier { - specifier: "My/Funk/ServiceName".to_string(), - }); + let consumer_discovery = runtime.find_service::(InstanceSpecifier::new("My/Funk/ServiceName").unwrap()); let available_service_instances = consumer_discovery.get_available_instances().unwrap(); // Create consumer from first discovered service diff --git a/com-api/examples/com-api-gen/com-api-gen-lola/src/lib.rs b/com-api/examples/com-api-gen/com-api-gen-lola/src/lib.rs index 24b681e..e2b894d 100644 --- a/com-api/examples/com-api-gen/com-api-gen-lola/src/lib.rs +++ b/com-api/examples/com-api-gen/com-api-gen-lola/src/lib.rs @@ -22,8 +22,7 @@ //! //! ``` -use com_api::*; -use com_api_runtime_lola::{LolaRuntimeImpl, SampleConsumerBuilder, SampleProducerBuilder}; +use com_api::{Consumer, Interface, OfferedProducer, Producer, Reloc, Runtime, Subscriber}; #[derive(Debug)] pub struct Tire {} @@ -35,59 +34,53 @@ unsafe impl Reloc for Exhaust {} pub struct VehicleInterface {} /// Generic -impl Interface for VehicleInterface {} - -pub struct AnotherInterface {} - -impl Interface for AnotherInterface {} - -pub struct VehicleProducer {} +impl Interface for VehicleInterface { + type Consumer = VehicleConsumer; + type Producer = VehicleProducer; +} -impl Producer for VehicleProducer { - type Interface = VehicleInterface; - type OfferedProducer = VehicleOfferedProducer; +pub struct VehicleConsumer { + pub left_tire: R::Subscriber, + pub exhaust: R::Subscriber, +} - fn offer(self) -> com_api::Result { - todo!() +impl Consumer for VehicleConsumer { + fn new(instance_info: R::ConsumerInfo) -> Self { + VehicleConsumer { + left_tire: R::Subscriber::new("left_tire", instance_info.clone()), + exhaust: R::Subscriber::new("exhaust", instance_info.clone()), + } } } -pub struct VehicleOfferedProducer { - pub left_tire: com_api_runtime_lola::Publisher, - pub exhaust: com_api_runtime_lola::Publisher, +pub struct AnotherInterface {} + +pub struct VehicleProducer +{ + _runtime: std::marker::PhantomData, } -impl OfferedProducer for VehicleOfferedProducer { +impl Producer for VehicleProducer { type Interface = VehicleInterface; - type Producer = VehicleProducer; + type OfferedProducer = VehicleOfferedProducer; - fn unoffer(self) -> Self::Producer { - VehicleProducer {} - } -} - -impl Builder for SampleProducerBuilder { - fn build(self) -> com_api::Result { + fn offer(self) -> com_api::Result { todo!() } } -impl ProducerBuilder - for SampleProducerBuilder -{ -} - -pub struct VehicleConsumer { - pub left_tire: com_api_runtime_lola::SubscribableImpl, - pub exhaust: com_api_runtime_lola::SubscribableImpl, +pub struct VehicleOfferedProducer { + pub left_tire: R::Publisher, + pub exhaust: R::Publisher, } -impl Consumer for VehicleConsumer {} - -impl ConsumerBuilder for SampleConsumerBuilder {} +impl OfferedProducer for VehicleOfferedProducer { + type Interface = VehicleInterface; + type Producer = VehicleProducer; -impl Builder for SampleConsumerBuilder { - fn build(self) -> com_api::Result { - todo!() + fn unoffer(self) -> Self::Producer { + VehicleProducer { + _runtime: std::marker::PhantomData, + } } } diff --git a/com-api/examples/com-api-gen/com-api-gen-mock/src/lib.rs b/com-api/examples/com-api-gen/com-api-gen-mock/src/lib.rs index e99f950..c30b804 100644 --- a/com-api/examples/com-api-gen/com-api-gen-mock/src/lib.rs +++ b/com-api/examples/com-api-gen/com-api-gen-mock/src/lib.rs @@ -23,7 +23,6 @@ //! ``` use com_api::*; -use com_api_runtime_mock::{MockRuntimeImpl, SampleConsumerBuilder, SampleProducerBuilder}; #[derive(Debug)] pub struct Tire {} @@ -35,59 +34,53 @@ unsafe impl Reloc for Exhaust {} pub struct VehicleInterface {} /// Generic -impl Interface for VehicleInterface {} - -pub struct AnotherInterface {} - -impl Interface for AnotherInterface {} - -pub struct VehicleProducer {} +impl Interface for VehicleInterface { + type Consumer = VehicleConsumer; + type Producer = VehicleProducer; +} -impl Producer for VehicleProducer { - type Interface = VehicleInterface; - type OfferedProducer = VehicleOfferedProducer; +pub struct VehicleConsumer { + pub left_tire: R::Subscriber, + pub exhaust: R::Subscriber, +} - fn offer(self) -> com_api::Result { - todo!() +impl Consumer for VehicleConsumer { + fn new(instance_info: R::ConsumerInfo) -> Self { + VehicleConsumer { + left_tire: R::Subscriber::new("left_tire", instance_info.clone()), + exhaust: R::Subscriber::new("exhaust", instance_info.clone()), + } } } -pub struct VehicleOfferedProducer { - pub left_tire: com_api_runtime_mock::Publisher, - pub exhaust: com_api_runtime_mock::Publisher, +pub struct AnotherInterface {} + +pub struct VehicleProducer +{ + _runtime: std::marker::PhantomData, } -impl OfferedProducer for VehicleOfferedProducer { +impl Producer for VehicleProducer { type Interface = VehicleInterface; - type Producer = VehicleProducer; + type OfferedProducer = VehicleOfferedProducer; - fn unoffer(self) -> Self::Producer { - VehicleProducer {} - } -} - -impl Builder for SampleProducerBuilder { - fn build(self) -> com_api::Result { + fn offer(self) -> com_api::Result { todo!() } } -impl ProducerBuilder - for SampleProducerBuilder -{ -} - -pub struct VehicleConsumer { - pub left_tire: com_api_runtime_mock::SubscribableImpl, - pub exhaust: com_api_runtime_mock::SubscribableImpl, +pub struct VehicleOfferedProducer { + pub left_tire: R::Publisher, + pub exhaust: R::Publisher, } -impl Consumer for VehicleConsumer {} - -impl ConsumerBuilder for SampleConsumerBuilder {} +impl OfferedProducer for VehicleOfferedProducer { + type Interface = VehicleInterface; + type Producer = VehicleProducer; -impl Builder for SampleConsumerBuilder { - fn build(self) -> com_api::Result { - todo!() + fn unoffer(self) -> Self::Producer { + VehicleProducer { + _runtime: std::marker::PhantomData, + } } } diff --git a/com-api/examples/com-api-gen/src/lib.rs b/com-api/examples/com-api-gen/src/lib.rs index b08db41..b5b5003 100644 --- a/com-api/examples/com-api-gen/src/lib.rs +++ b/com-api/examples/com-api-gen/src/lib.rs @@ -10,6 +10,6 @@ // SPDX-License-Identifier: Apache-2.0 #[cfg(feature = "mock")] -pub use com_api_gen_mock::{Tire, VehicleInterface}; +pub use com_api_gen_mock::{Tire, VehicleInterface, VehicleConsumer, VehicleProducer, VehicleOfferedProducer}; #[cfg(feature = "lola")] -pub use com_api_gen_lola::{Tire, VehicleInterface}; +pub use com_api_gen_lola::{Tire, VehicleInterface, VehicleConsumer, VehicleProducer, VehicleOfferedProducer}; From 03d8c17948eadbe2a9a4336a442e42c277eac577 Mon Sep 17 00:00:00 2001 From: bharatgoswami Date: Tue, 18 Nov 2025 17:54:03 +0530 Subject: [PATCH 2/5] Rust::com Review comment fix and one Gen file * Added Async API for get_instance * added Debug trait for All the Sample trait * Added Core instead of std all the possible palce * Added one Gen file and remove runtime specific gen file * Added both Mock and Lola time in same main file * Added VehicleMonitor as Consumer on example * Removed all the feature flag * added impl for Reloc * Removed root toml file --- Cargo.lock | 348 ------------------ Cargo.toml | 3 - README.md | 18 +- com-api/Cargo.lock | 17 - com-api/Cargo.toml | 4 + com-api/com-api-concept/src/lib.rs | 58 +-- com-api/com-api-runtime-lola/src/lib.rs | 50 ++- com-api/com-api-runtime-mock/src/lib.rs | 50 ++- com-api/com-api/Cargo.toml | 8 +- com-api/com-api/src/lib.rs | 15 +- com-api/examples/Cargo.toml | 6 +- com-api/examples/basic-consumer-producer.rs | 72 ++-- com-api/examples/com-api-gen/Cargo.toml | 7 +- .../com-api-gen/com-api-gen-lola/Cargo.toml | 13 - .../com-api-gen/com-api-gen-lola/src/lib.rs | 86 ----- .../com-api-gen/com-api-gen-mock/Cargo.toml | 13 - .../com-api-gen/com-api-gen-mock/src/lib.rs | 86 ----- com-api/examples/com-api-gen/src/lib.rs | 80 +++- 18 files changed, 238 insertions(+), 696 deletions(-) delete mode 100644 Cargo.lock delete mode 100644 Cargo.toml delete mode 100644 com-api/examples/com-api-gen/com-api-gen-lola/Cargo.toml delete mode 100644 com-api/examples/com-api-gen/com-api-gen-lola/src/lib.rs delete mode 100644 com-api/examples/com-api-gen/com-api-gen-mock/Cargo.toml delete mode 100644 com-api/examples/com-api-gen/com-api-gen-mock/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 40e4fa6..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,348 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets", -] - -[[package]] -name = "cfg-if" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" - -[[package]] -name = "com-api" -version = "0.1.0" - -[[package]] -name = "com-api-example" -version = "0.1.0" -dependencies = [ - "com-api", - "com-api-sample-gen", - "com-api-sample-runtime", - "tokio", -] - -[[package]] -name = "com-api-sample-gen" -version = "0.1.0" -dependencies = [ - "com-api", - "com-api-sample-runtime", -] - -[[package]] -name = "com-api-sample-runtime" -version = "0.1.0" -dependencies = [ - "com-api", - "futures", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "syn" -version = "2.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tokio" -version = "1.43.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "492a604e2fd7f814268a378409e6c92b5525d747d10db9a229723f55a417958c" -dependencies = [ - "backtrace", - "pin-project-lite", - "tokio-macros", -] - -[[package]] -name = "tokio-macros" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 47b0c6f..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,3 +0,0 @@ -[workspace] -members = ["com-api", "com-api-example", "com-api-sample-gen", "com-api-sample-runtime"] -resolver = "3" diff --git a/README.md b/README.md index 21b6b2b..f3671e1 100644 --- a/README.md +++ b/README.md @@ -5,27 +5,17 @@ Incubation repository for interprocess communication framework Examples can be built from examples directory by passing desired IPC adapter as feature. -For mock build: +For build: ``` -inc_mw_com$ cargo build --example basic-consumer-producer --features "mock" -``` - -For LoLa build: -``` -inc_mw_com/com-api$ cargo build --example basic-consumer-producer --features "lola" +inc_mw_com$ cargo build --example basic-consumer-producer ``` For mock test: ``` -inc_mw_com$ cargo test --test basic-consumer-producer-test --features "mock" +inc_mw_com$ cargo test --test basic-consumer-producer-test ``` For mock Build and Run: ``` -inc_mw_com/com-api$ cargo run --example basic-consumer-producer --features "mock" -``` - -For LoLa Build and Run: -``` -inc_mw_com/com-api$ cargo run --example basic-consumer-producer --features "lola" +inc_mw_com/com-api$ cargo run --example basic-consumer-producer ``` diff --git a/com-api/Cargo.lock b/com-api/Cargo.lock index 960d88e..a744b11 100644 --- a/com-api/Cargo.lock +++ b/com-api/Cargo.lock @@ -63,25 +63,8 @@ dependencies = [ [[package]] name = "com-api-gen" version = "0.1.0" -dependencies = [ - "com-api-gen-lola", - "com-api-gen-mock", -] - -[[package]] -name = "com-api-gen-lola" -version = "0.1.0" dependencies = [ "com-api", - "com-api-runtime-lola", -] - -[[package]] -name = "com-api-gen-mock" -version = "0.1.0" -dependencies = [ - "com-api", - "com-api-runtime-mock", ] [[package]] diff --git a/com-api/Cargo.toml b/com-api/Cargo.toml index c463bc4..91fc0b5 100644 --- a/com-api/Cargo.toml +++ b/com-api/Cargo.toml @@ -16,6 +16,10 @@ edition = "2024" publish = ["common"] license = "Apache-2.0" +[workspace.lints.clippy] +std_instead_of_core = "warn" +alloc_instead_of_core = "warn" + [workspace.dependencies] com-api = { path = "com-api"} com-api-concept = { path = "com-api-concept"} diff --git a/com-api/com-api-concept/src/lib.rs b/com-api/com-api-concept/src/lib.rs index 7b73e08..dfb658b 100644 --- a/com-api/com-api-concept/src/lib.rs +++ b/com-api/com-api-concept/src/lib.rs @@ -44,11 +44,11 @@ //! - Structures //! - Tuples -use std::collections::VecDeque; -use std::fmt::Debug; -use std::future::Future; -use std::ops::{Deref, DerefMut}; +use core::fmt::Debug; +use core::future::Future; +use core::ops::{Deref, DerefMut}; use std::path::Path; +use std::collections::VecDeque; #[derive(Debug)] pub enum Error { @@ -59,7 +59,7 @@ pub enum Error { SubscribeFailed, } -pub type Result = std::result::Result; +pub type Result = core::result::Result; /// Generic trait for all "factory-like" types pub trait Builder { @@ -75,9 +75,9 @@ pub trait Builder { // * ConsumerInfo - Information about a consumer instance required to pass to different traits/types/methods pub trait Runtime { type ServiceDiscovery: ServiceDiscovery; - type Subscriber: Subscriber; + type Subscriber: Subscriber; type ProducerBuilder>: ProducerBuilder; - type Publisher: Publisher; + type Publisher: Publisher; type ProviderInfo: Send + Clone; type ConsumerInfo: Send + Clone; @@ -104,7 +104,7 @@ where /// The string shall describe where to find a certain instance of a service. Each level shall look /// like this /// :my/path/to/service_name -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct InstanceSpecifier { specifier: Option, } @@ -115,9 +115,11 @@ impl InstanceSpecifier { pub const MATCH_ANY: Self = InstanceSpecifier { specifier: None }; fn check_str(_service_name: &str) -> bool { - // For now, accept any non-empty string as a valid service name - // In a real implementation, this might validate the format - true + + // need to validated service name convention according to backend specification + //for that either call into backend specific code or implement generic checks here + + todo!() } /// Create a new instance specifier, using the string-like input as the path to the @@ -171,6 +173,13 @@ pub unsafe trait Reloc {} unsafe impl Reloc for () {} unsafe impl Reloc for u32 {} +unsafe impl Reloc for u64 {} +unsafe impl Reloc for i32 {} +unsafe impl Reloc for i64 {} +unsafe impl Reloc for f32 {} +unsafe impl Reloc for f64 {} +unsafe impl Reloc for bool {} +unsafe impl Reloc for char {} /// A `Sample` provides a reference to a memory buffer of an event with immutable value. /// @@ -179,9 +188,9 @@ unsafe impl Reloc for u32 {} /// /// The ordering of SamplePtrs is total over the reception order // TODO: C++ doesn't yet support this. Expose API to compare SamplePtr ages. -pub trait Sample: Deref + Send + PartialOrd + Ord +pub trait Sample: Deref + Send + PartialOrd + Ord + Debug where - T: Send + Reloc, + T: Send + Reloc + Debug, { } @@ -189,9 +198,9 @@ where /// /// By implementing the `DerefMut` trait implementations of the trait support the `.` operator for dereferencing. /// The buffers with its data lives as long as there are references to it existing in the framework. -pub trait SampleMut: DerefMut +pub trait SampleMut: DerefMut + Debug where - T: Send + Reloc, + T: Send + Reloc + Debug, { /// The associated read-only sample type. type Sample: Sample; @@ -210,9 +219,9 @@ where /// /// TODO: Shall we also require DerefMut> from implementing types? How to deal /// TODO: with the ambiguous assume_init() then? -pub trait SampleMaybeUninit +pub trait SampleMaybeUninit : Debug where - T: Send + Reloc, + T: Send + Reloc + Debug, { /// Buffer type for mutable data after initialization type SampleMut: SampleMut; @@ -260,7 +269,7 @@ pub trait Producer { pub trait Publisher where - T: Reloc + Send, + T: Reloc + Send + Debug, { type SampleMaybeUninit<'a>: SampleMaybeUninit + 'a where @@ -289,7 +298,10 @@ pub trait ServiceDiscovery { type ServiceEnumerator: IntoIterator; fn get_available_instances(&self) -> Result; - // TODO: Provide an async stream for newly available services / ServiceDescriptors + + #[allow(clippy::manual_async_fn)] + fn get_available_instances_async(&self) -> impl Future> + Send; + } pub trait ConsumerDescriptor { @@ -301,7 +313,7 @@ pub trait ConsumerBuilder: { } -pub trait Subscriber { +pub trait Subscriber { type Subscription: Subscription; fn new(identifier: &str, instance_info: R::ConsumerInfo) -> Self; fn subscribe(self, max_num_samples: usize) -> Result; @@ -327,7 +339,7 @@ impl SampleContainer { pub fn iter<'a, T>(&'a self) -> impl Iterator where S: Sample, - T: Reloc + Send + 'a, + T: Reloc + Send + 'a + Debug, { self.inner.iter().map(::deref) } @@ -345,7 +357,7 @@ impl SampleContainer { self.inner.len() } - pub fn front(&self) -> Option<&T> + pub fn front(&self) -> Option<&T> where S: Sample, { @@ -353,7 +365,7 @@ impl SampleContainer { } } -pub trait Subscription { +pub trait Subscription { type Subscriber: Subscriber; type Sample<'a>: Sample where diff --git a/com-api/com-api-runtime-lola/src/lib.rs b/com-api/com-api-runtime-lola/src/lib.rs index b4680f5..29e7a17 100644 --- a/com-api/com-api-runtime-lola/src/lib.rs +++ b/com-api/com-api-runtime-lola/src/lib.rs @@ -14,14 +14,15 @@ #![allow(dead_code)] -use std::cmp::Ordering; -use std::collections::VecDeque; -use std::future::Future; -use std::marker::PhantomData; -use std::mem::MaybeUninit; -use std::ops::{Deref, DerefMut}; use std::path::Path; -use std::sync::atomic::AtomicUsize; +use std::collections::VecDeque; +use core::future::Future; +use core::marker::PhantomData; +use core::mem::MaybeUninit; +use core::ops::{Deref, DerefMut}; +use core::sync::atomic::AtomicUsize; +use core::cmp::Ordering; +use core::fmt::Debug; use com_api_concept::{ Builder, Consumer,ConsumerBuilder, ConsumerDescriptor, InstanceSpecifier, Interface, Reloc, Runtime, @@ -44,9 +45,9 @@ pub struct LolaConsumerInfo { impl Runtime for LolaRuntimeImpl { type ServiceDiscovery = SampleConsumerDiscovery; - type Subscriber = SubscribableImpl; + type Subscriber = SubscribableImpl; type ProducerBuilder> = SampleProducerBuilder; - type Publisher = Publisher; + type Publisher = Publisher; // TODO: Integrate with Producer::offer() method implementation type ProviderInfo = LolaProviderInfo; type ConsumerInfo = LolaConsumerInfo; @@ -68,10 +69,12 @@ impl Runtime for LolaRuntimeImpl { } } +#[derive(Debug)] struct LolaEvent { event: PhantomData, } +#[derive(Debug)] struct LolaBinding<'a, T> where T: Send, @@ -82,6 +85,7 @@ where unsafe impl<'a, T> Send for LolaBinding<'a, T> where T: Send {} +#[derive(Debug)] enum SampleBinding<'a, T> where T: Send, @@ -90,9 +94,10 @@ where Test(Box), } +#[derive(Debug)] pub struct Sample<'a, T> where - T: Reloc + Send, + T: Reloc + Send , { id: usize, inner: SampleBinding<'a, T>, @@ -102,11 +107,11 @@ static ID_COUNTER: AtomicUsize = AtomicUsize::new(0); impl<'a, T> From for Sample<'a, T> where - T: Reloc + Send, + T: Reloc + Send + Debug, { fn from(value: T) -> Self { Self { - id: ID_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed), + id: ID_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed), inner: SampleBinding::Test(Box::new(value)), } } @@ -126,7 +131,7 @@ where } } -impl<'a, T> com_api_concept::Sample for Sample<'a, T> where T: Send + Reloc {} +impl<'a, T> com_api_concept::Sample for Sample<'a, T> where T: Send + Reloc + Debug {} impl<'a, T> PartialEq for Sample<'a, T> where @@ -157,6 +162,8 @@ where } } + +#[derive(Debug)] pub struct SampleMut<'a, T> where T: Reloc, @@ -167,7 +174,7 @@ where impl<'a, T> com_api_concept::SampleMut for SampleMut<'a, T> where - T: Reloc + Send, + T: Reloc + Send + Debug, { type Sample = Sample<'a, T>; @@ -200,6 +207,7 @@ where } } +#[derive(Debug)] pub struct SampleMaybeUninit<'a, T> where T: Reloc + Send, @@ -210,7 +218,7 @@ where impl<'a, T> com_api_concept::SampleMaybeUninit for SampleMaybeUninit<'a, T> where - T: Reloc + Send, + T: Reloc + Send + Debug, { type SampleMut = SampleMut<'a, T>; @@ -250,7 +258,7 @@ impl Default for SubscribableImpl { } } -impl Subscriber for SubscribableImpl { +impl Subscriber for SubscribableImpl { type Subscription = SubscriberImpl; fn new(identifier: &str, instance_info: LolaConsumerInfo) -> Self { Self { @@ -289,7 +297,7 @@ where impl Subscription for SubscriberImpl where - T: Reloc + Send, + T: Reloc + Send + Debug, { type Subscriber = SubscribableImpl; type Sample<'a> @@ -344,7 +352,7 @@ where impl com_api_concept::Publisher for Publisher where - T: Reloc + Send, + T: Reloc + Send + Debug, { type SampleMaybeUninit<'a> = SampleMaybeUninit<'a, T> where Self: 'a; @@ -378,6 +386,12 @@ where fn get_available_instances(&self) -> com_api_concept::Result { Ok(Vec::new()) } + + #[allow(clippy::manual_async_fn)] + fn get_available_instances_async(&self) -> impl Future> { + async { Ok(Vec::new()) } + } + } impl ConsumerBuilder for SampleConsumerBuilder {} diff --git a/com-api/com-api-runtime-mock/src/lib.rs b/com-api/com-api-runtime-mock/src/lib.rs index 9ed974e..b21aeb2 100644 --- a/com-api/com-api-runtime-mock/src/lib.rs +++ b/com-api/com-api-runtime-mock/src/lib.rs @@ -16,14 +16,15 @@ #![allow(dead_code)] -use std::cmp::Ordering; -use std::collections::VecDeque; -use std::future::Future; -use std::marker::PhantomData; -use std::mem::MaybeUninit; -use std::ops::{Deref, DerefMut}; use std::path::Path; -use std::sync::atomic::AtomicUsize; +use std::collections::VecDeque; +use core::future::Future; +use core::marker::PhantomData; +use core::mem::MaybeUninit; +use core::ops::{Deref, DerefMut}; +use core::sync::atomic::AtomicUsize; +use core::cmp::Ordering; +use core::fmt::Debug; use com_api_concept::{ Builder, Consumer, ConsumerBuilder, ConsumerDescriptor, InstanceSpecifier, Interface, Reloc, Runtime, @@ -46,9 +47,9 @@ pub struct MockConsumerInfo { impl Runtime for MockRuntimeImpl { type ServiceDiscovery = SampleConsumerDiscovery; - type Subscriber = SubscribableImpl; + type Subscriber = SubscribableImpl; type ProducerBuilder> = SampleProducerBuilder; - type Publisher = Publisher; + type Publisher = Publisher; // TODO: Integrate with Producer::offer() method implementation type ProviderInfo = MockProviderInfo; type ConsumerInfo = MockConsumerInfo; @@ -70,10 +71,12 @@ impl Runtime for MockRuntimeImpl { } } +#[derive(Debug)] struct MockEvent { event: PhantomData, } +#[derive(Debug)] struct MockBinding<'a, T> where T: Send, @@ -84,6 +87,7 @@ where unsafe impl<'a, T> Send for MockBinding<'a, T> where T: Send {} +#[derive(Debug)] enum SampleBinding<'a, T> where T: Send, @@ -92,6 +96,7 @@ where Test(Box), } +#[derive(Debug)] pub struct Sample<'a, T> where T: Reloc + Send, @@ -104,11 +109,11 @@ static ID_COUNTER: AtomicUsize = AtomicUsize::new(0); impl<'a, T> From for Sample<'a, T> where - T: Reloc + Send, + T: Reloc + Send + Debug, { fn from(value: T) -> Self { Self { - id: ID_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed), + id: ID_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed), inner: SampleBinding::Test(Box::new(value)), } } @@ -128,7 +133,7 @@ where } } -impl<'a, T> com_api_concept::Sample for Sample<'a, T> where T: Send + Reloc {} +impl<'a, T> com_api_concept::Sample for Sample<'a, T> where T: Send + Reloc + Debug {} impl<'a, T> PartialEq for Sample<'a, T> where @@ -159,6 +164,7 @@ where } } +#[derive(Debug)] pub struct SampleMut<'a, T> where T: Reloc, @@ -169,7 +175,7 @@ where impl<'a, T> com_api_concept::SampleMut for SampleMut<'a, T> where - T: Reloc + Send, + T: Reloc + Send + Debug, { type Sample = Sample<'a, T>; @@ -202,6 +208,7 @@ where } } +#[derive(Debug)] pub struct SampleMaybeUninit<'a, T> where T: Reloc + Send, @@ -212,7 +219,7 @@ where impl<'a, T> com_api_concept::SampleMaybeUninit for SampleMaybeUninit<'a, T> where - T: Reloc + Send, + T: Reloc + Send + Debug, { type SampleMut = SampleMut<'a, T>; @@ -251,7 +258,7 @@ impl Default for SubscribableImpl { } } -impl Subscriber for SubscribableImpl { +impl Subscriber for SubscribableImpl { type Subscription = SubscriberImpl; fn new(identifier: &str, instance_info: MockConsumerInfo) -> Self { Self { @@ -290,7 +297,7 @@ where impl Subscription for SubscriberImpl where - T: Reloc + Send, + T: Reloc + Send + Debug, { type Subscriber = SubscribableImpl; type Sample<'a> @@ -345,11 +352,11 @@ where impl com_api_concept::Publisher for Publisher where - T: Reloc + Send, + T: Reloc + Send + Debug, { type SampleMaybeUninit<'a> = SampleMaybeUninit<'a, T> where Self: 'a; - fn allocate<'a>(&'a self) -> com_api_concept::Result> { + fn allocate<'a>(&'a self) -> com_api_concept::Result> { Ok(SampleMaybeUninit { data: MaybeUninit::uninit(), lifetime: PhantomData, @@ -379,6 +386,11 @@ where fn get_available_instances(&self) -> com_api_concept::Result { Ok(Vec::new()) } + + #[allow(clippy::manual_async_fn)] + fn get_available_instances_async(&self) -> impl Future> { + async { Ok(Vec::new()) } + } } pub struct SampleProducerBuilder { @@ -460,7 +472,7 @@ impl Default for RuntimeBuilderImpl { } impl RuntimeBuilderImpl { - /// Creates a new instance of the default implementation of the com layer + /// Creates a new instance of the default implementation for the com module of s-core pub fn new() -> Self { Self {} } diff --git a/com-api/com-api/Cargo.toml b/com-api/com-api/Cargo.toml index 0664f1f..fdcd21e 100644 --- a/com-api/com-api/Cargo.toml +++ b/com-api/com-api/Cargo.toml @@ -5,11 +5,7 @@ edition = "2024" publish = ["common"] license = "Apache-2.0" -[features] -mock = ["com-api-runtime-mock"] -lola = ["com-api-runtime-lola"] - [dependencies] com-api-concept = { workspace = true } -com-api-runtime-mock = { workspace = true, optional = true } -com-api-runtime-lola = { workspace = true, optional = true } +com-api-runtime-mock = { workspace = true } +com-api-runtime-lola = { workspace = true } diff --git a/com-api/com-api/src/lib.rs b/com-api/com-api/src/lib.rs index 7fb370c..b541f17 100644 --- a/com-api/com-api/src/lib.rs +++ b/com-api/com-api/src/lib.rs @@ -12,23 +12,14 @@ //! This crate provides the COM API, which is a common interface for different implementations //! of the COM API, e.g., for different IPC backends. //! The actual implementations are provided by the `com-api-runtime-mock` and `com-api-runtime-lola` crates. -//! The user must enable one of these features to use the COM API. - -#[cfg(not(any(feature = "mock", feature = "lola")))] -compile_error!("You must enable at least one feature: `mock` or `lola`!"); - -#[cfg(feature = "mock")] -pub use com_api_runtime_mock::RuntimeBuilderImpl; -#[cfg(feature = "mock")] +pub use com_api_runtime_mock::RuntimeBuilderImpl as MockRuntimeBuilderImpl; pub use com_api_runtime_mock::MockRuntimeImpl; -#[cfg(feature = "lola")] -pub use com_api_runtime_lola::RuntimeBuilderImpl; -#[cfg(feature = "lola")] +pub use com_api_runtime_lola::RuntimeBuilderImpl as LolaRuntimeBuilderImpl; pub use com_api_runtime_lola::LolaRuntimeImpl; pub use com_api_concept::{ - Builder, Consumer, ConsumerBuilder, ConsumerDescriptor, InstanceSpecifier, Interface, + Builder, Consumer, ConsumerBuilder, ConsumerDescriptor, Error, InstanceSpecifier, Interface, OfferedProducer, Producer, ProducerBuilder, Publisher, Reloc, Runtime, Result, SampleContainer, SampleMaybeUninit, SampleMut, ServiceDiscovery, Subscriber, Subscription, }; diff --git a/com-api/examples/Cargo.toml b/com-api/examples/Cargo.toml index 10575a9..0441e68 100644 --- a/com-api/examples/Cargo.toml +++ b/com-api/examples/Cargo.toml @@ -5,13 +5,9 @@ edition = "2024" publish = ["common"] license = "Apache-2.0" -[features] -mock = ["com-api/mock", "com-api-gen/mock"] -lola = ["com-api/lola", "com-api-gen/lola"] - [dependencies] com-api = { workspace = true } -com-api-gen = { workspace = true, optional = true } +com-api-gen = { workspace = true } tokio = { version = "~1.43", features = ["rt-multi-thread", "macros", "test-util"] } [[example]] diff --git a/com-api/examples/basic-consumer-producer.rs b/com-api/examples/basic-consumer-producer.rs index 2d6e79c..70b097b 100644 --- a/com-api/examples/basic-consumer-producer.rs +++ b/com-api/examples/basic-consumer-producer.rs @@ -12,25 +12,34 @@ use com_api::*; use com_api_gen::*; - fn use_vehicle_interface(consumer: VehicleConsumer) - { - // Subscribe to one event - let subscribed = consumer.left_tire.subscribe(3).unwrap(); - - // Create sample buffer to be used during receive - let mut sample_buf = SampleContainer::new(); - for _ in 0..10 { + +// Example struct demonstrating composition with VehicleConsumer +pub struct VehicleMonitor { + consumer: VehicleConsumer, +} + +impl VehicleMonitor { + /// Create a new VehicleMonitor with a consumer + pub fn new(consumer: VehicleConsumer) -> Self { + Self { consumer } + } + + /// Monitor tire data from the consumer + pub fn monitor_tire_data(self) -> Result { + let subscribed = self.consumer.left_tire.subscribe(3)?; + let mut sample_buf = SampleContainer::new(); + match subscribed.try_receive(&mut sample_buf, 1) { - Ok(0) => panic!("No sample received"), + Ok(0) => Err(Error::Fail), Ok(x) => { let sample = sample_buf.pop_front().unwrap(); - println!("{} samples received: sample[0] = {:?}", x, *sample) + Ok(format!("{} samples received: sample[0] = {:?}", x, *sample)) } - Err(e) => panic!("{:?}", e), + Err(e) => Err(e), } } +} - } fn use_consumer(runtime: &R) { @@ -44,7 +53,7 @@ fn use_consumer(runtime: &R) .find(|desc| desc.get_instance_id() == 42) .unwrap(); let consumer = consumer_builder.build().unwrap(); - use_vehicle_interface(consumer); + VehicleMonitor::new(consumer).monitor_tire_data().unwrap(); } fn use_producer(runtime: &R) @@ -59,11 +68,21 @@ fn use_producer(runtime: &R) sample.send().unwrap(); } +fn run_with_runtime(name: &str, runtime: &R) { + println!("\n=== Running with {} runtime ===", name); + use_producer(runtime); + use_consumer(runtime); + println!("=== {} runtime completed ===\n", name); +} + fn main() { - let runtime_builder = RuntimeBuilderImpl::new(); - let runtime = Builder::::build(runtime_builder).unwrap(); - use_producer(&runtime); - use_consumer(&runtime); + let mock_runtime_builder = MockRuntimeBuilderImpl::new(); + let mock_runtime = Builder::::build(mock_runtime_builder).unwrap(); + run_with_runtime("Mock", &mock_runtime); + + let lola_runtime_builder = LolaRuntimeBuilderImpl::new(); + let lola_runtime = Builder::::build(lola_runtime_builder).unwrap(); + run_with_runtime("Lola", &lola_runtime); } #[cfg(test)] @@ -73,16 +92,23 @@ mod test { #[test] fn create_producer() { // Factory - let runtime_builder = RuntimeBuilderImpl::new(); - let runtime = Builder::::build(runtime_builder).unwrap(); + let mock_runtime_builder = MockRuntimeBuilderImpl::new(); + let runtime = Builder::::build(mock_runtime_builder).unwrap(); use_producer(&runtime); + let lola_runtime_builder = LolaRuntimeBuilderImpl::new(); + let runtime = Builder::::build(lola_runtime_builder).unwrap(); + use_producer(&runtime); } #[test] fn create_consumer() { - let runtime_builder = RuntimeBuilderImpl::new(); - let runtime = Builder::::build(runtime_builder).unwrap(); + let mock_runtime_builder = MockRuntimeBuilderImpl::new(); + let runtime = Builder::::build(mock_runtime_builder).unwrap(); + use_consumer(&runtime); + + let lola_runtime_builder = LolaRuntimeBuilderImpl::new(); + let runtime = Builder::::build(lola_runtime_builder).unwrap(); use_consumer(&runtime); } @@ -105,8 +131,8 @@ mod test { #[tokio::test(flavor = "multi_thread")] async fn schedule_subscription_on_mt_scheduler() { - let runtime_builder = RuntimeBuilderImpl::new(); - let runtime = runtime_builder.build().unwrap(); + let mock_runtime_builder = MockRuntimeBuilderImpl::new(); + let runtime = Builder::::build(mock_runtime_builder).unwrap(); let consumer_discovery = runtime.find_service::(InstanceSpecifier::new("My/Funk/ServiceName").unwrap()); let available_service_instances = consumer_discovery.get_available_instances().unwrap(); diff --git a/com-api/examples/com-api-gen/Cargo.toml b/com-api/examples/com-api-gen/Cargo.toml index b4aa992..e786d59 100644 --- a/com-api/examples/com-api-gen/Cargo.toml +++ b/com-api/examples/com-api-gen/Cargo.toml @@ -5,10 +5,5 @@ edition = "2024" publish = ["common"] license = "Apache-2.0" -[features] -mock = ["com-api-gen-mock"] -lola = ["com-api-gen-lola"] - [dependencies] -com-api-gen-mock = { path = "com-api-gen-mock", optional = true } -com-api-gen-lola = { path = "com-api-gen-lola", optional = true } +com-api = { workspace = true } diff --git a/com-api/examples/com-api-gen/com-api-gen-lola/Cargo.toml b/com-api/examples/com-api-gen/com-api-gen-lola/Cargo.toml deleted file mode 100644 index a1652e4..0000000 --- a/com-api/examples/com-api-gen/com-api-gen-lola/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "com-api-gen-lola" -version = "0.1.0" -edition = "2024" -publish = ["common"] -license = "Apache-2.0" - -[features] -lola = ["com-api/lola"] - -[dependencies] -com-api-runtime-lola = { workspace = true } -com-api = { workspace = true } diff --git a/com-api/examples/com-api-gen/com-api-gen-lola/src/lib.rs b/com-api/examples/com-api-gen/com-api-gen-lola/src/lib.rs deleted file mode 100644 index e2b894d..0000000 --- a/com-api/examples/com-api-gen/com-api-gen-lola/src/lib.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2025 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 -// -// -// SPDX-License-Identifier: Apache-2.0 - -//! This is the "generated" code for an interface that looks like this (pseudo-IDL): -//! -//! ```poor-persons-idl -//! interface Vehicle { -//! left_tire: Event, -//! exhaust: Event, -//! set_indicator_state: FnMut(indicator_status: IndicatorStatus) -> Result, -//! } -//! -//! interface Another {} -//! -//! ``` - -use com_api::{Consumer, Interface, OfferedProducer, Producer, Reloc, Runtime, Subscriber}; - -#[derive(Debug)] -pub struct Tire {} -unsafe impl Reloc for Tire {} - -pub struct Exhaust {} -unsafe impl Reloc for Exhaust {} - -pub struct VehicleInterface {} - -/// Generic -impl Interface for VehicleInterface { - type Consumer = VehicleConsumer; - type Producer = VehicleProducer; -} - -pub struct VehicleConsumer { - pub left_tire: R::Subscriber, - pub exhaust: R::Subscriber, -} - -impl Consumer for VehicleConsumer { - fn new(instance_info: R::ConsumerInfo) -> Self { - VehicleConsumer { - left_tire: R::Subscriber::new("left_tire", instance_info.clone()), - exhaust: R::Subscriber::new("exhaust", instance_info.clone()), - } - } -} - -pub struct AnotherInterface {} - -pub struct VehicleProducer -{ - _runtime: std::marker::PhantomData, -} - -impl Producer for VehicleProducer { - type Interface = VehicleInterface; - type OfferedProducer = VehicleOfferedProducer; - - fn offer(self) -> com_api::Result { - todo!() - } -} - -pub struct VehicleOfferedProducer { - pub left_tire: R::Publisher, - pub exhaust: R::Publisher, -} - -impl OfferedProducer for VehicleOfferedProducer { - type Interface = VehicleInterface; - type Producer = VehicleProducer; - - fn unoffer(self) -> Self::Producer { - VehicleProducer { - _runtime: std::marker::PhantomData, - } - } -} diff --git a/com-api/examples/com-api-gen/com-api-gen-mock/Cargo.toml b/com-api/examples/com-api-gen/com-api-gen-mock/Cargo.toml deleted file mode 100644 index 9a12571..0000000 --- a/com-api/examples/com-api-gen/com-api-gen-mock/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "com-api-gen-mock" -version = "0.1.0" -edition = "2024" -publish = ["common"] -license = "Apache-2.0" - -[features] -mock = ["com-api/mock"] - -[dependencies] -com-api-runtime-mock = { workspace = true } -com-api = { workspace = true } diff --git a/com-api/examples/com-api-gen/com-api-gen-mock/src/lib.rs b/com-api/examples/com-api-gen/com-api-gen-mock/src/lib.rs deleted file mode 100644 index c30b804..0000000 --- a/com-api/examples/com-api-gen/com-api-gen-mock/src/lib.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2025 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 -// -// -// SPDX-License-Identifier: Apache-2.0 - -//! This is the "generated" code for an interface that looks like this (pseudo-IDL): -//! -//! ```poor-persons-idl -//! interface Vehicle { -//! left_tire: Event, -//! exhaust: Event, -//! set_indicator_state: FnMut(indicator_status: IndicatorStatus) -> Result, -//! } -//! -//! interface Another {} -//! -//! ``` - -use com_api::*; - -#[derive(Debug)] -pub struct Tire {} -unsafe impl Reloc for Tire {} - -pub struct Exhaust {} -unsafe impl Reloc for Exhaust {} - -pub struct VehicleInterface {} - -/// Generic -impl Interface for VehicleInterface { - type Consumer = VehicleConsumer; - type Producer = VehicleProducer; -} - -pub struct VehicleConsumer { - pub left_tire: R::Subscriber, - pub exhaust: R::Subscriber, -} - -impl Consumer for VehicleConsumer { - fn new(instance_info: R::ConsumerInfo) -> Self { - VehicleConsumer { - left_tire: R::Subscriber::new("left_tire", instance_info.clone()), - exhaust: R::Subscriber::new("exhaust", instance_info.clone()), - } - } -} - -pub struct AnotherInterface {} - -pub struct VehicleProducer -{ - _runtime: std::marker::PhantomData, -} - -impl Producer for VehicleProducer { - type Interface = VehicleInterface; - type OfferedProducer = VehicleOfferedProducer; - - fn offer(self) -> com_api::Result { - todo!() - } -} - -pub struct VehicleOfferedProducer { - pub left_tire: R::Publisher, - pub exhaust: R::Publisher, -} - -impl OfferedProducer for VehicleOfferedProducer { - type Interface = VehicleInterface; - type Producer = VehicleProducer; - - fn unoffer(self) -> Self::Producer { - VehicleProducer { - _runtime: std::marker::PhantomData, - } - } -} diff --git a/com-api/examples/com-api-gen/src/lib.rs b/com-api/examples/com-api-gen/src/lib.rs index b5b5003..4f43ba2 100644 --- a/com-api/examples/com-api-gen/src/lib.rs +++ b/com-api/examples/com-api-gen/src/lib.rs @@ -9,7 +9,79 @@ // // SPDX-License-Identifier: Apache-2.0 -#[cfg(feature = "mock")] -pub use com_api_gen_mock::{Tire, VehicleInterface, VehicleConsumer, VehicleProducer, VehicleOfferedProducer}; -#[cfg(feature = "lola")] -pub use com_api_gen_lola::{Tire, VehicleInterface, VehicleConsumer, VehicleProducer, VehicleOfferedProducer}; +//! This is the "generated" code for an interface that looks like this (pseudo-IDL): +//! +//! ```poor-persons-idl +//! interface Vehicle { +//! left_tire: Event, +//! exhaust: Event, +//! set_indicator_state: FnMut(indicator_status: IndicatorStatus) -> Result, +//! } +//! +//! interface Another {} +//! +//! ``` + +use com_api::{Consumer, Interface, OfferedProducer, Producer, Reloc, Runtime, Subscriber}; + +#[derive(Debug)] +pub struct Tire {} +unsafe impl Reloc for Tire {} + +#[derive(Debug)] +pub struct Exhaust {} +unsafe impl Reloc for Exhaust {} + +pub struct VehicleInterface {} + +/// Generic +impl Interface for VehicleInterface { + type Consumer = VehicleConsumer; + type Producer = VehicleProducer; +} + +pub struct VehicleConsumer { + pub left_tire: R::Subscriber, + pub exhaust: R::Subscriber, +} + +impl Consumer for VehicleConsumer { + fn new(instance_info: R::ConsumerInfo) -> Self { + VehicleConsumer { + left_tire: R::Subscriber::new("left_tire", instance_info.clone()), + exhaust: R::Subscriber::new("exhaust", instance_info.clone()), + } + } +} + +pub struct AnotherInterface {} + +pub struct VehicleProducer +{ + _runtime: core::marker::PhantomData, +} + +impl Producer for VehicleProducer { + type Interface = VehicleInterface; + type OfferedProducer = VehicleOfferedProducer; + + fn offer(self) -> com_api::Result { + todo!() + } +} + +pub struct VehicleOfferedProducer { + pub left_tire: R::Publisher, + pub exhaust: R::Publisher, +} + +impl OfferedProducer for VehicleOfferedProducer { + type Interface = VehicleInterface; + type Producer = VehicleProducer; + + fn unoffer(self) -> Self::Producer { + VehicleProducer { + _runtime: std::marker::PhantomData, + } + } +} From 9f46793e5c05daeafa01d4635bb5db5bebe770a8 Mon Sep 17 00:00:00 2001 From: bharatgoswami Date: Wed, 19 Nov 2025 19:02:17 +0530 Subject: [PATCH 3/5] Rust::code Review comment fix * Added ProviderInfo instance in producer struct and API side * Added Example in detail * Subscriber API pass self as refrence * Added eraly fail check for consumer and producer * Added Reloc in seprate file and used as module * Added Type id with interface trait * Added AsMut trait bound with SampleMaybeUninit trait * Validation for Service name * InstanceSpecifier enum added with ANY and specific instance name * Find Service API take FindServiceSpecifier enum as argument * instance id removed and instead of that used instance specifier to identify the insatnce --- README.md | 8 +- com-api/Cargo.toml | 4 +- com-api/com-api-concept/Cargo.toml | 2 + com-api/com-api-concept/src/lib.rs | 84 +++++++++++---------- com-api/com-api-concept/src/reloc.rs | 41 ++++++++++ com-api/com-api-runtime-lola/Cargo.toml | 1 + com-api/com-api-runtime-lola/src/lib.rs | 71 ++++++++++------- com-api/com-api-runtime-mock/src/lib.rs | 66 ++++++++++------ com-api/com-api/src/lib.rs | 13 ++-- com-api/examples/basic-consumer-producer.rs | 62 ++++++++------- com-api/examples/com-api-gen/src/lib.rs | 38 +++++++--- 11 files changed, 251 insertions(+), 139 deletions(-) create mode 100644 com-api/com-api-concept/src/reloc.rs diff --git a/README.md b/README.md index f3671e1..6d3b57c 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,15 @@ Examples can be built from examples directory by passing desired IPC adapter as For build: ``` -inc_mw_com$ cargo build --example basic-consumer-producer +inc_mw_com/com-api$ cargo build --example basic-consumer-producer ``` -For mock test: +For test: ``` -inc_mw_com$ cargo test --test basic-consumer-producer-test +inc_mw_com/com-api$ cargo test --test basic-consumer-producer-test ``` -For mock Build and Run: +For Build and Run: ``` inc_mw_com/com-api$ cargo run --example basic-consumer-producer ``` diff --git a/com-api/Cargo.toml b/com-api/Cargo.toml index 91fc0b5..b6c9a3f 100644 --- a/com-api/Cargo.toml +++ b/com-api/Cargo.toml @@ -7,7 +7,7 @@ members = [ "com-api-runtime-lola", "examples", - "examples/com-api-gen" + "examples/com-api-gen", ] [workspace.package] @@ -25,4 +25,4 @@ com-api = { path = "com-api"} com-api-concept = { path = "com-api-concept"} com-api-runtime-mock = { path = "com-api-runtime-mock"} com-api-runtime-lola = { path = "com-api-runtime-lola"} -com-api-gen = { path = "examples/com-api-gen"} +com-api-gen = { path = "examples/com-api-gen"} \ No newline at end of file diff --git a/com-api/com-api-concept/Cargo.toml b/com-api/com-api-concept/Cargo.toml index 656c1b9..d81568d 100644 --- a/com-api/com-api-concept/Cargo.toml +++ b/com-api/com-api-concept/Cargo.toml @@ -4,3 +4,5 @@ version = "0.1.0" edition = "2024" publish = ["common"] license = "Apache-2.0" + +[dependencies] diff --git a/com-api/com-api-concept/src/lib.rs b/com-api/com-api-concept/src/lib.rs index dfb658b..950dacd 100644 --- a/com-api/com-api-concept/src/lib.rs +++ b/com-api/com-api-concept/src/lib.rs @@ -47,8 +47,10 @@ use core::fmt::Debug; use core::future::Future; use core::ops::{Deref, DerefMut}; -use std::path::Path; +pub mod reloc; +pub use reloc::Reloc; use std::collections::VecDeque; +use std::path::Path; #[derive(Debug)] pub enum Error { @@ -77,13 +79,13 @@ pub trait Runtime { type ServiceDiscovery: ServiceDiscovery; type Subscriber: Subscriber; type ProducerBuilder>: ProducerBuilder; - type Publisher: Publisher; + type Publisher: Publisher; type ProviderInfo: Send + Clone; type ConsumerInfo: Send + Clone; fn find_service( &self, - _instance_specifier: InstanceSpecifier, + _instance_specifier: FindServiceSpecifier, ) -> Self::ServiceDiscovery; fn producer_builder>( @@ -110,16 +112,14 @@ pub struct InstanceSpecifier { } impl InstanceSpecifier { - /// Instance specifier that will match any instance. This can be used to find all - /// instances of a certain interface during service discovery. - pub const MATCH_ANY: Self = InstanceSpecifier { specifier: None }; - - fn check_str(_service_name: &str) -> bool { - - // need to validated service name convention according to backend specification - //for that either call into backend specific code or implement generic checks here - - todo!() + fn check_str(service_name: &str) -> bool { + // validation for service name- my/path/to/servicename + // allowed characters: a-z A-Z 0-9 and '/' + // no leading, trailing or consecutive '/' + !service_name.is_empty() + && service_name.split('/').all(|parts| { + !parts.is_empty() && parts.bytes().all(|part| part.is_ascii_alphanumeric()) + }) } /// Create a new instance specifier, using the string-like input as the path to the @@ -154,6 +154,11 @@ impl AsRef for InstanceSpecifier { .unwrap_or("[ANY]") } } +/// Specifies whether to find a specific service instance or any available instance +pub enum FindServiceSpecifier { + Specific(InstanceSpecifier), + Any, +} /// This trait shall ensure that we can safely use an instance of the implementing type across /// address boundaries. This property may be violated by the following circumstances: @@ -169,17 +174,9 @@ impl AsRef for InstanceSpecifier { /// /// Since it is yet to be proven whether this trait can be implemented safely (assumption is: no) it /// is unsafe for now. The expectation is that very few users ever need to implement this manually. -pub unsafe trait Reloc {} - -unsafe impl Reloc for () {} -unsafe impl Reloc for u32 {} -unsafe impl Reloc for u64 {} -unsafe impl Reloc for i32 {} -unsafe impl Reloc for i64 {} -unsafe impl Reloc for f32 {} -unsafe impl Reloc for f64 {} -unsafe impl Reloc for bool {} -unsafe impl Reloc for char {} + +// Reloc trait and its implementations have been moved to reloc.rs +// Use `use reloc::Reloc;` to import it here and in other files. /// A `Sample` provides a reference to a memory buffer of an event with immutable value. /// @@ -193,7 +190,6 @@ where T: Send + Reloc + Debug, { } - /// A `SampleMut` provides a reference to a memory buffer of an event with mutable value. /// /// By implementing the `DerefMut` trait implementations of the trait support the `.` operator for dereferencing. @@ -219,7 +215,7 @@ where /// /// TODO: Shall we also require DerefMut> from implementing types? How to deal /// TODO: with the ambiguous assume_init() then? -pub trait SampleMaybeUninit : Debug +pub trait SampleMaybeUninit: Debug + AsMut> where T: Send + Reloc + Debug, { @@ -239,15 +235,10 @@ where /// /// This corresponds to `MaybeUninit::write`. fn write(self, value: T) -> Self::SampleMut; - - /// Get a mutable pointer to the internal maybe uninitialized `T`. - /// - /// The caller has to make sure to initialize the data in the buffer. - /// Reading from the received pointer before initialization is undefined behavior. - fn as_mut_ptr(&mut self) -> *mut T; } pub trait Interface { + const TYPE_ID: &'static str; // the id will be used at backend type Consumer: Consumer; type Producer: Producer; } @@ -263,11 +254,13 @@ pub trait OfferedProducer { pub trait Producer { type Interface: Interface; type OfferedProducer: OfferedProducer; - + fn new(instance_info: R::ProviderInfo) -> Result + where + Self: Sized; fn offer(self) -> Result; } -pub trait Publisher +pub trait Publisher where T: Reloc + Send + Debug, { @@ -277,6 +270,10 @@ where fn allocate<'a>(&'a self) -> Result>; + fn new(identifier: &str, instance_info: R::ProviderInfo) -> Result + where + Self: Sized; + fn send(&self, value: T) -> Result<()> { let sample = self.allocate()?; let init_sample = sample.write(value); @@ -285,7 +282,9 @@ where } pub trait Consumer { - fn new(instance_info: R::ConsumerInfo) -> Self; + fn new(instance_info: R::ConsumerInfo) -> Result + where + Self: Sized; } pub trait ProducerBuilder, R: Runtime + ?Sized>: @@ -300,12 +299,13 @@ pub trait ServiceDiscovery { fn get_available_instances(&self) -> Result; #[allow(clippy::manual_async_fn)] - fn get_available_instances_async(&self) -> impl Future> + Send; - + fn get_available_instances_async( + &self, + ) -> impl Future> + Send; } pub trait ConsumerDescriptor { - fn get_instance_id(&self) -> usize; // TODO: Turn return type into separate type + fn get_instance_identifier(&self) -> String; } pub trait ConsumerBuilder: @@ -313,10 +313,12 @@ pub trait ConsumerBuilder: { } -pub trait Subscriber { +pub trait Subscriber { type Subscription: Subscription; - fn new(identifier: &str, instance_info: R::ConsumerInfo) -> Self; - fn subscribe(self, max_num_samples: usize) -> Result; + fn new(identifier: &str, instance_info: R::ConsumerInfo) -> Result + where + Self: Sized; + fn subscribe(&self, max_num_samples: usize) -> Result; } pub struct SampleContainer { diff --git a/com-api/com-api-concept/src/reloc.rs b/com-api/com-api-concept/src/reloc.rs new file mode 100644 index 0000000..1efcfb6 --- /dev/null +++ b/com-api/com-api-concept/src/reloc.rs @@ -0,0 +1,41 @@ +// Copyright (c) 2025 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 +// +// +// SPDX-License-Identifier: Apache-2.0 + +//! Reloc trait and implementations + +pub unsafe trait Reloc {} + +unsafe impl Reloc for () {} +unsafe impl Reloc for u32 {} +unsafe impl Reloc for u64 {} +unsafe impl Reloc for i32 {} +unsafe impl Reloc for i64 {} +unsafe impl Reloc for f32 {} +unsafe impl Reloc for f64 {} +unsafe impl Reloc for bool {} +unsafe impl Reloc for char {} +unsafe impl Reloc for usize {} +unsafe impl Reloc for u128 {} +unsafe impl Reloc for i128 {} +unsafe impl Reloc for isize {} + +// Arrays +unsafe impl Reloc for [T; N] {} + +// MaybeUninit +unsafe impl Reloc for core::mem::MaybeUninit {} + +// Tuples (up to 5 elements) +unsafe impl Reloc for (T1,) {} +unsafe impl Reloc for (T1, T2) {} +unsafe impl Reloc for (T1, T2, T3) {} +unsafe impl Reloc for (T1, T2, T3, T4) {} +unsafe impl Reloc for (T1, T2, T3, T4, T5) {} diff --git a/com-api/com-api-runtime-lola/Cargo.toml b/com-api/com-api-runtime-lola/Cargo.toml index e0208a6..06fb69a 100644 --- a/com-api/com-api-runtime-lola/Cargo.toml +++ b/com-api/com-api-runtime-lola/Cargo.toml @@ -8,5 +8,6 @@ license = "Apache-2.0" [dependencies] com-api-concept = { workspace = true } + [dev-dependencies] futures = "0.3" diff --git a/com-api/com-api-runtime-lola/src/lib.rs b/com-api/com-api-runtime-lola/src/lib.rs index 29e7a17..14b4819 100644 --- a/com-api/com-api-runtime-lola/src/lib.rs +++ b/com-api/com-api-runtime-lola/src/lib.rs @@ -14,19 +14,20 @@ #![allow(dead_code)] -use std::path::Path; -use std::collections::VecDeque; +use core::cmp::Ordering; +use core::fmt::Debug; use core::future::Future; use core::marker::PhantomData; use core::mem::MaybeUninit; use core::ops::{Deref, DerefMut}; use core::sync::atomic::AtomicUsize; -use core::cmp::Ordering; -use core::fmt::Debug; +use std::collections::VecDeque; +use std::path::Path; use com_api_concept::{ - Builder, Consumer,ConsumerBuilder, ConsumerDescriptor, InstanceSpecifier, Interface, Reloc, Runtime, - SampleContainer, ServiceDiscovery, Subscriber, Subscription, Producer, ProducerBuilder, Result, + Builder, Consumer, ConsumerBuilder, ConsumerDescriptor, FindServiceSpecifier, + InstanceSpecifier, Interface, Producer, ProducerBuilder, Reloc, Result, Runtime, + SampleContainer, ServiceDiscovery, Subscriber, Subscription, }; pub struct LolaRuntimeImpl {} @@ -48,13 +49,12 @@ impl Runtime for LolaRuntimeImpl { type Subscriber = SubscribableImpl; type ProducerBuilder> = SampleProducerBuilder; type Publisher = Publisher; - // TODO: Integrate with Producer::offer() method implementation type ProviderInfo = LolaProviderInfo; type ConsumerInfo = LolaConsumerInfo; fn find_service( &self, - _instance_specifier: InstanceSpecifier, + _instance_specifier: FindServiceSpecifier, ) -> Self::ServiceDiscovery { SampleConsumerDiscovery { _interface: PhantomData, @@ -97,7 +97,7 @@ where #[derive(Debug)] pub struct Sample<'a, T> where - T: Reloc + Send , + T: Reloc + Send, { id: usize, inner: SampleBinding<'a, T>, @@ -162,7 +162,6 @@ where } } - #[derive(Debug)] pub struct SampleMut<'a, T> where @@ -229,17 +228,21 @@ where } } - fn as_mut_ptr(&mut self) -> *mut T { - self.data.as_mut_ptr() - } - unsafe fn assume_init(self) -> SampleMut<'a, T> { SampleMut { data: unsafe { self.data.assume_init() }, lifetime: PhantomData, } } +} +impl<'a, T> AsMut> for SampleMaybeUninit<'a, T> +where + T: Reloc + Send + Debug, +{ + fn as_mut(&mut self) -> &mut core::mem::MaybeUninit { + &mut self.data + } } pub struct SubscribableImpl { @@ -258,16 +261,16 @@ impl Default for SubscribableImpl { } } -impl Subscriber for SubscribableImpl { +impl Subscriber for SubscribableImpl { type Subscription = SubscriberImpl; - fn new(identifier: &str, instance_info: LolaConsumerInfo) -> Self { - Self { + fn new(identifier: &str, instance_info: LolaConsumerInfo) -> com_api_concept::Result { + Ok(Self { identifier: identifier.to_string(), instance_info: Some(instance_info), data: PhantomData, - } + }) } - fn subscribe(self, _max_num_samples: usize) -> com_api_concept::Result { + fn subscribe(&self, _max_num_samples: usize) -> com_api_concept::Result { Ok(SubscriberImpl::new()) } } @@ -350,11 +353,18 @@ where } } -impl com_api_concept::Publisher for Publisher +impl com_api_concept::Publisher for Publisher where T: Reloc + Send + Debug, { - type SampleMaybeUninit<'a> = SampleMaybeUninit<'a, T> where Self: 'a; + type SampleMaybeUninit<'a> + = SampleMaybeUninit<'a, T> + where + Self: 'a; + + fn new(_identifier: &str, _instance_info: LolaProviderInfo) -> com_api_concept::Result { + Ok(Self { _data: PhantomData }) + } fn allocate<'a>(&'a self) -> com_api_concept::Result> { Ok(SampleMaybeUninit { @@ -388,10 +398,11 @@ where } #[allow(clippy::manual_async_fn)] - fn get_available_instances_async(&self) -> impl Future> { + fn get_available_instances_async( + &self, + ) -> impl Future> + Send { async { Ok(Vec::new()) } } - } impl ConsumerBuilder for SampleConsumerBuilder {} @@ -401,7 +412,7 @@ impl Builder> for SampleConsumerBuild let instance_info = LolaConsumerInfo { instance_specifier: self.instance_specifier.clone(), }; - Ok(Consumer::new(instance_info)) + Ok(Consumer::new(instance_info)?) } } @@ -419,15 +430,19 @@ impl SampleProducerBuilder { } } -impl> ProducerBuilder for SampleProducerBuilder {} +impl> + ProducerBuilder for SampleProducerBuilder +{ +} -impl> Builder

for SampleProducerBuilder { +impl> Builder

+ for SampleProducerBuilder +{ fn build(self) -> Result

{ todo!() } } - pub struct SampleConsumerDescriptor { _interface: PhantomData, } @@ -446,7 +461,7 @@ pub struct SampleConsumerBuilder { } impl ConsumerDescriptor for SampleConsumerBuilder { - fn get_instance_id(&self) -> usize { + fn get_instance_identifier(&self) -> String { todo!() } } diff --git a/com-api/com-api-runtime-mock/src/lib.rs b/com-api/com-api-runtime-mock/src/lib.rs index b21aeb2..455179c 100644 --- a/com-api/com-api-runtime-mock/src/lib.rs +++ b/com-api/com-api-runtime-mock/src/lib.rs @@ -16,19 +16,21 @@ #![allow(dead_code)] -use std::path::Path; -use std::collections::VecDeque; +use com_api_concept::Reloc; +use core::cmp::Ordering; +use core::fmt::Debug; use core::future::Future; use core::marker::PhantomData; use core::mem::MaybeUninit; use core::ops::{Deref, DerefMut}; use core::sync::atomic::AtomicUsize; -use core::cmp::Ordering; -use core::fmt::Debug; +use std::collections::VecDeque; +use std::path::Path; use com_api_concept::{ - Builder, Consumer, ConsumerBuilder, ConsumerDescriptor, InstanceSpecifier, Interface, Reloc, Runtime, - SampleContainer, ServiceDiscovery, Subscriber, Subscription, Producer, ProducerBuilder, Result, + Builder, Consumer, ConsumerBuilder, ConsumerDescriptor, FindServiceSpecifier, + InstanceSpecifier, Interface, Producer, ProducerBuilder, Result, Runtime, SampleContainer, + ServiceDiscovery, Subscriber, Subscription, }; pub struct MockRuntimeImpl {} @@ -50,13 +52,12 @@ impl Runtime for MockRuntimeImpl { type Subscriber = SubscribableImpl; type ProducerBuilder> = SampleProducerBuilder; type Publisher = Publisher; - // TODO: Integrate with Producer::offer() method implementation type ProviderInfo = MockProviderInfo; type ConsumerInfo = MockConsumerInfo; fn find_service( &self, - _instance_specifier: InstanceSpecifier, + _instance_specifier: FindServiceSpecifier, ) -> Self::ServiceDiscovery { SampleConsumerDiscovery { _interface: PhantomData, @@ -230,10 +231,6 @@ where } } - fn as_mut_ptr(&mut self) -> *mut T { - self.data.as_mut_ptr() - } - unsafe fn assume_init(self) -> SampleMut<'a, T> { SampleMut { data: unsafe { self.data.assume_init() }, @@ -242,6 +239,15 @@ where } } +impl<'a, T> AsMut> for SampleMaybeUninit<'a, T> +where + T: Reloc + Send + Debug, +{ + fn as_mut(&mut self) -> &mut core::mem::MaybeUninit { + &mut self.data + } +} + pub struct SubscribableImpl { identifier: String, instance_info: Option, @@ -260,14 +266,14 @@ impl Default for SubscribableImpl { impl Subscriber for SubscribableImpl { type Subscription = SubscriberImpl; - fn new(identifier: &str, instance_info: MockConsumerInfo) -> Self { - Self { + fn new(identifier: &str, instance_info: MockConsumerInfo) -> com_api_concept::Result { + Ok(Self { identifier: identifier.to_string(), instance_info: Some(instance_info), data: PhantomData, - } + }) } - fn subscribe(self, _max_num_samples: usize) -> com_api_concept::Result { + fn subscribe(&self, _max_num_samples: usize) -> com_api_concept::Result { Ok(SubscriberImpl::new()) } } @@ -350,11 +356,18 @@ where } } -impl com_api_concept::Publisher for Publisher +impl com_api_concept::Publisher for Publisher where T: Reloc + Send + Debug, { - type SampleMaybeUninit<'a> = SampleMaybeUninit<'a, T> where Self: 'a; + type SampleMaybeUninit<'a> + = SampleMaybeUninit<'a, T> + where + Self: 'a; + + fn new(_identifier: &str, _instance_info: MockProviderInfo) -> com_api_concept::Result { + Ok(Self { _data: PhantomData }) + } fn allocate<'a>(&'a self) -> com_api_concept::Result> { Ok(SampleMaybeUninit { @@ -388,7 +401,9 @@ where } #[allow(clippy::manual_async_fn)] - fn get_available_instances_async(&self) -> impl Future> { + fn get_available_instances_async( + &self, + ) -> impl Future> { async { Ok(Vec::new()) } } } @@ -407,9 +422,14 @@ impl SampleProducerBuilder { } } -impl> ProducerBuilder for SampleProducerBuilder {} +impl> + ProducerBuilder for SampleProducerBuilder +{ +} -impl> Builder

for SampleProducerBuilder { +impl> Builder

+ for SampleProducerBuilder +{ fn build(self) -> Result

{ todo!() } @@ -433,7 +453,7 @@ pub struct SampleConsumerBuilder { } impl ConsumerDescriptor for SampleConsumerBuilder { - fn get_instance_id(&self) -> usize { + fn get_instance_identifier(&self) -> String { todo!() } } @@ -446,7 +466,7 @@ impl Builder> for SampleConsumerBuild instance_specifier: self.instance_specifier.clone(), }; - Ok(Consumer::new(instance_info)) + Ok(Consumer::new(instance_info)?) } } diff --git a/com-api/com-api/src/lib.rs b/com-api/com-api/src/lib.rs index b541f17..30bfa6f 100644 --- a/com-api/com-api/src/lib.rs +++ b/com-api/com-api/src/lib.rs @@ -13,13 +13,14 @@ //! of the COM API, e.g., for different IPC backends. //! The actual implementations are provided by the `com-api-runtime-mock` and `com-api-runtime-lola` crates. -pub use com_api_runtime_mock::RuntimeBuilderImpl as MockRuntimeBuilderImpl; -pub use com_api_runtime_mock::MockRuntimeImpl; -pub use com_api_runtime_lola::RuntimeBuilderImpl as LolaRuntimeBuilderImpl; pub use com_api_runtime_lola::LolaRuntimeImpl; +pub use com_api_runtime_lola::RuntimeBuilderImpl as LolaRuntimeBuilderImpl; +pub use com_api_runtime_mock::MockRuntimeImpl; +pub use com_api_runtime_mock::RuntimeBuilderImpl as MockRuntimeBuilderImpl; pub use com_api_concept::{ - Builder, Consumer, ConsumerBuilder, ConsumerDescriptor, Error, InstanceSpecifier, Interface, - OfferedProducer, Producer, ProducerBuilder, Publisher, Reloc, Runtime, Result, SampleContainer, SampleMaybeUninit, - SampleMut, ServiceDiscovery, Subscriber, Subscription, + Builder, Consumer, ConsumerBuilder, ConsumerDescriptor, Error, FindServiceSpecifier, + InstanceSpecifier, Interface, OfferedProducer, Producer, ProducerBuilder, Publisher, Reloc, + Result, Runtime, SampleContainer, SampleMaybeUninit, SampleMut, ServiceDiscovery, Subscriber, + Subscription, }; diff --git a/com-api/examples/basic-consumer-producer.rs b/com-api/examples/basic-consumer-producer.rs index 70b097b..74103ed 100644 --- a/com-api/examples/basic-consumer-producer.rs +++ b/com-api/examples/basic-consumer-producer.rs @@ -12,23 +12,23 @@ use com_api::*; use com_api_gen::*; - // Example struct demonstrating composition with VehicleConsumer pub struct VehicleMonitor { consumer: VehicleConsumer, + producer: VehicleOfferedProducer, } impl VehicleMonitor { /// Create a new VehicleMonitor with a consumer - pub fn new(consumer: VehicleConsumer) -> Self { - Self { consumer } + pub fn new(consumer: VehicleConsumer, producer: VehicleOfferedProducer) -> Self { + Self { consumer, producer } } /// Monitor tire data from the consumer - pub fn monitor_tire_data(self) -> Result { + pub fn read_tire_data(&self) -> Result { let subscribed = self.consumer.left_tire.subscribe(3)?; let mut sample_buf = SampleContainer::new(); - + match subscribed.try_receive(&mut sample_buf, 1) { Ok(0) => Err(Error::Fail), Ok(x) => { @@ -38,40 +38,49 @@ impl VehicleMonitor { Err(e) => Err(e), } } -} + pub fn write_tire_data(&self, tire: Tire) -> Result<()> { + let uninit_sample = self.producer.left_tire.allocate()?; + let sample = uninit_sample.write(tire); + sample.send()?; + Ok(()) + } +} -fn use_consumer(runtime: &R) -{ - // Create service discovery - let consumer_discovery = runtime.find_service::(InstanceSpecifier::new("My/Funk/ServiceName").unwrap()); +fn use_consumer(runtime: &R) -> VehicleConsumer { + // Find all the avaiable service instances using ANY specifier + let consumer_discovery = runtime.find_service::(FindServiceSpecifier::Any); let available_service_instances = consumer_discovery.get_available_instances().unwrap(); - // Create consumer from first discovered service let consumer_builder = available_service_instances .into_iter() - .find(|desc| desc.get_instance_id() == 42) + .find(|desc| desc.get_instance_identifier() == "My/Funk/ServiceName") .unwrap(); + let consumer = consumer_builder.build().unwrap(); - VehicleMonitor::new(consumer).monitor_tire_data().unwrap(); + // + consumer } -fn use_producer(runtime: &R) -{ - let producer_builder = runtime.producer_builder::>(InstanceSpecifier::new("My/Funk/ServiceName").unwrap()); +fn use_producer(runtime: &R) -> VehicleOfferedProducer { + let producer_builder = runtime.producer_builder::>( + InstanceSpecifier::new("My/Funk/ServiceName").unwrap(), + ); let producer = producer_builder.build().unwrap(); let offered_producer = producer.offer().unwrap(); - - // Business logic - let uninit_sample = offered_producer.left_tire.allocate().unwrap(); - let sample = uninit_sample.write(Tire {}); - sample.send().unwrap(); + offered_producer } fn run_with_runtime(name: &str, runtime: &R) { println!("\n=== Running with {} runtime ===", name); - use_producer(runtime); - use_consumer(runtime); + + let monitor = VehicleMonitor::new(use_consumer(runtime), use_producer(runtime)); + + for _ in 0..5 { + monitor.write_tire_data(Tire {}).unwrap(); + let tire_data = monitor.read_tire_data().unwrap(); + println!("{}", tire_data); + } println!("=== {} runtime completed ===\n", name); } @@ -112,7 +121,7 @@ mod test { use_consumer(&runtime); } - async fn async_data_processor_fn(subscribed: impl Subscription) { + async fn async_data_processor_fn(subscribed: impl Subscription) { let mut buffer = SampleContainer::new(); for _ in 0..10 { match subscribed.receive(&mut buffer, 1, 1).await { @@ -134,13 +143,14 @@ mod test { let mock_runtime_builder = MockRuntimeBuilderImpl::new(); let runtime = Builder::::build(mock_runtime_builder).unwrap(); - let consumer_discovery = runtime.find_service::(InstanceSpecifier::new("My/Funk/ServiceName").unwrap()); + let consumer_discovery = + runtime.find_service::(FindServiceSpecifier::Any); let available_service_instances = consumer_discovery.get_available_instances().unwrap(); // Create consumer from first discovered service let consumer_builder = available_service_instances .into_iter() - .find(|desc| desc.get_instance_id() == 42) + .find(|desc| desc.get_instance_identifier() == "My/Funk/ServiceName") .unwrap(); let consumer = consumer_builder.build().unwrap(); diff --git a/com-api/examples/com-api-gen/src/lib.rs b/com-api/examples/com-api-gen/src/lib.rs index 4f43ba2..bbd520c 100644 --- a/com-api/examples/com-api-gen/src/lib.rs +++ b/com-api/examples/com-api-gen/src/lib.rs @@ -22,7 +22,9 @@ //! //! ``` -use com_api::{Consumer, Interface, OfferedProducer, Producer, Reloc, Runtime, Subscriber}; +use com_api::{ + Consumer, Interface, OfferedProducer, Producer, Publisher, Reloc, Runtime, Subscriber, +}; #[derive(Debug)] pub struct Tire {} @@ -36,6 +38,7 @@ pub struct VehicleInterface {} /// Generic impl Interface for VehicleInterface { + const TYPE_ID: &'static str = "VehicleInterface"; type Consumer = VehicleConsumer; type Producer = VehicleProducer; } @@ -46,19 +49,21 @@ pub struct VehicleConsumer { } impl Consumer for VehicleConsumer { - fn new(instance_info: R::ConsumerInfo) -> Self { - VehicleConsumer { - left_tire: R::Subscriber::new("left_tire", instance_info.clone()), - exhaust: R::Subscriber::new("exhaust", instance_info.clone()), - } + fn new(instance_info: R::ConsumerInfo) -> com_api::Result { + Ok(VehicleConsumer { + left_tire: R::Subscriber::new("left_tire", instance_info.clone()) + .expect("Failed to create subscriber for left_tire"), + exhaust: R::Subscriber::new("exhaust", instance_info.clone()) + .expect("Failed to create subscriber for exhaust"), + }) } } pub struct AnotherInterface {} -pub struct VehicleProducer -{ +pub struct VehicleProducer { _runtime: core::marker::PhantomData, + instance_info: R::ProviderInfo, } impl Producer for VehicleProducer { @@ -66,13 +71,27 @@ impl Producer for VehicleProducer { type OfferedProducer = VehicleOfferedProducer; fn offer(self) -> com_api::Result { - todo!() + Ok(VehicleOfferedProducer { + left_tire: R::Publisher::new("left_tire", self.instance_info.clone()) + .expect("Failed to create Publisher for left_tire"), + exhaust: R::Publisher::new("exhaust", self.instance_info.clone()) + .expect("Failed to create Publisher for exhaust"), + instance_info: self.instance_info, + }) + } + + fn new(instance_info: R::ProviderInfo) -> com_api::Result { + Ok(VehicleProducer { + _runtime: core::marker::PhantomData, + instance_info, + }) } } pub struct VehicleOfferedProducer { pub left_tire: R::Publisher, pub exhaust: R::Publisher, + instance_info: R::ProviderInfo, } impl OfferedProducer for VehicleOfferedProducer { @@ -82,6 +101,7 @@ impl OfferedProducer for VehicleOfferedProducer { fn unoffer(self) -> Self::Producer { VehicleProducer { _runtime: std::marker::PhantomData, + instance_info: self.instance_info, } } } From cc3cc73de5746a8c75f1701b057a41b48a72e63c Mon Sep 17 00:00:00 2001 From: bharatgoswami Date: Thu, 27 Nov 2025 13:14:03 +0530 Subject: [PATCH 4/5] Rust::com Review comment fix * Added Reloc u8,u16 and i8 ,i16 * Removed comment --- com-api/com-api-concept/Cargo.toml | 1 - com-api/com-api-concept/src/lib.rs | 3 --- com-api/com-api-concept/src/reloc.rs | 4 ++++ com-api/com-api-runtime-lola/Cargo.toml | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/com-api/com-api-concept/Cargo.toml b/com-api/com-api-concept/Cargo.toml index d81568d..864ef31 100644 --- a/com-api/com-api-concept/Cargo.toml +++ b/com-api/com-api-concept/Cargo.toml @@ -5,4 +5,3 @@ edition = "2024" publish = ["common"] license = "Apache-2.0" -[dependencies] diff --git a/com-api/com-api-concept/src/lib.rs b/com-api/com-api-concept/src/lib.rs index 950dacd..d755670 100644 --- a/com-api/com-api-concept/src/lib.rs +++ b/com-api/com-api-concept/src/lib.rs @@ -175,9 +175,6 @@ pub enum FindServiceSpecifier { /// Since it is yet to be proven whether this trait can be implemented safely (assumption is: no) it /// is unsafe for now. The expectation is that very few users ever need to implement this manually. -// Reloc trait and its implementations have been moved to reloc.rs -// Use `use reloc::Reloc;` to import it here and in other files. - /// A `Sample` provides a reference to a memory buffer of an event with immutable value. /// /// By implementing the `Deref` trait implementations of the trait support the `.` operator for dereferencing. diff --git a/com-api/com-api-concept/src/reloc.rs b/com-api/com-api-concept/src/reloc.rs index 1efcfb6..033a5a0 100644 --- a/com-api/com-api-concept/src/reloc.rs +++ b/com-api/com-api-concept/src/reloc.rs @@ -14,8 +14,12 @@ pub unsafe trait Reloc {} unsafe impl Reloc for () {} +unsafe impl Reloc for u8 {} +unsafe impl Reloc for u16 {} unsafe impl Reloc for u32 {} unsafe impl Reloc for u64 {} +unsafe impl Reloc for i8 {} +unsafe impl Reloc for i16 {} unsafe impl Reloc for i32 {} unsafe impl Reloc for i64 {} unsafe impl Reloc for f32 {} diff --git a/com-api/com-api-runtime-lola/Cargo.toml b/com-api/com-api-runtime-lola/Cargo.toml index 06fb69a..e0208a6 100644 --- a/com-api/com-api-runtime-lola/Cargo.toml +++ b/com-api/com-api-runtime-lola/Cargo.toml @@ -8,6 +8,5 @@ license = "Apache-2.0" [dependencies] com-api-concept = { workspace = true } - [dev-dependencies] futures = "0.3" From 4dd0b65f3032682c3d11c07c8293804576a989ef Mon Sep 17 00:00:00 2001 From: bharatgoswami Date: Fri, 28 Nov 2025 16:31:31 +0530 Subject: [PATCH 5/5] Rust::com review comment fix * Updated check_str validation logic * Updated example file * Removed unused new method * Added Into Trait impl for InstanceSpecifier --- com-api/com-api-concept/src/lib.rs | 92 ++++++++++++++++++--- com-api/com-api-runtime-lola/src/lib.rs | 27 ++---- com-api/com-api-runtime-mock/src/lib.rs | 32 ++----- com-api/examples/basic-consumer-producer.rs | 24 ++++-- 4 files changed, 110 insertions(+), 65 deletions(-) diff --git a/com-api/com-api-concept/src/lib.rs b/com-api/com-api-concept/src/lib.rs index d755670..b24b3b6 100644 --- a/com-api/com-api-concept/src/lib.rs +++ b/com-api/com-api-concept/src/lib.rs @@ -85,7 +85,7 @@ pub trait Runtime { fn find_service( &self, - _instance_specifier: FindServiceSpecifier, + instance_specifier: FindServiceSpecifier, ) -> Self::ServiceDiscovery; fn producer_builder>( @@ -105,20 +105,37 @@ where /// /// The string shall describe where to find a certain instance of a service. Each level shall look /// like this -/// :my/path/to/service_name +/// /my/path/to/service_name +/// validation for service name- /my/path/to/service_name +/// allowed characters: a-z A-Z 0-9 and '/' +/// Must start with leading/trailing check +/// Not allowed consecutive '/' characters +/// '_' is allowed in names #[derive(Clone, Debug)] pub struct InstanceSpecifier { - specifier: Option, + specifier: String, } impl InstanceSpecifier { fn check_str(service_name: &str) -> bool { - // validation for service name- my/path/to/servicename - // allowed characters: a-z A-Z 0-9 and '/' - // no leading, trailing or consecutive '/' + // Must start with exactly one leading slash + if !service_name.starts_with('/') || service_name.starts_with("//") { + return false; + } + + // Remove the single leading slash + let service_name = service_name.strip_prefix('/').unwrap(); + + // Check each character + let is_legal_char = |c| { + (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' + }; + + //validation of each path segment !service_name.is_empty() && service_name.split('/').all(|parts| { - !parts.is_empty() && parts.bytes().all(|part| part.is_ascii_alphanumeric()) + // No empty segments (reject trailing "/" and "//" in the middle) + !parts.is_empty() && parts.chars().all(|c| is_legal_char(c)) }) } @@ -131,7 +148,7 @@ impl InstanceSpecifier { let service_name = service_name.as_ref(); if Self::check_str(service_name) { Ok(Self { - specifier: Some(service_name.to_string()), + specifier: service_name.to_string(), }) } else { Err(Error::Fail) @@ -148,10 +165,7 @@ impl TryFrom<&str> for InstanceSpecifier { impl AsRef for InstanceSpecifier { fn as_ref(&self) -> &str { - self.specifier - .as_ref() - .map(String::as_str) - .unwrap_or("[ANY]") + &self.specifier } } /// Specifies whether to find a specific service instance or any available instance @@ -160,6 +174,13 @@ pub enum FindServiceSpecifier { Any, } +/// Convert an InstanceSpecifier into a FindServiceSpecifier +impl Into for InstanceSpecifier { + fn into(self) -> FindServiceSpecifier { + FindServiceSpecifier::Specific(self) + } +} + /// This trait shall ensure that we can safely use an instance of the implementing type across /// address boundaries. This property may be violated by the following circumstances: /// - usage of pointers to other members of the struct itself (akin to !Unpin structs) @@ -302,7 +323,7 @@ pub trait ServiceDiscovery { } pub trait ConsumerDescriptor { - fn get_instance_identifier(&self) -> String; + fn get_instance_identifier(&self) -> &InstanceSpecifier; } pub trait ConsumerBuilder: @@ -419,3 +440,48 @@ pub trait Subscription { max_samples: usize, ) -> impl Future> + Send; } + +mod tests { + #[test] + fn test_instance_specifier_validation() { + use super::InstanceSpecifier; + // Valid specifiers + let valid_specifiers = [ + "/my/service", + "/my/path/to/service_name", + "/Service_123/AnotherPart", + "/A", + "/A/abc_123/Xyz", + ]; + + for spec in &valid_specifiers { + assert!( + InstanceSpecifier::check_str(spec), + "Expected '{}' to be valid", + spec + ); + } + + // Invalid specifiers + let invalid_specifiers = [ + "my/service", // No leading slash + "/my//service", // Consecutive slashes + "/my/service/", // Trailing slash + "/my/ser!vice", // Illegal character '!' + "/my/ser vice", // Illegal character ' ' + "/", // Only root slash + "/my/path//to/service", // Consecutive slashes in the middle + "/my/path/to//", // Trailing consecutive slashes + "//my/service", // Leading consecutive slashes + "///my/service", // Leading consecutive slashes + ]; + + for spec in &invalid_specifiers { + assert!( + !InstanceSpecifier::check_str(spec), + "Expected '{}' to be invalid", + spec + ); + } + } +} diff --git a/com-api/com-api-runtime-lola/src/lib.rs b/com-api/com-api-runtime-lola/src/lib.rs index 14b4819..54dbc6e 100644 --- a/com-api/com-api-runtime-lola/src/lib.rs +++ b/com-api/com-api-runtime-lola/src/lib.rs @@ -335,24 +335,6 @@ pub struct Publisher { _data: PhantomData, } -impl Default for Publisher -where - T: Reloc + Send, -{ - fn default() -> Self { - Self::new() - } -} - -impl Publisher -where - T: Reloc + Send, -{ - pub fn new() -> Self { - Self { _data: PhantomData } - } -} - impl com_api_concept::Publisher for Publisher where T: Reloc + Send + Debug, @@ -461,7 +443,7 @@ pub struct SampleConsumerBuilder { } impl ConsumerDescriptor for SampleConsumerBuilder { - fn get_instance_identifier(&self) -> String { + fn get_instance_identifier(&self) -> &InstanceSpecifier { todo!() } } @@ -540,7 +522,12 @@ mod test { #[test] fn send_stuff() { - let test_publisher = super::Publisher::::new(); + let provider_info = super::LolaProviderInfo { + instance_specifier: com_api_concept::InstanceSpecifier::new("/test/publisher") + .expect("Invalid instance specifier"), + }; + let test_publisher = super::Publisher::::new("test_publisher", provider_info) + .expect("Publisher creation failed"); let sample = test_publisher.allocate().expect("Couldn't allocate sample"); let sample = sample.write(42); sample.send().expect("Send failed for sample"); diff --git a/com-api/com-api-runtime-mock/src/lib.rs b/com-api/com-api-runtime-mock/src/lib.rs index 455179c..4287950 100644 --- a/com-api/com-api-runtime-mock/src/lib.rs +++ b/com-api/com-api-runtime-mock/src/lib.rs @@ -16,7 +16,6 @@ #![allow(dead_code)] -use com_api_concept::Reloc; use core::cmp::Ordering; use core::fmt::Debug; use core::future::Future; @@ -29,8 +28,8 @@ use std::path::Path; use com_api_concept::{ Builder, Consumer, ConsumerBuilder, ConsumerDescriptor, FindServiceSpecifier, - InstanceSpecifier, Interface, Producer, ProducerBuilder, Result, Runtime, SampleContainer, - ServiceDiscovery, Subscriber, Subscription, + InstanceSpecifier, Interface, Producer, ProducerBuilder, Reloc, Result, Runtime, + SampleContainer, ServiceDiscovery, Subscriber, Subscription, }; pub struct MockRuntimeImpl {} @@ -338,24 +337,6 @@ pub struct Publisher { _data: PhantomData, } -impl Default for Publisher -where - T: Reloc + Send, -{ - fn default() -> Self { - Self::new() - } -} - -impl Publisher -where - T: Reloc + Send, -{ - pub fn new() -> Self { - Self { _data: PhantomData } - } -} - impl com_api_concept::Publisher for Publisher where T: Reloc + Send + Debug, @@ -453,7 +434,7 @@ pub struct SampleConsumerBuilder { } impl ConsumerDescriptor for SampleConsumerBuilder { - fn get_instance_identifier(&self) -> String { + fn get_instance_identifier(&self) -> &InstanceSpecifier { todo!() } } @@ -544,7 +525,12 @@ mod test { #[test] fn send_stuff() { - let test_publisher = super::Publisher::::new(); + let provider_info = super::MockProviderInfo { + instance_specifier: com_api_concept::InstanceSpecifier::new("/test/publisher") + .expect("Invalid instance specifier"), + }; + let test_publisher = super::Publisher::::new("test_publisher", provider_info) + .expect("Publisher creation failed"); let sample = test_publisher.allocate().expect("Couldn't allocate sample"); let sample = sample.write(42); sample.send().expect("Send failed for sample"); diff --git a/com-api/examples/basic-consumer-producer.rs b/com-api/examples/basic-consumer-producer.rs index 74103ed..ec59464 100644 --- a/com-api/examples/basic-consumer-producer.rs +++ b/com-api/examples/basic-consumer-producer.rs @@ -14,22 +14,27 @@ use com_api_gen::*; // Example struct demonstrating composition with VehicleConsumer pub struct VehicleMonitor { - consumer: VehicleConsumer, + _consumer: VehicleConsumer, producer: VehicleOfferedProducer, + tire_subscriber: <::Subscriber as Subscriber>::Subscription, } impl VehicleMonitor { /// Create a new VehicleMonitor with a consumer pub fn new(consumer: VehicleConsumer, producer: VehicleOfferedProducer) -> Self { - Self { consumer, producer } + let tire_subscriber = consumer.left_tire.subscribe(3).unwrap(); + Self { + _consumer: consumer, + producer, + tire_subscriber, + } } /// Monitor tire data from the consumer pub fn read_tire_data(&self) -> Result { - let subscribed = self.consumer.left_tire.subscribe(3)?; let mut sample_buf = SampleContainer::new(); - match subscribed.try_receive(&mut sample_buf, 1) { + match self.tire_subscriber.try_receive(&mut sample_buf, 1) { Ok(0) => Err(Error::Fail), Ok(x) => { let sample = sample_buf.pop_front().unwrap(); @@ -54,7 +59,7 @@ fn use_consumer(runtime: &R) -> VehicleConsumer { let consumer_builder = available_service_instances .into_iter() - .find(|desc| desc.get_instance_identifier() == "My/Funk/ServiceName") + .find(|desc| desc.get_instance_identifier().as_ref() == "/My/Funk/ServiceName") .unwrap(); let consumer = consumer_builder.build().unwrap(); @@ -64,7 +69,7 @@ fn use_consumer(runtime: &R) -> VehicleConsumer { fn use_producer(runtime: &R) -> VehicleOfferedProducer { let producer_builder = runtime.producer_builder::>( - InstanceSpecifier::new("My/Funk/ServiceName").unwrap(), + InstanceSpecifier::new("/My/Funk/ServiceName").unwrap(), ); let producer = producer_builder.build().unwrap(); let offered_producer = producer.offer().unwrap(); @@ -73,8 +78,9 @@ fn use_producer(runtime: &R) -> VehicleOfferedProducer { fn run_with_runtime(name: &str, runtime: &R) { println!("\n=== Running with {} runtime ===", name); - - let monitor = VehicleMonitor::new(use_consumer(runtime), use_producer(runtime)); + let producer = use_producer(runtime); + let consumer = use_consumer(runtime); + let monitor = VehicleMonitor::new(consumer, producer); for _ in 0..5 { monitor.write_tire_data(Tire {}).unwrap(); @@ -150,7 +156,7 @@ mod test { // Create consumer from first discovered service let consumer_builder = available_service_instances .into_iter() - .find(|desc| desc.get_instance_identifier() == "My/Funk/ServiceName") + .find(|desc| desc.get_instance_identifier().as_ref() == "/My/Funk/ServiceName") .unwrap(); let consumer = consumer_builder.build().unwrap();