@effindomv2/fui-rs 0.1.17 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/Cargo.toml +1 -1
  2. package/README.md +69 -0
  3. package/package.json +1 -1
  4. package/scripts/hostgen/rust-host-events.ts +43 -13
  5. package/src/app.rs +7 -0
  6. package/src/assets.rs +2 -2
  7. package/src/bindings/ui.rs +2 -0
  8. package/src/bridge_callbacks.rs +27 -17
  9. package/src/color.rs +112 -0
  10. package/src/controls/button.rs +1 -0
  11. package/src/controls/checkbox.rs +1 -0
  12. package/src/controls/combobox.rs +5 -3
  13. package/src/controls/dropdown.rs +3 -1
  14. package/src/controls/internal/pressable_labeled_control.rs +1 -0
  15. package/src/controls/internal/text_input_core.rs +7 -3
  16. package/src/controls/radio_button.rs +1 -0
  17. package/src/controls/shared.rs +2 -5
  18. package/src/controls/slider.rs +1 -0
  19. package/src/controls/switch.rs +1 -0
  20. package/src/controls/tests.rs +36 -7
  21. package/src/debug.rs +8 -5
  22. package/src/drag_drop.rs +1 -3
  23. package/src/drawing.rs +8 -0
  24. package/src/event.rs +39 -27
  25. package/src/fetch.rs +21 -7
  26. package/src/ffi.rs +3 -1
  27. package/src/file.rs +88 -59
  28. package/src/host_events.rs +41 -0
  29. package/src/lib.rs +55 -9
  30. package/src/node/core.rs +22 -21
  31. package/src/node/helpers.rs +1 -1
  32. package/src/node/mod.rs +1 -1
  33. package/src/node/scroll_bar.rs +101 -0
  34. package/src/node/scroll_box.rs +7 -0
  35. package/src/node/scroll_view.rs +20 -14
  36. package/src/node/virtual_list.rs +120 -33
  37. package/src/platform.rs +3 -0
  38. package/src/popup_presenter.rs +1 -0
  39. package/src/theme.rs +8 -48
  40. package/src/timers.rs +1 -1
  41. package/src/typography.rs +6 -14
  42. package/src/worker.rs +25 -9
  43. package/src/worker_runtime.rs +61 -17
@@ -16,6 +16,12 @@ pub struct ScrollView {
16
16
  active_animations: Rc<RefCell<ScrollViewAnimationState>>,
17
17
  }
18
18
 
19
+ impl Default for ScrollView {
20
+ fn default() -> Self {
21
+ Self::new()
22
+ }
23
+ }
24
+
19
25
  impl ScrollView {
20
26
  pub fn new() -> Self {
21
27
  let core = Rc::new(RefCell::new(NodeCore::new(NodeKind::ScrollView)));
@@ -473,6 +479,20 @@ impl ScrollView {
473
479
  }
474
480
  }
475
481
 
482
+ impl Node for ScrollView {
483
+ fn retained_node_ref(&self) -> NodeRef {
484
+ NodeRef::from_node(self.core.clone(), self.clone())
485
+ }
486
+
487
+ fn build_self(&self) {
488
+ apply_scroll_view_props(
489
+ self.handle(),
490
+ &self.props.borrow(),
491
+ self.core.borrow().behavior.clone(),
492
+ );
493
+ }
494
+ }
495
+
476
496
  #[cfg(test)]
477
497
  mod tests {
478
498
  use super::*;
@@ -544,17 +564,3 @@ mod tests {
544
564
  )));
545
565
  }
546
566
  }
547
-
548
- impl Node for ScrollView {
549
- fn retained_node_ref(&self) -> NodeRef {
550
- NodeRef::from_node(self.core.clone(), self.clone())
551
- }
552
-
553
- fn build_self(&self) {
554
- apply_scroll_view_props(
555
- self.handle(),
556
- &self.props.borrow(),
557
- self.core.borrow().behavior.clone(),
558
- );
559
- }
560
- }
@@ -4,6 +4,7 @@ use crate::controls::selection_area;
4
4
  use crate::controls::SelectionArea;
5
5
  use crate::frame_scheduler::mark_needs_commit;
6
6
  use crate::signal::Subscription;
7
+ use std::any::Any;
7
8
  use std::cell::{Cell, RefCell};
8
9
  use std::rc::Rc;
9
10
 
@@ -11,9 +12,9 @@ const FULL_SIZE: f32 = 100.0;
11
12
  const DEFAULT_MAX_VISIBLE_ITEMS: i32 = 20;
12
13
  const POOL_OVERSCAN_ITEMS: i32 = 2;
13
14
  const MISSING_BIND_ITEM_MESSAGE: &str =
14
- "VirtualList: item renderer not configured. Call .onBindItem() after construction.";
15
+ "VirtualList: item renderer not configured. Call .on_bind_item() after construction.";
15
16
 
16
- type VirtualListBinder = Rc<dyn Fn(&FlexBox, i32)>;
17
+ type VirtualListBinder = Rc<dyn Fn(usize, i32)>;
17
18
 
18
19
  struct VirtualListInner {
19
20
  root: FlexBox,
@@ -27,18 +28,28 @@ struct VirtualListInner {
27
28
  pool_size: i32,
28
29
  pool_rows: Vec<SelectionArea>,
29
30
  pool_containers: Vec<FlexBox>,
31
+ row_state_owner: RefCell<Option<Rc<dyn Any>>>,
30
32
  pool_item_index_by_row: RefCell<Vec<i32>>,
31
33
  subscriptions: RefCell<Vec<Subscription>>,
32
34
  current_first_visible_index: Cell<i32>,
33
35
  current_last_visible_index: Cell<i32>,
34
36
  }
35
37
 
36
- #[derive(Clone)]
37
- pub struct VirtualList {
38
+ pub struct VirtualList<T = FlexBox> {
38
39
  inner: Rc<VirtualListInner>,
40
+ row_states: Rc<Vec<T>>,
39
41
  }
40
42
 
41
- impl VirtualList {
43
+ impl<T> Clone for VirtualList<T> {
44
+ fn clone(&self) -> Self {
45
+ Self {
46
+ inner: self.inner.clone(),
47
+ row_states: self.row_states.clone(),
48
+ }
49
+ }
50
+ }
51
+
52
+ impl VirtualList<FlexBox> {
42
53
  pub fn new(total_items: i32, item_height: f32) -> Self {
43
54
  Self::with_max_visible(total_items, item_height, DEFAULT_MAX_VISIBLE_ITEMS)
44
55
  }
@@ -105,13 +116,43 @@ impl VirtualList {
105
116
  bottom_spacer,
106
117
  pool_size,
107
118
  pool_rows,
108
- pool_containers,
119
+ pool_containers: pool_containers.clone(),
120
+ row_state_owner: RefCell::new(None),
109
121
  pool_item_index_by_row: RefCell::new(pool_item_index_by_row),
110
122
  subscriptions: RefCell::new(Vec::new()),
111
123
  current_first_visible_index: Cell::new(-1),
112
124
  current_last_visible_index: Cell::new(-1),
113
125
  });
114
- let list = Self { inner };
126
+ let row_states = Rc::new(pool_containers);
127
+ inner
128
+ .row_state_owner
129
+ .replace(Some(row_states.clone() as Rc<dyn Any>));
130
+ let list = Self { inner, row_states };
131
+ list.attach_listeners();
132
+ list
133
+ }
134
+ }
135
+
136
+ impl<T: 'static> VirtualList<T> {
137
+ pub fn item_template<U: 'static>(self, template: impl Fn(&FlexBox) -> U) -> VirtualList<U> {
138
+ let row_states = Rc::new(
139
+ self.inner
140
+ .pool_containers
141
+ .iter()
142
+ .map(template)
143
+ .collect::<Vec<_>>(),
144
+ );
145
+ self.inner
146
+ .row_state_owner
147
+ .replace(Some(row_states.clone() as Rc<dyn Any>));
148
+ *self.inner.bind_item.borrow_mut() = Rc::new(|_, _| panic!("{MISSING_BIND_ITEM_MESSAGE}"));
149
+ self.inner.current_first_visible_index.set(-1);
150
+ self.inner.current_last_visible_index.set(-1);
151
+ self.inner.subscriptions.borrow_mut().clear();
152
+ let list = VirtualList {
153
+ inner: self.inner,
154
+ row_states,
155
+ };
115
156
  list.attach_listeners();
116
157
  list
117
158
  }
