use core::fmt;
use serde::{ser, Serialize};
use serde_json::{Map, Value};
use crate::types::NamespaceFormat;
pub const KEY_CONTENT: &str = "content";
#[derive(Debug, Clone)]
pub enum Configurations {
Properties(Map<String, Value>),
Json(Value),
Txt(Box<str>),
Other(Box<str>),
}
impl Configurations {
pub fn from_map(
map: &Map<String, Value>,
namespace_format: NamespaceFormat,
) -> Result<Self, ConfigurationsFromMapError> {
match namespace_format {
NamespaceFormat::Properties => Ok(Self::Properties(map.to_owned())),
NamespaceFormat::Xml
| NamespaceFormat::Json
| NamespaceFormat::Yml
| NamespaceFormat::Yaml
| NamespaceFormat::Txt => {
let content = map
.get(KEY_CONTENT)
.ok_or(ConfigurationsFromMapError::ContentMissing)?;
match namespace_format {
NamespaceFormat::Properties => unreachable!(),
NamespaceFormat::Xml => {
let content = content
.as_str()
.ok_or(ConfigurationsFromMapError::ContentTypeMismatch("String"))?;
Ok(Self::Other(content.into()))
}
NamespaceFormat::Json => {
let content = content
.as_str()
.ok_or(ConfigurationsFromMapError::ContentTypeMismatch("String"))?;
let value = serde_json::from_str(content)
.map_err(ConfigurationsFromMapError::JsonError)?;
Ok(Self::Json(value))
}
NamespaceFormat::Yml => {
let content = content
.as_str()
.ok_or(ConfigurationsFromMapError::ContentTypeMismatch("String"))?;
Ok(Self::Other(content.into()))
}
NamespaceFormat::Yaml => {
let content = content
.as_str()
.ok_or(ConfigurationsFromMapError::ContentTypeMismatch("String"))?;
Ok(Self::Other(content.into()))
}
NamespaceFormat::Txt => {
let content = content
.as_str()
.ok_or(ConfigurationsFromMapError::ContentTypeMismatch("String"))?;
Ok(Self::Txt(content.into()))
}
}
}
}
}
pub fn to_map(&self) -> Result<Map<String, Value>, ConfigurationsToMapError> {
match self {
Configurations::Properties(map) => Ok(map.to_owned()),
Configurations::Json(value) => {
let s = serde_json::to_string(value)
.map_err(ser::Error::custom)
.map_err(ConfigurationsToMapError::JsonError)?;
let mut map = Map::new();
map.insert(KEY_CONTENT.to_string(), Value::String(s));
Ok(map.to_owned())
}
Configurations::Txt(s) | Configurations::Other(s) => {
let mut map = Map::new();
map.insert(KEY_CONTENT.to_string(), Value::String(s.to_string()));
Ok(map.to_owned())
}
}
}
}
#[derive(Debug)]
pub enum ConfigurationsFromMapError {
ContentMissing,
ContentTypeMismatch(&'static str),
JsonError(serde_json::Error),
}
impl fmt::Display for ConfigurationsFromMapError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::error::Error for ConfigurationsFromMapError {}
#[derive(Debug)]
pub enum ConfigurationsToMapError {
JsonError(serde_json::Error),
}
impl fmt::Display for ConfigurationsToMapError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::error::Error for ConfigurationsToMapError {}
impl Serialize for Configurations {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let map = self.to_map().map_err(ser::Error::custom)?;
map.serialize(serializer)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Serialize)]
struct Foo {
configurations: Configurations,
}
#[test]
fn test_ser() {
let mut map = Map::new();
map.insert("content".to_string(), Value::String("content".into()));
assert_eq!(
serde_json::to_string(&Foo {
configurations: Configurations::Properties(map)
})
.unwrap(),
r#"{"configurations":{"content":"content"}}"#
);
let mut map = Map::new();
map.insert("k".to_string(), Value::String("v".into()));
assert_eq!(
serde_json::to_string(&Foo {
configurations: Configurations::Json(Value::Object(map))
})
.unwrap(),
r#"{"configurations":{"content":"{\"k\":\"v\"}"}}"#
);
assert_eq!(
serde_json::to_string(&Foo {
configurations: Configurations::Txt("test".into())
})
.unwrap(),
r#"{"configurations":{"content":"test"}}"#
);
assert_eq!(
serde_json::to_string(&Foo {
configurations: Configurations::Other("xxx".into())
})
.unwrap(),
r#"{"configurations":{"content":"xxx"}}"#
);
}
}