use crate::plugin::tables::data::{seal, FieldTypeId, Key, TableData, Value};
use crate::plugin::tables::field::Field;
use crate::plugin::tables::runtime::NoMetadata;
use crate::plugin::tables::runtime_table_validator::RuntimeTableValidator;
use crate::plugin::tables::table::raw::{IterationResult, RawTable};
use crate::plugin::tables::traits::{Entry, TableAccess, TableMetadata};
use crate::plugin::tables::vtable::fields::TableFields;
use crate::plugin::tables::vtable::reader::TableReader;
use crate::plugin::tables::vtable::writer::TableWriter;
use crate::plugin::tables::vtable::TablesInput;
use anyhow::Error;
use falco_plugin_api::{ss_plugin_state_data, ss_plugin_table_field_t, ss_plugin_table_fieldinfo};
use std::ffi::CStr;
use std::marker::PhantomData;
use std::ops::ControlFlow;
pub(in crate::plugin::tables) mod raw;
#[derive(Debug)]
pub struct Table<K, E = super::entry::Entry<NoMetadata<()>>, M = <E as Entry>::Metadata> {
pub(in crate::plugin::tables) raw_table: RawTable,
pub(in crate::plugin::tables) metadata: M,
pub(in crate::plugin::tables) is_nested: bool,
pub(in crate::plugin::tables) key_type: PhantomData<K>,
pub(in crate::plugin::tables) entry_type: PhantomData<E>,
}
impl<K, E, M> TableAccess for Table<K, E, M>
where
K: Key,
E: Entry<Metadata = M>,
M: TableMetadata + Clone,
{
type Key = K;
type Entry = E;
type Metadata = M;
fn new(raw_table: RawTable, metadata: Self::Metadata, is_nested: bool) -> Self {
Self {
raw_table,
metadata,
is_nested,
key_type: PhantomData,
entry_type: PhantomData,
}
}
fn get_entry(
&self,
reader_vtable: &impl TableReader,
key: &Self::Key,
) -> Result<Self::Entry, Error>
where
Self::Key: Key,
Self::Entry: Entry,
{
Table::get_entry(self, reader_vtable, key)
}
}
impl<K, E, M> Table<K, E, M>
where
K: Key,
E: Entry<Metadata = M>,
M: TableMetadata + Clone,
{
pub fn get_entry(&self, reader_vtable: &impl TableReader, key: &K) -> Result<E, Error> {
let raw_entry = self.raw_table.get_entry(reader_vtable, key)?;
Ok(E::new(
raw_entry,
self.raw_table.table,
self.metadata.clone(),
))
}
pub fn erase(&self, writer_vtable: &impl TableWriter, key: &K) -> Result<(), Error> {
unsafe { self.raw_table.erase(writer_vtable, key) }
}
pub fn insert(
&self,
reader_vtable: &impl TableReader,
writer_vtable: &impl TableWriter,
key: &K,
entry: E,
) -> Result<E, Error> {
let raw_entry = unsafe {
self.raw_table
.insert(reader_vtable, writer_vtable, key, entry.into_raw())
}?;
Ok(E::new(
raw_entry,
self.raw_table.table,
self.metadata.clone(),
))
}
}
impl<K, E, M> Table<K, E, M>
where
E: Entry<Metadata = M>,
M: TableMetadata + Clone,
{
pub(in crate::plugin::tables) fn new_without_key(
raw_table: RawTable,
metadata: E::Metadata,
is_nested: bool,
) -> Self {
Self {
raw_table,
metadata,
is_nested,
key_type: PhantomData,
entry_type: PhantomData,
}
}
pub(in crate::plugin::tables) fn table_validator(&self) -> RuntimeTableValidator {
let ptr = if self.is_nested {
std::ptr::null_mut()
} else {
self.raw_table.table
};
RuntimeTableValidator::new(ptr)
}
pub fn create_entry(&self, writer_vtable: &impl TableWriter) -> Result<E, Error> {
let raw_entry = self.raw_table.create_entry(writer_vtable)?;
Ok(E::new(
raw_entry,
self.raw_table.table,
self.metadata.clone(),
))
}
pub fn clear(&self, writer_vtable: &impl TableWriter) -> Result<(), Error> {
self.raw_table.clear(writer_vtable)
}
pub fn list_fields(&self, fields_vtable: &TableFields) -> &[ss_plugin_table_fieldinfo] {
self.raw_table.list_fields(fields_vtable)
}
pub fn get_field<V: Value + ?Sized>(
&self,
tables_input: &TablesInput,
name: &CStr,
) -> Result<Field<V, E>, Error> {
let field = self.raw_table.get_field(tables_input, name)?;
Ok(Field::new(field, self.table_validator()))
}
pub fn get_table_field<NK, V, U, F, R>(
&self,
tables_input: &TablesInput,
name: &CStr,
func: F,
) -> Result<(Field<V, E>, R), Error>
where
NK: Key,
for<'a> V::AssocData: From<&'a M>,
V: Value + ?Sized,
U: Entry,
U::Metadata: for<'a> From<&'a V::AssocData>,
F: FnOnce(&Table<(), U>) -> Result<R, Error>,
{
let field = self.raw_table.get_field::<V>(tables_input, name)?;
let metadata = U::Metadata::from(&field.assoc_data);
let fields = unsafe {
self.raw_table
.with_subtable::<NK, _, _>(field.field, tables_input, |subtable| {
let owned = RawTable {
table: subtable.table,
};
let table = Table::new_without_key(owned, metadata, true);
func(&table)
})??
};
let field = Field::new(field, self.table_validator());
Ok((field, fields))
}
pub fn add_field<V: Value<AssocData = ()> + ?Sized>(
&self,
tables_input: &TablesInput,
name: &CStr,
) -> Result<Field<V, E>, Error> {
let field = self.raw_table.add_field(tables_input, name)?;
Ok(Field::new(field, self.table_validator()))
}
pub fn get_name(&self, reader_vtable: &impl TableReader) -> anyhow::Result<&str> {
self.raw_table.get_name(reader_vtable)
}
pub fn get_size(&self, reader_vtable: &impl TableReader) -> anyhow::Result<usize> {
self.raw_table.get_size(reader_vtable)
}
pub fn iter_entries_mut<F>(
&self,
reader_vtable: &impl TableReader,
mut func: F,
) -> anyhow::Result<IterationResult>
where
F: FnMut(&mut E) -> ControlFlow<()>,
{
self.raw_table.iter_entries_mut(reader_vtable, move |raw| {
let mut entry = E::new(raw, self.raw_table.table, self.metadata.clone());
func(&mut entry)
})
}
}
impl<K, E, M> seal::Sealed for Table<K, E, M> {}
impl<K, E, M> TableData for Table<K, E, M> {
const TYPE_ID: FieldTypeId = FieldTypeId::Table;
fn to_data(&self) -> ss_plugin_state_data {
ss_plugin_state_data {
table: self.raw_table.table,
}
}
}
impl<K, E, M> Value for Table<K, E, M>
where
K: Key + 'static,
E: Entry<Metadata = M> + 'static,
M: TableMetadata + Clone + 'static,
{
type AssocData = M;
type Value<'a>
= Self
where
Self: 'a;
unsafe fn from_data_with_assoc<'a>(
data: &ss_plugin_state_data,
assoc: &Self::AssocData,
) -> Self::Value<'a> {
let table = unsafe { RawTable { table: data.table } };
Table::new(table, assoc.clone(), true)
}
unsafe fn get_assoc_from_raw_table(
table: &RawTable,
field: *mut ss_plugin_table_field_t,
tables_input: &TablesInput,
) -> Result<Self::AssocData, Error> {
unsafe {
table.with_subtable::<K, _, _>(field, tables_input, |subtable| {
M::new(subtable, tables_input)
})?
}
}
}