Skip to content

Commit e64436c

Browse files
authored
did I GAT this right? (#91)
1 parent ddfe9f1 commit e64436c

File tree

4 files changed

+80
-78
lines changed

4 files changed

+80
-78
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "pythonize"
33
version = "0.25.0"
44
authors = ["David Hewitt <1939362+davidhewitt@users.noreply.github.com>"]
55
edition = "2021"
6-
rust-version = "1.63"
6+
rust-version = "1.65"
77
license = "MIT"
88
description = "Serde Serializer & Deserializer from Rust <--> Python, backed by PyO3."
99
homepage = "https://github.com/davidhewitt/pythonize"

src/ser.rs

Lines changed: 56 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -9,44 +9,46 @@ use serde::{ser, Serialize};
99

1010
use crate::error::{PythonizeError, Result};
1111

12-
// TODO: move 'py lifetime into builder once GATs are available in MSRV
1312
/// Trait for types which can represent a Python mapping
14-
pub trait PythonizeMappingType<'py> {
13+
pub trait PythonizeMappingType {
1514
/// Builder type for Python mappings
16-
type Builder;
15+
type Builder<'py>: 'py;
1716

1817
/// Create a builder for a Python mapping
19-
fn builder(py: Python<'py>, len: Option<usize>) -> PyResult<Self::Builder>;
18+
fn builder<'py>(py: Python<'py>, len: Option<usize>) -> PyResult<Self::Builder<'py>>;
2019

2120
/// Adds the key-value item to the mapping being built
22-
fn push_item(
23-
builder: &mut Self::Builder,
21+
fn push_item<'py>(
22+
builder: &mut Self::Builder<'py>,
2423
key: Bound<'py, PyAny>,
2524
value: Bound<'py, PyAny>,
2625
) -> PyResult<()>;
2726

2827
/// Build the Python mapping
29-
fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>>;
28+
fn finish<'py>(builder: Self::Builder<'py>) -> PyResult<Bound<'py, PyMapping>>;
3029
}
3130

32-
// TODO: move 'py lifetime into builder once GATs are available in MSRV
3331
/// Trait for types which can represent a Python mapping and have a name
34-
pub trait PythonizeNamedMappingType<'py> {
32+
pub trait PythonizeNamedMappingType {
3533
/// Builder type for Python mappings with a name
36-
type Builder;
34+
type Builder<'py>: 'py;
3735

3836
/// Create a builder for a Python mapping with a name
39-
fn builder(py: Python<'py>, len: usize, name: &'static str) -> PyResult<Self::Builder>;
37+
fn builder<'py>(
38+
py: Python<'py>,
39+
len: usize,
40+
name: &'static str,
41+
) -> PyResult<Self::Builder<'py>>;
4042

4143
/// Adds the field to the named mapping being built
42-
fn push_field(
43-
builder: &mut Self::Builder,
44+
fn push_field<'py>(
45+
builder: &mut Self::Builder<'py>,
4446
name: Bound<'py, PyString>,
4547
value: Bound<'py, PyAny>,
4648
) -> PyResult<()>;
4749

4850
/// Build the Python mapping
49-
fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>>;
51+
fn finish<'py>(builder: Self::Builder<'py>) -> PyResult<Bound<'py, PyMapping>>;
5052
}
5153

5254
/// Trait for types which can represent a Python sequence
@@ -61,33 +63,32 @@ pub trait PythonizeListType: Sized {
6163
U: ExactSizeIterator<Item = T>;
6264
}
6365

64-
// TODO: remove 'py lifetime once GATs are available in MSRV
6566
/// Custom types for serialization
66-
pub trait PythonizeTypes<'py> {
67+
pub trait PythonizeTypes {
6768
/// Python map type (should be representable as python mapping)
68-
type Map: PythonizeMappingType<'py>;
69+
type Map: PythonizeMappingType;
6970
/// Python (struct-like) named map type (should be representable as python mapping)
70-
type NamedMap: PythonizeNamedMappingType<'py>;
71+
type NamedMap: PythonizeNamedMappingType;
7172
/// Python sequence type (should be representable as python sequence)
7273
type List: PythonizeListType;
7374
}
7475

