falco_plugin/plugin/
schema.rs1use schemars::{schema_for, JsonSchema};
2use serde::de::DeserializeOwned;
3use std::any::TypeId;
4use std::collections::BTreeMap;
5use std::ffi::{CStr, CString};
6use std::sync::Mutex;
7use thiserror::Error;
8
9#[derive(Error, Debug)]
10pub enum SchemaError {
11 #[error("JSON deserialization error: {0}")]
12 JsonError(#[from] serde_json::Error),
13}
14
15pub type SchemaResult<T> = Result<T, SchemaError>;
16
17pub enum ConfigSchemaType {
18 None,
19 Json(&'static CStr),
20}
21
22#[derive(Debug)]
27pub struct Json<T: JsonSchema + DeserializeOwned>(pub T);
28
29pub trait ConfigSchema: Sized {
30 fn get_schema() -> ConfigSchemaType;
31
32 fn from_str(s: &str) -> SchemaResult<Self>;
33}
34
35impl<T: JsonSchema + DeserializeOwned + 'static> ConfigSchema for Json<T> {
36 fn get_schema() -> ConfigSchemaType {
37 static CONFIG_SCHEMA: Mutex<BTreeMap<TypeId, CString>> = Mutex::new(BTreeMap::new());
38
39 let ty = TypeId::of::<Self>();
40 let mut schema_map = CONFIG_SCHEMA.lock().unwrap();
41 let ptr = unsafe {
48 CStr::from_ptr(
49 schema_map
50 .entry(ty)
51 .or_insert_with(|| {
52 let schema = schema_for!(T);
53 let schema = serde_json::to_string_pretty(&schema)
54 .expect("failed to serialize config schema");
55 CString::new(schema.into_bytes())
56 .expect("failed to add NUL to config schema")
57 })
58 .as_ptr(),
59 )
60 };
61
62 ConfigSchemaType::Json(ptr)
63 }
64
65 fn from_str(s: &str) -> SchemaResult<Self> {
66 let target: T = serde_json::from_str(s)?;
67 Ok(Json(target))
68 }
69}
70
71impl ConfigSchema for String {
72 fn get_schema() -> ConfigSchemaType {
73 ConfigSchemaType::None
74 }
75
76 fn from_str(s: &str) -> SchemaResult<Self> {
77 Ok(s.to_string())
78 }
79}
80
81impl ConfigSchema for () {
82 fn get_schema() -> ConfigSchemaType {
83 ConfigSchemaType::None
84 }
85
86 fn from_str(_: &str) -> SchemaResult<Self> {
87 Ok(())
88 }
89}