Skip to content

Commit f235672

Browse files
authored
Merge pull request #27 from zeenix/field-visibility-spec
Allow visibility specifiers on struct fields
2 parents 79521b2 + cf3c819 commit f235672

File tree

5 files changed

+67
-3
lines changed

5 files changed

+67
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 0.4.1 (Nov 26th, 2025)
2+
3+
* Allow specifying visibility on struct fields.
4+
15
# 0.4.0 (Nov 26th, 2025)
26

37
## Breaking Changes

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "firmware-controller"
33
description = "Controller to decouple interactions between components in a no_std environment."
4-
version = "0.4.0"
4+
version = "0.4.1"
55
edition = "2021"
66
authors = [
77
"Zeeshan Ali Khan <[email protected]>",

src/controller/item_struct.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ pub(crate) fn expand(mut input: ItemStruct) -> Result<ExpandedStruct> {
129129
.collect();
130130

131131
let fields = struct_fields.raw_fields().collect::<Vec<_>>();
132+
// Generate function parameters without visibility (visibility is only valid on struct fields).
133+
let new_fn_params = fields.iter().map(|f| {
134+
let ident = f.ident.as_ref().unwrap();
135+
let ty = &f.ty;
136+
quote! { #ident: #ty }
137+
});
132138
let vis = &input.vis;
133139

134140
// Generate initial value sends for Watch channels.
@@ -149,7 +155,7 @@ pub(crate) fn expand(mut input: ItemStruct) -> Result<ExpandedStruct> {
149155

150156
impl #struct_name {
151157
#[allow(clippy::too_many_arguments)]
152-
pub fn new(#(#fields),*) -> Self {
158+
pub fn new(#(#new_fn_params),*) -> Self {
153159
let __self = Self {
154160
#(#field_names),*,
155161
#sender_fields_initializations

tests/integration.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,57 @@ fn test_controller_basic_functionality() {
219219
async fn controller_task(controller: Controller) {
220220
controller.run().await;
221221
}
222+
223+
/// Test that visibility specifiers on struct fields are preserved.
224+
#[controller]
225+
mod visibility_test_controller {
226+
pub struct Controller {
227+
#[controller(getter)]
228+
pub public_field: u32,
229+
#[controller(getter)]
230+
pub(crate) crate_field: i32,
231+
#[controller(getter)]
232+
private_field: bool,
233+
}
234+
235+
impl Controller {}
236+
}
237+
238+
#[test]
239+
fn test_visibility_on_fields() {
240+
// Verify struct compiles and fields have correct visibility.
241+
let controller = visibility_test_controller::Controller::new(42, -1, true);
242+
243+
// Public field should be accessible.
244+
assert_eq!(controller.public_field, 42);
245+
246+
// pub(crate) field should be accessible within this crate.
247+
assert_eq!(controller.crate_field, -1);
248+
249+
// Note: private_field is not accessible here, which is correct.
250+
// We can only access it through the method.
251+
252+
// Run the controller in a background thread.
253+
std::thread::spawn(move || {
254+
let executor = Box::leak(Box::new(embassy_executor::Executor::new()));
255+
executor.run(move |spawner| {
256+
spawner
257+
.spawn(visibility_controller_task(controller))
258+
.unwrap();
259+
});
260+
});
261+
262+
futures::executor::block_on(async {
263+
let client = visibility_test_controller::ControllerClient::new();
264+
265+
// Use generated getters from #[controller(getter)] attribute.
266+
assert_eq!(client.public_field().await, 42);
267+
assert_eq!(client.crate_field().await, -1);
268+
assert_eq!(client.private_field().await, true);
269+
});
270+
}
271+
272+
#[embassy_executor::task]
273+
async fn visibility_controller_task(controller: visibility_test_controller::Controller) {
274+
controller.run().await;
275+
}

0 commit comments

Comments
 (0)