75-
impl<'py> PythonizeMappingType<'py> for PyDict {
76-
type Builder = Bound<'py, Self>;
76+
impl PythonizeMappingType for PyDict {
77+
type Builder<'py> = Bound<'py, Self>;
7778

78-
fn builder(py: Python<'py>, _len: Option<usize>) -> PyResult<Self::Builder> {
79+
fn builder<'py>(py: Python<'py>, _len: Option<usize>) -> PyResult<Self::Builder<'py>> {
7980
Ok(Self::new(py))
8081
}
8182

82-
fn push_item(
83-
builder: &mut Self::Builder,
83+
fn push_item<'py>(
84+
builder: &mut Self::Builder<'py>,
8485
key: Bound<'py, PyAny>,
8586
value: Bound<'py, PyAny>,
8687
) -> PyResult<()> {
8788
builder.set_item(key, value)
8889
}
8990

90-
fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>> {
91+
fn finish<'py>(builder: Self::Builder<'py>) -> PyResult<Bound<'py, PyMapping>> {
9192
Ok(builder.into_mapping())
9293
}
9394
}
@@ -99,30 +100,31 @@ impl<'py> PythonizeMappingType<'py> for PyDict {
99100
/// This adapter is commonly applied to use the same unnamed mapping type for
100101
/// both [`PythonizeTypes::Map`] and [`PythonizeTypes::NamedMap`] while only
101102
/// implementing [`PythonizeMappingType`].
102-
pub struct PythonizeUnnamedMappingAdapter<'py, T: PythonizeMappingType<'py>> {
103+
pub struct PythonizeUnnamedMappingAdapter<T: PythonizeMappingType> {
103104
_unnamed: T,
104-
_marker: PhantomData<&'py ()>,
105105
}
106106

107-
impl<'py, T: PythonizeMappingType<'py>> PythonizeNamedMappingType<'py>
108-
for PythonizeUnnamedMappingAdapter<'py, T>
109-
{
110-
type Builder = <T as PythonizeMappingType<'py>>::Builder;
107+
impl<T: PythonizeMappingType> PythonizeNamedMappingType for PythonizeUnnamedMappingAdapter<T> {
108+
type Builder<'py> = T::Builder<'py>;
111109

112-
fn builder(py: Python<'py>, len: usize, _name: &'static str) -> PyResult<Self::Builder> {
113-
<T as PythonizeMappingType>::builder(py, Some(len))
110+
fn builder<'py>(
111+
py: Python<'py>,
112+
len: usize,
113+
_name: &'static str,
114+
) -> PyResult<Self::Builder<'py>> {
115+
T::builder(py, Some(len))
114116
}
115117

116-
fn push_field(
117-
builder: &mut Self::Builder,
118+
fn push_field<'py>(
119+
builder: &mut Self::Builder<'py>,
118120
name: Bound<'py, PyString>,
119121
value: Bound<'py, PyAny>,
120122
) -> PyResult<()> {
121-
<T as PythonizeMappingType>::push_item(builder, name.into_any(), value)
123+
T::push_item(builder, name.into_any(), value)
122124
}
123125

124-
fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>> {
125-
<T as PythonizeMappingType>::finish(builder)
126+
fn finish<'py>(builder: Self::Builder<'py>) -> PyResult<Bound<'py, PyMapping>> {
127+
T::finish(builder)
126128
}
127129
}
128130

@@ -154,9 +156,9 @@ impl PythonizeListType for PyTuple {
154156

155157
pub struct PythonizeDefault;
156158

157-
impl<'py> PythonizeTypes<'py> for PythonizeDefault {
159+
impl PythonizeTypes for PythonizeDefault {
158160
type Map = PyDict;
159-
type NamedMap = PythonizeUnnamedMappingAdapter<'py, PyDict>;
161+
type NamedMap = PythonizeUnnamedMappingAdapter<PyDict>;
160162
type List = PyList;
161163
}
162164

@@ -173,7 +175,7 @@ where
173175
pub fn pythonize_custom<'py, P, T>(py: Python<'py>, value: &T) -> Result<Bound<'py, PyAny>>
174176
where
175177
T: ?Sized + Serialize,
176-
P: PythonizeTypes<'py>,
178+
P: PythonizeTypes,
177179
{
178180
value.serialize(Pythonizer::custom::<P>(py))
179181
}
@@ -221,28 +223,28 @@ pub struct PythonTupleVariantSerializer<'py, P> {
221223
}
222224

223225
#[doc(hidden)]
224-
pub struct PythonStructVariantSerializer<'py, P: PythonizeTypes<'py>> {
226+
pub struct PythonStructVariantSerializer<'py, P: PythonizeTypes> {
225227
name: &'static str,
226228
variant: &'static str,
227229
inner: PythonStructDictSerializer<'py, P>,
228230
}
229231

230232
#[doc(hidden)]
231-
pub struct PythonStructDictSerializer<'py, P: PythonizeTypes<'py>> {
233+
pub struct PythonStructDictSerializer<'py, P: PythonizeTypes> {
232234
py: Python<'py>,
233-
builder: <P::NamedMap as PythonizeNamedMappingType<'py>>::Builder,
235+
builder: <P::NamedMap as PythonizeNamedMappingType>::Builder<'py>,
234236
_types: PhantomData<P>,
235237
}
236238

237239
#[doc(hidden)]
238-
pub struct PythonMapSerializer<'py, P: PythonizeTypes<'py>> {
240+
pub struct PythonMapSerializer<'py, P: PythonizeTypes> {
239241
py: Python<'py>,
240-
builder: <P::Map as PythonizeMappingType<'py>>::Builder,
242+
builder: <P::Map as PythonizeMappingType>::Builder<'py>,
241243
key: Option<Bound<'py, PyAny>>,
242244
_types: PhantomData<P>,
243245
}
244246

245-
impl<'py, P: PythonizeTypes<'py>> Pythonizer<'py, P> {
247+
impl<'py, P: PythonizeTypes> Pythonizer<'py, P> {
246248
/// The default implementation for serialisation functions.
247249
#[inline]
248250
fn serialise_default<T>(self, v: T) -> Result<Bound<'py, PyAny>>
@@ -256,7 +258,7 @@ impl<'py, P: PythonizeTypes<'py>> Pythonizer<'py, P> {
256258
}
257259
}
258260

