float_pigment_css/
ffi.rs

1#![doc(hidden)]
2#![cfg(feature = "ffi")]
3
4use alloc::{
5    boxed::Box,
6    ffi::CString,
7    string::{String, ToString},
8    vec::Vec,
9};
10use bit_set::BitSet;
11use core::ffi::{c_char, CStr};
12use core::ptr::{null, null_mut};
13use hashbrown::HashMap;
14
15use crate::parser::parse_color_to_rgba;
16use crate::property::{Property, PropertyMeta};
17use crate::sheet::borrow::{InlineRule, Selector};
18use crate::typing::ImportantBitSet;
19
20use crate::group;
21use crate::parser;
22use crate::parser::property_value::var::{
23    CustomPropertyContext, CustomPropertyGetter, CustomPropertySetter,
24};
25use crate::sheet;
26use group::drop_css_extension;
27use group::StyleSheetImportIndex as StyleSheetImportIndexImpl;
28use parser::Warning;
29use sheet::borrow::{Array, StyleSheet};
30use sheet::str_store::StrRef;
31
32#[cfg(feature = "deserialize")]
33use sheet::borrow::de_static_ref_zero_copy_env;
34
35#[macro_export]
36macro_rules! check_null {
37    ($arg:expr, $error:expr, $default:expr) => {
38        if $arg.is_null() {
39            return FfiResult::error($error, $default);
40        }
41    };
42}
43
44#[macro_export]
45macro_rules! raw_ptr_as_mut_ref {
46    ($from:expr, $type:ty) => {
47        &mut *($from as *mut $type)
48    };
49}
50
51pub type RawMutPtr = *mut ();
52
53pub type NullPtr = *const ();
54
55#[repr(C)]
56pub enum FfiErrorCode {
57    None,
58    ThisNullPointer,
59    PathNullPointer,
60    PrefixNullPointer,
61    SourceNullPointer,
62    BufferNullPointer,
63    ExprPtrNullPointer,
64    StrNullPointer,
65    InlineStyleTextNullPointer,
66    InlineRuleNullPointer,
67    StyleTextNullPointer,
68    SelectorTextNullPointer,
69    InvalidPath,
70    JsonNullPointer,
71    ArrayNullPointer,
72    SelectorNullPointer,
73    StyleSheetNullPointer,
74    MapNullPointer,
75    Unknown,
76}
77
78#[repr(C)]
79pub struct FfiResult<T> {
80    pub value: T,
81    pub err: FfiErrorCode,
82}
83
84impl<T> FfiResult<T> {
85    pub fn ok(value: T) -> Self {
86        Self {
87            value,
88            err: FfiErrorCode::None,
89        }
90    }
91    pub fn error(err: FfiErrorCode, default: T) -> Self {
92        Self {
93            value: default,
94            err,
95        }
96    }
97}
98
99/// # Safety
100///
101/// Create a new style sheet resource.
102///
103/// # Arguments
104/// * `this` - A raw pointer to a [`StyleSheetResource`] instance
105/// * `path` - C string pointer to the style sheet path (UTF-8 encoded)
106/// * `source` - C string pointer to the CSS source content (UTF-8 encoded)
107/// * `warnings` - Optional output parameter to receive warnings array pointer
108///
109/// # Examples
110///
111/// ```c
112/// FfiResult result = FPStyleSheetResourceNew();
113/// if (result.err != FfiErrorCode::None) {
114///     // handle error
115/// }
116/// RawMutPtr resource = result.value;
117/// ```
118///
119#[export_name = "FPStyleSheetResourceNew"]
120pub unsafe extern "C" fn style_sheet_resource_new() -> FfiResult<RawMutPtr> {
121    FfiResult::ok(Box::into_raw(Box::new(group::StyleSheetResource::new())) as RawMutPtr)
122}
123
124/// # Safety
125///
126/// Free the style sheet resource.
127///
128/// # Arguments
129/// * `this` - A raw pointer to a [`StyleSheetResource`] instance
130///
131/// # Examples
132///
133/// ```c
134/// FfiResult result = FPStyleSheetResourceFree(resource);
135/// if (result.err != FfiErrorCode::None) {
136///     // handle error
137/// }
138/// ```
139///
140#[export_name = "FPStyleSheetResourceFree"]
141pub unsafe extern "C" fn style_sheet_resource_free(this: RawMutPtr) -> FfiResult<NullPtr> {
142    check_null!(this, FfiErrorCode::ThisNullPointer, null());
143    drop(Box::from_raw(this as *mut group::StyleSheetResource));
144    FfiResult::ok(null())
145}
146
147/// # Safety
148/// Add a tag name prefix to the resource.
149///
150/// # Arguments
151/// * `this` - A raw pointer to a [`StyleSheetResource`] instance
152/// * `path` - C string pointer to the stylesheet path (UTF-8 encoded)
153/// * `prefix` - C string pointer to the prefix to add to the tag name (UTF-8 encoded)
154///
155/// # Examples
156///
157/// ```c
158/// FfiResult result = FPStyleSheetResourceAddTagNamePrefix(resource, path, prefix);
159/// if (result.err != FfiErrorCode::None) {
160///     // handle error
161/// }
162/// ```
163///
164#[export_name = "FPStyleSheetResourceAddTagNamePrefix"]
165pub unsafe extern "C" fn style_sheet_resource_add_tag_name_prefix(
166    this: RawMutPtr,
167    path: *const c_char,
168    prefix: *const c_char,
169) -> FfiResult<NullPtr> {
170    check_null!(this, FfiErrorCode::ThisNullPointer, null());
171    check_null!(path, FfiErrorCode::PathNullPointer, null());
172    check_null!(prefix, FfiErrorCode::PrefixNullPointer, null());
173    let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
174    let path = CStr::from_ptr(path).to_string_lossy();
175    let prefix = CStr::from_ptr(prefix).to_string_lossy();
176    res.add_tag_name_prefix(&path, &prefix);
177    FfiResult::ok(null())
178}
179
180/// # Safety
181/// Serialize the specified style sheet to the JSON format.
182///
183/// # Arguments
184/// * `this` - A raw pointer to a [`StyleSheetResource`] instance
185/// * `path` - C string pointer to the stylesheet path (UTF-8 encoded)
186/// * `ret_buffer_len` - Pointer to a variable to store the length of the serialized data
187///
188/// # Examples
189///
190/// ```c
191/// FfiResult result = FPStyleSheetResourceSerializeJson(resource, path, &mut buffer_len);
192/// if (result.err != FfiErrorCode::None) {
193///     // handle error
194/// }
195/// ```
196///
197#[cfg(all(feature = "serialize", feature = "serialize_json"))]
198#[export_name = "FPStyleSheetResourceSerializeJson"]
199pub unsafe extern "C" fn style_sheet_resource_serialize_json(
200    this: RawMutPtr,
201    path: *const c_char,
202    ret_buffer_len: &mut usize,
203) -> FfiResult<*mut u8> {
204    check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
205    check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
206    let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
207    let path = CStr::from_ptr(path).to_string_lossy();
208    let serial = res.serialize_json(&path).unwrap_or_default();
209    *ret_buffer_len = serial.len();
210    let ret = Box::into_raw(serial.into_boxed_str());
211    FfiResult::ok(ret as *mut u8)
212}
213
214/// # Safety
215///
216/// Serialize the specified style sheet to the binary format.
217///
218/// # Arguments
219/// * `this` - A raw pointer to a [`StyleSheetResource`] instance
220/// * `path` - C string pointer to the stylesheet path (UTF-8 encoded)
221/// * `ret_buffer_len` - Pointer to a variable to store the length of the serialized data
222///
223/// # Examples
224///
225/// ```c
226/// FfiResult result = FPStyleSheetResourceSerializeBincode(resource, path, &mut buffer_len);
227/// if (result.err != FfiErrorCode::None) {
228///     // handle error
229/// }
230/// ```
231///
232#[cfg(feature = "serialize")]
233#[export_name = "FPStyleSheetResourceSerializeBincode"]
234pub unsafe extern "C" fn style_sheet_resource_serialize_bincode(
235    this: RawMutPtr,
236    path: *const c_char,
237    ret_buffer_len: &mut usize,
238) -> FfiResult<*mut u8> {
239    check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
240    check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
241    let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
242    let path = CStr::from_ptr(path).to_string_lossy();
243    let serial = res.serialize_bincode(&path).unwrap_or_default();
244    *ret_buffer_len = serial.len();
245    let ret = Box::into_raw(serial.into_boxed_slice());
246    FfiResult::ok(ret as *mut u8)
247}
248/// # Safety
249///
250/// Add a style sheet to the resource manager.
251///
252/// # Arguments
253/// * `this` - A raw pointer to a [`StyleSheetResource`] instance
254/// * `path` - C string pointer to the style sheet path (UTF-8 encoded)
255/// * `source` - C string pointer to the CSS source content (UTF-8 encoded)
256/// * `warnings` - Optional output parameter to receive warnings array pointer
257///
258/// # Examples
259///
260/// ```c
261/// FPStyleSheetResourceAddSource(resource, path, source, &mut warnings);
262/// ```
263///
264#[export_name = "FPStyleSheetResourceAddSource"]
265pub unsafe extern "C" fn style_sheet_resource_add_source(
266    this: RawMutPtr,
267    path: *const c_char,
268    source: *const c_char,
269    warnings: *mut *mut Array<Warning>,
270) -> FfiResult<NullPtr> {
271    check_null!(this, FfiErrorCode::ThisNullPointer, null());
272    check_null!(path, FfiErrorCode::PathNullPointer, null());
273    check_null!(source, FfiErrorCode::SourceNullPointer, null());
274    let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
275    let path = CStr::from_ptr(path).to_string_lossy();
276    let source = CStr::from_ptr(source).to_string_lossy();
277    let w = res.add_source(&path, &source);
278    if !warnings.is_null() {
279        *warnings = Box::into_raw(Box::new(w.into()));
280    }
281    FfiResult::ok(null())
282}
283
284/// # Safety
285///
286/// Add a style sheet to the resource manager with hooks.
287///
288/// # Arguments
289/// * `this` - A raw pointer to a [`StyleSheetResource`] instance
290/// * `hooks` - A parser hooks
291/// * `path` - C string pointer to the style sheet path (UTF-8 encoded)
292/// * `source` - C string pointer to the CSS source content (UTF-8 encoded)
293/// * `warnings` - Optional output parameter to receive warnings array pointer
294///
295/// # Examples
296///
297/// ```c
298/// FPStyleSheetResourceAddSourceWithHooks(resource, hooks, path, source, &mut warnings);
299/// ```
300///
301#[export_name = "FPStyleSheetResourceAddSourceWithHooks"]
302pub unsafe extern "C" fn style_sheet_resource_add_source_with_hooks(
303    this: RawMutPtr,
304    hooks: parser::hooks::CParserHooks,
305    path: *const c_char,
306    source: *const c_char,
307    warnings: *mut *mut Array<Warning>,
308) -> FfiResult<NullPtr> {
309    check_null!(this, FfiErrorCode::ThisNullPointer, null());
310    check_null!(path, FfiErrorCode::PathNullPointer, null());
311    check_null!(source, FfiErrorCode::SourceNullPointer, null());
312    let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
313    let path = CStr::from_ptr(path).to_string_lossy();
314    let source = CStr::from_ptr(source).to_string_lossy();
315    let w = res.add_source_with_hooks(&path, &source, Some(Box::new(hooks)));
316    if !warnings.is_null() {
317        *warnings = Box::into_raw(Box::new(w.into()));
318    }
319    FfiResult::ok(null())
320}
321
322/// # Safety
323/// Add a style sheet to the resource manager from binary format.
324///
325/// # Arguments
326/// * `this` - A raw pointer to a [`StyleSheetResource`] instance
327/// * `path` - C string pointer to the stylesheet path (UTF-8 encoded)
328/// * `buffer_ptr` - Pointer to the buffer to store the serialized data
329/// * `buffer_len` - Length of the buffer
330/// * `drop_fn` - Optional drop function
331/// * `drop_args` - Pointer to the drop argument
332/// * `warnings` - Optional output parameter to receive warnings array pointer
333///
334/// # Examples
335///
336/// ```c
337/// FPStyleSheetResourceAddBincode(resource, path, buffer_ptr, buffer_len, drop_fn, drop_args, &mut warnings);
338/// ```
339///
340#[cfg(feature = "deserialize")]
341#[export_name = "FPStyleSheetResourceAddBincode"]
342pub unsafe extern "C" fn style_sheet_resource_add_bincode(
343    this: RawMutPtr,
344    path: *const c_char,
345    buffer_ptr: *mut u8,
346    buffer_len: usize,
347    drop_fn: Option<unsafe extern "C" fn(RawMutPtr)>,
348    drop_args: RawMutPtr,
349    warnings: *mut *mut Array<Warning>,
350) -> FfiResult<NullPtr> {
351    check_null!(this, FfiErrorCode::ThisNullPointer, null());
352    check_null!(path, FfiErrorCode::PathNullPointer, null());
353    check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null());
354    let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
355    let bincode: *mut [u8] = core::slice::from_raw_parts_mut(buffer_ptr, buffer_len);
356    let path = CStr::from_ptr(path).to_string_lossy();
357    let w = res.add_bincode_zero_copy(&path, bincode, move || {
358        if let Some(drop_fn) = drop_fn {
359            drop_fn(drop_args);
360        }
361    });
362    if !warnings.is_null() {
363        *warnings = Box::into_raw(Box::new(w.into()));
364    }
365    FfiResult::ok(null())
366}
367
368/// # Safety
369/// Get the direct dependencies of the specified style sheet.
370///
371/// # Arguments
372/// * `this` - A raw pointer to a [`StyleSheetResource`] instance
373/// * `path` - C string pointer to the stylesheet path (UTF-8 encoded)
374///
375/// # Examples
376///
377/// ```c
378/// FPStyleSheetResourceDirectDependencies(resource, path);
379/// ```
380///
381#[export_name = "FPStyleSheetResourceDirectDependencies"]
382pub unsafe extern "C" fn style_sheet_resource_direct_dependencies(
383    this: RawMutPtr,
384    path: *const c_char,
385) -> FfiResult<*mut Array<StrRef>> {
386    check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
387    check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
388    let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
389    let path = CStr::from_ptr(path).to_string_lossy();
390    let deps = res.direct_dependencies(&path);
391    let deps: Vec<_> = deps.into_iter().map(StrRef::from).collect();
392    FfiResult::ok(Box::into_raw(Box::new(deps.into())))
393}
394
395/// # Safety
396///
397/// Generate the import index of the resource.
398///
399/// # Arguments
400/// * `this` - A raw pointer to a [`StyleSheetResource`] instance
401///
402/// # Examples
403///
404/// ```c
405/// FPStyleSheetResourceGenerateImportIndex(resource);
406/// ```
407///
408#[export_name = "FPStyleSheetResourceGenerateImportIndex"]
409pub unsafe extern "C" fn style_sheet_resource_generate_import_index(
410    this: RawMutPtr,
411) -> FfiResult<RawMutPtr> {
412    check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
413    let res = raw_ptr_as_mut_ref!(this, group::StyleSheetResource);
414    FfiResult::ok(
415        StyleSheetImportIndex {
416            inner: res.generate_import_indexes(),
417            map: StyleSheetMap::default(),
418        }
419        .into_raw(),
420    )
421}
422
423type StyleSheetMap = HashMap<String, StyleSheet>;
424
425struct StyleSheetImportIndex {
426    inner: StyleSheetImportIndexImpl,
427    map: StyleSheetMap,
428}
429
430impl StyleSheetImportIndex {
431    fn into_raw(self) -> RawMutPtr {
432        Box::into_raw(Box::new(self)) as RawMutPtr
433    }
434}
435
436/// # Safety
437/// Create a new style sheet import index.
438///
439/// # Examples
440///
441/// ```c
442/// RawMutPtr import_index = FPStyleSheetImportIndexNew();
443/// ```
444///
445#[export_name = "FPStyleSheetImportIndexNew"]
446pub unsafe extern "C" fn style_sheet_import_index_new() -> FfiResult<RawMutPtr> {
447    FfiResult::ok(
448        StyleSheetImportIndex {
449            inner: StyleSheetImportIndexImpl::new(),
450            map: StyleSheetMap::default(),
451        }
452        .into_raw(),
453    )
454}
455
456/// # Safety
457/// Free the style sheet import index.
458///
459/// # Arguments
460/// * `this` - A raw pointer to a [`StyleSheetImportIndex`] instance
461///
462/// # Examples
463///
464/// ```c
465/// FPStyleSheetImportIndexFree(import_index);
466/// ```
467///
468#[export_name = "FPStyleSheetImportIndexFree"]
469pub unsafe extern "C" fn style_sheet_import_index_free(this: RawMutPtr) -> FfiResult<NullPtr> {
470    check_null!(this, FfiErrorCode::ThisNullPointer, null());
471    drop(Box::from_raw(this as *mut StyleSheetImportIndex));
472    FfiResult::ok(null())
473}
474
475/// # Safety
476/// Query and mark the dependencies of the specified style sheet.
477///
478/// # Arguments
479/// * `this` - A raw pointer to a [`StyleSheetImportIndex`] instance
480/// * `path` - C string pointer to the style sheet path (UTF-8 encoded)
481///
482/// # Examples
483///
484/// ```c
485/// FPStyleSheetImportIndexQueryAndMarkDependencies(import_index, path);
486/// ```
487///
488#[export_name = "FPStyleSheetImportIndexQueryAndMarkDependencies"]
489pub unsafe extern "C" fn style_sheet_import_index_query_and_mark_dependencies(
490    this: RawMutPtr,
491    path: *const c_char,
492) -> FfiResult<*mut Array<StrRef>> {
493    check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
494    check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
495    let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
496    let path = CStr::from_ptr(path).to_string_lossy();
497    let deps = style_sheet_import_index
498        .inner
499        .query_and_mark_dependencies(&path);
500    let deps: Vec<_> = deps.into_iter().map(StrRef::from).collect();
501    FfiResult::ok(Box::into_raw(Box::new(deps.into())))
502}
503
504/// # Safety
505/// List the dependencies of the specified style sheet.
506///
507/// # Arguments
508/// * `this` - A raw pointer to a [`StyleSheetImportIndex`] instance
509/// * `path` - C string pointer to the style sheet path (UTF-8 encoded)
510///
511/// # Examples
512///
513/// ```c
514/// FPStyleSheetImportIndexListDependencies(import_index, path);
515/// ```
516///
517#[export_name = "FPStyleSheetImportIndexListDependencies"]
518pub unsafe extern "C" fn style_sheet_import_index_list_dependencies(
519    this: RawMutPtr,
520    path: *const c_char,
521) -> FfiResult<*mut Array<StrRef>> {
522    check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
523    check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
524    let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
525    let path = CStr::from_ptr(path).to_string_lossy();
526    let deps = style_sheet_import_index
527        .inner
528        .list_dependencies(&path, true);
529    let deps: Vec<_> = deps.into_iter().map(StrRef::from).collect();
530    FfiResult::ok(Box::into_raw(Box::new(deps.into())))
531}
532
533/// # Safety
534/// List the dependency of the specified style sheet.
535///
536/// # Arguments
537/// * `this` - A raw pointer to a [`StyleSheetImportIndex`] instance
538/// * `path` - C string pointer to the style sheet path (UTF-8 encoded)
539///
540/// # Examples
541///
542/// ```c
543/// FPStyleSheetImportIndexListDependency(import_index, path);
544/// ```
545///
546#[export_name = "FPStyleSheetImportIndexListDependency"]
547pub unsafe extern "C" fn style_sheet_import_index_list_dependency(
548    this: RawMutPtr,
549    path: *const c_char,
550) -> FfiResult<*mut Array<StrRef>> {
551    check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
552    check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
553    let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
554    let path = CStr::from_ptr(path).to_string_lossy();
555    let deps = style_sheet_import_index
556        .inner
557        .list_dependencies(&path, false);
558    let deps: Vec<_> = deps.into_iter().map(StrRef::from).collect();
559    FfiResult::ok(Box::into_raw(Box::new(deps.into())))
560}
561
562/// # Safety
563/// Add a style sheet to the import index from binary format.
564///
565/// # Arguments
566/// * `this` - A raw pointer to a [`StyleSheetImportIndex`] instance
567/// * `path` - C string pointer to the style sheet path (UTF-8 encoded)
568/// * `buffer_ptr` - Pointer to the buffer to store the serialized data
569/// * `buffer_len` - Length of the buffer
570/// * `drop_fn` - Optional drop function
571/// * `drop_args` - Pointer to the drop argument
572/// * `warnings` - Optional output parameter to receive warnings array pointer
573///
574/// # Examples
575///
576/// ```c
577/// FPStyleSheetImportIndexAddBincode(import_index, path, buffer_ptr, buffer_len, drop_fn, drop_args, &mut warnings);
578/// ```
579///
580#[cfg(feature = "deserialize")]
581#[export_name = "FPStyleSheetImportIndexAddBincode"]
582pub unsafe extern "C" fn style_sheet_import_index_add_bincode(
583    this: RawMutPtr,
584    path: *const c_char,
585    buffer_ptr: *mut u8,
586    buffer_len: usize,
587    drop_fn: Option<unsafe extern "C" fn(RawMutPtr)>,
588    drop_args: RawMutPtr,
589    warnings: *mut *mut Array<Warning>,
590) -> FfiResult<NullPtr> {
591    use float_pigment_consistent_bincode::Options;
592    use parser::WarningKind;
593    check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
594    check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
595    check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null_mut());
596    let path = CStr::from_ptr(path).to_string_lossy();
597    let sheet = de_static_ref_zero_copy_env(
598        core::slice::from_raw_parts_mut(buffer_ptr, buffer_len),
599        |s| {
600            let s: Result<StyleSheet, _> = float_pigment_consistent_bincode::DefaultOptions::new()
601                .allow_trailing_bytes()
602                .deserialize(s);
603            match s {
604                Ok(ss) => ss,
605                Err(err) => {
606                    let w = vec![Warning {
607                        kind: WarningKind::DeserializationFailed,
608                        message: format!(
609                            "failed to deserialize bincode formatted style sheet: {}",
610                            err
611                        )
612                        .into(),
613                        start_line: 0,
614                        start_col: 0,
615                        end_line: 0,
616                        end_col: 0,
617                    }];
618                    if !warnings.is_null() {
619                        *warnings = Box::into_raw(Box::new(w.into()));
620                    }
621                    StyleSheet::from_sheet(&sheet::CompiledStyleSheet::new())
622                }
623            }
624        },
625        move || {
626            if let Some(drop_fn) = drop_fn {
627                drop_fn(drop_args);
628            }
629        },
630    );
631    let path = drop_css_extension(&path).into();
632    let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
633    style_sheet_import_index.map.insert(path, sheet);
634    FfiResult::ok(null())
635}
636
637/// # Safety
638/// Remove a style sheet from the style sheet import index.
639///
640/// # Arguments
641/// * `this` - A raw pointer to a [`StyleSheetImportIndex`] instance
642/// * `path` - C string pointer to the style sheet path (UTF-8 encoded)
643///
644/// # Examples
645///
646/// ```c
647/// FPStyleSheetImportIndexRemoveBincode(import_index, path);
648/// ```
649///
650#[export_name = "FPStyleSheetImportIndexRemoveBincode"]
651pub unsafe extern "C" fn style_sheet_import_index_remove_bincode(
652    this: RawMutPtr,
653    path: *const c_char,
654) -> FfiResult<NullPtr> {
655    check_null!(this, FfiErrorCode::ThisNullPointer, null());
656    check_null!(path, FfiErrorCode::PathNullPointer, null());
657    let path = CStr::from_ptr(path).to_string_lossy();
658    let path = drop_css_extension(&path);
659    let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
660    style_sheet_import_index.map.remove(path);
661    FfiResult::ok(null())
662}
663/// # Safety
664/// Get the style sheet from the style sheet import index.
665///
666/// # Arguments
667/// * `this` - A raw pointer to a [`StyleSheetImportIndex`] instance
668/// * `path` - C string pointer to the style sheet path (UTF-8 encoded)
669///
670/// # Examples
671///
672/// ```c
673/// FPStyleSheetImportIndexGetStyleSheet(import_index, path);
674/// ```
675///
676#[export_name = "FPStyleSheetImportIndexGetStyleSheet"]
677pub unsafe extern "C" fn style_sheet_import_index_get_style_sheet(
678    this: RawMutPtr,
679    path: *const c_char,
680) -> FfiResult<*mut StyleSheet> {
681    check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
682    check_null!(path, FfiErrorCode::PathNullPointer, null_mut());
683    let path = CStr::from_ptr(path).to_string_lossy();
684    let path = drop_css_extension(&path);
685    let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
686    match style_sheet_import_index.map.get_mut(path) {
687        None => FfiResult::error(FfiErrorCode::InvalidPath, null_mut()),
688        Some(x) => FfiResult::ok(x as *mut StyleSheet),
689    }
690}
691/// # Safety
692/// Serialize the style sheet import index to the JSON format.
693///
694/// # Arguments
695/// * `this` - A raw pointer to a [`StyleSheetImportIndex`] instance
696/// * `ret_buffer_len` - Pointer to a variable to store the length of the serialized data
697///
698/// # Examples
699///
700/// ```c
701/// FPStyleSheetImportIndexSerializeJson(import_index, &buffer_len);
702/// ```
703///
704#[cfg(all(feature = "serialize", feature = "serialize_json"))]
705#[export_name = "FPStyleSheetImportIndexSerializeJson"]
706pub unsafe extern "C" fn style_sheet_import_index_serialize_json(
707    this: RawMutPtr,
708    ret_buffer_len: &mut usize,
709) -> FfiResult<*mut u8> {
710    check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
711    let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
712    let serial = style_sheet_import_index.inner.serialize_json();
713    *ret_buffer_len = serial.len();
714    let ret = Box::into_raw(serial.into_boxed_str());
715    FfiResult::ok(ret as *mut u8)
716}
717/// # Safety
718/// Serialize the style sheet import index to the binary format.
719///
720/// # Arguments
721/// * `this` - A raw pointer to a [`StyleSheetImportIndex`] instance
722/// * `ret_buffer_len` - Pointer to a variable to store the length of the serialized data
723///
724/// # Examples
725///
726/// ```c
727/// FPStyleSheetImportIndexSerializeBincode(import_index, &buffer_len);
728/// ```
729///
730#[cfg(feature = "serialize")]
731#[export_name = "FPStyleSheetImportIndexSerializeBincode"]
732pub unsafe extern "C" fn style_sheet_import_index_serialize_bincode(
733    this: RawMutPtr,
734    ret_buffer_len: &mut usize,
735) -> FfiResult<*mut u8> {
736    check_null!(this, FfiErrorCode::ThisNullPointer, null_mut());
737    let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
738    let serial = style_sheet_import_index.inner.serialize_bincode();
739    *ret_buffer_len = serial.len();
740    let ret = Box::into_raw(serial.into_boxed_slice());
741    FfiResult::ok(ret as *mut u8)
742}
743/// # Safety
744/// Deserialize the style sheet import index from the JSON format.
745///
746/// # Arguments
747/// * `json` - C string pointer to the JSON data
748///
749/// # Examples
750///
751/// ```c
752/// FPStyleSheetImportIndexDeserializeJson(json, &import_index);
753/// ```
754///
755#[cfg(all(feature = "deserialize", feature = "deserialize_json"))]
756#[export_name = "FPStyleSheetImportIndexDeserializeJson"]
757pub unsafe extern "C" fn style_sheet_import_index_deserialize_json(
758    json: *const c_char,
759) -> FfiResult<RawMutPtr> {
760    check_null!(json, FfiErrorCode::JsonNullPointer, null_mut());
761    let json = CStr::from_ptr(json).to_string_lossy();
762    FfiResult::ok(
763        StyleSheetImportIndex {
764            inner: StyleSheetImportIndexImpl::deserialize_json(&json),
765            map: StyleSheetMap::default(),
766        }
767        .into_raw(),
768    )
769}
770/// # Safety
771/// Deserialize the style sheet import index from the binary format.
772///
773/// # Arguments
774/// * `buffer_ptr` - Pointer to the binary data
775/// * `buffer_len` - Length of the binary data
776/// * `drop_fn` - Optional drop function
777/// * `drop_args` - Pointer to the drop argument
778///
779/// # Examples
780///
781/// ```c
782/// FPStyleSheetImportIndexDeserializeBincode(buffer_ptr, buffer_len, drop_fn, drop_args);
783/// ```
784///
785#[cfg(feature = "deserialize")]
786#[export_name = "FPStyleSheetImportIndexDeserializeBincode"]
787pub unsafe extern "C" fn style_sheet_import_index_deserialize_bincode(
788    buffer_ptr: *mut u8,
789    buffer_len: usize,
790    drop_fn: Option<unsafe extern "C" fn(RawMutPtr)>,
791    drop_args: RawMutPtr,
792) -> FfiResult<RawMutPtr> {
793    check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null_mut());
794    let bincode: *mut [u8] = core::slice::from_raw_parts_mut(buffer_ptr, buffer_len);
795    FfiResult::ok(
796        StyleSheetImportIndex {
797            inner: StyleSheetImportIndexImpl::deserialize_bincode_zero_copy(bincode, move || {
798                if let Some(drop_fn) = drop_fn {
799                    drop_fn(drop_args);
800                }
801            }),
802            map: StyleSheetMap::default(),
803        }
804        .into_raw(),
805    )
806}
807/// # Safety
808/// Merge the style sheet import index from binary format.
809///
810/// # Arguments
811/// * `this` - A raw pointer to a [`StyleSheetImportIndex`] instance
812/// * `buffer_ptr` - Pointer to the binary data
813/// * `buffer_len` - Length of the binary data
814/// * `drop_fn` - Optional drop function
815/// * `drop_args` - Pointer to the drop argument
816///
817/// # Examples
818///
819/// ```c
820/// FPStyleSheetImportIndexMergeBincode(import_index, buffer_ptr, buffer_len, drop_fn, drop_args);
821/// ```
822///
823#[cfg(feature = "deserialize")]
824#[export_name = "FPStyleSheetImportIndexMergeBincode"]
825pub unsafe extern "C" fn style_sheet_import_index_merge_bincode(
826    this: RawMutPtr,
827    buffer_ptr: *mut u8,
828    buffer_len: usize,
829    drop_fn: Option<unsafe extern "C" fn(*mut ())>,
830    drop_args: *mut (),
831) -> FfiResult<NullPtr> {
832    check_null!(this, FfiErrorCode::ThisNullPointer, null());
833    check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null());
834    let style_sheet_import_index = raw_ptr_as_mut_ref!(this, StyleSheetImportIndex);
835    let bincode: *mut [u8] = core::slice::from_raw_parts_mut(buffer_ptr, buffer_len);
836    style_sheet_import_index
837        .inner
838        .merge_bincode_zero_copy(bincode, move || {
839            if let Some(drop_fn) = drop_fn {
840                drop_fn(drop_args);
841            }
842        });
843    FfiResult::ok(null())
844}
845
846/// # Safety
847/// Free the buffer.
848///
849/// # Arguments
850/// * `buffer_ptr` - Pointer to the buffer
851/// * `buffer_len` - Length of the buffer
852///
853/// # Examples
854///
855/// ```c
856/// FPBufferFree(buffer_ptr, buffer_len);
857/// ```
858///
859#[export_name = "FPBufferFree"]
860pub unsafe extern "C" fn buffer_free(buffer_ptr: *mut u8, buffer_len: usize) -> FfiResult<NullPtr> {
861    check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null());
862    let x: *mut [u8] = core::slice::from_raw_parts_mut(buffer_ptr, buffer_len);
863    drop(Box::from_raw(x));
864    FfiResult::ok(null())
865}
866
867/// # Safety
868/// Free the array of string references.
869///
870/// # Arguments
871/// * `x` - Pointer to the array of string references
872///
873/// # Examples
874///
875/// ```c
876/// FPArrayStrRefFree(x);
877/// ```
878///
879#[export_name = "FPArrayStrRefFree"]
880pub unsafe extern "C" fn array_str_ref_free(x: *mut Array<StrRef>) -> FfiResult<NullPtr> {
881    check_null!(x, FfiErrorCode::ArrayNullPointer, null());
882    drop(Box::from_raw(x));
883    FfiResult::ok(null())
884}
885
886/// # Safety
887/// Free the array of warnings.
888///
889/// # Arguments
890/// * `warnings` - Pointer to the array of warnings
891///
892/// # Examples
893///
894/// ```c
895/// FPArrayWarningFree(warnings);
896/// ```
897///
898#[export_name = "FPArrayWarningFree"]
899pub unsafe extern "C" fn array_warning_free(
900    warnings: *mut Array<parser::Warning>,
901) -> FfiResult<NullPtr> {
902    check_null!(warnings, FfiErrorCode::ArrayNullPointer, null());
903    drop(Box::from_raw(warnings));
904    FfiResult::ok(null())
905}
906
907/// # Safety
908/// Parse the inline style from the string.
909///
910/// # Arguments
911/// * `inline_style_text_ptr` - Pointer to the inline style text
912/// * `warnings` - Optional output parameter to receive warnings array pointer
913///
914/// # Examples
915///
916/// ```c
917/// FPParseInlineStyle(inline_style_text_ptr, warnings);
918/// ```
919///
920#[export_name = "FPParseInlineStyle"]
921pub unsafe extern "C" fn parse_inline_style(
922    inline_style_text_ptr: *const c_char,
923    warnings: *mut *mut Array<parser::Warning>,
924) -> FfiResult<*mut InlineRule> {
925    check_null!(
926        inline_style_text_ptr,
927        FfiErrorCode::InlineStyleTextNullPointer,
928        null_mut()
929    );
930    let inline_style_text = CStr::from_ptr(inline_style_text_ptr).to_string_lossy();
931    let (prop, w) =
932        parser::parse_inline_style(&inline_style_text, parser::StyleParsingDebugMode::None);
933    if !warnings.is_null() {
934        *warnings = Box::into_raw(Box::new(w.into()));
935    }
936    let mut important = BitSet::new();
937    let mut bs_empty = true;
938    let properties = prop
939        .into_iter()
940        .enumerate()
941        .map(|(index, x)| match x {
942            PropertyMeta::Normal { property } => property,
943            PropertyMeta::Important { property } => {
944                important.insert(index);
945                bs_empty = false;
946                property
947            }
948            PropertyMeta::DebugGroup { .. } => Property::Unknown,
949        })
950        .collect();
951    let important = if bs_empty {
952        ImportantBitSet::None
953    } else {
954        ImportantBitSet::Array(important.into_bit_vec().to_bytes().into())
955    };
956    let inline_rule = InlineRule::new(properties, important);
957    FfiResult::ok(Box::into_raw(Box::new(inline_rule)))
958}
959
960/// # Safety
961/// Free the inline style.
962///
963/// # Arguments
964/// * `inline_rule` - Pointer to the inline style
965///
966/// # Examples
967///
968/// ```c
969/// FPInlineStyleFree(inline_rule);
970/// ```
971///
972#[export_name = "FPInlineStyleFree"]
973pub unsafe extern "C" fn inline_style_free(inline_rule: *mut InlineRule) -> FfiResult<NullPtr> {
974    check_null!(inline_rule, FfiErrorCode::InlineRuleNullPointer, null());
975    drop(Box::from_raw(inline_rule));
976    FfiResult::ok(null())
977}
978
979/// # Safety
980/// Parse the style sheet from the string.
981///
982/// # Arguments
983/// * `style_text_ptr` - Pointer to the style sheet text
984///
985/// # Examples
986///
987/// ```c
988/// FPStyleSheetFromString(style_text_ptr);
989/// ```
990///
991#[export_name = "FPParseStyleSheetFromString"]
992pub unsafe extern "C" fn parse_style_sheet_from_string(
993    style_text_ptr: *const c_char,
994) -> FfiResult<*mut StyleSheet> {
995    check_null!(
996        style_text_ptr,
997        FfiErrorCode::StyleTextNullPointer,
998        null_mut()
999    );
1000    let style_text = CStr::from_ptr(style_text_ptr).to_string_lossy();
1001    let (compiled_style_sheet, _) = parser::parse_style_sheet("string", &style_text);
1002    let style_sheet = StyleSheet::from_sheet(&compiled_style_sheet);
1003    FfiResult::ok(Box::into_raw(Box::new(style_sheet)))
1004}
1005
1006/// # Safety
1007/// Parse the selector from the string.
1008///
1009/// # Arguments
1010/// * `selector_text_ptr` - Pointer to the selector text
1011///
1012/// # Examples
1013///
1014/// ```c
1015/// FPParseSelectorFromString(selector_text_ptr);
1016/// ```
1017///
1018#[export_name = "FPParseSelectorFromString"]
1019pub unsafe extern "C" fn parse_selector_from_string(
1020    selector_text_ptr: *const c_char,
1021) -> FfiResult<*mut Selector> {
1022    check_null!(
1023        selector_text_ptr,
1024        FfiErrorCode::SelectorTextNullPointer,
1025        null_mut()
1026    );
1027    let selector_text = CStr::from_ptr(selector_text_ptr).to_string_lossy();
1028    let selector = Selector::from_string(&selector_text);
1029    FfiResult::ok(Box::into_raw(Box::new(selector)))
1030}
1031
1032/// # Safety
1033/// Free the selector.
1034///
1035/// # Arguments
1036/// * `selector` - Pointer to the selector
1037///
1038/// # Examples
1039///
1040/// ```c
1041/// FPSelectorFree(selector);
1042/// ```
1043///
1044#[export_name = "FPSelectorFree"]
1045pub unsafe extern "C" fn selector_free(selector: *mut Selector) -> FfiResult<NullPtr> {
1046    check_null!(selector, FfiErrorCode::SelectorNullPointer, null());
1047    drop(Box::from_raw(selector));
1048    FfiResult::ok(null())
1049}
1050
1051/// # Safety
1052/// Free the style sheet.
1053///
1054/// # Arguments
1055/// * `style_sheet` - Pointer to the style sheet
1056///
1057/// # Examples
1058///
1059/// ```c
1060/// FPStyleSheetFree(style_sheet);
1061/// ```
1062///
1063#[export_name = "FPStyleSheetFree"]
1064pub unsafe extern "C" fn style_sheet_free(style_sheet: *mut StyleSheet) -> FfiResult<NullPtr> {
1065    check_null!(style_sheet, FfiErrorCode::StyleSheetNullPointer, null());
1066    drop(Box::from_raw(style_sheet));
1067    FfiResult::ok(null())
1068}
1069
1070/// # Safety
1071/// Get the version of the style sheet in the binary format.
1072///
1073/// # Arguments
1074/// * `buffer_ptr` - Pointer to the buffer
1075/// * `buffer_len` - Length of the buffer
1076///
1077/// # Examples
1078///
1079/// ```c
1080/// FPStyleSheetBincodeVersion(buffer_ptr, buffer_len);
1081/// ```
1082///
1083#[cfg(feature = "deserialize")]
1084#[export_name = "FPStyleSheetBincodeVersion"]
1085pub unsafe extern "C" fn style_sheet_bincode_version(
1086    buffer_ptr: *mut u8,
1087    buffer_len: usize,
1088) -> FfiResult<*mut StrRef> {
1089    use float_pigment_consistent_bincode::Options;
1090    check_null!(buffer_ptr, FfiErrorCode::BufferNullPointer, null_mut());
1091    let sheet = de_static_ref_zero_copy_env(
1092        core::slice::from_raw_parts_mut(buffer_ptr, buffer_len),
1093        |s| {
1094            let s: Result<StyleSheet, _> = float_pigment_consistent_bincode::DefaultOptions::new()
1095                .allow_trailing_bytes()
1096                .deserialize(s);
1097            match s {
1098                Ok(ss) => ss,
1099                Err(err) => {
1100                    let mut ss = StyleSheet::from_sheet(&sheet::CompiledStyleSheet::new());
1101                    if let StyleSheet::V1(ssv) = &mut ss {
1102                        ssv.version = Box::new(
1103                            format!(
1104                                "Failed to deserialize bincode formatted style sheet: {}",
1105                                err
1106                            )
1107                            .into(),
1108                        );
1109                    }
1110                    ss
1111                }
1112            }
1113        },
1114        move || {},
1115    );
1116    let version = match sheet {
1117        StyleSheet::V1(v1) => v1.version,
1118        _ => Box::new("unknown version".into()),
1119    };
1120    FfiResult::ok(Box::into_raw(version))
1121}
1122
1123/// # Safety
1124/// Get the version of the CSS parser.
1125///
1126/// # Examples
1127///
1128/// ```c
1129/// FPCssParserVersion();
1130/// ```
1131#[export_name = "FPCssParserVersion"]
1132pub unsafe extern "C" fn css_parser_version() -> FfiResult<*mut StrRef> {
1133    let version = env!("CARGO_PKG_VERSION").to_string().into();
1134    FfiResult::ok(Box::into_raw(Box::new(version)))
1135}
1136
1137#[repr(C)]
1138#[derive(Debug, Default)]
1139pub struct ColorValue {
1140    red: u8,
1141    green: u8,
1142    blue: u8,
1143    alpha: u8,
1144}
1145
1146/// # Safety
1147/// Parse the color from the string.
1148///
1149/// # Arguments
1150/// * `source` - Pointer to the source string
1151///
1152/// # Examples
1153///
1154/// ```c
1155/// FPParseColorFromString(source);
1156/// ```
1157///
1158#[export_name = "FPParseColorFromString"]
1159pub unsafe extern "C" fn parse_color_from_string(source: *const c_char) -> FfiResult<ColorValue> {
1160    check_null!(
1161        source,
1162        FfiErrorCode::SourceNullPointer,
1163        ColorValue::default()
1164    );
1165    let source = CStr::from_ptr(source).to_string_lossy();
1166    let ret = parse_color_to_rgba(&source);
1167    FfiResult::ok(ColorValue {
1168        red: ret.0,
1169        green: ret.1,
1170        blue: ret.2,
1171        alpha: ret.3,
1172    })
1173}
1174
1175/// # Safety
1176/// Substitute the variable in the expression.
1177///
1178/// # Arguments
1179/// * `expr_ptr` - Pointer to the expression
1180/// * `map` - Pointer to the map
1181/// * `getter` - Custom property getter
1182/// * `setter` - Custom property setter
1183///
1184/// # Examples
1185///
1186/// ```c
1187/// FPSubstituteVariable(expr_ptr, map, getter, setter);
1188/// ```
1189///
1190#[export_name = "FPSubstituteVariable"]
1191pub unsafe extern "C" fn substitute_variable(
1192    expr_ptr: *const c_char,
1193    map: RawMutPtr,
1194    getter: CustomPropertyGetter,
1195    setter: CustomPropertySetter,
1196) -> FfiResult<*const c_char> {
1197    check_null!(expr_ptr, FfiErrorCode::ExprPtrNullPointer, null());
1198    check_null!(map, FfiErrorCode::MapNullPointer, null());
1199    let expr = CStr::from_ptr(expr_ptr).to_string_lossy();
1200    let context = CustomPropertyContext::create(map, getter, setter);
1201    if let Some(ret) = parser::property_value::var::substitute_variable(&expr, &context) {
1202        if let Ok(r) = CString::new(ret) {
1203            return FfiResult::ok(r.into_raw());
1204        }
1205    }
1206    FfiResult::ok(null())
1207}
1208
1209/// # Safety
1210/// Free the string.
1211///
1212/// # Arguments
1213/// * `ptr` - Pointer to the string
1214///
1215/// # Examples
1216///
1217/// ```c
1218/// FPStrFree(ptr);
1219/// ```
1220///
1221#[export_name = "FPStrFree"]
1222pub unsafe extern "C" fn str_free(ptr: *const c_char) -> FfiResult<NullPtr> {
1223    check_null!(ptr, FfiErrorCode::StrNullPointer, null());
1224    drop(CString::from_raw(ptr as *mut c_char));
1225    FfiResult::ok(null())
1226}