public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pbs-devel] [PATCH proxmox{, -api-types, -ve-rs} 0/6] Move perl deserializers from proxmox-login to proxmox-serde
@ 2025-05-13 10:14 Stefan Hanreich
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox 1/3] serde: add parsing helpers for perl Stefan Hanreich
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Stefan Hanreich @ 2025-05-13 10:14 UTC (permalink / raw)
  To: pbs-devel

There are other places where we need to deal with data coming from Perl as well,
so move those helpers to a more appropriate place, where they can be re-used
across multiple crates, without having to add a dependency to proxmox-login.

proxmox-serde needs a bump, all other crates from this series depend on the
changes there.

proxmox:

Stefan Hanreich (3):
  serde: add parsing helpers for perl
  login: move parse module to proxmox-serde
  client: move to proxmox_serde perl helpers

 proxmox-client/Cargo.toml                               | 2 ++
 proxmox-client/src/lib.rs                               | 4 ++--
 proxmox-login/Cargo.toml                                | 1 +
 proxmox-login/src/api.rs                                | 2 +-
 proxmox-login/src/lib.rs                                | 2 --
 proxmox-serde/Cargo.toml                                | 3 +++
 proxmox-serde/src/lib.rs                                | 3 +++
 proxmox-login/src/parse.rs => proxmox-serde/src/perl.rs | 0
 8 files changed, 12 insertions(+), 5 deletions(-)
 rename proxmox-login/src/parse.rs => proxmox-serde/src/perl.rs (100%)


proxmox-api-types:

Stefan Hanreich (2):
  generator: use proxmox_serde for perl helpers
  regenerate

 Cargo.toml                                 |   2 +-
 pve-api-types/Cargo.toml                   |   2 +-
 pve-api-types/generator-lib/Schema2Rust.pm |  26 +-
 pve-api-types/src/generated/types.rs       | 798 ++++++++++-----------
 4 files changed, 414 insertions(+), 414 deletions(-)


proxmox-ve-rs:

Stefan Hanreich (1):
  config: use proxmox_serde perl helpers

 proxmox-ve-config/Cargo.toml              |  1 +
 proxmox-ve-config/src/firewall/bridge.rs  |  3 +-
 proxmox-ve-config/src/firewall/cluster.rs |  6 +-
 proxmox-ve-config/src/firewall/guest.rs   | 14 ++--
 proxmox-ve-config/src/firewall/host.rs    | 26 ++++----
 proxmox-ve-config/src/firewall/parse.rs   | 80 -----------------------
 6 files changed, 24 insertions(+), 106 deletions(-)


Summary over all repositories:
  18 files changed, 450 insertions(+), 525 deletions(-)

-- 
Generated by git-murpp 0.8.0

_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel


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

* [pbs-devel] [PATCH proxmox 1/3] serde: add parsing helpers for perl
  2025-05-13 10:14 [pbs-devel] [PATCH proxmox{, -api-types, -ve-rs} 0/6] Move perl deserializers from proxmox-login to proxmox-serde Stefan Hanreich
