falco_plugin/plugin/exported_tables/
table.rs1use crate::plugin::exported_tables::entry::extensible::ExtensibleEntry;
2use crate::plugin::exported_tables::entry::table_metadata::extensible::ExtensibleEntryMetadata;
3use crate::plugin::exported_tables::entry::table_metadata::traits::TableMetadata;
4use crate::plugin::exported_tables::entry::traits::Entry;
5use crate::plugin::exported_tables::field_descriptor::{FieldDescriptor, FieldRef};
6use crate::plugin::exported_tables::field_value::dynamic::DynamicFieldValue;
7use crate::plugin::exported_tables::metadata::HasMetadata;
8use crate::plugin::exported_tables::metadata::Metadata;
9use crate::plugin::exported_tables::ref_shared::{
10 new_counted_ref, new_shared_ref, RefCounted, RefGuard, RefShared,
11};
12use crate::plugin::exported_tables::vtable::Vtable;
13use crate::plugin::tables::data::{FieldTypeId, Key};
14use crate::FailureReason;
15use falco_plugin_api::{ss_plugin_state_data, ss_plugin_table_fieldinfo};
16use std::borrow::Borrow;
17use std::collections::BTreeMap;
18use std::ffi::CStr;
19use std::fmt::{Debug, Formatter};
20
21#[must_use]
39pub struct Table<K, E>
40where
41 K: Key + Ord,
42 K: Borrow<<K as Key>::Borrowed>,
43 <K as Key>::Borrowed: Ord + ToOwned<Owned = K>,
44 E: Entry,
45 E::Metadata: TableMetadata,
46{
47 name: &'static CStr,
48 field_descriptors: Vec<ss_plugin_table_fieldinfo>,
49 metadata: RefShared<ExtensibleEntryMetadata<E::Metadata>>,
50 data: RefShared<BTreeMap<K, RefShared<ExtensibleEntry<E>>>>,
51
52 pub(in crate::plugin::exported_tables) vtable: RefCounted<Option<Box<Vtable>>>,
53}
54
55impl<K, E> Debug for Table<K, E>
56where
57 K: Key + Ord + Debug,
58 K: Borrow<<K as Key>::Borrowed>,
59 <K as Key>::Borrowed: Ord + ToOwned<Owned = K>,
60 E: Entry + Debug,
61 E::Metadata: TableMetadata + Debug,
62{
63 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
64 f.debug_struct("Table")
65 .field("name", &self.name)
66 .field("metadata", &self.metadata)
67 .field("data", &self.data)
68 .finish()
69 }
70}
71
72type TableMetadataType<E> = RefShared<ExtensibleEntryMetadata<<E as HasMetadata>::Metadata>>;
73pub(in crate::plugin::exported_tables) type TableEntryType<E> = RefGuard<ExtensibleEntry<E>>;
74
75impl<K, E> Table<K, E>
76where
77 K: Key + Ord,
78 K: Borrow<<K as Key>::Borrowed>,
79 <K as Key>::Borrowed: Ord + ToOwned<Owned = K>,
80 E: Entry,
81 E::Metadata: TableMetadata,
82{
83 pub fn new_with_metadata(
87 tag: &'static CStr,
88 metadata: &TableMetadataType<E>,
89 ) -> Result<Self, anyhow::Error> {
90 let table = Self {
91 name: tag,
92 field_descriptors: vec![],
93 metadata: metadata.clone(),
94 data: new_shared_ref(BTreeMap::new()),
95
96 vtable: new_counted_ref(None),
97 };
98
99 Ok(table)
100 }
101
102 pub fn new(name: &'static CStr) -> Result<Self, anyhow::Error> {
104 Ok(Self {
105 name,
106 field_descriptors: vec![],
107 metadata: new_shared_ref(ExtensibleEntryMetadata::new()?),
108 data: new_shared_ref(BTreeMap::new()),
109
110 vtable: new_counted_ref(None),
111 })
112 }
113
114 pub fn data(&self) -> RefShared<BTreeMap<K, RefShared<ExtensibleEntry<E>>>> {
124 self.data.clone()
125 }
126
127 pub fn name(&self) -> &'static CStr {
129 self.name
130 }
131
132 pub fn size(&self) -> usize {
134 self.data.read().len()
135 }
136
137 pub fn lookup<Q>(&self, key: &Q) -> Option<TableEntryType<E>>
139 where
140 K: Borrow<Q>,
141 Q: Ord + ?Sized,
142 {
143 Some(self.data.read().get(key)?.write_arc())
144 }
145
146 pub fn get_field_value(
148 &self,
149 entry: &TableEntryType<E>,
150 field: &FieldDescriptor,
151 out: &mut ss_plugin_state_data,
152 ) -> Result<(), anyhow::Error> {
153 let (type_id, index) = { (field.type_id, field.index) };
154
155 entry.get(index, type_id, out)
156 }
157
158 pub fn iterate_entries<F>(&mut self, mut func: F) -> bool
163 where
164 F: FnMut(&mut TableEntryType<E>) -> bool,
165 {
166 for value in &mut self.data.write().values_mut() {
167 if !func(&mut value.write_arc()) {
168 return false;
169 }
170 }
171 true
172 }
173
174 pub fn clear(&mut self) {
176 self.data.write().clear()
177 }
178
179 pub fn erase<Q>(&mut self, key: &Q) -> Option<TableEntryType<E>>
181 where
182 K: Borrow<Q>,
183 Q: Ord + ?Sized,
184 {
185 Some(self.data.write().remove(key)?.write_arc())
186 }
187
188 pub fn create_entry(&self) -> Result<TableEntryType<E>, anyhow::Error> {
192 Ok(new_shared_ref(ExtensibleEntry::new_with_metadata(
193 self.name,
194 &self.metadata,
195 )?)
196 .write_arc())
197 }
198
199 pub fn create_entry_fn(
216 &self,
217 ) -> impl Fn() -> Result<RefShared<ExtensibleEntry<E>>, anyhow::Error> {
218 let name = self.name;
219 let metadata = self.metadata.clone();
220
221 move || {
222 Ok(new_shared_ref(ExtensibleEntry::new_with_metadata(
223 name, &metadata,
224 )?))
225 }
226 }
227
228 pub fn insert<Q>(&mut self, key: &Q, entry: TableEntryType<E>) -> Option<TableEntryType<E>>
230 where
231 K: Borrow<Q>,
232 Q: Ord + ToOwned<Owned = K> + ?Sized,
233 {
234 self.data.write().insert(
236 key.to_owned(),
237 std::sync::Arc::clone(RefGuard::rwlock(&entry)),
238 );
239 drop(entry);
240 self.lookup(key)
241 }
242
243 pub fn write(
245 &self,
246 entry: &mut TableEntryType<E>,
247 field: &FieldDescriptor,
248 value: &ss_plugin_state_data,
249 ) -> Result<(), anyhow::Error> {
250 if field.read_only {
251 return Err(anyhow::anyhow!("Field is read-only").context(FailureReason::NotSupported));
252 }
253
254 let (type_id, index) = { (field.type_id, field.index) };
255
256 let value = unsafe {
257 DynamicFieldValue::from_data(value, type_id).ok_or_else(|| {
258 anyhow::anyhow!("Cannot store {:?} data (unsupported type)", type_id)
259 })?
260 };
261
262 entry.set(index, value)
263 }
264
265 pub fn list_fields(&mut self) -> &[ss_plugin_table_fieldinfo] {
267 self.field_descriptors.clear();
268 self.field_descriptors.extend(self.metadata.list_fields());
269 self.field_descriptors.as_slice()
270 }
271
272 pub fn get_field(&self, name: &CStr, field_type: FieldTypeId) -> Option<FieldRef> {
276 self.metadata
277 .get_field(name)
278 .filter(|f| f.as_ref().type_id == field_type)
279 }
280
281 pub fn add_field(
283 &mut self,
284 name: &CStr,
285 field_type: FieldTypeId,
286 read_only: bool,
287 ) -> Option<FieldRef> {
288 self.metadata.add_field(name, field_type, read_only)
289 }
290}
291
292#[cfg(test)]
293mod tests {
294 use crate::plugin::exported_tables::entry::dynamic::DynamicEntry;
295 use crate::tables::export::Table;
296 use crate::tables::import::Bool;
297 use crate::tables::TablesInput;
298 use std::ffi::CString;
299
300 #[allow(unused)]
302 fn add_table(input: &TablesInput) -> anyhow::Result<()> {
303 input.add_table(Table::<i8, DynamicEntry>::new(c"exported")?)?;
304 input.add_table(Table::<i16, DynamicEntry>::new(c"exported")?)?;
305 input.add_table(Table::<i32, DynamicEntry>::new(c"exported")?)?;
306 input.add_table(Table::<i64, DynamicEntry>::new(c"exported")?)?;
307 input.add_table(Table::<u8, DynamicEntry>::new(c"exported")?)?;
308 input.add_table(Table::<u16, DynamicEntry>::new(c"exported")?)?;
309 input.add_table(Table::<u32, DynamicEntry>::new(c"exported")?)?;
310 input.add_table(Table::<u64, DynamicEntry>::new(c"exported")?)?;
311 input.add_table(Table::<Bool, DynamicEntry>::new(c"exported")?)?;
312 input.add_table(Table::<CString, DynamicEntry>::new(c"exported")?)?;
313
314 Ok(())
315 }
316}