libplum_sys/
lib.rs

1#![allow(non_camel_case_types)]
2
3include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
4
5// Things that are not exported by bindgen.
6
7// These are `size_t`, and we enabled `bindgen::Builder::size_t_is_usize` in `build.rs`.
8pub const PLUM_MODE_FILENAME: usize = usize::MAX;
9pub const PLUM_MODE_BUFFER: usize = usize::MAX - 1;
10pub const PLUM_MODE_CALLBACK: usize = usize::MAX - 2;
11pub const PLUM_MAX_MEMORY_SIZE: usize = usize::MAX - 3;
12
13#[cfg(test)]
14mod tests {
15    use std::ffi::CString;
16
17    use super::*;
18
19    // One sanity check to see if the bindings work correctly.
20    // This doesn't test all functionality, I'd expect that to come from upstream libplum, or downstream consumers.
21    #[test]
22    fn load_test_square() {
23        // This entire test is a bit fast and loose with the lifetimes of refs/slices, but it's
24        // straightforward enough that we never use anything dangling.
25
26        let path = CString::new("./testsq.png").unwrap();
27        let mut error = 0u32;
28        // SAFETY: we conform to the API here, passing a pointer to a NUL-terminated string
29        //         together with `PLUM_MODE_FILENAME`.
30        let image = unsafe {
31            plum_load_image_limited(
32                path.as_ptr().cast(),
33                PLUM_MODE_FILENAME,
34                PLUM_COLOR_32 | PLUM_PALETTE_NONE,
35                isize::MAX as usize,
36                &mut error as *mut _,
37            )
38        };
39        // SAFETY: `plum_load_image`'s API is to return a pointer to a struct on success, and NULL on error.
40        //         - The pointer comes from `malloc`, which ensures alignment.
41        //         - The correct size is passed to `malloc`, which ensures it's dereferenceable.
42        //         - `plum_new_image` does a struct-to-struct assignment, which inits the entire struct
43        //           except padding, but AFAIK that's fine?
44        //         - The original pointer is lost (name rebound), and no copy exists(*),
45        //           which guarantees no aliasing.
46        // (*) Actually, libplum stores a copy of the pointer in its "allocator", but does not
47        //     make use of it outside of `plum_destroy_image`.
48        let Some(image) = (unsafe { image.as_mut() }) else {
49            panic!("Loading testsq.png failed, plum_load_image returned error {error}");
50        };
51        assert_eq!(plum_image_types::from(image.type_), PLUM_IMAGE_PNG);
52        assert_eq!(plum_flags::from(image.color_format), PLUM_COLOR_32);
53        assert_eq!(image.frames, 1);
54        assert_eq!(image.height, 21);
55        assert_eq!(image.width, 21);
56        assert_eq!(image.palette, std::ptr::null_mut());
57
58        let data = unsafe { image.data.as_ref() }.expect("image.data is NULL!?");
59        let data = unsafe {
60            std::slice::from_raw_parts(
61                data as *const _ as *const u32,
62                (image.height * image.width) as usize, // The size is capped by `plum_image_load_limited`.
63            )
64        };
65
66        const EXPECTED_COLORS: [u32; 21 * 21] = [
67            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
68            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
69            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
70            //
71            0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
72            0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
73            0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000,
74            //
75            0x00000000, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
76            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
77            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00000000,
78            //
79            0x00000000, 0x00ffffff, 0x00000000, 0x7fff0000, 0x7fff0000, 0x7fff0000, 0x7fff0000,
80            0x7fff0000, 0x7fff0000, 0x7fff0000, 0x00000000, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff,
81            0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x00000000, 0x00ffffff, 0x00000000,
82            //
83            0x00000000, 0x00ffffff, 0x00000000, 0x7fff0000, 0x7fff0000, 0x7fff0000, 0x7fff0000,
84            0x7fff0000, 0x7fff0000, 0x7fff0000, 0x00000000, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff,
85            0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x00000000, 0x00ffffff, 0x00000000,
86            //
87            0x00000000, 0x00ffffff, 0x00000000, 0x7fff0000, 0x7fff0000, 0x7fff0000, 0x7fff0000,
88            0x7fff0000, 0x7fff0000, 0x7fff0000, 0x00000000, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff,
89            0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x00000000, 0x00ffffff, 0x00000000,
90            //
91            0x00000000, 0x00ffffff, 0x00000000, 0x7fff0000, 0x7fff0000, 0x7fff0000, 0x7fff0000,
92            0x7fff0000, 0x7fff0000, 0x7fff0000, 0x00000000, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff,
93            0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x00000000, 0x00ffffff, 0x00000000,
94            //
95            0x00000000, 0x00ffffff, 0x00000000, 0x7fff0000, 0x7fff0000, 0x7fff0000, 0x7fff0000,
96            0x7fff0000, 0x7fff0000, 0x7fff0000, 0x00000000, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff,
97            0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x00000000, 0x00ffffff, 0x00000000,
98            //
99            0x00000000, 0x00ffffff, 0x00000000, 0x7fff0000, 0x7fff0000, 0x7fff0000, 0x7fff0000,
100            0x7fff0000, 0x7fff0000, 0x7fff0000, 0x00000000, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff,
101            0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x00000000, 0x00ffffff, 0x00000000,
102            //
103            0x00000000, 0x00ffffff, 0x00000000, 0x7fff0000, 0x7fff0000, 0x7fff0000, 0x7fff0000,
104            0x7fff0000, 0x7fff0000, 0x7fff0000, 0x00000000, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff,
105            0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x7f0000ff, 0x00000000, 0x00ffffff, 0x00000000,
106            //
107            0x00000000, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
108            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
109            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00000000,
110            //
111            0x00000000, 0x00ffffff, 0x00000000, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff,
112            0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x00000000, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00,
113            0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x00000000, 0x00ffffff, 0x00000000,
114            //
115            0x00000000, 0x00ffffff, 0x00000000, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff,
116            0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x00000000, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00,
117            0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x00000000, 0x00ffffff, 0x00000000,
118            //
119            0x00000000, 0x00ffffff, 0x00000000, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff,
120            0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x00000000, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00,
121            0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x00000000, 0x00ffffff, 0x00000000,
122            //
123            0x00000000, 0x00ffffff, 0x00000000, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff,
124            0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x00000000, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00,
125            0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x00000000, 0x00ffffff, 0x00000000,
126            //
127            0x00000000, 0x00ffffff, 0x00000000, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff,
128            0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x00000000, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00,
129            0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x00000000, 0x00ffffff, 0x00000000,
130            //
131            0x00000000, 0x00ffffff, 0x00000000, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff,
132            0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x00000000, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00,
133            0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x00000000, 0x00ffffff, 0x00000000,
134            //
135            0x00000000, 0x00ffffff, 0x00000000, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x7f00ffff,
136            0x7f00ffff, 0x7f00ffff, 0x7f00ffff, 0x00000000, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00,
137            0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x7f00ff00, 0x00000000, 0x00ffffff, 0x00000000,
138            //
139            0x00000000, 0x00ffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
140            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
141            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00000000,
142            //
143            0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
144            0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
145            0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000,
146            //
147            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
148            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
149            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
150            0x00000000,
151            //
152        ];
153        let mut matched = true;
154        for row_id in 0..21 {
155            let start = row_id * 21;
156            let range = start..=start + 20;
157            let expected = &EXPECTED_COLORS[range.clone()];
158            let got = &data[range];
159            if got != expected {
160                eprintln!("Row {row_id} mismatch!");
161                eprintln!("\tExpected {expected:?},");
162                eprintln!("\t     got {got:?}");
163                matched = false;
164            }
165        }
166        assert!(matched);
167    }
168}