refptr.rs (7903B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! A rust helper to ease the use of Gecko's refcounted types. 6 7 use crate::gecko_bindings::{bindings, structs}; 8 use crate::Atom; 9 use servo_arc::Arc; 10 use std::fmt::Write; 11 use std::marker::PhantomData; 12 use std::ops::Deref; 13 use std::{fmt, mem, ptr}; 14 15 /// Trait for all objects that have Addref() and Release 16 /// methods and can be placed inside RefPtr<T> 17 pub unsafe trait RefCounted { 18 /// Bump the reference count. 19 fn addref(&self); 20 /// Decrease the reference count. 21 unsafe fn release(&self); 22 } 23 24 /// Trait for types which can be shared across threads in RefPtr. 25 pub unsafe trait ThreadSafeRefCounted: RefCounted {} 26 27 /// A custom RefPtr implementation to take into account Drop semantics and 28 /// a bit less-painful memory management. 29 pub struct RefPtr<T: RefCounted> { 30 ptr: *mut T, 31 _marker: PhantomData<T>, 32 } 33 34 impl<T: RefCounted> fmt::Debug for RefPtr<T> { 35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 36 f.write_str("RefPtr { ")?; 37 self.ptr.fmt(f)?; 38 f.write_char('}') 39 } 40 } 41 42 impl<T: RefCounted> RefPtr<T> { 43 /// Create a new RefPtr from an already addrefed pointer obtained from FFI. 44 /// 45 /// The pointer must be valid, non-null and have been addrefed. 46 pub unsafe fn from_addrefed(ptr: *mut T) -> Self { 47 debug_assert!(!ptr.is_null()); 48 RefPtr { 49 ptr, 50 _marker: PhantomData, 51 } 52 } 53 54 /// Returns whether the current pointer is null. 55 pub fn is_null(&self) -> bool { 56 self.ptr.is_null() 57 } 58 59 /// Returns a null pointer. 60 pub fn null() -> Self { 61 Self { 62 ptr: ptr::null_mut(), 63 _marker: PhantomData, 64 } 65 } 66 67 /// Create a new RefPtr from a pointer obtained from FFI. 68 /// 69 /// This method calls addref() internally 70 pub unsafe fn new(ptr: *mut T) -> Self { 71 let ret = RefPtr { 72 ptr, 73 _marker: PhantomData, 74 }; 75 ret.addref(); 76 ret 77 } 78 79 /// Produces an FFI-compatible RefPtr that can be stored in style structs. 80 /// 81 /// structs::RefPtr does not have a destructor, so this may leak 82 pub fn forget(self) -> structs::RefPtr<T> { 83 let ret = structs::RefPtr { 84 mRawPtr: self.ptr, 85 _phantom_0: PhantomData, 86 }; 87 mem::forget(self); 88 ret 89 } 90 91 /// Returns the raw inner pointer to be fed back into FFI. 92 pub fn get(&self) -> *mut T { 93 self.ptr 94 } 95 96 /// Addref the inner data, obviously leaky on its own. 97 pub fn addref(&self) { 98 if !self.ptr.is_null() { 99 unsafe { 100 (*self.ptr).addref(); 101 } 102 } 103 } 104 105 /// Release the inner data. 106 /// 107 /// Call only when the data actually needs releasing. 108 pub unsafe fn release(&self) { 109 if !self.ptr.is_null() { 110 (*self.ptr).release(); 111 } 112 } 113 } 114 115 impl<T: RefCounted> Deref for RefPtr<T> { 116 type Target = T; 117 fn deref(&self) -> &T { 118 debug_assert!(!self.ptr.is_null()); 119 unsafe { &*self.ptr } 120 } 121 } 122 123 impl<T: RefCounted> structs::RefPtr<T> { 124 /// Produces a Rust-side RefPtr from an FFI RefPtr, bumping the refcount. 125 /// 126 /// Must be called on a valid, non-null structs::RefPtr<T>. 127 pub unsafe fn to_safe(&self) -> RefPtr<T> { 128 let r = RefPtr { 129 ptr: self.mRawPtr, 130 _marker: PhantomData, 131 }; 132 r.addref(); 133 r 134 } 135 /// Produces a Rust-side RefPtr, consuming the existing one (and not bumping 136 /// the refcount). 137 pub unsafe fn into_safe(self) -> RefPtr<T> { 138 debug_assert!(!self.mRawPtr.is_null()); 139 RefPtr { 140 ptr: self.mRawPtr, 141 _marker: PhantomData, 142 } 143 } 144 145 /// Replace a structs::RefPtr<T> with a different one, appropriately 146 /// addref/releasing. 147 /// 148 /// Both `self` and `other` must be valid, but can be null. 149 /// 150 /// Safe when called on an aliased pointer because the refcount in that case 151 /// needs to be at least two. 152 pub unsafe fn set(&mut self, other: &Self) { 153 self.clear(); 154 if !other.mRawPtr.is_null() { 155 *self = other.to_safe().forget(); 156 } 157 } 158 159 /// Clear an instance of the structs::RefPtr<T>, by releasing 160 /// it and setting its contents to null. 161 /// 162 /// `self` must be valid, but can be null. 163 pub unsafe fn clear(&mut self) { 164 if !self.mRawPtr.is_null() { 165 (*self.mRawPtr).release(); 166 self.mRawPtr = ptr::null_mut(); 167 } 168 } 169 170 /// Replace a `structs::RefPtr<T>` with a `RefPtr<T>`, 171 /// consuming the `RefPtr<T>`, and releasing the old 172 /// value in `self` if necessary. 173 /// 174 /// `self` must be valid, possibly null. 175 pub fn set_move(&mut self, other: RefPtr<T>) { 176 if !self.mRawPtr.is_null() { 177 unsafe { 178 (*self.mRawPtr).release(); 179 } 180 } 181 *self = other.forget(); 182 } 183 } 184 185 impl<T> structs::RefPtr<T> { 186 /// Returns a new, null refptr. 187 pub fn null() -> Self { 188 Self { 189 mRawPtr: ptr::null_mut(), 190 _phantom_0: PhantomData, 191 } 192 } 193 194 /// Create a new RefPtr from an arc. 195 pub fn from_arc(s: Arc<T>) -> Self { 196 Self { 197 mRawPtr: Arc::into_raw(s) as *mut _, 198 _phantom_0: PhantomData, 199 } 200 } 201 202 /// Sets the contents to an Arc<T>. 203 pub fn set_arc(&mut self, other: Arc<T>) { 204 unsafe { 205 if !self.mRawPtr.is_null() { 206 let _ = Arc::from_raw(self.mRawPtr); 207 } 208 self.mRawPtr = Arc::into_raw(other) as *mut _; 209 } 210 } 211 } 212 213 impl<T: RefCounted> Drop for RefPtr<T> { 214 fn drop(&mut self) { 215 unsafe { self.release() } 216 } 217 } 218 219 impl<T: RefCounted> Clone for RefPtr<T> { 220 fn clone(&self) -> Self { 221 self.addref(); 222 RefPtr { 223 ptr: self.ptr, 224 _marker: PhantomData, 225 } 226 } 227 } 228 229 impl<T: RefCounted> PartialEq for RefPtr<T> { 230 fn eq(&self, other: &Self) -> bool { 231 self.ptr == other.ptr 232 } 233 } 234 235 unsafe impl<T: ThreadSafeRefCounted> Send for RefPtr<T> {} 236 unsafe impl<T: ThreadSafeRefCounted> Sync for RefPtr<T> {} 237 238 macro_rules! impl_refcount { 239 ($t:ty, $addref:path, $release:path) => { 240 unsafe impl RefCounted for $t { 241 #[inline] 242 fn addref(&self) { 243 unsafe { $addref(self as *const _ as *mut _) } 244 } 245 246 #[inline] 247 unsafe fn release(&self) { 248 $release(self as *const _ as *mut _) 249 } 250 } 251 }; 252 } 253 254 // Companion of NS_DECL_THREADSAFE_FFI_REFCOUNTING. 255 // 256 // Gets you a free RefCounted impl implemented via FFI. 257 macro_rules! impl_threadsafe_refcount { 258 ($t:ty, $addref:path, $release:path) => { 259 impl_refcount!($t, $addref, $release); 260 unsafe impl ThreadSafeRefCounted for $t {} 261 }; 262 } 263 264 impl_threadsafe_refcount!( 265 structs::mozilla::URLExtraData, 266 bindings::Gecko_AddRefURLExtraDataArbitraryThread, 267 bindings::Gecko_ReleaseURLExtraDataArbitraryThread 268 ); 269 impl_threadsafe_refcount!( 270 structs::nsIURI, 271 bindings::Gecko_AddRefnsIURIArbitraryThread, 272 bindings::Gecko_ReleasensIURIArbitraryThread 273 ); 274 impl_threadsafe_refcount!( 275 structs::SheetLoadDataHolder, 276 bindings::Gecko_AddRefSheetLoadDataHolderArbitraryThread, 277 bindings::Gecko_ReleaseSheetLoadDataHolderArbitraryThread 278 ); 279 280 #[inline] 281 unsafe fn addref_atom(atom: *mut structs::nsAtom) { 282 mem::forget(Atom::from_raw(atom)); 283 } 284 285 #[inline] 286 unsafe fn release_atom(atom: *mut structs::nsAtom) { 287 let _ = Atom::from_addrefed(atom); 288 } 289 impl_threadsafe_refcount!(structs::nsAtom, addref_atom, release_atom);