Skip to content

Commit d289232

Browse files
authored
feat: support for struct reference index access (#304)
1 parent e1fa79d commit d289232

File tree

9 files changed

+300
-41
lines changed

9 files changed

+300
-41
lines changed

NativeScript/runtime/Interop.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,11 @@ class Interop {
119119
static id CallInitializer(v8::Local<v8::Context> context, const MethodMeta* methodMeta, id target, Class clazz, V8Args& args);
120120
static v8::Local<v8::Value> CallFunction(ObjCMethodCall& methodCall);
121121
static v8::Local<v8::Value> CallFunction(CMethodCall& methodCall);
122+
static v8::Local<v8::Value> GetResultByType(v8::Local<v8::Context> context, BaseDataWrapper* typeWrapper, BaseCall* call, std::shared_ptr<v8::Persistent<v8::Value>> parentStruct = nullptr);
122123
static v8::Local<v8::Value> GetResult(v8::Local<v8::Context> context, const TypeEncoding* typeEncoding, BaseCall* call, bool marshalToPrimitive, std::shared_ptr<v8::Persistent<v8::Value>> parentStruct = nullptr, bool isStructMember = false, bool ownsReturnedObject = false, bool returnsUnmanaged = false, bool isInitializer = false);
123124
static void SetStructPropertyValue(v8::Local<v8::Context> context, StructWrapper* wrapper, StructField field, v8::Local<v8::Value> value);
124125
static void InitializeStruct(v8::Local<v8::Context> context, void* destBuffer, std::vector<StructField> fields, v8::Local<v8::Value> inititalizer);
126+
static void WriteTypeValue(v8::Local<v8::Context> context, BaseDataWrapper* typeWrapper, void* dest, v8::Local<v8::Value> arg);
125127
static void WriteValue(v8::Local<v8::Context> context, const TypeEncoding* typeEncoding, void* dest, v8::Local<v8::Value> arg);
126128
static id ToObject(v8::Local<v8::Context> context, v8::Local<v8::Value> arg);
127129
static v8::Local<v8::Value> GetPrimitiveReturnType(v8::Local<v8::Context> context, BinaryTypeEncodingType type, BaseCall* call);

NativeScript/runtime/Interop.mm

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,44 @@ inline bool isBool() {
182182
IsOfType _isObject = UNDEFINED;
183183
};
184184

185+
void Interop::WriteTypeValue(Local<Context> context, BaseDataWrapper* typeWrapper, void* dest, Local<Value> arg) {
186+
Isolate* isolate = context->GetIsolate();
187+
ValueCache argHelper(arg);
188+
bool isEmptyOrUndefined = arg.IsEmpty() || arg->IsNullOrUndefined();
189+
bool success = false;
190+
191+
if (typeWrapper->Type() == WrapperType::StructType) {
192+
if (isEmptyOrUndefined) {
193+
StructTypeWrapper* structTypeWrapper = static_cast<StructTypeWrapper*>(typeWrapper);
194+
StructInfo structInfo = structTypeWrapper->StructInfo();
195+
196+
memset(dest, 0, structInfo.FFIType()->size);
197+
success = true;
198+
} else if (argHelper.isObject()) {
199+
BaseDataWrapper* wrapper = tns::GetValue(isolate, arg);
200+
if (wrapper != nullptr) {
201+
if (wrapper->Type() == WrapperType::Struct) {
202+
StructWrapper* structWrapper = static_cast<StructWrapper*>(wrapper);
203+
void* buffer = structWrapper->Data();
204+
size_t size = structWrapper->StructInfo().FFIType()->size;
205+
memcpy(dest, buffer, size);
206+
success = true;
207+
}
208+
} else {
209+
// Create the structure using the struct initializer syntax
210+
StructTypeWrapper* structTypeWrapper = static_cast<StructTypeWrapper*>(typeWrapper);
211+
StructInfo structInfo = structTypeWrapper->StructInfo();
212+
Interop::InitializeStruct(context, dest, structInfo.Fields(), arg.As<Object>());
213+
success = true;
214+
}
215+
}
216+
}
217+
218+
if (!success) {
219+
tns::Assert(false, isolate);
220+
}
221+
}
222+
185223
void Interop::WriteValue(Local<Context> context, const TypeEncoding* typeEncoding, void* dest, Local<Value> arg) {
186224
Isolate* isolate = context->GetIsolate();
187225
ExecuteWriteValueDebugValidationsIfInDebug(context, typeEncoding, dest, arg);
@@ -806,6 +844,21 @@ inline bool isBool() {
806844
*static_cast<T*>((void*)((uint8_t*)destBuffer + position)) = result;
807845
}
808846

847+
Local<Value> Interop::GetResultByType(Local<Context> context, BaseDataWrapper* typeWrapper, BaseCall* call, std::shared_ptr<Persistent<Value>> parentStruct) {
848+
Isolate* isolate = context->GetIsolate();
849+
850+
if (typeWrapper->Type() == WrapperType::StructType) {
851+
StructTypeWrapper* structTypeWrapper = static_cast<StructTypeWrapper*>(typeWrapper);
852+
StructInfo structInfo = structTypeWrapper->StructInfo();
853+
854+
void* result = call->ResultBuffer();
855+
Local<Value> value = Interop::StructToValue(context, result, structInfo, parentStruct);
856+
return value;
857+
}
858+
859+
return Null(isolate);
860+
}
861+
809862
Local<Value> Interop::GetResult(Local<Context> context, const TypeEncoding* typeEncoding, BaseCall* call, bool marshalToPrimitive, std::shared_ptr<Persistent<Value>> parentStruct, bool isStructMember, bool ownsReturnedObject, bool returnsUnmanaged, bool isInitializer) {
810863
Isolate* isolate = context->GetIsolate();
811864

@@ -1031,18 +1084,16 @@ inline bool isBool() {
10311084
}
10321085

10331086
const TypeEncoding* innerType = typeEncoding->details.pointer.getInnerType();
1087+
Local<Value> pointer = Pointer::NewInstance(context, result);
10341088

10351089
if (innerType->type == BinaryTypeEncodingType::VoidEncoding) {
1036-
Local<Value> instance = Pointer::NewInstance(context, result);
1037-
return instance;
1090+
return pointer;
10381091
}
10391092

1040-
BaseCall c(result);
1041-
Local<Value> value = Interop::GetResult(context, innerType, &c, true);
10421093
Local<Value> type = Interop::GetInteropType(context, innerType->type);
10431094

10441095
std::vector<Local<Value>> args;
1045-
args.push_back(value);
1096+
args.push_back(pointer);
10461097
if (!type.IsEmpty()) {
10471098
args.insert(args.begin(), type);
10481099
}

NativeScript/runtime/Reference.cpp

Lines changed: 78 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,20 @@ void Reference::IndexedPropertyGetCallback(uint32_t index, const PropertyCallbac
9999
Local<Object> thiz = info.This();
100100
Local<Context> context = isolate->GetCurrentContext();
101101

102-
DataPair pair = Reference::GetTypeEncodingDataPair(thiz);
102+
DataPair pair = Reference::GetDataPair(thiz);
103103
const TypeEncoding* typeEncoding = pair.typeEncoding_;
104104
size_t size = pair.size_;
105105
void* data = pair.data_;
106106

107107
void* ptr = (uint8_t*)data + index * size;
108108
BaseCall call((uint8_t*)ptr);
109-
Local<Value> result = Interop::GetResult(context, typeEncoding, &call, false);
109+
110+
Local<Value> result;
111+
if (typeEncoding != nullptr) {
112+
result = Interop::GetResult(context, typeEncoding, &call, false);
113+
} else {
114+
result = Interop::GetResultByType(context, pair.typeWrapper_, &call);
115+
}
110116
info.GetReturnValue().Set(result);
111117
}
112118

@@ -115,13 +121,17 @@ void Reference::IndexedPropertySetCallback(uint32_t index, Local<Value> value, c
115121
Local<Context> context = isolate->GetCurrentContext();
116122
Local<Object> thiz = info.This();
117123

118-
DataPair pair = Reference::GetTypeEncodingDataPair(thiz);
124+
DataPair pair = Reference::GetDataPair(thiz);
119125
const TypeEncoding* typeEncoding = pair.typeEncoding_;
120126
size_t size = pair.size_;
121127
void* data = pair.data_;
122-
123128
void* ptr = (uint8_t*)data + index * size;
124-
Interop::WriteValue(context, typeEncoding, ptr, value);
129+
130+
if (typeEncoding != nullptr) {
131+
Interop::WriteValue(context, typeEncoding, ptr, value);
132+
} else {
133+
Interop::WriteTypeValue(context, pair.typeWrapper_, ptr, value);
134+
}
125135
}
126136

127137
void Reference::GetValueCallback(Local<v8::Name> name, const PropertyCallbackInfo<Value>& info) {
@@ -186,11 +196,17 @@ Local<Value> Reference::GetReferredValue(Local<Context> context, Local<Value> va
186196
}
187197

188198
BaseDataWrapper* typeWrapper = wrapper->TypeWrapper();
189-
if (typeWrapper != nullptr && typeWrapper->Type() == WrapperType::Primitive && baseWrapper != nullptr && baseWrapper->Type() == WrapperType::Pointer) {
190-
Reference::DataPair pair = GetTypeEncodingDataPair(value.As<Object>());
191-
if (pair.data_ != nullptr && pair.typeEncoding_ != nullptr) {
199+
if (typeWrapper != nullptr && Reference::IsSupportedType(typeWrapper->Type()) && baseWrapper != nullptr && baseWrapper->Type() == WrapperType::Pointer) {
200+
Reference::DataPair pair = Reference::GetDataPair(value.As<Object>());
201+
if (pair.data_ != nullptr) {
192202
BaseCall call((uint8_t*)pair.data_);
193-
Local<Value> result = Interop::GetResult(context, pair.typeEncoding_, &call, false);
203+
Local<Value> result;
204+
205+
if (pair.typeEncoding_ != nullptr) {
206+
result = Interop::GetResult(context, pair.typeEncoding_, &call, false);
207+
} else {
208+
result = Interop::GetResultByType(context, typeWrapper, &call);
209+
}
194210
return result;
195211
}
196212
}
@@ -203,7 +219,6 @@ void* Reference::GetWrappedPointer(Local<Context> context, Local<Value> referenc
203219
return nullptr;
204220
}
205221

206-
207222
Isolate* isolate = context->GetIsolate();
208223
BaseDataWrapper* wrapper = tns::GetValue(isolate, reference);
209224
tns::Assert(wrapper != nullptr && wrapper->Type() == WrapperType::Reference, isolate);
@@ -313,47 +328,76 @@ void Reference::RegisterToStringMethod(Local<Context> context, Local<Object> pro
313328
tns::Assert(success, isolate);
314329
}
315330

316-
Reference::DataPair Reference::GetTypeEncodingDataPair(Local<Object> obj) {
331+
Reference::DataPair Reference::GetDataPair(Local<Object> obj) {
317332
Local<Context> context;
318333
bool success = obj->GetCreationContext().ToLocal(&context);
319334
tns::Assert(success);
320335
Isolate* isolate = context->GetIsolate();
321336
BaseDataWrapper* wrapper = tns::GetValue(isolate, obj);
322337
tns::Assert(wrapper != nullptr && wrapper->Type() == WrapperType::Reference, isolate);
323338
ReferenceWrapper* refWrapper = static_cast<ReferenceWrapper*>(wrapper);
324-
325339
BaseDataWrapper* typeWrapper = refWrapper->TypeWrapper();
326-
if (typeWrapper == nullptr) {
327-
// TODO: Missing type when creating the Reference instance
328-
tns::Assert(false, isolate);
329-
}
330-
331-
if (typeWrapper->Type() != WrapperType::Primitive) {
332-
// TODO: Currently only PrimitiveDataWrappers are supported as type parameters
333-
// Objective C class classes and structures should also be handled
334-
tns::Assert(false, isolate);
335-
}
336-
337-
PrimitiveDataWrapper* primitiveWrapper = static_cast<PrimitiveDataWrapper*>(typeWrapper);
340+
341+
size_t size = 0;
342+
343+
if (typeWrapper != nullptr) {
344+
const TypeEncoding* typeEncoding = nullptr;
345+
346+
if (Reference::IsSupportedType(typeWrapper->Type())) {
347+
switch(typeWrapper->Type()) {
348+
case WrapperType::Primitive: {
349+
PrimitiveDataWrapper* primitiveWrapper = static_cast<PrimitiveDataWrapper*>(typeWrapper);
350+
351+
size = primitiveWrapper->Size();
352+
typeEncoding = primitiveWrapper->TypeEncoding();
353+
break;
354+
}
355+
case WrapperType::StructType: {
356+
StructTypeWrapper* structTypeWrapper = static_cast<StructTypeWrapper*>(refWrapper->TypeWrapper());
357+
StructInfo structInfo = structTypeWrapper->StructInfo();
358+
359+
size = structInfo.FFIType()->size;
360+
break;
361+
}
362+
default: {
363+
break;
364+
}
365+
}
366+
} else {
367+
// TODO: Currently only PrimitiveDataWrappers and Structs are supported as type parameters
368+
// Objective C class classes should also be handled
369+
tns::Assert(false, isolate);
370+
}
338371

339-
Local<Value> value = refWrapper->Value()->Get(isolate);
340-
BaseDataWrapper* wrappedValue = tns::GetValue(isolate, value);
341-
if (wrappedValue != nullptr && wrappedValue->Type() == WrapperType::Pointer) {
342-
const TypeEncoding* typeEncoding = primitiveWrapper->TypeEncoding();
343-
PointerWrapper* pw = static_cast<PointerWrapper*>(wrappedValue);
344-
void* data = pw->Data();
372+
Local<Value> value = refWrapper->Value()->Get(isolate);
373+
BaseDataWrapper* wrappedValue = tns::GetValue(isolate, value);
374+
if (wrappedValue != nullptr && wrappedValue->Type() == WrapperType::Pointer) {
375+
PointerWrapper* pw = static_cast<PointerWrapper*>(wrappedValue);
376+
void* data = pw->Data();
345377

346-
DataPair pair(typeEncoding, data, primitiveWrapper->Size());
347-
return pair;
378+
DataPair pair(typeWrapper, typeEncoding, data, size);
379+
return pair;
380+
}
348381
}
349382

350383
if (refWrapper->Encoding() != nullptr && refWrapper->Data() != nullptr) {
351-
DataPair pair(refWrapper->Encoding(), refWrapper->Data(), primitiveWrapper->Size());
384+
const TypeEncoding* typeEncoding = refWrapper->Encoding();
385+
386+
if (typeWrapper == nullptr) {
387+
ffi_type* ffiType = FFICall::GetArgumentType(typeEncoding);
388+
size = ffiType->size;
389+
FFICall::DisposeFFIType(ffiType, typeEncoding);
390+
}
391+
392+
DataPair pair(typeWrapper, typeEncoding, refWrapper->Data(), size);
352393
return pair;
353394
}
354395

355396
tns::Assert(false, isolate);
356-
return DataPair(nullptr, nullptr, 0);
397+
return DataPair(typeWrapper, nullptr, nullptr, size);
357398
}
358399

400+
bool Reference::IsSupportedType(WrapperType type) {
401+
return type == WrapperType::Primitive || type == WrapperType::StructType;
402+
}
359403
}

NativeScript/runtime/Reference.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ class Reference {
1414
static void* GetWrappedPointer(v8::Local<v8::Context> context, v8::Local<v8::Value> reference, const TypeEncoding* typeEncoding);
1515
private:
1616
struct DataPair {
17-
DataPair(const TypeEncoding* typeEncoding, void* data, size_t size): typeEncoding_(typeEncoding), data_(data), size_(size) {
17+
DataPair(BaseDataWrapper* typeWrapper, const TypeEncoding* typeEncoding, void* data, size_t size): typeWrapper_(typeWrapper), typeEncoding_(typeEncoding), data_(data), size_(size) {
1818
}
1919

20+
BaseDataWrapper* typeWrapper_;
2021
const TypeEncoding* typeEncoding_;
2122
void* data_;
2223
size_t size_;
@@ -30,7 +31,8 @@ class Reference {
3031
static void GetValueCallback(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info);
3132
static void SetValueCallback(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info);
3233
static void RegisterToStringMethod(v8::Local<v8::Context> context, v8::Local<v8::Object> prototype);
33-
static DataPair GetTypeEncodingDataPair(v8::Local<v8::Object> obj);
34+
static DataPair GetDataPair(v8::Local<v8::Object> obj);
35+
static bool IsSupportedType(WrapperType type);
3436
};
3537

3638
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
#import <Foundation/Foundation.h>
3+
4+
typedef struct TNSPoint {
5+
int x;
6+
int y;
7+
} TNSPoint;
8+
9+
@interface TNSPointCollection : NSObject
10+
- (instancetype)initWithPoints:(const TNSPoint *)points count:(NSUInteger)count;
11+
@property (nonatomic, readonly) TNSPoint *points NS_RETURNS_INNER_POINTER;
12+
@property (nonatomic, readonly) NSUInteger pointCount;
13+
@end
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#import "TNSPointCollection.h"
2+
3+
NS_ASSUME_NONNULL_BEGIN
4+
5+
@implementation TNSPointCollection
6+
{
7+
TNSPoint *_points;
8+
NSUInteger _pointCount;
9+
}
10+
11+
- (instancetype)initWithPoints:(const TNSPoint *)points count:(NSUInteger)count
12+
{
13+
self = [super init];
14+
if (self)
15+
{
16+
_pointCount = count;
17+
if (count > 0)
18+
{
19+
_points = malloc(sizeof(TNSPoint) * count);
20+
memcpy(_points, points, sizeof(TNSPoint) * count);
21+
}
22+
else
23+
{
24+
_points = NULL;
25+
}
26+
}
27+
return self;
28+
}
29+
30+
- (NSUInteger)pointCount
31+
{
32+
return _pointCount;
33+
}
34+
35+
- (TNSPoint *)points
36+
{
37+
return _points;
38+
}
39+
40+
@end
41+
42+
NS_ASSUME_NONNULL_END

TestFixtures/TestFixtures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#import "Interfaces/TNSConstructorResolution.h"
1515
#import "Interfaces/TNSInheritance.h"
1616
#import "Interfaces/TNSMethodCalls.h"
17+
#import "Interfaces/TNSPointCollection.h"
1718
#import "Interfaces/TNSSwiftLike.h"
1819

1920
#import "Marshalling/TNSAllocLog.h"

0 commit comments

Comments
 (0)