@ 2025-05-13 10:14 ` Stefan Hanreich
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox 2/3] login: move parse module to proxmox-serde Stefan Hanreich
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Stefan Hanreich @ 2025-05-13 10:14 UTC (permalink / raw)
  To: pbs-devel

Those have been moved from the proxmox-login crate. This crate seems
like a more natural place for hosting helpers to parse data coming
from perl via serde.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
 proxmox-serde/Cargo.toml  |   3 +
 proxmox-serde/src/lib.rs  |   3 +
 proxmox-serde/src/perl.rs | 373 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 379 insertions(+)
 create mode 100644 proxmox-serde/src/perl.rs

diff --git a/proxmox-serde/Cargo.toml b/proxmox-serde/Cargo.toml
index aa77099a..b1edb60d 100644
--- a/proxmox-serde/Cargo.toml
+++ b/proxmox-serde/Cargo.toml
@@ -20,3 +20,6 @@ proxmox-time.workspace = true
 
 [dev-dependencies]
 serde_json.workspace = true
+
+[features]
+perl = []
diff --git a/proxmox-serde/src/lib.rs b/proxmox-serde/src/lib.rs
index c1628349..8a3d8794 100644
--- a/proxmox-serde/src/lib.rs
+++ b/proxmox-serde/src/lib.rs
@@ -8,6 +8,9 @@ pub mod serde_macros;
 #[cfg(feature = "serde_json")]
 pub mod json;
 
+#[cfg(feature = "perl")]
+pub mod perl;
+
 /// Serialize Unix epoch (i64) as RFC3339.
 ///
 /// Usage example:
diff --git a/proxmox-serde/src/perl.rs b/proxmox-serde/src/perl.rs
new file mode 100644
index 00000000..8efa86c9
--- /dev/null
+++ b/proxmox-serde/src/perl.rs
@@ -0,0 +1,373 @@
+//! Some parsing helpers for the PVE API, mainly to deal with perl's untypedness.
+
+use std::fmt;
+
+use serde::de::Unexpected;
+
+// Boolean:
+
+pub trait FromBool: Sized + Default {
+    fn from_bool(value: bool) -> Self;
+}
+
+impl FromBool for bool {
+    fn from_bool(value: bool) -> Self {
+        value
+    }
+}
+
+impl FromBool for Option<bool> {
+    fn from_bool(value: bool) -> Self {
+        Some(value)
+    }
+}
+
+pub fn deserialize_bool<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+where
+    D: serde::Deserializer<'de>,
+    T: FromBool,
+{
+    deserializer.deserialize_any(BoolVisitor::<T>::new())
+}
+
+struct BoolVisitor<T>(std::marker::PhantomData<T>);
+
+impl<T> BoolVisitor<T> {
+    fn new() -> Self {
+        Self(std::marker::PhantomData)
+    }
+}
+
+impl<'de, T: FromBool> serde::de::DeserializeSeed<'de> for BoolVisitor<T> {
+    type Value = T;
+
+    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        deserialize_bool(deserializer)
+    }
+}
+
+impl<'de, T> serde::de::Visitor<'de> for BoolVisitor<T>
+where
+    T: FromBool,
+{
+    type Value = T;
+
+    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str("a boolean-ish...")
+    }
+
+    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        deserializer.deserialize_any(self)
+    }
+
+    fn visit_none<E>(self) -> Result<Self::Value, E> {
+        Ok(Default::default())
+    }
+
+    fn visit_bool<E: serde::de::Error>(self, value: bool) -> Result<Self::Value, E> {
+        Ok(Self::Value::from_bool(value))
+    }
+
+    fn visit_i128<E: serde::de::Error>(self, value: i128) -> Result<Self::Value, E> {
+        Ok(Self::Value::from_bool(value != 0))
+    }
+
+    fn visit_i64<E: serde::de::Error>(self, value: i64) -> Result<Self::Value, E> {
+        Ok(Self::Value::from_bool(value != 0))
+    }
+
+    fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Self::Value, E> {
+        Ok(Self::Value::from_bool(value != 0))
+    }
+
+    fn visit_u128<E: serde::de::Error>(self, value: u128) -> Result<Self::Value, E> {
+        Ok(Self::Value::from_bool(value != 0))
+    }
+
+    fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
+        let value = if value.eq_ignore_ascii_case("true")
+            || value.eq_ignore_ascii_case("yes")
+            || value.eq_ignore_ascii_case("on")
+            || value == "1"
+        {
+            true
+        } else if value.eq_ignore_ascii_case("false")
+            || value.eq_ignore_ascii_case("no")
+            || value.eq_ignore_ascii_case("off")
+            || value == "0"
+        {
+            false
+        } else {
+            return Err(E::invalid_value(
+                serde::de::Unexpected::Str(value),
+                &"a boolean-like value",
+            ));
+        };
+        Ok(Self::Value::from_bool(value))
+    }
+}
+
+// integer helpers:
+
+macro_rules! integer_helper {
+    ($ty:ident, $deserialize_name:ident, $trait: ident, $from_name:ident, $visitor:ident) => {
+        #[doc(hidden)]
+        pub trait $trait: Sized + Default {
+            fn $from_name(value: $ty) -> Self;
+        }
+
+        impl $trait for $ty {
+            fn $from_name(value: $ty) -> Self {
+                value
+            }
+        }
+
+        impl $trait for Option<$ty> {
+            fn $from_name(value: $ty) -> Self {
+                Some(value)
+            }
+        }
+
+        pub fn $deserialize_name<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+        where
+            D: serde::Deserializer<'de>,
+            T: $trait,
+        {
+            deserializer.deserialize_any($visitor::<T>::new())
+        }
+
+        struct $visitor<T>(std::marker::PhantomData<T>);
+
+        impl<T> $visitor<T> {
+            fn new() -> Self {
+                Self(std::marker::PhantomData)
+            }
+        }
+
+        impl<'de, T: $trait> serde::de::DeserializeSeed<'de> for $visitor<T> {
+            type Value = T;
+
+            fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+            where
+                D: serde::Deserializer<'de>,
+            {
+                $deserialize_name(deserializer)
+            }
+        }
+
+        impl<'de, T> serde::de::Visitor<'de> for $visitor<T>
+        where
+            T: $trait,
+        {
+            type Value = T;
+
+            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                f.write_str(concat!("a ", stringify!($ty), "-ish..."))
+            }
+
+            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+            where
+                D: serde::Deserializer<'de>,
+            {
+                deserializer.deserialize_any(self)
+            }
+
+            fn visit_none<E>(self) -> Result<Self::Value, E> {
+                Ok(Default::default())
+            }
+
+            fn visit_i128<E: serde::de::Error>(self, value: i128) -> Result<Self::Value, E> {
+                $ty::try_from(value)
+                    .map_err(|_| E::invalid_value(Unexpected::Other("i128"), &self))
+                    .map(Self::Value::$from_name)
+            }
+
+            fn visit_i64<E: serde::de::Error>(self, value: i64) -> Result<Self::Value, E> {
+                $ty::try_from(value)
+                    .map_err(|_| E::invalid_value(Unexpected::Signed(value), &self))
+                    .map(Self::Value::$from_name)
+            }
+
+            fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Self::Value, E> {
+                $ty::try_from(value)
+                    .map_err(|_| E::invalid_value(Unexpected::Unsigned(value), &self))
+                    .map(Self::Value::$from_name)
+            }
+
+            fn visit_u128<E: serde::de::Error>(self, value: u128) -> Result<Self::Value, E> {
+                $ty::try_from(value)
+                    .map_err(|_| E::invalid_value(Unexpected::Other("u128"), &self))
+                    .map(Self::Value::$from_name)
+            }
+
+            fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
+                let value = value
+                    .parse()
+                    .map_err(|_| E::invalid_value(Unexpected::Str(value), &self))?;
+                self.visit_i64(value)
+            }
+        }
+    };
+}
+
+integer_helper!(
+    isize,
+    deserialize_isize,
+    FromIsize,
+    from_isize,
+    IsizeVisitor
+);
+
+integer_helper!(
+    usize,
+    deserialize_usize,
+    FromUsize,
+    from_usize,
+    UsizeVisitor
+);
+
+integer_helper!(u8, deserialize_u8, FromU8, from_u8, U8Visitor);
+integer_helper!(u16, deserialize_u16, FromU16, from_u16, U16Visitor);
+integer_helper!(u32, deserialize_u32, FromU32, from_u32, U32Visitor);
+integer_helper!(u64, deserialize_u64, FromU64, from_u64, U64Visitor);
+integer_helper!(i8, deserialize_i8, FromI8, from_i8, I8Visitor);
+integer_helper!(i16, deserialize_i16, FromI16, from_i16, I16Visitor);
+integer_helper!(i32, deserialize_i32, FromI32, from_i32, I32Visitor);
+integer_helper!(i64, deserialize_i64, FromI64, from_i64, I64Visitor);
+
+// float helpers:
+
+macro_rules! float_helper {
+    ($ty:ident, $deserialize_name:ident, $visitor:ident) => {
+        pub fn $deserialize_name<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+        where
+            D: serde::Deserializer<'de>,
+            T: FromF64,
+        {
+            deserializer.deserialize_any($visitor::<T>::new())
+        }
+
+        struct $visitor<T>(std::marker::PhantomData<T>);
+
+        impl<T> $visitor<T> {
+            fn new() -> Self {
+                Self(std::marker::PhantomData)
+            }
+        }
+
+        impl<'de, T: FromF64> serde::de::DeserializeSeed<'de> for $visitor<T> {
+            type Value = T;
+
+            fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+            where
+                D: serde::Deserializer<'de>,
+            {
+                $deserialize_name(deserializer)
+            }
+        }
+
+        impl<'de, T> serde::de::Visitor<'de> for $visitor<T>
+        where
+            T: FromF64,
+        {
+            type Value = T;
+
+            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                f.write_str(concat!("a ", stringify!($ty), "-ish..."))
+            }
+
+            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+            where
+                D: serde::Deserializer<'de>,
+            {
+                deserializer.deserialize_any(self)
+            }
+
+            fn visit_none<E>(self) -> Result<Self::Value, E> {
+                Ok(Default::default())
+            }
+
+            fn visit_f64<E: serde::de::Error>(self, value: f64) -> Result<Self::Value, E> {
+                Ok(T::from_f64(value))
+            }
+
+            fn visit_i128<E: serde::de::Error>(self, value: i128) -> Result<Self::Value, E> {
+                let conv = value as f64;
+                if conv as i128 == value {
+                    Ok(T::from_f64(conv))
+                } else {
+                    Err(E::invalid_value(Unexpected::Other("i128"), &self))
+                }
+            }
+
+            fn visit_i64<E: serde::de::Error>(self, value: i64) -> Result<Self::Value, E> {
+                let conv = value as f64;
+                if conv as i64 == value {
+                    Ok(T::from_f64(conv))
+                } else {
+                    Err(E::invalid_value(Unexpected::Signed(value), &self))
+                }
+            }
+
+            fn visit_u128<E: serde::de::Error>(self, value: u128) -> Result<Self::Value, E> {
+                let conv = value as f64;
+                if conv as u128 == value {
+                    Ok(T::from_f64(conv))
+                } else {
+                    Err(E::invalid_value(Unexpected::Other("u128"), &self))
+                }
+            }
+
+            fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Self::Value, E> {
+                let conv = value as f64;
+                if conv as u64 == value {
+                    Ok(T::from_f64(conv))
+                } else {
+                    Err(E::invalid_value(Unexpected::Unsigned(value), &self))
+                }
+            }
+
+            fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
+                let value = value
+                    .parse()
+                    .map_err(|_| E::invalid_value(Unexpected::Str(value), &self))?;
+                self.visit_f64(value)
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+pub trait FromF64: Sized + Default {
+    fn from_f64(value: f64) -> Self;
+}
+
+impl FromF64 for f32 {
+    #[inline(always)]
+    fn from_f64(f: f64) -> f32 {
+        f as f32
+    }
+}
+
+impl FromF64 for f64 {
+    #[inline(always)]
+    fn from_f64(f: f64) -> f64 {
+        f
+    }
+}
+
+impl<T: FromF64> FromF64 for Option<T> {
+    #[inline(always)]
+    fn from_f64(f: f64) -> Option<T> {
+        Some(T::from_f64(f))
+    }
+}
+
+float_helper!(f32, deserialize_f32, F32Visitor);
+float_helper!(f64, deserialize_f64, F64Visitor);
-- 
2.39.5


_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel


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

* [pbs-devel] [PATCH proxmox 2/3] login: move parse module to proxmox-serde
  2025-05-13 10:14 [pbs-devel] [PATCH proxmox{, -api-types, -ve-rs} 0/6] Move perl deserializers from proxmox-login to proxmox-serde Stefan Hanreich
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox 1/3] serde: add parsing helpers for perl Stefan Hanreich
@ 2025-05-13 10:14 ` Stefan Hanreich
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox 3/3] client: move to proxmox_serde perl helpers Stefan Hanreich
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Stefan Hanreich @ 2025-05-13 10:14 UTC (permalink / raw)
  To: pbs-devel

