* Re: [pbs-devel] [PATCH proxmox] add api_string_type macro
@ 2021-05-05 5:51 Dietmar Maurer
0 siblings, 0 replies; 2+ messages in thread
From: Dietmar Maurer @ 2021-05-05 5:51 UTC (permalink / raw)
To: Proxmox Backup Server development discussion, Wolfgang Bumiller
While building the package I get (doctest fails)
error[E0432]: unresolved import `proxmox::api::api`
--> src/api/api_type_macros.rs:6:5
|
4 | use proxmox::api::api;
| ^^^^^^^^^^^^^^^^^ no `api` in `api`
...
Some errors have detailed explanations: E0432, E0599.
For more information about an error, try `rustc --explain E0432`.
Couldn't compile the test.
failures:
src/api/api_type_macros.rs - api_string_type (line 5)
test result: FAILED. 60 passed; 1 failed; 7 ignored; 0 measured; 0 filtered out; finished in 9.29s
error: test failed, to rerun pass '--doc'
> On 05/04/2021 2:41 PM Wolfgang Bumiller <w.bumiller@proxmox.com> wrote:
>
>
> 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
>
>
>
> _______________________________________________
> pbs-devel mailing list
> pbs-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel
^ permalink raw reply [flat|nested] 2+ messages in thread
* [pbs-devel] [PATCH proxmox] add api_string_type macro
@ 2021-05-04 12:41 Wolfgang Bumiller
0 siblings, 0 replies; 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
end of thread, other threads:[~2021-05-05 5:51 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-05 5:51 [pbs-devel] [PATCH proxmox] add api_string_type macro Dietmar Maurer
-- strict thread matches above, loose matches on Subject: below --
2021-05-04 12:41 Wolfgang Bumiller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox