ext_php_rs/error.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
//! Error and result types returned from the library functions.
use std::{
error::Error as ErrorTrait,
ffi::{CString, NulError},
fmt::Display,
};
use crate::{
boxed::ZBox,
exception::PhpException,
ffi::php_error_docref,
flags::{ClassFlags, DataType, ErrorType, ZvalTypeFlags},
types::ZendObject,
};
/// The main result type which is passed by the library.
pub type Result<T, E = Error> = std::result::Result<T, E>;
/// The main error type which is passed by the library inside the custom
/// [`Result`] type.
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
/// An incorrect number of arguments was given to a PHP function.
///
/// The enum carries two integers - the first representing the minimum
/// number of arguments expected, and the second representing the number of
/// arguments that were received.
IncorrectArguments(usize, usize),
/// There was an error converting a Zval into a primitive type.
///
/// The enum carries the data type of the Zval.
ZvalConversion(DataType),
/// The type of the Zval is unknown.
///
/// The enum carries the integer representation of the type of Zval.
UnknownDatatype(u32),
/// Attempted to convert a [`ZvalTypeFlags`] struct to a [`DataType`].
/// The flags did not contain a datatype.
///
/// The enum carries the flags that were attempted to be converted to a
/// [`DataType`].
InvalidTypeToDatatype(ZvalTypeFlags),
/// The function called was called in an invalid scope (calling
/// class-related functions inside of a non-class bound function).
InvalidScope,
/// The pointer inside a given type was invalid, either null or pointing to
/// garbage.
InvalidPointer,
/// The given property name does not exist.
InvalidProperty,
/// The string could not be converted into a C-string due to the presence of
/// a NUL character.
InvalidCString,
/// The string could not be converted into a valid Utf8 string
InvalidUtf8,
/// Could not call the given function.
Callable,
/// An object was expected.
Object,
/// An invalid exception type was thrown.
InvalidException(ClassFlags),
/// Converting integer arguments resulted in an overflow.
IntegerOverflow,
/// An exception was thrown in a function.
Exception(ZBox<ZendObject>),
/// A failure occurred while registering the stream wrapper
StreamWrapperRegistrationFailure,
/// A failure occurred while unregistering the stream wrapper
StreamWrapperUnregistrationFailure,
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::IncorrectArguments(n, expected) => write!(
f,
"Expected at least {expected} arguments, got {n} arguments."
),
Error::ZvalConversion(ty) => write!(
f,
"Could not convert Zval from type {ty} into primitive type."
),
Error::UnknownDatatype(dt) => write!(f, "Unknown datatype {dt}."),
Error::InvalidTypeToDatatype(dt) => {
write!(f, "Type flags did not contain a datatype: {dt:?}")
}
Error::InvalidScope => write!(f, "Invalid scope."),
Error::InvalidPointer => write!(f, "Invalid pointer."),
Error::InvalidProperty => write!(f, "Property does not exist on object."),
Error::InvalidCString => write!(
f,
"String given contains NUL-bytes which cannot be present in a C string."
),
Error::InvalidUtf8 => write!(f, "Invalid Utf8 byte sequence."),
Error::Callable => write!(f, "Could not call given function."),
Error::Object => write!(f, "An object was expected."),
Error::InvalidException(flags) => {
write!(f, "Invalid exception type was thrown: {flags:?}")
}
Error::IntegerOverflow => {
write!(f, "Converting integer arguments resulted in an overflow.")
}
Error::Exception(e) => write!(f, "Exception was thrown: {e:?}"),
Error::StreamWrapperRegistrationFailure => {
write!(f, "A failure occurred while registering the stream wrapper")
}
Error::StreamWrapperUnregistrationFailure => {
write!(
f,
"A failure occurred while unregistering the stream wrapper"
)
}
}
}
}
impl ErrorTrait for Error {}
impl From<NulError> for Error {
fn from(_: NulError) -> Self {
Self::InvalidCString
}
}
impl From<Error> for PhpException {
fn from(err: Error) -> Self {
Self::default(err.to_string())
}
}
/// Trigger an error that is reported in PHP the same way `trigger_error()` is.
///
/// See specific error type descriptions at <https://www.php.net/manual/en/errorfunc.constants.php>.
pub fn php_error(type_: ErrorType, message: &str) {
let c_string = match CString::new(message) {
Ok(string) => string,
Err(_) => {
return;
}
};
unsafe { php_error_docref(std::ptr::null(), type_.bits() as _, c_string.as_ptr()) }
}