THRIFT-4099: Derive Hash trait for Rust structs
Client: rs
This closes #1246
diff --git a/compiler/cpp/src/thrift/generate/t_rs_generator.cc b/compiler/cpp/src/thrift/generate/t_rs_generator.cc
index 78794a5..c34ed17 100644
--- a/compiler/cpp/src/thrift/generate/t_rs_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_rs_generator.cc
@@ -245,6 +245,13 @@
// rendered code is calling such a function it has to dereference `v`.
bool needs_deref_on_container_write(t_type* ttype);
+ // Return the variable (including all dereferences) required to write values from a rust container
+ // to the output protocol. For example, if you were iterating through a container and using the temp
+ // variable `v` to represent each element, then `ttype` is the type stored in the container and
+ // `base_var` is "v". The return value is the actual string you will have to use to properly reference
+ // the temp variable for writing to the output protocol.
+ string string_container_write_variable(t_type* ttype, const string& base_var);
+
// Write the code to read bytes from the wire into the given `t_struct`. `struct_name` is the
// actual Rust name of the `t_struct`. If `struct_type` is `T_ARGS` then all struct fields are
// necessary. Otherwise, the field's default optionality is used.
@@ -377,6 +384,9 @@
// Write the documentation for a struct, service-call or other documentation-annotated element.
void render_rustdoc(t_doc* tdoc);
+ // Return `true` if the true type of `ttype` is a thrift double, `false` otherwise.
+ bool is_double(t_type* ttype);
+
// Return a string representing the rust type given a `t_type`.
string to_rust_type(t_type* ttype, bool ordered_float = true);
@@ -655,10 +665,7 @@
f_gen_ << tvalue->get_integer();
break;
case t_base_type::TYPE_DOUBLE:
- f_gen_
- << indent()
- << "OrderedFloat::from(" << tvalue->get_double() << ")"
- << endl;
+ f_gen_ << "OrderedFloat::from(" << tvalue->get_double() << " as f64)";
break;
default:
throw "cannot generate const value for " + t_base_type::t_base_name(tbase_type->get_base());
@@ -826,7 +833,7 @@
void t_rs_generator::render_enum_definition(t_enum* tenum, const string& enum_name) {
render_rustdoc((t_doc*) tenum);
- f_gen_ << "#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]" << endl;
+ f_gen_ << "#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl;
f_gen_ << "pub enum " << enum_name << " {" << endl;
indent_up();
@@ -965,7 +972,7 @@
t_rs_generator::e_struct_type struct_type
) {
render_rustdoc((t_doc*) tstruct);
- f_gen_ << "#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]" << endl;
+ f_gen_ << "#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl;
f_gen_ << visibility_qualifier(struct_type) << "struct " << struct_name << " {" << endl;
// render the members
@@ -1311,7 +1318,7 @@
throw "cannot generate rust enum with 0 members"; // may be valid thrift, but it's invalid rust
}
- f_gen_ << "#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]" << endl;
+ f_gen_ << "#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl;
f_gen_ << "pub enum " << union_name << " {" << endl;
indent_up();
@@ -1543,7 +1550,7 @@
string ref(list_var_is_ref ? "" : "&");
f_gen_ << indent() << "for e in " << ref << list_var << " {" << endl;
indent_up();
- render_type_sync_write(needs_deref_on_container_write(elem_type) ? "*e" : "e", true, elem_type);
+ render_type_sync_write(string_container_write_variable(elem_type, "e"), true, elem_type);
f_gen_ << indent() << "o_prot.write_list_end()?;" << endl;
indent_down();
f_gen_ << indent() << "}" << endl;
@@ -1564,7 +1571,7 @@
string ref(set_var_is_ref ? "" : "&");
f_gen_ << indent() << "for e in " << ref << set_var << " {" << endl;
indent_up();
- render_type_sync_write(needs_deref_on_container_write(elem_type) ? "*e" : "e", true, elem_type);
+ render_type_sync_write(string_container_write_variable(elem_type, "e"), true, elem_type);
f_gen_ << indent() << "o_prot.write_set_end()?;" << endl;
indent_down();
f_gen_ << indent() << "}" << endl;
@@ -1587,13 +1594,30 @@
string ref(map_var_is_ref ? "" : "&");
f_gen_ << indent() << "for (k, v) in " << ref << map_var << " {" << endl;
indent_up();
- render_type_sync_write(needs_deref_on_container_write(key_type) ? "*k" : "k", true, key_type);
- render_type_sync_write(needs_deref_on_container_write(val_type) ? "*v" : "v", true, val_type);
+ render_type_sync_write(string_container_write_variable(key_type, "k"), true, key_type);
+ render_type_sync_write(string_container_write_variable(val_type, "v"), true, val_type);
f_gen_ << indent() << "o_prot.write_map_end()?;" << endl;
indent_down();
f_gen_ << indent() << "}" << endl;
}
+string t_rs_generator::string_container_write_variable(t_type* ttype, const string& base_var) {
+ bool type_needs_deref = needs_deref_on_container_write(ttype);
+ bool type_is_double = is_double(ttype);
+
+ string write_variable;
+
+ if (type_is_double && type_needs_deref) {
+ write_variable = "(*" + base_var + ")";
+ } else if (type_needs_deref) {
+ write_variable = "*" + base_var;
+ } else {
+ write_variable = base_var;
+ }
+
+ return write_variable;
+}
+
bool t_rs_generator::needs_deref_on_container_write(t_type* ttype) {
ttype = get_true_type(ttype);
return ttype->is_base_type() && !ttype->is_string();
@@ -2864,6 +2888,18 @@
f_gen_ << indent() << ")" << endl;
}
+bool t_rs_generator::is_double(t_type* ttype) {
+ ttype = get_true_type(ttype);
+ if (ttype->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+ if (tbase == t_base_type::TYPE_DOUBLE) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
string t_rs_generator::to_rust_type(t_type* ttype, bool ordered_float) {
// ttype = get_true_type(ttype); <-- recurses through as many typedef layers as necessary
if (ttype->is_base_type()) {
diff --git a/lib/rs/src/transport/mem.rs b/lib/rs/src/transport/mem.rs
index 8ec2a98..97ec503 100644
--- a/lib/rs/src/transport/mem.rs
+++ b/lib/rs/src/transport/mem.rs
@@ -109,7 +109,7 @@
let buf = {
let b = self.write_buffer_as_ref();
let mut b_ret = vec![0; b.len()];
- b_ret.copy_from_slice(&b);
+ b_ret.copy_from_slice(b);
b_ret
};
diff --git a/lib/rs/test/thrifts/Base_One.thrift b/lib/rs/test/thrifts/Base_One.thrift
index ceb1207..3da083d 100644
--- a/lib/rs/test/thrifts/Base_One.thrift
+++ b/lib/rs/test/thrifts/Base_One.thrift
@@ -31,6 +31,10 @@
const list<Temperature> Temperatures = [10, 11, 22, 33]
+// IMPORTANT: temps should end with ".0" because this tests
+// that we don't have a problem with const float list generation
+const list<double> CommonTemperatures = [300.0, 450.0]
+
const double MealsPerDay = 2.5;
struct Noodle {
@@ -48,6 +52,21 @@
1: Size size
}
+struct MeasuringCup {
+ 1: double millis
+}
+
+union MeasuringAids {
+ 1: MeasuringSpoon spoon
+ 2: MeasuringCup cup
+}
+
+struct CookingTemperatures {
+ 1: set<double> commonTemperatures
+ 2: list<double> usedTemperatures
+ 3: map<double, double> fahrenheitToCentigradeConversions
+}
+
struct Recipe {
1: string recipeName
2: string cuisine