diff --git a/Cargo.toml b/Cargo.toml index b9d4df2..d636384 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "pythonize" version = "0.25.0" authors = ["David Hewitt <1939362+davidhewitt@users.noreply.github.com>"] edition = "2021" -rust-version = "1.63" +rust-version = "1.65" license = "MIT" description = "Serde Serializer & Deserializer from Rust <--> Python, backed by PyO3." homepage = "https://github.com/davidhewitt/pythonize" diff --git a/src/ser.rs b/src/ser.rs index 513a8e2..dce22e3 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -9,44 +9,46 @@ use serde::{ser, Serialize}; use crate::error::{PythonizeError, Result}; -// TODO: move 'py lifetime into builder once GATs are available in MSRV /// Trait for types which can represent a Python mapping -pub trait PythonizeMappingType<'py> { +pub trait PythonizeMappingType { /// Builder type for Python mappings - type Builder; + type Builder<'py>: 'py; /// Create a builder for a Python mapping - fn builder(py: Python<'py>, len: Option) -> PyResult; + fn builder<'py>(py: Python<'py>, len: Option) -> PyResult>; /// Adds the key-value item to the mapping being built - fn push_item( - builder: &mut Self::Builder, + fn push_item<'py>( + builder: &mut Self::Builder<'py>, key: Bound<'py, PyAny>, value: Bound<'py, PyAny>, ) -> PyResult<()>; /// Build the Python mapping - fn finish(builder: Self::Builder) -> PyResult>; + fn finish<'py>(builder: Self::Builder<'py>) -> PyResult>; } -// TODO: move 'py lifetime into builder once GATs are available in MSRV /// Trait for types which can represent a Python mapping and have a name -pub trait PythonizeNamedMappingType<'py> { +pub trait PythonizeNamedMappingType { /// Builder type for Python mappings with a name - type Builder; + type Builder<'py>: 'py; /// Create a builder for a Python mapping with a name - fn builder(py: Python<'py>, len: usize, name: &'static str) -> PyResult; + fn builder<'py>( + py: Python<'py>, + len: usize, + name: &'static str, + ) -> PyResult>; /// Adds the field to the named mapping being built - fn push_field( - builder: &mut Self::Builder, + fn push_field<'py>( + builder: &mut Self::Builder<'py>, name: Bound<'py, PyString>, value: Bound<'py, PyAny>, ) -> PyResult<()>; /// Build the Python mapping - fn finish(builder: Self::Builder) -> PyResult>; + fn finish<'py>(builder: Self::Builder<'py>) -> PyResult>; } /// Trait for types which can represent a Python sequence @@ -61,33 +63,32 @@ pub trait PythonizeListType: Sized { U: ExactSizeIterator; } -// TODO: remove 'py lifetime once GATs are available in MSRV /// Custom types for serialization -pub trait PythonizeTypes<'py> { +pub trait PythonizeTypes { /// Python map type (should be representable as python mapping) - type Map: PythonizeMappingType<'py>; + type Map: PythonizeMappingType; /// Python (struct-like) named map type (should be representable as python mapping) - type NamedMap: PythonizeNamedMappingType<'py>; + type NamedMap: PythonizeNamedMappingType; /// Python sequence type (should be representable as python sequence) type List: PythonizeListType; } -impl<'py> PythonizeMappingType<'py> for PyDict { - type Builder = Bound<'py, Self>; +impl PythonizeMappingType for PyDict { + type Builder<'py> = Bound<'py, Self>; - fn builder(py: Python<'py>, _len: Option) -> PyResult { + fn builder<'py>(py: Python<'py>, _len: Option) -> PyResult> { Ok(Self::new(py)) } - fn push_item( - builder: &mut Self::Builder, + fn push_item<'py>( + builder: &mut Self::Builder<'py>, key: Bound<'py, PyAny>, value: Bound<'py, PyAny>, ) -> PyResult<()> { builder.set_item(key, value) } - fn finish(builder: Self::Builder) -> PyResult> { + fn finish<'py>(builder: Self::Builder<'py>) -> PyResult> { Ok(builder.into_mapping()) } } @@ -99,30 +100,31 @@ impl<'py> PythonizeMappingType<'py> for PyDict { /// This adapter is commonly applied to use the same unnamed mapping type for /// both [`PythonizeTypes::Map`] and [`PythonizeTypes::NamedMap`] while only /// implementing [`PythonizeMappingType`]. -pub struct PythonizeUnnamedMappingAdapter<'py, T: PythonizeMappingType<'py>> { +pub struct PythonizeUnnamedMappingAdapter { _unnamed: T, - _marker: PhantomData<&'py ()>, } -impl<'py, T: PythonizeMappingType<'py>> PythonizeNamedMappingType<'py> - for PythonizeUnnamedMappingAdapter<'py, T> -{ - type Builder = >::Builder; +impl PythonizeNamedMappingType for PythonizeUnnamedMappingAdapter { + type Builder<'py> = T::Builder<'py>; - fn builder(py: Python<'py>, len: usize, _name: &'static str) -> PyResult { - ::builder(py, Some(len)) + fn builder<'py>( + py: Python<'py>, + len: usize, + _name: &'static str, + ) -> PyResult> { + T::builder(py, Some(len)) } - fn push_field( - builder: &mut Self::Builder, + fn push_field<'py>( + builder: &mut Self::Builder<'py>, name: Bound<'py, PyString>, value: Bound<'py, PyAny>, ) -> PyResult<()> { - ::push_item(builder, name.into_any(), value) + T::push_item(builder, name.into_any(), value) } - fn finish(builder: Self::Builder) -> PyResult> { - ::finish(builder) + fn finish<'py>(builder: Self::Builder<'py>) -> PyResult> { + T::finish(builder) } } @@ -154,9 +156,9 @@ impl PythonizeListType for PyTuple { pub struct PythonizeDefault; -impl<'py> PythonizeTypes<'py> for PythonizeDefault { +impl PythonizeTypes for PythonizeDefault { type Map = PyDict; - type NamedMap = PythonizeUnnamedMappingAdapter<'py, PyDict>; + type NamedMap = PythonizeUnnamedMappingAdapter; type List = PyList; } @@ -173,7 +175,7 @@ where pub fn pythonize_custom<'py, P, T>(py: Python<'py>, value: &T) -> Result> where T: ?Sized + Serialize, - P: PythonizeTypes<'py>, + P: PythonizeTypes, { value.serialize(Pythonizer::custom::

