-
Notifications
You must be signed in to change notification settings - Fork 64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Creating example grid in Rust based on C code example #107
Comments
Hi! Sorry for the late reply, have been busy. That's an oversight in how the codegen was done since methods are not autogenerated for |
Note that you will have to substitute the C call to |
Some progress, still no grid. |
After digging into everything, I still have absolutely no clue what's going on and why it's not working. I'll get back to this tomorrow and try to get it fixed then though. |
Already a lot of thanks for all the effort you are putting into this. |
Seems like you uncovered something pretty gnarly here; see #110 for details. Until a proper solution is decided on, this works: let mut buttons = Vec::new();
let mut styles = Vec::new();
for i in 0..9 {
let col = i % 3;
let row = i / 3;
let btn = {
buttons.push(Btn::create(&mut cont)?);
buttons.last_mut().unwrap()
};
let btn_style =
{
styles.push(Style::default());
styles.last_mut().unwrap()
};
btn_style.set_grid_cell_column_pos(col);
btn_style.set_grid_cell_row_pos(row);
btn_style.set_grid_cell_column_span(1);
btn_style.set_grid_cell_row_span(1);
btn_style.set_grid_cell_x_align(GridAlign::STRETCH);
btn_style.set_grid_cell_y_align(GridAlign::STRETCH);
btn_style.set_width(70);
btn_style.set_height(50);
info!(" row {} col {}", row, col);
btn.add_style(Part::Main, btn_style)?;
let mut label = Label::create(btn)?;
let s = CString::new(format!("c{}, r{} ", col, row)).unwrap();
label.set_text(&s)?;
label.set_align(Align::Center, 0, 0)?;
} |
Thanks for the deep dive to solve the issue, looks you found something that would create an issue iin any language that uses lvgl. Hope it get addressed quickly. |
LVGL seems to expect everything to be statically declared. Examples in C always declare statically the UI elements. https://github.com/lvgl/lvgl/blob/master/demos/music/lv_demo_music_list.c#L31-L41 |
That's.... terrifying, frankly. I suppose we can just leak the |
@nia-e yeah, I think that is a fair approach. |
I can imagine where the static lifetime expectation comes from , it looks a lot like CSS in an HTML document that also exist permanently during the display. Or coming from an embedded system where styles are in FLASH as constants. But then I would expect a big warning in the doc specifying that lvgl styles should be static. Maybe I missed that in the lvgl doc. Changing this at the LVGL C source code , is probably very bad for backward compatibility Maybe push the lifecycle of the styles to the programmer. Who has to do the bookkeeping of all these styles in line with the objects to which it applies. Managing that in the RUST layer above LVGL creates a lot of maintenance in the future. Some other ideas : For the moment I extended your approach, see below.
|
There is no |
We might have a way out of this still, though. We have the |
It's hidden / mentioned in the doc : https://docs.lvgl.io/master/overview/style.html#initialize-styles-and-set-get-properties
Should have a big red flashing box around it. ;-) |
I saw that but it's very very easy to cause problems if we never drop styles, e.g. a UI which creates a new screen on function call instead of initializing a screen once and reusing it causing memory leaks all over the place (which is exactly what I first intuited coming from Rust, assuming that everything will be nicely dropped as needed) |
I thought a lot about storing and handling the life-time of those types of objects within the crate. But that may take considerable memory, and I'm not certain about how acceptable that is in constrained environments. I agree that leaking memory is not great, I just don't know what to suggest as an alternative. |
As far as I understand, as long as we strictly use struct Style<'a> {
inner: lv_style_t,
}
struct Obj<'a> {
ptr: *mut lv_obj_t,
// We pretend to own a reference (this gets optimized away)
styles_used: PhantomData<&'a lv_style_t>,
}
impl<'a> Obj<'a> {
fn add_style(&mut self, &'b style: Style) {
/* call the lvgl_sys function for adding a style as we do now */
// Sum lifetimes; 'a + 'b becomes the new 'a
// If this is for some reason impossible, we can simply make add_style consume self and return a new Self
self.styles_used = PhantomData<&'a + 'b lv_style_t>;
}
} Since at the end we assign to a zero-sized marker type, I'm pretty sure it gets optimized away. I will manually check the generated code before merging anything like this, though. |
TL;DR I was right about it being fine I tested this out in Compiler Explorer and the codegen is indeed just 1 |
The approach of PhatomData ( which I don't fully understand being noob on Rust ) has been implemented ? So I would be able to avoid keeping styles in a static Vec ? |
No, not yet - this is still a sketch as it would be a massive change to the internals. Also, holding the styles in some sort of collection or moving them into the greater scope would still be necessary (just we're making it so the compiler should properly complain instead of silently allowing it) |
Re: CE code, seems like we can also reliably bet on this happening and it's not "just" that we got lucky; in MIR, the fn <impl at /app/example.rs:12:1: 12:19>::create(_1: u8, _2: &Ghost) -> Holds<'_> {
debug data => _1; // in scope 0 at /app/example.rs:14:19: 14:23
debug _ghost => _2; // in scope 0 at /app/example.rs:14:29: 14:35
let mut _0: Holds<'_>; // return place in scope 0 at /app/example.rs:14:51: 14:55
bb0: {
_0 = Holds::<'_> { data: _1, phantom: const PhantomData::<&Ghost> }; // scope 0 at /app/example.rs:15:9: 21:10
return; // scope 0 at /app/example.rs:22:6: 22:6
}
} whereas in LLVM IR (with unmangled names), we have define noundef i8 @create(i8 noundef returned %data, ptr noalias nocapture noundef readonly align 1 dereferenceable(64) %_ghost) unnamed_addr #0 {
ret i8 %data
} so it gets eliminated even before LLVM IR is generated but after MIR which makes sense (on low opt-level it seems to still get optimised out but the struct creation is pretty ugly: define i8 @create(i8 %data, ptr align 1 %_ghost) unnamed_addr #0 {
%0 = alloca i8, align 1
store i8 %data, ptr %0, align 1
%1 = load i8, ptr %0, align 1, !noundef !2
ret i8 %1
} such is the price for debugging, I suppose). I guess this makes sense since there's no machine-code way to express the idea of doing anything with a ZST (or even acknowledging it exists) |
As I am trying to build the example in Rust which is documented here : https://docs.lvgl.io/8.3/layouts/grid.html?highlight=gris#example
It's not clear how I can create a container within the screen , a Obj cannot be created in the way I would expect , meaning
The result looks like this :
while I was expecting this :
Code can be found here :
https://github.com/vortex314/lv_1/blob/main/src/main.rs
Changing Part::Any or Part::Main doesn't make a difference.
The text was updated successfully, but these errors were encountered: