@@ -733,6 +733,268 @@ macro_rules! include_value {
733
733
} ;
734
734
}
735
735
736
+ #[ doc( hidden) ]
737
+ #[ macro_export]
738
+ macro_rules! cryptocorrosion_derive_traits {
739
+ (
740
+ #[ repr( $repr: ident) ]
741
+ $( #[ $attr: meta] ) *
742
+ $vis: vis struct $name: ident $( <$( $tyvar: ident) ,* >) ?
743
+ $(
744
+ (
745
+ $( $tuple_field_vis: vis $tuple_field_ty: ty) ,*
746
+ ) ;
747
+ ) ?
748
+
749
+ $(
750
+ {
751
+ $( $field_vis: vis $field_name: ident: $field_ty: ty, ) *
752
+ }
753
+ ) ?
754
+ ) => {
755
+ $crate:: cryptocorrosion_derive_traits!( @assert_allowed_struct_repr #[ repr( $repr) ] ) ;
756
+
757
+ $( #[ $attr] ) *
758
+ #[ repr( $repr) ]
759
+ $vis struct $name $( <$( $tyvar) ,* >) ?
760
+ $(
761
+ (
762
+ $( $tuple_field_vis $tuple_field_ty) ,*
763
+ ) ;
764
+ ) ?
765
+
766
+ $(
767
+ {
768
+ $( $field_vis $field_name: $field_ty, ) *
769
+ }
770
+ ) ?
771
+
772
+ // SAFETY: See inline.
773
+ unsafe impl $( <$( $tyvar) ,* >) ? $crate:: TryFromBytes for $name$( <$( $tyvar) ,* >) ?
774
+ where
775
+ $(
776
+ $( $tuple_field_ty: $crate:: FromBytes , ) *
777
+ ) ?
778
+
779
+ $(
780
+ $( $field_ty: $crate:: FromBytes , ) *
781
+ ) ?
782
+ {
783
+ fn is_bit_valid<A >( _c: $crate:: Maybe <' _, Self , A >) -> bool
784
+ where
785
+ A : $crate:: pointer:: invariant:: Reference
786
+ {
787
+ // SAFETY: This macro only accepts `#[repr(C)]` and
788
+ // `#[repr(transparent)]` structs, and this `impl` block
789
+ // requires all field types to be `FromBytes`. Thus, all
790
+ // initialized byte sequences constitutes valid instances of
791
+ // `Self`.
792
+ true
793
+ }
794
+
795
+ fn only_derive_is_allowed_to_implement_this_trait( ) { }
796
+ }
797
+
798
+ // SAFETY: This macro only accepts `#[repr(C)]` and
799
+ // `#[repr(transparent)]` structs, and this `impl` block requires all
800
+ // field types to be `FromBytes`, which is a sub-trait of `FromZeros`.
801
+ unsafe impl $( <$( $tyvar) ,* >) ? $crate:: FromZeros for $name$( <$( $tyvar) ,* >) ?
802
+ where
803
+ $(
804
+ $( $tuple_field_ty: $crate:: FromBytes , ) *
805
+ ) ?
806
+
807
+ $(
808
+ $( $field_ty: $crate:: FromBytes , ) *
809
+ ) ?
810
+ {
811
+ fn only_derive_is_allowed_to_implement_this_trait( ) { }
812
+ }
813
+
814
+ // SAFETY: This macro only accepts `#[repr(C)]` and
815
+ // `#[repr(transparent)]` structs, and this `impl` block requires all
816
+ // field types to be `FromBytes`.
817
+ unsafe impl $( <$( $tyvar) ,* >) ? $crate:: FromBytes for $name$( <$( $tyvar) ,* >) ?
818
+ where
819
+ $(
820
+ $( $tuple_field_ty: $crate:: FromBytes , ) *
821
+ ) ?
822
+
823
+ $(
824
+ $( $field_ty: $crate:: FromBytes , ) *
825
+ ) ?
826
+ {
827
+ fn only_derive_is_allowed_to_implement_this_trait( ) { }
828
+ }
829
+
830
+ // SAFETY: This macro only accepts `#[repr(C)]` and
831
+ // `#[repr(transparent)]` structs, this `impl` block requires all field
832
+ // types to be `IntoBytes`, and a padding check is used to ensures that
833
+ // there are no padding bytes.
834
+ unsafe impl $( <$( $tyvar) ,* >) ? $crate:: IntoBytes for $name$( <$( $tyvar) ,* >) ?
835
+ where
836
+ $(
837
+ $( $tuple_field_ty: $crate:: IntoBytes , ) *
838
+ ) ?
839
+
840
+ $(
841
+ $( $field_ty: $crate:: IntoBytes , ) *
842
+ ) ?
843
+
844
+ ( ) : $crate:: util:: macro_util:: PaddingFree <
845
+ Self ,
846
+ {
847
+ $crate:: cryptocorrosion_derive_traits!(
848
+ @struct_padding_check #[ repr( $repr) ]
849
+ $( ( $( $tuple_field_ty) ,* ) ) ?
850
+ $( { $( $field_ty) ,* } ) ?
851
+ )
852
+ } ,
853
+ >,
854
+ {
855
+ fn only_derive_is_allowed_to_implement_this_trait( ) { }
856
+ }
857
+
858
+ // SAFETY: This macro only accepts `#[repr(C)]` and
859
+ // `#[repr(transparent)]` structs, and this `impl` block requires all
860
+ // field types to be `Immutable`.
861
+ unsafe impl $( <$( $tyvar) ,* >) ? $crate:: Immutable for $name$( <$( $tyvar) ,* >) ?
862
+ where
863
+ $(
864
+ $( $tuple_field_ty: $crate:: Immutable , ) *
865
+ ) ?
866
+
867
+ $(
868
+ $( $field_ty: $crate:: Immutable , ) *
869
+ ) ?
870
+ {
871
+ fn only_derive_is_allowed_to_implement_this_trait( ) { }
872
+ }
873
+ } ;
874
+ ( @assert_allowed_struct_repr #[ repr( transparent) ] ) => { } ;
875
+ ( @assert_allowed_struct_repr #[ repr( C ) ] ) => { } ;
876
+ ( @assert_allowed_struct_repr #[ $_attr: meta] ) => {
877
+ compile_error!( "repr must be `#[repr(transparent)]` or `#[repr(C)]`" ) ;
878
+ } ;
879
+ (
880
+ @struct_padding_check #[ repr( transparent) ]
881
+ $( ( $( $tuple_field_ty: ty) ,* ) ) ?
882
+ $( { $( $field_ty: ty) ,* } ) ?
883
+ ) => {
884
+ // SAFETY: `#[repr(transparent)]` structs cannot have the same layout as
885
+ // their single non-zero-sized field, and so cannot have any padding
886
+ // outside of that field.
887
+ false
888
+ } ;
889
+ (
890
+ @struct_padding_check #[ repr( C ) ]
891
+ $( ( $( $tuple_field_ty: ty) ,* ) ) ?
892
+ $( { $( $field_ty: ty) ,* } ) ?
893
+ ) => {
894
+ $crate:: struct_has_padding!(
895
+ Self ,
896
+ [
897
+ $( $( $tuple_field_ty) ,* ) ?
898
+ $( $( $field_ty) ,* ) ?
899
+ ]
900
+ )
901
+ } ;
902
+ (
903
+ #[ repr( C ) ]
904
+ $( #[ $attr: meta] ) *
905
+ $vis: vis union $name: ident {
906
+ $(
907
+ $field_name: ident: $field_ty: ty,
908
+ ) *
909
+ }
910
+ ) => {
911
+ $( #[ $attr] ) *
912
+ #[ repr( C ) ]
913
+ $vis union $name {
914
+ $(
915
+ $field_name: $field_ty,
916
+ ) *
917
+ }
918
+
919
+ // SAFETY: See inline.
920
+ unsafe impl $crate:: TryFromBytes for $name
921
+ where
922
+ $(
923
+ $field_ty: $crate:: FromBytes ,
924
+ ) *
925
+ {
926
+ fn is_bit_valid<A >( _c: $crate:: Maybe <' _, Self , A >) -> bool
927
+ where
928
+ A : $crate:: pointer:: invariant:: Reference
929
+ {
930
+ // SAFETY: This macro only accepts `#[repr(C)]` unions, and this
931
+ // `impl` block requires all field types to be `FromBytes`.
932
+ // Thus, all initialized byte sequences constitutes valid
933
+ // instances of `Self`.
934
+ true
935
+ }
936
+
937
+ fn only_derive_is_allowed_to_implement_this_trait( ) { }
938
+ }
939
+
940
+ // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl`
941
+ // block requires all field types to be `FromBytes`, which is a
942
+ // sub-trait of `FromZeros`.
943
+ unsafe impl $crate:: FromZeros for $name
944
+ where
945
+ $(
946
+ $field_ty: $crate:: FromBytes ,
947
+ ) *
948
+ {
949
+ fn only_derive_is_allowed_to_implement_this_trait( ) { }
950
+ }
951
+
952
+ // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl`
953
+ // block requires all field types to be `FromBytes`.
954
+ unsafe impl $crate:: FromBytes for $name
955
+ where
956
+ $(
957
+ $field_ty: $crate:: FromBytes ,
958
+ ) *
959
+ {
960
+ fn only_derive_is_allowed_to_implement_this_trait( ) { }
961
+ }
962
+
963
+ // SAFETY: This macro only accepts `#[repr(C)]` unions, this `impl`
964
+ // block requires all field types to be `IntoBytes`, and a padding check
965
+ // is used to ensures that there are no padding bytes before or after
966
+ // any field.
967
+ unsafe impl $crate:: IntoBytes for $name
968
+ where
969
+ $(
970
+ $field_ty: $crate:: IntoBytes ,
971
+ ) *
972
+ ( ) : $crate:: util:: macro_util:: PaddingFree <
973
+ Self ,
974
+ {
975
+ $crate:: union_has_padding!(
976
+ Self ,
977
+ [ $( $field_ty) ,* ]
978
+ )
979
+ } ,
980
+ >,
981
+ {
982
+ fn only_derive_is_allowed_to_implement_this_trait( ) { }
983
+ }
984
+
985
+ // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl`
986
+ // block requires all field types to be `Immutable`.
987
+ unsafe impl $crate:: Immutable for $name
988
+ where
989
+ $(
990
+ $field_ty: $crate:: Immutable ,
991
+ ) *
992
+ {
993
+ fn only_derive_is_allowed_to_implement_this_trait( ) { }
994
+ }
995
+ } ;
996
+ }
997
+
736
998
#[ cfg( test) ]
737
999
mod tests {
738
1000
use crate :: util:: testutil:: * ;
@@ -990,4 +1252,130 @@ mod tests {
990
1252
const AS_I32 : i32 = include_value ! ( "../testdata/include_value/data" ) ;
991
1253
assert_eq ! ( AS_I32 , i32 :: from_ne_bytes( [ b'a' , b'b' , b'c' , b'd' ] ) ) ;
992
1254
}
1255
+
1256
+ #[ test]
1257
+ #[ allow( non_camel_case_types) ]
1258
+ fn test_cryptocorrosion_derive_traits ( ) {
1259
+ // Test the set of invocations added in
1260
+ // https://github.com/cryptocorrosion/cryptocorrosion/pull/85
1261
+
1262
+ fn assert_impls < T : FromBytes + IntoBytes + Immutable > ( ) { }
1263
+
1264
+ cryptocorrosion_derive_traits ! {
1265
+ #[ repr( C ) ]
1266
+ #[ derive( Clone , Copy ) ]
1267
+ pub union vec128_storage {
1268
+ d: [ u32 ; 4 ] ,
1269
+ q: [ u64 ; 2 ] ,
1270
+ }
1271
+ }
1272
+
1273
+ assert_impls :: < vec128_storage > ( ) ;
1274
+
1275
+ cryptocorrosion_derive_traits ! {
1276
+ #[ repr( transparent) ]
1277
+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
1278
+ pub struct u32x4_generic( [ u32 ; 4 ] ) ;
1279
+ }
1280
+
1281
+ assert_impls :: < u32x4_generic > ( ) ;
1282
+
1283
+ cryptocorrosion_derive_traits ! {
1284
+ #[ repr( transparent) ]
1285
+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
1286
+ pub struct u64x2_generic( [ u64 ; 2 ] ) ;
1287
+ }
1288
+
1289
+ assert_impls :: < u64x2_generic > ( ) ;
1290
+
1291
+ cryptocorrosion_derive_traits ! {
1292
+ #[ repr( transparent) ]
1293
+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
1294
+ pub struct u128x1_generic( [ u128 ; 1 ] ) ;
1295
+ }
1296
+
1297
+ assert_impls :: < u128x1_generic > ( ) ;
1298
+
1299
+ cryptocorrosion_derive_traits ! {
1300
+ #[ repr( transparent) ]
1301
+ #[ derive( Copy , Clone , Default ) ]
1302
+ #[ allow( non_camel_case_types) ]
1303
+ pub struct x2<W , G >( pub [ W ; 2 ] , PhantomData <G >) ;
1304
+ }
1305
+
1306
+ enum NotZerocopy { }
1307
+ assert_impls :: < x2 < ( ) , NotZerocopy > > ( ) ;
1308
+
1309
+ cryptocorrosion_derive_traits ! {
1310
+ #[ repr( transparent) ]
1311
+ #[ derive( Copy , Clone , Default ) ]
1312
+ #[ allow( non_camel_case_types) ]
1313
+ pub struct x4<W >( pub [ W ; 4 ] ) ;
1314
+ }
1315
+
1316
+ assert_impls :: < x4 < ( ) > > ( ) ;
1317
+
1318
+ #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
1319
+ {
1320
+ use core:: arch:: x86:: { __m128i, __m256i} ;
1321
+
1322
+ cryptocorrosion_derive_traits ! {
1323
+ #[ repr( C ) ]
1324
+ #[ derive( Copy , Clone ) ]
1325
+ pub struct X4 ( __m128i, __m128i, __m128i, __m128i) ;
1326
+ }
1327
+
1328
+ assert_impls :: < X4 > ( ) ;
1329
+
1330
+ cryptocorrosion_derive_traits ! {
1331
+ #[ repr( C ) ]
1332
+ /// Generic wrapper for unparameterized storage of any of the possible impls.
1333
+ /// Converting into and out of this type should be essentially free, although it may be more
1334
+ /// aligned than a particular impl requires.
1335
+ #[ allow( non_camel_case_types) ]
1336
+ #[ derive( Copy , Clone ) ]
1337
+ pub union vec128_storage {
1338
+ u32x4: [ u32 ; 4 ] ,
1339
+ u64x2: [ u64 ; 2 ] ,
1340
+ u128x1: [ u128 ; 1 ] ,
1341
+ sse2: __m128i,
1342
+ }
1343
+ }
1344
+
1345
+ assert_impls :: < vec128_storage > ( ) ;
1346
+
1347
+ cryptocorrosion_derive_traits ! {
1348
+ #[ repr( transparent) ]
1349
+ #[ allow( non_camel_case_types) ]
1350
+ #[ derive( Copy , Clone ) ]
1351
+ pub struct vec<S3 , S4 , NI > {
1352
+ x: __m128i,
1353
+ s3: PhantomData <S3 >,
1354
+ s4: PhantomData <S4 >,
1355
+ ni: PhantomData <NI >,
1356
+ }
1357
+ }
1358
+
1359
+ assert_impls :: < vec < NotZerocopy , NotZerocopy , NotZerocopy > > ( ) ;
1360
+
1361
+ cryptocorrosion_derive_traits ! {
1362
+ #[ repr( transparent) ]
1363
+ #[ derive( Copy , Clone ) ]
1364
+ pub struct u32x4x2_avx2<NI > {
1365
+ x: __m256i,
1366
+ ni: PhantomData <NI >,
1367
+ }
1368
+ }
1369
+
1370
+ assert_impls :: < u32x4x2_avx2 < NotZerocopy > > ( ) ;
1371
+ }
1372
+
1373
+ // Make sure that our derive works for `#[repr(C)]` structs even though
1374
+ // cryptocorrosion doesn't currently have any.
1375
+ cryptocorrosion_derive_traits ! {
1376
+ #[ repr( C ) ]
1377
+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
1378
+ pub struct ReprC ( u8 , u8 , u16 ) ;
1379
+ }
1380
+ }
993
1381
}
0 commit comments