259-
impl<'py, P: PythonizeTypes<'py>> ser::Serializer for Pythonizer<'py, P> {
261+
impl<'py, P: PythonizeTypes> ser::Serializer for Pythonizer<'py, P> {
260262
type Ok = Bound<'py, PyAny>;
261263
type Error = PythonizeError;
262264
type SerializeSeq = PythonCollectionSerializer<'py, P>;
@@ -464,7 +466,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::Serializer for Pythonizer<'py, P> {
464466
}
465467
}
466468

467-
impl<'py, P: PythonizeTypes<'py>> ser::SerializeSeq for PythonCollectionSerializer<'py, P> {
469+
impl<'py, P: PythonizeTypes> ser::SerializeSeq for PythonCollectionSerializer<'py, P> {
468470
type Ok = Bound<'py, PyAny>;
469471
type Error = PythonizeError;
470472

@@ -482,7 +484,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeSeq for PythonCollectionSerializ
482484
}
483485
}
484486

485-
impl<'py, P: PythonizeTypes<'py>> ser::SerializeTuple for PythonCollectionSerializer<'py, P> {
487+
impl<'py, P: PythonizeTypes> ser::SerializeTuple for PythonCollectionSerializer<'py, P> {
486488
type Ok = Bound<'py, PyAny>;
487489
type Error = PythonizeError;
488490

@@ -498,7 +500,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeTuple for PythonCollectionSerial
498500
}
499501
}
500502

501-
impl<'py, P: PythonizeTypes<'py>> ser::SerializeTupleStruct for PythonCollectionSerializer<'py, P> {
503+
impl<'py, P: PythonizeTypes> ser::SerializeTupleStruct for PythonCollectionSerializer<'py, P> {
502504
type Ok = Bound<'py, PyAny>;
503505
type Error = PythonizeError;
504506

@@ -514,9 +516,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeTupleStruct for PythonCollection
514516
}
515517
}
516518

517-
impl<'py, P: PythonizeTypes<'py>> ser::SerializeTupleVariant
518-
for PythonTupleVariantSerializer<'py, P>
519-
{
519+
impl<'py, P: PythonizeTypes> ser::SerializeTupleVariant for PythonTupleVariantSerializer<'py, P> {
520520
type Ok = Bound<'py, PyAny>;
521521
type Error = PythonizeError;
522522

@@ -538,7 +538,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeTupleVariant
538538
}
539539
}
540540

541-
impl<'py, P: PythonizeTypes<'py>> ser::SerializeMap for PythonMapSerializer<'py, P> {
541+
impl<'py, P: PythonizeTypes> ser::SerializeMap for PythonMapSerializer<'py, P> {
542542
type Ok = Bound<'py, PyAny>;
543543
type Error = PythonizeError;
544544

@@ -569,7 +569,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeMap for PythonMapSerializer<'py,
569569
}
570570
}
571571

572-
impl<'py, P: PythonizeTypes<'py>> ser::SerializeStruct for PythonStructDictSerializer<'py, P> {
572+
impl<'py, P: PythonizeTypes> ser::SerializeStruct for PythonStructDictSerializer<'py, P> {
573573
type Ok = Bound<'py, PyAny>;
574574
type Error = PythonizeError;
575575

@@ -590,9 +590,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeStruct for PythonStructDictSeria
590590
}
591591
}
592592