Remove the parse module, that has been moved to proxmox-serde. Fix all
usages of the parse module in the process and add the new dependency.
No functional changes intended.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
 proxmox-login/Cargo.toml   |   1 +
 proxmox-login/src/api.rs   |   2 +-
 proxmox-login/src/lib.rs   |   2 -
 proxmox-login/src/parse.rs | 373 -------------------------------------
 4 files changed, 2 insertions(+), 376 deletions(-)
 delete mode 100644 proxmox-login/src/parse.rs

diff --git a/proxmox-login/Cargo.toml b/proxmox-login/Cargo.toml
index 50dfe2c8..2dc28d52 100644
--- a/proxmox-login/Cargo.toml
+++ b/proxmox-login/Cargo.toml
@@ -16,6 +16,7 @@ base64.workspace = true
 percent-encoding.workspace = true
 serde = { workspace = true, features = [ "derive" ] }
 serde_json.workspace = true
+proxmox-serde = { workspace = true, features = [ "perl" ] }
 
 # For webauthn types
 webauthn-rs = { workspace = true, optional = true }
diff --git a/proxmox-login/src/api.rs b/proxmox-login/src/api.rs
index b7107312..6023485c 100644
--- a/proxmox-login/src/api.rs
+++ b/proxmox-login/src/api.rs
@@ -11,7 +11,7 @@ pub struct CreateTicket {
     /// With webauthn the format of half-authenticated tickts changed. New
     /// clients should pass 1 here and not worry about the old format. The old
     /// format is deprecated and will be retired with PVE-8.0
-    #[serde(deserialize_with = "crate::parse::deserialize_bool")]
+    #[serde(deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     #[serde(default, skip_serializing_if = "Option::is_none")]
     #[serde(rename = "new-format")]
     pub new_format: Option<bool>,
diff --git a/proxmox-login/src/lib.rs b/proxmox-login/src/lib.rs
index e97ece7b..4482f2e4 100644
--- a/proxmox-login/src/lib.rs
+++ b/proxmox-login/src/lib.rs
@@ -5,8 +5,6 @@
 
 use serde::{Deserialize, Serialize};
 
-pub mod parse;
-
 pub mod api;
 pub mod error;
 pub mod tfa;
diff --git a/proxmox-login/src/parse.rs b/proxmox-login/src/parse.rs
deleted file mode 100644
index 8efa86c9..00000000
--- a/proxmox-login/src/parse.rs
+++ /dev/null
@@ -1,373 +0,0 @@
-//! Some parsing helpers for the PVE API, mainly to deal with perl's untypedness.
-
-use std::fmt;
-
-use serde::de::Unexpected;
-
-// Boolean:
-
-pub trait FromBool: Sized + Default {
-    fn from_bool(value: bool) -> Self;
-}
-
-impl FromBool for bool {
-    fn from_bool(value: bool) -> Self {
-        value
-    }
-}
-
-impl FromBool for Option<bool> {
-    fn from_bool(value: bool) -> Self {
-        Some(value)
-    }
-}
-
-pub fn deserialize_bool<'de, D, T>(deserializer: D) -> Result<T, D::Error>
-where
-    D: serde::Deserializer<'de>,
-    T: FromBool,
-{
-    deserializer.deserialize_any(BoolVisitor::<T>::new())
-}
-
-struct BoolVisitor<T>(std::marker::PhantomData<T>);
-
-impl<T> BoolVisitor<T> {
-    fn new() -> Self {
-        Self(std::marker::PhantomData)
-    }
-}
-
-impl<'de, T: FromBool> serde::de::DeserializeSeed<'de> for BoolVisitor<T> {
-    type Value = T;
-
-    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        deserialize_bool(deserializer)
-    }
-}
-
-impl<'de, T> serde::de::Visitor<'de> for BoolVisitor<T>
-where
-    T: FromBool,
-{
-    type Value = T;
-
-    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write_str("a boolean-ish...")
-    }
-
-    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
-    where
-        D: serde::Deserializer<'de>,
-    {
-        deserializer.deserialize_any(self)
-    }
-
-    fn visit_none<E>(self) -> Result<Self::Value, E> {
-        Ok(Default::default())
-    }
-
-    fn visit_bool<E: serde::de::Error>(self, value: bool) -> Result<Self::Value, E> {
-        Ok(Self::Value::from_bool(value))
-    }
-
-    fn visit_i128<E: serde::de::Error>(self, value: i128) -> Result<Self::Value, E> {
-        Ok(Self::Value::from_bool(value != 0))
-    }
-
-    fn visit_i64<E: serde::de::Error>(self, value: i64) -> Result<Self::Value, E> {
-        Ok(Self::Value::from_bool(value != 0))
-    }
-
-    fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Self::Value, E> {
-        Ok(Self::Value::from_bool(value != 0))
-    }
-
-    fn visit_u128<E: serde::de::Error>(self, value: u128) -> Result<Self::Value, E> {
-        Ok(Self::Value::from_bool(value != 0))
-    }
-
-    fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
-        let value = if value.eq_ignore_ascii_case("true")
-            || value.eq_ignore_ascii_case("yes")
-            || value.eq_ignore_ascii_case("on")
-            || value == "1"
-        {
-            true
-        } else if value.eq_ignore_ascii_case("false")
-            || value.eq_ignore_ascii_case("no")
-            || value.eq_ignore_ascii_case("off")
-            || value == "0"
-        {
-            false
-        } else {
-            return Err(E::invalid_value(
-                serde::de::Unexpected::Str(value),
-                &"a boolean-like value",
-            ));
-        };
-        Ok(Self::Value::from_bool(value))
-    }
-}
-
-// integer helpers:
-
-macro_rules! integer_helper {
-    ($ty:ident, $deserialize_name:ident, $trait: ident, $from_name:ident, $visitor:ident) => {
-        #[doc(hidden)]
-        pub trait $trait: Sized + Default {
-            fn $from_name(value: $ty) -> Self;
-        }
-
-        impl $trait for $ty {
-            fn $from_name(value: $ty) -> Self {
-                value
-            }
-        }
-
-        impl $trait for Option<$ty> {
-            fn $from_name(value: $ty) -> Self {
-                Some(value)
-            }
-        }
-
-        pub fn $deserialize_name<'de, D, T>(deserializer: D) -> Result<T, D::Error>
-        where
-            D: serde::Deserializer<'de>,
-            T: $trait,
-        {
-            deserializer.deserialize_any($visitor::<T>::new())
-        }
-
-        struct $visitor<T>(std::marker::PhantomData<T>);
-
-        impl<T> $visitor<T> {
-            fn new() -> Self {
-                Self(std::marker::PhantomData)
-            }
-        }
-
-        impl<'de, T: $trait> serde::de::DeserializeSeed<'de> for $visitor<T> {
-            type Value = T;
-
-            fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
-            where
-                D: serde::Deserializer<'de>,
-            {
-                $deserialize_name(deserializer)
-            }
-        }
-
-        impl<'de, T> serde::de::Visitor<'de> for $visitor<T>
-        where
-            T: $trait,
-        {
-            type Value = T;
-
-            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
-                f.write_str(concat!("a ", stringify!($ty), "-ish..."))
-            }
-
-            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
-            where
-                D: serde::Deserializer<'de>,
-            {
-                deserializer.deserialize_any(self)
-            }
-
-            fn visit_none<E>(self) -> Result<Self::Value, E> {
-                Ok(Default::default())
-            }
-
-            fn visit_i128<E: serde::de::Error>(self, value: i128) -> Result<Self::Value, E> {
-                $ty::try_from(value)
-                    .map_err(|_| E::invalid_value(Unexpected::Other("i128"), &self))
-                    .map(Self::Value::$from_name)
-            }
-
-            fn visit_i64<E: serde::de::Error>(self, value: i64) -> Result<Self::Value, E> {
-                $ty::try_from(value)
-                    .map_err(|_| E::invalid_value(Unexpected::Signed(value), &self))
-                    .map(Self::Value::$from_name)
-            }
-
-            fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Self::Value, E> {
-                $ty::try_from(value)
-                    .map_err(|_| E::invalid_value(Unexpected::Unsigned(value), &self))
-                    .map(Self::Value::$from_name)
-            }
-
-            fn visit_u128<E: serde::de::Error>(self, value: u128) -> Result<Self::Value, E> {
-                $ty::try_from(value)
-                    .map_err(|_| E::invalid_value(Unexpected::Other("u128"), &self))
-                    .map(Self::Value::$from_name)
-            }
-
-            fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
-                let value = value
-                    .parse()
-                    .map_err(|_| E::invalid_value(Unexpected::Str(value), &self))?;
-                self.visit_i64(value)
-            }
-        }
-    };
-}
-
-integer_helper!(
-    isize,
-    deserialize_isize,
-    FromIsize,
-    from_isize,
-    IsizeVisitor
-);
-
-integer_helper!(
-    usize,
-    deserialize_usize,
-    FromUsize,
-    from_usize,
-    UsizeVisitor
-);
-
-integer_helper!(u8, deserialize_u8, FromU8, from_u8, U8Visitor);
-integer_helper!(u16, deserialize_u16, FromU16, from_u16, U16Visitor);
-integer_helper!(u32, deserialize_u32, FromU32, from_u32, U32Visitor);
-integer_helper!(u64, deserialize_u64, FromU64, from_u64, U64Visitor);
-integer_helper!(i8, deserialize_i8, FromI8, from_i8, I8Visitor);
-integer_helper!(i16, deserialize_i16, FromI16, from_i16, I16Visitor);
-integer_helper!(i32, deserialize_i32, FromI32, from_i32, I32Visitor);
-integer_helper!(i64, deserialize_i64, FromI64, from_i64, I64Visitor);
-
-// float helpers:
-
-macro_rules! float_helper {
-    ($ty:ident, $deserialize_name:ident, $visitor:ident) => {
-        pub fn $deserialize_name<'de, D, T>(deserializer: D) -> Result<T, D::Error>
-        where
-            D: serde::Deserializer<'de>,
-            T: FromF64,
-        {
-            deserializer.deserialize_any($visitor::<T>::new())
-        }
-
-        struct $visitor<T>(std::marker::PhantomData<T>);
-
-        impl<T> $visitor<T> {
-            fn new() -> Self {
-                Self(std::marker::PhantomData)
-            }
-        }
-
-        impl<'de, T: FromF64> serde::de::DeserializeSeed<'de> for $visitor<T> {
-            type Value = T;
-
-            fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
-            where
-                D: serde::Deserializer<'de>,
-            {
-                $deserialize_name(deserializer)
-            }
-        }
-
-        impl<'de, T> serde::de::Visitor<'de> for $visitor<T>
-        where
-            T: FromF64,
-        {
-            type Value = T;
-
-            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
-                f.write_str(concat!("a ", stringify!($ty), "-ish..."))
-            }
-
-            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
-            where
-                D: serde::Deserializer<'de>,
-            {
-                deserializer.deserialize_any(self)
-            }
-
-            fn visit_none<E>(self) -> Result<Self::Value, E> {
-                Ok(Default::default())
-            }
-
-            fn visit_f64<E: serde::de::Error>(self, value: f64) -> Result<Self::Value, E> {
-                Ok(T::from_f64(value))
-            }
-
-            fn visit_i128<E: serde::de::Error>(self, value: i128) -> Result<Self::Value, E> {
-                let conv = value as f64;
-                if conv as i128 == value {
-                    Ok(T::from_f64(conv))
-                } else {
-                    Err(E::invalid_value(Unexpected::Other("i128"), &self))
-                }
-            }
-
-            fn visit_i64<E: serde::de::Error>(self, value: i64) -> Result<Self::Value, E> {
-                let conv = value as f64;
-                if conv as i64 == value {
-                    Ok(T::from_f64(conv))
-                } else {
-                    Err(E::invalid_value(Unexpected::Signed(value), &self))
-                }
-            }
-
-            fn visit_u128<E: serde::de::Error>(self, value: u128) -> Result<Self::Value, E> {
-                let conv = value as f64;
-                if conv as u128 == value {
-                    Ok(T::from_f64(conv))
-                } else {
-                    Err(E::invalid_value(Unexpected::Other("u128"), &self))
-                }
-            }
-
-            fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Self::Value, E> {
-                let conv = value as f64;
-                if conv as u64 == value {
-                    Ok(T::from_f64(conv))
-                } else {
-                    Err(E::invalid_value(Unexpected::Unsigned(value), &self))
-                }
-            }
-
-            fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
-                let value = value
-                    .parse()
-                    .map_err(|_| E::invalid_value(Unexpected::Str(value), &self))?;
-                self.visit_f64(value)
-            }
-        }
-    };
-}
-
-#[doc(hidden)]
-pub trait FromF64: Sized + Default {
-    fn from_f64(value: f64) -> Self;
-}
-
-impl FromF64 for f32 {
-    #[inline(always)]
-    fn from_f64(f: f64) -> f32 {
-        f as f32
-    }
-}
-
-impl FromF64 for f64 {
-    #[inline(always)]
-    fn from_f64(f: f64) -> f64 {
-        f
-    }
-}
-
-impl<T: FromF64> FromF64 for Option<T> {
-    #[inline(always)]
-    fn from_f64(f: f64) -> Option<T> {
-        Some(T::from_f64(f))
-    }
-}
-
-float_helper!(f32, deserialize_f32, F32Visitor);
-float_helper!(f64, deserialize_f64, F64Visitor);
-- 
2.39.5


