Generate methods with str as argument

This commit is contained in:
Rafael Caricio 2020-06-12 20:34:56 +02:00 committed by Rafael Carício
parent b0113fc747
commit 67cbca4942
3 changed files with 69 additions and 20 deletions

View file

@ -17,6 +17,7 @@ itertools = "0.9.0"
proc-macro2 = "1.0.18" proc-macro2 = "1.0.18"
Inflector = "0.11.4" Inflector = "0.11.4"
lang-c = "0.8.1" lang-c = "0.8.1"
syn = "1.0.31"
[build-dependencies] [build-dependencies]
cc = "1.0.50" cc = "1.0.50"

View file

@ -1,4 +1,4 @@
use clang::{Availability, Clang, Entity, EntityKind, Index, Linkage, Type}; use clang::{Clang, Entity, EntityKind, Index, Linkage, Type};
use inflector::cases::pascalcase::to_pascal_case; use inflector::cases::pascalcase::to_pascal_case;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
@ -17,7 +17,8 @@ lazy_static! {
("uint16_t", "u16"), ("uint16_t", "u16"),
("int32_t", "i32"), ("int32_t", "i32"),
("uint8_t", "u8"), ("uint8_t", "u8"),
("bool", "bool") ("bool", "bool"),
("const char *", "&str"),
] ]
.iter() .iter()
.cloned() .cloned()
@ -111,15 +112,16 @@ impl Rusty for LvFunc {
}); });
} }
// Make sure all argumets can be generated, skip the first arg (self)!
for arg in self.args.iter().skip(1) {
arg.code(self)?;
}
// We don't deal with methods that return types yet // We don't deal with methods that return types yet
if self.ret.is_some() { if self.ret.is_some() {
return Err(WrapperError::Skip); return Err(WrapperError::Skip);
} }
// Make sure all arguments can be generated, skip the first arg (self)!
for arg in self.args.iter().skip(1) {
arg.code(self)?;
}
let args_decl = self let args_decl = self
.args .args
.iter() .iter()
@ -155,7 +157,7 @@ impl Rusty for LvFunc {
let next_arg = if i == 0 { let next_arg = if i == 0 {
quote!(self.core.raw()?.as_mut()) quote!(self.core.raw()?.as_mut())
} else { } else {
let var = arg.get_name_ident(); let var = arg.get_value_usage();
quote!(#var) quote!(#var)
}; };
if args.is_empty() { if args.is_empty() {
@ -213,7 +215,21 @@ impl LvArg {
} }
pub fn get_name_ident(&self) -> Ident { pub fn get_name_ident(&self) -> Ident {
format_ident!("r#{}", self.name) syn::parse_str::<syn::Ident>(self.name.as_str())
.unwrap_or_else(|_| format_ident!("r#{}", self.name.as_str()))
}
pub fn get_value_usage(&self) -> TokenStream {
let ident = self.get_name_ident();
if self.typ.is_str() {
quote! {
cstr_core::CString::new(#ident).unwrap().into_raw()
}
} else {
quote! {
#ident
}
}
} }
pub fn get_type(&self) -> &LvType { pub fn get_type(&self) -> &LvType {
@ -255,6 +271,10 @@ impl LvType {
pub fn is_const(&self) -> bool { pub fn is_const(&self) -> bool {
self.typ.starts_with("const ") self.typ.starts_with("const ")
} }
pub fn is_str(&self) -> bool {
self.typ.ends_with("char *")
}
} }
impl Rusty for LvType { impl Rusty for LvType {
@ -263,9 +283,14 @@ impl Rusty for LvType {
fn code(&self, _parent: &Self::Parent) -> WrapperResult<TokenStream> { fn code(&self, _parent: &Self::Parent) -> WrapperResult<TokenStream> {
match TYPE_MAPPINGS.get(self.typ.as_str()) { match TYPE_MAPPINGS.get(self.typ.as_str()) {
Some(name) => { Some(name) => {
let ident = format_ident!("{}", name); let val = if self.is_str() {
quote!(&str)
} else {
let ident = format_ident!("{}", name);
quote!(#ident)
};
Ok(quote! { Ok(quote! {
#ident #val
}) })
} }
None => Err(WrapperError::Skip), None => Err(WrapperError::Skip),
@ -444,7 +469,7 @@ mod test {
let code = arc_set_bg_end_angle.code(&arc_widget).unwrap(); let code = arc_set_bg_end_angle.code(&arc_widget).unwrap();
let expected_code = quote! { let expected_code = quote! {
pub fn set_bg_end_angle(&mut self, end: u16) -> LvResult<()> { pub fn set_bg_end_angle(&mut self, end: u16) -> crate::LvResult<()> {
unsafe { unsafe {
lvgl_sys::lv_arc_set_bg_end_angle(self.core.raw()?.as_mut(), end); lvgl_sys::lv_arc_set_bg_end_angle(self.core.raw()?.as_mut(), end);
} }
@ -455,6 +480,38 @@ mod test {
assert_eq!(code.to_string(), expected_code.to_string()); assert_eq!(code.to_string(), expected_code.to_string());
} }
#[test]
fn generate_method_wrapper_for_str_types_as_argument() {
// void lv_label_set_text(lv_obj_t * label, const char * text)
let label_set_text = LvFunc::new(
"lv_label_set_text".to_string(),
vec![
LvArg::new("label".to_string(), LvType::new("lv_obj_t *".to_string())),
LvArg::new("text".to_string(), LvType::new("const char *".to_string())),
],
None,
);
let parent_widget = LvWidget {
name: "label".to_string(),
methods: vec![],
};
let code = label_set_text.code(&parent_widget).unwrap();
let expected_code = quote! {
pub fn set_text(&mut self, text: &str) -> crate::LvResult<()> {
unsafe {
lvgl_sys::lv_label_set_text(
self.core.raw()?.as_mut(),
cstr_core::CString::new(text).unwrap().into_raw()
);
}
Ok(())
}
};
assert_eq!(code.to_string(), expected_code.to_string());
}
#[test] #[test]
fn generate_basic_widget_code() { fn generate_basic_widget_code() {
let arc_widget = LvWidget { let arc_widget = LvWidget {

View file

@ -1,16 +1,7 @@
use crate::widgets::Label; use crate::widgets::Label;
use crate::{LvResult, NativeObject}; use crate::{LvResult, NativeObject};
use cstr_core::CString;
impl Label { impl Label {
pub fn set_text(&mut self, text: &str) -> LvResult<()> {
let text = CString::new(text).unwrap();
unsafe {
lvgl_sys::lv_label_set_text(self.core.raw()?.as_mut(), text.as_ptr());
}
Ok(())
}
pub fn set_label_align(&mut self, align: LabelAlign) -> LvResult<()> { pub fn set_label_align(&mut self, align: LabelAlign) -> LvResult<()> {
unsafe { unsafe {
lvgl_sys::lv_label_set_align(self.core.raw()?.as_mut(), align as u8); lvgl_sys::lv_label_set_align(self.core.raw()?.as_mut(), align as u8);