THRIFT-5600: upgrade rust toolchain to 1.61 and edition 2021
THRIFT-5606: Wrong indent for const double
Client: rs
Patch: Ommy Zhang <tdxdxoz@gmail.com>

This closes #2634
diff --git a/LANGUAGES.md b/LANGUAGES.md
index f787b93..9d989da 100644
--- a/LANGUAGES.md
+++ b/LANGUAGES.md
@@ -319,7 +319,7 @@
 <td align=left><a href="https://github.com/apache/thrift/blob/master/lib/rs/README.md">Rust</a></td>
 <!-- Since -----------------><td>0.11.0</td>
 <!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
-<!-- Language Levels -------><td>1.40.0</td><td>1.xx.x</td>
+<!-- Language Levels -------><td>1.61.0</td><td>1.xx.x</td>
 <!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
 <!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
 <!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
diff --git a/build/docker/README.md b/build/docker/README.md
index 7ea986f..1746d6d 100644
--- a/build/docker/README.md
+++ b/build/docker/README.md
@@ -172,7 +172,7 @@
 | C++ gcc   | 5.4.0         | 7.4.0         |       |
 | C++ clang | 3.8           | 6.0           |       |
 | C# (mono) | 4.2.1.0       | 4.6.2.7       |       |
-| c_glib    | 2.48.2        | 2.56.4        |       |
+| c\_glib    | 2.48.2        | 2.56.4        |       |
 | cl (sbcl) |               | 1.5.3         |       |
 | d         | 2.087.0       | 2.087.0       |       |
 | dart      | 2.0.0         | 2.4.0         |       |
@@ -180,7 +180,7 @@
 | erlang    | OTP-18        | OTP-23        |       |
 | go        | 1.15.10       | 1.16.2        |       |
 | haxe      | 3.2.1         | 3.4.4         | THRIFT-4352: avoid 3.4.2 |
-| java      | 1.8.0_191     | 11.0.3        |       |
+| java      | 1.8.0\_191     | 11.0.3        |       |
 | js        | Node.js 6.17.1, V8 5.1.281.111, npm 3.10.10 | Node.js 10.18.0, V8 6.8.275.32, npm 6.13.4 |     |
 | lua       |               | 5.2.4         | Lua 5.3: see THRIFT-4386 |
 | netstd    | 6.0           | 6.0           |       |
@@ -191,6 +191,6 @@
 | python    | 2.7.12        | 2.7.15        |       |
 | python3   | 3.5.2         | 3.6.8         |       |
 | ruby      | 2.3.1p112     | 2.5.1p57      |       |
-| rust      | 1.40.0        | 1.40.0        |       |
+| rust      | 1.61.0        | 1.61.0        |       |
 | smalltalk |               |               | Not in CI |
 | swift     |               | 5.1.4         |       |
diff --git a/build/docker/ubuntu-bionic/Dockerfile b/build/docker/ubuntu-bionic/Dockerfile
index aff9df4..1c859dd 100644
--- a/build/docker/ubuntu-bionic/Dockerfile
+++ b/build/docker/ubuntu-bionic/Dockerfile
@@ -254,7 +254,7 @@
       ruby-bundler
 
 # Rust dependencies
-RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y
+RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.61.0 -y
 ENV PATH /root/.cargo/bin:$PATH
 
 # Swift on Linux for cross tests
diff --git a/build/docker/ubuntu-disco/Dockerfile b/build/docker/ubuntu-disco/Dockerfile
index d530a35..6707079 100644
--- a/build/docker/ubuntu-disco/Dockerfile
+++ b/build/docker/ubuntu-disco/Dockerfile
@@ -254,7 +254,7 @@
       ruby-bundler
 
 # Rust dependencies
-RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y
+RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.61.0 -y
 ENV PATH /root/.cargo/bin:$PATH
 
 # Swift on Linux for cross tests
diff --git a/build/docker/ubuntu-xenial/Dockerfile b/build/docker/ubuntu-xenial/Dockerfile
index aec9bd3..34e902e 100644
--- a/build/docker/ubuntu-xenial/Dockerfile
+++ b/build/docker/ubuntu-xenial/Dockerfile
@@ -249,7 +249,7 @@
       ruby-bundler
 
 # Rust dependencies
-RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y
+RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.61.0 -y
 
 # Locale(s) for cpp unit tests
 RUN apt-get install -y --no-install-recommends \
diff --git a/compiler/cpp/src/thrift/generate/t_rs_generator.cc b/compiler/cpp/src/thrift/generate/t_rs_generator.cc
index 2f26847..6ce4027 100644
--- a/compiler/cpp/src/thrift/generate/t_rs_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_rs_generator.cc
@@ -127,7 +127,7 @@
   void render_const_value_holder(const string& name, t_type* ttype, t_const_value* tvalue);
 
   // Write the actual const value - the right side of a const definition.
-  void render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned = true);
+  void render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned = true, bool is_inline = true);
 
   // Write a const struct (returned from `const_value` method).
   void render_const_struct(t_type* ttype, t_const_value* tvalue);
@@ -141,14 +141,6 @@
   // Write a const map (returned from `const_value` method).
   void render_const_map(t_type* ttype, t_const_value* tvalue);
 
-  // Write the code to insert constant values into a rust vec or set. The
-  // `insert_function` is the rust function that we'll use to insert the elements.
-  void render_container_const_value(
-    const string& insert_function,
-    t_type* ttype,
-    t_const_value* tvalue
-  );
-
   // Write the rust representation of a thrift struct to the generated file. Set `struct_type` to `T_ARGS`
   // if rendering the struct used to pack arguments for a service call. When `struct_type` is `T_ARGS` the
   // struct and its members have module visibility, and all fields are required. When `struct_type` is
@@ -195,10 +187,6 @@
   // user-defined exception to be properly handled as Rust errors.
   void render_exception_struct_error_trait_impls(const string& struct_name, t_struct* tstruct);
 
-  // Write the implementations for the `Default`. This trait allows you to specify only the fields you want
-  // and use `..Default::default()` to fill in the rest.
-  void render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct);
-
   // Write the function that serializes a struct to its wire representation. If `struct_type` is `T_ARGS`
   // then all fields are considered "required", if not, the default optionality is used.
   void render_struct_sync_write(t_struct *tstruct, t_rs_generator::e_struct_type struct_type);
@@ -541,18 +529,21 @@
 void t_rs_generator::render_attributes_and_includes() {
   // turn off some compiler/clippy warnings
 
+  // code may not be used
+  f_gen_ << "#![allow(dead_code)]" << endl;
   // code always includes BTreeMap/BTreeSet/OrderedFloat
   f_gen_ << "#![allow(unused_imports)]" << endl;
   // code might not include imports from crates
   f_gen_ << "#![allow(unused_extern_crates)]" << endl;
   // constructors take *all* struct parameters, which can trigger the "too many arguments" warning
   // some auto-gen'd types can be deeply nested. clippy recommends factoring them out which is hard to autogen
+  // some methods may start with "is_"
   // FIXME: re-enable the 'vec_box' lint see: [THRIFT-5364](https://issues.apache.org/jira/browse/THRIFT-5364)
   // This can happen because we automatically generate a Vec<Box<Type>> when the type is a typedef
   // and it's a forward typedef. This (typedef + forward typedef) can happen in two situations:
   // 1. When the type is recursive
   // 2. When you define types out of order
-  f_gen_ << "#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::vec_box)]" << endl;
+  f_gen_ << "#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::vec_box, clippy::wrong_self_convention)]" << endl;
   // prevent rustfmt from running against this file
   // lines are too long, code is (thankfully!) not visual-indented, etc.
   // can't use #[rustfmt::skip] see: https://github.com/rust-lang/rust/issues/54726
@@ -684,7 +675,7 @@
 
   f_gen_ << indent() << "pub fn const_value() -> " << to_rust_type(ttype) << " {" << endl;
   indent_up();
-  render_const_value(ttype, tvalue);
+  render_const_value(ttype, tvalue, true, false);
   indent_down();
   f_gen_ << indent() << "}" << endl;
 
@@ -693,7 +684,11 @@
   f_gen_ << endl;
 }
 
-void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned) {
+void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned, bool is_inline) {
+  if (!is_inline) {
+    f_gen_ << indent();
+  }
+
   if (ttype->is_base_type()) {
     t_base_type* tbase_type = (t_base_type*)ttype;
     switch (tbase_type->get_base()) {
@@ -727,9 +722,9 @@
       throw "cannot generate const value for " + t_base_type::t_base_name(tbase_type->get_base());
     }
   } else if (ttype->is_typedef()) {
-    render_const_value(get_true_type(ttype), tvalue);
+    render_const_value(get_true_type(ttype), tvalue, is_owned, true);
   } else if (ttype->is_enum()) {
-    f_gen_ << indent() << "{" << endl;
+    f_gen_ << "{" << endl;
     indent_up();
     f_gen_
       << indent()
@@ -739,13 +734,11 @@
       << ").expect(\"expecting valid const value\")"
       << endl;
     indent_down();
-    f_gen_ << indent() << "}" << endl;
+    f_gen_ << indent() << "}";
   } else if (ttype->is_struct() || ttype->is_xception()) {
     render_const_struct(ttype, tvalue);
   } else if (ttype->is_container()) {
-    f_gen_ << indent() << "{" << endl;
-    indent_up();
-
+    // all of them use vec! or from(), extra block is no longer needed
     if (ttype->is_list()) {
       render_const_list(ttype, tvalue);
     } else if (ttype->is_set()) {
@@ -755,111 +748,87 @@
     } else {
       throw "cannot generate const container value for " + ttype->get_name();
     }
-
-    indent_down();
-    f_gen_ << indent() << "}" << endl;
   } else {
     throw "cannot generate const value for " + ttype->get_name();
   }
+
+  if (!is_inline) {
+    f_gen_ << endl;
+  }
 }
 
 void t_rs_generator::render_const_struct(t_type* ttype, t_const_value*) {
   if (((t_struct*)ttype)->is_union()) {
-    f_gen_ << indent() << "{" << endl;
+    f_gen_ << "{" << endl;
     indent_up();
     f_gen_ << indent() << "unimplemented!()" << endl;
     indent_down();
-    f_gen_ << indent() << "}" << endl;
+    f_gen_ << indent() << "}";
   } else {
-    f_gen_ << indent() << "{" << endl;
+    f_gen_ << "{" << endl;
     indent_up();
     f_gen_ << indent() << "unimplemented!()" << endl;
     indent_down();
-    f_gen_ << indent() << "}" << endl;
+    f_gen_ << indent() << "}";
   }
 }
 
 void t_rs_generator::render_const_list(t_type* ttype, t_const_value* tvalue) {
   t_type* elem_type = ((t_list*)ttype)->get_elem_type();
-  f_gen_ << indent() << "let mut l: Vec<" << to_rust_type(elem_type) << "> = Vec::new();" << endl;
+  f_gen_ << "vec![" << endl;
+  indent_up();
   const vector<t_const_value*>& elems = tvalue->get_list();
   vector<t_const_value*>::const_iterator elem_iter;
   for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
+    f_gen_ << indent();
     t_const_value* elem_value = (*elem_iter);
-    render_container_const_value("l.push", elem_type, elem_value);
+    render_const_value(elem_type, elem_value);
+    f_gen_ << "," << endl;
   }
-  f_gen_ << indent() << "l" << endl;
+  indent_down();
+  f_gen_ << indent() << "]";
 }
 
 void t_rs_generator::render_const_set(t_type* ttype, t_const_value* tvalue) {
   t_type* elem_type = ((t_set*)ttype)->get_elem_type();
-  f_gen_ << indent() << "let mut s: BTreeSet<" << to_rust_type(elem_type) << "> = BTreeSet::new();" << endl;
+  f_gen_ << "BTreeSet::from([" << endl;
+  indent_up();
   const vector<t_const_value*>& elems = tvalue->get_list();
   vector<t_const_value*>::const_iterator elem_iter;
   for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
+    f_gen_ << indent();
     t_const_value* elem_value = (*elem_iter);
-    render_container_const_value("s.insert", elem_type, elem_value);
+    render_const_value(elem_type, elem_value);
+    f_gen_ << "," << endl;
   }
-  f_gen_ << indent() << "s" << endl;
+  indent_down();
+  f_gen_ << indent() << "])";
 }
 
 void t_rs_generator::render_const_map(t_type* ttype, t_const_value* tvalue) {
   t_type* key_type = ((t_map*)ttype)->get_key_type();
   t_type* val_type = ((t_map*)ttype)->get_val_type();
-  f_gen_
-    << indent()
-    << "let mut m: BTreeMap<"
-    << to_rust_type(key_type) << ", " << to_rust_type(val_type)
-    << "> = BTreeMap::new();"
-    << endl;
+  f_gen_ << "BTreeMap::from([" << endl;
+  indent_up();
   const map<t_const_value*, t_const_value*, t_const_value::value_compare>& elems = tvalue->get_map();
   map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator elem_iter;
   for (elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
     t_const_value* key_value = elem_iter->first;
     t_const_value* val_value = elem_iter->second;
-    if (get_true_type(key_type)->is_base_type()) {
-      f_gen_ << indent() << "let k = ";
-      render_const_value(key_type, key_value);
-      f_gen_ << ";" << endl;
-    } else {
-      f_gen_ << indent() << "let k = {" << endl;
-      indent_up();
-      render_const_value(key_type, key_value);
-      indent_down();
-      f_gen_ << indent() << "};" << endl;
-    }
-    if (get_true_type(val_type)->is_base_type()) {
-      f_gen_ << indent() << "let v = ";
-      render_const_value(val_type, val_value);
-      f_gen_ << ";" << endl;
-    } else {
-      f_gen_ << indent() << "let v = {" << endl;
-      indent_up();
-      render_const_value(val_type, val_value);
-      indent_down();
-      f_gen_ << indent() << "};" << endl;
-    }
-    f_gen_ <<  indent() << "m.insert(k, v);" << endl;
-  }
-  f_gen_ << indent() << "m" << endl;
-}
 
