[pbs-devel] [RFC backup 1/2] implement an api_string_type helper macro
Dietmar Maurer
dietmar at proxmox.com
Tue May 4 13:17:56 CEST 2021
two suggestions:
1.) Move the code to the proxmox crate
2.) Do not implement Debug (can be derived)
On 5/4/21 12:19 PM, Wolfgang Bumiller wrote:
> Signed-off-by: Wolfgang Bumiller <w.bumiller at 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)
> + }
> + }
> + );
> +}
More information about the pbs-devel
mailing list