@@ -3693,6 +3693,270 @@ func TestSliceOfGC(t *testing.T) {
3693
3693
}
3694
3694
}
3695
3695
3696
+ func TestStructOf (t * testing.T ) {
3697
+ // check construction and use of type not in binary
3698
+ fields := []StructField {
3699
+ StructField {
3700
+ Name : "S" ,
3701
+ Tag : "s" ,
3702
+ Type : TypeOf ("" ),
3703
+ },
3704
+ StructField {
3705
+ Name : "X" ,
3706
+ Tag : "x" ,
3707
+ Type : TypeOf (byte (0 )),
3708
+ },
3709
+ StructField {
3710
+ Name : "Y" ,
3711
+ Type : TypeOf (uint64 (0 )),
3712
+ },
3713
+ StructField {
3714
+ Name : "Z" ,
3715
+ Type : TypeOf ([3 ]uint16 {}),
3716
+ },
3717
+ }
3718
+
3719
+ st := StructOf (fields )
3720
+ v := New (st ).Elem ()
3721
+ runtime .GC ()
3722
+ v .FieldByName ("X" ).Set (ValueOf (byte (2 )))
3723
+ v .FieldByIndex ([]int {1 }).Set (ValueOf (byte (1 )))
3724
+ runtime .GC ()
3725
+
3726
+ s := fmt .Sprint (v .Interface ())
3727
+ want := `{ 1 0 [0 0 0]}`
3728
+ if s != want {
3729
+ t .Errorf ("constructed struct = %s, want %s" , s , want )
3730
+ }
3731
+
3732
+ // check the size, alignment and field offsets
3733
+ stt := TypeOf (struct {
3734
+ String string
3735
+ X byte
3736
+ Y uint64
3737
+ Z [3 ]uint16
3738
+ }{})
3739
+ if st .Size () != stt .Size () {
3740
+ t .Errorf ("constructed struct size = %v, want %v" , st .Size (), stt .Size ())
3741
+ }
3742
+ if st .Align () != stt .Align () {
3743
+ t .Errorf ("constructed struct align = %v, want %v" , st .Align (), stt .Align ())
3744
+ }
3745
+ if st .FieldAlign () != stt .FieldAlign () {
3746
+ t .Errorf ("constructed struct field align = %v, want %v" , st .FieldAlign (), stt .FieldAlign ())
3747
+ }
3748
+ for i := 0 ; i < st .NumField (); i ++ {
3749
+ o1 := st .Field (i ).Offset
3750
+ o2 := stt .Field (i ).Offset
3751
+ if o1 != o2 {
3752
+ t .Errorf ("constructed struct field %v offset = %v, want %v" , i , o1 , o2 )
3753
+ }
3754
+ }
3755
+
3756
+ // check duplicate names
3757
+ shouldPanic (func () {
3758
+ StructOf ([]StructField {
3759
+ StructField {Name : "string" , Type : TypeOf ("" )},
3760
+ StructField {Name : "string" , Type : TypeOf ("" )},
3761
+ })
3762
+ })
3763
+ shouldPanic (func () {
3764
+ StructOf ([]StructField {
3765
+ StructField {Type : TypeOf ("" )},
3766
+ StructField {Name : "string" , Type : TypeOf ("" )},
3767
+ })
3768
+ })
3769
+ shouldPanic (func () {
3770
+ StructOf ([]StructField {
3771
+ StructField {Type : TypeOf ("" )},
3772
+ StructField {Type : TypeOf ("" )},
3773
+ })
3774
+ })
3775
+ // check that type already in binary is found
3776
+ checkSameType (t , Zero (StructOf (fields [2 :3 ])).Interface (), struct { Y uint64 }{})
3777
+ }
3778
+
3779
+ func TestStructOfGC (t * testing.T ) {
3780
+ type T * uintptr
3781
+ tt := TypeOf (T (nil ))
3782
+ fields := []StructField {
3783
+ {Name : "X" , Type : TypeOf (T (nil ))},
3784
+ {Name : "Y" , Type : TypeOf (T (nil ))},
3785
+ }
3786
+ st := StructOf (fields )
3787
+
3788
+ const n = 10000
3789
+ var x []interface {}
3790
+ for i := 0 ; i < n ; i ++ {
3791
+ v := New (st ).Elem ()
3792
+ for j := 0 ; j < v .NumField (); j += 1 {
3793
+ p := new (uintptr )
3794
+ * p = uintptr (i * n + j )
3795
+ v .Field (j ).Set (ValueOf (p ).Convert (tt ))
3796
+ }
3797
+ x = append (x , v .Interface ())
3798
+ }
3799
+ runtime .GC ()
3800
+
3801
+ for i , xi := range x {
3802
+ v := ValueOf (xi )
3803
+ for j := 0 ; j < v .NumField (); j += 1 {
3804
+ k := v .Field (j ).Elem ().Interface ()
3805
+ if k != uintptr (i * n + j ) {
3806
+ t .Errorf ("lost x[%d]%c = %d, want %d" , i , "XY" [j ], k , i * n + j )
3807
+ }
3808
+ }
3809
+ }
3810
+ }
3811
+
3812
+ func TestStructOfAlg (t * testing.T ) {
3813
+ st := StructOf ([]StructField {{Name : "X" , Tag : "x" , Type : TypeOf (int (0 ))}})
3814
+ v1 := New (st ).Elem ()
3815
+ v2 := New (st ).Elem ()
3816
+ if ! DeepEqual (v1 .Interface (), v1 .Interface ()) {
3817
+ t .Errorf ("constructed struct %v not equal to itself" , v1 .Interface ())
3818
+ }
3819
+ v1 .FieldByName ("X" ).Set (ValueOf (int (1 )))
3820
+ if i1 , i2 := v1 .Interface (), v2 .Interface (); DeepEqual (i1 , i2 ) {
3821
+ t .Errorf ("constructed structs %v and %v should not be equal" , i1 , i2 )
3822
+ }
3823
+
3824
+ st = StructOf ([]StructField {{Name : "X" , Tag : "x" , Type : TypeOf ([]int (nil ))}})
3825
+ v1 = New (st ).Elem ()
3826
+ shouldPanic (func () { _ = v1 .Interface () == v1 .Interface () })
3827
+ }
3828
+
3829
+ func TestStructOfGenericAlg (t * testing.T ) {
3830
+ st1 := StructOf ([]StructField {
3831
+ {Name : "X" , Tag : "x" , Type : TypeOf (int64 (0 ))},
3832
+ {Name : "Y" , Type : TypeOf (string ("" ))},
3833
+ })
3834
+ st := StructOf ([]StructField {
3835
+ {Name : "S0" , Type : st1 },
3836
+ {Name : "S1" , Type : st1 },
3837
+ })
3838
+
3839
+ for _ , table := range []struct {
3840
+ rt Type
3841
+ idx []int
3842
+ }{
3843
+ {
3844
+ rt : st ,
3845
+ idx : []int {0 , 1 },
3846
+ },
3847
+ {
3848
+ rt : st1 ,
3849
+ idx : []int {1 },
3850
+ },
3851
+ {
3852
+ rt : StructOf (
3853
+ []StructField {
3854
+ {Name : "XX" , Type : TypeOf ([0 ]int {})},
3855
+ {Name : "YY" , Type : TypeOf ("" )},
3856
+ },
3857
+ ),
3858
+ idx : []int {1 },
3859
+ },
3860
+ {
3861
+ rt : StructOf (
3862
+ []StructField {
3863
+ {Name : "XX" , Type : TypeOf ([0 ]int {})},
3864
+ {Name : "YY" , Type : TypeOf ("" )},
3865
+ {Name : "ZZ" , Type : TypeOf ([2 ]int {})},
3866
+ },
3867
+ ),
3868
+ idx : []int {1 },
3869
+ },
3870
+ {
3871
+ rt : StructOf (
3872
+ []StructField {
3873
+ {Name : "XX" , Type : TypeOf ([1 ]int {})},
3874
+ {Name : "YY" , Type : TypeOf ("" )},
3875
+ },
3876
+ ),
3877
+ idx : []int {1 },
3878
+ },
3879
+ {
3880
+ rt : StructOf (
3881
+ []StructField {
3882
+ {Name : "XX" , Type : TypeOf ([1 ]int {})},
3883
+ {Name : "YY" , Type : TypeOf ("" )},
3884
+ {Name : "ZZ" , Type : TypeOf ([1 ]int {})},
3885
+ },
3886
+ ),
3887
+ idx : []int {1 },
3888
+ },
3889
+ {
3890
+ rt : StructOf (
3891
+ []StructField {
3892
+ {Name : "XX" , Type : TypeOf ([2 ]int {})},
3893
+ {Name : "YY" , Type : TypeOf ("" )},
3894
+ {Name : "ZZ" , Type : TypeOf ([2 ]int {})},
3895
+ },
3896
+ ),
3897
+ idx : []int {1 },
3898
+ },
3899
+ {
3900
+ rt : StructOf (
3901
+ []StructField {
3902
+ {Name : "XX" , Type : TypeOf (int64 (0 ))},
3903
+ {Name : "YY" , Type : TypeOf (byte (0 ))},
3904
+ {Name : "ZZ" , Type : TypeOf ("" )},
3905
+ },
3906
+ ),
3907
+ idx : []int {2 },
3908
+ },
3909
+ {
3910
+ rt : StructOf (
3911
+ []StructField {
3912
+ {Name : "XX" , Type : TypeOf (int64 (0 ))},
3913
+ {Name : "YY" , Type : TypeOf (int64 (0 ))},
3914
+ {Name : "ZZ" , Type : TypeOf ("" )},
3915
+ {Name : "AA" , Type : TypeOf ([1 ]int64 {})},
3916
+ },
3917
+ ),
3918
+ idx : []int {2 },
3919
+ },
3920
+ } {
3921
+ v1 := New (table .rt ).Elem ()
3922
+ v2 := New (table .rt ).Elem ()
3923
+
3924
+ if ! DeepEqual (v1 .Interface (), v1 .Interface ()) {
3925
+ t .Errorf ("constructed struct %v not equal to itself" , v1 .Interface ())
3926
+ }
3927
+
3928
+ v1 .FieldByIndex (table .idx ).Set (ValueOf ("abc" ))
3929
+ v2 .FieldByIndex (table .idx ).Set (ValueOf ("def" ))
3930
+ if i1 , i2 := v1 .Interface (), v2 .Interface (); DeepEqual (i1 , i2 ) {
3931
+ t .Errorf ("constructed structs %v and %v should not be equal" , i1 , i2 )
3932
+ }
3933
+
3934
+ abc := "abc"
3935
+ v1 .FieldByIndex (table .idx ).Set (ValueOf (abc ))
3936
+ val := "+" + abc + "-"
3937
+ v2 .FieldByIndex (table .idx ).Set (ValueOf (val [1 :4 ]))
3938
+ if i1 , i2 := v1 .Interface (), v2 .Interface (); ! DeepEqual (i1 , i2 ) {
3939
+ t .Errorf ("constructed structs %v and %v should be equal" , i1 , i2 )
3940
+ }
3941
+
3942
+ // Test hash
3943
+ m := MakeMap (MapOf (table .rt , TypeOf (int (0 ))))
3944
+ m .SetMapIndex (v1 , ValueOf (1 ))
3945
+ if i1 , i2 := v1 .Interface (), v2 .Interface (); ! m .MapIndex (v2 ).IsValid () {
3946
+ t .Errorf ("constructed structs %#v and %#v have different hashes" , i1 , i2 )
3947
+ }
3948
+
3949
+ v2 .FieldByIndex (table .idx ).Set (ValueOf ("a" + "b" + "c" ))
3950
+ if i1 , i2 := v1 .Interface (), v2 .Interface (); ! DeepEqual (i1 , i2 ) {
3951
+ t .Errorf ("constructed structs %v and %v should be equal" , i1 , i2 )
3952
+ }
3953
+
3954
+ if i1 , i2 := v1 .Interface (), v2 .Interface (); ! m .MapIndex (v2 ).IsValid () {
3955
+ t .Errorf ("constructed structs %v and %v have different hashes" , i1 , i2 )
3956
+ }
3957
+ }
3958
+ }
3959
+
3696
3960
func TestChanOf (t * testing.T ) {
3697
3961
// check construction and use of type not in binary
3698
3962
type T string
0 commit comments