use std::convert::TryFrom;
use bytes::Bytes;
use crate::filters::Error;
#[derive(Clone, Debug, PartialEq, schemars::JsonSchema)]
pub enum ConfigType {
#[schemars(with = "serde_json::Value")]
Static(serde_json::Value),
#[schemars(skip)]
Dynamic(prost_types::Any),
}
impl ConfigType {
pub fn deserialize<TextConfiguration, BinaryConfiguration>(
self,
filter_name: &str,
) -> Result<(serde_json::Value, TextConfiguration), Error>
where
BinaryConfiguration: prost::Message + Default,
TextConfiguration:
serde::Serialize + for<'de> serde::Deserialize<'de> + TryFrom<BinaryConfiguration>,
Error: From<<BinaryConfiguration as TryInto<TextConfiguration>>::Error>,
{
match self {
ConfigType::Static(ref config) => serde_yaml::to_string(config)
.and_then(|raw_config| {
serde_yaml::from_str::<TextConfiguration>(raw_config.as_str())
})
.map_err(|err| {
Error::DeserializeFailed(format!(
"filter `{filter_name}`: failed to YAML deserialize config: {err}",
))
})
.and_then(|config| {
Self::get_json_config(filter_name, &config)
.map(|config_json| (config_json, config))
}),
ConfigType::Dynamic(config) => prost::Message::decode(Bytes::from(config.value))
.map_err(|err| {
Error::DeserializeFailed(format!(
"filter `{filter_name}`: config decode error: {err}",
))
})
.and_then(|config| TextConfiguration::try_from(config).map_err(From::from))
.and_then(|config| {
Self::get_json_config(filter_name, &config)
.map(|config_json| (config_json, config))
}),
}
}
fn get_json_config<T>(filter_name: &str, config: &T) -> Result<serde_json::Value, Error>
where
T: serde::Serialize + for<'de> serde::Deserialize<'de>,
{
serde_json::to_value(config).map_err(|err| {
Error::DeserializeFailed(format!(
"filter `{filter_name}`: failed to serialize config to json: {err}",
))
})
}
}
impl<'de> serde::Deserialize<'de> for ConfigType {
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
serde_json::Value::deserialize(de).map(ConfigType::Static)
}
}
impl serde::Serialize for ConfigType {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
Self::Static(value) => value.serialize(ser),
Self::Dynamic(_) => Err(serde::ser::Error::custom(
"Protobuf configs can't be serialized.",
)),
}
}
}
impl From<serde_json::Value> for ConfigType {
fn from(value: serde_json::Value) -> Self {
Self::Static(value)
}
}
#[cfg(test)]
mod tests {
use super::ConfigType;
use serde::{Deserialize, Serialize};
#[test]
fn get_json_config() {
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
struct TestConfig {
name: String,
value: usize,
}
let expected_config = TestConfig {
name: "bebop".into(),
value: 98,
};
let config_json = ConfigType::get_json_config("my-filter", &expected_config).unwrap();
assert_eq!(
serde_json::json!({
"name": "bebop",
"value": 98,
}),
config_json
)
}
}