use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Clone, Default)]
pub struct Strings(pub Vec<String>);
impl Serialize for Strings {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if self.0.len() == 1 {
self.0[0].serialize(serializer)
} else {
self.0.serialize(serializer)
}
}
}
impl<'de> Deserialize<'de> for Strings {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum StringOrVec {
String(String),
Vec(Vec<String>),
}
match StringOrVec::deserialize(deserializer)? {
StringOrVec::String(s) => Ok(Strings(vec![s])),
StringOrVec::Vec(v) => Ok(Strings(v)),
}
}
}
impl Strings {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn first(&self) -> Option<&String> {
self.0.first()
}
pub fn iter(&self) -> impl Iterator<Item = &String> {
self.0.iter()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Flag {
False,
#[default]
Default,
True,
}
impl Flag {
pub fn with_default(self, default_value: bool) -> bool {
match self {
Flag::False => false,
Flag::Default => default_value,
Flag::True => true,
}
}
}
impl Serialize for Flag {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Flag::False => serializer.serialize_bool(false),
Flag::Default => serializer.serialize_none(),
Flag::True => serializer.serialize_bool(true),
}
}
}
impl<'de> Deserialize<'de> for Flag {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let opt: Option<bool> = Option::deserialize(deserializer)?;
Ok(match opt {
Some(true) => Flag::True,
Some(false) => Flag::False,
None => Flag::Default,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Priority {
#[default]
Default,
Disabled,
Value(i64),
}
impl Priority {
pub fn with_default(self, default_value: i64) -> Option<i64> {
match self {
Priority::Default => Some(default_value),
Priority::Disabled => None,
Priority::Value(v) => Some(v),
}
}
}
impl Serialize for Priority {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Priority::Default => serializer.serialize_none(),
Priority::Disabled => serializer.serialize_bool(false),
Priority::Value(v) => serializer.serialize_i64(*v),
}
}
}
impl<'de> Deserialize<'de> for Priority {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum PriorityValue {
Bool(bool),
Int(i64),
}
let opt: Option<PriorityValue> = Option::deserialize(deserializer)?;
Ok(match opt {
None => Priority::Default,
Some(PriorityValue::Bool(false)) => Priority::Disabled,
Some(PriorityValue::Bool(true)) => Priority::Value(1),
Some(PriorityValue::Int(v)) => {
if v <= 0 {
Priority::Disabled
} else {
Priority::Value(v)
}
}
})
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OptionalDuration(
#[serde(default, skip_serializing_if = "Option::is_none")] pub Option<String>,
);
impl OptionalDuration {
pub fn is_none(&self) -> bool {
self.0.is_none()
}
pub fn as_str(&self) -> Option<&str> {
self.0.as_deref()
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OptionalInteger(
#[serde(default, skip_serializing_if = "Option::is_none")] pub Option<i64>,
);
impl OptionalInteger {
pub fn is_none(&self) -> bool {
self.0.is_none()
}
pub fn value(&self) -> Option<i64> {
self.0
}
pub fn with_default(&self, default: i64) -> i64 {
self.0.unwrap_or(default)
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OptionalString(
#[serde(default, skip_serializing_if = "Option::is_none")] pub Option<String>,
);
impl OptionalString {
pub fn is_none(&self) -> bool {
self.0.is_none()
}
pub fn as_str(&self) -> Option<&str> {
self.0.as_deref()
}
pub fn with_default<'a>(&'a self, default: &'a str) -> &'a str {
self.0.as_deref().unwrap_or(default)
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OptionalBytes(
#[serde(default, skip_serializing_if = "Option::is_none")] pub Option<String>,
);
impl OptionalBytes {
pub fn is_none(&self) -> bool {
self.0.is_none()
}
pub fn as_str(&self) -> Option<&str> {
self.0.as_deref()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strings_single() {
let s: Strings = serde_json::from_str(r#""/ip4/0.0.0.0/tcp/4001""#).unwrap();
assert_eq!(s.0.len(), 1);
assert_eq!(s.0[0], "/ip4/0.0.0.0/tcp/4001");
}
#[test]
fn test_strings_array() {
let s: Strings =
serde_json::from_str(r#"["/ip4/0.0.0.0/tcp/4001", "/ip6/::/tcp/4001"]"#).unwrap();
assert_eq!(s.0.len(), 2);
}
#[test]
fn test_flag() {
let f: Flag = serde_json::from_str("true").unwrap();
assert_eq!(f, Flag::True);
let f: Flag = serde_json::from_str("false").unwrap();
assert_eq!(f, Flag::False);
let f: Flag = serde_json::from_str("null").unwrap();
assert_eq!(f, Flag::Default);
}
#[test]
fn test_priority() {
let p: Priority = serde_json::from_str("100").unwrap();
assert_eq!(p, Priority::Value(100));
let p: Priority = serde_json::from_str("false").unwrap();
assert_eq!(p, Priority::Disabled);
let p: Priority = serde_json::from_str("null").unwrap();
assert_eq!(p, Priority::Default);
}
}