@@ -129,23 +129,41 @@ impl Rusty for LvFunc {
129
129
} ) ;
130
130
}
131
131
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
+ } ;
136
151
137
152
// Make sure all arguments can be generated, skip the first arg (self)!
138
153
for arg in self . args . iter ( ) . skip ( 1 ) {
139
154
arg. code ( self ) ?;
140
155
}
141
156
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
142
161
let args_decl = self
143
162
. args
144
163
. iter ( )
145
164
. 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 {
149
167
if arg. get_type ( ) . is_const ( ) {
150
168
quote ! ( & self )
151
169
} else {
@@ -154,14 +172,14 @@ impl Rusty for LvFunc {
154
172
} else {
155
173
arg. code ( self ) . unwrap ( )
156
174
} ;
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 }
165
183
}
166
184
} ) ;
167
185
@@ -189,37 +207,55 @@ impl Rusty for LvFunc {
189
207
}
190
208
} ) ;
191
209
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
193
216
. args
194
217
. iter ( )
195
218
. 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 {
199
221
quote ! ( self . core. raw( ) . as_mut( ) )
200
222
} else {
201
223
let var = arg. get_value_usage ( ) ;
202
224
quote ! ( #var)
203
225
} ;
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 }
212
234
}
213
235
} ) ;
214
236
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
+
216
251
Ok ( quote ! {
217
- pub fn #func_name( #args_decl) -> crate :: LvResult < ( ) > {
252
+ pub fn #func_name( #args_decl) -> #return_type {
218
253
#args_processing
219
254
unsafe {
220
- lvgl_sys:: #original_func_name( #args_call ) ;
255
+ lvgl_sys:: #original_func_name( #ffi_args ) #optional_semicolon
221
256
}
222
- Ok ( ( ) )
257
+
258
+ #explicit_ok
223
259
}
224
260
} )
225
261
}
@@ -555,11 +591,10 @@ mod test {
555
591
556
592
let code = arc_set_bg_end_angle. code ( & arc_widget) . unwrap ( ) ;
557
593
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 ) -> ( ) {
559
595
unsafe {
560
596
lvgl_sys:: lv_arc_set_bg_end_angle( self . core. raw( ) . as_mut( ) , end) ;
561
597
}
562
- Ok ( ( ) )
563
598
}
564
599
} ;
565
600
@@ -587,16 +622,106 @@ mod test {
587
622
let code = label_set_text. code ( & parent_widget) . unwrap ( ) ;
588
623
let expected_code = quote ! {
589
624
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 ) -> ( ) {
591
660
unsafe {
592
661
lvgl_sys:: lv_label_set_text(
593
662
self . core. raw( ) . as_mut( ) ,
594
663
text. as_ptr( )
595
664
) ;
596
665
}
597
- Ok ( ( ) )
598
666
}
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
+ }
599
700
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
+ }
600
725
} ;
601
726
602
727
assert_eq ! ( code. to_string( ) , expected_code. to_string( ) ) ;
0 commit comments