Skip to main content

slint_interpreter/
ffi.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4// cSpell: ignore stru
5use crate::dynamic_item_tree::ErasedItemTreeBox;
6
7use super::*;
8use core::ptr::NonNull;
9use i_slint_core::model::{Model, ModelNotify, SharedVectorModel};
10use i_slint_core::slice::Slice;
11use i_slint_core::window::WindowAdapter;
12use std::ffi::c_void;
13use vtable::VRef;
14
15/// Construct a new Value in the given memory location
16#[unsafe(no_mangle)]
17pub extern "C" fn slint_interpreter_value_new() -> Box<Value> {
18    Box::new(Value::default())
19}
20
21/// Construct a new Value in the given memory location
22#[unsafe(no_mangle)]
23pub extern "C" fn slint_interpreter_value_clone(other: &Value) -> Box<Value> {
24    Box::new(other.clone())
25}
26
27/// Destruct the value in that memory location
28#[unsafe(no_mangle)]
29pub extern "C" fn slint_interpreter_value_destructor(val: Box<Value>) {
30    drop(val);
31}
32
33#[unsafe(no_mangle)]
34pub extern "C" fn slint_interpreter_value_eq(a: &Value, b: &Value) -> bool {
35    a == b
36}
37
38/// Construct a new Value in the given memory location as string
39#[unsafe(no_mangle)]
40pub extern "C" fn slint_interpreter_value_new_string(str: &SharedString) -> Box<Value> {
41    Box::new(Value::String(str.clone()))
42}
43
44/// Construct a new Value in the given memory location as double
45#[unsafe(no_mangle)]
46pub extern "C" fn slint_interpreter_value_new_double(double: f64) -> Box<Value> {
47    Box::new(Value::Number(double))
48}
49
50/// Construct a new Value in the given memory location as bool
51#[unsafe(no_mangle)]
52pub extern "C" fn slint_interpreter_value_new_bool(b: bool) -> Box<Value> {
53    Box::new(Value::Bool(b))
54}
55
56/// Construct a new Value in the given memory location as array model
57#[unsafe(no_mangle)]
58pub extern "C" fn slint_interpreter_value_new_array_model(
59    a: &SharedVector<Box<Value>>,
60) -> Box<Value> {
61    let vec = a.iter().map(|vb| vb.as_ref().clone()).collect::<SharedVector<_>>();
62    Box::new(Value::Model(ModelRc::new(SharedVectorModel::from(vec))))
63}
64
65/// Construct a new Value in the given memory location as Brush
66#[unsafe(no_mangle)]
67pub extern "C" fn slint_interpreter_value_new_brush(brush: &Brush) -> Box<Value> {
68    Box::new(Value::Brush(brush.clone()))
69}
70
71/// Construct a new Value in the given memory location as Struct
72#[unsafe(no_mangle)]
73pub extern "C" fn slint_interpreter_value_new_struct(struc: &StructOpaque) -> Box<Value> {
74    Box::new(Value::Struct(struc.as_struct().clone()))
75}
76
77/// Construct a new Value in the given memory location as image
78#[unsafe(no_mangle)]
79pub extern "C" fn slint_interpreter_value_new_image(img: &Image) -> Box<Value> {
80    Box::new(Value::Image(img.clone()))
81}
82
83/// Construct a new Value containing a model in the given memory location
84#[unsafe(no_mangle)]
85pub unsafe extern "C" fn slint_interpreter_value_new_model(
86    model: NonNull<u8>,
87    vtable: &ModelAdaptorVTable,
88) -> Box<Value> {
89    Box::new(Value::Model(ModelRc::new(ModelAdaptorWrapper(unsafe {
90        vtable::VBox::from_raw(NonNull::from(vtable), model)
91    }))))
92}
93
94/// If the value contains a model set from [`slint_interpreter_value_new_model]` with the same vtable pointer,
95/// return the model that was set.
96/// Returns a null ptr otherwise
97#[unsafe(no_mangle)]
98pub extern "C" fn slint_interpreter_value_to_model(
99    val: &Value,
100    vtable: &ModelAdaptorVTable,
101) -> *const u8 {
102    if let Value::Model(m) = val
103        && let Some(m) = m.as_any().downcast_ref::<ModelAdaptorWrapper>()
104        && core::ptr::eq(m.0.get_vtable() as *const _, vtable as *const _)
105    {
106        return m.0.as_ptr();
107    }
108    core::ptr::null()
109}
110
111#[unsafe(no_mangle)]
112pub extern "C" fn slint_interpreter_value_type(val: &Value) -> ValueType {
113    val.value_type()
114}
115
116#[unsafe(no_mangle)]
117pub extern "C" fn slint_interpreter_value_to_string(val: &Value) -> Option<&SharedString> {
118    match val {
119        Value::String(v) => Some(v),
120        _ => None,
121    }
122}
123
124#[unsafe(no_mangle)]
125pub extern "C" fn slint_interpreter_value_to_number(val: &Value) -> Option<&f64> {
126    match val {
127        Value::Number(v) => Some(v),
128        _ => None,
129    }
130}
131
132#[unsafe(no_mangle)]
133pub extern "C" fn slint_interpreter_value_to_bool(val: &Value) -> Option<&bool> {
134    match val {
135        Value::Bool(v) => Some(v),
136        _ => None,
137    }
138}
139
140/// Extracts a `SharedVector<ValueOpaque>` out of the given value `val`, writes that into the
141/// `out` parameter and returns true; returns false if the value does not hold an extractable
142/// array.
143#[unsafe(no_mangle)]
144#[allow(clippy::borrowed_box)]
145pub extern "C" fn slint_interpreter_value_to_array(
146    val: &Box<Value>,
147    out: &mut SharedVector<Box<Value>>,
148) -> bool {
149    match val.as_ref() {
150        Value::Model(m) => {
151            let vec = m.iter().map(Box::new).collect::<SharedVector<_>>();
152            *out = vec;
153            true
154        }
155        _ => false,
156    }
157}
158
159#[unsafe(no_mangle)]
160pub extern "C" fn slint_interpreter_value_to_brush(val: &Value) -> Option<&Brush> {
161    match val {
162        Value::Brush(b) => Some(b),
163        _ => None,
164    }
165}
166
167#[unsafe(no_mangle)]
168pub extern "C" fn slint_interpreter_value_to_struct(val: &Value) -> *const StructOpaque {
169    match val {
170        Value::Struct(s) => s as *const Struct as *const StructOpaque,
171        _ => std::ptr::null(),
172    }
173}
174
175#[unsafe(no_mangle)]
176pub extern "C" fn slint_interpreter_value_to_image(val: &Value) -> Option<&Image> {
177    match val {
178        Value::Image(img) => Some(img),
179        _ => None,
180    }
181}
182
183/// Construct a new Value containing a DataTransfer
184#[unsafe(no_mangle)]
185pub extern "C" fn slint_interpreter_value_new_data_transfer(
186    data: &i_slint_core::data_transfer::DataTransfer,
187) -> Box<Value> {
188    Box::new(Value::DataTransfer(data.clone()))
189}
190
191#[unsafe(no_mangle)]
192pub extern "C" fn slint_interpreter_value_to_data_transfer(
193    val: &Value,
194) -> Option<&i_slint_core::data_transfer::DataTransfer> {
195    match val {
196        Value::DataTransfer(data) => Some(data),
197        _ => None,
198    }
199}
200
201/// Construct a new Value containing a Keys
202#[unsafe(no_mangle)]
203pub extern "C" fn slint_interpreter_value_new_keys(keys: &i_slint_core::input::Keys) -> Box<Value> {
204    Box::new(Value::Keys(keys.clone()))
205}
206
207#[unsafe(no_mangle)]
208pub extern "C" fn slint_interpreter_value_to_keys(
209    val: &Value,
210) -> Option<&i_slint_core::input::Keys> {
211    match val {
212        Value::Keys(keys) => Some(keys),
213        _ => None,
214    }
215}
216
217/// Construct a new Value containing a StyledText
218#[unsafe(no_mangle)]
219pub extern "C" fn slint_interpreter_value_new_styled_text(
220    text: &i_slint_core::styled_text::StyledText,
221) -> Box<Value> {
222    Box::new(Value::StyledText(text.clone()))
223}
224
225#[unsafe(no_mangle)]
226pub extern "C" fn slint_interpreter_value_to_styled_text(
227    val: &Value,
228) -> Option<&i_slint_core::styled_text::StyledText> {
229    match val {
230        Value::StyledText(text) => Some(text),
231        _ => None,
232    }
233}
234
235#[unsafe(no_mangle)]
236pub extern "C" fn slint_interpreter_value_enum_to_string(
237    val: &Value,
238    result: &mut SharedString,
239) -> bool {
240    match val {
241        Value::EnumerationValue(_, value) => {
242            *result = SharedString::from(value);
243            true
244        }
245        _ => false,
246    }
247}
248
249#[unsafe(no_mangle)]
250pub extern "C" fn slint_interpreter_value_new_enum(
251    name: Slice<u8>,
252    value: Slice<u8>,
253) -> Box<Value> {
254    Box::new(Value::EnumerationValue(
255        std::str::from_utf8(&name).unwrap().to_string(),
256        std::str::from_utf8(&value).unwrap().to_string(),
257    ))
258}
259
260#[repr(C)]
261#[cfg(target_pointer_width = "64")]
262pub struct StructOpaque([usize; 6]);
263#[repr(C)]
264#[cfg(target_pointer_width = "32")]
265pub struct StructOpaque([u64; 4]);
266const _: [(); std::mem::size_of::<StructOpaque>()] = [(); std::mem::size_of::<Struct>()];
267const _: [(); std::mem::align_of::<StructOpaque>()] = [(); std::mem::align_of::<Struct>()];
268
269impl StructOpaque {
270    fn as_struct(&self) -> &Struct {
271        // Safety: there should be no way to construct a StructOpaque without it holding an actual Struct
272        unsafe { std::mem::transmute::<&StructOpaque, &Struct>(self) }
273    }
274    fn as_struct_mut(&mut self) -> &mut Struct {
275        // Safety: there should be no way to construct a StructOpaque without it holding an actual Struct
276        unsafe { std::mem::transmute::<&mut StructOpaque, &mut Struct>(self) }
277    }
278}
279
280/// Construct a new Struct in the given memory location
281#[unsafe(no_mangle)]
282pub unsafe extern "C" fn slint_interpreter_struct_new(val: *mut StructOpaque) {
283    unsafe { std::ptr::write(val as *mut Struct, Struct::default()) }
284}
285
286/// Construct a new Struct in the given memory location
287#[unsafe(no_mangle)]
288pub unsafe extern "C" fn slint_interpreter_struct_clone(
289    other: &StructOpaque,
290    val: *mut StructOpaque,
291) {
292    unsafe { std::ptr::write(val as *mut Struct, other.as_struct().clone()) }
293}
294
295/// Destruct the struct in that memory location
296#[unsafe(no_mangle)]
297pub unsafe extern "C" fn slint_interpreter_struct_destructor(val: *mut StructOpaque) {
298    drop(unsafe { std::ptr::read(val as *mut Struct) })
299}
300
301#[unsafe(no_mangle)]
302pub extern "C" fn slint_interpreter_struct_get_field(
303    stru: &StructOpaque,
304    name: Slice<u8>,
305) -> *mut Value {
306    if let Some(value) = stru.as_struct().get_field(std::str::from_utf8(&name).unwrap()) {
307        Box::into_raw(Box::new(value.clone()))
308    } else {
309        std::ptr::null_mut()
310    }
311}
312
313#[unsafe(no_mangle)]
314pub extern "C" fn slint_interpreter_struct_set_field(
315    stru: &mut StructOpaque,
316    name: Slice<u8>,
317    value: &Value,
318) {
319    stru.as_struct_mut().set_field(std::str::from_utf8(&name).unwrap().into(), value.clone())
320}
321
322type StructIterator<'a> = std::collections::hash_map::Iter<'a, SmolStr, Value>;
323#[repr(C)]
324pub struct StructIteratorOpaque<'a>([usize; 5], std::marker::PhantomData<StructIterator<'a>>);
325const _: [(); std::mem::size_of::<StructIteratorOpaque>()] =
326    [(); std::mem::size_of::<StructIterator>()];
327const _: [(); std::mem::align_of::<StructIteratorOpaque>()] =
328    [(); std::mem::align_of::<StructIterator>()];
329
330#[unsafe(no_mangle)]
331pub unsafe extern "C" fn slint_interpreter_struct_iterator_destructor(
332    val: *mut StructIteratorOpaque,
333) {
334    #[allow(clippy::drop_non_drop)] // the drop is a no-op but we still want to be explicit
335    drop(unsafe { std::ptr::read(val as *mut StructIterator) })
336}
337
338/// Advance the iterator and return the next value, or a null pointer
339#[unsafe(no_mangle)]
340pub unsafe extern "C" fn slint_interpreter_struct_iterator_next<'a>(
341    iter: &'a mut StructIteratorOpaque,
342    k: &mut Slice<'a, u8>,
343) -> *mut Value {
344    if let Some((str, val)) =
345        unsafe { (*(iter as *mut StructIteratorOpaque as *mut StructIterator)).next() }
346    {
347        *k = Slice::from_slice(str.as_bytes());
348        Box::into_raw(Box::new(val.clone()))
349    } else {
350        *k = Slice::default();
351        std::ptr::null_mut()
352    }
353}
354
355#[unsafe(no_mangle)]
356pub extern "C" fn slint_interpreter_struct_make_iter(
357    stru: &StructOpaque,
358) -> StructIteratorOpaque<'_> {
359    let ret_it: StructIterator = stru.as_struct().0.iter();
360    unsafe {
361        let mut r = std::mem::MaybeUninit::<StructIteratorOpaque>::uninit();
362        std::ptr::write(r.as_mut_ptr() as *mut StructIterator, ret_it);
363        r.assume_init()
364    }
365}
366
367/// Get a property. Returns a null pointer if the property does not exist.
368#[unsafe(no_mangle)]
369pub extern "C" fn slint_interpreter_component_instance_get_property(
370    inst: &ErasedItemTreeBox,
371    name: Slice<u8>,
372) -> *mut Value {
373    generativity::make_guard!(guard);
374    let comp = inst.unerase(guard);
375    match comp
376        .description()
377        .get_property(comp.borrow(), &normalize_identifier(std::str::from_utf8(&name).unwrap()))
378    {
379        Ok(val) => Box::into_raw(Box::new(val)),
380        Err(_) => std::ptr::null_mut(),
381    }
382}
383
384#[unsafe(no_mangle)]
385pub extern "C" fn slint_interpreter_component_instance_set_property(
386    inst: &ErasedItemTreeBox,
387    name: Slice<u8>,
388    val: &Value,
389) -> bool {
390    generativity::make_guard!(guard);
391    let comp = inst.unerase(guard);
392    comp.description()
393        .set_property(
394            comp.borrow(),
395            &normalize_identifier(std::str::from_utf8(&name).unwrap()),
396            val.clone(),
397        )
398        .is_ok()
399}
400
401/// Invoke a callback or function. Returns raw boxed value on success and null ptr on failure.
402#[unsafe(no_mangle)]
403pub extern "C" fn slint_interpreter_component_instance_invoke(
404    inst: &ErasedItemTreeBox,
405    name: Slice<u8>,
406    args: Slice<Box<Value>>,
407) -> *mut Value {
408    let args = args.iter().map(|vb| vb.as_ref().clone()).collect::<Vec<_>>();
409    generativity::make_guard!(guard);
410    let comp = inst.unerase(guard);
411    match comp.description().invoke(
412        comp.borrow(),
413        &normalize_identifier(std::str::from_utf8(&name).unwrap()),
414        args.as_slice(),
415    ) {
416        Ok(val) => Box::into_raw(Box::new(val)),
417        Err(_) => std::ptr::null_mut(),
418    }
419}
420
421/// Wrap the user_data provided by the native code and call the drop function on Drop.
422///
423/// Safety: user_data must be a pointer that can be destroyed by the drop_user_data function.
424/// callback must be a valid callback that initialize the `ret`
425pub struct CallbackUserData {
426    user_data: *mut c_void,
427    drop_user_data: Option<extern "C" fn(*mut c_void)>,
428    callback: extern "C" fn(user_data: *mut c_void, arg: Slice<Box<Value>>) -> Box<Value>,
429}
430
431impl Drop for CallbackUserData {
432    fn drop(&mut self) {
433        if let Some(x) = self.drop_user_data {
434            x(self.user_data)
435        }
436    }
437}
438
439impl CallbackUserData {
440    pub unsafe fn new(
441        user_data: *mut c_void,
442        drop_user_data: Option<extern "C" fn(*mut c_void)>,
443        callback: extern "C" fn(user_data: *mut c_void, arg: Slice<Box<Value>>) -> Box<Value>,
444    ) -> Self {
445        Self { user_data, drop_user_data, callback }
446    }
447
448    pub fn call(&self, args: &[Value]) -> Value {
449        let args = args.iter().map(|v| v.clone().into()).collect::<Vec<_>>();
450        (self.callback)(self.user_data, Slice::from_slice(args.as_ref())).as_ref().clone()
451    }
452}
453
454/// Set a handler for the callback.
455/// The `callback` function must initialize the `ret` (the `ret` passed to the callback is initialized and is assumed initialized after the function)
456#[unsafe(no_mangle)]
457pub unsafe extern "C" fn slint_interpreter_component_instance_set_callback(
458    inst: &ErasedItemTreeBox,
459    name: Slice<u8>,
460    callback: extern "C" fn(user_data: *mut c_void, arg: Slice<Box<Value>>) -> Box<Value>,
461    user_data: *mut c_void,
462    drop_user_data: Option<extern "C" fn(*mut c_void)>,
463) -> bool {
464    let ud = unsafe { CallbackUserData::new(user_data, drop_user_data, callback) };
465
466    generativity::make_guard!(guard);
467    let comp = inst.unerase(guard);
468    comp.description()
469        .set_callback_handler(
470            comp.borrow(),
471            &normalize_identifier(std::str::from_utf8(&name).unwrap()),
472            Box::new(move |args| ud.call(args)),
473        )
474        .is_ok()
475}
476
477/// Get a global property. Returns a raw boxed value on success; nullptr otherwise.
478#[unsafe(no_mangle)]
479pub unsafe extern "C" fn slint_interpreter_component_instance_get_global_property(
480    inst: &ErasedItemTreeBox,
481    global: Slice<u8>,
482    property_name: Slice<u8>,
483) -> *mut Value {
484    generativity::make_guard!(guard);
485    let comp = inst.unerase(guard);
486    match comp
487        .description()
488        .get_global(comp.borrow(), &normalize_identifier(std::str::from_utf8(&global).unwrap()))
489        .and_then(|g| {
490            g.as_ref()
491                .get_property(&normalize_identifier(std::str::from_utf8(&property_name).unwrap()))
492        }) {
493        Ok(val) => Box::into_raw(Box::new(val)),
494        Err(_) => std::ptr::null_mut(),
495    }
496}
497
498#[unsafe(no_mangle)]
499pub extern "C" fn slint_interpreter_component_instance_set_global_property(
500    inst: &ErasedItemTreeBox,
501    global: Slice<u8>,
502    property_name: Slice<u8>,
503    val: &Value,
504) -> bool {
505    generativity::make_guard!(guard);
506    let comp = inst.unerase(guard);
507    comp.description()
508        .get_global(comp.borrow(), &normalize_identifier(std::str::from_utf8(&global).unwrap()))
509        .and_then(|g| {
510            g.as_ref()
511                .set_property(
512                    &normalize_identifier(std::str::from_utf8(&property_name).unwrap()),
513                    val.clone(),
514                )
515                .map_err(|_| ())
516        })
517        .is_ok()
518}
519
520/// The `callback` function must initialize the `ret` (the `ret` passed to the callback is initialized and is assumed initialized after the function)
521#[unsafe(no_mangle)]
522pub unsafe extern "C" fn slint_interpreter_component_instance_set_global_callback(
523    inst: &ErasedItemTreeBox,
524    global: Slice<u8>,
525    name: Slice<u8>,
526    callback: extern "C" fn(user_data: *mut c_void, arg: Slice<Box<Value>>) -> Box<Value>,
527    user_data: *mut c_void,
528    drop_user_data: Option<extern "C" fn(*mut c_void)>,
529) -> bool {
530    let ud = unsafe { CallbackUserData::new(user_data, drop_user_data, callback) };
531
532    generativity::make_guard!(guard);
533    let comp = inst.unerase(guard);
534    comp.description()
535        .get_global(comp.borrow(), &normalize_identifier(std::str::from_utf8(&global).unwrap()))
536        .and_then(|g| {
537            g.as_ref().set_callback_handler(
538                &normalize_identifier(std::str::from_utf8(&name).unwrap()),
539                Box::new(move |args| ud.call(args)),
540            )
541        })
542        .is_ok()
543}
544
545/// Invoke a global callback or function. Returns raw boxed value on success; nullptr otherwise.
546#[unsafe(no_mangle)]
547pub unsafe extern "C" fn slint_interpreter_component_instance_invoke_global(
548    inst: &ErasedItemTreeBox,
549    global: Slice<u8>,
550    callable_name: Slice<u8>,
551    args: Slice<Box<Value>>,
552) -> *mut Value {
553    let args = args.iter().map(|vb| vb.as_ref().clone()).collect::<Vec<_>>();
554    generativity::make_guard!(guard);
555    let comp = inst.unerase(guard);
556    let callable_name = std::str::from_utf8(&callable_name).unwrap();
557    match comp
558        .description()
559        .get_global(comp.borrow(), &normalize_identifier(std::str::from_utf8(&global).unwrap()))
560        .and_then(|g| {
561            if matches!(
562                comp.description()
563                    .original
564                    .root_element
565                    .borrow()
566                    .lookup_property(callable_name)
567                    .property_type,
568                i_slint_compiler::langtype::Type::Function { .. }
569            ) {
570                g.as_ref()
571                    .eval_function(&normalize_identifier(callable_name), args.as_slice().to_vec())
572            } else {
573                g.as_ref().invoke_callback(&normalize_identifier(callable_name), args.as_slice())
574            }
575        }) {
576        Ok(val) => Box::into_raw(Box::new(val)),
577        Err(_) => std::ptr::null_mut(),
578    }
579}
580
581/// Show or hide
582#[unsafe(no_mangle)]
583pub extern "C" fn slint_interpreter_component_instance_show(
584    inst: &ErasedItemTreeBox,
585    is_visible: bool,
586) {
587    generativity::make_guard!(guard);
588    let comp = inst.unerase(guard);
589    match is_visible {
590        true => comp.borrow_instance().window_adapter().window().show().unwrap(),
591        false => comp.borrow_instance().window_adapter().window().hide().unwrap(),
592    }
593}
594
595/// Return a window for the component
596///
597/// The out pointer must be uninitialized and must be destroyed with
598/// slint_windowrc_drop after usage
599#[unsafe(no_mangle)]
600pub unsafe extern "C" fn slint_interpreter_component_instance_window(
601    inst: &ErasedItemTreeBox,
602    out: *mut *const i_slint_core::window::ffi::WindowAdapterRcOpaque,
603) {
604    assert_eq!(
605        core::mem::size_of::<Rc<dyn WindowAdapter>>(),
606        core::mem::size_of::<i_slint_core::window::ffi::WindowAdapterRcOpaque>()
607    );
608    unsafe {
609        core::ptr::write(
610            out as *mut *const Rc<dyn WindowAdapter>,
611            inst.window_adapter_ref().unwrap() as *const _,
612        )
613    }
614}
615
616/// Instantiate an instance from a definition.
617///
618/// The `out` must be uninitialized and is going to be initialized after the call
619/// and need to be destroyed with slint_interpreter_component_instance_destructor
620#[unsafe(no_mangle)]
621pub unsafe extern "C" fn slint_interpreter_component_instance_create(
622    def: &ComponentDefinitionOpaque,
623    out: *mut ComponentInstance,
624) {
625    unsafe { std::ptr::write(out, def.as_component_definition().create().unwrap()) }
626}
627
628#[unsafe(no_mangle)]
629pub unsafe extern "C" fn slint_interpreter_component_instance_component_definition(
630    inst: &ErasedItemTreeBox,
631    component_definition_ptr: *mut ComponentDefinitionOpaque,
632) {
633    generativity::make_guard!(guard);
634    let definition = ComponentDefinition { inner: inst.unerase(guard).description().into() };
635    unsafe { std::ptr::write(component_definition_ptr as *mut ComponentDefinition, definition) };
636}
637
638#[vtable::vtable]
639#[repr(C)]
640pub struct ModelAdaptorVTable {
641    pub row_count: extern "C" fn(VRef<ModelAdaptorVTable>) -> usize,
642    pub row_data: unsafe extern "C" fn(VRef<ModelAdaptorVTable>, row: usize) -> *mut Value,
643    pub set_row_data: extern "C" fn(VRef<ModelAdaptorVTable>, row: usize, value: Box<Value>),
644    pub get_notify: extern "C" fn(VRef<'_, ModelAdaptorVTable>) -> &ModelNotifyOpaque,
645    pub drop: extern "C" fn(VRefMut<ModelAdaptorVTable>),
646}
647
648struct ModelAdaptorWrapper(vtable::VBox<ModelAdaptorVTable>);
649impl Model for ModelAdaptorWrapper {
650    type Data = Value;
651
652    fn row_count(&self) -> usize {
653        self.0.row_count()
654    }
655
656    fn row_data(&self, row: usize) -> Option<Value> {
657        let val_ptr = unsafe { self.0.row_data(row) };
658        if val_ptr.is_null() { None } else { Some(*unsafe { Box::from_raw(val_ptr) }) }
659    }
660
661    fn model_tracker(&self) -> &dyn i_slint_core::model::ModelTracker {
662        self.0.get_notify().as_model_notify()
663    }
664
665    fn set_row_data(&self, row: usize, data: Value) {
666        let val = Box::new(data);
667        self.0.set_row_data(row, val);
668    }
669
670    fn as_any(&self) -> &dyn core::any::Any {
671        self
672    }
673}
674
675#[repr(C)]
676#[cfg(target_pointer_width = "64")]
677pub struct ModelNotifyOpaque([usize; 8]);
678#[repr(C)]
679#[cfg(target_pointer_width = "32")]
680pub struct ModelNotifyOpaque([usize; 12]);
681/// Asserts that ModelNotifyOpaque is at least as large as ModelNotify, otherwise this would overflow
682const _: usize = std::mem::size_of::<ModelNotifyOpaque>() - std::mem::size_of::<ModelNotify>();
683const _: usize = std::mem::align_of::<ModelNotifyOpaque>() - std::mem::align_of::<ModelNotify>();
684
685impl ModelNotifyOpaque {
686    fn as_model_notify(&self) -> &ModelNotify {
687        // Safety: there should be no way to construct a ModelNotifyOpaque without it holding an actual ModelNotify
688        unsafe { std::mem::transmute::<&ModelNotifyOpaque, &ModelNotify>(self) }
689    }
690}
691
692/// Construct a new ModelNotifyNotify in the given memory region
693#[unsafe(no_mangle)]
694pub unsafe extern "C" fn slint_interpreter_model_notify_new(val: *mut ModelNotifyOpaque) {
695    unsafe { std::ptr::write(val as *mut ModelNotify, ModelNotify::default()) };
696}
697
698/// Destruct the value in that memory location
699#[unsafe(no_mangle)]
700pub unsafe extern "C" fn slint_interpreter_model_notify_destructor(val: *mut ModelNotifyOpaque) {
701    drop(unsafe { std::ptr::read(val as *mut ModelNotify) })
702}
703
704#[unsafe(no_mangle)]
705pub unsafe extern "C" fn slint_interpreter_model_notify_row_changed(
706    notify: &ModelNotifyOpaque,
707    row: usize,
708) {
709    notify.as_model_notify().row_changed(row);
710}
711
712#[unsafe(no_mangle)]
713pub unsafe extern "C" fn slint_interpreter_model_notify_row_added(
714    notify: &ModelNotifyOpaque,
715    row: usize,
716    count: usize,
717) {
718    notify.as_model_notify().row_added(row, count);
719}
720
721#[unsafe(no_mangle)]
722pub unsafe extern "C" fn slint_interpreter_model_notify_reset(notify: &ModelNotifyOpaque) {
723    notify.as_model_notify().reset();
724}
725
726#[unsafe(no_mangle)]
727pub unsafe extern "C" fn slint_interpreter_model_notify_row_removed(
728    notify: &ModelNotifyOpaque,
729    row: usize,
730    count: usize,
731) {
732    notify.as_model_notify().row_removed(row, count);
733}
734
735// FIXME: Figure out how to re-export the one from compilerlib
736/// DiagnosticLevel describes the severity of a diagnostic.
737#[derive(Clone)]
738#[repr(u8)]
739pub enum DiagnosticLevel {
740    /// The diagnostic belongs to an error.
741    Error,
742    /// The diagnostic belongs to a warning.
743    Warning,
744    /// The diagnostic is a note
745    Note,
746}
747
748/// Diagnostic describes the aspects of either a warning or an error, along
749/// with its location and a description. Diagnostics are typically returned by
750/// slint::interpreter::ComponentCompiler::diagnostics() in a vector.
751#[derive(Clone)]
752#[repr(C)]
753pub struct Diagnostic {
754    /// The message describing the warning or error.
755    message: SharedString,
756    /// The path to the source file where the warning or error is located.
757    source_file: SharedString,
758    /// The line within the source file. Line numbers start at 1.
759    line: usize,
760    /// The column within the source file. Column numbers start at 1.
761    column: usize,
762    /// The level of the diagnostic, such as a warning or an error.
763    level: DiagnosticLevel,
764}
765
766#[repr(transparent)]
767pub struct ComponentCompilerOpaque(#[allow(deprecated)] NonNull<ComponentCompiler>);
768
769#[allow(deprecated)]
770impl ComponentCompilerOpaque {
771    fn as_component_compiler(&self) -> &ComponentCompiler {
772        // Safety: there should be no way to construct a ComponentCompilerOpaque without it holding an actual ComponentCompiler
773        unsafe { self.0.as_ref() }
774    }
775    fn as_component_compiler_mut(&mut self) -> &mut ComponentCompiler {
776        // Safety: there should be no way to construct a ComponentCompilerOpaque without it holding an actual ComponentCompiler
777        unsafe { self.0.as_mut() }
778    }
779}
780
781#[unsafe(no_mangle)]
782#[allow(deprecated)]
783pub unsafe extern "C" fn slint_interpreter_component_compiler_new(
784    compiler: *mut ComponentCompilerOpaque,
785) {
786    unsafe {
787        *compiler = ComponentCompilerOpaque(NonNull::new_unchecked(Box::into_raw(Box::new(
788            ComponentCompiler::default(),
789        ))));
790    }
791}
792
793#[unsafe(no_mangle)]
794pub unsafe extern "C" fn slint_interpreter_component_compiler_destructor(
795    compiler: *mut ComponentCompilerOpaque,
796) {
797    drop(unsafe { Box::from_raw((*compiler).0.as_ptr()) })
798}
799
800#[unsafe(no_mangle)]
801pub unsafe extern "C" fn slint_interpreter_component_compiler_set_include_paths(
802    compiler: &mut ComponentCompilerOpaque,
803    paths: &SharedVector<SharedString>,
804) {
805    compiler
806        .as_component_compiler_mut()
807        .set_include_paths(paths.iter().map(|path| path.as_str().into()).collect())
808}
809
810#[unsafe(no_mangle)]
811pub unsafe extern "C" fn slint_interpreter_component_compiler_set_style(
812    compiler: &mut ComponentCompilerOpaque,
813    style: Slice<u8>,
814) {
815    compiler.as_component_compiler_mut().set_style(std::str::from_utf8(&style).unwrap().to_string())
816}
817
818#[unsafe(no_mangle)]
819pub unsafe extern "C" fn slint_interpreter_component_compiler_set_translation_domain(
820    compiler: &mut ComponentCompilerOpaque,
821    translation_domain: Slice<u8>,
822) {
823    compiler
824        .as_component_compiler_mut()
825        .set_translation_domain(std::str::from_utf8(&translation_domain).unwrap().to_string())
826}
827
828#[unsafe(no_mangle)]
829pub unsafe extern "C" fn slint_interpreter_component_compiler_get_style(
830    compiler: &ComponentCompilerOpaque,
831    style_out: &mut SharedString,
832) {
833    *style_out =
834        compiler.as_component_compiler().style().map_or(SharedString::default(), |s| s.into());
835}
836
837#[unsafe(no_mangle)]
838pub unsafe extern "C" fn slint_interpreter_component_compiler_get_include_paths(
839    compiler: &ComponentCompilerOpaque,
840    paths: &mut SharedVector<SharedString>,
841) {
842    paths.extend(
843        compiler
844            .as_component_compiler()
845            .include_paths()
846            .iter()
847            .map(|path| path.to_str().map_or_else(Default::default, |str| str.into())),
848    );
849}
850
851#[unsafe(no_mangle)]
852pub unsafe extern "C" fn slint_interpreter_component_compiler_get_diagnostics(
853    compiler: &ComponentCompilerOpaque,
854    out_diags: &mut SharedVector<Diagnostic>,
855) {
856    #[allow(deprecated)]
857    out_diags.extend(compiler.as_component_compiler().diagnostics.iter().map(|diagnostic| {
858        let (line, column) = diagnostic.line_column();
859        Diagnostic {
860            message: diagnostic.message().into(),
861            source_file: diagnostic
862                .source_file()
863                .and_then(|path| path.to_str())
864                .map_or_else(Default::default, |str| str.into()),
865            line,
866            column,
867            level: match diagnostic.level() {
868                i_slint_compiler::diagnostics::DiagnosticLevel::Error => DiagnosticLevel::Error,
869                i_slint_compiler::diagnostics::DiagnosticLevel::Warning => DiagnosticLevel::Warning,
870                i_slint_compiler::diagnostics::DiagnosticLevel::Note => DiagnosticLevel::Note,
871                _ => DiagnosticLevel::Warning,
872            },
873        }
874    }));
875}
876
877#[unsafe(no_mangle)]
878pub unsafe extern "C" fn slint_interpreter_component_compiler_build_from_source(
879    compiler: &mut ComponentCompilerOpaque,
880    source_code: Slice<u8>,
881    path: Slice<u8>,
882    component_definition_ptr: *mut ComponentDefinitionOpaque,
883) -> bool {
884    match spin_on::spin_on(compiler.as_component_compiler_mut().build_from_source(
885        std::str::from_utf8(&source_code).unwrap().to_string(),
886        std::str::from_utf8(&path).unwrap().to_string().into(),
887    )) {
888        Some(definition) => {
889            unsafe {
890                std::ptr::write(component_definition_ptr as *mut ComponentDefinition, definition)
891            };
892            true
893        }
894        None => false,
895    }
896}
897
898#[unsafe(no_mangle)]
899pub unsafe extern "C" fn slint_interpreter_component_compiler_build_from_path(
900    compiler: &mut ComponentCompilerOpaque,
901    path: Slice<u8>,
902    component_definition_ptr: *mut ComponentDefinitionOpaque,
903) -> bool {
904    use std::str::FromStr;
905    match spin_on::spin_on(
906        compiler
907            .as_component_compiler_mut()
908            .build_from_path(PathBuf::from_str(std::str::from_utf8(&path).unwrap()).unwrap()),
909    ) {
910        Some(definition) => {
911            unsafe {
912                std::ptr::write(component_definition_ptr as *mut ComponentDefinition, definition)
913            };
914            true
915        }
916        None => false,
917    }
918}
919
920/// PropertyDescriptor is a simple structure that's used to describe a property declared in .slint
921/// code. It is returned from in a vector from
922/// slint::interpreter::ComponentDefinition::properties().
923#[derive(Clone)]
924#[repr(C)]
925pub struct PropertyDescriptor {
926    /// The name of the declared property.
927    property_name: SharedString,
928    /// The type of the property.
929    property_type: ValueType,
930}
931
932#[repr(C)]
933// Note: This needs to stay the size of 1 pointer to allow for the null pointer definition
934// in the C++ wrapper to allow for the null state.
935pub struct ComponentDefinitionOpaque([usize; 1]);
936/// Asserts that ComponentCompilerOpaque is as large as ComponentCompiler and has the same alignment, to make transmute safe.
937const _: [(); std::mem::size_of::<ComponentDefinitionOpaque>()] =
938    [(); std::mem::size_of::<ComponentDefinition>()];
939const _: [(); std::mem::align_of::<ComponentDefinitionOpaque>()] =
940    [(); std::mem::align_of::<ComponentDefinition>()];
941
942impl ComponentDefinitionOpaque {
943    fn as_component_definition(&self) -> &ComponentDefinition {
944        // Safety: there should be no way to construct a ComponentDefinitionOpaque without it holding an actual ComponentDefinition
945        unsafe { std::mem::transmute::<&ComponentDefinitionOpaque, &ComponentDefinition>(self) }
946    }
947}
948
949/// Construct a new Value in the given memory location
950#[unsafe(no_mangle)]
951pub unsafe extern "C" fn slint_interpreter_component_definition_clone(
952    other: &ComponentDefinitionOpaque,
953    def: *mut ComponentDefinitionOpaque,
954) {
955    unsafe {
956        std::ptr::write(def as *mut ComponentDefinition, other.as_component_definition().clone())
957    }
958}
959
960/// Destruct the component definition in that memory location
961#[unsafe(no_mangle)]
962pub unsafe extern "C" fn slint_interpreter_component_definition_destructor(
963    val: *mut ComponentDefinitionOpaque,
964) {
965    drop(unsafe { std::ptr::read(val as *mut ComponentDefinition) })
966}
967
968/// Returns the list of properties of the component the component definition describes
969#[unsafe(no_mangle)]
970pub unsafe extern "C" fn slint_interpreter_component_definition_properties(
971    def: &ComponentDefinitionOpaque,
972    props: &mut SharedVector<PropertyDescriptor>,
973) {
974    props.extend(def.as_component_definition().properties().map(
975        |(property_name, property_type)| PropertyDescriptor {
976            property_name: property_name.into(),
977            property_type,
978        },
979    ))
980}
981
982/// Returns the list of callback names of the component the component definition describes
983#[unsafe(no_mangle)]
984pub unsafe extern "C" fn slint_interpreter_component_definition_callbacks(
985    def: &ComponentDefinitionOpaque,
986    callbacks: &mut SharedVector<SharedString>,
987) {
988    callbacks.extend(def.as_component_definition().callbacks().map(|name| name.into()))
989}
990
991/// Returns the list of function names of the component the component definition describes
992#[unsafe(no_mangle)]
993pub unsafe extern "C" fn slint_interpreter_component_definition_functions(
994    def: &ComponentDefinitionOpaque,
995    functions: &mut SharedVector<SharedString>,
996) {
997    functions.extend(def.as_component_definition().functions().map(|name| name.into()))
998}
999
1000/// Return the name of the component definition
1001#[unsafe(no_mangle)]
1002pub unsafe extern "C" fn slint_interpreter_component_definition_name(
1003    def: &ComponentDefinitionOpaque,
1004    name: &mut SharedString,
1005) {
1006    *name = def.as_component_definition().name().into()
1007}
1008
1009/// Returns a vector of strings with the names of all exported global singletons.
1010#[unsafe(no_mangle)]
1011pub unsafe extern "C" fn slint_interpreter_component_definition_globals(
1012    def: &ComponentDefinitionOpaque,
1013    names: &mut SharedVector<SharedString>,
1014) {
1015    names.extend(def.as_component_definition().globals().map(|name| name.into()))
1016}
1017
1018/// Returns a vector of the property descriptors of the properties of the specified publicly exported global
1019/// singleton. Returns true if a global exists under the specified name; false otherwise.
1020#[unsafe(no_mangle)]
1021pub unsafe extern "C" fn slint_interpreter_component_definition_global_properties(
1022    def: &ComponentDefinitionOpaque,
1023    global_name: Slice<u8>,
1024    properties: &mut SharedVector<PropertyDescriptor>,
1025) -> bool {
1026    if let Some(property_it) =
1027        def.as_component_definition().global_properties(std::str::from_utf8(&global_name).unwrap())
1028    {
1029        properties.extend(property_it.map(|(property_name, property_type)| PropertyDescriptor {
1030            property_name: property_name.into(),
1031            property_type,
1032        }));
1033        true
1034    } else {
1035        false
1036    }
1037}
1038
1039/// Returns a vector of the names of the callbacks of the specified publicly exported global
1040/// singleton. Returns true if a global exists under the specified name; false otherwise.
1041#[unsafe(no_mangle)]
1042pub unsafe extern "C" fn slint_interpreter_component_definition_global_callbacks(
1043    def: &ComponentDefinitionOpaque,
1044    global_name: Slice<u8>,
1045    names: &mut SharedVector<SharedString>,
1046) -> bool {
1047    if let Some(name_it) =
1048        def.as_component_definition().global_callbacks(std::str::from_utf8(&global_name).unwrap())
1049    {
1050        names.extend(name_it.map(|name| name.into()));
1051        true
1052    } else {
1053        false
1054    }
1055}
1056
1057/// Returns a vector of the names of the functions of the specified publicly exported global
1058/// singleton. Returns true if a global exists under the specified name; false otherwise.
1059#[unsafe(no_mangle)]
1060pub unsafe extern "C" fn slint_interpreter_component_definition_global_functions(
1061    def: &ComponentDefinitionOpaque,
1062    global_name: Slice<u8>,
1063    names: &mut SharedVector<SharedString>,
1064) -> bool {
1065    if let Some(name_it) =
1066        def.as_component_definition().global_functions(std::str::from_utf8(&global_name).unwrap())
1067    {
1068        names.extend(name_it.map(|name| name.into()));
1069        true
1070    } else {
1071        false
1072    }
1073}