@@ -595,10 +595,85 @@ where
595
595
}
596
596
}
597
597
598
+ impl < B , T > Ref < B , T >
599
+ where
600
+ B : ByteSlice ,
601
+ T : KnownLayout + ?Sized ,
602
+ {
603
+ /// Attempts to dereference this `Ref<_, T>` into a `&T` without copying.
604
+ ///
605
+ /// If the bytes of `self` are a valid instance of `T`, this method returns
606
+ /// a reference to those bytes interpreted as `T`. If those bytes are not a
607
+ /// valid instance of `T`, this returns `Err`.
608
+ ///
609
+ /// # Examples
610
+ ///
611
+ /// ```
612
+ /// use zerocopy::Ref;
613
+ /// # use zerocopy_derive::*;
614
+ ///
615
+ /// // The only valid value of this type is the byte `0xC0`
616
+ /// #[derive(TryFromBytes, KnownLayout, Immutable)]
617
+ /// #[repr(u8)]
618
+ /// enum C0 { xC0 = 0xC0 }
619
+ ///
620
+ /// // The only valid value of this type is the bytes `0xC0C0`.
621
+ /// #[derive(TryFromBytes, KnownLayout, Immutable)]
622
+ /// #[repr(C, packed)]
623
+ /// struct C0C0(C0, C0);
624
+ ///
625
+ /// #[derive(TryFromBytes, KnownLayout, Immutable)]
626
+ /// #[repr(C)]
627
+ /// struct Packet {
628
+ /// magic_number: C0C0,
629
+ /// mug_size: u8,
630
+ /// temperature: u8,
631
+ /// marshmallows: [[u8; 2]],
632
+ /// }
633
+ ///
634
+ /// let bytes = &[0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5][..];
635
+ ///
636
+ /// let r = Ref::<_, Packet>::new(bytes).unwrap();
637
+ /// let packet = Ref::try_as_ref(r).unwrap();
638
+ ///
639
+ /// assert_eq!(packet.mug_size, 240);
640
+ /// assert_eq!(packet.temperature, 77);
641
+ /// assert_eq!(packet.marshmallows, [[0, 1], [2, 3], [4, 5]]);
642
+ /// ```
643
+ #[ must_use = "has no side effects" ]
644
+ #[ inline( always) ]
645
+ pub fn try_as_ref ( r : & Self ) -> Result < & T , ValidityError < & Self , T > >
646
+ where
647
+ T : TryFromBytes + Immutable ,
648
+ {
649
+ // Presumably unreachable, since we've guarded each constructor of `Ref`.
650
+ static_assert_dst_is_not_zst ! ( T ) ;
651
+
652
+ // SAFETY: We don't call any methods on `r` other than those provided by
653
+ // `ByteSlice`.
654
+ let b = unsafe { r. as_byte_slice ( ) } ;
655
+
656
+ match Ptr :: from_ref ( b. deref ( ) ) . try_cast_into_no_leftover :: < T , BecauseImmutable > ( None ) {
657
+ Ok ( candidate) => match candidate. try_into_valid ( ) {
658
+ Ok ( valid) => Ok ( valid. as_ref ( ) ) ,
659
+ Err ( e) => Err ( e. map_src ( |_| r) ) ,
660
+ } ,
661
+ Err ( CastError :: Validity ( i) ) => match i { } ,
662
+ Err ( CastError :: Alignment ( _) | CastError :: Size ( _) ) => {
663
+ // SAFETY: By invariant on `Ref::0`, the referenced byte slice
664
+ // is aligned to `T`'s alignment and its size corresponds to a
665
+ // valid size for `T`. Since properties are checked upon
666
+ // constructing `Ref`, these failures are unreachable.
667
+ unsafe { core:: hint:: unreachable_unchecked ( ) }
668
+ }
669
+ }
670
+ }
671
+ }
672
+
598
673
impl < ' a , B , T > Ref < B , T >
599
674
where
600
675
B : ' a + IntoByteSlice < ' a > ,
601
- T : FromBytes + KnownLayout + Immutable + ?Sized ,
676
+ T : TryFromBytes + KnownLayout + Immutable + ?Sized ,
602
677
{
603
678
/// Converts this `Ref` into a reference.
604
679
///
@@ -609,7 +684,10 @@ where
609
684
/// there is no conflict with a method on the inner type.
610
685
#[ must_use = "has no side effects" ]
611
686
#[ inline( always) ]
612
- pub fn into_ref ( r : Self ) -> & ' a T {
687
+ pub fn into_ref ( r : Self ) -> & ' a T
688
+ where
689
+ T : FromBytes ,
690
+ {
613
691
// Presumably unreachable, since we've guarded each constructor of `Ref`.
614
692
static_assert_dst_is_not_zst ! ( T ) ;
615
693
@@ -627,12 +705,91 @@ where
627
705
let ptr = ptr. bikeshed_recall_valid ( ) ;
628
706
ptr. as_ref ( )
629
707
}
708
+
709
+ /// Attempts to convert this `Ref<_, T>` into a `&T` without copying.
710
+ ///
711
+ /// If the bytes of `self` are a valid instance of `T`, this method returns
712
+ /// a reference to those bytes interpreted as `T`. If those bytes are not a
713
+ /// valid instance of `T`, this returns `Err`.
714
+ ///
715
+ /// # Examples
716
+ ///
717
+ /// ```
718
+ /// use zerocopy::Ref;
719
+ /// # use zerocopy_derive::*;
720
+ ///
721
+ /// // The only valid value of this type is the byte `0xC0`
722
+ /// #[derive(TryFromBytes, KnownLayout, Immutable)]
723
+ /// #[repr(u8)]
724
+ /// enum C0 { xC0 = 0xC0 }
725
+ ///
726
+ /// // The only valid value of this type is the bytes `0xC0C0`.
727
+ /// #[derive(TryFromBytes, KnownLayout, Immutable)]
728
+ /// #[repr(C, packed)]
729
+ /// struct C0C0(C0, C0);
730
+ ///
731
+ /// #[derive(TryFromBytes, KnownLayout, Immutable)]
732
+ /// #[repr(C)]
733
+ /// struct Packet {
734
+ /// magic_number: C0C0,
735
+ /// mug_size: u8,
736
+ /// temperature: u8,
737
+ /// marshmallows: [[u8; 2]],
738
+ /// }
739
+ ///
740
+ /// let bytes = &[0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5][..];
741
+ ///
742
+ /// let r = Ref::<_, Packet>::new(bytes).unwrap();
743
+ /// let packet = Ref::try_into_ref(r).unwrap();
744
+ ///
745
+ /// assert_eq!(packet.mug_size, 240);
746
+ /// assert_eq!(packet.temperature, 77);
747
+ /// assert_eq!(packet.marshmallows, [[0, 1], [2, 3], [4, 5]]);
748
+ /// ```
749
+ #[ must_use = "has no side effects" ]
750
+ #[ inline( always) ]
751
+ pub fn try_into_ref ( r : Self ) -> Result < & ' a T , ValidityError < Self , T > > {
752
+ // Presumably unreachable, since we've guarded each constructor of `Ref`.
753
+ static_assert_dst_is_not_zst ! ( T ) ;
754
+
755
+ // SAFETY: We don't call any methods on `b` other than those provided by
756
+ // `ByteSlice`.
757
+ let bytes = unsafe { r. as_byte_slice ( ) } ;
758
+
759
+ let bytes: & ' _ [ u8 ] = bytes. deref ( ) ;
760
+
761
+ // Extend the lifetime of `bytes` to `'a`. This gives us a reference
762
+ // `bytes` with the same lifetime as if we had called
763
+ // `r.into_byte_slice()`, but without consuming `r`. This is valuable,
764
+ // since we will need to return `r` if validation fails.
765
+ //
766
+ // SAFETY: This is sound because `bytes` lives for `'a`. `Self` is
767
+ // `IntoByteSlice`, whose `.into_byte_slice()` method is guaranteed to
768
+ // produce a `&'a [u8]` with the same address and length as the slice
769
+ // obtained by `.deref()` (which is how `bytes` is obtained).
770
+ let bytes = unsafe { mem:: transmute :: < & [ u8 ] , & ' a [ u8 ] > ( bytes) } ;
771
+
772
+ match Ptr :: from_ref ( bytes) . try_cast_into_no_leftover :: < T , BecauseImmutable > ( None ) {
773
+ Ok ( candidate) => match candidate. try_into_valid ( ) {
774
+ Ok ( candidate) => Ok ( candidate. as_ref ( ) ) ,
775
+ Err ( e) => Err ( e. with_src ( r) ) ,
776
+ } ,
777
+ Err ( CastError :: Validity ( i) ) => match i { } ,
778
+ Err ( CastError :: Alignment ( _) | CastError :: Size ( _) ) => {
779
+ // SAFETY: By invariant on `Ref::0`, the referenced byte slice
780
+ // is aligned to `T`'s alignment and its size corresponds to a
781
+ // valid size for `T`. Since properties are checked upon
782
+ // constructing `Ref`, these failures are unreachable.
783
+ unsafe { core:: hint:: unreachable_unchecked ( ) }
784
+ }
785
+ }
786
+ }
630
787
}
631
788
632
789
impl < ' a , B , T > Ref < B , T >
633
790
where
634
791
B : ' a + IntoByteSliceMut < ' a > ,
635
- T : FromBytes + IntoBytes + KnownLayout + ?Sized ,
792
+ T : TryFromBytes + IntoBytes + KnownLayout + ?Sized ,
636
793
{
637
794
/// Converts this `Ref` into a mutable reference.
638
795
///
@@ -643,7 +800,10 @@ where
643
800
/// there is no conflict with a method on the inner type.
644
801
#[ must_use = "has no side effects" ]
645
802
#[ inline( always) ]
646
- pub fn into_mut ( r : Self ) -> & ' a mut T {
803
+ pub fn into_mut ( r : Self ) -> & ' a mut T
804
+ where
805
+ T : FromBytes ,
806
+ {
647
807
// Presumably unreachable, since we've guarded each constructor of `Ref`.
648
808
static_assert_dst_is_not_zst ! ( T ) ;
649
809
@@ -661,6 +821,86 @@ where
661
821
let ptr = ptr. bikeshed_recall_valid ( ) ;
662
822
ptr. as_mut ( )
663
823
}
824
+
825
+ /// Attempts to convert this `Ref<_, T>` into a `&mut T` without copying.
826
+ ///
827
+ /// If the bytes of `self` are a valid instance of `T`, this method returns
828
+ /// a reference to those bytes interpreted as `T`. If those bytes are not a
829
+ /// valid instance of `T`, this returns `Err`.
830
+ ///
831
+ /// # Examples
832
+ ///
833
+ /// ```
834
+ /// use zerocopy::Ref;
835
+ /// # use zerocopy_derive::*;
836
+ ///
837
+ /// // The only valid value of this type is the byte `0xC0`
838
+ /// #[derive(TryFromBytes, IntoBytes, KnownLayout, Immutable)]
839
+ /// #[repr(u8)]
840
+ /// enum C0 { xC0 = 0xC0 }
841
+ ///
842
+ /// // The only valid value of this type is the bytes `0xC0C0`.
843
+ /// #[derive(TryFromBytes, IntoBytes, KnownLayout, Immutable)]
844
+ /// #[repr(C, packed)]
845
+ /// struct C0C0(C0, C0);
846
+ ///
847
+ /// #[derive(TryFromBytes, IntoBytes, KnownLayout, Immutable)]
848
+ /// #[repr(C, packed)]
849
+ /// struct Packet {
850
+ /// magic_number: C0C0,
851
+ /// mug_size: u8,
852
+ /// temperature: u8,
853
+ /// marshmallows: [[u8; 2]],
854
+ /// }
855
+ ///
856
+ /// let bytes = &mut [0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5][..];
857
+ ///
858
+ /// let r = Ref::<_, Packet>::new(bytes).unwrap();
859
+ /// let packet = Ref::try_into_mut(r).unwrap();
860
+ ///
861
+ /// assert_eq!(packet.mug_size, 240);
862
+ /// assert_eq!(packet.temperature, 77);
863
+ /// assert_eq!(packet.marshmallows, [[0, 1], [2, 3], [4, 5]]);
864
+ /// ```
865
+ #[ must_use = "has no side effects" ]
866
+ #[ inline( always) ]
867
+ pub fn try_into_mut ( mut r : Self ) -> Result < & ' a mut T , ValidityError < Self , T > > {
868
+ // Presumably unreachable, since we've guarded each constructor of `Ref`.
869
+ static_assert_dst_is_not_zst ! ( T ) ;
870
+
871
+ // SAFETY: We don't call any methods on `b` other than those provided by
872
+ // `ByteSliceMut`.
873
+ let bytes = unsafe { r. as_byte_slice_mut ( ) } ;
874
+
875
+ let bytes: & ' _ mut [ u8 ] = bytes. deref_mut ( ) ;
876
+
877
+ // Extend the lifetime of `bytes` to `'a`. This gives us a reference
878
+ // `bytes` with the same lifetime as if we had called
879
+ // `r.into_byte_slice_mut()`, but without consuming `r`. This is
880
+ // valuable, since we will need to return `r` if validation fails.
881
+ //
882
+ // SAFETY: This is sound because `bytes` lives for `'a`. `Self` is
883
+ // `IntoByteSliceMut`, whose `.into_byte_slice_mut()` method is
884
+ // guaranteed to produce a `&'a [u8]` with the same address and length
885
+ // as the slice obtained by `.deref()` (which is how `bytes` is
886
+ // obtained).
887
+ let bytes = unsafe { mem:: transmute :: < & mut [ u8 ] , & ' a mut [ u8 ] > ( bytes) } ;
888
+
889
+ match Ptr :: from_mut ( bytes) . try_cast_into_no_leftover :: < T , BecauseExclusive > ( None ) {
890
+ Ok ( candidate) => match candidate. try_into_valid ( ) {
891
+ Ok ( candidate) => Ok ( candidate. as_mut ( ) ) ,
892
+ Err ( e) => Err ( e. with_src ( r) ) ,
893
+ } ,
894
+ Err ( CastError :: Validity ( i) ) => match i { } ,
895
+ Err ( CastError :: Alignment ( _) | CastError :: Size ( _) ) => {
896
+ // SAFETY: By invariant on `Ref::0`, the referenced byte slice
897
+ // is aligned to `T`'s alignment and its size corresponds to a
898
+ // valid size for `T`. Since properties are checked upon
899
+ // constructing `Ref`, these failures are unreachable.
900
+ unsafe { core:: hint:: unreachable_unchecked ( ) }
901
+ }
902
+ }
903
+ }
664
904
}
665
905
666
906
impl < B , T > Ref < B , T >
@@ -1109,6 +1349,33 @@ mod tests {
1109
1349
assert ! ( Ref :: <_, [ AU64 ] >:: from_suffix_with_elems( & buf. t[ ..] , unreasonable_len) . is_err( ) ) ;
1110
1350
}
1111
1351
1352
+ #[ test]
1353
+ #[ allow( unstable_name_collisions) ]
1354
+ #[ allow( clippy:: as_conversions) ]
1355
+ fn test_try_as_ref ( ) {
1356
+ #[ allow( unused) ]
1357
+ use crate :: util:: AsAddress as _;
1358
+
1359
+ // valid source
1360
+
1361
+ let buf = Align :: < [ u8 ; 8 ] , u64 > :: default ( ) ;
1362
+ let buf_addr = ( & buf. t as * const [ u8 ; 8 ] ) . addr ( ) ;
1363
+
1364
+ let r = Ref :: < _ , u64 > :: from_bytes ( & buf. t [ ..] ) . unwrap ( ) ;
1365
+ let rf = Ref :: try_as_ref ( & r) . unwrap ( ) ;
1366
+ assert_eq ! ( rf, & 0u64 ) ;
1367
+ assert_eq ! ( ( rf as * const u64 ) . addr( ) , buf_addr) ;
1368
+
1369
+ // invalid source
1370
+
1371
+ let buf = Align :: < [ u8 ; 1 ] , u64 > :: new ( [ 42 ] ) ;
1372
+ let buf_addr = ( & buf. t as * const [ u8 ; 1 ] ) . addr ( ) ;
1373
+
1374
+ let r = Ref :: < _ , bool > :: from_bytes ( & buf. t [ ..] ) . unwrap ( ) ;
1375
+ let re = Ref :: try_as_ref ( & r) . unwrap_err ( ) ;
1376
+ assert_eq ! ( Ref :: bytes( re. into_src( ) ) . addr( ) , buf_addr) ;
1377
+ }
1378
+
1112
1379
#[ test]
1113
1380
#[ allow( unstable_name_collisions) ]
1114
1381
#[ allow( clippy:: as_conversions) ]
@@ -1132,6 +1399,42 @@ mod tests {
1132
1399
assert_eq ! ( buf. t, [ 0xFF ; 8 ] ) ;
1133
1400
}
1134
1401
1402
+ #[ test]
1403
+ #[ allow( unstable_name_collisions) ]
1404
+ #[ allow( clippy:: as_conversions) ]
1405
+ fn test_try_into_ref_mut ( ) {
1406
+ #[ allow( unused) ]
1407
+ use crate :: util:: AsAddress as _;
1408
+
1409
+ // valid source
1410
+
1411
+ let mut buf = Align :: < [ u8 ; 8 ] , u64 > :: default ( ) ;
1412
+ let buf_addr = ( & buf. t as * const [ u8 ; 8 ] ) . addr ( ) ;
1413
+
1414
+ let r = Ref :: < _ , u64 > :: from_bytes ( & buf. t [ ..] ) . unwrap ( ) ;
1415
+ let rf = Ref :: try_into_ref ( r) . unwrap ( ) ;
1416
+ assert_eq ! ( rf, & 0u64 ) ;
1417
+ assert_eq ! ( ( rf as * const u64 ) . addr( ) , buf_addr) ;
1418
+
1419
+ let r = Ref :: < _ , u64 > :: from_bytes ( & mut buf. t [ ..] ) . unwrap ( ) ;
1420
+ let rf = Ref :: try_into_mut ( r) . unwrap ( ) ;
1421
+ assert_eq ! ( rf, & mut 0u64 ) ;
1422
+ assert_eq ! ( ( rf as * mut u64 ) . addr( ) , buf_addr) ;
1423
+
1424
+ // invalid source
1425
+
1426
+ let mut buf = Align :: < [ u8 ; 1 ] , u64 > :: new ( [ 42 ] ) ;
1427
+ let buf_addr = ( & buf. t as * const [ u8 ; 1 ] ) . addr ( ) ;
1428
+
1429
+ let r = Ref :: < _ , bool > :: from_bytes ( & buf. t [ ..] ) . unwrap ( ) ;
1430
+ let re = Ref :: try_into_ref ( r) . unwrap_err ( ) ;
1431
+ assert_eq ! ( Ref :: bytes( & re. into_src( ) ) . addr( ) , buf_addr) ;
1432
+
1433
+ let r = Ref :: < _ , bool > :: from_bytes ( & mut buf. t [ ..] ) . unwrap ( ) ;
1434
+ let re = Ref :: try_into_mut ( r) . unwrap_err ( ) ;
1435
+ assert_eq ! ( Ref :: bytes( & re. into_src( ) ) . addr( ) , buf_addr) ;
1436
+ }
1437
+
1135
1438
#[ test]
1136
1439
fn test_display_debug ( ) {
1137
1440
let buf = Align :: < [ u8 ; 8 ] , u64 > :: default ( ) ;
0 commit comments