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