1 #pragma once
2 
3 #include <jsi/jsi.h>
4 
5 namespace jsi = facebook::jsi;
6 namespace expo {
7 namespace gl_cpp {
8 
9 enum class TypedArrayKind {
10   Int8Array,
11   Int16Array,
12   Int32Array,
13   Uint8Array,
14   Uint8ClampedArray,
15   Uint16Array,
16   Uint32Array,
17   Float32Array,
18   Float64Array,
19 };
20 
21 template <TypedArrayKind T>
22 class TypedArray;
23 
24 template <TypedArrayKind T>
25 struct typedArrayTypeMap;
26 template <>
27 struct typedArrayTypeMap<TypedArrayKind::Int8Array> {
28   typedef int8_t type;
29 };
30 template <>
31 struct typedArrayTypeMap<TypedArrayKind::Int16Array> {
32   typedef int16_t type;
33 };
34 template <>
35 struct typedArrayTypeMap<TypedArrayKind::Int32Array> {
36   typedef int32_t type;
37 };
38 template <>
39 struct typedArrayTypeMap<TypedArrayKind::Uint8Array> {
40   typedef uint8_t type;
41 };
42 template <>
43 struct typedArrayTypeMap<TypedArrayKind::Uint8ClampedArray> {
44   typedef uint8_t type;
45 };
46 template <>
47 struct typedArrayTypeMap<TypedArrayKind::Uint16Array> {
48   typedef uint16_t type;
49 };
50 template <>
51 struct typedArrayTypeMap<TypedArrayKind::Uint32Array> {
52   typedef uint32_t type;
53 };
54 template <>
55 struct typedArrayTypeMap<TypedArrayKind::Float32Array> {
56   typedef float type;
57 };
58 template <>
59 struct typedArrayTypeMap<TypedArrayKind::Float64Array> {
60   typedef double type;
61 };
62 
63 // Instance of this class will invalidate PropNameIDCache when destructor is called.
64 // Attach this object to global in specific jsi::Runtime to make sure lifecycle of
65 // the cache object is connected to the lifecycle of the js runtime
66 class InvalidateCacheOnDestroy : public jsi::HostObject {
67  public:
68   InvalidateCacheOnDestroy(jsi::Runtime &runtime);
69   virtual ~InvalidateCacheOnDestroy();
70   virtual jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) {
71     return jsi::Value::null();
72   }
73   virtual void set(jsi::Runtime &, const jsi::PropNameID &name, const jsi::Value &value) {}
74   virtual std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) {
75     return {};
76   }
77 
78  private:
79   uintptr_t key;
80 };
81 
82 class TypedArrayBase : public jsi::Object {
83  public:
84   template <TypedArrayKind T>
85   using ContentType = typename typedArrayTypeMap<T>::type;
86 
87   TypedArrayBase(jsi::Runtime &, size_t, TypedArrayKind);
88   TypedArrayBase(jsi::Runtime &, const jsi::Object &);
89   TypedArrayBase(TypedArrayBase &&) = default;
90   TypedArrayBase &operator=(TypedArrayBase &&) = default;
91 
92   TypedArrayKind getKind(jsi::Runtime &runtime) const;
93 
94   template <TypedArrayKind T>
95   TypedArray<T> get(jsi::Runtime &runtime) const &;
96   template <TypedArrayKind T>
97   TypedArray<T> get(jsi::Runtime &runtime) &&;
98   template <TypedArrayKind T>
99   TypedArray<T> as(jsi::Runtime &runtime) const &;
100   template <TypedArrayKind T>
101   TypedArray<T> as(jsi::Runtime &runtime) &&;
102 
103   size_t size(jsi::Runtime &runtime) const;
104   size_t length(jsi::Runtime &runtime) const;
105   size_t byteLength(jsi::Runtime &runtime) const;
106   size_t byteOffset(jsi::Runtime &runtime) const;
107   bool hasBuffer(jsi::Runtime &runtime) const;
108 
109   std::vector<uint8_t> toVector(jsi::Runtime &runtime);
110   jsi::ArrayBuffer getBuffer(jsi::Runtime &runtime) const;
111 
112  private:
113   template <TypedArrayKind>
114   friend class TypedArray;
115 };
116 
117 bool isTypedArray(jsi::Runtime &runtime, const jsi::Object &jsObj);
118 TypedArrayBase getTypedArray(jsi::Runtime &runtime, const jsi::Object &jsObj);
119 
120 std::vector<uint8_t> arrayBufferToVector(jsi::Runtime &runtime, jsi::Object &jsObj);
121 void arrayBufferUpdate(
122     jsi::Runtime &runtime,
123     jsi::ArrayBuffer &buffer,
124     std::vector<uint8_t> data,
125     size_t offset);
126 
127 template <TypedArrayKind T>
128 class TypedArray : public TypedArrayBase {
129  public:
130   TypedArray(jsi::Runtime &runtime, size_t size);
131   TypedArray(jsi::Runtime &runtime, std::vector<ContentType<T>> data);
132   TypedArray(TypedArrayBase &&base);
133   TypedArray(TypedArray &&) = default;
134   TypedArray &operator=(TypedArray &&) = default;
135 
136   std::vector<ContentType<T>> toVector(jsi::Runtime &runtime);
137   void update(jsi::Runtime &runtime, const std::vector<ContentType<T>> &data);
138 };
139 
140 template <TypedArrayKind T>
141 TypedArray<T> TypedArrayBase::get(jsi::Runtime &runtime) const & {
142   assert(getKind(runtime) == T);
143   (void)runtime; // when assert is disabled we need to mark this as used
144   return TypedArray<T>(jsi::Value(runtime, jsi::Value(runtime, *this).asObject(runtime)));
145 }
146 
147 template <TypedArrayKind T>
148 TypedArray<T> TypedArrayBase::get(jsi::Runtime &runtime) && {
149   assert(getKind(runtime) == T);
150   (void)runtime; // when assert is disabled we need to mark this as used
151   return TypedArray<T>(std::move(*this));
152 }
153 
154 template <TypedArrayKind T>
155 TypedArray<T> TypedArrayBase::as(jsi::Runtime &runtime) const & {
156   if (getKind(runtime) != T) {
157     throw jsi::JSError(runtime, "Object is not a TypedArray");
158   }
159   return get<T>(runtime);
160 }
161 
162 template <TypedArrayKind T>
163 TypedArray<T> TypedArrayBase::as(jsi::Runtime &runtime) && {
164   if (getKind(runtime) != T) {
165     throw jsi::JSError(runtime, "Object is not a TypedArray");
166   }
167   return std::move(*this).get<T>(runtime);
168 }
169 } // namespace gl_cpp
170 } // namespace expo
171