From e94c6578104d8530f9465eb8fe998feccd52582d Mon Sep 17 00:00:00 2001 From: jmjoy Date: Thu, 5 Mar 2026 11:06:30 +0800 Subject: [PATCH 1/4] Implements more elements for FromZVal/FromZValMut --- phper/src/values.rs | 80 ++++++++++++++++++++++----------- tests/integration/src/values.rs | 16 +++---- 2 files changed, 62 insertions(+), 34 deletions(-) diff --git a/phper/src/values.rs b/phper/src/values.rs index 810eb95..250ab5e 100644 --- a/phper/src/values.rs +++ b/phper/src/values.rs @@ -238,22 +238,12 @@ pub struct ZVal { /// Conversion from immutable [`ZVal`]. pub trait FromZVal<'a>: Sized { - /// Converts from `ZVal`, return `None` when type mismatch. - fn as_(val: &'a ZVal) -> Option { - Self::expect(val).ok() - } - /// Converts from `ZVal`, return [`ExpectTypeError`] when type mismatch. fn expect(val: &'a ZVal) -> crate::Result; } /// Conversion from mutable [`ZVal`]. pub trait FromZValMut<'a>: Sized { - /// Converts from mutable `ZVal`, return `None` when type mismatch. - fn as_(val: &'a mut ZVal) -> Option { - Self::expect(val).ok() - } - /// Converts from mutable `ZVal`, return [`ExpectTypeError`] when type /// mismatch. fn expect(val: &'a mut ZVal) -> crate::Result; @@ -445,14 +435,6 @@ impl ZVal { t.into() } - /// Converts to target type by [`FromZVal`]. - pub fn as_type<'a, T>(&'a self) -> Option - where - T: FromZVal<'a>, - { - T::as_(self) - } - /// Converts to target type by [`FromZVal`], otherwise returns /// [`ExpectTypeError`]. pub fn expect_type<'a, T>(&'a self) -> crate::Result @@ -462,14 +444,6 @@ impl ZVal { T::expect(self) } - /// Converts to target mutable type by [`FromZValMut`]. - pub fn as_mut_type<'a, T>(&'a mut self) -> Option - where - T: FromZValMut<'a>, - { - T::as_(self) - } - /// Converts to target mutable type by [`FromZValMut`], otherwise returns /// [`ExpectTypeError`]. pub fn expect_mut_type<'a, T>(&'a mut self) -> crate::Result @@ -615,6 +589,24 @@ impl ZVal { self.inner_expect_z_str().map(|x| &*x) } + /// Converts to bytes if `ZVal` is string, otherwise returns + /// [`ExpectTypeError`]. + pub fn expect_bytes(&self) -> crate::Result<&[u8]> { + self.expect_z_str().map(ZStr::to_bytes) + } + + /// Converts to str if `ZVal` is string and valid UTF-8, otherwise returns + /// error. + pub fn expect_str(&self) -> crate::Result<&str> { + Ok(self.expect_z_str()?.to_str()?) + } + + /// Converts to CStr if `ZVal` is string and contains a valid trailing nul, + /// otherwise returns error. + pub fn expect_c_str(&self) -> crate::Result<&CStr> { + Ok(self.expect_z_str()?.to_c_str()?) + } + /// Converts to mutable string if `ZVal` is string. pub fn as_mut_z_str(&mut self) -> Option<&mut ZStr> { self.expect_mut_z_str().ok() @@ -884,6 +876,42 @@ impl<'a> FromZVal<'a> for &'a ZStr { } } +impl<'a> FromZVal<'a> for &'a [u8] { + fn expect(val: &'a ZVal) -> crate::Result { + val.expect_bytes() + } +} + +impl<'a> FromZValMut<'a> for &'a [u8] { + fn expect(val: &'a mut ZVal) -> crate::Result { + val.expect_mut_z_str().map(|s| s.to_bytes()) + } +} + +impl<'a> FromZVal<'a> for &'a str { + fn expect(val: &'a ZVal) -> crate::Result { + val.expect_str() + } +} + +impl<'a> FromZValMut<'a> for &'a str { + fn expect(val: &'a mut ZVal) -> crate::Result { + Ok(val.expect_mut_z_str()?.to_str()?) + } +} + +impl<'a> FromZVal<'a> for &'a CStr { + fn expect(val: &'a ZVal) -> crate::Result { + val.expect_c_str() + } +} + +impl<'a> FromZValMut<'a> for &'a CStr { + fn expect(val: &'a mut ZVal) -> crate::Result { + Ok(val.expect_mut_z_str()?.to_c_str()?) + } +} + impl<'a> FromZValMut<'a> for &'a mut ZStr { fn expect(val: &'a mut ZVal) -> crate::Result { val.expect_mut_z_str() diff --git a/tests/integration/src/values.rs b/tests/integration/src/values.rs index 164a79e..a663c47 100644 --- a/tests/integration/src/values.rs +++ b/tests/integration/src/values.rs @@ -190,22 +190,22 @@ fn integration_values_as(_: &mut [ZVal]) -> Result<(), Infallible> { { let val = ZVal::default(); - assert_eq!(val.as_type::<()>(), Some(())); + assert_eq!(val.expect_type::<()>().ok(), Some(())); assert!(val.expect_type::<()>().is_ok()); assert!(val.expect_type::().is_err()); } { let val = ZVal::from(true); - assert_eq!(val.as_type::(), Some(true)); - assert_eq!(val.as_type::(), None); + assert_eq!(val.expect_type::().ok(), Some(true)); + assert_eq!(val.expect_type::().ok(), None); assert!(val.expect_type::().is_err()); } { let mut val = ZVal::from(100i64); - assert_eq!(val.as_type::(), Some(100)); - if let Some(l) = val.as_mut_type::<&mut i64>() { + assert_eq!(val.expect_type::().ok(), Some(100)); + if let Some(l) = val.expect_mut_type::<&mut i64>().ok() { *l += 100; } assert_eq!(val.expect_type::().unwrap(), 200); @@ -214,8 +214,8 @@ fn integration_values_as(_: &mut [ZVal]) -> Result<(), Infallible> { { let mut val = ZVal::from(100f64); - assert_eq!(val.as_type::(), Some(100.)); - if let Some(d) = val.as_mut_type::<&mut f64>() { + assert_eq!(val.expect_type::().ok(), Some(100.)); + if let Some(d) = val.expect_mut_type::<&mut f64>().ok() { *d += 100.; } assert_eq!(val.expect_type::().unwrap(), 200.); @@ -225,7 +225,7 @@ fn integration_values_as(_: &mut [ZVal]) -> Result<(), Infallible> { { let val = ZVal::from("foo"); assert_eq!( - val.as_type::<&phper::strings::ZStr>().unwrap().to_bytes(), + val.expect_type::<&phper::strings::ZStr>().unwrap().to_bytes(), b"foo" ); assert!(val.expect_type::<&phper::arrays::ZArr>().is_err()); From 29602a316bf3333910a91cf67c2915740a5b2be0 Mon Sep 17 00:00:00 2001 From: jmjoy Date: Thu, 5 Mar 2026 11:41:04 +0800 Subject: [PATCH 2/4] style: Format code for better readability in integration_values_as function --- tests/integration/src/values.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration/src/values.rs b/tests/integration/src/values.rs index a663c47..105bcc2 100644 --- a/tests/integration/src/values.rs +++ b/tests/integration/src/values.rs @@ -225,7 +225,9 @@ fn integration_values_as(_: &mut [ZVal]) -> Result<(), Infallible> { { let val = ZVal::from("foo"); assert_eq!( - val.expect_type::<&phper::strings::ZStr>().unwrap().to_bytes(), + val.expect_type::<&phper::strings::ZStr>() + .unwrap() + .to_bytes(), b"foo" ); assert!(val.expect_type::<&phper::arrays::ZArr>().is_err()); From ab621e795671d157fb71d27ed012149968db4008 Mon Sep 17 00:00:00 2001 From: jmjoy Date: Thu, 5 Mar 2026 12:42:15 +0800 Subject: [PATCH 3/4] feat: Implement FromZVal and FromZValMut traits for references to ZVal --- phper/src/values.rs | 18 ++++++++++++++++++ tests/integration/src/values.rs | 15 +++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/phper/src/values.rs b/phper/src/values.rs index 250ab5e..2861c91 100644 --- a/phper/src/values.rs +++ b/phper/src/values.rs @@ -846,6 +846,24 @@ impl<'a> FromZVal<'a> for bool { } } +impl<'a> FromZVal<'a> for &'a ZVal { + fn expect(val: &'a ZVal) -> crate::Result { + Ok(val) + } +} + +impl<'a> FromZValMut<'a> for &'a ZVal { + fn expect(val: &'a mut ZVal) -> crate::Result { + Ok(val) + } +} + +impl<'a> FromZValMut<'a> for &'a mut ZVal { + fn expect(val: &'a mut ZVal) -> crate::Result { + Ok(val) + } +} + impl<'a> FromZVal<'a> for i64 { fn expect(val: &'a ZVal) -> crate::Result { val.expect_long() diff --git a/tests/integration/src/values.rs b/tests/integration/src/values.rs index 105bcc2..28944e8 100644 --- a/tests/integration/src/values.rs +++ b/tests/integration/src/values.rs @@ -202,6 +202,21 @@ fn integration_values_as(_: &mut [ZVal]) -> Result<(), Infallible> { assert!(val.expect_type::().is_err()); } + { + let mut val = ZVal::from(100i64); + let borrowed = val.expect_type::<&ZVal>().unwrap(); + assert_eq!(borrowed.expect_long().unwrap(), 100); + let borrowed_from_mut = val.expect_mut_type::<&ZVal>().unwrap(); + assert_eq!(borrowed_from_mut.expect_long().unwrap(), 100); + + { + let borrowed_mut = val.expect_mut_type::<&mut ZVal>().unwrap(); + *borrowed_mut.expect_mut_long().unwrap() += 1; + } + + assert_eq!(val.expect_long().unwrap(), 101); + } + { let mut val = ZVal::from(100i64); assert_eq!(val.expect_type::().ok(), Some(100)); From 794a01b75274ef8e282af15aad049baa94b1db9e Mon Sep 17 00:00:00 2001 From: jmjoy Date: Thu, 5 Mar 2026 13:46:56 +0800 Subject: [PATCH 4/4] fix: Update integration_values_as to use Result for expect_mut_type --- tests/integration/src/values.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/src/values.rs b/tests/integration/src/values.rs index 28944e8..c4699a6 100644 --- a/tests/integration/src/values.rs +++ b/tests/integration/src/values.rs @@ -220,7 +220,7 @@ fn integration_values_as(_: &mut [ZVal]) -> Result<(), Infallible> { { let mut val = ZVal::from(100i64); assert_eq!(val.expect_type::().ok(), Some(100)); - if let Some(l) = val.expect_mut_type::<&mut i64>().ok() { + if let Ok(l) = val.expect_mut_type::<&mut i64>() { *l += 100; } assert_eq!(val.expect_type::().unwrap(), 200); @@ -230,7 +230,7 @@ fn integration_values_as(_: &mut [ZVal]) -> Result<(), Infallible> { { let mut val = ZVal::from(100f64); assert_eq!(val.expect_type::().ok(), Some(100.)); - if let Some(d) = val.expect_mut_type::<&mut f64>().ok() { + if let Ok(d) = val.expect_mut_type::<&mut f64>() { *d += 100.; } assert_eq!(val.expect_type::().unwrap(), 200.);