@@ -187,13 +187,13 @@ pub trait GetBorrowChecker<T: PyClassImpl> {
187
187
188
188
impl < T : PyClassImpl < PyClassMutability = Self > > GetBorrowChecker < T > for MutableClass {
189
189
fn borrow_checker ( class_object : & T :: Layout ) -> & BorrowChecker {
190
- & class_object. contents ( ) . borrow_checker
190
+ & class_object. contents ( ) . 0 . borrow_checker
191
191
}
192
192
}
193
193
194
194
impl < T : PyClassImpl < PyClassMutability = Self > > GetBorrowChecker < T > for ImmutableClass {
195
195
fn borrow_checker ( class_object : & T :: Layout ) -> & EmptySlot {
196
- & class_object. contents ( ) . borrow_checker
196
+ & class_object. contents ( ) . 0 . borrow_checker
197
197
}
198
198
}
199
199
@@ -226,7 +226,7 @@ pub struct PyVariableClassObjectBase {
226
226
227
227
unsafe impl < T > PyLayout < T > for PyVariableClassObjectBase { }
228
228
229
- impl < T : PyTypeInfo > PyClassObjectLayout < T > for PyVariableClassObjectBase {
229
+ impl < T : PyTypeInfo > PyClassObjectBaseLayout < T > for PyVariableClassObjectBase {
230
230
fn ensure_threadsafe ( & self ) { }
231
231
fn check_threadsafe ( & self ) -> Result < ( ) , PyBorrowError > {
232
232
Ok ( ( ) )
@@ -237,7 +237,7 @@ impl<T: PyTypeInfo> PyClassObjectLayout<T> for PyVariableClassObjectBase {
237
237
}
238
238
239
239
#[ doc( hidden) ]
240
- pub trait PyClassObjectLayout < T > : PyLayout < T > {
240
+ pub trait PyClassObjectBaseLayout < T > : PyLayout < T > {
241
241
fn ensure_threadsafe ( & self ) ;
242
242
fn check_threadsafe ( & self ) -> Result < ( ) , PyBorrowError > ;
243
243
/// Implementation of tp_dealloc.
@@ -247,6 +247,30 @@ pub trait PyClassObjectLayout<T>: PyLayout<T> {
247
247
unsafe fn tp_dealloc ( py : Python < ' _ > , slf : * mut ffi:: PyObject ) ;
248
248
}
249
249
250
+ /// Allow [PyClassObjectLayout] to have public visibility without leaking the structure of [PyClassObjectContents].
251
+ #[ doc( hidden) ]
252
+ #[ repr( transparent) ]
253
+ pub struct WrappedPyClassObjectContents < T : PyClassImpl > ( pub ( crate ) PyClassObjectContents < T > ) ;
254
+
255
+ impl < ' a , T : PyClassImpl > From < & ' a PyClassObjectContents < T > >
256
+ for & ' a WrappedPyClassObjectContents < T >
257
+ {
258
+ fn from ( value : & ' a PyClassObjectContents < T > ) -> & ' a WrappedPyClassObjectContents < T > {
259
+ // Safety: Wrapped struct must use repr(transparent)
260
+ unsafe { std:: mem:: transmute ( value) }
261
+ }
262
+ }
263
+
264
+ impl < ' a , T : PyClassImpl > From < & ' a mut PyClassObjectContents < T > >
265
+ for & ' a mut WrappedPyClassObjectContents < T >
266
+ {
267
+ fn from ( value : & ' a mut PyClassObjectContents < T > ) -> & ' a mut WrappedPyClassObjectContents < T > {
268
+ // Safety: Wrapped struct must use repr(transparent)
269
+ unsafe { std:: mem:: transmute ( value) }
270
+ }
271
+ }
272
+
273
+ /// Functionality required for creating and managing the memory associated with a pyclass annotated struct.
250
274
#[ doc( hidden) ]
251
275
#[ cfg_attr(
252
276
all( diagnostic_namespace) ,
@@ -256,18 +280,18 @@ pub trait PyClassObjectLayout<T>: PyLayout<T> {
256
280
note = "the python version being built against influences which layouts are valid" ,
257
281
)
258
282
) ]
259
- pub trait InternalPyClassObjectLayout < T : PyClassImpl > : PyClassObjectLayout < T > {
283
+ pub trait PyClassObjectLayout < T : PyClassImpl > : PyClassObjectBaseLayout < T > {
260
284
/// Obtain a pointer to the contents of an uninitialized PyObject of this type
261
285
/// Safety: the provided object must have the layout that the implementation is expecting
262
286
unsafe fn contents_uninitialised (
263
287
obj : * mut ffi:: PyObject ,
264
- ) -> * mut MaybeUninit < PyClassObjectContents < T > > ;
288
+ ) -> * mut MaybeUninit < WrappedPyClassObjectContents < T > > ;
265
289
266
290
fn get_ptr ( & self ) -> * mut T ;
267
291
268
- fn contents ( & self ) -> & PyClassObjectContents < T > ;
292
+ fn contents ( & self ) -> & WrappedPyClassObjectContents < T > ;
269
293
270
- fn contents_mut ( & mut self ) -> & mut PyClassObjectContents < T > ;
294
+ fn contents_mut ( & mut self ) -> & mut WrappedPyClassObjectContents < T > ;
271
295
272
296
fn ob_base ( & self ) -> & <T :: BaseType as PyClassBaseType >:: LayoutAsBase ;
273
297
@@ -287,7 +311,7 @@ pub trait InternalPyClassObjectLayout<T: PyClassImpl>: PyClassObjectLayout<T> {
287
311
fn borrow_checker ( & self ) -> & <T :: PyClassMutability as PyClassMutability >:: Checker ;
288
312
}
289
313
290
- impl < T , U > PyClassObjectLayout < T > for PyClassObjectBase < U >
314
+ impl < T , U > PyClassObjectBaseLayout < T > for PyClassObjectBase < U >
291
315
where
292
316
U : PySizedLayout < T > ,
293
317
T : PyTypeInfo ,
@@ -301,6 +325,10 @@ where
301
325
}
302
326
}
303
327
328
+ /// Implementation of tp_dealloc.
329
+ /// # Safety
330
+ /// - obj must be a valid pointer to an instance of the type at `type_ptr` or a subclass.
331
+ /// - obj must not be used after this call (as it will be freed).
304
332
unsafe fn tp_dealloc ( py : Python < ' _ > , obj : * mut ffi:: PyObject , type_ptr : * mut ffi:: PyTypeObject ) {
305
333
// FIXME: there is potentially subtle issues here if the base is overwritten
306
334
// at runtime? To be investigated.
@@ -376,14 +404,14 @@ pub struct PyStaticClassObject<T: PyClassImpl> {
376
404
contents : PyClassObjectContents < T > ,
377
405
}
378
406
379
- impl < T : PyClassImpl > InternalPyClassObjectLayout < T > for PyStaticClassObject < T > {
407
+ impl < T : PyClassImpl > PyClassObjectLayout < T > for PyStaticClassObject < T > {
380
408
unsafe fn contents_uninitialised (
381
409
obj : * mut ffi:: PyObject ,
382
- ) -> * mut MaybeUninit < PyClassObjectContents < T > > {
410
+ ) -> * mut MaybeUninit < WrappedPyClassObjectContents < T > > {
383
411
#[ repr( C ) ]
384
412
struct PartiallyInitializedClassObject < T : PyClassImpl > {
385
413
_ob_base : <T :: BaseType as PyClassBaseType >:: LayoutAsBase ,
386
- contents : MaybeUninit < PyClassObjectContents < T > > ,
414
+ contents : MaybeUninit < WrappedPyClassObjectContents < T > > ,
387
415
}
388
416
let obj: * mut PartiallyInitializedClassObject < T > = obj. cast ( ) ;
389
417
addr_of_mut ! ( ( * obj) . contents)
@@ -397,12 +425,12 @@ impl<T: PyClassImpl> InternalPyClassObjectLayout<T> for PyStaticClassObject<T> {
397
425
& self . ob_base
398
426
}
399
427
400
- fn contents ( & self ) -> & PyClassObjectContents < T > {
401
- & self . contents
428
+ fn contents ( & self ) -> & WrappedPyClassObjectContents < T > {
429
+ ( & self . contents ) . into ( )
402
430
}
403
431
404
- fn contents_mut ( & mut self ) -> & mut PyClassObjectContents < T > {
405
- & mut self . contents
432
+ fn contents_mut ( & mut self ) -> & mut WrappedPyClassObjectContents < T > {
433
+ ( & mut self . contents ) . into ( )
406
434
}
407
435
408
436
/// used to set PyType_Spec::basicsize
@@ -453,9 +481,9 @@ impl<T: PyClassImpl> InternalPyClassObjectLayout<T> for PyStaticClassObject<T> {
453
481
unsafe impl < T : PyClassImpl > PyLayout < T > for PyStaticClassObject < T > { }
454
482
impl < T : PyClass > PySizedLayout < T > for PyStaticClassObject < T > { }
455
483
456
- impl < T : PyClassImpl > PyClassObjectLayout < T > for PyStaticClassObject < T >
484
+ impl < T : PyClassImpl > PyClassObjectBaseLayout < T > for PyStaticClassObject < T >
457
485
where
458
- <T :: BaseType as PyClassBaseType >:: LayoutAsBase : PyClassObjectLayout < T :: BaseType > ,
486
+ <T :: BaseType as PyClassBaseType >:: LayoutAsBase : PyClassObjectBaseLayout < T :: BaseType > ,
459
487
{
460
488
fn ensure_threadsafe ( & self ) {
461
489
self . contents . thread_checker . ensure ( ) ;
@@ -470,7 +498,7 @@ where
470
498
unsafe fn tp_dealloc ( py : Python < ' _ > , slf : * mut ffi:: PyObject ) {
471
499
// Safety: Python only calls tp_dealloc when no references to the object remain.
472
500
let class_object = & mut * ( slf. cast :: < T :: Layout > ( ) ) ;
473
- class_object. contents_mut ( ) . dealloc ( py, slf) ;
501
+ class_object. contents_mut ( ) . 0 . dealloc ( py, slf) ;
474
502
<T :: BaseType as PyClassBaseType >:: LayoutAsBase :: tp_dealloc ( py, slf)
475
503
}
476
504
}
@@ -482,41 +510,41 @@ pub struct PyVariableClassObject<T: PyClassImpl> {
482
510
483
511
impl < T : PyClassImpl > PyVariableClassObject < T > {
484
512
#[ cfg( Py_3_12 ) ]
485
- fn get_contents_of_obj ( obj : * mut ffi:: PyObject ) -> * mut PyClassObjectContents < T > {
513
+ fn get_contents_of_obj ( obj : * mut ffi:: PyObject ) -> * mut WrappedPyClassObjectContents < T > {
486
514
// https://peps.python.org/pep-0697/
487
515
let type_obj = unsafe { ffi:: Py_TYPE ( obj) } ;
488
516
let pointer = unsafe { ffi:: PyObject_GetTypeData ( obj, type_obj) } ;
489
- pointer as * mut PyClassObjectContents < T >
517
+ pointer as * mut WrappedPyClassObjectContents < T >
490
518
}
491
519
492
520
#[ cfg( Py_3_12 ) ]
493
- fn get_contents_ptr ( & self ) -> * mut PyClassObjectContents < T > {
521
+ fn get_contents_ptr ( & self ) -> * mut WrappedPyClassObjectContents < T > {
494
522
Self :: get_contents_of_obj ( self as * const PyVariableClassObject < T > as * mut ffi:: PyObject )
495
523
}
496
524
}
497
525
498
526
#[ cfg( Py_3_12 ) ]
499
- impl < T : PyClassImpl > InternalPyClassObjectLayout < T > for PyVariableClassObject < T > {
527
+ impl < T : PyClassImpl > PyClassObjectLayout < T > for PyVariableClassObject < T > {
500
528
unsafe fn contents_uninitialised (
501
529
obj : * mut ffi:: PyObject ,
502
- ) -> * mut MaybeUninit < PyClassObjectContents < T > > {
503
- Self :: get_contents_of_obj ( obj) as * mut MaybeUninit < PyClassObjectContents < T > >
530
+ ) -> * mut MaybeUninit < WrappedPyClassObjectContents < T > > {
531
+ Self :: get_contents_of_obj ( obj) as * mut MaybeUninit < WrappedPyClassObjectContents < T > >
504
532
}
505
533
506
534
fn get_ptr ( & self ) -> * mut T {
507
- self . contents ( ) . value . get ( )
535
+ self . contents ( ) . 0 . value . get ( )
508
536
}
509
537
510
538
fn ob_base ( & self ) -> & <T :: BaseType as PyClassBaseType >:: LayoutAsBase {
511
539
& self . ob_base
512
540
}
513
541
514
- fn contents ( & self ) -> & PyClassObjectContents < T > {
515
- unsafe { ( self . get_contents_ptr ( ) as * const PyClassObjectContents < T > ) . as_ref ( ) }
542
+ fn contents ( & self ) -> & WrappedPyClassObjectContents < T > {
543
+ unsafe { self . get_contents_ptr ( ) . cast_const ( ) . as_ref ( ) }
516
544
. expect ( "should be able to cast PyClassObjectContents pointer" )
517
545
}
518
546
519
- fn contents_mut ( & mut self ) -> & mut PyClassObjectContents < T > {
547
+ fn contents_mut ( & mut self ) -> & mut WrappedPyClassObjectContents < T > {
520
548
unsafe { self . get_contents_ptr ( ) . as_mut ( ) }
521
549
. expect ( "should be able to cast PyClassObjectContents pointer" )
522
550
}
@@ -560,24 +588,24 @@ impl<T: PyClassImpl> InternalPyClassObjectLayout<T> for PyVariableClassObject<T>
560
588
unsafe impl < T : PyClassImpl > PyLayout < T > for PyVariableClassObject < T > { }
561
589
562
590
#[ cfg( Py_3_12 ) ]
563
- impl < T : PyClassImpl > PyClassObjectLayout < T > for PyVariableClassObject < T >
591
+ impl < T : PyClassImpl > PyClassObjectBaseLayout < T > for PyVariableClassObject < T >
564
592
where
565
- <T :: BaseType as PyClassBaseType >:: LayoutAsBase : PyClassObjectLayout < T :: BaseType > ,
593
+ <T :: BaseType as PyClassBaseType >:: LayoutAsBase : PyClassObjectBaseLayout < T :: BaseType > ,
566
594
{
567
595
fn ensure_threadsafe ( & self ) {
568
- self . contents ( ) . thread_checker . ensure ( ) ;
596
+ self . contents ( ) . 0 . thread_checker . ensure ( ) ;
569
597
self . ob_base . ensure_threadsafe ( ) ;
570
598
}
571
599
fn check_threadsafe ( & self ) -> Result < ( ) , PyBorrowError > {
572
- if !self . contents ( ) . thread_checker . check ( ) {
600
+ if !self . contents ( ) . 0 . thread_checker . check ( ) {
573
601
return Err ( PyBorrowError { _private : ( ) } ) ;
574
602
}
575
603
self . ob_base . check_threadsafe ( )
576
604
}
577
605
unsafe fn tp_dealloc ( py : Python < ' _ > , slf : * mut ffi:: PyObject ) {
578
606
// Safety: Python only calls tp_dealloc when no references to the object remain.
579
607
let class_object = & mut * ( slf. cast :: < T :: Layout > ( ) ) ;
580
- class_object. contents_mut ( ) . dealloc ( py, slf) ;
608
+ class_object. contents_mut ( ) . 0 . dealloc ( py, slf) ;
581
609
<T :: BaseType as PyClassBaseType >:: LayoutAsBase :: tp_dealloc ( py, slf)
582
610
}
583
611
}
0 commit comments