Skip to content

Commit bdc49f7

Browse files
authored
Update generator (#191)
* codegen: Handle return values of u[8,16,32] and boolean type * codegen: Update wrapper creation to handle return values * codegen: How to handle calls for getters? * codegen: Update and handle tests for getters * Remove manual getters from custom code, now they're generated * codegen: Add comments and renaming variables for clarity * codegen: Improve? matching return types * label: Comment out get_recolor interface * codegen: Don't clone return value, we can reference it * codegen: Don't use extra variable, we can check self.ret to know if there's a return value * widgets: Remove commented out interfaces
1 parent 941c7c5 commit bdc49f7

File tree

4 files changed

+161
-46
lines changed

4 files changed

+161
-46
lines changed

lvgl-codegen/src/lib.rs

Lines changed: 160 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -129,23 +129,41 @@ impl Rusty for LvFunc {
129129
});
130130
}
131131

132-
// We don't deal with methods that return types yet
133-
if self.ret.is_some() {
134-
return Err(WrapperError::Skip);
135-
}
132+
// Handle return values
133+
let return_type = match self.ret {
134+
// function returns void
135+
None => quote!(()),
136+
// function returns something
137+
_ => {
138+
let return_value: &LvType = self.ret.as_ref().unwrap();
139+
match return_value.literal_name.as_str() {
140+
"bool" => quote!(bool),
141+
"u32" => quote!(u32),
142+
"i32" => quote!(i32),
143+
"u16" => quote!(u16),
144+
"i16" => quote!(i16),
145+
"u8" => quote!(u8),
146+
"i8" => quote!(i8),
147+
_ => return Err(WrapperError::Skip)
148+
}
149+
}
150+
};
136151

137152
// Make sure all arguments can be generated, skip the first arg (self)!
138153
for arg in self.args.iter().skip(1) {
139154
arg.code(self)?;
140155
}
141156