-void t_rs_generator::render_container_const_value(
-  const string& insert_function,
-  t_type* ttype,
-  t_const_value* tvalue
-) {
-  if (get_true_type(ttype)->is_base_type()) {
-    f_gen_ << indent() << insert_function << "(";
-    render_const_value(ttype, tvalue);
-    f_gen_ << ");" << endl;
-  } else {
-    f_gen_ << indent() << insert_function << "(" << endl;
+    f_gen_ << indent() << "(" << endl;
     indent_up();
-    render_const_value(ttype, tvalue);
+    f_gen_ << indent();
+    render_const_value(key_type, key_value);
+    f_gen_ << "," << endl;
+    f_gen_ << indent();
+    render_const_value(val_type, val_value);
+    f_gen_ << "," << endl;
     indent_down();
-    f_gen_ << indent() << ");" << endl;
+    f_gen_ << indent() << ")," << endl;
   }
+  indent_down();
+  f_gen_ << indent() << "])";
 }
 
 //-----------------------------------------------------------------------------
@@ -1057,9 +1026,6 @@
   render_type_comment(struct_name);
   render_struct_definition(struct_name, tstruct, struct_type);
   render_struct_impl(struct_name, tstruct, struct_type);
-  if (struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION) {
-    render_struct_default_trait_impl(struct_name, tstruct);
-  }
   if (struct_type == t_rs_generator::T_EXCEPTION) {
     render_exception_struct_error_trait_impls(struct_name, tstruct);
   }
@@ -1071,15 +1037,27 @@
   t_rs_generator::e_struct_type struct_type
 ) {
   render_rustdoc((t_doc*) tstruct);
-  f_gen_ << "#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl;
+
+  const vector<t_field*> members = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator members_iter;
+  bool need_default = struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION;
+  for (members_iter = members.begin(); need_default && members_iter != members.end(); ++members_iter) {
+    t_field* member = *members_iter;
+    if (!is_optional(member->get_req())) {
+      need_default = false;
+    }
+  }
+  f_gen_
+    << "#[derive(Clone, Debug"
+    << (need_default ? ", Default" : "")
+    << ", Eq, Hash, Ord, PartialEq, PartialOrd)]"
+    << endl;
   f_gen_ << visibility_qualifier(struct_type) << "struct " << struct_name << " {" << endl;
 
   // render the members
-  vector<t_field*> members = tstruct->get_sorted_members();
   if (!members.empty()) {
     indent_up();
 
-    vector<t_field*>::iterator members_iter;
     for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
       t_field* member = (*members_iter);
       t_field::e_req member_req = actual_field_req(member, struct_type);
@@ -1137,49 +1115,6 @@
   f_gen_ << endl;
 }
 
-void t_rs_generator::render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct) {
-  bool has_required_field = false;
-
-  const vector<t_field*>& members = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator members_iter;
-  for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
-    t_field* member = *members_iter;
-    if (!is_optional(member->get_req())) {
-      has_required_field = true;
-      break;
-    }
-  }
-
-  if (has_required_field) {
-    return;
-  }
-
-  f_gen_ << "impl Default for " << struct_name << " {" << endl;
-  indent_up();
-  f_gen_ << indent() << "fn default() -> Self {" << endl;
-  indent_up();
-
-  if (members.empty()) {
-    f_gen_ << indent() << struct_name << "{}" << endl;
-  } else {
-    f_gen_ << indent() << struct_name << "{" << endl;
-    indent_up();
-    for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
-      t_field *member = (*members_iter);
-      string member_name(rust_field_name(member));
-      f_gen_ << indent() << member_name << ": " << opt_in_req_out_value(member->get_type()) << "," << endl;
-    }
-    indent_down();
-    f_gen_ << indent() << "}" << endl;
-  }
-
-  indent_down();
-  f_gen_ << indent() << "}" << endl;
-  indent_down();
-  f_gen_ << "}" << endl;
-  f_gen_ << endl;
-}
-
 void t_rs_generator::render_struct_impl(
   const string& struct_name,
   t_struct* tstruct,
@@ -1777,29 +1712,35 @@
   f_gen_ << indent() << "}" << endl;
 
   // now read all the fields found
-  f_gen_ << indent() << "let field_id = field_id(&field_ident)?;" << endl;
-  f_gen_ << indent() << "match field_id {" << endl; // start match
-  indent_up();
-
-  for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
-    t_field* tfield = (*members_iter);
-    f_gen_ << indent() << rust_safe_field_id(tfield->get_key()) << " => {" << endl;
+  // avoid clippy::match_single_binding
+  if (members.empty()) {
+    f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl;
+  } else {
+    f_gen_ << indent() << "let field_id = field_id(&field_ident)?;" << endl;
+    f_gen_ << indent() << "match field_id {" << endl; // start match
     indent_up();
-    render_type_sync_read("val", tfield->get_type());
-    f_gen_ << indent() << struct_field_read_temp_variable(tfield) << " = Some(val);" << endl;
+
+    for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+      t_field* tfield = (*members_iter);
+      f_gen_ << indent() << rust_safe_field_id(tfield->get_key()) << " => {" << endl;
+      indent_up();
+      render_type_sync_read("val", tfield->get_type());
+      f_gen_ << indent() << struct_field_read_temp_variable(tfield) << " = Some(val);" << endl;
+      indent_down();
+      f_gen_ << indent() << "}," << endl;
+    }
+
+    // default case (skip fields)
+    f_gen_ << indent() << "_ => {" << endl;
+    indent_up();
+    f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl;
     indent_down();
     f_gen_ << indent() << "}," << endl;
+
+    indent_down();
+    f_gen_ << indent() << "};" << endl; // finish match
   }
 
-  // default case (skip fields)
-  f_gen_ << indent() << "_ => {" << endl;
-  indent_up();
-  f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl;
-  indent_down();
-  f_gen_ << indent() << "}," << endl;
-
-  indent_down();
-  f_gen_ << indent() << "};" << endl; // finish match
   f_gen_ << indent() << "i_prot.read_field_end()?;" << endl;
   indent_down();
   f_gen_ << indent() << "}" << endl; // finish loop
diff --git a/lib/rs/Cargo.toml b/lib/rs/Cargo.toml
index 6c862aa..1ef524e 100644
--- a/lib/rs/Cargo.toml
+++ b/lib/rs/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "thrift"
 description = "Rust bindings for the Apache Thrift RPC system"
-edition = "2018"
+edition = "2021"
 version = "0.18.0"
 license = "Apache-2.0"
 authors = ["Apache Thrift Developers <dev@thrift.apache.org>"]
diff --git a/lib/rs/src/protocol/compact.rs b/lib/rs/src/protocol/compact.rs
index 566f344..87cfbfc 100644
--- a/lib/rs/src/protocol/compact.rs
+++ b/lib/rs/src/protocol/compact.rs
@@ -84,14 +84,13 @@
         let header = self.read_byte()?;
         let element_type = collection_u8_to_type(header & 0x0F)?;
 
-        let element_count;
         let possible_element_count = (header & 0xF0) >> 4;
-        if possible_element_count != 15 {
+        let element_count = if possible_element_count != 15 {
             // high bits set high if count and type encoded separately
-            element_count = possible_element_count as i32;
+            possible_element_count as i32
         } else {
-            element_count = self.transport.read_varint::<u32>()? as i32;
-        }
+            self.transport.read_varint::<u32>()? as i32
+        };
 
         Ok((element_type, element_count))
     }
diff --git a/lib/rs/src/server/multiplexed.rs b/lib/rs/src/server/multiplexed.rs
index 8331d91..b447d38 100644
--- a/lib/rs/src/server/multiplexed.rs
+++ b/lib/rs/src/server/multiplexed.rs
@@ -170,8 +170,7 @@
             let (_, svc_call) = svc_call.split_at(1); // remove colon from service call name
             (Some(svc_name), svc_call)
         })
-        .or_else(|| Some((None, ident_name)))
-        .unwrap()
+        .unwrap_or((None, ident_name))
 }
 
 fn missing_processor_message(svc_name: Option<&str>) -> String {
diff --git a/lib/rs/test/src/bin/kitchen_sink_client.rs b/lib/rs/test/src/bin/kitchen_sink_client.rs
index b98afb8..4cd2ba9 100644
--- a/lib/rs/test/src/bin/kitchen_sink_client.rs
+++ b/lib/rs/test/src/bin/kitchen_sink_client.rs
@@ -33,7 +33,6 @@
 use kitchen_sink::recursive::{CoRec, CoRec2, RecList, RecTree, TTestServiceSyncClient};
 use kitchen_sink::ultimate::{FullMealServiceSyncClient, TFullMealServiceSyncClient};
 
-use thrift;
 use thrift::protocol::{
     TBinaryInputProtocol, TBinaryOutputProtocol, TCompactInputProtocol, TCompactOutputProtocol,
     TInputProtocol, TOutputProtocol,
diff --git a/lib/rs/test/src/bin/kitchen_sink_server.rs b/lib/rs/test/src/bin/kitchen_sink_server.rs
index ea571c6..1abd07c 100644
--- a/lib/rs/test/src/bin/kitchen_sink_server.rs
+++ b/lib/rs/test/src/bin/kitchen_sink_server.rs
@@ -18,7 +18,6 @@
 use clap::{clap_app, value_t};
 use log::*;
 
-use thrift;
 use thrift::protocol::{
     TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory, TCompactInputProtocolFactory,
     TCompactOutputProtocolFactory, TInputProtocolFactory, TOutputProtocolFactory,
diff --git a/lib/rs/test/src/lib.rs b/lib/rs/test/src/lib.rs
index 91fd027..06f65cb 100644
--- a/lib/rs/test/src/lib.rs
+++ b/lib/rs/test/src/lib.rs
@@ -18,8 +18,8 @@
 pub mod base_one;
 pub mod base_two;
 pub mod midlayer;
-pub mod ultimate;
 pub mod recursive;
+pub mod ultimate;
 
 #[cfg(test)]
 mod tests {
diff --git a/lib/rs/test_recursive/src/lib.rs b/lib/rs/test_recursive/src/lib.rs
index bac37b4..5b9211c 100644
--- a/lib/rs/test_recursive/src/lib.rs
+++ b/lib/rs/test_recursive/src/lib.rs
@@ -17,9 +17,9 @@
 
 #![allow(dead_code)]
 
+pub mod maintenance;
 pub mod transit;
 pub mod vehicles;
-pub mod maintenance;
 
 mod server {
     use crate::maintenance::maintenance_facility::{
diff --git a/rust-toolchain b/rust-toolchain
index 32b7211..91951fd 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1 +1 @@
-1.40.0
+1.61.0
diff --git a/test/rs/src/bin/test_client.rs b/test/rs/src/bin/test_client.rs
index 8274aae..a44bac3 100644
--- a/test/rs/src/bin/test_client.rs
+++ b/test/rs/src/bin/test_client.rs
@@ -16,7 +16,6 @@
 // under the License.
 
 use clap::{clap_app, value_t};
-use env_logger;
 use log::*;
 
 use std::collections::{BTreeMap, BTreeSet};
@@ -28,7 +27,6 @@
 #[cfg(unix)]
 use std::path::Path;
 
-use thrift;
 use thrift::protocol::{
     TBinaryInputProtocol, TBinaryOutputProtocol, TCompactInputProtocol, TCompactOutputProtocol,
     TInputProtocol, TMultiplexedOutputProtocol, TOutputProtocol,
@@ -346,60 +344,44 @@
 
     info!("testList");
     {
-        let mut v_snd: Vec<i32> = Vec::new();
-        v_snd.push(29384);
-        v_snd.push(238);
-        v_snd.push(32498);
+        let v_snd: Vec<i32> = vec![29384, 238, 32498];
 
-        let mut v_cmp: Vec<i32> = Vec::new();
-        v_cmp.push(29384);
-        v_cmp.push(238);
-        v_cmp.push(32498);
+        let v_cmp: Vec<i32> = vec![29384, 238, 32498];
 
         verify_expected_result(thrift_test_client.test_list(v_snd), v_cmp)?;
     }
 
     info!("testSet");
     {
-        let mut s_snd: BTreeSet<i32> = BTreeSet::new();
-        s_snd.insert(293_481);
-        s_snd.insert(23);
-        s_snd.insert(3234);
+        let s_snd: BTreeSet<i32> = BTreeSet::from([293_481, 23, 3234]);
 
-        let mut s_cmp: BTreeSet<i32> = BTreeSet::new();
-        s_cmp.insert(293_481);
-        s_cmp.insert(23);
-        s_cmp.insert(3234);
+        let s_cmp: BTreeSet<i32> = BTreeSet::from([293_481, 23, 3234]);
 
         verify_expected_result(thrift_test_client.test_set(s_snd), s_cmp)?;
     }
 
     info!("testMap");
     {
-        let mut m_snd: BTreeMap<i32, i32> = BTreeMap::new();
-        m_snd.insert(2, 4);
-        m_snd.insert(4, 6);
-        m_snd.insert(8, 7);
+        let m_snd: BTreeMap<i32, i32> = BTreeMap::from([(2, 4), (4, 6), (8, 7)]);
 
-        let mut m_cmp: BTreeMap<i32, i32> = BTreeMap::new();
-        m_cmp.insert(2, 4);
-        m_cmp.insert(4, 6);
-        m_cmp.insert(8, 7);
+        let m_cmp: BTreeMap<i32, i32> = BTreeMap::from([(2, 4), (4, 6), (8, 7)]);
 
         verify_expected_result(thrift_test_client.test_map(m_snd), m_cmp)?;
     }
 
     info!("testStringMap");
     {
-        let mut m_snd: BTreeMap<String, String> = BTreeMap::new();
-        m_snd.insert("2".to_owned(), "4_string".to_owned());
-        m_snd.insert("4".to_owned(), "6_string".to_owned());
-        m_snd.insert("8".to_owned(), "7_string".to_owned());
+        let m_snd: BTreeMap<String, String> = BTreeMap::from([
+            ("2".to_owned(), "4_string".to_owned()),
+            ("4".to_owned(), "6_string".to_owned()),
+            ("8".to_owned(), "7_string".to_owned()),
+        ]);
 
-        let mut m_rcv: BTreeMap<String, String> = BTreeMap::new();
-        m_rcv.insert("2".to_owned(), "4_string".to_owned());
-        m_rcv.insert("4".to_owned(), "6_string".to_owned());
-        m_rcv.insert("8".to_owned(), "7_string".to_owned());
+        let m_rcv: BTreeMap<String, String> = BTreeMap::from([
+            ("2".to_owned(), "4_string".to_owned()),
+            ("4".to_owned(), "6_string".to_owned()),
+            ("8".to_owned(), "7_string".to_owned()),
+        ]);
 
         verify_expected_result(thrift_test_client.test_string_map(m_snd), m_rcv)?;
     }
@@ -409,27 +391,19 @@
     // => 2, 3 => 3, 4 => 4, }, }
     info!("testMapMap");
     {
-        let mut m_cmp_nested_0: BTreeMap<i32, i32> = BTreeMap::new();
-        for i in (-4 as i32)..0 {
-            m_cmp_nested_0.insert(i, i);
-        }
-        let mut m_cmp_nested_1: BTreeMap<i32, i32> = BTreeMap::new();
-        for i in 1..5 {
-            m_cmp_nested_1.insert(i, i);
-        }
+        let m_cmp_nested_0: BTreeMap<i32, i32> = (-4..0).map(|i| (i, i)).collect();
+        let m_cmp_nested_1: BTreeMap<i32, i32> = (1..5).map(|i| (i, i)).collect();
 
-        let mut m_cmp: BTreeMap<i32, BTreeMap<i32, i32>> = BTreeMap::new();
-        m_cmp.insert(-4, m_cmp_nested_0);
-        m_cmp.insert(4, m_cmp_nested_1);
+        let m_cmp: BTreeMap<i32, BTreeMap<i32, i32>> =
+            BTreeMap::from([(-4, m_cmp_nested_0), (4, m_cmp_nested_1)]);
 
         verify_expected_result(thrift_test_client.test_map_map(42), m_cmp)?;
     }
 
     info!("testMulti");
     {
-        let mut m_snd: BTreeMap<i16, String> = BTreeMap::new();
-        m_snd.insert(1298, "fizz".to_owned());
-        m_snd.insert(-148, "buzz".to_owned());
+        let m_snd: BTreeMap<i16, String> =
+            BTreeMap::from([(1298, "fizz".to_owned()), (-148, "buzz".to_owned())]);
 
         let s_cmp = Xtruct {
             string_thing: Some("Hello2".to_owned()),
@@ -452,48 +426,48 @@
     //   2 => { 6 => <empty Insanity struct>, },
     // }
     {
-        let mut arg_map_usermap: BTreeMap<Numberz, i64> = BTreeMap::new();
-        arg_map_usermap.insert(Numberz::ONE, 4289);
-        arg_map_usermap.insert(Numberz::EIGHT, 19);
+        let arg_map_usermap: BTreeMap<Numberz, i64> =
+            BTreeMap::from([(Numberz::ONE, 4289), (Numberz::EIGHT, 19)]);
 
-        let mut arg_vec_xtructs: Vec<Xtruct> = Vec::new();
-        arg_vec_xtructs.push(Xtruct {
-            string_thing: Some("foo".to_owned()),
-            byte_thing: Some(8),
-            i32_thing: Some(29),
-            i64_thing: Some(92384),
-        });
-        arg_vec_xtructs.push(Xtruct {
-            string_thing: Some("bar".to_owned()),
-            byte_thing: Some(28),
-            i32_thing: Some(2),
-            i64_thing: Some(-1281),
-        });
-        arg_vec_xtructs.push(Xtruct {
-            string_thing: Some("baz".to_owned()),
-            byte_thing: Some(0),
-            i32_thing: Some(3_948_539),
-            i64_thing: Some(-12_938_492),
-        });
+        let arg_vec_xtructs: Vec<Xtruct> = vec![
+            Xtruct {
+                string_thing: Some("foo".to_owned()),
+                byte_thing: Some(8),
+                i32_thing: Some(29),
+                i64_thing: Some(92384),
+            },
+            Xtruct {
+                string_thing: Some("bar".to_owned()),
+                byte_thing: Some(28),
+                i32_thing: Some(2),
+                i64_thing: Some(-1281),
+            },
+            Xtruct {
+                string_thing: Some("baz".to_owned()),
+                byte_thing: Some(0),
+                i32_thing: Some(3_948_539),
+                i64_thing: Some(-12_938_492),
+            },
+        ];
 
-        let mut s_cmp_nested_1: BTreeMap<Numberz, Insanity> = BTreeMap::new();
         let insanity = Insanity {
             user_map: Some(arg_map_usermap),
             xtructs: Some(arg_vec_xtructs),
         };
-        s_cmp_nested_1.insert(Numberz::TWO, insanity.clone());
-        s_cmp_nested_1.insert(Numberz::THREE, insanity.clone());
+        let s_cmp_nested_1: BTreeMap<Numberz, Insanity> = BTreeMap::from([
+            (Numberz::TWO, insanity.clone()),
+            (Numberz::THREE, insanity.clone()),
+        ]);
 
-        let mut s_cmp_nested_2: BTreeMap<Numberz, Insanity> = BTreeMap::new();
         let empty_insanity = Insanity {
             user_map: Some(BTreeMap::new()),
             xtructs: Some(Vec::new()),
         };
-        s_cmp_nested_2.insert(Numberz::SIX, empty_insanity);
+        let s_cmp_nested_2: BTreeMap<Numberz, Insanity> =
+            BTreeMap::from([(Numberz::SIX, empty_insanity)]);
 
-        let mut s_cmp: BTreeMap<UserId, BTreeMap<Numberz, Insanity>> = BTreeMap::new();
-        s_cmp.insert(1 as UserId, s_cmp_nested_1);
-        s_cmp.insert(2 as UserId, s_cmp_nested_2);
+        let s_cmp: BTreeMap<UserId, BTreeMap<Numberz, Insanity>> =
+            BTreeMap::from([(1, s_cmp_nested_1), (2, s_cmp_nested_2)]);
 
         verify_expected_result(thrift_test_client.test_insanity(insanity), s_cmp)?;
     }
diff --git a/test/rs/src/bin/test_server.rs b/test/rs/src/bin/test_server.rs
index 7e6d08f..a27bd77 100644
--- a/test/rs/src/bin/test_server.rs
+++ b/test/rs/src/bin/test_server.rs
@@ -16,14 +16,12 @@
 // under the License.
 
 use clap::{clap_app, value_t};
-use env_logger;
 use log::*;
 
 use std::collections::{BTreeMap, BTreeSet};
 use std::thread;
 use std::time::Duration;
 
-use thrift;
 use thrift::protocol::{
     TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory, TCompactInputProtocolFactory,
     TCompactOutputProtocolFactory, TInputProtocolFactory, TOutputProtocolFactory,
@@ -256,7 +254,7 @@
         info!("testMapMap({})", hello);
 
         let mut inner_map_0: BTreeMap<i32, i32> = BTreeMap::new();
-        for i in -4..(0 as i32) {
+        for i in -4..0 {
             inner_map_0.insert(i, i);
         }