mirror of
https://github.com/icewind1991/ivory.git
synced 2026-06-03 18:54:07 +02:00
more casting
This commit is contained in:
parent
b8cd60fff5
commit
4a597c8330
8 changed files with 175 additions and 85 deletions
|
|
@ -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
3
ivory/macro/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
target/
|
||||||
|
**/*.rs.bk
|
||||||
|
Cargo.lock
|
||||||
51
ivory/src/error.rs
Normal file
51
ivory/src/error.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
68
ivory/tests/tests.rs
Normal 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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -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`
|
||||||
Loading…
Add table
Add a link
Reference in a new issue