@@ -17,10 +17,9 @@ use alloc::borrow::Cow;
1717use num_traits:: { Signed , ToPrimitive } ;
1818
1919use rustpython_host_env:: ctypes:: {
20- ArrayElementWriteValue , DecodedValue , WCHAR_SIZE , WCharArrayWriteError , char_array_field_value,
21- int_to_sized_bytes, read_array_element, simple_type_size, uint_to_sized_bytes,
22- wchar_from_bytes, write_array_element, write_char_array_raw, write_char_array_value,
23- write_wchar_array_value, wstring_from_bytes, zeroed_bytes,
20+ DecodedValue , WCHAR_SIZE , WCharArrayWriteError , char_array_field_value, read_array_element,
21+ simple_type_size, wchar_from_bytes, write_char_array_raw, write_char_array_value,
22+ write_wchar_array_value, wstring_from_bytes,
2423} ;
2524
2625fn cow_bytes_as_mut < ' buf > ( buffer : & ' buf mut Cow < ' _ , [ u8 ] > ) -> & ' buf mut [ u8 ] {
@@ -508,33 +507,6 @@ impl PyCArray {
508507 PyGenericAlias :: from_args ( cls, object, vm)
509508 }
510509
511- fn int_to_bytes ( i : & malachite_bigint:: BigInt , size : usize ) -> Vec < u8 > {
512- // Try unsigned first (handles values like 0xFFFFFFFF that overflow signed)
513- // then fall back to signed (handles negative values)
514- match size {
515- 1 => {
516- if let Some ( v) = i. to_u8 ( ) {
517- vec ! [ v]
518- } else {
519- vec ! [ i. to_i8( ) . unwrap_or( 0 ) as u8 ]
520- }
521- }
522- 2 => i. to_u16 ( ) . map_or_else (
523- || int_to_sized_bytes ( i. to_i16 ( ) . unwrap_or ( 0 ) . into ( ) , 2 ) ,
524- |v| uint_to_sized_bytes ( v. into ( ) , 2 ) ,
525- ) ,
526- 4 => i. to_u32 ( ) . map_or_else (
527- || int_to_sized_bytes ( i. to_i32 ( ) . unwrap_or ( 0 ) . into ( ) , 4 ) ,
528- |v| uint_to_sized_bytes ( v. into ( ) , 4 ) ,
529- ) ,
530- 8 => i. to_u64 ( ) . map_or_else (
531- || int_to_sized_bytes ( i. to_i64 ( ) . unwrap_or ( 0 ) , 8 ) ,
532- |v| uint_to_sized_bytes ( v, 8 ) ,
533- ) ,
534- _ => zeroed_bytes ( size) ,
535- }
536- }
537-
538510 fn getitem_by_index ( zelf : & Py < Self > , i : isize , vm : & VirtualMachine ) -> PyResult {
539511 let stg = zelf. class ( ) . stg_info_opt ( ) ;
540512 let length = stg. as_ref ( ) . map_or ( 0 , |i| i. length ) as isize ;
@@ -616,231 +588,39 @@ impl PyCArray {
616588 }
617589 }
618590
619- /// Helper to write an element value to a buffer at given offset
620- fn write_element_to_buffer (
621- offset : usize ,
622- element_size : usize ,
623- type_code : Option < & str > ,
624- value : & PyObject ,
625- zelf : & Py < Self > ,
626- index : usize ,
627- vm : & VirtualMachine ,
628- ) -> PyResult < ( ) > {
629- // Conversions and reference replacement may call Python. Only the raw
630- // storage write runs under the buffer lock.
631- let write = |value| {
632- let mut buffer = zelf. 0 . buffer . write ( ) ;
633- write_array_element ( cow_bytes_as_mut ( & mut buffer) , offset, value) ;
634- } ;
635- match type_code {
636- Some ( "c" ) => {
637- if let Some ( b) = value. downcast_ref :: < PyBytes > ( ) {
638- write ( ArrayElementWriteValue :: Byte (
639- b. as_bytes ( ) . first ( ) . copied ( ) . unwrap_or ( 0 ) ,
640- ) ) ;
641- } else if let Ok ( int_val) = value. try_int ( vm) {
642- write ( ArrayElementWriteValue :: Byte (
643- int_val. as_bigint ( ) . to_u8 ( ) . unwrap_or ( 0 ) ,
644- ) ) ;
645- } else {
646- return Err ( vm. new_type_error ( "an integer or bytes of length 1 is required" ) ) ;
647- }
648- }
649- Some ( "u" ) => {
650- if let Some ( s) = value. downcast_ref :: < PyStr > ( ) {
651- let code = s. as_wtf8 ( ) . code_points ( ) . next ( ) . map_or ( 0 , |c| c. to_u32 ( ) ) ;
652- write ( ArrayElementWriteValue :: Wchar ( code) ) ;
653- } else {
654- return Err ( vm. new_type_error ( "unicode string expected" ) ) ;
655- }
656- }
657- Some ( "z" ) => {
658- let mut hidden = None ;
659- let ( ptr_val, converted) = if value. is ( & vm. ctx . none ) {
660- ( 0usize , None )
661- } else if let Some ( bytes) = value. downcast_ref :: < PyBytes > ( ) {
662- let ( kept_alive, ptr) = super :: base:: ensure_z_null_terminated ( bytes, vm) ;
663- hidden = Some ( kept_alive) ;
664- ( ptr, Some ( value. to_owned ( ) ) )
665- } else if let Some ( simple) = value. downcast_ref :: < super :: PyCSimple > ( )
666- && value. class ( ) . type_code ( vm) . as_deref ( ) == Some ( "z" )
667- {
668- let buffer = simple. 0 . buffer . read ( ) ;
669- (
670- rustpython_host_env:: ctypes:: read_pointer_from_buffer ( & buffer) ,
671- None ,
672- )
673- } else if let Ok ( int_val) = value. try_index ( vm) {
674- ( int_val. as_bigint ( ) . to_usize ( ) . unwrap_or ( 0 ) , None )
675- } else {
676- return Err ( vm. new_type_error ( format ! (
677- "bytes or integer address expected instead of {} instance" ,
678- value. class( ) . name( )
679- ) ) ) ;
680- } ;
681- write ( ArrayElementWriteValue :: Pointer {
682- value : ptr_val,
683- size : element_size,
684- } ) ;
685- if let Some ( c) = converted {
686- return zelf. 0 . keep_ref_with_hidden ( index, c, hidden, vm) ;
687- }
688- }
689- Some ( "Z" ) => {
690- let ( ptr_val, converted) = if value. is ( & vm. ctx . none ) {
691- ( 0usize , None )
692- } else if let Some ( s) = value. downcast_ref :: < PyStr > ( ) {
693- let ( holder, ptr) = super :: base:: str_to_wchar_bytes ( s. as_wtf8 ( ) , vm) ;
694- ( ptr, Some ( holder) )
695- } else if let Some ( simple) = value. downcast_ref :: < super :: PyCSimple > ( )
696- && value. class ( ) . type_code ( vm) . as_deref ( ) == Some ( "Z" )
697- {
698- let buffer = simple. 0 . buffer . read ( ) ;
699- (
700- rustpython_host_env:: ctypes:: read_pointer_from_buffer ( & buffer) ,
701- None ,
702- )
703- } else if let Ok ( int_val) = value. try_index ( vm) {
704- ( int_val. as_bigint ( ) . to_usize ( ) . unwrap_or ( 0 ) , None )
705- } else {
706- return Err ( vm. new_type_error ( "unicode string or integer address expected" ) ) ;
707- } ;
708- write ( ArrayElementWriteValue :: Pointer {
709- value : ptr_val,
710- size : element_size,
711- } ) ;
712- if let Some ( c) = converted {
713- return zelf. 0 . keep_ref ( index, c, vm) ;
714- }
715- }
716- Some ( "O" ) => {
717- // A py_object instance contributes its stored reference, while
718- // other Python objects are the value itself.
719- if value. downcast_ref :: < PyCData > ( ) . is_none ( ) {
720- write ( ArrayElementWriteValue :: Pointer {
721- value : value. get_id ( ) ,
722- size : element_size,
723- } ) ;
724- return zelf. 0 . keep_ref ( index, value. to_owned ( ) , vm) ;
725- }
726- let stg = zelf. class ( ) . stg_info ( vm) ?;
727- let element_type = stg. element_type . as_ref ( ) . unwrap ( ) ;
728- if !value. fast_isinstance ( element_type) {
729- return Err ( vm. new_type_error ( format ! (
730- "expected {} instance, not {}" ,
731- element_type. name( ) ,
732- value. class( ) . name( )
733- ) ) ) ;
734- }
735- let cdata = value. downcast_ref :: < PyCData > ( ) . unwrap ( ) ;
736- let bytes = cdata. buffer . read ( ) . to_vec ( ) ;
737- write ( ArrayElementWriteValue :: Bytes {
738- bytes : & bytes,
739- size : element_size,
740- } ) ;
741- }
742- Some ( "f" ) => {
743- // c_float: convert int/float to f32 bytes
744- let f32_val = if let Ok ( float_val) = value. try_float ( vm) {
745- float_val. to_f64 ( ) as f32
746- } else if let Ok ( int_val) = value. try_int ( vm) {
747- int_val. as_bigint ( ) . to_f64 ( ) . unwrap_or ( 0.0 ) as f32
748- } else {
749- return Err ( vm. new_type_error ( "a float is required" ) ) ;
750- } ;
751- write ( ArrayElementWriteValue :: Float {
752- value : f32_val. into ( ) ,
753- size : 4 ,
754- } ) ;
755- }
756- Some ( "d" | "g" ) => {
757- // c_double / c_longdouble: convert int/float to f64 bytes
758- let f64_val = if let Ok ( float_val) = value. try_float ( vm) {
759- float_val. to_f64 ( )
760- } else if let Ok ( int_val) = value. try_int ( vm) {
761- int_val. as_bigint ( ) . to_f64 ( ) . unwrap_or ( 0.0 )
762- } else {
763- return Err ( vm. new_type_error ( "a float is required" ) ) ;
764- } ;
765- write ( ArrayElementWriteValue :: Float {
766- value : f64_val,
767- size : 8 ,
768- } ) ;
769- // For "g" type, remaining bytes stay zero
770- }
771- _ => {
772- // Handle ctypes instances (copy their buffer)
773- if let Some ( cdata) = value. downcast_ref :: < PyCData > ( ) {
774- let src_buffer = cdata. buffer . read ( ) . to_vec ( ) ;
775- write ( ArrayElementWriteValue :: Bytes {
776- bytes : & src_buffer,
777- size : element_size,
778- } ) ;
779- // Other types: use int_to_bytes
780- } else if let Ok ( int_val) = value. try_int ( vm) {
781- let bytes = Self :: int_to_bytes ( int_val. as_bigint ( ) , element_size) ;
782- write ( ArrayElementWriteValue :: Bytes {
783- bytes : & bytes,
784- size : element_size,
785- } ) ;
786- } else {
787- return Err ( vm. new_type_error ( format ! (
788- "expected {} instance, not {}" ,
789- type_code. unwrap_or( "value" ) ,
790- value. class( ) . name( )
791- ) ) ) ;
792- }
793- }
794- }
795-
796- // KeepRef
797- if super :: base:: PyCData :: should_keep_ref ( value) {
798- zelf. 0 . keep_cdata ( index, value, vm) ?;
799- }
800-
801- Ok ( ( ) )
802- }
803-
804591 fn setitem_by_index (
805592 zelf : & Py < Self > ,
806593 i : isize ,
807594 value : & PyObject ,
808595 vm : & VirtualMachine ,
809596 ) -> PyResult < ( ) > {
810- let stg = zelf. class ( ) . stg_info_opt ( ) ;
811- let length = stg. as_ref ( ) . map_or ( 0 , |i| i. length ) as isize ;
597+ let ( length, element_size, element_type) = {
598+ let stg = zelf. class ( ) . stg_info ( vm) ?;
599+ (
600+ stg. length as isize ,
601+ stg. element_size ,
602+ stg. element_type
603+ . clone ( )
604+ . ok_or_else ( || vm. new_type_error ( "no element type" ) ) ?,
605+ )
606+ } ;
812607 let index = if i < 0 { length + i } else { i } ;
813608 if index < 0 || index >= length {
814609 return Err ( vm. new_index_error ( "invalid index" ) ) ;
815610 }
816611 let index = index as usize ;
817- let element_size = stg. as_ref ( ) . map_or ( 0 , |i| i. element_size ) ;
818- let offset = index * element_size;
819- let type_code = Self :: get_element_type_code ( zelf, vm) ;
820-
821- if let Some ( element_type) = stg. as_ref ( ) . and_then ( |info| info. element_type . as_ref ( ) )
822- && super :: simple:: is_swapped ( element_type)
823- && value. downcast_ref :: < PyCData > ( ) . is_none ( )
824- {
825- let type_code = type_code
826- . as_deref ( )
827- . ok_or_else ( || vm. new_type_error ( "no _type_ attribute" ) ) ?;
828- let bytes = super :: simple:: swapped_value_bytes ( type_code, value, vm) ?;
829- zelf. 0 . write_bytes_at_offset ( offset, & bytes) ;
830- return Ok ( ( ) ) ;
831- }
832-
833- // A view's buffer already points to its element. Its base can be a
834- // pointer object, whose own buffer stores an address rather than data.
835- Self :: write_element_to_buffer (
836- offset,
837- element_size,
838- type_code. as_deref ( ) ,
612+ let prepared = super :: base:: CDataValue :: new (
613+ & element_type,
839614 value,
840- zelf ,
841- index ,
615+ element_size ,
616+ super :: simple :: is_swapped ( & element_type ) ,
842617 vm,
843- )
618+ ) ?;
619+ // A view's buffer already points to its element. Its base can be a
620+ // pointer object, whose own buffer stores an address rather than data.
621+ zelf. 0
622+ . write_bytes_at_offset ( index * element_size, & prepared. bytes ) ;
623+ prepared. keep ( & zelf. 0 , index, vm)
844624 }
845625
846626 // Array_subscript
0 commit comments