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 {}