THRIFT-4478: Thrift will not build with dlang 2.078 or later (#1559)

* THRIFT-4478 Thrift will not build with dlang 2.078 or later

This fixes build errors and deprecation warnings on dmd v2.080.0.

* THRIFT-4478: Update ubuntu-artful docker build image to use DMD 2.080.0

* THRIFT-4478 Fix build failure for nonblocking

* THRIFT-4478: update readme files
diff --git a/lib/d/src/thrift/async/socket.d b/lib/d/src/thrift/async/socket.d
index 6de13d9..a08f51d 100644
--- a/lib/d/src/thrift/async/socket.d
+++ b/lib/d/src/thrift/async/socket.d
@@ -18,6 +18,7 @@
  */
 module thrift.async.socket;
 
+import core.stdc.errno: ECONNRESET;
 import core.thread : Fiber;
 import core.time : dur, Duration;
 import std.array : empty;
diff --git a/lib/d/src/thrift/server/transport/base.d b/lib/d/src/thrift/server/transport/base.d
index da165d3..704e16d 100644
--- a/lib/d/src/thrift/server/transport/base.d
+++ b/lib/d/src/thrift/server/transport/base.d
@@ -95,16 +95,7 @@
 
   ///
   this(Type type, string file = __FILE__, size_t line = __LINE__, Throwable next = null) {
-    string msg = "TTransportException: ";
-    switch (type) {
-      case Type.UNKNOWN: msg ~= "Unknown server transport exception"; break;
-      case Type.NOT_LISTENING: msg ~= "Server transport not listening"; break;
-      case Type.ALREADY_LISTENING: msg ~= "Server transport already listening"; break;
-      case Type.RESOURCE_FAILED: msg ~= "An underlying resource failed"; break;
-      default: msg ~= "(Invalid exception type)"; break;
-    }
-
-    this(msg, type, file, line, next);
+    this(errorMsg(type), type, file, line, next);
   }
 
   ///
@@ -129,5 +120,18 @@
 
 protected:
   Type type_;
+
+private:
+  string errorMsg(Type type) {
+    string msg = "TTransportException: ";
+    switch (type) {
+      case Type.UNKNOWN: msg ~= "Unknown server transport exception"; break;
+      case Type.NOT_LISTENING: msg ~= "Server transport not listening"; break;
+      case Type.ALREADY_LISTENING: msg ~= "Server transport already listening"; break;
+      case Type.RESOURCE_FAILED: msg ~= "An underlying resource failed"; break;
+      default: msg ~= "(Invalid exception type)"; break;
+    }
+    return msg;
+  }
 }
 
diff --git a/lib/d/src/thrift/transport/file.d b/lib/d/src/thrift/transport/file.d
index aac7289..fe88e73 100644
--- a/lib/d/src/thrift/transport/file.d
+++ b/lib/d/src/thrift/transport/file.d
@@ -37,7 +37,8 @@
 import std.algorithm : min, max;
 import std.concurrency;
 import std.conv : to;
-import std.datetime : AutoStart, dur, Duration, StopWatch;
+import std.datetime : dur, Duration;
+import std.datetime.stopwatch : AutoStart, StopWatch;
 import std.exception;
 import std.stdio : File;
 import thrift.base;
@@ -1076,15 +1077,15 @@
 
       // If any attempt takes more than 500ms, treat that as a fatal failure to
       // avoid looping over a potentially very slow operation.
-      enforce(sw.peek().msecs < 1500,
-        text("close() took ", sw.peek().msecs, "ms."));
+      enforce(sw.peek().total!"msecs" < 1500,
+        text("close() took ", sw.peek().total!"msecs", "ms."));
 
       // Normally, it takes less than 5ms on my dev box.
       // However, if the box is heavily loaded, some of the test runs can take
       // longer. Additionally, on a Windows Server 2008 instance running in
       // a VirtualBox VM, it has been observed that about a quarter of the runs
       // takes (217 ± 1) ms, for reasons not yet known.
-      if (sw.peek().msecs > 50) {
+      if (sw.peek().total!"msecs" > 50) {
         ++numOver;
       }
 
diff --git a/lib/d/src/thrift/transport/socket.d b/lib/d/src/thrift/transport/socket.d
index 228abf0..fcb38da 100644
--- a/lib/d/src/thrift/transport/socket.d
+++ b/lib/d/src/thrift/transport/socket.d
@@ -18,6 +18,7 @@
  */
 module thrift.transport.socket;
 
+import core.stdc.errno: ECONNRESET;
 import core.thread : Thread;
 import core.time : dur, Duration;
 import std.array : empty;
@@ -256,7 +257,7 @@
         new TCompoundOperationException(
           text(
             "All addresses tried failed (",
-            joiner(map!q{text(a._0, `: "`, a._1.msg, `"`)}(zip(addrs, errors)), ", "),
+            joiner(map!q{text(a[0], `: "`, a[1].msg, `"`)}(zip(addrs, errors)), ", "),
             ")."
           ),
           errors
diff --git a/lib/d/test/client_pool_test.d b/lib/d/test/client_pool_test.d
index 85bcb29..52207d9 100644
--- a/lib/d/test/client_pool_test.d
+++ b/lib/d/test/client_pool_test.d
@@ -409,8 +409,8 @@
     )();
     Thread.sleep(dur!"msecs"(20));
     auto resultTuple = partialResult.finishGet();
-    enforce(resultTuple._0 == ports[0 .. 2]);
-    enforce(equal(map!"a.port"(cast(TestServiceException[])resultTuple._1),
+    enforce(resultTuple[0] == ports[0 .. 2]);
+    enforce(equal(map!"a.port"(cast(TestServiceException[])resultTuple[1]),
       ports[3 .. $ - 1]));
   }
 }
diff --git a/lib/d/test/serialization_benchmark.d b/lib/d/test/serialization_benchmark.d
index 35515c8..40d0480 100644
--- a/lib/d/test/serialization_benchmark.d
+++ b/lib/d/test/serialization_benchmark.d
@@ -13,7 +13,7 @@
  */
 module serialization_benchmark;
 
-import std.datetime : AutoStart, StopWatch;
+import std.datetime.stopwatch : AutoStart, StopWatch;
 import std.math : PI;
 import std.stdio;
 import thrift.protocol.binary;
@@ -46,7 +46,7 @@
     }
     sw.stop();
 
-    auto msecs = sw.peek().msecs;
+    auto msecs = sw.peek().total!"msecs";
     writefln("Write: %s ms (%s kHz)", msecs, ITERATIONS / msecs);
   }
 
@@ -64,7 +64,7 @@
     }
     sw.stop();
 
-    auto msecs = sw.peek().msecs;
+    auto msecs = sw.peek().total!"msecs";
     writefln(" Read: %s ms (%s kHz)", msecs, ITERATIONS / msecs);
   }
 }