more casting

This commit is contained in:
Robin Appelman 2019-04-04 19:08:01 +02:00
commit 4a597c8330
8 changed files with 175 additions and 85 deletions

View file

@ -12,6 +12,10 @@ edition = "2018"
ivory-macro = { version = "0.1", path = "macro" } ivory-macro = { version = "0.1", path = "macro" }
ivory-sys = { version = "7.3", path = "sys" } ivory-sys = { version = "7.3", path = "sys" }
[dev-dependencies]
maplit = "1.0"
pretty_assertions = "0.6"
[lib] [lib]
name = "ivory" name = "ivory"

3
ivory/macro/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
target/
**/*.rs.bk
Cargo.lock

51
ivory/src/error.rs Normal file
View file

@ -0,0 +1,51 @@
use crate::zend::ZValType;
use std::error::Error;
use std::fmt;
use std::fmt::Display;
#[derive(Debug)]
pub struct CastError {
pub actual: ZValType,
}
#[derive(Debug)]
pub enum ArgError {
CastError(CastError),
NotEnoughArguments,
}
impl From<CastError> for ArgError {
fn from(from: CastError) -> Self {
ArgError::CastError(from)
}
}
impl Display for CastError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Incorrect variable type, got {}", self.actual)
}
}
impl Display for ArgError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ArgError::CastError(err) => err.fmt(f),
ArgError::NotEnoughArguments => write!(f, "Not enough arugments"),
}
}
}
impl Error for CastError {
fn cause(&self) -> Option<&Error> {
None
}
}
impl Error for ArgError {
fn cause(&self) -> Option<&Error> {
match self {
ArgError::CastError(err) => Some(err),
_ => None,
}
}
}

View file

@ -1,8 +1,10 @@
#[macro_use] #[macro_use]
pub mod macros; pub mod macros;
pub mod error;
pub mod externs; pub mod externs;
pub mod info; pub mod info;
pub mod zend; pub mod zend;
pub use crate::zend::{ArgError, ArrayKey, CastError, PhpVal}; pub use crate::error::{ArgError, CastError};
pub use crate::zend::{ArrayKey, PhpVal};
pub use ivory_macro::{ivory_export, ivory_module}; pub use ivory_macro::{ivory_export, ivory_module};

View file

@ -1,6 +1,6 @@
pub use self::function::*; pub use self::function::*;
pub use self::module::*; pub use self::module::*;
pub use self::zval::{ArgError, ArrayKey, CastError, ExecuteData, PhpVal, ZVal}; pub use self::zval::{ArrayKey, ExecuteData, PhpVal, ZVal, ZValType};
mod function; mod function;
mod module; mod module;

View file

@ -1,7 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error;
use std::fmt; use std::fmt;
use std::fmt::Display;
use std::intrinsics::transmute; use std::intrinsics::transmute;
use std::mem::size_of; use std::mem::size_of;
use std::os::raw::c_char; use std::os::raw::c_char;
@ -9,6 +7,10 @@ use std::str;
use ivory_sys::{zend_execute_data, zend_string, zval}; use ivory_sys::{zend_execute_data, zend_string, zval};
use crate::CastError;
use std::fmt::Display;
use std::hash::Hash;
#[repr(transparent)] #[repr(transparent)]
pub struct ExecuteData(zend_execute_data); pub struct ExecuteData(zend_execute_data);
@ -121,7 +123,7 @@ impl ZVal {
} }
} }
#[derive(Debug)] #[derive(Debug, PartialEq)]
#[repr(u8)] #[repr(u8)]
pub enum ZValType { pub enum ZValType {
Undef = 0, Undef = 0,
@ -164,31 +166,30 @@ impl From<u8> for ZValType {
} }
} }
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub enum ArrayKey { pub enum ArrayKey {
String(String), String(String),
Int(u64), Int(u64),
} }
impl From<String> for ArrayKey { macro_rules! impl_from_array_key {
fn from(input: String) -> Self { ($type:ty, $variant:ident, $type2:ty) => {
ArrayKey::String(input) impl From<$type> for ArrayKey {
} fn from(input: $type) -> Self {
ArrayKey::$variant(input as $type2)
}
}
};
} }
impl From<u64> for ArrayKey { impl_from_array_key!(String, String, String);
fn from(input: u64) -> Self { impl_from_array_key!(u64, Int, u64);
ArrayKey::Int(input) impl_from_array_key!(u32, Int, u64);
} impl_from_array_key!(u16, Int, u64);
} impl_from_array_key!(u8, Int, u64);
impl_from_array_key!(usize, Int, u64);
impl From<usize> for ArrayKey { #[derive(Debug, PartialEq)]
fn from(input: usize) -> Self {
ArrayKey::Int(input as u64)
}
}
#[derive(Debug)]
pub enum PhpVal { pub enum PhpVal {
Undef, Undef,
Null, Null,
@ -259,6 +260,12 @@ macro_rules! impl_from_phpval {
} }
} }
} }
impl From<$type> for PhpVal {
fn from(input: $type) -> Self {
PhpVal::$variant(input)
}
}
}; };
} }
@ -267,24 +274,6 @@ impl_from_phpval!(f64, Double);
impl_from_phpval!(bool, Bool); impl_from_phpval!(bool, Bool);
impl_from_phpval!(String, String); impl_from_phpval!(String, String);
impl From<i64> for PhpVal {
fn from(input: i64) -> Self {
PhpVal::Long(input)
}
}
impl From<String> for PhpVal {
fn from(input: String) -> Self {
PhpVal::String(input)
}
}
impl From<bool> for PhpVal {
fn from(input: bool) -> Self {
PhpVal::Bool(input)
}
}
impl<T: Into<PhpVal>> From<Option<T>> for PhpVal { impl<T: Into<PhpVal>> From<Option<T>> for PhpVal {
fn from(input: Option<T>) -> Self { fn from(input: Option<T>) -> Self {
match input { match input {
@ -317,49 +306,13 @@ impl<K: Into<ArrayKey>, T: Into<PhpVal>> From<Vec<(K, T)>> for PhpVal {
} }
} }
#[derive(Debug)] impl<K: Into<ArrayKey> + Hash + Eq, T: Into<PhpVal>> From<HashMap<K, T>> for PhpVal {
pub struct CastError { fn from(input: HashMap<K, T>) -> Self {
actual: ZValType, PhpVal::Array(
} input
.into_iter()
#[derive(Debug)] .map(|(key, value)| (key.into(), value.into()))
pub enum ArgError { .collect(),
CastError(CastError), )
NotEnoughArguments,
}
impl From<CastError> for ArgError {
fn from(from: CastError) -> Self {
ArgError::CastError(from)
}
}
impl Display for CastError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Incorrect variable type, got {}", self.actual)
}
}
impl Display for ArgError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ArgError::CastError(err) => err.fmt(f),
ArgError::NotEnoughArguments => write!(f, "Not enough arugments"),
}
}
}
impl Error for CastError {
fn cause(&self) -> Option<&Error> {
None
}
}
impl Error for ArgError {
fn cause(&self) -> Option<&Error> {
match self {
ArgError::CastError(err) => Some(err),
_ => None,
}
} }
} }

68
ivory/tests/tests.rs Normal file
View file

@ -0,0 +1,68 @@
use maplit::hashmap;
use pretty_assertions::assert_eq;
use ivory::{ArrayKey, PhpVal};
#[test]
fn cast_into_php_val() {
assert_eq!(PhpVal::Long(1), 1.into());
assert_eq!(PhpVal::Double(1.1), (1.1).into());
assert_eq!(PhpVal::String("foo".to_string()), "foo".to_string().into());
assert_eq!(PhpVal::Bool(true), true.into());
assert_eq!(PhpVal::Bool(false), false.into());
assert_eq!(
PhpVal::Array(vec![
(ArrayKey::Int(0), PhpVal::Long(1)),
(ArrayKey::Int(1), PhpVal::Long(2)),
(ArrayKey::Int(2), PhpVal::Long(3))
]),
vec![1, 2, 3].into()
);
assert_eq!(
PhpVal::Array(vec![
(ArrayKey::Int(0), PhpVal::Long(1)),
(ArrayKey::Int(1), PhpVal::Double(2.1)),
(ArrayKey::Int(2), PhpVal::String("3".to_string()))
]),
vec![
PhpVal::Long(1),
PhpVal::Double(2.1),
PhpVal::String("3".to_string())
]
.into()
);
assert_eq!(
PhpVal::Array(vec![
(ArrayKey::Int(0), PhpVal::Long(1)),
(ArrayKey::Int(3), PhpVal::Long(2)),
(ArrayKey::Int(6), PhpVal::Long(3))
]),
vec![(0u8, 1), (3, 2), (6, 3)].into()
);
assert_eq!(
PhpVal::Array(vec![
(ArrayKey::Int(0), PhpVal::Long(1)),
(ArrayKey::Int(3), PhpVal::Long(2)),
(ArrayKey::String("foo".to_string()), PhpVal::Long(3))
]),
vec![
(ArrayKey::Int(0), 1),
(ArrayKey::Int(3), 2),
(ArrayKey::String("foo".to_string()), 3)
]
.into()
);
assert_eq!(
PhpVal::Array(vec![
(ArrayKey::Int(0), PhpVal::Long(1)),
(ArrayKey::Int(3), PhpVal::Long(2)),
(ArrayKey::Int(6), PhpVal::Long(3))
]),
hashmap! {
0u8 => 1,
3 => 2,
6 => 3
}
.into()
);
}

View file

@ -1 +1,10 @@
# Tests # Ivory integration tests
A basic php module to test the transition between php and rust
# Usage
Due to the particularities with loading dynamic libraries in rust tests, the tests have to be rebuild *before* running the tests after making changes.
- `cargo build`
- `cargo test`