lvgl/
mem.rs

1use core::mem;
2use core::ops::{Deref, DerefMut};
3use core::ptr::NonNull;
4
5/// Places a sized `T` into LVGL memory.
6///
7/// This is useful for cases when we need to allocate memory on Rust side
8/// and handover the management of that memory to LVGL. May also be used in cases we
9/// want to use dynamic memory in the Rust side.
10pub(crate) struct Box<T>(NonNull<T>);
11
12impl<T> Box<T> {
13    /// Allocate memory using LVGL memory API and place `T` in the LVGL tracked memory.
14    pub fn new(value: T) -> Self {
15        let size = mem::size_of::<T>();
16        let inner = unsafe {
17            let ptr = lvgl_sys::lv_mem_alloc(size as cty::size_t) as *mut T;
18
19            // LVGL should align the memory address for us!
20            assert_eq!(
21                ptr as usize % mem::align_of::<T>(),
22                0,
23                "Memory address not aligned!"
24            );
25
26            NonNull::new(ptr)
27                .map(|p| {
28                    p.as_ptr().write(value);
29                    p
30                })
31                .unwrap_or_else(|| {
32                    panic!("Could not allocate memory {} bytes: {:?}", size, mem_info());
33                })
34        };
35        Self(inner)
36    }
37
38    pub fn into_raw(self) -> *mut T {
39        let b = mem::ManuallyDrop::new(self);
40        b.0.as_ptr()
41    }
42}
43
44impl<T> Drop for Box<T> {
45    fn drop(&mut self) {
46        unsafe {
47            lvgl_sys::lv_mem_free(self.0.as_ptr() as *mut cty::c_void);
48        }
49    }
50}
51
52impl<T> DerefMut for Box<T> {
53    fn deref_mut(&mut self) -> &mut Self::Target {
54        self.as_mut()
55    }
56}
57
58impl<T> Deref for Box<T> {
59    type Target = T;
60
61    fn deref(&self) -> &Self::Target {
62        unsafe { self.0.as_ref() }
63    }
64}
65
66impl<T> AsMut<T> for Box<T> {
67    fn as_mut(&mut self) -> &mut T {
68        unsafe { self.0.as_mut() }
69    }
70}
71
72impl<T: Clone> Clone for Box<T> {
73    fn clone(&self) -> Self {
74        unsafe { Self::new(self.0.as_ref().clone()) }
75    }
76}
77
78fn mem_info() -> lvgl_sys::lv_mem_monitor_t {
79    let mut info = lvgl_sys::lv_mem_monitor_t {
80        total_size: 0,
81        free_cnt: 0,
82        free_size: 0,
83        free_biggest_size: 0,
84        used_cnt: 0,
85        max_used: 0,
86        used_pct: 0,
87        frag_pct: 0,
88    };
89    unsafe {
90        lvgl_sys::lv_mem_monitor(&mut info as *mut _);
91    }
92    info
93}
94
95#[cfg(test)]
96mod test {
97    use super::*;
98    use crate::mem::mem_info;
99    use crate::*;
100    use std::vec::Vec;
101
102    /*
103    fn init() {
104        unsafe {
105            lvgl_sys::lv_init();
106        };
107    }
108    */
109
110    fn teardown() {
111        unsafe {
112            lvgl_sys::lv_deinit();
113        }
114    }
115
116    #[test]
117    fn place_value_in_lv_mem() {
118        tests::initialize_test();
119
120        let v = Box::new(5);
121        drop(v);
122        let v = Box::new(10);
123        drop(v);
124
125        teardown();
126    }
127
128    #[test]
129    fn place_complex_value_in_lv_mem() {
130        tests::initialize_test();
131
132        #[repr(C)]
133        #[derive(Debug)]
134        struct Point {
135            x: u64,
136            y: i8,
137            t: i32,
138            disp: i32,
139        }
140
141        let initial_mem_info = mem_info();
142
143        let mut keep = Vec::new();
144        for i in 0..100 {
145            let p = Point {
146                x: i,
147                y: 42,
148                t: 0,
149                disp: -100,
150            };
151
152            println!("{:?}", p);
153            let mut b = Box::new(p);
154
155            println!("memory address is {:p}", b.as_mut());
156
157            let point = b.as_mut();
158            if point.x != i {
159                println!("{:?}", point);
160            }
161            assert_eq!(point.x, i);
162
163            let info = mem_info();
164            println!("mem info: {:?}", &info);
165            keep.push(b);
166        }
167        drop(keep);
168
169        //unsafe {
170        //    lvgl_sys::lv_mem_defrag();
171        //}
172
173        let final_info = mem_info();
174        println!("mem info: {:?}", &final_info);
175
176        // If this fails, we are leaking memory! BOOM! \o/
177        assert_eq!(initial_mem_info.free_size, final_info.free_size);
178
179        teardown();
180    }
181
182    #[test]
183    fn clone_object_in_lv_mem() {
184        #[cfg(feature = "unsafe_no_autoinit")]
185        crate::init();
186
187        let v1 = Box::new(5);
188        let v2 = v1.clone();
189
190        // Ensure that the two objects have identical values.
191        assert_eq!(*v1, *v2);
192        // They should have different memory addresses, however.
193        assert_ne!(v1.into_raw() as usize, v2.into_raw() as usize);
194    }
195}