@@ -2605,6 +2605,92 @@ mod _io {
26052605 }
26062606 }
26072607
2608+ #[ pyclass( module = "_io" , name, no_attr) ]
2609+ #[ derive( Debug , PyPayload ) ]
2610+ struct StatelessIncrementalEncoder {
2611+ encode : PyObjectRef ,
2612+ errors : Option < PyStrRef > ,
2613+ name : Option < PyStrRef > ,
2614+ }
2615+
2616+ #[ pyclass]
2617+ impl StatelessIncrementalEncoder {
2618+ #[ pymethod]
2619+ fn encode (
2620+ & self ,
2621+ input : PyObjectRef ,
2622+ _final : OptionalArg < bool > ,
2623+ vm : & VirtualMachine ,
2624+ ) -> PyResult {
2625+ let mut args: Vec < PyObjectRef > = vec ! [ input] ;
2626+ if let Some ( errors) = & self . errors {
2627+ args. push ( errors. to_owned ( ) . into ( ) ) ;
2628+ }
2629+ let res = self . encode . call ( args, vm) ?;
2630+ let tuple: PyTupleRef = res. try_into_value ( vm) ?;
2631+ if tuple. len ( ) != 2 {
2632+ return Err ( vm. new_type_error ( "encoder must return a tuple (object, integer)" ) ) ;
2633+ }
2634+ Ok ( tuple[ 0 ] . clone ( ) )
2635+ }
2636+
2637+ #[ pymethod]
2638+ fn reset ( & self ) { }
2639+
2640+ #[ pymethod]
2641+ fn setstate ( & self , _state : PyObjectRef ) { }
2642+
2643+ #[ pymethod]
2644+ fn getstate ( & self , vm : & VirtualMachine ) -> PyObjectRef {
2645+ vm. ctx . new_int ( 0 ) . into ( )
2646+ }
2647+
2648+ #[ pygetset]
2649+ fn name ( & self ) -> Option < PyStrRef > {
2650+ self . name . clone ( )
2651+ }
2652+ }
2653+
2654+ #[ pyclass( module = "_io" , name, no_attr) ]
2655+ #[ derive( Debug , PyPayload ) ]
2656+ struct StatelessIncrementalDecoder {
2657+ decode : PyObjectRef ,
2658+ errors : Option < PyStrRef > ,
2659+ }
2660+
2661+ #[ pyclass]
2662+ impl StatelessIncrementalDecoder {
2663+ #[ pymethod]
2664+ fn decode (
2665+ & self ,
2666+ input : PyObjectRef ,
2667+ _final : OptionalArg < bool > ,
2668+ vm : & VirtualMachine ,
2669+ ) -> PyResult {
2670+ let mut args: Vec < PyObjectRef > = vec ! [ input] ;
2671+ if let Some ( errors) = & self . errors {
2672+ args. push ( errors. to_owned ( ) . into ( ) ) ;
2673+ }
2674+ let res = self . decode . call ( args, vm) ?;
2675+ let tuple: PyTupleRef = res. try_into_value ( vm) ?;
2676+ if tuple. len ( ) != 2 {
2677+ return Err ( vm. new_type_error ( "decoder must return a tuple (object, integer)" ) ) ;
2678+ }
2679+ Ok ( tuple[ 0 ] . clone ( ) )
2680+ }
2681+
2682+ #[ pymethod]
2683+ fn getstate ( & self , vm : & VirtualMachine ) -> ( PyBytesRef , u64 ) {
2684+ ( vm. ctx . empty_bytes . to_owned ( ) , 0 )
2685+ }
2686+
2687+ #[ pymethod]
2688+ fn setstate ( & self , _state : PyTupleRef , _vm : & VirtualMachine ) { }
2689+
2690+ #[ pymethod]
2691+ fn reset ( & self ) { }
2692+ }
2693+
26082694 #[ pyattr]
26092695 #[ pyclass( name = "TextIOWrapper" , base = _TextIOBase) ]
26102696 #[ derive( Debug , Default ) ]
@@ -2828,7 +2914,25 @@ mod _io {
28282914
28292915 let encoder = if vm. call_method ( buffer, "writable" , ( ) ) ?. try_to_bool ( vm) ? {
28302916 let incremental_encoder =
2831- codec. get_incremental_encoder ( Some ( errors. to_owned ( ) ) , vm) ?;
2917+ match codec. get_incremental_encoder ( Some ( errors. to_owned ( ) ) , vm) {
2918+ Ok ( encoder) => encoder,
2919+ Err ( err)
2920+ if err. fast_isinstance ( vm. ctx . exceptions . type_error )
2921+ || err. fast_isinstance ( vm. ctx . exceptions . attribute_error ) =>
2922+ {
2923+ let name = vm
2924+ . get_attribute_opt ( codec. as_tuple ( ) . to_owned ( ) . into ( ) , "name" ) ?
2925+ . and_then ( |obj| obj. downcast :: < PyStr > ( ) . ok ( ) ) ;
2926+ StatelessIncrementalEncoder {
2927+ encode : codec. get_encode_func ( ) . to_owned ( ) ,
2928+ errors : Some ( errors. to_owned ( ) ) ,
2929+ name,
2930+ }
2931+ . into_ref ( & vm. ctx )
2932+ . into ( )
2933+ }
2934+ Err ( err) => return Err ( err) ,
2935+ } ;
28322936 let encoding_name = vm. get_attribute_opt ( incremental_encoder. clone ( ) , "name" ) ?;
28332937 let encode_func = encoding_name. and_then ( |name| {
28342938 let name = name. downcast_ref :: < PyStr > ( ) ?;
@@ -2843,7 +2947,21 @@ mod _io {
28432947 } ;
28442948
28452949 let decoder = if vm. call_method ( buffer, "readable" , ( ) ) ?. try_to_bool ( vm) ? {
2846- let decoder = codec. get_incremental_decoder ( Some ( errors. to_owned ( ) ) , vm) ?;
2950+ let decoder = match codec. get_incremental_decoder ( Some ( errors. to_owned ( ) ) , vm) {
2951+ Ok ( decoder) => decoder,
2952+ Err ( err)
2953+ if err. fast_isinstance ( vm. ctx . exceptions . type_error )
2954+ || err. fast_isinstance ( vm. ctx . exceptions . attribute_error ) =>
2955+ {
2956+ StatelessIncrementalDecoder {
2957+ decode : codec. get_decode_func ( ) . to_owned ( ) ,
2958+ errors : Some ( errors. to_owned ( ) ) ,
2959+ }
2960+ . into_ref ( & vm. ctx )
2961+ . into ( )
2962+ }
2963+ Err ( err) => return Err ( err) ,
2964+ } ;
28472965 if let Newlines :: Universal | Newlines :: Passthrough = newline {
28482966 let args = IncrementalNewlineDecoderArgs {
28492967 decoder,
0 commit comments