@@ -570,17 +570,6 @@ impl PyUntypedBuffer {
570570 self . raw ( ) . buf
571571 }
572572
573- /// Returns the Python object that owns the buffer data.
574- ///
575- /// This is the object that was passed to [`PyBuffer::get()`]
576- /// when the buffer was created.
577- /// Calling this before [`release()`][Self::release] and cloning the result
578- /// allows you to keep the object alive after the buffer is released.
579- #[ inline]
580- pub fn obj < ' py > ( & self , py : Python < ' py > ) -> Option < & Bound < ' py , PyAny > > {
581- unsafe { Bound :: ref_from_ptr_or_opt ( py, & self . raw ( ) . obj ) . as_ref ( ) }
582- }
583-
584573 /// Gets a pointer to the specified item.
585574 ///
586575 /// If `indices.len() < self.dimensions()`, returns the start address of the sub-array at the specified dimension.
@@ -1288,6 +1277,27 @@ mod tests {
12881277 ( c"=d" , Float { bytes : 8 } ) ,
12891278 ( c"=z" , Unknown ) ,
12901279 ( c"=0" , Unknown ) ,
1280+ // bare char (no prefix) goes to native_element_type_from_type_char
1281+ (
1282+ c"b" ,
1283+ SignedInteger {
1284+ bytes : size_of :: < c_schar > ( ) ,
1285+ } ,
1286+ ) ,
1287+ (
1288+ c"B" ,
1289+ UnsignedInteger {
1290+ bytes : size_of :: < c_uchar > ( ) ,
1291+ } ,
1292+ ) ,
1293+ ( c"?" , Bool ) ,
1294+ ( c"f" , Float { bytes : 4 } ) ,
1295+ ( c"d" , Float { bytes : 8 } ) ,
1296+ ( c"z" , Unknown ) ,
1297+ // <, >, ! prefixes go to standard_element_type_from_type_char
1298+ ( c"<i" , SignedInteger { bytes : 4 } ) ,
1299+ ( c">H" , UnsignedInteger { bytes : 2 } ) ,
1300+ ( c"!q" , SignedInteger { bytes : 8 } ) ,
12911301 // unknown prefix -> Unknown
12921302 ( c":b" , Unknown ) ,
12931303 ] {
@@ -1325,6 +1335,7 @@ mod tests {
13251335 assert_eq ! ( slice. len( ) , 5 ) ;
13261336 assert_eq ! ( slice[ 0 ] . get( ) , b'a' ) ;
13271337 assert_eq ! ( slice[ 2 ] . get( ) , b'c' ) ;
1338+ assert_eq ! ( unsafe { * slice[ 0 ] . as_ptr( ) } , b'a' ) ;
13281339
13291340 assert_eq ! ( unsafe { * ( buffer. get_ptr( & [ 1 ] ) . cast:: <u8 >( ) ) } , b'b' ) ;
13301341
@@ -1398,47 +1409,67 @@ mod tests {
13981409 } ) ;
13991410 }
14001411
1412+ #[ test]
1413+ fn test_copy_to_fortran_slice ( ) {
1414+ Python :: attach ( |py| {
1415+ let array = py
1416+ . import ( "array" )
1417+ . unwrap ( )
1418+ . call_method ( "array" , ( "f" , ( 1.0 , 1.5 , 2.0 , 2.5 ) ) , None )
1419+ . unwrap ( ) ;
1420+ let buffer = PyBuffer :: get ( & array) . unwrap ( ) ;
1421+
1422+ // wrong length
1423+ assert ! ( buffer. copy_to_fortran_slice( py, & mut [ 0.0f32 ] ) . is_err( ) ) ;
1424+ // correct length
1425+ let mut arr = [ 0.0f32 ; 4 ] ;
1426+ buffer. copy_to_fortran_slice ( py, & mut arr) . unwrap ( ) ;
1427+ assert_eq ! ( arr, [ 1.0 , 1.5 , 2.0 , 2.5 ] ) ;
1428+ } ) ;
1429+ }
1430+
1431+ #[ test]
1432+ fn test_copy_from_slice_wrong_length ( ) {
1433+ Python :: attach ( |py| {
1434+ let array = py
1435+ . import ( "array" )
1436+ . unwrap ( )
1437+ . call_method ( "array" , ( "f" , ( 1.0 , 1.5 , 2.0 , 2.5 ) ) , None )
1438+ . unwrap ( ) ;
1439+ let buffer = PyBuffer :: get ( & array) . unwrap ( ) ;
1440+ // writable buffer, but wrong length
1441+ assert ! ( !buffer. readonly( ) ) ;
1442+ assert ! ( buffer. copy_from_slice( py, & [ 0.0f32 ; 2 ] ) . is_err( ) ) ;
1443+ assert ! ( buffer. copy_from_fortran_slice( py, & [ 0.0f32 ; 2 ] ) . is_err( ) ) ;
1444+ } ) ;
1445+ }
1446+
14011447 #[ test]
14021448 fn test_untyped_buffer ( ) {
14031449 Python :: attach ( |py| {
14041450 let bytes = PyBytes :: new ( py, b"abcde" ) ;
1405- let untyped = PyUntypedBuffer :: get ( & bytes) . unwrap ( ) ;
1406- assert_eq ! ( untyped. dimensions( ) , 1 ) ;
1407- assert_eq ! ( untyped. item_count( ) , 5 ) ;
1408- assert_eq ! ( untyped. format( ) . to_str( ) . unwrap( ) , "B" ) ;
1409- assert_eq ! ( untyped. shape( ) , [ 5 ] ) ;
1451+ let buffer = PyUntypedBuffer :: get ( & bytes) . unwrap ( ) ;
1452+ assert_eq ! ( buffer. dimensions( ) , 1 ) ;
1453+ assert_eq ! ( buffer. item_count( ) , 5 ) ;
1454+ assert_eq ! ( buffer. format( ) . to_str( ) . unwrap( ) , "B" ) ;
1455+ assert_eq ! ( buffer. shape( ) , [ 5 ] ) ;
1456+ assert ! ( !buffer. buf_ptr( ) . is_null( ) ) ;
1457+ assert_eq ! ( buffer. strides( ) , & [ 1 ] ) ;
1458+ assert_eq ! ( buffer. len_bytes( ) , 5 ) ;
1459+ assert_eq ! ( buffer. item_size( ) , 1 ) ;
1460+ assert ! ( buffer. readonly( ) ) ;
1461+ assert ! ( buffer. suboffsets( ) . is_none( ) ) ;
14101462
1411- let typed: & PyBuffer < u8 > = untyped. as_typed ( ) . unwrap ( ) ;
1463+ assert ! ( format!( "{:?}" , buffer) . starts_with( "PyUntypedBuffer { buf: " ) ) ;
1464+
1465+ let typed: & PyBuffer < u8 > = buffer. as_typed ( ) . unwrap ( ) ;
14121466 assert_eq ! ( typed. dimensions( ) , 1 ) ;
14131467 assert_eq ! ( typed. item_count( ) , 5 ) ;
14141468 assert_eq ! ( typed. format( ) . to_str( ) . unwrap( ) , "B" ) ;
14151469 assert_eq ! ( typed. shape( ) , [ 5 ] ) ;
14161470 } ) ;
14171471 }
14181472
1419- #[ test]
1420- fn test_obj_getter ( ) {
1421- Python :: attach ( |py| {
1422- let bytes = PyBytes :: new ( py, b"hello" ) ;
1423- let buf = PyUntypedBuffer :: get ( bytes. as_any ( ) ) . unwrap ( ) ;
1424-
1425- // obj() returns the same object that owns the buffer
1426- let owner = buf. obj ( py) . unwrap ( ) ;
1427- assert ! ( owner. is_instance_of:: <PyBytes >( ) ) ;
1428- assert ! ( owner. is( & bytes) ) ;
1429-
1430- // can keep the owner alive after releasing the buffer
1431- let owner_ref: crate :: Py < PyAny > = owner. clone ( ) . unbind ( ) ;
1432- buf. release ( py) ;
1433- drop ( bytes) ;
1434- // owner_ref still valid after buffer and original are dropped
1435- Python :: attach ( |py| {
1436- let rebound = owner_ref. bind ( py) ;
1437- assert ! ( rebound. is_instance_of:: <PyBytes >( ) ) ;
1438- } ) ;
1439- } ) ;
1440- }
1441-
14421473 #[ test]
14431474 fn test_untyped_buffer_view ( ) {
14441475 Python :: attach ( |py| {
@@ -1536,6 +1567,48 @@ mod tests {
15361567 } ) ;
15371568 }
15381569
1570+ #[ test]
1571+ fn test_typed_buffer_view_with_flags ( ) {
1572+ Python :: attach ( |py| {
1573+ let array = py
1574+ . import ( "array" )
1575+ . unwrap ( )
1576+ . call_method ( "array" , ( "f" , ( 1.0 , 1.5 , 2.0 , 2.5 ) ) , None )
1577+ . unwrap ( ) ;
1578+
1579+ PyBufferView :: < f32 , Known , Unknown , Unknown > :: with_flags (
1580+ & array,
1581+ ffi:: PyBUF_ND ,
1582+ |view| {
1583+ assert_eq ! ( view. item_count( ) , 4 ) ;
1584+ assert_eq ! ( view. format( ) . to_str( ) . unwrap( ) , "f" ) ;
1585+
1586+ let slice = view. as_slice ( py) . unwrap ( ) ;
1587+ assert_eq ! ( slice[ 0 ] . get( ) , 1.0 ) ;
1588+ assert_eq ! ( slice[ 3 ] . get( ) , 2.5 ) ;
1589+
1590+ let mut_slice = view. as_mut_slice ( py) . unwrap ( ) ;
1591+ mut_slice[ 0 ] . set ( 9.0 ) ;
1592+ assert_eq ! ( slice[ 0 ] . get( ) , 9.0 ) ;
1593+ } ,
1594+ )
1595+ . unwrap ( ) ;
1596+ } ) ;
1597+ }
1598+
1599+ #[ test]
1600+ fn test_typed_buffer_view_with_flags_incompatible ( ) {
1601+ Python :: attach ( |py| {
1602+ let bytes = PyBytes :: new ( py, b"abcde" ) ;
1603+ let result = PyBufferView :: < f32 , Known , Unknown , Unknown > :: with_flags (
1604+ & bytes,
1605+ ffi:: PyBUF_ND ,
1606+ |_view| { } ,
1607+ ) ;
1608+ assert ! ( result. is_err( ) ) ;
1609+ } ) ;
1610+ }
1611+
15391612 #[ test]
15401613 fn test_buffer_view_error ( ) {
15411614 Python :: attach ( |py| {
0 commit comments