12
12
#[ pymodule]
13
13
pub ( crate ) mod _struct {
14
14
use crate :: {
15
- builtins:: { float, PyBaseExceptionRef , PyBytesRef , PyStr , PyStrRef , PyTupleRef , PyTypeRef } ,
16
- common:: str:: wchar_t,
17
- function:: {
18
- ArgAsciiBuffer , ArgBytesLike , ArgIntoBool , ArgMemoryBuffer , IntoPyObject , PosArgs ,
15
+ builtins:: {
16
+ float, PyBaseExceptionRef , PyBytes , PyBytesRef , PyStr , PyStrRef , PyTupleRef , PyTypeRef ,
19
17
} ,
18
+ common:: str:: wchar_t,
19
+ function:: { ArgBytesLike , ArgIntoBool , ArgMemoryBuffer , IntoPyObject , PosArgs } ,
20
20
protocol:: PyIterReturn ,
21
21
slots:: { IteratorIterable , SlotConstructor , SlotIterator } ,
22
- PyObjectRef , PyRef , PyResult , PyValue , TryFromObject , VirtualMachine ,
22
+ PyObjectRef , PyRef , PyResult , PyValue , TryFromObject , TypeProtocol , VirtualMachine ,
23
23
} ;
24
24
use crossbeam_utils:: atomic:: AtomicCell ;
25
25
use half:: f16;
@@ -203,6 +203,39 @@ pub(crate) mod _struct {
203
203
204
204
const OVERFLOW_MSG : & str = "total struct size too long" ;
205
205
206
+ struct IntoStructFormatBytes ( PyStrRef ) ;
207
+
208
+ impl TryFromObject for IntoStructFormatBytes {
209
+ fn try_from_object ( vm : & VirtualMachine , obj : PyObjectRef ) -> PyResult < Self > {
210
+ // CPython turns str to bytes but we do reversed way here
211
+ // The only performance difference is this transition cost
212
+ let fmt = match_class ! {
213
+ match obj {
214
+ s @ PyStr => if s. is_ascii( ) {
215
+ Some ( s)
216
+ } else {
217
+ None
218
+ } ,
219
+ b @ PyBytes => if b. is_ascii( ) {
220
+ Some ( unsafe {
221
+ PyStr :: new_ascii_unchecked( b. as_bytes( ) . to_vec( ) )
222
+ } . into_ref( vm) )
223
+ } else {
224
+ None
225
+ } ,
226
+ other => return Err ( vm. new_type_error( format!( "Struct() argument 1 must be a str or bytes object, not {}" , other. class( ) . name( ) ) ) ) ,
227
+ }
228
+ } . ok_or_else ( || vm. new_unicode_decode_error ( "Struct format must be a ascii string" . to_owned ( ) ) ) ?;
229
+ Ok ( IntoStructFormatBytes ( fmt) )
230
+ }
231
+ }
232
+
233
+ impl IntoStructFormatBytes {
234
+ fn format_spec ( & self , vm : & VirtualMachine ) -> PyResult < FormatSpec > {
235
+ FormatSpec :: parse ( self . 0 . as_str ( ) . as_bytes ( ) , vm)
236
+ }
237
+ }
238
+
206
239
#[ derive( Debug , Clone ) ]
207
240
pub ( crate ) struct FormatSpec {
208
241
endianness : Endianness ,
@@ -708,20 +741,19 @@ pub(crate) mod _struct {
708
741
}
709
742
710
743
#[ pyfunction]
711
- fn pack ( fmt : ArgAsciiBuffer , args : PosArgs , vm : & VirtualMachine ) -> PyResult < Vec < u8 > > {
712
- let format_spec = fmt. with_ref ( |bytes| FormatSpec :: parse ( bytes, vm) ) ?;
713
- format_spec. pack ( args. into_vec ( ) , vm)
744
+ fn pack ( fmt : IntoStructFormatBytes , args : PosArgs , vm : & VirtualMachine ) -> PyResult < Vec < u8 > > {
745
+ fmt. format_spec ( vm) ?. pack ( args. into_vec ( ) , vm)
714
746
}
715
747
716
748
#[ pyfunction]
717
749
fn pack_into (
718
- fmt : ArgAsciiBuffer ,
750
+ fmt : IntoStructFormatBytes ,
719
751
buffer : ArgMemoryBuffer ,
720
752
offset : isize ,
721
753
args : PosArgs ,
722
754
vm : & VirtualMachine ,
723
755
) -> PyResult < ( ) > {
724
- let format_spec = fmt. with_ref ( |bytes| FormatSpec :: parse ( bytes , vm ) ) ?;
756
+ let format_spec = fmt. format_spec ( vm ) ?;
725
757
let offset = get_buffer_offset ( buffer. len ( ) , offset, format_spec. size , true , vm) ?;
726
758
buffer. with_ref ( |data| format_spec. pack_into ( & mut data[ offset..] , args. into_vec ( ) , vm) )
727
759
}
@@ -744,11 +776,11 @@ pub(crate) mod _struct {
744
776
745
777
#[ pyfunction]
746
778
fn unpack (
747
- fmt : ArgAsciiBuffer ,
779
+ fmt : IntoStructFormatBytes ,
748
780
buffer : ArgBytesLike ,
749
781
vm : & VirtualMachine ,
750
782
) -> PyResult < PyTupleRef > {
751
- let format_spec = fmt. with_ref ( |bytes| FormatSpec :: parse ( bytes , vm ) ) ?;
783
+ let format_spec = fmt. format_spec ( vm ) ?;
752
784
buffer. with_ref ( |buf| format_spec. unpack ( buf, vm) )
753
785
}
754
786
@@ -761,11 +793,11 @@ pub(crate) mod _struct {
761
793
762
794
#[ pyfunction]
763
795
fn unpack_from (
764
- fmt : ArgAsciiBuffer ,
796
+ fmt : IntoStructFormatBytes ,
765
797
args : UpdateFromArgs ,
766
798
vm : & VirtualMachine ,
767
799
) -> PyResult < PyTupleRef > {
768
- let format_spec = fmt. with_ref ( |bytes| FormatSpec :: parse ( bytes , vm ) ) ?;
800
+ let format_spec = fmt. format_spec ( vm ) ?;
769
801
let offset =
770
802
get_buffer_offset ( args. buffer . len ( ) , args. offset , format_spec. size , false , vm) ?;
771
803
args. buffer
@@ -836,48 +868,42 @@ pub(crate) mod _struct {
836
868
837
869
#[ pyfunction]
838
870
fn iter_unpack (
839
- fmt : ArgAsciiBuffer ,
871
+ fmt : IntoStructFormatBytes ,
840
872
buffer : ArgBytesLike ,
841
873
vm : & VirtualMachine ,
842
874
) -> PyResult < UnpackIterator > {
843
- let format_spec = fmt. with_ref ( |bytes| FormatSpec :: parse ( bytes , vm ) ) ?;
875
+ let format_spec = fmt. format_spec ( vm ) ?;
844
876
UnpackIterator :: new ( vm, format_spec, buffer)
845
877
}
846
878
847
879
#[ pyfunction]
848
- fn calcsize ( fmt : ArgAsciiBuffer , vm : & VirtualMachine ) -> PyResult < usize > {
849
- let format_spec = fmt. with_ref ( |bytes| FormatSpec :: parse ( bytes, vm) ) ?;
850
- Ok ( format_spec. size )
880
+ fn calcsize ( fmt : IntoStructFormatBytes , vm : & VirtualMachine ) -> PyResult < usize > {
881
+ Ok ( fmt. format_spec ( vm) ?. size )
851
882
}
852
883
853
884
#[ pyattr]
854
885
#[ pyclass( name = "Struct" ) ]
855
886
#[ derive( Debug , PyValue ) ]
856
887
struct PyStruct {
857
888
spec : FormatSpec ,
858
- fmt_str : PyStrRef ,
889
+ format : PyStrRef ,
859
890
}
860
891
861
892
impl SlotConstructor for PyStruct {
862
- type Args = ArgAsciiBuffer ;
893
+ type Args = IntoStructFormatBytes ;
863
894
864
895
fn py_new ( cls : PyTypeRef , fmt : Self :: Args , vm : & VirtualMachine ) -> PyResult {
865
- let spec = fmt. with_ref ( |bytes| FormatSpec :: parse ( bytes, vm) ) ?;
866
- let fmt_str = match fmt {
867
- ArgAsciiBuffer :: String ( s) => s,
868
- buffer => buffer
869
- . with_ref ( |bytes| PyStr :: from ( std:: str:: from_utf8 ( bytes) . unwrap ( ) ) )
870
- . into_ref ( vm) ,
871
- } ;
872
- PyStruct { spec, fmt_str } . into_pyresult_with_type ( vm, cls)
896
+ let spec = fmt. format_spec ( vm) ?;
897
+ let format = fmt. 0 ;
898
+ PyStruct { spec, format } . into_pyresult_with_type ( vm, cls)
873
899
}
874
900
}
875
901
876
902
#[ pyimpl( with( SlotConstructor ) ) ]
877
903
impl PyStruct {
878
904
#[ pyproperty]
879
905
fn format ( & self ) -> PyStrRef {
880
- self . fmt_str . clone ( )
906
+ self . format . clone ( )
881
907
}
882
908
883
909
#[ pyproperty]
0 commit comments