1use crate::{Rect, Settings};
9
10pub const CAPACITY: usize = 64;
14
15static mut SCRATCH: [f64; CAPACITY * 4] = [0.0; CAPACITY * 4];
17
18#[expect(unsafe_code, reason = "exporting a C symbol and its scratch buffer")]
20#[unsafe(no_mangle)]
21pub extern "C" fn solium_layout_scratch() -> *const f64 {
22 &raw const SCRATCH as *const f64
23}
24
25#[must_use]
26pub const fn capacity() -> usize {
27 CAPACITY
28}
29
30#[expect(unsafe_code, reason = "exporting a C symbol")]
31#[unsafe(no_mangle)]
32pub extern "C" fn solium_layout_capacity() -> u32 {
33 CAPACITY as u32
34}
35
36#[expect(unsafe_code, reason = "writing the scratch buffer the caller reads")]
38fn publish(slots: &[Rect]) -> u32 {
39 let written = slots.len().min(CAPACITY);
40 let scratch = &raw mut SCRATCH;
41 for (index, slot) in slots.iter().take(written).enumerate() {
42 unsafe {
48 (*scratch)[index * 4] = slot.x;
49 (*scratch)[index * 4 + 1] = slot.y;
50 (*scratch)[index * 4 + 2] = slot.w;
51 (*scratch)[index * 4 + 3] = slot.h;
52 }
53 }
54 written as u32
55}
56
57fn settings(gap: f64, ratio: f64, column: f64, padding: f64) -> Settings {
58 Settings {
59 gap,
60 ratio,
61 column,
62 padding,
63 ..Settings::default()
66 }
67}
68
69#[expect(unsafe_code, reason = "exporting a C symbol")]
70#[unsafe(no_mangle)]
71pub extern "C" fn solium_layout_master_stack(
72 count: u32,
73 x: f64,
74 y: f64,
75 w: f64,
76 h: f64,
77 gap: f64,
78 ratio: f64,
79) -> u32 {
80 let slots = crate::master_stack(
81 count as usize,
82 Rect::new(x, y, w, h),
83 settings(gap, ratio, 0.44, 24.0),
84 );
85 publish(&slots)
86}
87
88#[expect(unsafe_code, reason = "exporting a C symbol")]
89#[unsafe(no_mangle)]
90pub extern "C" fn solium_layout_scrolling(
91 count: u32,
92 x: f64,
93 y: f64,
94 w: f64,
95 h: f64,
96 gap: f64,
97 column: f64,
98 offset: f64,
99) -> u32 {
100 let slots = crate::scrolling(
101 count as usize,
102 Rect::new(x, y, w, h),
103 settings(gap, 0.6, column, 24.0),
104 offset,
105 );
106 publish(&slots)
107}
108
109#[expect(unsafe_code, reason = "exporting a C symbol and reading its scratch")]
114#[unsafe(no_mangle)]
115pub extern "C" fn solium_layout_grid(
116 count: u32,
117 x: f64,
118 y: f64,
119 w: f64,
120 h: f64,
121 padding: f64,
122) -> u32 {
123 let count = (count as usize).min(CAPACITY);
124 let scratch = &raw const SCRATCH;
125 let sizes: Vec<Rect> = (0..count)
126 .map(|index| {
127 unsafe {
129 Rect::new(
130 (*scratch)[index * 4],
131 (*scratch)[index * 4 + 1],
132 (*scratch)[index * 4 + 2],
133 (*scratch)[index * 4 + 3],
134 )
135 }
136 })
137 .collect();
138
139 let slots = crate::grid(
140 &sizes,
141 Rect::new(x, y, w, h),
142 settings(12.0, 0.6, 0.44, padding),
143 );
144 publish(&slots)
145}
146
147#[expect(unsafe_code, reason = "exporting a C symbol")]
148#[unsafe(no_mangle)]
149pub extern "C" fn solium_layout_scroll_to(
150 index: u32,
151 count: u32,
152 x: f64,
153 y: f64,
154 w: f64,
155 h: f64,
156 gap: f64,
157 column: f64,
158 offset: f64,
159) -> f64 {
160 crate::scroll_to(
161 index as usize,
162 count as usize,
163 Rect::new(x, y, w, h),
164 settings(gap, 0.6, column, 24.0),
165 offset,
166 )
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172
173 #[test]
174 #[expect(unsafe_code, reason = "reading the scratch the call just wrote")]
175 fn the_exported_arrangement_matches_the_engine() {
176 let written = solium_layout_master_stack(3, 0.0, 34.0, 1600.0, 866.0, 12.0, 0.6);
177 assert_eq!(written, 3);
178
179 let direct =
180 crate::master_stack(3, Rect::new(0.0, 34.0, 1600.0, 866.0), Settings::default());
181 let scratch = &raw const SCRATCH;
182 for (index, slot) in direct.iter().enumerate() {
183 unsafe {
185 assert!(((*scratch)[index * 4] - slot.x).abs() < f64::EPSILON);
186 assert!(((*scratch)[index * 4 + 2] - slot.w).abs() < f64::EPSILON);
187 }
188 }
189 }
190
191 #[test]
192 fn more_windows_than_the_buffer_holds_are_dropped_not_written_past() {
193 let written = solium_layout_master_stack(500, 0.0, 0.0, 1600.0, 900.0, 12.0, 0.6);
194 assert_eq!(written as usize, CAPACITY);
195 }
196}