libddwaf/
builder.rs

1use std::ptr::null_mut;
2
3use crate::object::{AsRawMutObject, WafArray, WafMap, WafOwned};
4use crate::{Config, Handle};
5
6/// A builder for [`Handle`]s.
7///
8/// This is used to maintain a live view over mutable configuration, and is best
9/// suited for cases where the Waf's configuration evolves regularly, such as
10/// through remote configuration.
11#[repr(transparent)]
12pub struct Builder {
13    raw: libddwaf_sys::ddwaf_builder,
14}
15impl Builder {
16    /// Creates a new [`Builder`] instance using the provided [`Config`]. Returns [`None`] if the
17    /// builder's initialization fails.
18    #[must_use]
19    pub fn new(config: &Config) -> Option<Self> {
20        let builder = Builder {
21            raw: unsafe { libddwaf_sys::ddwaf_builder_init(&raw const config.raw) },
22        };
23        if builder.raw.is_null() {
24            return None;
25        }
26        Some(builder)
27    }
28
29    /// Adds or updates the configuration for the given path.
30    ///
31    /// Returns true if the ruleset was successfully added or updated. Any warning/error information
32    /// is conveyed through the provided diagnostics object.
33    ///
34    /// # Panics
35    /// Panics if the provided `path` is longer than [`u32::MAX`] bytes.
36    #[must_use]
37    pub fn add_or_update_config(
38        &mut self,
39        path: &str,
40        ruleset: &impl AsRef<libddwaf_sys::ddwaf_object>,
41        diagnostics: Option<&mut WafOwned<WafMap>>,
42    ) -> bool {
43        debug_assert!(
44            !path.is_empty(),
45            concat!(
46                "path cannot be empty (",
47                stringify!(bindings::ddwaf_builder_add_or_update_config),
48                " would always fail)"
49            )
50        );
51        let path_len = u32::try_from(path.len()).expect("path is too long");
52        unsafe {
53            libddwaf_sys::ddwaf_builder_add_or_update_config(
54                self.raw,
55                path.as_ptr().cast(),
56                path_len,
57                ruleset.as_ref(),
58                diagnostics.map_or(null_mut(), |o| std::ptr::from_mut(o.as_raw_mut()).cast()),
59            )
60        }
61    }
62
63    /// Removes the configuration for the given path if some exists.
64    ///
65    /// Returns true if some configuration was indeed removed.
66    ///
67    /// # Panics
68    /// Panics if the provided `path` is longer than [`u32::MAX`] bytes.
69    pub fn remove_config(&mut self, path: &str) -> bool {
70        let path_len = u32::try_from(path.len()).expect("path is too long");
71        unsafe {
72            libddwaf_sys::ddwaf_builder_remove_config(self.raw, path.as_ptr().cast(), path_len)
73        }
74    }
75
76    /// Returns the number of configuration paths currently loaded in this [`Builder`], optionally
77    /// filtered by a regular expression.
78    ///
79    /// # Panics
80    /// Panics if the provided `filter` regular expression is longer than [`u32::MAX`] bytes.
81    #[must_use]
82    pub fn config_paths_count(&mut self, filter: Option<&'_ str>) -> u32 {
83        let filter = filter.unwrap_or("");
84        let filter_len = u32::try_from(filter.len()).expect("filter is too long");
85        unsafe {
86            libddwaf_sys::ddwaf_builder_get_config_paths(
87                self.raw,
88                null_mut(),
89                filter.as_ptr().cast(),
90                filter_len,
91            )
92        }
93    }
94
95    /// Returns the configuration paths currently loaded in this [`Builder`], optionally filtered by
96    /// a regular expression.
97    ///
98    /// # Panics
99    /// Panics if the provided `filter` regular expression is longer than [`u32::MAX`] bytes.
100    #[must_use]
101    pub fn config_paths(&mut self, filter: Option<&'_ str>) -> WafOwned<WafArray> {
102        let mut res = WafOwned::<WafArray>::default();
103        let filter = filter.unwrap_or("");
104        let filter_len = u32::try_from(filter.len()).expect("filter is too long");
105        let _ = unsafe {
106            libddwaf_sys::ddwaf_builder_get_config_paths(
107                self.raw,
108                res.as_raw_mut(),
109                filter.as_ptr().cast(),
110                filter_len,
111            )
112        };
113        res
114    }
115
116    /// Builds a new [`Handle`] from the current configuration in this [`Builder`].
117    ///
118    /// Returns [`None`] if the builder fails to create a new [`Handle`], meaning the current
119    /// configuration contains no active instructions (no rules nor processors are available).
120    #[must_use]
121    pub fn build(&mut self) -> Option<Handle> {
122        let raw = unsafe { libddwaf_sys::ddwaf_builder_build_instance(self.raw) };
123        if raw.is_null() {
124            return None;
125        }
126        Some(Handle { raw })
127    }
128}
129impl Drop for Builder {
130    fn drop(&mut self) {
131        unsafe { libddwaf_sys::ddwaf_builder_destroy(self.raw) }
132    }
133}
134
135// SAFETY: no thread-local data and no data can be changed under us if we have an owning handle
136unsafe impl Send for Builder {}
137// SAFETY: changes are only made through exclusive references
138unsafe impl Sync for Builder {}