11use crate :: model:: {
2- Argument , Arguments , Attribute , Class , Function , Module , VariableLengthArgument ,
2+ Argument , Arguments , Attribute , Class , Function , Module , TypeHint , TypeHintExpr ,
3+ VariableLengthArgument ,
34} ;
45use anyhow:: { anyhow, bail, ensure, Context , Result } ;
56use goblin:: elf:: section_header:: SHN_XINDEX ;
@@ -9,11 +10,13 @@ use goblin::mach::symbols::{NO_SECT, N_SECT};
910use goblin:: mach:: { Mach , MachO , SingleArch } ;
1011use goblin:: pe:: PE ;
1112use goblin:: Object ;
12- use serde:: Deserialize ;
13+ use serde:: de:: value:: MapAccessDeserializer ;
14+ use serde:: de:: { Error , MapAccess , Visitor } ;
15+ use serde:: { Deserialize , Deserializer } ;
1316use std:: cmp:: Ordering ;
1417use std:: collections:: HashMap ;
1518use std:: path:: Path ;
16- use std:: { fs, str} ;
19+ use std:: { fmt , fs, str} ;
1720
1821/// Introspect a cdylib built with PyO3 and returns the definition of a Python module.
1922///
@@ -192,7 +195,7 @@ fn convert_function(
192195 name : & str ,
193196 arguments : & ChunkArguments ,
194197 decorators : & [ String ] ,
195- returns : & Option < String > ,
198+ returns : & Option < ChunkTypeHint > ,
196199) -> Function {
197200 Function {
198201 name : name. into ( ) ,
@@ -210,30 +213,58 @@ fn convert_function(
210213 . as_ref ( )
211214 . map ( convert_variable_length_argument) ,
212215 } ,
213- returns : returns. clone ( ) ,
216+ returns : returns. as_ref ( ) . map ( convert_type_hint ) ,
214217 }
215218}
216219
217220fn convert_argument ( arg : & ChunkArgument ) -> Argument {
218221 Argument {
219222 name : arg. name . clone ( ) ,
220223 default_value : arg. default . clone ( ) ,
221- annotation : arg. annotation . clone ( ) ,
224+ annotation : arg. annotation . as_ref ( ) . map ( convert_type_hint ) ,
222225 }
223226}
224227
225228fn convert_variable_length_argument ( arg : & ChunkArgument ) -> VariableLengthArgument {
226229 VariableLengthArgument {
227230 name : arg. name . clone ( ) ,
228- annotation : arg. annotation . clone ( ) ,
231+ annotation : arg. annotation . as_ref ( ) . map ( convert_type_hint ) ,
229232 }
230233}
231234
232- fn convert_attribute ( name : & str , value : & Option < String > , annotation : & Option < String > ) -> Attribute {
235+ fn convert_attribute (
236+ name : & str ,
237+ value : & Option < String > ,
238+ annotation : & Option < ChunkTypeHint > ,
239+ ) -> Attribute {
233240 Attribute {
234241 name : name. into ( ) ,
235242 value : value. clone ( ) ,
236- annotation : annotation. clone ( ) ,
243+ annotation : annotation. as_ref ( ) . map ( convert_type_hint) ,
244+ }
245+ }
246+
247+ fn convert_type_hint ( arg : & ChunkTypeHint ) -> TypeHint {
248+ match arg {
249+ ChunkTypeHint :: Ast ( expr) => TypeHint :: Ast ( convert_type_hint_expr ( expr) ) ,
250+ ChunkTypeHint :: Plain ( t) => TypeHint :: Plain ( t. clone ( ) ) ,
251+ }
252+ }
253+
254+ fn convert_type_hint_expr ( expr : & ChunkTypeHintExpr ) -> TypeHintExpr {
255+ match expr {
256+ ChunkTypeHintExpr :: Builtin { id } => TypeHintExpr :: Builtin { id : id. clone ( ) } ,
257+ ChunkTypeHintExpr :: Attribute { module, attr } => TypeHintExpr :: Attribute {
258+ module : module. clone ( ) ,
259+ attr : attr. clone ( ) ,
260+ } ,
261+ ChunkTypeHintExpr :: Union { elts } => TypeHintExpr :: Union {
262+ elts : elts. iter ( ) . map ( convert_type_hint_expr) . collect ( ) ,
263+ } ,
264+ ChunkTypeHintExpr :: Subscript { value, slice } => TypeHintExpr :: Subscript {
265+ value : Box :: new ( convert_type_hint_expr ( value) ) ,
266+ slice : slice. iter ( ) . map ( convert_type_hint_expr) . collect ( ) ,
267+ } ,
237268 }
238269}
239270
@@ -388,8 +419,8 @@ enum Chunk {
388419 parent : Option < String > ,
389420 #[ serde( default ) ]
390421 decorators : Vec < String > ,
391- #[ serde( default ) ]
392- returns : Option < String > ,
422+ #[ serde( default , deserialize_with = "deserialize_type_hint" ) ]
423+ returns : Option < ChunkTypeHint > ,
393424 } ,
394425 Attribute {
395426 #[ serde( default ) ]
@@ -399,8 +430,8 @@ enum Chunk {
399430 name : String ,
400431 #[ serde( default ) ]
401432 value : Option < String > ,
402- #[ serde( default ) ]
403- annotation : Option < String > ,
433+ #[ serde( default , deserialize_with = "deserialize_type_hint" ) ]
434+ annotation : Option < ChunkTypeHint > ,
404435 } ,
405436}
406437
@@ -423,6 +454,69 @@ struct ChunkArgument {
423454 name : String ,
424455 #[ serde( default ) ]
425456 default : Option < String > ,
426- #[ serde( default ) ]
427- annotation : Option < String > ,
457+ #[ serde( default , deserialize_with = "deserialize_type_hint" ) ]
458+ annotation : Option < ChunkTypeHint > ,
459+ }
460+
461+ /// Variant of [`TypeHint`] that implements deserialization.
462+ ///
463+ /// We keep separated type to allow them to evolve independently (this type will need to handle backward compatibility).
464+ enum ChunkTypeHint {
465+ Ast ( ChunkTypeHintExpr ) ,
466+ Plain ( String ) ,
467+ }
468+
469+ #[ derive( Deserialize ) ]
470+ #[ serde( tag = "type" , rename_all = "lowercase" ) ]
471+ enum ChunkTypeHintExpr {
472+ Builtin {
473+ id : String ,
474+ } ,
475+ Attribute {
476+ module : String ,
477+ attr : String ,
478+ } ,
479+ Union {
480+ elts : Vec < ChunkTypeHintExpr > ,
481+ } ,
482+ Subscript {
483+ value : Box < ChunkTypeHintExpr > ,
484+ slice : Vec < ChunkTypeHintExpr > ,
485+ } ,
486+ }
487+
488+ fn deserialize_type_hint < ' de , D : Deserializer < ' de > > (
489+ deserializer : D ,
490+ ) -> Result < Option < ChunkTypeHint > , D :: Error > {
491+ struct AnnotationVisitor ;
492+
493+ impl < ' de > Visitor < ' de > for AnnotationVisitor {
494+ type Value = ChunkTypeHint ;
495+
496+ fn expecting ( & self , formatter : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
497+ formatter. write_str ( "annotation" )
498+ }
499+
500+ fn visit_str < E > ( self , v : & str ) -> Result < Self :: Value , E >
501+ where
502+ E : Error ,
503+ {
504+ self . visit_string ( v. into ( ) )
505+ }
506+
507+ fn visit_string < E > ( self , v : String ) -> Result < Self :: Value , E >
508+ where
509+ E : Error ,
510+ {
511+ Ok ( ChunkTypeHint :: Plain ( v) )
512+ }
513+
514+ fn visit_map < M : MapAccess < ' de > > ( self , map : M ) -> Result < ChunkTypeHint , M :: Error > {
515+ Ok ( ChunkTypeHint :: Ast ( Deserialize :: deserialize (
516+ MapAccessDeserializer :: new ( map) ,
517+ ) ?) )
518+ }
519+ }
520+
521+ Ok ( Some ( deserializer. deserialize_any ( AnnotationVisitor ) ?) )
428522}
0 commit comments