• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

davidcole1340 / ext-php-rs / 14502041373

16 Apr 2025 08:30PM UTC coverage: 14.129% (+0.7%) from 13.479%
14502041373

push

github

web-flow
style(clippy): apply pedantic rules

Refs: #418

41 of 345 new or added lines in 46 files covered. (11.88%)

48 existing lines in 25 files now uncovered.

553 of 3914 relevant lines covered (14.13%)

1.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

30.77
/src/class.rs
1
//! Types and traits used for registering classes with PHP.
2

3
use std::{
4
    collections::HashMap,
5
    marker::PhantomData,
6
    sync::atomic::{AtomicPtr, Ordering},
7
};
8

9
use once_cell::sync::OnceCell;
10

11
use crate::{
12
    builders::{ClassBuilder, FunctionBuilder},
13
    convert::IntoZvalDyn,
14
    describe::DocComments,
15
    exception::PhpException,
16
    flags::{ClassFlags, MethodFlags},
17
    internal::property::PropertyInfo,
18
    zend::{ClassEntry, ExecuteData, ZendObjectHandlers},
19
};
20

21
/// Implemented on Rust types which are exported to PHP. Allows users to get and
22
/// set PHP properties on the object.
23
pub trait RegisteredClass: Sized + 'static {
24
    /// PHP class name of the registered class.
25
    const CLASS_NAME: &'static str;
26

27
    /// Function to be called when building the class. Allows user to modify the
28
    /// class at runtime (add runtime constants etc).
29
    const BUILDER_MODIFIER: Option<fn(ClassBuilder) -> ClassBuilder>;
30

31
    /// Parent class entry. Optional.
32
    const EXTENDS: Option<fn() -> &'static ClassEntry>;
33

34
    /// Interfaces implemented by the class.
35
    const IMPLEMENTS: &'static [fn() -> &'static ClassEntry];
36

37
    /// PHP flags applied to the class.
38
    const FLAGS: ClassFlags = ClassFlags::empty();
39

40
    /// Doc comments for the class.
41
    const DOC_COMMENTS: DocComments = &[];
42

43
    /// Returns a reference to the class metadata, which stores the class entry
44
    /// and handlers.
45
    ///
46
    /// This must be statically allocated, and is usually done through the
47
    /// [`macro@php_class`] macro.
48
    ///
49
    /// [`macro@php_class`]: crate::php_class
50
    fn get_metadata() -> &'static ClassMetadata<Self>;
51

52
    /// Returns a hash table containing the properties of the class.
53
    ///
54
    /// The key should be the name of the property and the value should be a
55
    /// reference to the property with reference to `self`. The value is a
56
    /// [`PropertyInfo`].
57
    ///
58
    /// Instead of using this method directly, you should access the properties
59
    /// through the [`ClassMetadata::get_properties`] function, which builds the
60
    /// hashmap one and stores it in memory.
61
    fn get_properties<'a>() -> HashMap<&'static str, PropertyInfo<'a, Self>>;
62

63
    /// Returns the method builders required to build the class.
64
    fn method_builders() -> Vec<(FunctionBuilder<'static>, MethodFlags)>;
65

66
    /// Returns the class constructor (if any).
67
    fn constructor() -> Option<ConstructorMeta<Self>>;
68

69
    /// Returns the constants provided by the class.
70
    fn constants() -> &'static [(&'static str, &'static dyn IntoZvalDyn, DocComments)];
71
}
72

73
/// Stores metadata about a classes Rust constructor, including the function
74
/// pointer and the arguments of the function.
75
pub struct ConstructorMeta<T> {
76
    /// Constructor function.
77
    pub constructor: fn(&mut ExecuteData) -> ConstructorResult<T>,
78
    /// Function called to build the constructor function. Usually adds
79
    /// arguments.
80
    pub build_fn: fn(FunctionBuilder) -> FunctionBuilder,
81
}
82

83
/// Result returned from a constructor of a class.
84
pub enum ConstructorResult<T> {
85
    /// Successfully constructed the class, contains the new class object.
86
    Ok(T),
87
    /// An exception occurred while constructing the class.
88
    Exception(PhpException),
89
    /// Invalid arguments were given to the constructor.
90
    ArgError,
91
}
92

