@@ -14,6 +14,7 @@ use crate::{
14
14
} ;
15
15
#[ allow( deprecated) ]
16
16
use crate :: { IntoPy , ToPyObject } ;
17
+ use std:: ops:: Deref ;
17
18
use std:: {
18
19
borrow:: Cow ,
19
20
ffi:: { CStr , CString } ,
@@ -1229,6 +1230,7 @@ pub struct PyClassGetterGenerator<
1229
1230
const IMPLEMENTS_INTOPY : bool ,
1230
1231
const IMPLEMENTS_INTOPYOBJECT_REF : bool ,
1231
1232
const IMPLEMENTS_INTOPYOBJECT : bool ,
1233
+ const IMPLEMENTS_DEREF : bool ,
1232
1234
> ( PhantomData < ( ClassT , FieldT , Offset ) > ) ;
1233
1235
1234
1236
impl <
@@ -1240,6 +1242,7 @@ impl<
1240
1242
const IMPLEMENTS_INTOPY : bool ,
1241
1243
const IMPLEMENTS_INTOPYOBJECT_REF : bool ,
1242
1244
const IMPLEMENTS_INTOPYOBJECT : bool ,
1245
+ const IMPLEMENTS_DEREF : bool ,
1243
1246
>
1244
1247
PyClassGetterGenerator <
1245
1248
ClassT ,
@@ -1250,6 +1253,7 @@ impl<
1250
1253
IMPLEMENTS_INTOPY ,
1251
1254
IMPLEMENTS_INTOPYOBJECT_REF ,
1252
1255
IMPLEMENTS_INTOPYOBJECT ,
1256
+ IMPLEMENTS_DEREF ,
1253
1257
>
1254
1258
{
1255
1259
/// Safety: constructing this type requires that there exists a value of type FieldT
@@ -1267,6 +1271,7 @@ impl<
1267
1271
const IMPLEMENTS_INTOPY : bool ,
1268
1272
const IMPLEMENTS_INTOPYOBJECT_REF : bool ,
1269
1273
const IMPLEMENTS_INTOPYOBJECT : bool ,
1274
+ const IMPLEMENTS_DEREF : bool ,
1270
1275
>
1271
1276
PyClassGetterGenerator <
1272
1277
ClassT ,
@@ -1277,6 +1282,7 @@ impl<
1277
1282
IMPLEMENTS_INTOPY ,
1278
1283
IMPLEMENTS_INTOPYOBJECT_REF ,
1279
1284
IMPLEMENTS_INTOPYOBJECT ,
1285
+ IMPLEMENTS_DEREF ,
1280
1286
>
1281
1287
{
1282
1288
/// `Py<T>` fields have a potential optimization to use Python's "struct members" to read
@@ -1312,7 +1318,19 @@ impl<
1312
1318
FieldT : ToPyObject ,
1313
1319
Offset : OffsetCalculator < ClassT , FieldT > ,
1314
1320
const IMPLEMENTS_INTOPY : bool ,
1315
- > PyClassGetterGenerator < ClassT , FieldT , Offset , false , true , IMPLEMENTS_INTOPY , false , false >
1321
+ const IMPLEMENTS_DEREF : bool ,
1322
+ >
1323
+ PyClassGetterGenerator <
1324
+ ClassT ,
1325
+ FieldT ,
1326
+ Offset ,
1327
+ false ,
1328
+ true ,
1329
+ IMPLEMENTS_INTOPY ,
1330
+ false ,
1331
+ false ,
1332
+ IMPLEMENTS_DEREF ,
1333
+ >
1316
1334
{
1317
1335
pub const fn generate ( & self , name : & ' static CStr , doc : & ' static CStr ) -> PyMethodDefType {
1318
1336
PyMethodDefType :: Getter ( PyGetterDef {
@@ -1332,6 +1350,7 @@ impl<
1332
1350
const IMPLEMENTS_TOPYOBJECT : bool ,
1333
1351
const IMPLEMENTS_INTOPY : bool ,
1334
1352
const IMPLEMENTS_INTOPYOBJECT : bool ,
1353
+ const IMPLEMENTS_DEREF : bool ,
1335
1354
>
1336
1355
PyClassGetterGenerator <
1337
1356
ClassT ,
@@ -1342,6 +1361,7 @@ impl<
1342
1361
IMPLEMENTS_INTOPY ,
1343
1362
true ,
1344
1363
IMPLEMENTS_INTOPYOBJECT ,
1364
+ IMPLEMENTS_DEREF ,
1345
1365
>
1346
1366
where
1347
1367
ClassT : PyClass ,
@@ -1357,9 +1377,34 @@ where
1357
1377
}
1358
1378
}
1359
1379
1380
+ /// If Field does not implement `IntoPyObject` but Deref::Target does, use that instead
1381
+ impl < ClassT , FieldT , Offset >
1382
+ PyClassGetterGenerator < ClassT , FieldT , Offset , false , false , false , false , false , true >
1383
+ where
1384
+ ClassT : PyClass ,
1385
+ FieldT : Deref ,
1386
+ for < ' a , ' py > & ' a FieldT :: Target : IntoPyObject < ' py > ,
1387
+ Offset : OffsetCalculator < ClassT , FieldT > ,
1388
+ {
1389
+ pub const fn generate ( & self , name : & ' static CStr , doc : & ' static CStr ) -> PyMethodDefType {
1390
+ PyMethodDefType :: Getter ( PyGetterDef {
1391
+ name,
1392
+ meth : pyo3_get_value_into_pyobject_deref :: < ClassT , FieldT , Offset > ,
1393
+ doc,
1394
+ } )
1395
+ }
1396
+ }
1397
+
1360
1398
/// Temporary case to prefer `IntoPyObject + Clone` over `IntoPy + Clone`, while still showing the
1361
1399
/// `IntoPyObject` suggestion if neither is implemented;
1362
- impl < ClassT , FieldT , Offset , const IMPLEMENTS_TOPYOBJECT : bool , const IMPLEMENTS_INTOPY : bool >
1400
+ impl <
1401
+ ClassT ,
1402
+ FieldT ,
1403
+ Offset ,
1404
+ const IMPLEMENTS_TOPYOBJECT : bool ,
1405
+ const IMPLEMENTS_INTOPY : bool ,
1406
+ const IMPLEMENTS_DEREF : bool ,
1407
+ >
1363
1408
PyClassGetterGenerator <
1364
1409
ClassT ,
1365
1410
FieldT ,
@@ -1369,6 +1414,7 @@ impl<ClassT, FieldT, Offset, const IMPLEMENTS_TOPYOBJECT: bool, const IMPLEMENTS
1369
1414
IMPLEMENTS_INTOPY ,
1370
1415
false ,
1371
1416
true ,
1417
+ IMPLEMENTS_DEREF ,
1372
1418
>
1373
1419
where
1374
1420
ClassT : PyClass ,
@@ -1386,8 +1432,18 @@ where
1386
1432
1387
1433
/// IntoPy + Clone fallback case, which was the only behaviour before PyO3 0.22.
1388
1434
#[ allow( deprecated) ]
1389
- impl < ClassT , FieldT , Offset >
1390
- PyClassGetterGenerator < ClassT , FieldT , Offset , false , false , true , false , false >
1435
+ impl < ClassT , FieldT , Offset , const IMPLEMENTS_DEREF : bool >
1436
+ PyClassGetterGenerator <
1437
+ ClassT ,
1438
+ FieldT ,
1439
+ Offset ,
1440
+ false ,
1441
+ false ,
1442
+ true ,
1443
+ false ,
1444
+ false ,
1445
+ IMPLEMENTS_DEREF ,
1446
+ >
1391
1447
where
1392
1448
ClassT : PyClass ,
1393
1449
Offset : OffsetCalculator < ClassT , FieldT > ,
@@ -1415,7 +1471,7 @@ impl<'py, T> PyO3GetField<'py> for T where T: IntoPyObject<'py> + Clone {}
1415
1471
1416
1472
/// Base case attempts to use IntoPyObject + Clone
1417
1473
impl < ClassT : PyClass , FieldT , Offset : OffsetCalculator < ClassT , FieldT > >
1418
- PyClassGetterGenerator < ClassT , FieldT , Offset , false , false , false , false , false >
1474
+ PyClassGetterGenerator < ClassT , FieldT , Offset , false , false , false , false , false , false >
1419
1475
{
1420
1476
pub const fn generate ( & self , _name : & ' static CStr , _doc : & ' static CStr ) -> PyMethodDefType
1421
1477
// The bound goes here rather than on the block so that this impl is always available
@@ -1489,6 +1545,28 @@ where
1489
1545
. into_ptr ( ) )
1490
1546
}
1491
1547
1548
+ fn pyo3_get_value_into_pyobject_deref < ClassT , FieldT , Offset > (
1549
+ py : Python < ' _ > ,
1550
+ obj : * mut ffi:: PyObject ,
1551
+ ) -> PyResult < * mut ffi:: PyObject >
1552
+ where
1553
+ ClassT : PyClass ,
1554
+ FieldT : Deref ,
1555
+ for < ' a , ' py > & ' a FieldT :: Target : IntoPyObject < ' py > ,
1556
+ Offset : OffsetCalculator < ClassT , FieldT > ,
1557
+ {
1558
+ let _holder = unsafe { ensure_no_mutable_alias :: < ClassT > ( py, & obj) ? } ;
1559
+ let value = field_from_object :: < ClassT , FieldT , Offset > ( obj) ;
1560
+
1561
+ // SAFETY: Offset is known to describe the location of the value, and
1562
+ // _holder is preventing mutable aliasing
1563
+ Ok ( ( unsafe { & * value } )
1564
+ . deref ( )
1565
+ . into_pyobject ( py)
1566
+ . map_err ( Into :: into) ?
1567
+ . into_ptr ( ) )
1568
+ }
1569
+
1492
1570
fn pyo3_get_value_into_pyobject < ClassT , FieldT , Offset > (
1493
1571
py : Python < ' _ > ,
1494
1572
obj : * mut ffi:: PyObject ,
0 commit comments