feat: FromPyFromStr and ToStrToPy macros YAY

This commit is contained in:
J / Jacob Babich
2026-07-09 01:35:49 -04:00
parent c637ad2d76
commit 9a9cefee37
25 changed files with 343 additions and 394 deletions

View File

@@ -4,6 +4,6 @@ version = "0.1.0"
edition = "2024"
[dependencies]
proc-macro2 = "1.0.106"
quote = "1.0.46"
syn = "2.0.118"
proc-macro2 = { workspace = true }
quote = { workspace = true }
syn = { workspace = true }

View File

@@ -0,0 +1,56 @@
use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use syn::{
DeriveInput, GenericParam,
parse::{Parse, ParseStream},
parse_quote,
};
pub struct FromPyFromStr {
derive_input: DeriveInput,
}
impl Parse for FromPyFromStr {
fn parse(input: ParseStream) -> syn::Result<Self> {
let derive_input = input.parse()?;
let this = Self { derive_input };
Ok(this)
}
}
impl ToTokens for FromPyFromStr {
fn to_tokens(&self, tokens: &mut TokenStream) {
let name = &self.derive_input.ident;
let (_, ty_generics, where_clause) = self.derive_input.generics.split_for_impl();
let mut generics = self.derive_input.generics.clone();
let a_lifetime: GenericParam = parse_quote!('a);
let py_lifetime: GenericParam = parse_quote!('py);
generics.params.push(a_lifetime.clone());
generics.params.push(py_lifetime.clone());
let (impl_generics, _, _) = generics.split_for_impl();
let output = quote! {
impl #impl_generics ::pyo3::conversion::FromPyObject<#a_lifetime, #py_lifetime> for #name #ty_generics #where_clause
where
#name #ty_generics: ::std::str::FromStr,
<#name #ty_generics as ::std::str::FromStr>::Err: ::std::fmt::Display,
{
type Error = ::python_utils::ExtractPyObjectViaParseError<<#name #ty_generics as ::std::str::FromStr>::Err>;
fn extract(obj: ::pyo3::Borrowed<#a_lifetime, #py_lifetime, ::pyo3::types::PyAny>) -> ::core::result::Result<Self, Self::Error> {
::python_utils::FromPyObjectViaParse::extract(obj).map(|wrapper| wrapper.0)
}
}
};
dbg!(&output.to_string());
tokens.extend(output);
}
}

View File

@@ -1,17 +1,5 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::{DeriveInput, parse_macro_input};
mod from_py_from_str;
mod to_str_to_py;
pub fn py_from_str(input: TokenStream) -> TokenStream {
let derive_input: DeriveInput = parse_macro_input!(input);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let expanded = quote! {
impl #impl_generics MyTrait for #name #ty_generics #where_clause {
// ...
}
};
expanded
}
pub use from_py_from_str::FromPyFromStr;
pub use to_str_to_py::ToStrToPy;

View File

@@ -0,0 +1,56 @@
use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use syn::{
DeriveInput, GenericParam,
parse::{Parse, ParseStream},
parse_quote,
};
pub struct ToStrToPy {
derive_input: DeriveInput,
}
impl Parse for ToStrToPy {
fn parse(input: ParseStream) -> syn::Result<Self> {
let derive_input = input.parse()?;
let this = Self { derive_input };
Ok(this)
}
}
impl ToTokens for ToStrToPy {
fn to_tokens(&self, tokens: &mut TokenStream) {
let name = &self.derive_input.ident;
let (_, ty_generics, where_clause) = self.derive_input.generics.split_for_impl();
let mut generics = self.derive_input.generics.clone();
let py_lifetime: GenericParam = parse_quote!('py);
generics.params.push(py_lifetime.clone());
let (impl_generics, _, _) = generics.split_for_impl();
let output = quote! {
impl #impl_generics ::pyo3::conversion::IntoPyObject<#py_lifetime> for #name #ty_generics #where_clause
where
#name #ty_generics: ::std::fmt::Display
{
type Target = ::pyo3::types::PyString;
type Output = ::pyo3::Bound<#py_lifetime, Self::Target>;
type Error = ::std::convert::Infallible;
fn into_pyobject(self, py: ::pyo3::Python<#py_lifetime>) -> ::core::result::Result<Self::Output, Self::Error> {
let s = ::std::string::ToString::to_string(&self);
::pyo3::conversion::IntoPyObject::into_pyobject(s, py)
}
}
};
dbg!(&output.to_string());
tokens.extend(output);
}
}