slint_interpreter/
ffi.rs

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