Dart: Encode/Decode handle and interface types.

Adds sample_service_test.dart to test.

BUG=
R=abarth@chromium.org

Review URL: https://codereview.chromium.org/851173002
diff --git a/mojo/dart/embedder/test/dart_to_cpp_tests.dart b/mojo/dart/embedder/test/dart_to_cpp_tests.dart
index af3e076..531666a 100644
--- a/mojo/dart/embedder/test/dart_to_cpp_tests.dart
+++ b/mojo/dart/embedder/test/dart_to_cpp_tests.dart
@@ -64,8 +64,8 @@
       var messagePipe1 = new core.MojoMessagePipe();
       var messagePipe2 = new core.MojoMessagePipe();
 
-      arg.dataHandle = dataPipe1.consumer.handle;
-      arg.messageHandle = messagePipe1.endpoints[0].handle;
+      arg.dataHandle = dataPipe1.consumer;
+      arg.messageHandle = messagePipe1.endpoints[0];
 
       var specialArg = new EchoArgs();
       specialArg.si64 = -1;
@@ -73,8 +73,8 @@
       specialArg.si16 = -1;
       specialArg.si8 = -1;
       specialArg.name = 'going';
-      specialArg.dataHandle = dataPipe2.consumer.handle;
-      specialArg.messageHandle = messagePipe2.endpoints[0].handle;
+      specialArg.dataHandle = dataPipe2.consumer;
+      specialArg.messageHandle = messagePipe2.endpoints[0];
 
       dataPipe1.producer.write(_sampleData.buffer.asByteData());
       dataPipe2.producer.write(_sampleData.buffer.asByteData());
diff --git a/mojo/dart/embedder/test/run_dart_tests.cc b/mojo/dart/embedder/test/run_dart_tests.cc
index da6e3da..d6e5903 100644
--- a/mojo/dart/embedder/test/run_dart_tests.cc
+++ b/mojo/dart/embedder/test/run_dart_tests.cc
@@ -140,6 +140,10 @@
   RunTest("bindings_generation_test.dart", false, nullptr, 0);
 }
 
+TEST(DartTest, sample_service_test) {
+  RunTest("sample_service_test.dart", false, nullptr, 0);
+}
+
 TEST(DartTest, compile_all_interfaces_test) {
   RunTest("compile_all_interfaces_test.dart", true, nullptr, 0);
 }
diff --git a/mojo/dart/test/core_test.dart b/mojo/dart/test/core_test.dart
index 337785a..c62a267 100644
--- a/mojo/dart/test/core_test.dart
+++ b/mojo/dart/test/core_test.dart
@@ -60,13 +60,13 @@
   Expect.isTrue(dataPipe.consumer.status.isInvalidArgument);
 
   // Shared buffer.
-  MojoSharedBuffer sharedBuffer = new MojoSharedBuffer(10);
+  MojoSharedBuffer sharedBuffer = new MojoSharedBuffer.create(10);
   Expect.isNotNull(sharedBuffer);
   sharedBuffer.close();
   MojoSharedBuffer duplicate = new MojoSharedBuffer.duplicate(sharedBuffer);
   Expect.isNull(duplicate);
 
-  sharedBuffer = new MojoSharedBuffer(10);
+  sharedBuffer = new MojoSharedBuffer.create(10);
   Expect.isNotNull(sharedBuffer);
   sharedBuffer.close();
   result = sharedBuffer.map(0, 10);
@@ -239,7 +239,7 @@
 
 
 basicSharedBufferTest() {
-  MojoSharedBuffer mojoBuffer = new MojoSharedBuffer(
+  MojoSharedBuffer mojoBuffer = new MojoSharedBuffer.create(
       100, MojoSharedBuffer.CREATE_FLAG_NONE);
   Expect.isNotNull(mojoBuffer);
   Expect.isNotNull(mojoBuffer.status);
diff --git a/mojo/dart/test/sample_service_test.dart b/mojo/dart/test/sample_service_test.dart
new file mode 100644
index 0000000..29eb16b
--- /dev/null
+++ b/mojo/dart/test/sample_service_test.dart
@@ -0,0 +1,80 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:isolate';
+import 'dart:mojo_bindings' as bindings;
+import 'dart:mojo_core' as core;
+
+import 'package:mojo/public/interfaces/bindings/tests/sample_service.mojom.dart' as sample;
+
+class ExpectPortInterfaceImpl implements sample.PortInterface {
+  String _expected;
+  ExpectPortInterfaceImpl([this._expected = ""]);
+
+  void postMessage(String messageText, sample.PortClient port) {
+    assert(messageText == _expected);
+    port.close();
+  }
+}
+
+class ServiceImpl extends sample.ServiceInterface {
+  ServiceImpl(core.MojoMessagePipeEndpoint endpoint) : super(endpoint);
+
+  void frobinate(sample.Foo foo, int baz, sample.PortClient portClient) {
+    var portInterface = new sample.PortInterface.unbound();
+    portInterface.delegate = new ExpectPortInterfaceImpl();
+    portClient.callPostMessage("frobinated", portInterface);
+    portInterface.listen();
+    callDidFrobinate(42);
+    portClient.close();
+  }
+
+  void getPort(sample.PortInterface portInterface) {
+    portInterface.delegate = new ExpectPortInterfaceImpl("port");
+    portInterface.listen();
+  }
+}
+
+class ServiceClientImpl extends sample.ServiceClientInterface
+                        with sample.ServiceCalls {
+  Completer completer;
+
+  ServiceClientImpl(core.MojoMessagePipeEndpoint endpoint) : super(endpoint);
+
+  void didFrobinate(int result) {
+    assert(result == 42);
+    completer.complete(null);
+  }
+
+  Future run() {
+    completer = new Completer();
+
+    listen();
+    var portClient = new sample.PortClient.unbound();
+    callGetPort(portClient);
+    portClient.close();
+
+    var portInterface = new sample.PortInterface.unbound();
+    portInterface.delegate = new ExpectPortInterfaceImpl("frobinated");
+    callFrobinate(new sample.Foo(), sample.BazOptions_EXTRA, portInterface);
+    portInterface.listen();
+    return completer.future;
+  }
+}
+
+void serviceIsolate(core.MojoMessagePipeEndpoint endpoint) {
+  var service = new ServiceImpl(endpoint);
+  service.listen();
+}
+
+main() async {
+  var pipe = new core.MojoMessagePipe();
+  var isolate = await Isolate.spawn(serviceIsolate, pipe.endpoints[0]);
+
+  var serviceClient = new ServiceClientImpl(pipe.endpoints[1]);
+  await serviceClient.run();
+
+  serviceClient.close();
+}
diff --git a/mojo/public/dart/src/buffer.dart b/mojo/public/dart/src/buffer.dart
index c0071b3..4467315 100644
--- a/mojo/public/dart/src/buffer.dart
+++ b/mojo/public/dart/src/buffer.dart
@@ -5,16 +5,16 @@
 part of core;
 
 class _MojoSharedBufferNatives {
-  static List Create(int num_bytes, int flags)
+  static List Create(int numBytes, int flags)
       native "MojoSharedBuffer_Create";
 
-  static List Duplicate(int buffer_handle, int flags)
+  static List Duplicate(int bufferHandle, int flags)
       native "MojoSharedBuffer_Duplicate";
 
   static List Map(MojoSharedBuffer buffer,
-                  int buffer_handle,
+                  int bufferHandle,
                   int offset,
-                  int num_bytes,
+                  int numBytes,
                   int flags)
       native "MojoSharedBuffer_Map";
 
@@ -32,14 +32,11 @@
   MojoResult status;
   ByteData mapping;
 
-  MojoSharedBuffer._() {
-    handle = null;
-    status = MojoResult.OK;
-    mapping = null;
-  }
+  MojoSharedBuffer(
+      this.handle, [this.status = MojoResult.OK, this.mapping = null]);
 
-  factory MojoSharedBuffer(int num_bytes, [int flags = 0]) {
-    List result = _MojoSharedBufferNatives.Create(num_bytes, flags);
+  factory MojoSharedBuffer.create(int numBytes, [int flags = 0]) {
+    List result = _MojoSharedBufferNatives.Create(numBytes, flags);
     if (result == null) {
       return null;
     }
@@ -49,10 +46,8 @@
       return null;
     }
 
-    MojoSharedBuffer buf = new MojoSharedBuffer._();
-    buf.status = r;
-    buf.handle = new MojoHandle(result[1]);
-    buf.mapping = null;
+    MojoSharedBuffer buf =
+        new MojoSharedBuffer(new MojoHandle(result[1]), r, null);
     return buf;
   }
 
@@ -67,10 +62,8 @@
       return null;
     }
 
-    MojoSharedBuffer dupe = new MojoSharedBuffer._();
-    dupe.status = r;
-    dupe.handle = new MojoHandle(result[1]);
-    dupe.mapping = null;  // The buffer is not mapped in the duplicate.
+    MojoSharedBuffer dupe =
+        new MojoSharedBuffer(new MojoHandle(result[1]), r, null);
     return dupe;
   }
 
@@ -85,13 +78,13 @@
     return status;
   }
 
