@@ -393,6 +393,170 @@ impl PyCArray {
393393 Err ( vm. new_type_error ( "expected bytes" . to_owned ( ) ) )
394394 }
395395 }
396+
397+ #[ pyclassmethod]
398+ fn from_address ( cls : PyTypeRef , address : isize , vm : & VirtualMachine ) -> PyResult {
399+ use crate :: function:: Either ;
400+ use crate :: stdlib:: ctypes:: _ctypes:: size_of;
401+
402+ // Get size from cls
403+ let size = size_of ( Either :: A ( cls. clone ( ) ) , vm) ?;
404+
405+ // Create instance with data from address
406+ if address != 0 && size > 0 {
407+ unsafe {
408+ let ptr = address as * const u8 ;
409+ let bytes = std:: slice:: from_raw_parts ( ptr, size) ;
410+ // Get element type and length from cls
411+ let element_type = cls. as_object ( ) . get_attr ( "_type_" , vm) ?;
412+ let element_type: PyTypeRef = element_type
413+ . downcast ( )
414+ . map_err ( |_| vm. new_type_error ( "_type_ must be a type" . to_owned ( ) ) ) ?;
415+ let length = cls
416+ . as_object ( )
417+ . get_attr ( "_length_" , vm) ?
418+ . try_int ( vm) ?
419+ . as_bigint ( )
420+ . to_usize ( )
421+ . unwrap_or ( 0 ) ;
422+ let element_size = if length > 0 { size / length } else { 0 } ;
423+
424+ Ok ( PyCArray {
425+ typ : PyRwLock :: new ( element_type) ,
426+ length : AtomicCell :: new ( length) ,
427+ element_size : AtomicCell :: new ( element_size) ,
428+ buffer : PyRwLock :: new ( bytes. to_vec ( ) ) ,
429+ }
430+ . into_pyobject ( vm) )
431+ }
432+ } else {
433+ Err ( vm. new_value_error ( "NULL pointer access" . to_owned ( ) ) )
434+ }
435+ }
436+
437+ #[ pyclassmethod]
438+ fn from_buffer (
439+ cls : PyTypeRef ,
440+ source : PyObjectRef ,
441+ offset : crate :: function:: OptionalArg < isize > ,
442+ vm : & VirtualMachine ,
443+ ) -> PyResult {
444+ use crate :: TryFromObject ;
445+ use crate :: function:: Either ;
446+ use crate :: protocol:: PyBuffer ;
447+ use crate :: stdlib:: ctypes:: _ctypes:: size_of;
448+
449+ let offset = offset. unwrap_or ( 0 ) ;
450+ if offset < 0 {
451+ return Err ( vm. new_value_error ( "offset cannot be negative" . to_owned ( ) ) ) ;
452+ }
453+ let offset = offset as usize ;
454+
455+ // Get buffer from source
456+ let buffer = PyBuffer :: try_from_object ( vm, source. clone ( ) ) ?;
457+
458+ // Check if buffer is writable
459+ if buffer. desc . readonly {
460+ return Err ( vm. new_type_error ( "underlying buffer is not writable" . to_owned ( ) ) ) ;
461+ }
462+
463+ // Get size from cls
464+ let size = size_of ( Either :: A ( cls. clone ( ) ) , vm) ?;
465+
466+ // Check if buffer is large enough
467+ let buffer_len = buffer. desc . len ;
468+ if offset + size > buffer_len {
469+ return Err ( vm. new_value_error ( format ! (
470+ "Buffer size too small ({} instead of at least {} bytes)" ,
471+ buffer_len,
472+ offset + size
473+ ) ) ) ;
474+ }
475+
476+ // Read bytes from buffer at offset
477+ let bytes = buffer. obj_bytes ( ) ;
478+ let data = & bytes[ offset..offset + size] ;
479+
480+ // Get element type and length from cls
481+ let element_type = cls. as_object ( ) . get_attr ( "_type_" , vm) ?;
482+ let element_type: PyTypeRef = element_type
483+ . downcast ( )
484+ . map_err ( |_| vm. new_type_error ( "_type_ must be a type" . to_owned ( ) ) ) ?;
485+ let length = cls
486+ . as_object ( )
487+ . get_attr ( "_length_" , vm) ?
488+ . try_int ( vm) ?
489+ . as_bigint ( )
490+ . to_usize ( )
491+ . unwrap_or ( 0 ) ;
492+ let element_size = if length > 0 { size / length } else { 0 } ;
493+
494+ Ok ( PyCArray {
495+ typ : PyRwLock :: new ( element_type) ,
496+ length : AtomicCell :: new ( length) ,
497+ element_size : AtomicCell :: new ( element_size) ,
498+ buffer : PyRwLock :: new ( data. to_vec ( ) ) ,
499+ }
500+ . into_pyobject ( vm) )
501+ }
502+
503+ #[ pyclassmethod]
504+ fn from_buffer_copy (
505+ cls : PyTypeRef ,
506+ source : crate :: function:: ArgBytesLike ,
507+ offset : crate :: function:: OptionalArg < isize > ,
508+ vm : & VirtualMachine ,
509+ ) -> PyResult {
510+ use crate :: function:: Either ;
511+ use crate :: stdlib:: ctypes:: _ctypes:: size_of;
512+
513+ let offset = offset. unwrap_or ( 0 ) ;
514+ if offset < 0 {
515+ return Err ( vm. new_value_error ( "offset cannot be negative" . to_owned ( ) ) ) ;
516+ }
517+ let offset = offset as usize ;
518+
519+ // Get size from cls
520+ let size = size_of ( Either :: A ( cls. clone ( ) ) , vm) ?;
521+
522+ // Borrow bytes from source
523+ let source_bytes = source. borrow_buf ( ) ;
524+ let buffer_len = source_bytes. len ( ) ;
525+
526+ // Check if buffer is large enough
527+ if offset + size > buffer_len {
528+ return Err ( vm. new_value_error ( format ! (
529+ "Buffer size too small ({} instead of at least {} bytes)" ,
530+ buffer_len,
531+ offset + size
532+ ) ) ) ;
533+ }
534+
535+ // Copy bytes from buffer at offset
536+ let data = & source_bytes[ offset..offset + size] ;
537+
538+ // Get element type and length from cls
539+ let element_type = cls. as_object ( ) . get_attr ( "_type_" , vm) ?;
540+ let element_type: PyTypeRef = element_type
541+ . downcast ( )
542+ . map_err ( |_| vm. new_type_error ( "_type_ must be a type" . to_owned ( ) ) ) ?;
543+ let length = cls
544+ . as_object ( )
545+ . get_attr ( "_length_" , vm) ?
546+ . try_int ( vm) ?
547+ . as_bigint ( )
548+ . to_usize ( )
549+ . unwrap_or ( 0 ) ;
550+ let element_size = if length > 0 { size / length } else { 0 } ;
551+
552+ Ok ( PyCArray {
553+ typ : PyRwLock :: new ( element_type) ,
554+ length : AtomicCell :: new ( length) ,
555+ element_size : AtomicCell :: new ( element_size) ,
556+ buffer : PyRwLock :: new ( data. to_vec ( ) ) ,
557+ }
558+ . into_pyobject ( vm) )
559+ }
396560}
397561
398562impl PyCArray {
0 commit comments