Skip to main content

ext_php_rs/zend/
streams.rs

1use std::ptr::{self, NonNull};
2
3use crate::{
4    error::Error,
5    ffi::{
6        php_register_url_stream_wrapper, php_register_url_stream_wrapper_volatile, php_stream,
7        php_stream_context, php_stream_locate_url_wrapper, php_stream_wrapper,
8        php_stream_wrapper_ops, php_unregister_url_stream_wrapper,
9        php_unregister_url_stream_wrapper_volatile, zend_string,
10    },
11    types::ZendStr,
12};
13
14/// Wrapper for PHP streams
15pub type StreamWrapper = php_stream_wrapper;
16
17/// Stream opener function
18pub type StreamOpener = unsafe extern "C" fn(
19    *mut StreamWrapper,
20    *const std::ffi::c_char,
21    *const std::ffi::c_char,
22    i32,
23    *mut *mut zend_string,
24    *mut php_stream_context,
25    i32,
26    *const std::ffi::c_char,
27    u32,
28    *const std::ffi::c_char,
29    u32,
30) -> *mut Stream;
31
32impl StreamWrapper {
33    /// Get wrapped stream by name
34    #[inline]
35    #[must_use]
36    pub fn get(name: &str) -> Option<&Self> {
37        unsafe {
38            let result = php_stream_locate_url_wrapper(name.as_ptr().cast(), ptr::null_mut(), 0);
39            Some(NonNull::new(result)?.as_ref())
40        }
41    }
42
43    /// Get mutable wrapped stream by name
44    #[inline]
45    #[must_use]
46    #[allow(clippy::mut_from_ref)]
47    pub fn get_mut(name: &str) -> Option<&mut Self> {
48        unsafe {
49            let result = php_stream_locate_url_wrapper(name.as_ptr().cast(), ptr::null_mut(), 0);
50            Some(NonNull::new(result)?.as_mut())
51        }
52    }
53
54    /// Register stream wrapper for name
55    ///
56    /// # Errors
57    ///
58    /// * `Error::StreamWrapperRegistrationFailure` - If the stream wrapper
59    ///   could not be registered
60    ///
61    /// # Panics
62    ///
63    /// * If the name cannot be converted to a C string
64    pub fn register(self, name: &str) -> Result<Self, Error> {
65        // We have to convert it to a static so owned streamwrapper doesn't get dropped.
66        let copy = Box::new(self);
67        let copy = Box::leak(copy);
68        let name = std::ffi::CString::new(name).expect("Could not create C string for name!");
69        let result = unsafe { php_register_url_stream_wrapper(name.as_ptr(), copy) };
70        if result == 0 {
71            Ok(*copy)
72        } else {
73            Err(Error::StreamWrapperRegistrationFailure)
74        }
75    }
76
77    /// Register volatile stream wrapper for name
78    ///
79    /// # Errors
80    ///
81    /// * `Error::StreamWrapperRegistrationFailure` - If the stream wrapper
82    ///   could not be registered
83    pub fn register_volatile(self, name: &str) -> Result<Self, Error> {
84        // We have to convert it to a static so owned streamwrapper doesn't get dropped.
85        let copy = Box::new(self);
86        let copy = Box::leak(copy);
87        let name = ZendStr::new(name, false);
88        let result =
89            unsafe { php_register_url_stream_wrapper_volatile((*name).as_ptr().cast_mut(), copy) };
90        if result == 0 {
91            Ok(*copy)
92        } else {
93            Err(Error::StreamWrapperRegistrationFailure)
94        }
95    }
96
97    /// Unregister stream wrapper by name
98    ///
99    /// # Errors
100    ///
101    /// * `Error::StreamWrapperUnregistrationFailure` - If the stream wrapper
102    ///   could not be unregistered
103    ///
104    /// # Panics
105    ///
106    /// * If the name cannot be converted to a C string
107    pub fn unregister(name: &str) -> Result<(), Error> {
108        let name = std::ffi::CString::new(name).expect("Could not create C string for name!");
109        match unsafe { php_unregister_url_stream_wrapper(name.as_ptr()) } {
110            0 => Ok(()),
111            _ => Err(Error::StreamWrapperUnregistrationFailure),
112        }
113    }
114
115    /// Unregister volatile stream wrapper by name
116    ///
117    /// # Errors
118    ///
119    /// * `Error::StreamWrapperUnregistrationFailure` - If the stream wrapper
120    ///   could not be unregistered
121    pub fn unregister_volatile(name: &str) -> Result<(), Error> {
122        let name = ZendStr::new(name, false);
123        match unsafe { php_unregister_url_stream_wrapper_volatile((*name).as_ptr().cast_mut()) } {
124            0 => Ok(()),
125            _ => Err(Error::StreamWrapperUnregistrationFailure),
126        }
127    }
128
129    /// Get the operations the stream wrapper can perform
130    #[must_use]
131    pub fn wops(&self) -> &php_stream_wrapper_ops {
132        unsafe { &*self.wops }
133    }
134
135    /// Get the mutable operations the stream can perform
136    pub fn wops_mut(&mut self) -> &mut php_stream_wrapper_ops {
137        unsafe { &mut *(self.wops.cast_mut()) }
138    }
139}
140
141/// A PHP stream
142pub type Stream = php_stream;
143
144/// Operations that can be performed with a stream wrapper
145pub type StreamWrapperOps = php_stream_wrapper_ops;
146
147impl StreamWrapperOps {}