-  MojoResult map(int offset, int num_bytes, [int flags = 0]) {
+  MojoResult map(int offset, int numBytes, [int flags = 0]) {
     if (handle == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return status;
     }
     List result = _MojoSharedBufferNatives.Map(
-        this, handle.h, offset, num_bytes, flags);
+        this, handle.h, offset, numBytes, flags);
     if (result == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return status;
diff --git a/mojo/public/dart/src/client.dart b/mojo/public/dart/src/client.dart
index a056402..f8ec73c 100644
--- a/mojo/public/dart/src/client.dart
+++ b/mojo/public/dart/src/client.dart
@@ -12,10 +12,14 @@
       _completerMap = {},
       super(endpoint);
 
-  Client.fromHandle(int handle) :
+  Client.fromHandle(core.MojoHandle handle) :
       _completerMap = {},
       super.fromHandle(handle);
 
+  Client.unbound() :
+      _completerMap = {},
+      super.unbound();
+
   void handleResponse(ServiceMessage reader);
 
   void handleRead() {
diff --git a/mojo/public/dart/src/codec.dart b/mojo/public/dart/src/codec.dart
index 8969ea1..d5f5b90 100644
--- a/mojo/public/dart/src/codec.dart
+++ b/mojo/public/dart/src/codec.dart
@@ -138,6 +138,42 @@
     }
   }
 
+  void encodeMessagePipeHandle(
+      core.MojoMessagePipeEndpoint value, int offset, bool nullable) =>
+      encodeHandle(value != null ? value.handle : null, offset, nullable);
+
+  void encodeConsumerHandle(
+      core.MojoDataPipeConsumer value, int offset, bool nullable) =>
+      encodeHandle(value != null ? value.handle : null, offset, nullable);
+
+  void encodeProducerHandle(
+      core.MojoDataPipeProducer value, int offset, bool nullable) =>
+      encodeHandle(value != null ? value.handle : null, offset, nullable);
+
+  void encodeSharedBufferHandle(
+      core.MojoSharedBuffer value, int offset, bool nullable) =>
+      encodeHandle(value != null ? value.handle : null, offset, nullable);
+
+  void encodeInterface(Interface interface, int offset, bool nullable) {
+    if (interface == null) {
+      encodeInvalideHandle(offset, nullable);
+      return;
+    }
+    var pipe = new core.MojoMessagePipe();
+    interface.bind(pipe.endpoints[0]);
+    encodeMessagePipeHandle(pipe.endpoints[1], offset, nullable);
+  }
+
+  void encodeInterfaceRequest(Client client, int offset, bool nullable) {
+    if (client == null) {
+      encodeInvalideHandle(offset, nullable);
+      return;
+    }
+    var pipe = new core.MojoMessagePipe();
+    client.bind(pipe.endpoints[0]);
+    encodeMessagePipeHandle(pipe.endpoints[1], offset, nullable);
+  }
+
   void encodeNullPointer(int offset, bool nullable) {
     if (!nullable) {
       throw 'Trying to encode a null pointer for a non-nullable type';
@@ -271,10 +307,11 @@
       encodeArray((e, v) => e.appendDoubleArray(v),
                   8, value, offset, nullability, expectedLength);
 
-  void encodeHandleArray(List<core.MojoHandle> value,
-                         int offset,
-                         int nullability,
-                         int expectedLength) {
+  void _handleArrayEncodeHelper(Function elementEncoder,
+                                List value,
+                                int offset,
+                                int nullability,
+                                int expectedLength) {
     if (value == null) {
       encodeNullPointer(offset, isArrayNullable(nullability));
       return;
@@ -283,11 +320,74 @@
         kSerializedHandleSize, value.length, offset, expectedLength);
     for (int i = 0; i < value.length; ++i) {
       int handleOffset = DataHeader.kHeaderSize + kSerializedHandleSize * i;
-      encoder.encodeHandle(
-          value[i], handleOffset, isElementNullable(nullability));
+      elementEncoder(
+          encoder, value[i], handleOffset, isElementNullable(nullability));
     }
   }
 
+  void encodeHandleArray(
+      List<core.MojoHandle> value,
+      int offset,
+      int nullability,
+      int expectedLength) =>
+      _handleArrayEncodeHelper(
+          (e, v, o, n) => e.encodeHandle(v, o, n),
+          value, offset, nullability, expectedLength);
+
+  void encodeMessagePipeHandleArray(
+      List<core.MojoMessagePipeEndpoint> value,
+      int offset,
+      int nullability,
+      int expectedLength) =>
+      _handleArrayEncodeHelper(
+          (e, v, o, n) => e.encodeMessagePipeHandle(v, o, n),
+          value, offset, nullability, expectedLength);
+
+  void encodeConsumerHandleArray(
+      List<core.MojoDataPipeConsumer> value,
+      int offset,
+      int nullability,
+      int expectedLength) =>
+      _handleArrayEncodeHelper(
+          (e, v, o, n) => e.encodeConsumerHandle(v, o, n),
+          value, offset, nullability, expectedLength);
+
+  void encodeProducerHandleArray(
+      List<core.MojoDataPipeProducer> value,
+      int offset,
+      int nullability,
+      int expectedLength) =>
+      _handleArrayEncodeHelper(
+          (e, v, o, n) => e.encodeProducerHandle(v, o, n),
+          value, offset, nullability, expectedLength);
+
+  void encodeSharedBufferHandleArray(
+      List<core.MojoSharedBuffer> value,
+      int offset,
+      int nullability,
+      int expectedLength) =>
+      _handleArrayEncodeHelper(
+          (e, v, o, n) => e.encodeSharedBufferHandle(v, o, n),
+          value, offset, nullability, expectedLength);
+
+  void encodeInterfaceRequestArray(
+      List<Client> value,
+      int offset,
+      int nullability,
+      int expectedLength) =>
+      _handleArrayEncodeHelper(
+          (e, v, o, n) => e.encodeInterfaceRequest(v, o, n),
+          value, offset, nullability, expectedLength);
+
+  void encodeInterfaceArray(
+      List<Interface> value,
+      int offset,
+      int nullability,
+      int expectedLength) =>
+      _handleArrayEncodeHelper(
+          (e, v, o, n) => e.encodeInterface(v, o, n),
+          value, offset, nullability, expectedLength);
+
   static Uint8List _utf8OfString(String s) =>
       (new Uint8List.fromList((const Utf8Encoder()).convert(s)));
 
@@ -346,6 +446,7 @@
   }
 }
 
+
 class Decoder {
   Message _message;
   int _base = 0;
@@ -393,6 +494,31 @@
     return _handles[index];
   }
 
+  core.MojoMessagePipeEndpoint decodeMessagePipeHandle(
+      int offset, bool nullable) =>
+      new core.MojoMessagePipeEndpoint(decodeHandle(offset, nullable));
+
+  core.MojoDataPipeConsumer decodeConsumerHandle(int offset, bool nullable) =>
+      new core.MojoDataPipeConsumer(decodeHandle(offset, nullable));
+
+  core.MojoDataPipeProducer decodeProducerHandle(int offset, bool nullable) =>
+      new core.MojoDataPipeProducer(decodeHandle(offset, nullable));
+
+  core.MojoSharedBuffer decodeSharedBufferHandle(int offset, bool nullable) =>
+      new core.MojoSharedBuffer(decodeHandle(offset, nullable));
+
+  Client decodeServiceInterface(
+      int offset, bool nullable, Function clientFactory) {
+    var endpoint = decodeMessagePipeHandle(offset, nullable);
+    return endpoint.handle.isValid ? clientFactory(endpoint) : null;
+  }
+
+  Interface decodeInterfaceRequest(
+      int offset, bool nullable, Function interfaceFactory) {
+    var endpoint = decodeMessagePipeHandle(offset, nullable);
+    return endpoint.handle.isValid ? interfaceFactory(endpoint) : null;
+  }
+
   Decoder decodePointer(int offset, bool nullable) {
     int basePosition = _base + offset;
     int pointerOffset = decodeUint64(offset);
@@ -528,22 +654,69 @@
       decodeArray((b, s, l) => new Float64List.view(b, s, l),
                   8, offset, nullability, expectedLength);
 
-  List<core.MojoHandle> decodeHandleArray(
-      int offset, int nullability, int expectedLength) {
+  List _handleArrayDecodeHelper(Function elementDecoder,
+                                int offset,
+                                int nullability,
+                                int expectedLength) {
     Decoder d = decodePointer(offset, isArrayNullable(nullability));
     if (d == null) {
       return null;
     }
     var header = d.decodeDataHeaderForArray(4, expectedLength);
-    var result = new core.MojoHandle(header.numFields);
+    var result = new List(header.numFields);
     for (int i = 0; i < result.length; ++i) {
-      result[i] = d.decodeHandle(
+      result[i] = elementDecoder(
+          d,
           DataHeader.kHeaderSize + kSerializedHandleSize * i,
           isElementNullable(nullability));
     }
     return result;
+
   }
 
+  List<core.MojoHandle> decodeHandleArray(
+      int offset, int nullability, int expectedLength) =>
+      _handleArrayDecodeHelper((d, o, n) => d.decodeHandle(o, n),
+                               offset, nullability, expectedLength);
+
+  List<core.MojoDataPipeConsumer> decodeConsumerHandleArray(
+      int offset, int nullability, int expectedLength) =>
+      _handleArrayDecodeHelper((d, o, n) => d.decodeConsumerHandle(o, n),
+                               offset, nullability, expectedLength);
+
+  List<core.MojoDataPipeProducer> decodeProducerHandleArray(
+      int offset, int nullability, int expectedLength) =>
+      _handleArrayDecodeHelper((d, o, n) => d.decodeProducerHandle(o, n),
+                               offset, nullability, expectedLength);
+
+  List<core.MojoMessagePipeEndpoint> decodeMessagePipeHandleArray(
+      int offset, int nullability, int expectedLength) =>
+      _handleArrayDecodeHelper((d, o, n) => d.decodeMessagePipeHandle(o, n),
+                               offset, nullability, expectedLength);
+
+  List<core.MojoSharedBuffer> decodeSharedBufferHandleArray(
+      int offset, int nullability, int expectedLength) =>
+      _handleArrayDecodeHelper((d, o, n) => d.decodeSharedBufferHandle(o, n),
+                               offset, nullability, expectedLength);
+
+  List<Interface> decodeInterfaceRequestArray(
+      int offset,
+      int nullability,
+      int expectedLength,
+      Function interfaceFactory) =>
+      _handleArrayDecodeHelper(
+          (d, o, n) => d.decodeInterfaceRequest(o, n, interfaceFactory),
+          offset, nullability, expectedLength);
+
+  List<Client> decodeServiceInterfaceArray(
+      int offset,
+      int nullability,
+      int expectedLength,
+      Function clientFactory) =>
+      _handleArrayDecodeHelper(
+          (d, o, n) => d.decodeServiceInterface(o, n, clientFactory),
+          offset, nullability, expectedLength);
+
   static String _stringOfUtf8(Uint8List bytes) =>
       (const Utf8Decoder()).convert(bytes.toList());
 
diff --git a/mojo/public/dart/src/data_pipe.dart b/mojo/public/dart/src/data_pipe.dart
index 44acee9..7f3b3eb 100644
--- a/mojo/public/dart/src/data_pipe.dart
+++ b/mojo/public/dart/src/data_pipe.dart
@@ -7,25 +7,25 @@
 
 class _MojoDataPipeNatives {
   static List MojoCreateDataPipe(
-      int element_bytes, int capacity_bytes, int flags)
+      int elementBytes, int capacityBytes, int flags)
       native "MojoDataPipe_Create";
 
-  static List MojoWriteData(int handle, ByteData data, int num_bytes, int flags)
+  static List MojoWriteData(int handle, ByteData data, int numBytes, int flags)
       native "MojoDataPipe_WriteData";
 
-  static List MojoBeginWriteData(int handle, int buffer_bytes, int flags)
+  static List MojoBeginWriteData(int handle, int bufferBytes, int flags)
       native "MojoDataPipe_BeginWriteData";
 
-  static int MojoEndWriteData(int handle, int bytes_written)
+  static int MojoEndWriteData(int handle, int bytesWritten)
       native "MojoDataPipe_EndWriteData";
 
-  static List MojoReadData(int handle, ByteData data, int num_bytes, int flags)
+  static List MojoReadData(int handle, ByteData data, int numBytes, int flags)
       native "MojoDataPipe_ReadData";
 
-  static List MojoBeginReadData(int handle, int buffer_bytes, int flags)
+  static List MojoBeginReadData(int handle, int bufferBytes, int flags)
       native "MojoDataPipe_BeginReadData";
 
-  static int MojoEndReadData(int handle, int bytes_read)
+  static int MojoEndReadData(int handle, int bytesRead)
       native "MojoDataPipe_EndReadData";
 }
 
@@ -36,21 +36,20 @@
 
   MojoHandle handle;
   MojoResult status;
-  final int element_bytes;
+  final int elementBytes;
 
-  MojoDataPipeProducer(this.handle,
-                       this.status,
-                       this.element_bytes);
+  MojoDataPipeProducer(
+      this.handle, [this.status = MojoResult.OK, this.elementBytes = 1]);
 
-  int write(ByteData data, [int num_bytes = -1, int flags = 0]) {
+  int write(ByteData data, [int numBytes = -1, int flags = 0]) {
     if (handle == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return status;
     }
 
-    int data_num_bytes = (num_bytes == -1) ? data.lengthInBytes : num_bytes;
+    int data_numBytes = (numBytes == -1) ? data.lengthInBytes : numBytes;
     List result = _MojoDataPipeNatives.MojoWriteData(
-        handle.h, data, data_num_bytes, flags);
+        handle.h, data, data_numBytes, flags);
     if (result == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return status;
@@ -61,14 +60,14 @@
     return result[1];
   }
 
-  ByteData beginWrite(int buffer_bytes, [int flags = 0]) {
+  ByteData beginWrite(int bufferBytes, [int flags = 0]) {
     if (handle == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return null;
     }
 
     List result = _MojoDataPipeNatives.MojoBeginWriteData(
-        handle.h, buffer_bytes, flags);
+        handle.h, bufferBytes, flags);
     if (result == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return null;
@@ -79,12 +78,12 @@
     return result[1];
   }
 
-  MojoResult endWrite(int bytes_written) {
+  MojoResult endWrite(int bytesWritten) {
     if (handle == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return status;
     }
-    int result = _MojoDataPipeNatives.MojoEndWriteData(handle.h, bytes_written);
+    int result = _MojoDataPipeNatives.MojoEndWriteData(handle.h, bytesWritten);
     status = new MojoResult(result);
     return status;
   }
@@ -100,20 +99,20 @@
 
   MojoHandle handle;
   MojoResult status;
-  final int element_bytes;
+  final int elementBytes;
 
   MojoDataPipeConsumer(
-      this.handle, [this.status = MojoResult.OK, this.element_bytes = 1]);
+      this.handle, [this.status = MojoResult.OK, this.elementBytes = 1]);
 
-  int read(ByteData data, [int num_bytes = -1, int flags = 0]) {
+  int read(ByteData data, [int numBytes = -1, int flags = 0]) {
     if (handle == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return status;
     }
 
-    int data_num_bytes = (num_bytes == -1) ? data.lengthInBytes : num_bytes;
+    int data_numBytes = (numBytes == -1) ? data.lengthInBytes : numBytes;
     List result = _MojoDataPipeNatives.MojoReadData(
-        handle.h, data, data_num_bytes, flags);
+        handle.h, data, data_numBytes, flags);
     if (result == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return status;
@@ -123,14 +122,14 @@
     return result[1];
   }
 
-  ByteData beginRead([int buffer_bytes = 0, int flags = 0]) {
+  ByteData beginRead([int bufferBytes = 0, int flags = 0]) {
     if (handle == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return null;
     }
 
     List result = _MojoDataPipeNatives.MojoBeginReadData(
-        handle.h, buffer_bytes, flags);
+        handle.h, bufferBytes, flags);
     if (result == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return null;
@@ -141,12 +140,12 @@
     return result[1];
   }
 
-  MojoResult endRead(int bytes_read) {
+  MojoResult endRead(int bytesRead) {
     if (handle == null) {
       status = MojoResult.INVALID_ARGUMENT;
       return status;
     }
-    int result = _MojoDataPipeNatives.MojoEndReadData(handle.h, bytes_read);
+    int result = _MojoDataPipeNatives.MojoEndReadData(handle.h, bytesRead);
     status = new MojoResult(result);
     return status;
   }
@@ -171,22 +170,22 @@
     status = MojoResult.OK;
   }
 
-  factory MojoDataPipe([int element_bytes = DEFAULT_ELEMENT_SIZE,
-                        int capacity_bytes = DEFAULT_CAPACITY,
+  factory MojoDataPipe([int elementBytes = DEFAULT_ELEMENT_SIZE,
+                        int capacityBytes = DEFAULT_CAPACITY,
                         int flags = FLAG_NONE]) {
     List result = _MojoDataPipeNatives.MojoCreateDataPipe(
-        element_bytes, capacity_bytes, flags);
+        elementBytes, capacityBytes, flags);
     if (result == null) {
       return null;
     }
     assert((result is List) && (result.length == 3));
-    MojoHandle producer_handle = new MojoHandle(result[1]);
-    MojoHandle consumer_handle = new MojoHandle(result[2]);
+    MojoHandle producerHandle = new MojoHandle(result[1]);
+    MojoHandle consumerHandle = new MojoHandle(result[2]);
     MojoDataPipe pipe = new MojoDataPipe._internal();
     pipe.producer = new MojoDataPipeProducer(
-        producer_handle, new MojoResult(result[0]), element_bytes);
+        producerHandle, new MojoResult(result[0]), elementBytes);
     pipe.consumer = new MojoDataPipeConsumer(
-        consumer_handle, new MojoResult(result[0]), element_bytes);
+        consumerHandle, new MojoResult(result[0]), elementBytes);
     pipe.status = new MojoResult(result[0]);
     return pipe;
   }
diff --git a/mojo/public/dart/src/event_stream.dart b/mojo/public/dart/src/event_stream.dart
index bde490d..797f0e6 100644
--- a/mojo/public/dart/src/event_stream.dart
+++ b/mojo/public/dart/src/event_stream.dart
@@ -122,17 +122,36 @@
 class MojoEventStreamListener {
   MojoMessagePipeEndpoint _endpoint;
   MojoEventStream _eventStream;
-  bool _isOpen;
-  bool _isInHandler;
+  bool _isOpen = false;
+  bool _isInHandler = false;
 
   MojoEventStreamListener(MojoMessagePipeEndpoint endpoint) :
       _endpoint = endpoint,
       _eventStream = new MojoEventStream(endpoint.handle),
       _isOpen = false;
 
-  MojoEventStreamListener.fromHandle(int handle) {
-    _endpoint = new MojoMessagePipeEndpoint(new MojoHandle(handle));
-    _eventStream = new MojoEventStream(_endpoint.handle);
+  MojoEventStreamListener.fromHandle(MojoHandle handle) {
+    _endpoint = new MojoMessagePipeEndpoint(handle);
+    _eventStream = new MojoEventStream(handle);
+    _isOpen = false;
+  }
+
+  MojoEventStreamListener.unbound() :
+      _endpoint = null,
+      _eventStream = null,
+      _isOpen = false;
+
+  void bind(MojoMessagePipeEndpoint endpoint) {
+    assert(!isBound);
+    _endpoint = endpoint;
+    _eventStream = new MojoEventStream(endpoint.handle);
+    _isOpen = false;
+  }
+
+  void bindFromHandle(MojoHandle handle) {
+    assert(!isBound);
+    _endpoint = new MojoMessagePipeEndpoint(handle);
+    _eventStream = new MojoEventStream(handle);
     _isOpen = false;
   }
 
@@ -168,6 +187,7 @@
       _eventStream.close();
       _isOpen = false;
       _eventStream = null;
+      _endpoint = null;
     }
   }
 
@@ -183,4 +203,5 @@
   MojoMessagePipeEndpoint get endpoint => _endpoint;
   bool get isOpen => _isOpen;
   bool get isInHandler => _isInHandler;
+  bool get isBound => _endpoint != null;
 }
diff --git a/mojo/public/dart/src/interface.dart b/mojo/public/dart/src/interface.dart
index eab591e..0e73214 100644
--- a/mojo/public/dart/src/interface.dart
+++ b/mojo/public/dart/src/interface.dart
@@ -10,7 +10,9 @@
 
   Interface(core.MojoMessagePipeEndpoint endpoint) : super(endpoint);
 
-  Interface.fromHandle(int handle) : super.fromHandle(handle);
+  Interface.fromHandle(core.MojoHandle handle) : super.fromHandle(handle);
+
+  Interface.unbound() : super.unbound();
 
   Future<Message> handleMessage(ServiceMessage message);
 
@@ -91,7 +93,7 @@
                     serviceMessage.buffer.lengthInBytes,
                     serviceMessage.handles);
     if (!endpoint.status.isOk) {
-      throw "message pipe write failed";
+      throw "message pipe write failed: ${endpoint.status}";
     }
   }
 
diff --git a/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
index c680055..d9fee1c 100644
--- a/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl
@@ -46,7 +46,14 @@
 class {{interface|name}}Client extends bindings.Client with {{interface|name}}Calls {
   {{interface|name}}Client(core.MojoMessagePipeEndpoint endpoint) : super(endpoint);
 
-  {{interface|name}}Client.fromHandle(int handle) : super.fromHandle(handle);
+  {{interface|name}}Client.fromHandle(core.MojoHandle handle) :
+      super.fromHandle(handle);
+
+  {{interface|name}}Client.unbound() : super.unbound();
+
+  static {{interface|name}}Client newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) =>
+      new {{interface|name}}Client(endpoint);
 
   void handleResponse(bindings.ServiceMessage message) {
     switch (message.header.type) {
@@ -73,13 +80,22 @@
 }
 
 
-abstract class {{interface|name}}Interface extends bindings.Interface
+class {{interface|name}}Interface extends bindings.Interface
 {% if interface.client != None -%}
 with {{imported_from[interface.client]}}{{interface.client|upper_camel_case}}Calls
 {% endif -%} {
+  {{interface|name}}Interface _delegate = null;
+
   {{interface|name}}Interface(core.MojoMessagePipeEndpoint endpoint) : super(endpoint);
 
-  {{interface|name}}Interface.fromHandle(int handle) : super.fromHandle(handle);
+  {{interface|name}}Interface.fromHandle(core.MojoHandle handle) :
+      super.fromHandle(handle);
+
+  {{interface|name}}Interface.unbound() : super.unbound();
+
+  static {{interface|name}}Interface newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) =>
+      new {{interface|name}}Interface(endpoint);
 
   static const String name = '{{namespace|replace(".","::")}}::{{interface|name}}';
 
@@ -89,14 +105,26 @@
   {%- for parameter in method.parameters -%}
     {{parameter.kind|dart_type}} {{parameter|name}}{% if not loop.last %}, {% endif %}
   {%- endfor -%}
-  );
+  ) {
+    assert(_delegate != null);
+    _delegate.{{method|name}}(
+      {%- for parameter in method.parameters -%}
+        {{parameter|name}}{% if not loop.last %}, {% endif %}
+      {%- endfor %});
+  }
 {%- else %}
 {%- set response_struct = method|response_struct_from_method %}
   Future<{{response_struct|name}}> {{method|name}}(
   {%- for parameter in method.parameters -%}
     {{parameter.kind|dart_type}} {{parameter|name}}{% if not loop.last %}, {% endif %}
   {%- endfor -%}
-  );
+  ) {
+    assert(_delegate != null);
+    return _delegate.{{method|name}}(
+      {%- for parameter in method.parameters -%}
+        {{parameter|name}}{% if not loop.last %}, {% endif %}
+      {%- endfor %});
+  }
 {%- endif %}
 {%- endfor %}
 
@@ -136,6 +164,12 @@
     }
     return null;
   }
+
+  {{interface|name}}Interface get delegate => _delegate;
+      set delegate({{interface|name}}Interface d) {
+    assert(_delegate == null);
+    _delegate = d;
+  }
 }
 
 
diff --git a/mojo/public/tools/bindings/generators/mojom_dart_generator.py b/mojo/public/tools/bindings/generators/mojom_dart_generator.py
index 9fcdde8..893e665 100644
--- a/mojo/public/tools/bindings/generators/mojom_dart_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_dart_generator.py
@@ -51,15 +51,15 @@
   mojom.UINT32:                "int",
   mojom.FLOAT:                 "double",
   mojom.HANDLE:                "core.MojoHandle",
-  mojom.DCPIPE:                "core.MojoHandle",
-  mojom.DPPIPE:                "core.MojoHandle",
-  mojom.MSGPIPE:               "core.MojoHandle",
-  mojom.SHAREDBUFFER:          "core.MojoHandle",
+  mojom.DCPIPE:                "core.MojoDataPipeConsumer",
+  mojom.DPPIPE:                "core.MojoDataPipeProducer",
+  mojom.MSGPIPE:               "core.MojoMessagePipeEndpoint",
+  mojom.SHAREDBUFFER:          "core.MojoSharedBuffer",
   mojom.NULLABLE_HANDLE:       "core.MojoHandle",
-  mojom.NULLABLE_DCPIPE:       "core.MojoHandle",
-  mojom.NULLABLE_DPPIPE:       "core.MojoHandle",
-  mojom.NULLABLE_MSGPIPE:      "core.MojoHandle",
-  mojom.NULLABLE_SHAREDBUFFER: "core.MojoHandle",
+  mojom.NULLABLE_DCPIPE:       "core.MojoDataPipeConsumer",
+  mojom.NULLABLE_DPPIPE:       "core.MojoDataPipeProducer",
+  mojom.NULLABLE_MSGPIPE:      "core.MojoMessagePipeEndpoint",
+  mojom.NULLABLE_SHAREDBUFFER: "core.MojoSharedBuffer",
   mojom.INT64:                 "int",
   mojom.UINT64:                "int",
   mojom.DOUBLE:                "double",
@@ -78,14 +78,14 @@
   mojom.INT32.spec:                 'decodeInt32',
   mojom.INT64.spec:                 'decodeInt64',
   mojom.INT8.spec:                  'decodeInt8',
-  mojom.MSGPIPE.spec:               'decodeHandle',
-  mojom.NULLABLE_DCPIPE.spec:       'decodeHandle',
-  mojom.NULLABLE_DPPIPE.spec:       'decodeHandle',
+  mojom.MSGPIPE.spec:               'decodeMessagePipeHandle',
+  mojom.NULLABLE_DCPIPE.spec:       'decodeConsumerHandle',
+  mojom.NULLABLE_DPPIPE.spec:       'decodeProducerHandle',
   mojom.NULLABLE_HANDLE.spec:       'decodeHandle',
-  mojom.NULLABLE_MSGPIPE.spec:      'decodeHandle',
-  mojom.NULLABLE_SHAREDBUFFER.spec: 'decodeHandle',
+  mojom.NULLABLE_MSGPIPE.spec:      'decodeMessagePipeHandle',
+  mojom.NULLABLE_SHAREDBUFFER.spec: 'decodeSharedBufferHandle',
   mojom.NULLABLE_STRING.spec:       'decodeString',
-  mojom.SHAREDBUFFER.spec:          'decodeHandle',
+  mojom.SHAREDBUFFER.spec:          'decodeSharedBufferHandle',
   mojom.STRING.spec:                'decodeString',
   mojom.UINT16.spec:                'decodeUint16',
   mojom.UINT32.spec:                'decodeUint32',
@@ -104,14 +104,14 @@
   mojom.INT32.spec:                 'encodeInt32',
   mojom.INT64.spec:                 'encodeInt64',
   mojom.INT8.spec:                  'encodeInt8',
-  mojom.MSGPIPE.spec:               'encodeHandle',
-  mojom.NULLABLE_DCPIPE.spec:       'encodeHandle',
-  mojom.NULLABLE_DPPIPE.spec:       'encodeHandle',
+  mojom.MSGPIPE.spec:               'encodeMessagePipeHandle',
+  mojom.NULLABLE_DCPIPE.spec:       'encodeConsumerHandle',
+  mojom.NULLABLE_DPPIPE.spec:       'encodeProducerHandle',
   mojom.NULLABLE_HANDLE.spec:       'encodeHandle',
-  mojom.NULLABLE_MSGPIPE.spec:      'encodeHandle',
-  mojom.NULLABLE_SHAREDBUFFER.spec: 'encodeHandle',
+  mojom.NULLABLE_MSGPIPE.spec:      'encodeMessagePipeHandle',
+  mojom.NULLABLE_SHAREDBUFFER.spec: 'encodeSharedBufferHandle',
   mojom.NULLABLE_STRING.spec:       'encodeString',
-  mojom.SHAREDBUFFER.spec:          'encodeHandle',
+  mojom.SHAREDBUFFER.spec:          'encodeSharedBufferHandle',
   mojom.STRING.spec:                'encodeString',
   mojom.UINT16.spec:                'encodeUint16',
   mojom.UINT32.spec:                'encodeUint32',
@@ -140,7 +140,7 @@
     return "null"
   if mojom.IsInterfaceKind(field.kind) or \
      mojom.IsInterfaceRequestKind(field.kind):
-    return _kind_to_dart_default_value[mojom.MSGPIPE]
+    return "null"
   if mojom.IsEnumKind(field.kind):
     return "0"
 
@@ -158,7 +158,7 @@
     return "Map<"+ key_type + ", " + value_type + ">"
   if mojom.IsInterfaceKind(kind) or \
      mojom.IsInterfaceRequestKind(kind):
-    return _kind_to_dart_decl_type[mojom.MSGPIPE]
+    return "Object"
   if mojom.IsEnumKind(kind):
     return "int"
 
@@ -242,7 +242,29 @@
         flags_to_set = [NOTHING_NULLABLE]
     return ' | '.join(flags_to_set)
 
-def AppendEncodeDecodeParams(initial_params, kind, bit):
+def AppendDecodeParams(initial_params, kind, bit):
+  """ Appends standard parameters for decode calls. """
+  params = list(initial_params)
+  if (kind == mojom.BOOL):
+    params.append(str(bit))
+  if mojom.IsReferenceKind(kind):
+    if mojom.IsArrayKind(kind):
+      params.append(GetArrayNullabilityFlags(kind))
+    else:
+      params.append(GetDartTrueFalse(mojom.IsNullableKind(kind)))
+  if mojom.IsInterfaceKind(kind):
+    params.append('%sClient.newFromEndpoint' % GetDartType(kind))
+  if mojom.IsArrayKind(kind) and mojom.IsInterfaceKind(kind.kind):
+    params.append('%sClient.newFromEndpoint' % GetDartType(kind.kind))
+  if mojom.IsInterfaceRequestKind(kind):
+    params.append('%sInterface.newFromEndpoint' % GetDartType(kind.kind))
+  if mojom.IsArrayKind(kind) and mojom.IsInterfaceRequestKind(kind.kind):
+    params.append('%sInterface.newFromEndpoint' % GetDartType(kind.kind.kind))
+  if mojom.IsArrayKind(kind):
+    params.append(GetArrayExpectedLength(kind))
+  return params
+
+def AppendEncodeParams(initial_params, kind, bit):
   """ Appends standard parameters shared between encode and decode calls. """
   params = list(initial_params)
   if (kind == mojom.BOOL):
@@ -263,12 +285,12 @@
     if mojom.IsEnumKind(kind):
       return _DecodeMethodName(mojom.INT32)
     if mojom.IsInterfaceRequestKind(kind):
-      return 'decodeHandle'
+      return 'decodeInterfaceRequest'
     if mojom.IsInterfaceKind(kind):
-      return 'decodeHandle'
+      return 'decodeServiceInterface'
     return _spec_to_decode_method[kind.spec]
   methodName = _DecodeMethodName(kind)
-  params = AppendEncodeDecodeParams([ str(offset) ], kind, bit)
+  params = AppendDecodeParams([ str(offset) ], kind, bit)
   return '%s(%s)' % (methodName, ', '.join(params))
 
 def EncodeMethod(kind, variable, offset, bit):
@@ -280,12 +302,12 @@
     if mojom.IsEnumKind(kind):
       return _EncodeMethodName(mojom.INT32)
     if mojom.IsInterfaceRequestKind(kind):
-      return 'encodeHandle'
+      return 'encodeInterfaceRequest'
     if mojom.IsInterfaceKind(kind):
-      return 'encodeHandle'
+      return 'encodeInterface'
     return _spec_to_encode_method[kind.spec]
   methodName = _EncodeMethodName(kind)
-  params = AppendEncodeDecodeParams([ variable, str(offset) ], kind, bit)
+  params = AppendEncodeParams([ variable, str(offset) ], kind, bit)
   return '%s(%s)' % (methodName, ', '.join(params))
 
 def TranslateConstants(token):