From b255739ee730d3b7293501c5224e62930c01608f Mon Sep 17 00:00:00 2001 From: Armin Sander Date: Tue, 19 Apr 2022 08:33:45 +0200 Subject: [PATCH] Implement FromStr and Display based on Serialize and Deserialize for all configuration enum types --- src/rest/config/devices.rs | 12 ++++++++++++ src/rest/config/folders.rs | 11 +++++++++++ src/rest/config/gui.rs | 8 ++++++-- src/rest/config/ldap.rs | 3 +++ src/rest/config/options.rs | 9 +++++++++ src/utils.rs | 22 +++++++++++++++++++++- 6 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/rest/config/devices.rs b/src/rest/config/devices.rs index 81d40bb..12db2e6 100644 --- a/src/rest/config/devices.rs +++ b/src/rest/config/devices.rs @@ -1,4 +1,5 @@ use super::{FolderId, Kibibytes, KibibytesPerSecond, PortNumber}; +use crate::utils::impl_from_str_and_display; use ipnet::IpNet; use serde::{Deserialize, Serialize}; use url::Url; @@ -96,6 +97,8 @@ pub enum Compression { Never, } +impl_from_str_and_display!(Compression); + impl Default for Compression { fn default() -> Self { Self::Metadata @@ -110,6 +113,8 @@ pub enum Address { Static(Url), } +impl_from_str_and_display!(Address); + mod strings { use crate::utils::named_unit_variant; named_unit_variant!(dynamic); @@ -189,4 +194,11 @@ mod tests { "untrusted": false, "remoteGUIPort": 0 }"#; + + #[test] + fn address_from_str_to_display() { + let addr_str = "tcp://host:22000"; + let addr: Address = addr_str.parse().unwrap(); + assert_eq!(addr.to_string(), addr_str); + } } diff --git a/src/rest/config/folders.rs b/src/rest/config/folders.rs index 4bf723c..67fd6f1 100644 --- a/src/rest/config/folders.rs +++ b/src/rest/config/folders.rs @@ -1,4 +1,5 @@ use super::{Count, FolderId, Kibibytes, MinDiskFree, Seconds}; +use crate::utils::impl_from_str_and_display; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -172,6 +173,8 @@ pub enum FilesystemType { Fake, } +impl_from_str_and_display!(FilesystemType); + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] #[serde(rename_all(serialize = "lowercase", deserialize = "lowercase"))] pub enum Type { @@ -192,6 +195,8 @@ pub enum Type { ReceiveEncrypted, } +impl_from_str_and_display!(Type); + #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] #[serde(rename_all(serialize = "camelCase", deserialize = "camelCase"))] pub struct Device { @@ -236,6 +241,8 @@ pub enum PullOrder { NewestFirst, } +impl_from_str_and_display!(PullOrder); + impl Default for PullOrder { fn default() -> Self { Self::Random @@ -258,6 +265,8 @@ pub enum BlockPullOrder { InOrder, } +impl_from_str_and_display!(BlockPullOrder); + impl Default for BlockPullOrder { fn default() -> Self { Self::Standard @@ -275,6 +284,8 @@ pub enum CopyRangeMethod { All, } +impl_from_str_and_display!(CopyRangeMethod); + #[cfg(test)] mod tests { use super::*; diff --git a/src/rest/config/gui.rs b/src/rest/config/gui.rs index 5c0e230..c56ca50 100644 --- a/src/rest/config/gui.rs +++ b/src/rest/config/gui.rs @@ -1,3 +1,5 @@ +use super::PortNumber; +use crate::utils::impl_from_str_and_display; use serde::{Deserialize, Serialize}; use std::{ fmt::{Display, Write}, @@ -7,8 +9,6 @@ use std::{ str::FromStr, }; -use super::PortNumber; - /// The GUI configuration. /// #[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] @@ -69,6 +69,8 @@ pub enum Address { Path(PathBuf), } +impl_from_str_and_display!(Address); + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] pub struct WildcardPort(PortNumber); @@ -138,6 +140,8 @@ pub enum AuthMode { Ldap, } +impl_from_str_and_display!(AuthMode); + #[cfg(test)] mod tests { use super::*; diff --git a/src/rest/config/ldap.rs b/src/rest/config/ldap.rs index 6eeb6dc..4643015 100644 --- a/src/rest/config/ldap.rs +++ b/src/rest/config/ldap.rs @@ -1,3 +1,4 @@ +use crate::utils::impl_from_str_and_display; use serde::{Deserialize, Serialize}; /// LDAP configuration options. The mechanism is described in detail under LDAP Authentication. @@ -39,3 +40,5 @@ pub enum Transport { /// StartTLS connection mode. StartTls, } + +impl_from_str_and_display!(Transport); diff --git a/src/rest/config/options.rs b/src/rest/config/options.rs index 064c5ee..99704e8 100644 --- a/src/rest/config/options.rs +++ b/src/rest/config/options.rs @@ -1,6 +1,7 @@ use super::{ Count, Hours, Kibibytes, KibibytesPerSecond, MinDiskFree, Minutes, PortNumber, Seconds, }; +use crate::utils::impl_from_str_and_display; use ipnet::IpNet; use serde::{Deserialize, Serialize}; use url::Url; @@ -194,6 +195,8 @@ pub enum ListenAddress { Address(Url), } +impl_from_str_and_display!(ListenAddress); + /// A URI to a global announce (discovery) server, or the word default to include the default /// servers. The syntax for non-default entries is that of an HTTP or HTTPS URL. A number of options /// may be added as query options to the URL: `insecure` to prevent certificate validation (required @@ -207,6 +210,8 @@ pub enum AnnounceServer { Address(Url), } +impl_from_str_and_display!(AnnounceServer); + #[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] #[serde(untagged)] pub enum StunServer { @@ -216,6 +221,8 @@ pub enum StunServer { Address(String), } +impl_from_str_and_display!(StunServer); + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] #[serde(rename_all(serialize = "lowercase", deserialize = "lowercase"))] pub enum DatabaseTuning { @@ -224,6 +231,8 @@ pub enum DatabaseTuning { Auto, } +impl_from_str_and_display!(DatabaseTuning); + mod strings { use crate::utils::named_unit_variant; named_unit_variant!(default); diff --git a/src/utils.rs b/src/utils.rs index f34669a..1f0f112 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -63,5 +63,25 @@ macro_rules! named_unit_variant { } }; } - pub(crate) use named_unit_variant; + +/// Implements `FromStr` and `Display` in terms of `Serialize` and `Deserialize` implementations. +macro_rules! impl_from_str_and_display { + ($ty:ty) => { + impl std::str::FromStr for $ty { + type Err = serde_json::Error; + fn from_str(s: &str) -> Result { + serde_json::from_value(serde_json::Value::String(s.into())) + } + } + + impl std::fmt::Display for $ty { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let v = serde_json::to_value(&self).map_err(|_| std::fmt::Error)?; + v.as_str().ok_or(std::fmt::Error)?.fmt(f) + } + } + }; +} + +pub(crate) use impl_from_str_and_display;