_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel


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

* [pbs-devel] [PATCH proxmox 3/3] client: move to proxmox_serde perl helpers
  2025-05-13 10:14 [pbs-devel] [PATCH proxmox{, -api-types, -ve-rs} 0/6] Move perl deserializers from proxmox-login to proxmox-serde Stefan Hanreich
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox 1/3] serde: add parsing helpers for perl Stefan Hanreich
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox 2/3] login: move parse module to proxmox-serde Stefan Hanreich
@ 2025-05-13 10:14 ` Stefan Hanreich
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox-api-types 1/2] generator: use proxmox_serde for " Stefan Hanreich
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox-ve-rs 1/1] config: use proxmox_serde " Stefan Hanreich
  4 siblings, 0 replies; 7+ messages in thread
From: Stefan Hanreich @ 2025-05-13 10:14 UTC (permalink / raw)
  To: pbs-devel

The perl helpers have been moved to proxmox_serde from proxmox_login,
so fix all occurences using the proxmox_login crate.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
 proxmox-client/Cargo.toml | 2 ++
 proxmox-client/src/lib.rs | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/proxmox-client/Cargo.toml b/proxmox-client/Cargo.toml
index c2682e77..b15c9faa 100644
--- a/proxmox-client/Cargo.toml
+++ b/proxmox-client/Cargo.toml
@@ -27,6 +27,8 @@ proxmox-login = { workspace = true, features = [ "http" ] }
 proxmox-http = { workspace = true, optional = true, features = [ "client" ] }
 hyper = { workspace = true, optional = true }
 
+proxmox-serde = { workspace = true, features = [ "perl" ] }
+
 [dev-dependencies]
 serde_plain.workspace = true
 
diff --git a/proxmox-client/src/lib.rs b/proxmox-client/src/lib.rs
index e802f4ce..f1df1e1d 100644
--- a/proxmox-client/src/lib.rs
+++ b/proxmox-client/src/lib.rs
@@ -173,10 +173,10 @@ pub struct ApiResponseData<T> {
 
 #[derive(serde::Deserialize)]
 struct RawApiResponse<T> {
-    #[serde(default, deserialize_with = "proxmox_login::parse::deserialize_u16")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_u16")]
     status: Option<u16>,
     message: Option<String>,
-    #[serde(default, deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     success: Option<bool>,
     data: Option<T>,
 
-- 
2.39.5


_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel


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

* [pbs-devel] [PATCH proxmox-api-types 1/2] generator: use proxmox_serde for perl helpers
  2025-05-13 10:14 [pbs-devel] [PATCH proxmox{, -api-types, -ve-rs} 0/6] Move perl deserializers from proxmox-login to proxmox-serde Stefan Hanreich
                   ` (2 preceding siblings ...)
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox 3/3] client: move to proxmox_serde perl helpers Stefan Hanreich
@ 2025-05-13 10:14 ` Stefan Hanreich
  2025-05-13 11:44   ` Stefan Hanreich
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox-ve-rs 1/1] config: use proxmox_serde " Stefan Hanreich
  4 siblings, 1 reply; 7+ messages in thread
