float_pigment_css/parser/
hooks.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//! Parser hooks can be used to attach some compilation information.

use alloc::vec::Vec;
#[cfg(feature = "ffi")]
use core::ffi::{c_char, CStr};

use cssparser::SourceLocation;

use super::{Warning, WarningKind};
use crate::property::Property;

/// A `context` for current sompilation step.
pub struct ParserHooksContext<'a> {
    pub(super) warnings: &'a mut Vec<Warning>,
    pub(super) start_loc: SourceLocation,
    pub(super) end_loc: SourceLocation,
}

impl<'a> ParserHooksContext<'a> {
    /// Generate a new warning in the current location.
    pub fn generate_warning(&mut self, message: &str) {
        let start = self.start_loc;
        let end = self.end_loc;
        self.warnings.push(Warning {
            kind: WarningKind::HooksGenerated,
            message: message.into(),
            start_line: start.line,
            start_col: start.column,
            end_line: end.line,
            end_col: end.column,
        })
    }
}

/// A list of hooks that can be implemented.
pub trait Hooks {
    /// Trigger once whenever a property has been parsed.
    fn parsed_property(&mut self, _ctx: &mut ParserHooksContext, _p: &mut Property) {}
}

/// The C FFI for `ParserHooksContext`.
#[cfg(feature = "ffi")]
#[repr(C)]
pub struct CParserHooksContext {
    inner: *mut (),
}

#[cfg(feature = "ffi")]
impl CParserHooksContext {
    /// The C FFI for `ParserHooksContext::generate_warning`.
    ///
    /// # Safety
    ///
    /// The message should be a valid C string.
    #[no_mangle]
    pub unsafe extern "C" fn generate_warning(&mut self, message: *const c_char) {
        let message = CStr::from_ptr(message).to_string_lossy();
        let ctx = &mut *(self.inner as *mut ParserHooksContext);
        ctx.generate_warning(&message);
    }
}

/// The C FFI for `ParserHooks`.
#[cfg(feature = "ffi")]
#[repr(C)]
pub struct CParserHooks {
    parsed_property: extern "C" fn(CParserHooksContext, *mut Property),
}

#[cfg(feature = "ffi")]
impl Hooks for CParserHooks {
    fn parsed_property(&mut self, ctx: &mut ParserHooksContext, p: &mut Property) {
        let ctx = CParserHooksContext {
            inner: ctx as *mut _ as *mut (),
        };
        let f = &mut self.parsed_property;
        f(ctx, p);
    }
}