all lists on 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 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