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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ format_multirun(
name = "format",
cc = "@clang_format//:executable",
python = "@aspect_rules_lint//lint:ruff_bin",
rust = "//tools/lint:rustfmt_with_config",
starlark = "@buildifier_prebuilt//:buildifier",
target_compatible_with = ["@platforms//os:linux"],
)
Expand All @@ -85,6 +86,7 @@ format_test(
cc = "@clang_format//:executable",
no_sandbox = True,
python = "@aspect_rules_lint//lint:ruff_bin",
rust = "//tools/lint:rustfmt_with_config",
starlark = "@buildifier_prebuilt//:buildifier",
tags = ["no-flaky-test-detection"],
target_compatible_with = ["@platforms//os:linux"],
Expand Down
5 changes: 5 additions & 0 deletions CI.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ The goal is not to ensure a specific format but to have consistency in the proje
Ensure that the modified Python files are formatted following our decided style.
The goal is not to ensure a specific format but to have consistency in the project.

#### Formatting of Rust files

Ensure that the modified Rust files are formatted following our decided style.
The goal is not to ensure a specific format but to have consistency in the project.

#### Build everything and run unit tests (x86-64 linux)

Builds everything and runs all unit tests for all languages (C++, Rust, Python, etc.).
Expand Down
6 changes: 3 additions & 3 deletions score/mw/com/example/com-api-example/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ rust_library(
name = "com-api-example-lib",
srcs = glob(["src/**/*.rs"]),
crate_name = "com_api_example",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edition 2021 seems to be the agreed upon edition in S-CORE for now.

Please update the commit message to link where S-CORE says that Rust 2021 should be used.

edition = "2024",
edition = "2021",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we specifying rust edition per target? This is like in C++ we would specify the C++ version per target. If edition is not specified, it defaults to the one used by the toolchain.
If there is no good reason to specify the edition in every single target, I would like we specify it only in the toolchain.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. @bharatGoswami8 if you do not disagree, I'll do that change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed as we are going to use default so we can remove this completely - https://github.com/eclipse-score/toolchains_rust/blob/main/toolchains/x86_64-unknown-linux-gnu/BUILD.bazel#L24

features = ["link_std_cpp_lib"],
deps = [
"//score/mw/com/example/com-api-example/com-api-gen",
Expand All @@ -35,7 +35,7 @@ rust_binary(
"etc/logging.json",
"etc/mw_com_config.json",
],
edition = "2024",
edition = "2021",
env = {
"MW_LOG_CONFIG_FILE": "score/mw/com/example/com-api-example/etc/logging.json",
},
Expand All @@ -55,7 +55,7 @@ rust_test(
name = "com-api-example-tokio-integration-test",
srcs = ["tests_using_tokio_runtime.rs"],
data = ["etc/mw_com_config.json"],
edition = "2024",
edition = "2021",
features = ["link_std_cpp_lib"],
tags = ["manual"],
deps = [
Expand Down
68 changes: 26 additions & 42 deletions score/mw/com/example/com-api-example/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,62 +86,54 @@ const ASYNC_PRODUCER_STARTUP_DELAY_MS: u64 = 2000;
// Run the consumer with the specified runtime and example type
fn run_consumer<R: Runtime>(name: &str, example_type: &ExampleType, runtime: &R) {
log::info!("Running with {} runtime", name);
let service_id = InstanceSpecifier::new("/Vehicle/Service1/Instance")
.expect("Failed to create InstanceSpecifier");
let service_id = InstanceSpecifier::new("/Vehicle/Service1/Instance").expect("Failed to create InstanceSpecifier");
if matches!(example_type, ExampleType::Sync) {
std::thread::sleep(std::time::Duration::from_millis(
SYNC_CONSUMER_STARTUP_DELAY_MS,
));
std::thread::sleep(std::time::Duration::from_millis(SYNC_CONSUMER_STARTUP_DELAY_MS));
}

let consumer_monitor = match example_type {
// it does the service discovery and receving data synchronously
ExampleType::Sync => {
let consumer_monitor =
VehicleMonitorConsumer::find_available_instances(runtime, service_id)
.expect("Failed to create consumer");
let consumer_monitor = VehicleMonitorConsumer::find_available_instances(runtime, service_id)
.expect("Failed to create consumer");
consumer_monitor
.read_tire_data(SAMPLE_COUNT)
.expect("Failed to read tire data synchronously");
consumer_monitor
}
},
// it does the service discovery asynchronously and receving data synchronously
ExampleType::AsyncServiceDiscovery => {
let consumer_monitor = futures::executor::block_on(
VehicleMonitorConsumer::find_available_instances_async(runtime, service_id),
)
let consumer_monitor = futures::executor::block_on(VehicleMonitorConsumer::find_available_instances_async(
runtime, service_id,
))
.expect("Failed to create consumer");
consumer_monitor
.read_tire_data(SAMPLE_COUNT)
.expect("Failed to read tire data synchronously");
consumer_monitor
}
},
// it does the service discovery asynchronously and receving data asynchronously without timeout
// for the receive operation, it will wait until the data is received.
ExampleType::AsyncReceive => {
let consumer_monitor = futures::executor::block_on(
VehicleMonitorConsumer::find_available_instances_async(runtime, service_id),
)
let consumer_monitor = futures::executor::block_on(VehicleMonitorConsumer::find_available_instances_async(
runtime, service_id,
))
.expect("Failed to create consumer");
futures::executor::block_on(
consumer_monitor.read_tire_data_async_without_timeout(SAMPLE_COUNT),
)
.expect("Failed to read tire data asynchronously");
futures::executor::block_on(consumer_monitor.read_tire_data_async_without_timeout(SAMPLE_COUNT))
.expect("Failed to read tire data asynchronously");
consumer_monitor
}
},
// it does the service discovery asynchronously and receving data asynchronously with timeout
// for the receive operation, it will wait until the data is received or timeout occurs.
ExampleType::AsyncReceiveWithTimeout => {
let consumer_monitor = futures::executor::block_on(
VehicleMonitorConsumer::find_available_instances_async(runtime, service_id),
)
let consumer_monitor = futures::executor::block_on(VehicleMonitorConsumer::find_available_instances_async(
runtime, service_id,
))
.expect("Failed to create consumer");
futures::executor::block_on(
consumer_monitor.read_tire_data_async_with_timeout(SAMPLE_COUNT),
)
.expect("Failed to read tire data asynchronously with timeout");
futures::executor::block_on(consumer_monitor.read_tire_data_async_with_timeout(SAMPLE_COUNT))
.expect("Failed to read tire data asynchronously with timeout");
consumer_monitor
}
},
// it does the service discovery asynchronously and receving data asynchronously with streaming
ExampleType::Streaming => {
let mut consumer_monitor = futures::executor::block_on(
Expand All @@ -150,7 +142,7 @@ fn run_consumer<R: Runtime>(name: &str, example_type: &ExampleType, runtime: &R)
.expect("Failed to create consumer");
futures::executor::block_on(consumer_monitor.read_tire_data_stream(SAMPLE_COUNT));
consumer_monitor
}
},
};
consumer_monitor.unsubscribe();
log::info!("runtime execution completed");
Expand All @@ -159,16 +151,12 @@ fn run_consumer<R: Runtime>(name: &str, example_type: &ExampleType, runtime: &R)
// Run the producer with the specified runtime and example type
fn run_producer<R: Runtime>(name: &str, example_type: &ExampleType, runtime: &R) {
log::info!("Running with {} runtime", name);
let service_id = InstanceSpecifier::new("/Vehicle/Service1/Instance")
.expect("Failed to create InstanceSpecifier");
let service_id = InstanceSpecifier::new("/Vehicle/Service1/Instance").expect("Failed to create InstanceSpecifier");
// In async examples, we will not wait before offering the service to simulate async discovery.
if !matches!(example_type, ExampleType::Sync) {
std::thread::sleep(std::time::Duration::from_millis(
ASYNC_PRODUCER_STARTUP_DELAY_MS,
));
std::thread::sleep(std::time::Duration::from_millis(ASYNC_PRODUCER_STARTUP_DELAY_MS));
}
let producer_monitor =
VehicleMonitorProducer::new(runtime, service_id).expect("Failed to create producer");
let producer_monitor = VehicleMonitorProducer::new(runtime, service_id).expect("Failed to create producer");
log::info!("Producer created and offered successfully");
producer_monitor.run_publish_loop(INITIAL_TIRE_PRESSURE, SAMPLE_COUNT);
producer_monitor.unoffer();
Expand Down Expand Up @@ -199,11 +187,7 @@ fn main() {
init_logging();
let args = Arguments::parse();
let lola_runtime_builder = create_lola_runtime_builder(&args.service_instance_manifest);
let lola_runtime = Arc::new(
lola_runtime_builder
.build()
.expect("Failed to build Lola runtime"),
);
let lola_runtime = Arc::new(lola_runtime_builder.build().expect("Failed to build Lola runtime"));

let example_type = args.example_type.clone();
let runtime_producer = Arc::clone(&lola_runtime);
Expand Down
34 changes: 12 additions & 22 deletions score/mw/com/example/com-api-example/src/consumer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

use score_com::{
ConsumerBuilder, FindServiceSpecifier, InstanceSpecifier, Result, Runtime, SampleContainer,
ServiceDiscovery, Subscriber, Subscription,
};
use com_api_gen::{Exhaust, Tire, VehicleInterface};
use futures::channel::oneshot;
use futures::{FutureExt, StreamExt};
use score_com::{
ConsumerBuilder, FindServiceSpecifier, InstanceSpecifier, Result, Runtime, SampleContainer, ServiceDiscovery,
Subscriber, Subscription,
};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
Expand All @@ -31,8 +31,7 @@ const SYNC_RECEIVE_POLL_INTERVAL_MS: u64 = 1000;

pub struct VehicleMonitorConsumer<R: Runtime> {
tire_subscriber: <<R as Runtime>::Subscriber<Tire> as Subscriber<Tire, R>>::Subscription,
_exhaust_subscriber:
<<R as Runtime>::Subscriber<Exhaust> as Subscriber<Exhaust, R>>::Subscription,
_exhaust_subscriber: <<R as Runtime>::Subscriber<Exhaust> as Subscriber<Exhaust, R>>::Subscription,
}

impl<R: Runtime> VehicleMonitorConsumer<R> {
Expand Down Expand Up @@ -65,32 +64,25 @@ impl<R: Runtime> VehicleMonitorConsumer<R> {
match result {
Ok(0) => log::info!("No tire data received"),
Ok(x) => {
let sample = sample_buf
.pop_front()
.expect("Sample buffer pop operation error");
let sample = sample_buf.pop_front().expect("Sample buffer pop operation error");
log::info!("{} samples received: sample[0] = {:?}", x, *sample);
}
},
Err(e) => log::error!("Error receiving tire data: {:?}", e),
}
}

/// Finds available service instances and constructs a VehicleMonitorConsumer.
/// It will return immediately regardless of whether any instances are available or not.
pub fn find_available_instances(runtime: &R, service_id: InstanceSpecifier) -> Result<Self> {
let consumer_discovery =
runtime.find_service::<VehicleInterface>(FindServiceSpecifier::Specific(service_id));
let consumer_discovery = runtime.find_service::<VehicleInterface>(FindServiceSpecifier::Specific(service_id));
let instances = consumer_discovery.get_available_instances()?;
Self::from_service_instances(instances)
}

/// Finds available service instances asynchronously and constructs a VehicleMonitorConsumer.
/// It will wait for the service availability and return once an instance is found.
pub async fn find_available_instances_async(
runtime: &R,
service_id: InstanceSpecifier,
) -> Result<Self> {
let consumer_discovery =
runtime.find_service::<VehicleInterface>(FindServiceSpecifier::Specific(service_id));
pub async fn find_available_instances_async(runtime: &R, service_id: InstanceSpecifier) -> Result<Self> {
let consumer_discovery = runtime.find_service::<VehicleInterface>(FindServiceSpecifier::Specific(service_id));
let instances = consumer_discovery.get_available_instances_async().await?;
Self::from_service_instances(instances)
}
Expand Down Expand Up @@ -136,9 +128,7 @@ impl<R: Runtime> VehicleMonitorConsumer<R> {
for _ in 0..count {
// Request a timeout from the shared timer thread.
let (tx, rx) = oneshot::channel();
timer_tx
.send(tx)
.expect("Timer thread unexpectedly stopped");
timer_tx.send(tx).expect("Timer thread unexpectedly stopped");

// Map the receiver to resolve to () instead of Result<(), Canceled>
let timeout_future = rx.map(|_| ());
Expand All @@ -162,7 +152,7 @@ impl<R: Runtime> VehicleMonitorConsumer<R> {
None => {
log::info!("Stream ended");
break;
}
},
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions score/mw/com/example/com-api-example/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ pub mod producer;
pub use consumer::VehicleMonitorConsumer;
pub use producer::VehicleMonitorProducer;

use score_com::{Interface, Producer};
use com_api_gen::VehicleInterface;
use score_com::{Interface, Producer};

// Type aliases for generated consumer and offered producer types for the Vehicle interface
// VehicleConsumer is the consumer type generated for the Vehicle interface, parameterized by the runtime R
pub type VehicleConsumer<R> = <VehicleInterface as Interface>::Consumer<R>;
// VehicleOfferedProducer is the offered producer type generated for the Vehicle interface, parameterized by the runtime R
pub type VehicleOfferedProducer<R> =
<<VehicleInterface as Interface>::Producer<R> as Producer<R>>::OfferedProducer;
pub type VehicleOfferedProducer<R> = <<VehicleInterface as Interface>::Producer<R> as Producer<R>>::OfferedProducer;
9 changes: 3 additions & 6 deletions score/mw/com/example/com-api-example/src/producer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@
********************************************************************************/

use crate::VehicleOfferedProducer;
use com_api_gen::{Tire, VehicleInterface};
use score_com::{
Builder, InstanceSpecifier, OfferedProducer, Producer, Publisher, Result, Runtime,
SampleMaybeUninit, SampleMut,
Builder, InstanceSpecifier, OfferedProducer, Producer, Publisher, Result, Runtime, SampleMaybeUninit, SampleMut,
};
use com_api_gen::{Tire, VehicleInterface};
use std::thread;
use std::time::Duration;

Expand All @@ -34,9 +33,7 @@ impl<R: Runtime> VehicleMonitorProducer<R> {
/// Create a new VehicleMonitorProducer
pub fn new(runtime: &R, service_id: InstanceSpecifier) -> Result<Self> {
let producer_builder = runtime.producer_builder::<VehicleInterface>(service_id);
let producer = producer_builder
.build()
.expect("Failed to build producer instance");
let producer = producer_builder.build().expect("Failed to build producer instance");
let producer = producer.offer().expect("Failed to offer producer instance");
Ok(Self { producer })
}
Expand Down
Loading
Loading