all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [pbs-devel] [PATCH proxmox] add api_string_type macro
@ 2021-05-04 12:41 Wolfgang Bumiller
  2021-05-05  5:48 ` [pbs-devel] applied: " Dietmar Maurer
  0 siblings, 1 reply; 2+ messages in thread
From: Wolfgang Bumiller @ 2021-05-04 12:41 UTC (permalink / raw)
  To: pbs-devel

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
---
Difference to the original RFC for the proxmox-backup crate:
* dropped `Debug` implementation
* added `TryFrom<String>` implementation

 proxmox/src/api/api_type_macros.rs | 113 +++++++++++++++++++++++++++++
 proxmox/src/api/mod.rs             |   3 +
 2 files changed, 116 insertions(+)
 create mode 100644 proxmox/src/api/api_type_macros.rs

diff --git a/proxmox/src/api/api_type_macros.rs b/proxmox/src/api/api_type_macros.rs
new file mode 100644
index 0000000..542520d
--- /dev/null
+++ b/proxmox/src/api/api_type_macros.rs
@@ -0,0 +1,113 @@
+/// Helper macro to generate a simple string type wrapper.
+///
+/// This is meant to be used with an API-type tuple struct containing a single `String` like this:
+///
+/// ```
+/// # use proxmox::api::api;
+/// # use proxmox::api::schema::ApiStringFormat;
+/// # const PROXMOX_SAFE_ID_FORMAT: ApiStringFormat = ApiStringFormat::Enum(&[]);
+/// use proxmox::api_string_type;
+/// use serde::{Deserialize, Serialize};
+///
+/// api_string_type! {
+///     #[api(format: &PROXMOX_SAFE_ID_FORMAT)]
+///     /// ACME account name.
+///     #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
+///     #[serde(transparent)]
+///     pub struct AccountName(String);
+/// }
+/// ```
+///
+/// This will automatically implements:
+/// * `Display` as a pass-through to `String`'s `Display`
+/// * `Deref`
+/// * `DerefMut`
+/// * `AsRef<str>`
+/// * `TryFrom<String>`
+/// * `fn into_string(self) -> String`
+/// * `fn as_str(&self) -> &str`
+/// * `fn from_string(inner: String) -> Result<Self, anyhow::Error>` using
+///   `StringSchema::check_constraints`.
+/// * `unsafe fn from_string_unchecked(inner: String) -> Self`
+#[macro_export]
+macro_rules! api_string_type {
+    (
+        $(#[$doc:meta])*
+        $vis:vis struct $name:ident(String);
+    ) => (
+        $(#[$doc])*
+        $vis struct $name(String);
+
+        impl ::std::ops::Deref for $name {
+            type Target = str;
+
+            #[inline]
+            fn deref(&self) -> &str {
+                &self.0
+            }
+        }
+
+        impl ::std::ops::DerefMut for $name {
+            #[inline]
+            fn deref_mut(&mut self) -> &mut str {
+                &mut self.0
+            }
+        }
+
+        impl AsRef<str> for $name {
+            #[inline]
+            fn as_ref(&self) -> &str {
+                self.0.as_ref()
+            }
+        }
+
+        impl ::std::convert::TryFrom<String> for $name {
+            type Error = ::anyhow::Error;
+
+            fn try_from(inner: String) -> Result<Self, ::anyhow::Error> {
+                Self::from_string(inner)
+            }
+        }
+
+        impl $name {
+            /// Get the contained string.
+            pub fn into_string(self) -> String {
+                self.0
+            }
+
+            /// Get the string as slice.
+            pub fn as_str(&self) -> &str {
+                self.0.as_str()
+            }
+
+            /// Create an instance directly from a `String`.
+            ///
+            /// # Safety
+            ///
+            /// It is the caller's job to have validated the contents.
+            /// While there are no memory safety issues, a wrong string can cause API calls to
+            /// fail parameter validation.
+            pub unsafe fn from_string_unchecked(name: String) -> Self {
+                Self(name)
+            }
+
+            /// Create an instance directly from a `String`, validating it using the API schema's
+            /// [`check_constraints`](::proxmox::api::schema::StringSchema::check_constraints())
+            /// method.
+            pub fn from_string(inner: String) -> Result<Self, ::anyhow::Error> {
+                match &Self::API_SCHEMA {
+                    ::proxmox::api::schema::Schema::String(s) => s.check_constraints(&inner)?,
+                    _ => unreachable!(),
+                }
+                Ok(Self(inner))
+            }
+        }
+
+        impl ::std::fmt::Display for $name {
+            #[inline]
+            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+                ::std::fmt::Display::fmt(&self.0, f)
+            }
+        }
+    );
+}
diff --git a/proxmox/src/api/mod.rs b/proxmox/src/api/mod.rs
index 8c6f597..aaec7df 100644
--- a/proxmox/src/api/mod.rs
+++ b/proxmox/src/api/mod.rs
@@ -9,6 +9,9 @@
 #[cfg(feature = "api-macro")]
 pub use proxmox_api_macro::{api, router};
 
+#[macro_use]
+mod api_type_macros;
+
 #[doc(hidden)]
 pub mod const_regex;
 #[doc(hidden)]
-- 
2.20.1





^ permalink raw reply	[flat|nested] 2+ messages in thread

* [pbs-devel] applied:  [PATCH proxmox] add api_string_type macro
  2021-05-04 12:41 [pbs-devel] [PATCH proxmox] add api_string_type macro Wolfgang Bumiller
@ 2021-05-05  5:48 ` Dietmar Maurer
  0 siblings, 0 replies; 2+ messages in thread
From: Dietmar Maurer @ 2021-05-05  5:48 UTC (permalink / raw)
  To: Proxmox Backup Server development discussion, Wolfgang Bumiller

applied




^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-05-05  5:48 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-04 12:41 [pbs-devel] [PATCH proxmox] add api_string_type macro Wolfgang Bumiller
2021-05-05  5:48 ` [pbs-devel] applied: " Dietmar Maurer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal