[pbs-devel] [PATCH proxmox 2/3] login: move parse module to proxmox-serde
Stefan Hanreich
s.hanreich at proxmox.com
Tue May 13 12:14:55 CEST 2025
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 at 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
More information about the pbs-devel
mailing list