Add a Uint16List typed data wrapper

Change-Id: I85fbd1dae7a8234eed25c9138d81159a28bb5451
diff --git a/typed_data/BUILD.gn b/typed_data/BUILD.gn
index 8cc067e..496bdbf 100644
--- a/typed_data/BUILD.gn
+++ b/typed_data/BUILD.gn
@@ -18,6 +18,8 @@
     "int32_list.h",
     "uint8_list.cc",
     "uint8_list.h",
+    "uint16_list.cc",
+    "uint16_list.h",
   ]
 
   deps = [
diff --git a/typed_data/uint16_list.cc b/typed_data/uint16_list.cc
new file mode 100644
index 0000000..955a3bf
--- /dev/null
+++ b/typed_data/uint16_list.cc
@@ -0,0 +1,82 @@
+// Copyright 2015 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tonic/typed_data/uint16_list.h"
+
+#include <string.h>
+
+#include "tonic/logging/dart_error.h"
+
+namespace tonic {
+
+Uint16List::Uint16List()
+    : data_(nullptr), num_elements_(0), dart_handle_(nullptr) {}
+
+Uint16List::Uint16List(Dart_Handle list)
+    : data_(nullptr), num_elements_(0), dart_handle_(list) {
+  if (Dart_IsNull(list))
+    return;
+
+  Dart_TypedData_Type type;
+  Dart_TypedDataAcquireData(list, &type, reinterpret_cast<void**>(&data_),
+                            &num_elements_);
+  TONIC_DCHECK(!LogIfError(list));
+  if (type != Dart_TypedData_kUint16)
+    Dart_ThrowException(ToDart("Non-genuine Uint16List passed to engine."));
+}
+
+Uint16List::Uint16List(Uint16List&& other)
+    : data_(other.data_),
+      num_elements_(other.num_elements_),
+      dart_handle_(other.dart_handle_) {
+  other.data_ = nullptr;
+  other.dart_handle_ = nullptr;
+}
+
+Uint16List::~Uint16List() {
+  Release();
+}
+
+void Uint16List::Release() {
+  if (data_) {
+    Dart_TypedDataReleaseData(dart_handle_);
+    data_ = nullptr;
+    num_elements_ = 0;
+    dart_handle_ = nullptr;
+  }
+}
+
+Uint16List DartConverter<Uint16List>::FromArguments(Dart_NativeArguments args,
+                                                    int index,
+                                                    Dart_Handle& exception) {
+  Dart_Handle list = Dart_GetNativeArgument(args, index);
+  TONIC_DCHECK(!LogIfError(list));
+  return Uint16List(list);
+}
+
+void DartConverter<Uint16List>::SetReturnValue(Dart_NativeArguments args,
+                                               Uint16List val) {
+  Dart_SetReturnValue(args, val.dart_handle());
+}
+
+Dart_Handle DartConverter<Uint16List>::ToDart(const uint16_t* buffer,
+                                              unsigned int length) {
+  const intptr_t buffer_length = static_cast<intptr_t>(length);
+  Dart_Handle array = Dart_NewTypedData(Dart_TypedData_kUint16, buffer_length);
+  TONIC_DCHECK(!LogIfError(array));
+  {
+    Dart_TypedData_Type type;
+    void* data = nullptr;
+    intptr_t data_length = 0;
+    Dart_TypedDataAcquireData(array, &type, &data, &data_length);
+    TONIC_CHECK(type == Dart_TypedData_kUint16);
+    TONIC_CHECK(data);
+    TONIC_CHECK(data_length == buffer_length);
+    memmove(data, buffer, data_length);
+    Dart_TypedDataReleaseData(array);
+  }
+  return array;
+}
+
+}  // namespace tonic
diff --git a/typed_data/uint16_list.h b/typed_data/uint16_list.h
new file mode 100644
index 0000000..f606893
--- /dev/null
+++ b/typed_data/uint16_list.h
@@ -0,0 +1,62 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_TONIC_TYPED_DATA_UINT16_LIST_H_
+#define LIB_TONIC_TYPED_DATA_UINT16_LIST_H_
+
+#include "third_party/dart/runtime/include/dart_api.h"
+#include "tonic/converter/dart_converter.h"
+
+namespace tonic {
+
+// A simple wrapper around a Dart Uint16List. It uses Dart_TypedDataAcquireData
+// to obtain a raw pointer to the data, which is released when this object is
+// destroyed.
+//
+// This is designed to be used with DartConverter only.
+class Uint16List {
+ public:
+  explicit Uint16List(Dart_Handle list);
+  Uint16List(Uint16List&& other);
+  Uint16List();
+  ~Uint16List();
+
+  uint16_t& at(intptr_t i) {
+    TONIC_CHECK(i < num_elements_);
+    return data_[i];
+  }
+  const uint16_t& at(intptr_t i) const {
+    TONIC_CHECK(i < num_elements_);
+    return data_[i];
+  }
+
+  uint16_t& operator[](intptr_t i) { return at(i); }
+  const uint16_t& operator[](intptr_t i) const { return at(i); }
+
+  const uint16_t* data() const { return data_; }
+  intptr_t num_elements() const { return num_elements_; }
+  Dart_Handle dart_handle() const { return dart_handle_; }
+
+  void Release();
+
+ private:
+  uint16_t* data_;
+  intptr_t num_elements_;
+  Dart_Handle dart_handle_;
+
+  Uint16List(const Uint16List& other) = delete;
+};
+
+template <>
+struct DartConverter<Uint16List> {
+  static void SetReturnValue(Dart_NativeArguments args, Uint16List val);
+  static Uint16List FromArguments(Dart_NativeArguments args,
+                                 int index,
+                                 Dart_Handle& exception);
+  static Dart_Handle ToDart(const uint16_t* buffer, unsigned int length);
+};
+
+}  // namespace tonic
+
+#endif  // LIB_TONIC_TYPED_DATA_UINT16_LIST_H_