From: Wolfgang Bumiller <w.bumiller@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [RFC backup 1/2] implement an api_string_type helper macro
Date: Tue, 4 May 2021 12:19:29 +0200 [thread overview]
Message-ID: <20210504101930.3590-1-w.bumiller@proxmox.com> (raw)
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
---
src/tools.rs | 3 +
src/tools/api_string_type.rs | 105 +++++++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+)
create mode 100644 src/tools/api_string_type.rs
diff --git a/src/tools.rs b/src/tools.rs
index c58569a6..98597c29 100644
--- a/src/tools.rs
+++ b/src/tools.rs
@@ -18,6 +18,9 @@ use percent_encoding::{utf8_percent_encode, AsciiSet};
pub use proxmox::tools::fd::Fd;
use proxmox::tools::fs::{create_path, CreateOptions};
+#[macro_use]
+pub mod api_string_type;
+
pub mod acl;
pub mod apt;
pub mod async_io;
diff --git a/src/tools/api_string_type.rs b/src/tools/api_string_type.rs
new file mode 100644
index 00000000..122fcbed
--- /dev/null
+++ b/src/tools/api_string_type.rs
@@ -0,0 +1,105 @@
+/// 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:
+///
+/// ```ignore
+/// api_string_type! {
+/// #[api(format: &PROXMOX_SAFE_ID_FORMAT)]
+/// /// ACME account name.
+/// #[derive(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`
+/// * `Debug` as a pass-through to `String`'s `Debug`
+/// * `Deref`
+/// * `DerefMut`
+/// * `AsRef<str>`
+/// * `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_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 $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::Debug for $name {
+ #[inline]
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ ::std::fmt::Debug::fmt(&self.0, f)
+ }
+ }
+
+ 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)
+ }
+ }
+ );
+}
--
2.20.1
next reply other threads:[~2021-05-04 10:19 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-05-04 10:19 Wolfgang Bumiller [this message]
2021-05-04 10:19 ` [pbs-devel] [RFC backup 2/2] use api_string_type macro Wolfgang Bumiller
2021-05-05 6:33 ` [pbs-devel] applied: " Dietmar Maurer
2021-05-04 11:17 ` [pbs-devel] [RFC backup 1/2] implement an api_string_type helper macro Dietmar Maurer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210504101930.3590-1-w.bumiller@proxmox.com \
--to=w.bumiller@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox