use crate::plugin::extract::extractor_fn::{ExtractLambda, ExtractorFn};
use crate::plugin::extract::fields::{Extract, ExtractFieldTypeId};
use crate::plugin::extract::ExtractPlugin;
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use std::fmt::{Debug, Formatter};
#[derive(Clone, Copy, Debug)]
pub enum ExtractArgType {
None,
OptionalIndex,
OptionalKey,
RequiredIndex,
RequiredKey,
}
impl Serialize for ExtractArgType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
ExtractArgType::None => serializer.serialize_none(),
ExtractArgType::OptionalIndex => {
let mut ss = serializer.serialize_struct("arg", 1)?;
ss.serialize_field("isIndex", &true)?;
ss.end()
}
ExtractArgType::OptionalKey => {
let mut ss = serializer.serialize_struct("arg", 1)?;
ss.serialize_field("isKey", &true)?;
ss.end()
}
ExtractArgType::RequiredIndex => {
let mut ss = serializer.serialize_struct("arg", 2)?;
ss.serialize_field("isIndex", &true)?;
ss.serialize_field("isRequired", &true)?;
ss.end()
}
ExtractArgType::RequiredKey => {
let mut ss = serializer.serialize_struct("arg", 2)?;
ss.serialize_field("isKey", &true)?;
ss.serialize_field("isRequired", &true)?;
ss.end()
}
}
}
}
pub fn serialize_field_type<S: Serializer>(
f: &ExtractFieldTypeId,
serializer: S,
) -> Result<S::Ok, S::Error> {
match f {
ExtractFieldTypeId::U64 => serializer.serialize_str("uint64"),
ExtractFieldTypeId::String => serializer.serialize_str("string"),
ExtractFieldTypeId::RelTime => serializer.serialize_str("reltime"),
ExtractFieldTypeId::AbsTime => serializer.serialize_str("abstime"),
ExtractFieldTypeId::Bool => serializer.serialize_str("bool"),
ExtractFieldTypeId::IpAddr => serializer.serialize_str("ipaddr"),
ExtractFieldTypeId::IpNet => serializer.serialize_str("ipnet"),
}
}
fn is_false(b: &bool) -> bool {
!*b
}
#[derive(Serialize)]
pub struct ExtractFieldInfo<P: ExtractPlugin> {
pub name: &'static str,
#[serde(rename = "type")]
#[serde(serialize_with = "serialize_field_type")]
pub field_type: ExtractFieldTypeId,
#[serde(rename = "isList")]
pub is_list: bool,
pub arg: ExtractArgType,
#[serde(rename = "display")]
pub display_name: Option<&'static str>,
#[serde(rename = "desc")]
pub description: &'static str,
#[serde(rename = "addOutput")]
#[serde(skip_serializing_if = "is_false")]
pub add_output: bool,
#[serde(skip)]
pub func: ExtractLambda<P>,
}
impl<P: ExtractPlugin> Debug for ExtractFieldInfo<P> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let json = serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)?;
f.write_str(&json)
}
}
impl<P: ExtractPlugin> ExtractFieldInfo<P> {
pub const fn with_display(mut self, display_name: &'static str) -> Self {
self.display_name = Some(display_name);
self
}
pub const fn with_description(mut self, description: &'static str) -> Self {
self.description = description;
self
}
pub const fn add_output(mut self) -> Self {
self.add_output = true;
self
}
}
pub const fn field<P, R, F, A>(name: &'static str, func: &'static F) -> ExtractFieldInfo<P>
where
P: ExtractPlugin,
R: Extract + 'static,
F: ExtractorFn<P, R, A>,
A: 'static,
{
ExtractFieldInfo {
name,
field_type: <R as Extract>::TYPE_ID,
is_list: <R as Extract>::IS_LIST,
arg: F::ARG_TYPE,
display_name: None,
description: name,
add_output: false,
func: ExtractLambda {
obj: func as *const _ as *const (),
func: F::extract,
},
}
}