593-
impl<'py, P: PythonizeTypes<'py>> ser::SerializeStructVariant
594-
for PythonStructVariantSerializer<'py, P>
595-
{
593+
impl<'py, P: PythonizeTypes> ser::SerializeStructVariant for PythonStructVariantSerializer<'py, P> {
596594
type Ok = Bound<'py, PyAny>;
597595
type Error = PythonizeError;
598596

tests/test_custom_types.rs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ impl PythonizeListType for CustomList {
5858
}
5959

6060
struct PythonizeCustomList;
61-
impl<'py> PythonizeTypes<'py> for PythonizeCustomList {
61+
impl<'py> PythonizeTypes for PythonizeCustomList {
6262
type Map = PyDict;
63-
type NamedMap = PythonizeUnnamedMappingAdapter<'py, PyDict>;
63+
type NamedMap = PythonizeUnnamedMappingAdapter<PyDict>;
6464
type List = CustomList;
6565
}
6666

@@ -107,10 +107,10 @@ impl CustomDict {
107107
}
108108
}
109109

110-
impl<'py> PythonizeMappingType<'py> for CustomDict {
111-
type Builder = Bound<'py, CustomDict>;
110+
impl PythonizeMappingType for CustomDict {
111+
type Builder<'py> = Bound<'py, CustomDict>;
112112

113-
fn builder(py: Python<'py>, len: Option<usize>) -> PyResult<Self::Builder> {
113+
fn builder<'py>(py: Python<'py>, len: Option<usize>) -> PyResult<Self::Builder<'py>> {
114114
Bound::new(
115115
py,
116116
CustomDict {
@@ -119,23 +119,23 @@ impl<'py> PythonizeMappingType<'py> for CustomDict {
119119
)
120120
}
121121

122-
fn push_item(
123-
builder: &mut Self::Builder,
122+
fn push_item<'py>(
123+
builder: &mut Self::Builder<'py>,
124124
key: Bound<'py, PyAny>,
125125
value: Bound<'py, PyAny>,
126126
) -> PyResult<()> {
127127
unsafe { builder.downcast_unchecked::<PyMapping>() }.set_item(key, value)
128128
}
129129

130-
fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>> {
130+
fn finish<'py>(builder: Self::Builder<'py>) -> PyResult<Bound<'py, PyMapping>> {
131131
Ok(unsafe { builder.into_any().downcast_into_unchecked() })
132132
}
133133
}
134134

135135
struct PythonizeCustomDict;
136-
impl<'py> PythonizeTypes<'py> for PythonizeCustomDict {
136+
impl<'py> PythonizeTypes for PythonizeCustomDict {
137137
type Map = CustomDict;
138-
type NamedMap = PythonizeUnnamedMappingAdapter<'py, CustomDict>;
138+
type NamedMap = PythonizeUnnamedMappingAdapter<CustomDict>;
139139
type List = PyTuple;
140140
}
141141

@@ -215,10 +215,14 @@ impl NamedCustomDict {
215215
}
216216
}
217217

218-
impl<'py> PythonizeNamedMappingType<'py> for NamedCustomDict {
219-
type Builder = Bound<'py, NamedCustomDict>;
218+
impl PythonizeNamedMappingType for NamedCustomDict {
219+
type Builder<'py> = Bound<'py, NamedCustomDict>;
220220

221-
fn builder(py: Python<'py>, len: usize, name: &'static str) -> PyResult<Self::Builder> {
221+
fn builder<'py>(
222+
py: Python<'py>,
223+
len: usize,
224+
name: &'static str,
225+
) -> PyResult<Self::Builder<'py>> {
222226
Bound::new(
223227
py,
224228
NamedCustomDict {
@@ -228,21 +232,21 @@ impl<'py> PythonizeNamedMappingType<'py> for NamedCustomDict {
228232
)
229233
}
230234

231-
fn push_field(
232-
builder: &mut Self::Builder,
235+
fn push_field<'py>(
236+
builder: &mut Self::Builder<'py>,
233237
name: Bound<'py, pyo3::types::PyString>,
234238
value: Bound<'py, PyAny>,
235239
) -> PyResult<()> {
236240
unsafe { builder.downcast_unchecked::<PyMapping>() }.set_item(name, value)
237241
}
238242

239-
fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>> {
243+
fn finish<'py>(builder: Self::Builder<'py>) -> PyResult<Bound<'py, PyMapping>> {
240244
Ok(unsafe { builder.into_any().downcast_into_unchecked() })
241245
}
242246
}
243247

244248
struct PythonizeNamedCustomDict;
245-
impl<'py> PythonizeTypes<'py> for PythonizeNamedCustomDict {
249+
impl<'py> PythonizeTypes for PythonizeNamedCustomDict {
246250
type Map = CustomDict;
247251
type NamedMap = NamedCustomDict;
248252
type List = PyTuple;

0 commit comments

Comments
 (0)