157+
// Generate the arguments being passed into the Rust 'wrapper'
158+
//
159+
// - Iif the first argument (of the C function) is const then we require a &self immutable reference, otherwise an &mut self reference
160+
// - The arguments will be appended to the accumulator (args_accumulator) as they are generated in the closure
142161
let args_decl = self
143162
.args
144163
.iter()
145164
.enumerate()
146-
.fold(quote!(), |args, (i, arg)| {
147-
// if first arg is `const`, then it should be immutable
148-
let next_arg = if i == 0 {
165+
.fold(quote!(), |args_accumulator, (arg_idx, arg)| {
166+
let next_arg = if arg_idx == 0 {
149167
if arg.get_type().is_const() {
150168
quote!(&self)
151169
} else {
@@ -154,14 +172,14 @@ impl Rusty for LvFunc {
154172
} else {
155173
arg.code(self).unwrap()
156174
};
157-
if args.is_empty() {
158-
quote! {
159-
#next_arg
160-
}
161-
} else {
162-
quote! {
163-
#args, #next_arg
164-
}
175+
176+
// If the accummulator is empty then we call quote! only with the next_arg content
177+
if args_accumulator.is_empty() {
178+
quote! {#next_arg}
179+
}
180+
// Otherwise we append next_arg at the end of the accumulator
181+
else {
182+
quote! {#args_accumulator, #next_arg}
165183
}
166184
});
167185

@@ -189,37 +207,55 @@ impl Rusty for LvFunc {
189207
}
190208
});
191209

192-
let args_call = self
210+
// Generate the arguments being passed into the FFI interface
211+
//
212+
// - The first argument will be always self.core.raw().as_mut() (see quote! when arg_idx == 0), it's most likely a pointer to lv_obj_t
213+
// TODO: When handling getters this should be self.raw().as_ptr() instead, this also requires updating args_decl
214+
// - The arguments will be appended to the accumulator (args_accumulator) as they are generated in the closure
215+
let ffi_args = self
193216
.args
194217
.iter()
195218
.enumerate()
196-
.fold(quote!(), |args, (i, arg)| {
197-
// if first arg is `const`, then it should be immutable
198-
let next_arg = if i == 0 {
219+
.fold(quote!(), |args_accumulator, (arg_idx, arg)| {
220+
let next_arg = if arg_idx == 0 {
199221
quote!(self.core.raw().as_mut())
200222
} else {
201223
let var = arg.get_value_usage();
202224
quote!(#var)
203225
};
204-
if args.is_empty() {
205-
quote! {
206-
#next_arg
207-
}
208-
} else {
209-
quote! {
210-
#args, #next_arg
211-
}
226+
227+
// If the accummulator is empty then we call quote! only with the next_arg content
228+
if args_accumulator.is_empty() {
229+
quote! {#next_arg}
230+
}
231+
// Otherwise we append next_arg at the end of the accumulator
232+
else {
233+
quote! {#args_accumulator, #next_arg}
212234
}
213235
});
214236

215-
// TODO: Handle methods that return types
237+
// NOTE: When the function returns something we can 'avoid' placing an Ok() at the end.
238+
let explicit_ok = if return_type.is_empty() {
239+
quote!(Ok(()))
240+
} else {
241+
quote!()
242+
};
243+
244+
// Append a semicolon at the end of the unsafe code only if there's no return value.
245+
// Otherwise we should remove it
246+
let optional_semicolon= match self.ret {
247+
None => quote!(;),
248+
_ => quote!()
249+
};
250+
216251
Ok(quote! {
217-
pub fn #func_name(#args_decl) -> crate::LvResult<()> {
252+
pub fn #func_name(#args_decl) -> #return_type {
218253
#args_processing
219254
unsafe {
220-
lvgl_sys::#original_func_name(#args_call);
255+
lvgl_sys::#original_func_name(#ffi_args)#optional_semicolon
221256
}
222-
Ok(())
257+
258+
#explicit_ok
223259
}
224260
})
225261
}
@@ -555,11 +591,10 @@ mod test {
555591

556592
let code = arc_set_bg_end_angle.code(&arc_widget).unwrap();
557593
let expected_code = quote! {
558-
pub fn set_bg_end_angle(&mut self, end: u16) -> crate::LvResult<()> {
594+
pub fn set_bg_end_angle(&mut self, end: u16) -> () {
559595
unsafe {
560596
lvgl_sys::lv_arc_set_bg_end_angle(self.core.raw().as_mut(), end);
561597
}
562-
Ok(())
563598
}
564599
};
565600

@@ -587,16 +622,106 @@ mod test {
587622
let code = label_set_text.code(&parent_widget).unwrap();
588623
let expected_code = quote! {
589624

590-
pub fn set_text(&mut self, text: &cstr_core::CStr) -> crate::LvResult<()> {
625+
pub fn set_text(&mut self, text: &cstr_core::CStr) -> () {
626+
unsafe {
627+
lvgl_sys::lv_label_set_text(
628+
self.core.raw().as_mut(),
629+
text.as_ptr()
630+
);
631+
}
632+
}
633+
634+
};
635+
636+
assert_eq!(code.to_string(), expected_code.to_string());
637+
}
638+
639+
#[test]
640+
fn generate_method_wrapper_for_void_return() {
641+
let bindgen_code = quote! {
642+
extern "C" {
643+
#[doc = " Set a new text for a label. Memory will be allocated to store the text by the label."]
644+
#[doc = " @param label pointer to a label object"]
645+
#[doc = " @param text '\\0' terminated character string. NULL to refresh with the current text."]
646+
pub fn lv_label_set_text(label: *mut lv_obj_t, text: *const cty::c_char);
647+
}
648+
};
649+
let cg = CodeGen::load_func_defs(bindgen_code.to_string().as_str()).unwrap();
650+
651+
let label_set_text = cg.get(0).unwrap().clone();
652+
let parent_widget = LvWidget {
653+
name: "label".to_string(),
654+
methods: vec![],
655+
};
656+
657+
let code = label_set_text.code(&parent_widget).unwrap();
658+
let expected_code = quote! {
659+
pub fn set_text(&mut self, text: &cstr_core::CStr) -> () {
591660
unsafe {
592661
lvgl_sys::lv_label_set_text(
593662
self.core.raw().as_mut(),
594663
text.as_ptr()
595664
);
596665
}
597-
Ok(())
598666
}
667+
};
668+
669+
assert_eq!(code.to_string(), expected_code.to_string());
670+
}
671+
672+
#[test]
673+
fn generate_method_wrapper_for_boolean_return() {
674+
let bindgen_code = quote! {
675+
extern "C" {
676+
pub fn lv_label_get_recolor(label: *mut lv_obj_t) -> bool;
677+
}
678+
};
679+
let cg = CodeGen::load_func_defs(bindgen_code.to_string().as_str()).unwrap();
680+
681+
let label_get_recolor = cg.get(0).unwrap().clone();
682+
let parent_widget = LvWidget {
683+
name: "label".to_string(),
684+
methods: vec![],
685+
};
686+
687+
let code = label_get_recolor.code(&parent_widget).unwrap();
688+
let expected_code = quote! {
689+
pub fn get_recolor(&mut self) -> bool {
690+
unsafe {
691+
lvgl_sys::lv_label_get_recolor(
692+
self.core.raw().as_mut()
693+
)
694+
}
695+
}
696+
};
697+
698+
assert_eq!(code.to_string(), expected_code.to_string());
699+
}
599700

701+
#[test]
702+
fn generate_method_wrapper_for_uint32_return() {
703+
let bindgen_code = quote! {
704+
extern "C" {
705+
pub fn lv_label_get_text_selection_start(label: *mut lv_obj_t) -> u32;
706+
}
707+
};
708+
let cg = CodeGen::load_func_defs(bindgen_code.to_string().as_str()).unwrap();
709+
710+
let label_get_text_selection_start = cg.get(0).unwrap().clone();
711+
let parent_widget = LvWidget {
712+
name: "label".to_string(),
713+
methods: vec![],
714+
};
715+
716+
let code = label_get_text_selection_start.code(&parent_widget).unwrap();
717+
let expected_code = quote! {
718+
pub fn get_text_selection_start(&mut self) -> u32 {
719+
unsafe {
720+
lvgl_sys::lv_label_get_text_selection_start(
721+
self.core.raw().as_mut()
722+
)
723+
}
724+
}
600725
};
601726

602727
assert_eq!(code.to_string(), expected_code.to_string());

lvgl/src/widgets/arc.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@ impl Arc<'_> {
3737
// }
3838
// Ok(())
3939
// }
40-
41-
/// Gets the current value of the arc
42-
pub fn get_value(&self) -> i32 {
43-
unsafe { lvgl_sys::lv_bar_get_value(self.core.raw().as_ptr()) }
44-
}
4540
}
4641
/*
4742
/// The different parts, of an arc object.

lvgl/src/widgets/bar.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ impl Bar<'_> {
1717
lvgl_sys::lv_bar_set_value(self.core.raw().as_mut(), value, anim.into());
1818
}
1919
}
20-
21-
/// Gets the current value of the bar
22-
pub fn get_value(&self) -> i32 {
23-
unsafe { lvgl_sys::lv_bar_get_value(self.core.raw().as_ptr()) }
24-
}
2520
}
2621
/*
2722
/// The different parts, of a bar object.

lvgl/src/widgets/label.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ mod alloc_imp {
1313
// text.try_into().unwrap()
1414
let text_cstr = CString::new(text.as_ref()).unwrap();
1515
let mut label = Label::new().unwrap();
16-
label.set_text(text_cstr.as_c_str()).unwrap();
16+
label.set_text(text_cstr.as_c_str());
1717
label
1818
}
1919
}

0 commit comments

Comments
 (0)