From: Stefan Hanreich @ 2025-05-13 10:14 UTC (permalink / raw)
  To: pbs-devel

The helpers for parsing perl values have been moved to proxmox_serde,
update all references to proxmox_login. No functional changes.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
 Cargo.toml                                 |  2 +-
 pve-api-types/Cargo.toml                   |  2 +-
 pve-api-types/generator-lib/Schema2Rust.pm | 26 +++++++++++-----------
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 1bbdd01..1e119d3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,7 +22,7 @@ serde_plain = "1"
 serde_json = "1"
 
 proxmox-api-macro = "1.3"
-proxmox-login = "0.2"
+proxmox-serde = "0.1.2"
 proxmox-schema = "4"
 
 proxmox-client = "0.5"
diff --git a/pve-api-types/Cargo.toml b/pve-api-types/Cargo.toml
index 73cd3ef..e388cac 100644
--- a/pve-api-types/Cargo.toml
+++ b/pve-api-types/Cargo.toml
@@ -18,7 +18,7 @@ serde_json.workspace = true
 serde_plain.workspace = true
 #
 proxmox-api-macro.workspace = true
-proxmox-login.workspace = true
+proxmox-serde = { workspace = true, features = [ "perl" ] }
 proxmox-schema = { workspace = true, features = [ "api-types", "api-macro" ] }
 
 # For the client feature:
diff --git a/pve-api-types/generator-lib/Schema2Rust.pm b/pve-api-types/generator-lib/Schema2Rust.pm
index 009cf13..99a8fd6 100644
--- a/pve-api-types/generator-lib/Schema2Rust.pm
+++ b/pve-api-types/generator-lib/Schema2Rust.pm
@@ -1127,18 +1127,18 @@ my sub array_type : prototype($$$) {
 }
 
 my %serde_num = (
-    usize => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_usize")]',
-    isize => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_isize")]',
-    u8 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_u8")]',
-    u16 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_u16")]',
-    u32 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_u32")]',
-    u64 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_u64")]',
-    i8 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_i8")]',
-    i16 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_i16")]',
-    i32 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_i32")]',
-    i64 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_i64")]',
-    f32 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_f32")]',
-    f64 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_f64")]',
+    usize => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_usize")]',
+    isize => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_isize")]',
+    u8 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u8")]',
+    u16 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u16")]',
+    u32 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u32")]',
+    u64 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u64")]',
+    i8 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_i8")]',
+    i16 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_i16")]',
+    i32 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_i32")]',
+    i64 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_i64")]',
+    f32 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_f32")]',
+    f64 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_f64")]',
 );
 
 sub handle_def : prototype($$$) {
@@ -1169,7 +1169,7 @@ sub handle_def : prototype($$$) {
     } elsif ($type eq 'boolean') {
         $def->{type} = 'bool';
         push $def->{attrs}->@*,
-            "#[serde(deserialize_with = \"proxmox_login::parse::deserialize_bool\")]";
+            "#[serde(deserialize_with = \"proxmox_serde::perl::deserialize_bool\")]";
         $def->{api}->{default} = bool(delete $schema->{default});
     } elsif ($type eq 'number') {
         $def->{api}->{default} = delete $schema->{default};
-- 
2.39.5


_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel


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

* [pbs-devel] [PATCH proxmox-ve-rs 1/1] config: use proxmox_serde perl helpers
  2025-05-13 10:14 [pbs-devel] [PATCH proxmox{, -api-types, -ve-rs} 0/6] Move perl deserializers from proxmox-login to proxmox-serde Stefan Hanreich
                   ` (3 preceding siblings ...)
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox-api-types 1/2] generator: use proxmox_serde for " Stefan Hanreich
@ 2025-05-13 10:14 ` Stefan Hanreich
  4 siblings, 0 replies; 7+ messages in thread
From: Stefan Hanreich @ 2025-05-13 10:14 UTC (permalink / raw)
  To: pbs-devel

proxmox_serde provides helpers for parsing optional numbers / booleans
coming from perl, so move to using them instead of implementing our
own versions here. No functional changes intended.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
 proxmox-ve-config/Cargo.toml              |  1 +
 proxmox-ve-config/src/firewall/bridge.rs  |  3 +-
 proxmox-ve-config/src/firewall/cluster.rs |  6 +-
 proxmox-ve-config/src/firewall/guest.rs   | 14 ++--
 proxmox-ve-config/src/firewall/host.rs    | 26 ++++----
 proxmox-ve-config/src/firewall/parse.rs   | 80 -----------------------
 6 files changed, 24 insertions(+), 106 deletions(-)

diff --git a/proxmox-ve-config/Cargo.toml b/proxmox-ve-config/Cargo.toml
index 6c7a47e..e998b45 100644
--- a/proxmox-ve-config/Cargo.toml
+++ b/proxmox-ve-config/Cargo.toml
@@ -16,6 +16,7 @@ serde = { version = "1", features = [ "derive" ] }
 serde_json = "1"
 serde_plain = "1"
 serde_with = "3"
+proxmox-serde = { version = "0.1.2", features = [ "perl" ]}
 
 proxmox-schema = "4"
 proxmox-sys = "0.6.4"
diff --git a/proxmox-ve-config/src/firewall/bridge.rs b/proxmox-ve-config/src/firewall/bridge.rs
index 4acb6fa..6dea60e 100644
--- a/proxmox-ve-config/src/firewall/bridge.rs
+++ b/proxmox-ve-config/src/firewall/bridge.rs
@@ -3,7 +3,6 @@ use std::io;
 use anyhow::Error;
 use serde::Deserialize;
 
-use crate::firewall::parse::serde_option_bool;
 use crate::firewall::types::log::LogLevel;
 use crate::firewall::types::rule::{Direction, Verdict};
 
@@ -55,7 +54,7 @@ impl Config {
 #[derive(Debug, Default, Deserialize)]
 #[cfg_attr(test, derive(Eq, PartialEq))]
 pub struct Options {
-    #[serde(default, with = "serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     enable: Option<bool>,
 
     policy_forward: Option<Verdict>,
diff --git a/proxmox-ve-config/src/firewall/cluster.rs b/proxmox-ve-config/src/firewall/cluster.rs
index ce3dd53..a775cd9 100644
--- a/proxmox-ve-config/src/firewall/cluster.rs
+++ b/proxmox-ve-config/src/firewall/cluster.rs
@@ -10,7 +10,7 @@ use crate::firewall::types::log::LogRateLimit;
 use crate::firewall::types::rule::{Direction, Verdict};
 use crate::firewall::types::{Alias, Group, Rule};
 
-use crate::firewall::parse::{serde_option_bool, serde_option_log_ratelimit};
+use crate::firewall::parse::serde_option_log_ratelimit;
 
 #[derive(Debug, Default)]
 pub struct Config {
@@ -118,10 +118,10 @@ impl Config {
 #[derive(Debug, Default, Deserialize)]
 #[cfg_attr(test, derive(Eq, PartialEq))]
 pub struct Options {
-    #[serde(default, with = "serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     enable: Option<bool>,
 
-    #[serde(default, with = "serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     ebtables: Option<bool>,
 
     #[serde(default, with = "serde_option_log_ratelimit")]
diff --git a/proxmox-ve-config/src/firewall/guest.rs b/proxmox-ve-config/src/firewall/guest.rs
index 23eaa4e..4428a75 100644
--- a/proxmox-ve-config/src/firewall/guest.rs
+++ b/proxmox-ve-config/src/firewall/guest.rs
@@ -13,8 +13,6 @@ use crate::firewall::types::Ipset;
 use anyhow::{bail, Error};
 use serde::Deserialize;
 
-use crate::firewall::parse::serde_option_bool;
-
 /// default return value for [`Config::is_enabled()`]
 pub const GUEST_ENABLED_DEFAULT: bool = false;
 /// default return value for [`Config::allow_ndp()`]
@@ -37,25 +35,25 @@ pub const GUEST_POLICY_FORWARD_DEFAULT: Verdict = Verdict::Accept;
 #[derive(Debug, Default, Deserialize)]
 #[cfg_attr(test, derive(Eq, PartialEq))]
 pub struct Options {
-    #[serde(default, with = "serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     dhcp: Option<bool>,
 
-    #[serde(default, with = "serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     enable: Option<bool>,
 
-    #[serde(default, with = "serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     ipfilter: Option<bool>,
 
-    #[serde(default, with = "serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     ndp: Option<bool>,
 
-    #[serde(default, with = "serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     radv: Option<bool>,
 
     log_level_in: Option<LogLevel>,
     log_level_out: Option<LogLevel>,
 
-    #[serde(default, with = "serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     macfilter: Option<bool>,
 
     #[serde(rename = "policy_in")]
diff --git a/proxmox-ve-config/src/firewall/host.rs b/proxmox-ve-config/src/firewall/host.rs
index 394896c..f7b02f9 100644
--- a/proxmox-ve-config/src/firewall/host.rs
+++ b/proxmox-ve-config/src/firewall/host.rs
@@ -36,49 +36,49 @@ pub const HOST_LOG_INVALID_CONNTRACK: bool = false;
 #[derive(Debug, Default, Deserialize)]
 #[cfg_attr(test, derive(Eq, PartialEq))]
 pub struct Options {
-    #[serde(default, with = "parse::serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     enable: Option<bool>,
 
-    #[serde(default, with = "parse::serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     nftables: Option<bool>,
 
     log_level_in: Option<LogLevel>,
     log_level_out: Option<LogLevel>,
     log_level_forward: Option<LogLevel>,
 
-    #[serde(default, with = "parse::serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     log_nf_conntrack: Option<bool>,
-    #[serde(default, with = "parse::serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     ndp: Option<bool>,
 
-    #[serde(default, with = "parse::serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     nf_conntrack_allow_invalid: Option<bool>,
 
     // is Option<Vec<>> for easier deserialization
     #[serde(default, with = "parse::serde_option_conntrack_helpers")]
     nf_conntrack_helpers: Option<Vec<String>>,
 
-    #[serde(default, with = "parse::serde_option_number")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_i64")]
     nf_conntrack_max: Option<i64>,
-    #[serde(default, with = "parse::serde_option_number")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_i64")]
     nf_conntrack_tcp_timeout_established: Option<i64>,
-    #[serde(default, with = "parse::serde_option_number")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_i64")]
     nf_conntrack_tcp_timeout_syn_recv: Option<i64>,
 
-    #[serde(default, with = "parse::serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     nosmurfs: Option<bool>,
 
-    #[serde(default, with = "parse::serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     protection_synflood: Option<bool>,
-    #[serde(default, with = "parse::serde_option_number")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_i64")]
     protection_synflood_burst: Option<i64>,
-    #[serde(default, with = "parse::serde_option_number")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_i64")]
     protection_synflood_rate: Option<i64>,
 
     smurf_log_level: Option<LogLevel>,
     tcp_flags_log_level: Option<LogLevel>,
 
-    #[serde(default, with = "parse::serde_option_bool")]
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
     tcpflags: Option<bool>,
 }
 
diff --git a/proxmox-ve-config/src/firewall/parse.rs b/proxmox-ve-config/src/firewall/parse.rs
index 8cf4757..7fd5c84 100644
--- a/proxmox-ve-config/src/firewall/parse.rs
+++ b/proxmox-ve-config/src/firewall/parse.rs
@@ -148,86 +148,6 @@ pub fn parse_named_section_tail<'a>(
     })
 }
 
-// parses a number from a string OR number
-pub mod serde_option_number {
-    use std::fmt;
-
-    use serde::de::{Deserializer, Error, Visitor};
-
-    pub fn deserialize<'de, D: Deserializer<'de>>(
-        deserializer: D,
-    ) -> Result<Option<i64>, D::Error> {
-        struct V;
-
-        impl<'de> Visitor<'de> for V {
-            type Value = Option<i64>;
-
-            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
-                f.write_str("a numerical value")
-            }
-
-            fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
-                v.parse().map_err(E::custom).map(Some)
-            }
-
-            fn visit_none<E: Error>(self) -> Result<Self::Value, E> {
-                Ok(None)
-            }
-
-            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
-            where
-                D: Deserializer<'de>,
-            {
-                deserializer.deserialize_any(self)
-            }
-        }
-
-        deserializer.deserialize_any(V)
-    }
-}
-
-// parses a bool from a string OR bool
-pub mod serde_option_bool {
-    use std::fmt;
-
-    use serde::de::{Deserializer, Error, Visitor};
-
-    pub fn deserialize<'de, D: Deserializer<'de>>(
-        deserializer: D,
-    ) -> Result<Option<bool>, D::Error> {
-        struct V;
-
-        impl<'de> Visitor<'de> for V {
-            type Value = Option<bool>;
-
-            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
-                f.write_str("a boolean-like value")
-            }
-
-            fn visit_bool<E: Error>(self, v: bool) -> Result<Self::Value, E> {
-                Ok(Some(v))
-            }
-
-            fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
-                super::parse_bool(v).map_err(E::custom).map(Some)
-            }
-
-            fn visit_none<E: Error>(self) -> Result<Self::Value, E> {
-                Ok(None)
-            }
-
-            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
-            where
-                D: Deserializer<'de>,
-            {
-                deserializer.deserialize_any(self)
-            }
-        }
-
-        deserializer.deserialize_any(V)
-    }
-}
-
 // parses a comma_separated list of strings
 pub mod serde_option_conntrack_helpers {
     use std::fmt;
-- 
2.39.5


_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel


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

* Re: [pbs-devel] [PATCH proxmox-api-types 1/2] generator: use proxmox_serde for perl helpers
  2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox-api-types 1/2] generator: use proxmox_serde for " Stefan Hanreich
@ 2025-05-13 11:44   ` Stefan Hanreich
  0 siblings, 0 replies; 7+ messages in thread
From: Stefan Hanreich @ 2025-05-13 11:44 UTC (permalink / raw)
  To: pbs-devel

Since the patch #2 didn't go through due to size:

pve-api-types would need to be re-generated after this patch.

On 5/13/25 12:14, Stefan Hanreich wrote:
> The helpers for parsing perl values have been moved to proxmox_serde,
> update all references to proxmox_login. No functional changes.
> 
> Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
> ---
>  Cargo.toml                                 |  2 +-
>  pve-api-types/Cargo.toml                   |  2 +-
>  pve-api-types/generator-lib/Schema2Rust.pm | 26 +++++++++++-----------
>  3 files changed, 15 insertions(+), 15 deletions(-)
> 
> diff --git a/Cargo.toml b/Cargo.toml
> index 1bbdd01..1e119d3 100644
> --- a/Cargo.toml
> +++ b/Cargo.toml
> @@ -22,7 +22,7 @@ serde_plain = "1"
>  serde_json = "1"
>  
>  proxmox-api-macro = "1.3"
> -proxmox-login = "0.2"
> +proxmox-serde = "0.1.2"
>  proxmox-schema = "4"
>  
>  proxmox-client = "0.5"
> diff --git a/pve-api-types/Cargo.toml b/pve-api-types/Cargo.toml
> index 73cd3ef..e388cac 100644
> --- a/pve-api-types/Cargo.toml
> +++ b/pve-api-types/Cargo.toml
> @@ -18,7 +18,7 @@ serde_json.workspace = true
>  serde_plain.workspace = true
>  #
>  proxmox-api-macro.workspace = true
> -proxmox-login.workspace = true
> +proxmox-serde = { workspace = true, features = [ "perl" ] }
>  proxmox-schema = { workspace = true, features = [ "api-types", "api-macro" ] }
>  
>  # For the client feature:
> diff --git a/pve-api-types/generator-lib/Schema2Rust.pm b/pve-api-types/generator-lib/Schema2Rust.pm
> index 009cf13..99a8fd6 100644
> --- a/pve-api-types/generator-lib/Schema2Rust.pm
> +++ b/pve-api-types/generator-lib/Schema2Rust.pm
> @@ -1127,18 +1127,18 @@ my sub array_type : prototype($$$) {
>  }
>  
>  my %serde_num = (
> -    usize => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_usize")]',
> -    isize => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_isize")]',
> -    u8 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_u8")]',
> -    u16 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_u16")]',
> -    u32 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_u32")]',
> -    u64 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_u64")]',
> -    i8 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_i8")]',
> -    i16 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_i16")]',
> -    i32 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_i32")]',
> -    i64 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_i64")]',
> -    f32 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_f32")]',
> -    f64 => '#[serde(deserialize_with = "proxmox_login::parse::deserialize_f64")]',
> +    usize => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_usize")]',
> +    isize => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_isize")]',
> +    u8 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u8")]',
> +    u16 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u16")]',
> +    u32 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u32")]',
> +    u64 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_u64")]',
> +    i8 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_i8")]',
> +    i16 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_i16")]',
> +    i32 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_i32")]',
> +    i64 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_i64")]',
> +    f32 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_f32")]',
> +    f64 => '#[serde(deserialize_with = "proxmox_serde::perl::deserialize_f64")]',
>  );
>  
>  sub handle_def : prototype($$$) {
> @@ -1169,7 +1169,7 @@ sub handle_def : prototype($$$) {
>      } elsif ($type eq 'boolean') {
>          $def->{type} = 'bool';
>          push $def->{attrs}->@*,
> -            "#[serde(deserialize_with = \"proxmox_login::parse::deserialize_bool\")]";
> +            "#[serde(deserialize_with = \"proxmox_serde::perl::deserialize_bool\")]";
>          $def->{api}->{default} = bool(delete $schema->{default});
>      } elsif ($type eq 'number') {
>          $def->{api}->{default} = delete $schema->{default};



_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel


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

end of thread, other threads:[~2025-05-13 11:43 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-13 10:14 [pbs-devel] [PATCH proxmox{, -api-types, -ve-rs} 0/6] Move perl deserializers from proxmox-login to proxmox-serde Stefan Hanreich
2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox 1/3] serde: add parsing helpers for perl Stefan Hanreich
2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox 2/3] login: move parse module to proxmox-serde Stefan Hanreich
2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox 3/3] client: move to proxmox_serde perl helpers Stefan Hanreich
2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox-api-types 1/2] generator: use proxmox_serde for " Stefan Hanreich
2025-05-13 11:44   ` Stefan Hanreich
2025-05-13 10:14 ` [pbs-devel] [PATCH proxmox-ve-rs 1/1] config: use proxmox_serde " Stefan Hanreich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal