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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! Types relating to registering constants in PHP.

use std::ffi::CString;

use super::flags::GlobalConstantFlags;
use crate::bindings::{
    zend_register_bool_constant, zend_register_double_constant, zend_register_long_constant,
    zend_register_string_constant,
};
use crate::errors::Result;

pub trait IntoConst: Sized {
    /// Registers a global module constant in PHP, with the value as the content of self.
    /// This function _must_ be called in the module startup function, which is called after
    /// the module is initialized. The second parameter of the startup function will be the
    /// module number. By default, the case-insensitive and persistent flags are set when
    /// registering the constant.
    ///
    /// Returns a result containing nothing if the constant was successfully registered.
    ///
    /// # Parameters
    ///
    /// * `name` - The name of the constant.
    /// * `module_number` - The module number that we are registering the constant under.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ext_php_rs::php::{constants::IntoConst, flags::ZendResult};
    ///
    /// pub extern "C" fn startup_function(_type: i32, module_number: i32) -> i32 {
    ///     5.register_constant("MY_CONST_NAME", module_number); // MY_CONST_NAME == 5
    ///     "Hello, world!".register_constant("STRING_CONSTANT", module_number); // STRING_CONSTANT == "Hello, world!"
    ///     0
    /// }
    /// ```
    fn register_constant(&self, name: &str, module_number: i32) -> Result<()> {
        self.register_constant_flags(
            name,
            module_number,
            GlobalConstantFlags::CaseSensitive | GlobalConstantFlags::Persistent,
        )
    }

    /// Registers a global module constant in PHP, with the value as the content of self.
    /// This function _must_ be called in the module startup function, which is called after
    /// the module is initialized. The second parameter of the startup function will be the
    /// module number. This function allows you to pass any extra flags in if you require.
    /// Note that the case-sensitive and persistent flags *are not* set when you use this function,
    /// you must set these yourself.
    ///
    /// Returns a result containing nothing if the constant was successfully registered.
    ///
    /// # Parameters
    ///
    /// * `name` - The name of the constant.
    /// * `module_number` - The module number that we are registering the constant under.
    /// * `flags` - Flags to register the constant with.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ext_php_rs::php::{constants::IntoConst, flags::{GlobalConstantFlags, ZendResult}};
    ///
    /// pub extern "C" fn startup_function(_type: i32, module_number: i32) -> i32 {
    ///     42.register_constant_flags("MY_CONST_NAME", module_number, GlobalConstantFlags::Persistent | GlobalConstantFlags::Deprecated);
    ///     0
    /// }
    /// ```
    fn register_constant_flags(
        &self,
        name: &str,
        module_number: i32,
        flags: GlobalConstantFlags,
    ) -> Result<()>;
}

impl IntoConst for String {
    fn register_constant_flags(
        &self,
        name: &str,
        module_number: i32,
        flags: GlobalConstantFlags,
    ) -> Result<()> {
        self.as_str()
            .register_constant_flags(name, module_number, flags)
    }
}

impl IntoConst for &str {
    fn register_constant_flags(
        &self,
        name: &str,
        module_number: i32,
        flags: GlobalConstantFlags,
    ) -> Result<()> {
        unsafe {
            zend_register_string_constant(
                CString::new(name)?.as_ptr(),
                name.len() as _,
                CString::new(*self)?.as_ptr(),
                flags.bits() as _,
                module_number,
            )
        };
        Ok(())
    }
}

impl IntoConst for bool {
    fn register_constant_flags(
        &self,
        name: &str,
        module_number: i32,
        flags: GlobalConstantFlags,
    ) -> Result<()> {
        unsafe {
            zend_register_bool_constant(
                CString::new(name)?.as_ptr(),
                name.len() as _,
                *self,
                flags.bits() as _,
                module_number,
            )
        };
        Ok(())
    }
}

/// Implements the `IntoConst` trait for a given number type using a given function.
macro_rules! into_const_num {
    ($type: ty, $fn: expr) => {
        impl IntoConst for $type {
            fn register_constant_flags(
                &self,
                name: &str,
                module_number: i32,
                flags: GlobalConstantFlags,
            ) -> Result<()> {
                Ok(unsafe {
                    $fn(
                        CString::new(name)?.as_ptr(),
                        name.len() as _,
                        *self as _,
                        flags.bits() as _,
                        module_number,
                    )
                })
            }
        }
    };
}

into_const_num!(i8, zend_register_long_constant);
into_const_num!(i16, zend_register_long_constant);
into_const_num!(i32, zend_register_long_constant);
into_const_num!(i64, zend_register_long_constant);
into_const_num!(f32, zend_register_double_constant);
into_const_num!(f64, zend_register_double_constant);