@@ -181,19 +222,17 @@ impl VirtualList {
181
222
  self
182
223
  }
183
224
 
184
- pub fn on_bind_item(&self, renderer: impl Fn(&FlexBox, i32) + 'static) -> &Self {
185
- *self.inner.bind_item.borrow_mut() = Rc::new(renderer);
225
+ pub fn on_bind_item(&self, renderer: impl Fn(&T, i32) + 'static) -> &Self {
226
+ let row_states = self.row_states.clone();
227
+ *self.inner.bind_item.borrow_mut() = Rc::new(move |pool_index, item_index| {
228
+ renderer(&row_states[pool_index], item_index);
229
+ });
186
230
  self.inner.current_first_visible_index.set(-1);
187
231
  self.inner.current_last_visible_index.set(-1);
188
232
  self.rebuild_visible_range(true);
189
233
  self
190
234
  }
191
235
 
192
- #[allow(non_snake_case)]
193
- pub fn onBindItem(&self, renderer: impl Fn(&FlexBox, i32) + 'static) -> &Self {
194
- self.on_bind_item(renderer)
195
- }
196
-
197
236
  pub fn update_item_count(&self, next: i32) {
198
237
  self.inner.total_items.set(next.max(0));
199
238
  self.inner
@@ -217,27 +256,33 @@ impl VirtualList {
217
256
 
218
257
  fn attach_listeners(&self) {
219
258
  let weak = Rc::downgrade(&self.inner);
259
+ let weak_row_states = Rc::downgrade(&self.row_states);
220
260
  self.inner
221
261
  .subscriptions
222
262
  .borrow_mut()
223
263
  .push(self.inner.scroll_state.subscribe_offset_y(move || {
224
- if let Some(inner) = weak.upgrade() {
225
- VirtualList { inner }.handle_scroll_offset_changed();
264
+ if let (Some(inner), Some(row_states)) = (weak.upgrade(), weak_row_states.upgrade())
265
+ {
266
+ VirtualList { inner, row_states }.handle_scroll_offset_changed();
226
267
  }
227
268
  }));
228
269
  let weak = Rc::downgrade(&self.inner);
270
+ let weak_row_states = Rc::downgrade(&self.row_states);
229
271
  self.inner.subscriptions.borrow_mut().push(
230
272
  self.inner.scroll_state.subscribe_viewport_height(move || {
231
- if let Some(inner) = weak.upgrade() {
232
- VirtualList { inner }.handle_metrics_changed();
273
+ if let (Some(inner), Some(row_states)) = (weak.upgrade(), weak_row_states.upgrade())
274
+ {
275
+ VirtualList { inner, row_states }.handle_metrics_changed();
233
276
  }
234
277
  }),
235
278
  );
236
279
  let weak = Rc::downgrade(&self.inner);
280
+ let weak_row_states = Rc::downgrade(&self.row_states);
237
281
  self.inner.subscriptions.borrow_mut().push(
238
282
  self.inner.scroll_state.subscribe_content_height(move || {
239
- if let Some(inner) = weak.upgrade() {
240
- VirtualList { inner }.handle_metrics_changed();
283
+ if let (Some(inner), Some(row_states)) = (weak.upgrade(), weak_row_states.upgrade())
284
+ {
285
+ VirtualList { inner, row_states }.handle_metrics_changed();
241
286
  }
242
287
  }),
243
288
  );
@@ -325,8 +370,12 @@ impl VirtualList {
325
370
  let previous_item_index_by_row = self.inner.pool_item_index_by_row.borrow().clone();
326
371
  let visible_items = (last_visible_index - first_visible_index) as usize;
327
372
 
328
- for pool_index in 0..self.inner.pool_size as usize {
329
- let previous_item_index = previous_item_index_by_row[pool_index];
373
+ for (pool_index, previous_item_index) in previous_item_index_by_row
374
+ .iter()
375
+ .copied()
376
+ .enumerate()
377
+ .take(self.inner.pool_size as usize)
378
+ {
330
379
  if previous_item_index != -1
331
380
  && (previous_item_index < first_visible_index
332
381
  || previous_item_index >= last_visible_index)
@@ -340,8 +389,7 @@ impl VirtualList {
340
389
  if pool_index < visible_items {
341
390
  let next_item_index = first_visible_index + pool_index as i32;
342
391
  row_area.height(self.inner.item_height, Unit::Pixel);
343
- let container = &self.inner.pool_containers[pool_index];
344
- self.render_item(container, next_item_index);
392
+ self.render_item(pool_index, next_item_index);
345
393
  self.inner.pool_item_index_by_row.borrow_mut()[pool_index] = next_item_index;
346
394
  } else {
347
395
  self.hide_pool_item(pool_index);
@@ -450,9 +498,9 @@ impl VirtualList {
450
498
  mark_needs_commit();
451
499
  }
452
500
 
453
- fn render_item(&self, container: &FlexBox, index: i32) {
501
+ fn render_item(&self, pool_index: usize, index: i32) {
454
502
  let binder = self.inner.bind_item.borrow().clone();
455
- binder(container, index);
503
+ binder(pool_index, index);
456
504
  }
457
505
 
458
506
  fn max_offset_for_current_viewport(&self) -> f32 {
@@ -478,7 +526,7 @@ impl VirtualList {
478
526
  }
479
527
  }
480
528
 
481
- impl Node for VirtualList {
529
+ impl<T: 'static> Node for VirtualList<T> {
482
530
  fn retained_node_ref(&self) -> NodeRef {
483
531
  let list = self.clone();
484
532
  self.inner
@@ -507,22 +555,24 @@ impl Node for VirtualList {
507
555
  }
508
556
  }
509
557
 
510
- impl HasFlexBoxRoot for VirtualList {
558
+ impl<T: 'static> HasFlexBoxRoot for VirtualList<T> {
511
559
  fn flex_box_root(&self) -> &FlexBox {
512
560
  &self.inner.root
513
561
  }
514
562
  }
515
563
 
516
- impl ThemeBindable for VirtualList {
564
+ impl<T: 'static> ThemeBindable for VirtualList<T> {
517
565
  fn theme_binding_node(&self) -> NodeRef {
518
566
  self.inner.root.retained_node_ref()
519
567
  }
520
568
 
521
569
  fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
522
570
  let weak = Rc::downgrade(&self.inner);
571
+ let weak_row_states = Rc::downgrade(&self.row_states);
523
572
  Box::new(move || {
524
573
  Some(VirtualList {
525
574
  inner: weak.upgrade()?,
575
+ row_states: weak_row_states.upgrade()?,
526
576
  })
527
577
  })
528
578
  }
@@ -583,7 +633,7 @@ mod tests {
583
633
  let list = VirtualList::new(10_000, 20.0);
584
634
  let captured_indices = rendered_indices.clone();
585
635
  let captured_labels = labels.clone();
586
- list.onBindItem(move |container, index| {
636
+ list.on_bind_item(move |container, index| {
587
637
  tracked_bind_virtual_list_item(&captured_indices, &captured_labels, container, index);
588
638
  });
589
639
  list.width(180.0, Unit::Pixel);
@@ -608,7 +658,7 @@ mod tests {
608
658
  let list = VirtualList::new(10_000, 20.0);
609
659
  let captured_indices = rendered_indices.clone();
610
660
  let captured_labels = labels.clone();
611
- list.onBindItem(move |container, index| {
661
+ list.on_bind_item(move |container, index| {
612
662
  tracked_bind_virtual_list_item(&captured_indices, &captured_labels, container, index);
613
663
  });
614
664
  list.width(180.0, Unit::Pixel);
@@ -653,7 +703,7 @@ mod tests {
653
703
  let labels = Rc::new(RefCell::new(HashMap::new()));
654
704
  let list = VirtualList::new(10_000, 24.0);
655
705
  let captured_labels = labels.clone();
656
- list.onBindItem(move |container, index| {
706
+ list.on_bind_item(move |container, index| {
657
707
  static_bind_virtual_list_item(&captured_labels, container, index);
658
708
  });
659
709
  list.height(120.0, Unit::Pixel);
@@ -676,7 +726,7 @@ mod tests {
676
726
  let list = VirtualList::new(10_000, 20.0);
677
727
  let captured_indices = rendered_indices.clone();
678
728
  let captured_labels = labels.clone();
679
- list.onBindItem(move |container, index| {
729
+ list.on_bind_item(move |container, index| {
680
730
  tracked_bind_virtual_list_item(&captured_indices, &captured_labels, container, index);
681
731
  });
682
732
  list.width(180.0, Unit::Pixel);
@@ -690,4 +740,41 @@ mod tests {
690
740
  assert_eq!(rendered[rendered.len() - 1], 5);
691
741
  list.dispose();
692
742
  }
743
+
744
+ #[test]
745
+ fn typed_item_template_creates_one_retained_state_per_pool_row_and_rebinds_it() {
746
+ #[derive(Clone)]
747
+ struct Row {
748
+ label: TextNode,
749
+ }
750
+
751
+ ffi::test::reset();
752
+ let template_count = Rc::new(Cell::new(0));
753
+ let captured_template_count = template_count.clone();
754
+ let list = VirtualList::with_max_visible(10_000, 20.0, 4).item_template(move |container| {
755
+ captured_template_count.set(captured_template_count.get() + 1);
756
+ let label = text("");
757
+ container.child(&label);
758
+ Row { label }
759
+ });
760
+ let bound_indices = Rc::new(RefCell::new(Vec::new()));
761
+ let captured_indices = bound_indices.clone();
762
+ list.on_bind_item(move |row, index| {
763
+ captured_indices.borrow_mut().push(index);
764
+ row.label.text(format!("typed item {index}"));
765
+ });
766
+ list.height(60.0, Unit::Pixel);
767
+ Application::mount(list.clone());
768
+
769
+ assert_eq!(template_count.get(), 6);
770
+ bound_indices.borrow_mut().clear();
771
+ ffi::test::reset();
772
+ list.scroll_state().set_offset_y(40.0);
773
+
774
+ assert_eq!(&*bound_indices.borrow(), &[2, 3, 4, 5]);
775
+ assert!(!ffi::test::take_calls()
776
+ .iter()
777
+ .any(|call| matches!(call, Call::CreateNode { .. } | Call::DeleteNode { .. })));
778
+ Application::unmount();
779
+ }
693
780
  }
package/src/platform.rs CHANGED
@@ -260,6 +260,9 @@ pub fn show_open_folder_dialog(
260
260
  }
261
261
 
262
262
  #[cfg(feature = "native-runtime")]
263
+ /// # Safety
264
+ /// `payload` must reference at least `payload_length` readable bytes when
265
+ /// `payload_length` is non-zero.
263
266
  #[no_mangle]
264
267
  pub unsafe extern "C" fn __fui_complete_native_file_dialog(
265
268
  request_id: u64,
@@ -189,6 +189,7 @@ impl PopupPresenter {
189
189
  );
190
190
  }
191
191
 
192
+ #[allow(clippy::too_many_arguments)]
192
193
  pub fn show_anchored_with_placement(
193
194
  &self,
194
195
  anchor_x: f32,
package/src/theme.rs CHANGED
@@ -1,12 +1,15 @@
1
1
  use crate::generated::framework_host_services;
2
+ use crate::color::{
3
+ color_alpha, color_blue, color_green, color_red, mix_color, rgb, rgba, with_alpha,
4
+ };
2
5
  use crate::signal::{Callback, Signal, SubscriptionGuard};
3
6
  use crate::typography::{FontFamily, FontStack};
4
7
  use std::cell::RefCell;
5
8
  use std::rc::Rc;
6
9
 
7
- const DEFAULT_ACCENT_COLOR: u32 = 0x2563EBFF;
8
- const WHITE: u32 = 0xFFFFFFFF;
9
- const BLACK: u32 = 0x000000FF;
10
+ const DEFAULT_ACCENT_COLOR: u32 = rgb(0x25, 0x63, 0xeb);
11
+ const WHITE: u32 = rgb(0xff, 0xff, 0xff);
12
+ const BLACK: u32 = rgb(0x00, 0x00, 0x00);
10
13
 
11
14
  #[derive(Clone, Copy, Debug, PartialEq, Eq)]
12
15
  pub struct Colors {
@@ -166,49 +169,6 @@ fn default_fonts() -> Fonts {
166
169
  }
167
170
  }
168
171
 
169
- const fn rgba(r: u32, g: u32, b: u32, a: u32) -> u32 {
170
- (r << 24) | (g << 16) | (b << 8) | a
171
- }
172
-
173
- fn color_red(color: u32) -> u32 {
174
- (color >> 24) & 0xff
175
- }
176
- fn color_green(color: u32) -> u32 {
177
- (color >> 16) & 0xff
178
- }
179
- fn color_blue(color: u32) -> u32 {
180
- (color >> 8) & 0xff
181
- }
182
- fn color_alpha(color: u32) -> u32 {
183
- color & 0xff
184
- }
185
- fn clamp_unit(value: f32) -> f32 {
186
- value.clamp(0.0, 1.0)
187
- }
188
-
189
- fn mix_channel(from: u32, to: u32, amount: f32) -> u32 {
190
- let weight = clamp_unit(amount);
191
- (from as f32 + ((to as f32 - from as f32) * weight)).round() as u32
192
- }
193
-
194
- fn mix_color(from: u32, to: u32, amount: f32) -> u32 {
195
- rgba(
196
- mix_channel(color_red(from), color_red(to), amount),
197
- mix_channel(color_green(from), color_green(to), amount),
198
- mix_channel(color_blue(from), color_blue(to), amount),
199
- mix_channel(color_alpha(from), color_alpha(to), amount),
200
- )
201
- }
202
-
203
- fn with_alpha(color: u32, alpha: u32) -> u32 {
204
- rgba(
205
- color_red(color),
206
- color_green(color),
207
- color_blue(color),
208
- alpha,
209
- )
210
- }
211
-
212
172
  fn normalize_accent_color(color: u32) -> u32 {
213
173
  if color == 0 {
214
174
  return DEFAULT_ACCENT_COLOR;
@@ -517,12 +477,12 @@ trait Pipe: Sized {
517
477
 
518
478
  impl<T> Pipe for T {}
519
479
 
520
- #[no_mangle]
480
+ #[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
521
481
  pub extern "C" fn __fui_on_system_dark_mode_changed(is_dark: bool) {
522
482
  handle_system_dark_mode_changed(is_dark);
523
483
  }
524
484
 
525
- #[no_mangle]
485
+ #[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
526
486
  pub extern "C" fn __fui_on_system_accent_color_changed(color: u32) {
527
487
  handle_system_accent_color_changed(color);
528
488
  }
package/src/timers.rs CHANGED
@@ -58,7 +58,7 @@ pub fn cancel_all_timers() {
58
58
  ACTIVE_TIMERS.with(|timers| timers.borrow_mut().clear());
59
59
  }
60
60
 
61
- #[no_mangle]
61
+ #[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
62
62
  pub extern "C" fn __fui_on_timer(timer_id: u32) {
63
63
  let callback = ACTIVE_TIMERS.with(|timers| timers.borrow_mut().remove(&timer_id));
64
64
  if let Some(callback) = callback {
package/src/typography.rs CHANGED
@@ -15,32 +15,22 @@ thread_local! {
15
15
  static REGISTERED_FONT_FALLBACKS: RefCell<Vec<(u32, u32)>> = const { RefCell::new(Vec::new()) };
16
16
  }
17
17
 
18
- #[derive(Clone, Copy, Debug, PartialEq, Eq)]
18
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
19
19
  pub enum FontStyle {
20
+ #[default]
20
21
  Normal = 0,
21
22
  Italic = 1,
22
23
  }
23
24
 
24
- impl Default for FontStyle {
25
- fn default() -> Self {
26
- Self::Normal
27
- }
28
- }
29
-
30
- #[derive(Clone, Copy, Debug, PartialEq, Eq)]
25
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
31
26
  pub enum FontWeight {
27
+ #[default]
32
28
  Regular = 400,
33
29
  Medium = 500,
34
30
  Semibold = 600,
35
31
  Bold = 700,
36
32
  }
37
33
 
38
- impl Default for FontWeight {
39
- fn default() -> Self {
40
- Self::Regular
41
- }
42
- }
43
-
44
34
  #[derive(Clone, Debug, PartialEq, Eq)]
45
35
  pub struct FontFaceLoadedEventArgs {
46
36
  pub font: FontFace,
@@ -308,6 +298,7 @@ pub struct FontFamily {
308
298
  }
309
299
 
310
300
  impl FontFamily {
301
+ #[allow(clippy::too_many_arguments)]
311
302
  pub fn new(
312
303
  regular_stack: FontStack,
313
304
  bold_stack: Option<FontStack>,
@@ -331,6 +322,7 @@ impl FontFamily {
331
322
  }
332
323
 
333
324
  #[cfg(test)]
325
+ #[allow(clippy::too_many_arguments)]
334
326
  pub(crate) fn from_ids(
335
327
  regular: u32,
336
328
  bold: u32,
package/src/worker.rs CHANGED
@@ -108,7 +108,7 @@ impl Worker {
108
108
  if already_started {
109
109
  return self;
110
110
  }
111
- if input.as_bytes().len() > MAX_WORKER_START_INPUT_BYTES {
111
+ if input.len() > MAX_WORKER_START_INPUT_BYTES {
112
112
  let (worker_id, callback) = {
113
113
  let mut inner = self.inner.borrow_mut();
114
114
  inner.started = true;
@@ -186,8 +186,14 @@ fn with_active_worker(worker_id: u32, callback: impl FnOnce(&mut WorkerInner)) {
186
186
  callback(&mut inner);
187
187
  }
188
188
 
189
- #[no_mangle]
190
- pub extern "C" fn __fui_on_worker_progress(worker_id: u32, text_ptr: *const u8, text_len: u32) {
189
+ #[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
190
+ /// # Safety
191
+ /// `text_ptr` must be null for an empty message or point to `text_len` readable bytes.
192
+ pub unsafe extern "C" fn __fui_on_worker_progress(
193
+ worker_id: u32,
194
+ text_ptr: *const u8,
195
+ text_len: u32,
196
+ ) {
191
197
  let message = if text_ptr.is_null() || text_len == 0 {
192
198
  String::new()
193
199
  } else {
@@ -204,8 +210,14 @@ pub extern "C" fn __fui_on_worker_progress(worker_id: u32, text_ptr: *const u8,
204
210
  });
205
211
  }
206
212
 
207
- #[no_mangle]
208
- pub extern "C" fn __fui_on_worker_complete(worker_id: u32, text_ptr: *const u8, text_len: u32) {
213
+ #[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
214
+ /// # Safety
215
+ /// `text_ptr` must be null for an empty result or point to `text_len` readable bytes.
216
+ pub unsafe extern "C" fn __fui_on_worker_complete(
217
+ worker_id: u32,
218
+ text_ptr: *const u8,
219
+ text_len: u32,
220
+ ) {
209
221
  let result = if text_ptr.is_null() || text_len == 0 {
210
222
  String::new()
211
223
  } else {
@@ -228,8 +240,10 @@ pub extern "C" fn __fui_on_worker_complete(worker_id: u32, text_ptr: *const u8,
228
240
  }
229
241
  }
230
242
 
231
- #[no_mangle]
232
- pub extern "C" fn __fui_on_worker_error(worker_id: u32, text_ptr: *const u8, text_len: u32) {
243
+ #[cfg_attr(not(feature = "worker-runtime"), no_mangle)]
244
+ /// # Safety
245
+ /// `text_ptr` must be null for an empty message or point to `text_len` readable bytes.
246
+ pub unsafe extern "C" fn __fui_on_worker_error(worker_id: u32, text_ptr: *const u8, text_len: u32) {
233
247
  let message = if text_ptr.is_null() || text_len == 0 {
234
248
  String::new()
235
249
  } else {
@@ -300,8 +314,10 @@ mod tests {
300
314
  result_clone.replace(event.result);
301
315
  })
302
316
  .start("hello");
303
- super::__fui_on_worker_progress(1, b"25%".as_ptr(), 3);
304
- super::__fui_on_worker_complete(1, b"done".as_ptr(), 4);
317
+ unsafe {
318
+ super::__fui_on_worker_progress(1, b"25%".as_ptr(), 3);
319
+ super::__fui_on_worker_complete(1, b"done".as_ptr(), 4);
320
+ }
305
321
  assert_eq!(&*progress.borrow(), "25%");
306
322
  assert_eq!(&*result.borrow(), "done");
307
323
  }