66// option. This file may not be copied, modified, or distributed
77// except according to those terms.
88
9+ use std:: mem:: { size_of, ManuallyDrop } ;
910use alloc:: slice;
1011use alloc:: vec;
1112use alloc:: vec:: Vec ;
@@ -1583,8 +1584,11 @@ where
15831584 }
15841585 }
15851586
1586- /// Convert an array or array view to another with the same type, but
1587- /// different dimensionality type. Errors if the dimensions don't agree.
1587+ /// Convert an array or array view to another with the same type, but different dimensionality
1588+ /// type. Errors if the dimensions don't agree (the number of axes must match).
1589+ ///
1590+ /// Note that conversion to a dynamic dimensional array will never fail (and is equivalent to
1591+ /// the `into_dyn` method).
15881592 ///
15891593 /// ```
15901594 /// use ndarray::{ArrayD, Ix2, IxDyn};
@@ -1600,15 +1604,29 @@ where
16001604 where
16011605 D2 : Dimension ,
16021606 {
1603- if let Some ( dim) = D2 :: from_dimension ( & self . dim ) {
1604- if let Some ( strides) = D2 :: from_dimension ( & self . strides ) {
1607+ if D :: NDIM == D2 :: NDIM {
1608+ // safe because D == D2
1609+ unsafe {
1610+ let dim = unlimited_transmute :: < D , D2 > ( self . dim ) ;
1611+ let strides = unlimited_transmute :: < D , D2 > ( self . strides ) ;
16051612 return Ok ( ArrayBase {
16061613 data : self . data ,
16071614 ptr : self . ptr ,
16081615 dim,
16091616 strides,
16101617 } ) ;
16111618 }
1619+ } else if D :: NDIM == None || D2 :: NDIM == None { // one is dynamic dim
1620+ if let Some ( dim) = D2 :: from_dimension ( & self . dim ) {
1621+ if let Some ( strides) = D2 :: from_dimension ( & self . strides ) {
1622+ return Ok ( ArrayBase {
1623+ data : self . data ,
1624+ ptr : self . ptr ,
1625+ dim,
1626+ strides,
1627+ } ) ;
1628+ }
1629+ }
16121630 }
16131631 Err ( ShapeError :: from_kind ( ErrorKind :: IncompatibleShape ) )
16141632 }
@@ -2375,3 +2393,18 @@ where
23752393 } ) ;
23762394 }
23772395}
2396+
2397+
2398+ /// Transmute from A to B.
2399+ ///
2400+ /// Like transmute, but does not have the compile-time size check which blocks
2401+ /// using regular transmute in some cases.
2402+ ///
2403+ /// **Panics** if the size of A and B are different.
2404+ #[ inline]
2405+ unsafe fn unlimited_transmute < A , B > ( data : A ) -> B {
2406+ // safe when sizes are equal and caller guarantees that representations are equal
2407+ assert_eq ! ( size_of:: <A >( ) , size_of:: <B >( ) ) ;
2408+ let old_data = ManuallyDrop :: new ( data) ;
2409+ ( & * old_data as * const A as * const B ) . read ( )
2410+ }
0 commit comments