@@ -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( ) ) ;
0 commit comments