(py)) } @@ -221,28 +223,28 @@ pub struct PythonTupleVariantSerializer<'py, P> { } #[doc(hidden)] -pub struct PythonStructVariantSerializer<'py, P: PythonizeTypes<'py>> { +pub struct PythonStructVariantSerializer<'py, P: PythonizeTypes> { name: &'static str, variant: &'static str, inner: PythonStructDictSerializer<'py, P>, } #[doc(hidden)] -pub struct PythonStructDictSerializer<'py, P: PythonizeTypes<'py>> { +pub struct PythonStructDictSerializer<'py, P: PythonizeTypes> { py: Python<'py>, - builder: >::Builder, + builder: ::Builder<'py>, _types: PhantomData

, } #[doc(hidden)] -pub struct PythonMapSerializer<'py, P: PythonizeTypes<'py>> { +pub struct PythonMapSerializer<'py, P: PythonizeTypes> { py: Python<'py>, - builder: >::Builder, + builder: ::Builder<'py>, key: Option>, _types: PhantomData

, } -impl<'py, P: PythonizeTypes<'py>> Pythonizer<'py, P> { +impl<'py, P: PythonizeTypes> Pythonizer<'py, P> { /// The default implementation for serialisation functions. #[inline] fn serialise_default(self, v: T) -> Result> @@ -256,7 +258,7 @@ impl<'py, P: PythonizeTypes<'py>> Pythonizer<'py, P> { } } -impl<'py, P: PythonizeTypes<'py>> ser::Serializer for Pythonizer<'py, P> { +impl<'py, P: PythonizeTypes> ser::Serializer for Pythonizer<'py, P> { type Ok = Bound<'py, PyAny>; type Error = PythonizeError; type SerializeSeq = PythonCollectionSerializer<'py, P>; @@ -464,7 +466,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::Serializer for Pythonizer<'py, P> { } } -impl<'py, P: PythonizeTypes<'py>> ser::SerializeSeq for PythonCollectionSerializer<'py, P> { +impl<'py, P: PythonizeTypes> ser::SerializeSeq for PythonCollectionSerializer<'py, P> { type Ok = Bound<'py, PyAny>; type Error = PythonizeError; @@ -482,7 +484,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeSeq for PythonCollectionSerializ } } -impl<'py, P: PythonizeTypes<'py>> ser::SerializeTuple for PythonCollectionSerializer<'py, P> { +impl<'py, P: PythonizeTypes> ser::SerializeTuple for PythonCollectionSerializer<'py, P> { type Ok = Bound<'py, PyAny>; type Error = PythonizeError; @@ -498,7 +500,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeTuple for PythonCollectionSerial } } -impl<'py, P: PythonizeTypes<'py>> ser::SerializeTupleStruct for PythonCollectionSerializer<'py, P> { +impl<'py, P: PythonizeTypes> ser::SerializeTupleStruct for PythonCollectionSerializer<'py, P> { type Ok = Bound<'py, PyAny>; type Error = PythonizeError; @@ -514,9 +516,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeTupleStruct for PythonCollection } } -impl<'py, P: PythonizeTypes<'py>> ser::SerializeTupleVariant - for PythonTupleVariantSerializer<'py, P> -{ +impl<'py, P: PythonizeTypes> ser::SerializeTupleVariant for PythonTupleVariantSerializer<'py, P> { type Ok = Bound<'py, PyAny>; type Error = PythonizeError; @@ -538,7 +538,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeTupleVariant } } -impl<'py, P: PythonizeTypes<'py>> ser::SerializeMap for PythonMapSerializer<'py, P> { +impl<'py, P: PythonizeTypes> ser::SerializeMap for PythonMapSerializer<'py, P> { type Ok = Bound<'py, PyAny>; type Error = PythonizeError; @@ -569,7 +569,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeMap for PythonMapSerializer<'py, } } -impl<'py, P: PythonizeTypes<'py>> ser::SerializeStruct for PythonStructDictSerializer<'py, P> { +impl<'py, P: PythonizeTypes> ser::SerializeStruct for PythonStructDictSerializer<'py, P> { type Ok = Bound<'py, PyAny>; type Error = PythonizeError; @@ -590,9 +590,7 @@ impl<'py, P: PythonizeTypes<'py>> ser::SerializeStruct for PythonStructDictSeria } } -impl<'py, P: PythonizeTypes<'py>> ser::SerializeStructVariant - for PythonStructVariantSerializer<'py, P> -{ +impl<'py, P: PythonizeTypes> ser::SerializeStructVariant for PythonStructVariantSerializer<'py, P> { type Ok = Bound<'py, PyAny>; type Error = PythonizeError; diff --git a/tests/test_custom_types.rs b/tests/test_custom_types.rs index d311c14..32c5768 100644 --- a/tests/test_custom_types.rs +++ b/tests/test_custom_types.rs @@ -58,9 +58,9 @@ impl PythonizeListType for CustomList { } struct PythonizeCustomList; -impl<'py> PythonizeTypes<'py> for PythonizeCustomList { +impl<'py> PythonizeTypes for PythonizeCustomList { type Map = PyDict; - type NamedMap = PythonizeUnnamedMappingAdapter<'py, PyDict>; + type NamedMap = PythonizeUnnamedMappingAdapter; type List = CustomList; } @@ -107,10 +107,10 @@ impl CustomDict { } } -impl<'py> PythonizeMappingType<'py> for CustomDict { - type Builder = Bound<'py, CustomDict>; +impl PythonizeMappingType for CustomDict { + type Builder<'py> = Bound<'py, CustomDict>; - fn builder(py: Python<'py>, len: Option) -> PyResult { + fn builder<'py>(py: Python<'py>, len: Option) -> PyResult> { Bound::new( py, CustomDict { @@ -119,23 +119,23 @@ impl<'py> PythonizeMappingType<'py> for CustomDict { ) } - fn push_item( - builder: &mut Self::Builder, + fn push_item<'py>( + builder: &mut Self::Builder<'py>, key: Bound<'py, PyAny>, value: Bound<'py, PyAny>, ) -> PyResult<()> { unsafe { builder.downcast_unchecked::() }.set_item(key, value) } - fn finish(builder: Self::Builder) -> PyResult> { + fn finish<'py>(builder: Self::Builder<'py>) -> PyResult> { Ok(unsafe { builder.into_any().downcast_into_unchecked() }) } } struct PythonizeCustomDict; -impl<'py> PythonizeTypes<'py> for PythonizeCustomDict { +impl<'py> PythonizeTypes for PythonizeCustomDict { type Map = CustomDict; - type NamedMap = PythonizeUnnamedMappingAdapter<'py, CustomDict>; + type NamedMap = PythonizeUnnamedMappingAdapter; type List = PyTuple; } @@ -215,10 +215,14 @@ impl NamedCustomDict { } } -impl<'py> PythonizeNamedMappingType<'py> for NamedCustomDict { - type Builder = Bound<'py, NamedCustomDict>; +impl PythonizeNamedMappingType for NamedCustomDict { + type Builder<'py> = Bound<'py, NamedCustomDict>; - fn builder(py: Python<'py>, len: usize, name: &'static str) -> PyResult { + fn builder<'py>( + py: Python<'py>, + len: usize, + name: &'static str, + ) -> PyResult> { Bound::new( py, NamedCustomDict { @@ -228,21 +232,21 @@ impl<'py> PythonizeNamedMappingType<'py> for NamedCustomDict { ) } - fn push_field( - builder: &mut Self::Builder, + fn push_field<'py>( + builder: &mut Self::Builder<'py>, name: Bound<'py, pyo3::types::PyString>, value: Bound<'py, PyAny>, ) -> PyResult<()> { unsafe { builder.downcast_unchecked::() }.set_item(name, value) } - fn finish(builder: Self::Builder) -> PyResult> { + fn finish<'py>(builder: Self::Builder<'py>) -> PyResult> { Ok(unsafe { builder.into_any().downcast_into_unchecked() }) } } struct PythonizeNamedCustomDict; -impl<'py> PythonizeTypes<'py> for PythonizeNamedCustomDict { +impl<'py> PythonizeTypes for PythonizeNamedCustomDict { type Map = CustomDict; type NamedMap = NamedCustomDict; type List = PyTuple; diff --git a/tests/test_with_serde_path_to_err.rs b/tests/test_with_serde_path_to_err.rs index 5f2b970..9c3b688 100644 --- a/tests/test_with_serde_path_to_err.rs +++ b/tests/test_with_serde_path_to_err.rs @@ -13,9 +13,9 @@ struct Root { root_map: BTreeMap>, } -impl<'py, T> PythonizeTypes<'py> for Root { +impl<'py, T> PythonizeTypes for Root { type Map = PyDict; - type NamedMap = PythonizeUnnamedMappingAdapter<'py, PyDict>; + type NamedMap = PythonizeUnnamedMappingAdapter; type List = PyList; }