@@ -152,6 +152,7 @@ class t_go_generator : public t_generator {
152
152
const string& tstruct_name,
153
153
bool is_result = false ,
154
154
bool uses_countsetfields = false );
155
+ void generate_go_struct_equals (std::ostream& out, t_struct* tstruct, const string& tstruct_name);
155
156
void generate_go_function_helpers (t_function* tfunction);
156
157
void get_publicized_name_and_def_value (t_field* tfield,
157
158
string* OUT_pub_name,
@@ -229,6 +230,12 @@ class t_go_generator : public t_generator {
229
230
230
231
void generate_serialize_list_element (std::ostream& out, t_list* tlist, std::string iter);
231
232
233
+ void generate_go_equals (std::ostream& out, t_type* ttype, string tgt, string src);
234
+
235
+ void generate_go_equals_struct (std::ostream& out, t_type* ttype, string tgt, string src);
236
+
237
+ void generate_go_equals_container (std::ostream& out, t_type* ttype, string tgt, string src);
238
+
232
239
void generate_go_docstring (std::ostream& out, t_struct* tstruct);
233
240
234
241
void generate_go_docstring (std::ostream& out, t_function* tfunction);
@@ -307,6 +314,7 @@ class t_go_generator : public t_generator {
307
314
std::set<std::string> package_identifiers_set_;
308
315
std::string read_method_name_;
309
316
std::string write_method_name_;
317
+ std::string equals_method_name_;
310
318
311
319
std::set<std::string> commonInitialisms;
312
320
@@ -724,6 +732,7 @@ void t_go_generator::init_generator() {
724
732
read_method_name_ = " Read" ;
725
733
write_method_name_ = " Write" ;
726
734
}
735
+ equals_method_name_ = " Equals" ;
727
736
728
737
while (true ) {
729
738
// TODO: Do better error checking here.
@@ -912,7 +921,6 @@ string t_go_generator::go_imports_begin(bool consts) {
912
921
std::vector<string> system_packages;
913
922
system_packages.push_back (" bytes" );
914
923
system_packages.push_back (" context" );
915
- system_packages.push_back (" reflect" );
916
924
// If not writing constants, and there are enums, need extra imports.
917
925
if (!consts && get_program ()->get_enums ().size () > 0 ) {
918
926
system_packages.push_back (" database/sql/driver" );
@@ -937,7 +945,6 @@ string t_go_generator::go_imports_end() {
937
945
" var _ = thrift.ZERO\n "
938
946
" var _ = fmt.Printf\n "
939
947
" var _ = context.Background\n "
940
- " var _ = reflect.DeepEqual\n "
941
948
" var _ = time.Now\n "
942
949
" var _ = bytes.Equal\n\n " );
943
950
}
@@ -1482,6 +1489,9 @@ void t_go_generator::generate_go_struct_definition(ostream& out,
1482
1489
generate_isset_helpers (out, tstruct, tstruct_name, is_result);
1483
1490
generate_go_struct_reader (out, tstruct, tstruct_name, is_result);
1484
1491
generate_go_struct_writer (out, tstruct, tstruct_name, is_result, num_setable > 0 );
1492
+ if (!is_result && !is_args) {
1493
+ generate_go_struct_equals (out, tstruct, tstruct_name);
1494
+ }
1485
1495
1486
1496
out << indent () << " func (p *" << tstruct_name << " ) String() string {" << endl;
1487
1497
out << indent () << " if p == nil {" << endl;
@@ -1851,6 +1861,61 @@ void t_go_generator::generate_go_struct_writer(ostream& out,
1851
1861
}
1852
1862
}
1853
1863
1864
+ void t_go_generator::generate_go_struct_equals (ostream& out,
1865
+ t_struct* tstruct,
1866
+ const string& tstruct_name) {
1867
+ string name (tstruct->get_name ());
1868
+ const vector<t_field*>& fields = tstruct->get_sorted_members ();
1869
+ vector<t_field*>::const_iterator f_iter;
1870
+ indent (out) << " func (p *" << tstruct_name << " ) " << equals_method_name_ << " (other *"
1871
+ << tstruct_name << " ) bool {" << endl;
1872
+ indent_up ();
1873
+
1874
+ string field_name;
1875
+ string publicize_field_name;
1876
+ out << indent () << " if p == other {" << endl;
1877
+ indent_up ();
1878
+ out << indent () << " return true" << endl;
1879
+ indent_down ();
1880
+ out << indent () << " } else if p == nil || other == nil {" << endl;
1881
+ indent_up ();
1882
+ out << indent () << " return false" << endl;
1883
+ indent_down ();
1884
+ out << indent () << " }" << endl;
1885
+
1886
+ for (f_iter = fields.begin (); f_iter != fields.end (); ++f_iter) {
1887
+ field_name = (*f_iter)->get_name ();
1888
+ t_type* field_type = (*f_iter)->get_type ();
1889
+ publicize_field_name = publicize (field_name);
1890
+ string goType = type_to_go_type_with_opt (field_type, is_pointer_field (*f_iter));
1891
+
1892
+ string tgt = " p." + publicize_field_name;
1893
+ string src = " other." + publicize_field_name;
1894
+ t_type* ttype = field_type->get_true_type ();
1895
+ // Compare field contents
1896
+ if (is_pointer_field (*f_iter)
1897
+ && (ttype->is_base_type () || ttype->is_enum () || ttype->is_container ())) {
1898
+ string tgtv = " (*" + tgt + " )" ;
1899
+ string srcv = " (*" + src + " )" ;
1900
+ out << indent () << " if " << tgt << " != " << src << " {" << endl;
1901
+ indent_up ();
1902
+ out << indent () << " if " << tgt << " == nil || " << src << " == nil {" << endl;
1903
+ indent_up ();
1904
+ out << indent () << " return false" << endl;
1905
+ indent_down ();
1906
+ out << indent () << " }" << endl;
1907
+ generate_go_equals (out, field_type, tgtv, srcv);
1908
+ indent_down ();
1909
+ out << indent () << " }" << endl;
1910
+ } else {
1911
+ generate_go_equals (out, field_type, tgt, src);
1912
+ }
1913
+ }
1914
+ out << indent () << " return true" << endl;
1915
+ indent_down ();
1916
+ out << indent () << " }" << endl << endl;
1917
+ }
1918
+
1854
1919
/* *
1855
1920
* Generates a thrift service.
1856
1921
*
@@ -3389,15 +3454,30 @@ void t_go_generator::generate_serialize_container(ostream& out,
3389
3454
} else if (ttype->is_set ()) {
3390
3455
t_set* tset = (t_set*)ttype;
3391
3456
out << indent () << " for i := 0; i<len(" << prefix << " ); i++ {" << endl;
3392
- out << indent () << " for j := i+1; j<len(" << prefix << " ); j++ {" << endl;
3457
+ indent_up ();
3458
+ out << indent () << " for j := i+1; j<len(" << prefix << " ); j++ {" << endl;
3459
+ indent_up ();
3393
3460
string wrapped_prefix = prefix;
3394
3461
if (pointer_field) {
3395
3462
wrapped_prefix = " (" + prefix + " )" ;
3396
3463
}
3397
- out << indent () << " if reflect.DeepEqual(" << wrapped_prefix << " [i]," << wrapped_prefix << " [j]) { " << endl;
3398
- out << indent () << " return thrift.PrependError(\"\" , fmt.Errorf(\" %T error writing set field: slice is not unique\" , " << wrapped_prefix << " [i]))" << endl;
3399
- out << indent () << " }" << endl;
3400
- out << indent () << " }" << endl;
3464
+ string goType = type_to_go_type (tset->get_elem_type ());
3465
+ out << indent () << " if func(tgt, src " << goType << " ) bool {" << endl;
3466
+ indent_up ();
3467
+ generate_go_equals (out, tset->get_elem_type (), " tgt" , " src" );
3468
+ out << indent () << " return true" << endl;
3469
+ indent_down ();
3470
+ out << indent () << " }(" << wrapped_prefix << " [i], " << wrapped_prefix << " [j]) {" << endl;
3471
+ indent_up ();
3472
+ out << indent ()
3473
+ << " return thrift.PrependError(\"\" , fmt.Errorf(\" %T error writing set field: slice is not "
3474
+ " unique\" , "
3475
+ << wrapped_prefix << " ))" << endl;
3476
+ indent_down ();
3477
+ out << indent () << " }" << endl;
3478
+ indent_down ();
3479
+ out << indent () << " }" << endl;
3480
+ indent_down ();
3401
3481
out << indent () << " }" << endl;
3402
3482
out << indent () << " for _, v := range " << prefix << " {" << endl;
3403
3483
indent_up ();
@@ -3463,6 +3543,111 @@ void t_go_generator::generate_serialize_list_element(ostream& out, t_list* tlist
3463
3543
generate_serialize_field (out, &efield, prefix);
3464
3544
}
3465
3545
3546
+ /* *
3547
+ * Compares any type
3548
+ */
3549
+ void t_go_generator::generate_go_equals (ostream& out, t_type* ori_type, string tgt, string src) {
3550
+
3551
+ t_type* ttype = get_true_type (ori_type);
3552
+ // Do nothing for void types
3553
+ if (ttype->is_void ()) {
3554
+ throw " compiler error: cannot generate equals for void type: " + tgt;
3555
+ }
3556
+
3557
+ if (ttype->is_struct () || ttype->is_xception ()) {
3558
+ generate_go_equals_struct (out, ttype, tgt, src);
3559
+ } else if (ttype->is_container ()) {
3560
+ generate_go_equals_container (out, ttype, tgt, src);
3561
+ } else if (ttype->is_base_type () || ttype->is_enum ()) {
3562
+ out << indent () << " if " ;
3563
+ if (ttype->is_base_type ()) {
3564
+ t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base ();
3565
+ switch (tbase) {
3566
+ case t_base_type::TYPE_VOID:
3567
+ throw " compiler error: cannot equals void: " + tgt;
3568
+ break ;
3569
+
3570
+ case t_base_type::TYPE_STRING:
3571
+ if (ttype->is_binary ()) {
3572
+ out << " bytes.Compare(" << tgt << " , " << src << " ) != 0" ;
3573
+ } else {
3574
+ out << tgt << " != " << src;
3575
+ }
3576
+ break ;
3577
+
3578
+ case t_base_type::TYPE_BOOL:
3579
+ case t_base_type::TYPE_I8:
3580
+ case t_base_type::TYPE_I16:
3581
+ case t_base_type::TYPE_I32:
3582
+ case t_base_type::TYPE_I64:
3583
+ case t_base_type::TYPE_DOUBLE:
3584
+ out << tgt << " != " << src;
3585
+ break ;
3586
+
3587
+ default :
3588
+ throw " compiler error: no Go name for base type " + t_base_type::t_base_name (tbase);
3589
+ }
3590
+ } else if (ttype->is_enum ()) {
3591
+ out << tgt << " != " << src;
3592
+ }
3593
+
3594
+ out << " { return false }" << endl;
3595
+ } else {
3596
+ throw " compiler error: Invalid type in generate_go_equals '" + ttype->get_name () + " ' for '"
3597
+ + tgt + " '" ;
3598
+ }
3599
+ }
3600
+
3601
+ /* *
3602
+ * Compares the members of a struct
3603
+ */
3604
+ void t_go_generator::generate_go_equals_struct (ostream& out,
3605
+ t_type* ttype,
3606
+ string tgt,
3607
+ string src) {
3608
+ (void )ttype;
3609
+ out << indent () << " if !" << tgt << " ." << equals_method_name_ << " (" << src
3610
+ << " ) { return false }" << endl;
3611
+ }
3612
+
3613
+ /* *
3614
+ * Compares any container type
3615
+ */
3616
+ void t_go_generator::generate_go_equals_container (ostream& out,
3617
+ t_type* ttype,
3618
+ string tgt,
3619
+ string src) {
3620
+ out << indent () << " if len(" << tgt << " ) != len(" << src << " ) { return false }" << endl;
3621
+ if (ttype->is_map ()) {
3622
+ t_map* tmap = (t_map*)ttype;
3623
+ out << indent () << " for k, _tgt := range " << tgt << " {" << endl;
3624
+ indent_up ();
3625
+ string element_source = tmp (" _src" );
3626
+ out << indent () << element_source << " := " << src << " [k]" << endl;
3627
+ generate_go_equals (out, tmap->get_val_type (), " _tgt" , element_source);
3628
+ indent_down ();
3629
+ indent (out) << " }" << endl;
3630
+ } else if (ttype->is_list () || ttype->is_set ()) {
3631
+ t_type* elem;
3632
+ if (ttype->is_list ()) {
3633
+ t_list* temp = (t_list*)ttype;
3634
+ elem = temp->get_elem_type ();
3635
+ } else {
3636
+ t_set* temp = (t_set*)ttype;
3637
+ elem = temp->get_elem_type ();
3638
+ }
3639
+ out << indent () << " for i, _tgt := range " << tgt << " {" << endl;
3640
+ indent_up ();
3641
+ string element_source = tmp (" _src" );
3642
+ out << indent () << element_source << " := " << src << " [i]" << endl;
3643
+ generate_go_equals (out, elem, " _tgt" , element_source);
3644
+ indent_down ();
3645
+ indent (out) << " }" << endl;
3646
+ } else {
3647
+ throw " INVALID TYPE IN generate_go_equals_container '" + ttype->get_name ();
3648
+ }
3649
+ }
3650
+
3466
3651
/* *
3467
3652
* Generates the docstring for a given struct.
3468
3653
*/
0 commit comments