93
impl<T, E> From<std::result::Result<T, E>> for ConstructorResult<T>
94
where
95
    E: Into<PhpException>,
96
{
97
    fn from(result: std::result::Result<T, E>) -> Self {
×
98
        match result {
×
99
            Ok(x) => Self::Ok(x),
×
100
            Err(e) => Self::Exception(e.into()),
×
101
        }
102
    }
103
}
104

105
impl<T> From<T> for ConstructorResult<T> {
106
    fn from(result: T) -> Self {
×
107
        Self::Ok(result)
×
108
    }
109
}
110

111
/// Stores the class entry and handlers for a Rust type which has been exported
112
/// to PHP. Usually allocated statically.
113
pub struct ClassMetadata<T> {
114
    handlers: OnceCell<ZendObjectHandlers>,
115
    properties: OnceCell<HashMap<&'static str, PropertyInfo<'static, T>>>,
116
    ce: AtomicPtr<ClassEntry>,
117

118
    // `AtomicPtr` is used here because it is `Send + Sync`.
119
    // fn() -> T could have been used but that is incompatible with const fns at
120
    // the moment.
121
    phantom: PhantomData<AtomicPtr<T>>,
122
}
123

124
impl<T> ClassMetadata<T> {
125
    /// Creates a new class metadata instance.
126
    #[must_use]
UNCOV
127
    pub const fn new() -> Self {
×
128
        Self {
129
            handlers: OnceCell::new(),
×
130
            properties: OnceCell::new(),
×
131
            ce: AtomicPtr::new(std::ptr::null_mut()),
×
132
            phantom: PhantomData,
133
        }
134
    }
135
}
136

137
impl<T> Default for ClassMetadata<T> {
138
    fn default() -> Self {
×
139
        Self::new()
×
140
    }
141
}
142

143
impl<T: RegisteredClass> ClassMetadata<T> {
144
    /// Returns an immutable reference to the object handlers contained inside
145
    /// the class metadata.
146
    pub fn handlers(&self) -> &ZendObjectHandlers {
×
147
        self.handlers.get_or_init(ZendObjectHandlers::new::<T>)
×
148
    }
149

150
    /// Checks if the class entry has been stored, returning a boolean.
151
    pub fn has_ce(&self) -> bool {
1✔
152
        !self.ce.load(Ordering::SeqCst).is_null()
1✔
153
    }
154

155
    /// Retrieves a reference to the stored class entry.
156
    ///
157
    /// # Panics
158
    ///
159
    /// Panics if there is no class entry stored inside the class metadata.
160
    pub fn ce(&self) -> &'static ClassEntry {
×
161
        // SAFETY: There are only two values that can be stored in the atomic ptr: null
162
        // or a static reference to a class entry. On the latter case,
163
        // `as_ref()` will return `None` and the function will panic.
164
        unsafe { self.ce.load(Ordering::SeqCst).as_ref() }
×
165
            .expect("Attempted to retrieve class entry before it has been stored.")
166
    }
167

168
    /// Stores a reference to a class entry inside the class metadata.
169
    ///
170
    /// # Parameters
171
    ///
172
    /// * `ce` - The class entry to store.
173
    ///
174
    /// # Panics
175
    ///
176
    /// Panics if the class entry has already been set in the class metadata.
177
    /// This function should only be called once.
178
    pub fn set_ce(&self, ce: &'static mut ClassEntry) {
1✔
179
        self.ce
1✔
180
            .compare_exchange(
181
                std::ptr::null_mut(),
1✔
182
                ce,
1✔
183
                Ordering::SeqCst,
1✔
184
                Ordering::Relaxed,
1✔
185
            )
186
            .expect("Class entry has already been set");
187
    }
188

189
    /// Retrieves a reference to the hashmap storing the classes property
190
    /// accessors.
191
    ///
192
    /// # Returns
193
    ///
194
    /// Immutable reference to the properties hashmap.
195
    pub fn get_properties(&self) -> &HashMap<&'static str, PropertyInfo<'static, T>> {
×
196
        self.properties.get_or_init(T::get_properties)
×
197
    }
198
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc