Skip to content

Commit 0a45dea

Browse files
authored
Merge pull request #51 from lightpanda-io/unwrapObject
unwrapObject
2 parents a96bd8a + 2fd00d3 commit 0a45dea

File tree

3 files changed

+142
-8
lines changed

3 files changed

+142
-8
lines changed

src/binding.cpp

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "include/v8.h"
77
#include "src/api/api.h"
88
#include "src/inspector/protocol/Runtime.h"
9+
#include "src/inspector/v8-string-conversions.h"
910

1011
#include "inspector.h"
1112

@@ -1556,6 +1557,11 @@ void v8__base__SetDcheckFunction(void (*func)(const char*, int, const char*)) {
15561557

15571558
// Utils
15581559

1560+
struct CZigString {
1561+
const char *ptr = nullptr;
1562+
uint64_t len = 0;
1563+
};
1564+
15591565
/// Header for Zig
15601566
/// Allocates `bytes` bytes of memory using the allocator.
15611567
/// @param allocator: A Zig std.mem.Allocator
@@ -1567,6 +1573,12 @@ static inline v8_inspector::StringView toStringView(const char *str, size_t leng
15671573
auto* stringView = reinterpret_cast<const uint8_t*>(str);
15681574
return { stringView, length };
15691575
}
1576+
/// Overload for safety in case the function is called with a string literal
1577+
static inline v8_inspector::StringView toStringView(const char *str) {
1578+
size_t length = strlen(str);
1579+
auto* stringView = reinterpret_cast<const uint8_t*>(str);
1580+
return { stringView, length };
1581+
}
15701582
static inline v8_inspector::StringView toStringView(const std::string &str) {
15711583
return toStringView(str.c_str(), str.length());
15721584
}
@@ -1586,7 +1598,7 @@ static inline std::string fromStringView(v8::Isolate* isolate, const v8_inspecto
15861598
/// @param str: The string to return
15871599
/// @param allocator: A Zig std.mem.Allocator
15881600
/// @returns string pointer with null terminator, null if allocation failed
1589-
const char* toHeapCharPtr(const v8_inspector::String16& str, const void* allocator) {
1601+
const char* allocStringWith0(const v8_inspector::String16& str, const void* allocator) {
15901602
std::string utf8_str = str.utf8(); // Note the data*'s lifetime is tied to utf8_str and this may hold the string data on the stack as an SSO, so we need to copy it onto the heap.
15911603
char* heap_str = zigAlloc(allocator, utf8_str.length() + 1); // +1 for null terminator, needed to communicate the length to Zig
15921604
if (heap_str == nullptr) {
@@ -1596,6 +1608,41 @@ const char* toHeapCharPtr(const v8_inspector::String16& str, const void* allocat
15961608
return heap_str;
15971609
}
15981610

1611+
/// Allocates a string as utf8 on the allocator without \0 terminator, for use in Zig.
1612+
/// The strings pointer and length should therefore be returned together
1613+
/// @param str: The string contents to allocate
1614+
/// @param allocator: A Zig std.mem.Allocator
1615+
/// @param out: Points to the now allocated string on the heap (without sentinel \0), NULL if view was null, invalid if allocation failed
1616+
/// @returns false if allocation errored
1617+
bool allocString(const v8_inspector::StringView& input, const void* allocator, CZigString& output) {
1618+
if (input.characters8() == nullptr) {
1619+
output.ptr = nullptr;
1620+
output.len = 0;
1621+
return true;
1622+
}
1623+
1624+
std::string utf8_str; // Harmless if not used by 8bit string
1625+
if (input.is8Bit()) {
1626+
output.len = input.length();
1627+
} else {
1628+
utf8_str = v8_inspector::UTF16ToUTF8(input.characters16(), input.length());
1629+
output.len = utf8_str.length();
1630+
}
1631+
1632+
char* heap_str = zigAlloc(allocator, output.len);
1633+
if (heap_str == nullptr) {
1634+
return false;
1635+
}
1636+
1637+
if (input.is8Bit()) {
1638+
memcpy(heap_str, input.characters8(), output.len);
1639+
} else {
1640+
memcpy(heap_str, utf8_str.c_str(), output.len);
1641+
}
1642+
output.ptr = heap_str;
1643+
return true;
1644+
}
1645+
15991646

16001647
// Inspector
16011648

@@ -1666,6 +1713,32 @@ v8_inspector::protocol::Runtime::RemoteObject* v8_inspector__Session__wrapObject
16661713
return static_cast<v8_inspector::protocol::Runtime::RemoteObject*>(remote_object.release());
16671714
}
16681715

1716+
bool v8_inspector__Session__unwrapObject(
1717+
v8_inspector::V8InspectorSession *session,
1718+
const void *allocator,
1719+
CZigString &out_error,
1720+
CZigString in_objectId,
1721+
v8::Local<v8::Value> &out_value,
1722+
v8::Local<v8::Context> &out_context,
1723+
CZigString &out_objectGroup
1724+
) {
1725+
auto objectId = toStringView(in_objectId.ptr, in_objectId.len);
1726+
auto error = v8_inspector::StringBuffer::create({});
1727+
auto objectGroup = v8_inspector::StringBuffer::create({});
1728+
1729+
// [out optional ] std::unique_ptr<StringBuffer>* error,
1730+
// [in required ] StringView objectId,
1731+
// [out required ] v8::Local<v8::Value> * value
1732+
// [out required ] v8::Local<v8::Context> * context
1733+
// [out optional ] std::unique_ptr<StringBuffer>* objectGroup
1734+
bool result = session->unwrapObject(&error, objectId, &out_value, &out_context, &objectGroup);
1735+
if (!result) {
1736+
allocString(error->string(), allocator, out_error);
1737+
return false;
1738+
}
1739+
return allocString(objectGroup->string(), allocator, out_objectGroup);
1740+
}
1741+
16691742
// RemoteObject
16701743

16711744
// To prevent extra allocations on every call a single default value is reused everytime.
@@ -1679,7 +1752,7 @@ void v8_inspector__RemoteObject__DELETE(v8_inspector::protocol::Runtime::RemoteO
16791752
// RemoteObject - Type
16801753
const char* v8_inspector__RemoteObject__getType(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
16811754
auto str = self->getType();
1682-
return toHeapCharPtr(str, allocator);
1755+
return allocStringWith0(str, allocator);
16831756
}
16841757
void v8_inspector__RemoteObject__setType(v8_inspector::protocol::Runtime::RemoteObject* self, const char* type, int type_len) {
16851758
self->setType(v8_inspector::String16::fromUTF8(type, type_len));
@@ -1691,7 +1764,7 @@ bool v8_inspector__RemoteObject__hasSubtype(v8_inspector::protocol::Runtime::Rem
16911764
}
16921765
const char* v8_inspector__RemoteObject__getSubtype(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
16931766
auto str = self->getSubtype(DEFAULT_STRING);
1694-
return toHeapCharPtr(str, allocator);
1767+
return allocStringWith0(str, allocator);
16951768
}
16961769
void v8_inspector__RemoteObject__setSubtype(v8_inspector::protocol::Runtime::RemoteObject* self, const char* subtype, int subtype_len) {
16971770
self->setSubtype(v8_inspector::String16::fromUTF8(subtype, subtype_len));
@@ -1703,7 +1776,7 @@ bool v8_inspector__RemoteObject__hasClassName(v8_inspector::protocol::Runtime::R
17031776
}
17041777
const char* v8_inspector__RemoteObject__getClassName(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
17051778
auto str = self->getClassName(DEFAULT_STRING);
1706-
return toHeapCharPtr(str, allocator);
1779+
return allocStringWith0(str, allocator);
17071780
}
17081781
void v8_inspector__RemoteObject__setClassName(v8_inspector::protocol::Runtime::RemoteObject* self, const char* className, int className_len) {
17091782
self->setClassName(v8_inspector::String16::fromUTF8(className, className_len));
@@ -1726,7 +1799,7 @@ bool v8_inspector__RemoteObject__hasUnserializableValue(v8_inspector::protocol::
17261799
}
17271800
const char* v8_inspector__RemoteObject__getUnserializableValue(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
17281801
auto str = self->getUnserializableValue(DEFAULT_STRING);
1729-
return toHeapCharPtr(str, allocator);
1802+
return allocStringWith0(str, allocator);
17301803
}
17311804
void v8_inspector__RemoteObject__setUnserializableValue(v8_inspector::protocol::Runtime::RemoteObject* self, const char* unserializableValue, int unserializableValue_len) {
17321805
self->setUnserializableValue(v8_inspector::String16::fromUTF8(unserializableValue, unserializableValue_len));
@@ -1738,7 +1811,7 @@ bool v8_inspector__RemoteObject__hasDescription(v8_inspector::protocol::Runtime:
17381811
}
17391812
const char* v8_inspector__RemoteObject__getDescription(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
17401813
auto str = self->getDescription(DEFAULT_STRING);
1741-
return toHeapCharPtr(str, allocator);
1814+
return allocStringWith0(str, allocator);
17421815
}
17431816
void v8_inspector__RemoteObject__setDescription(v8_inspector::protocol::Runtime::RemoteObject* self, const char* description, int description_len) {
17441817
self->setDescription(v8_inspector::String16::fromUTF8(description, description_len));
@@ -1762,7 +1835,7 @@ bool v8_inspector__RemoteObject__hasObjectId(v8_inspector::protocol::Runtime::Re
17621835

17631836
const char* v8_inspector__RemoteObject__getObjectId(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
17641837
auto str = self->getObjectId(DEFAULT_STRING);
1765-
return toHeapCharPtr(str, allocator);
1838+
return allocStringWith0(str, allocator);
17661839
}
17671840
void v8_inspector__RemoteObject__setObjectId(v8_inspector::protocol::Runtime::RemoteObject* self, const char* objectId, int objectId_len) {
17681841
self->setObjectId(v8_inspector::String16::fromUTF8(objectId, objectId_len));

src/binding.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,13 @@ const String* v8__JSON__Stringify(
958958
// Misc.
959959
void v8__base__SetDcheckFunction(void (*func)(const char*, int, const char*));
960960

961+
// Utils
962+
963+
typedef struct {
964+
const char *ptr;
965+
uint64_t len;
966+
} CZigString;
967+
961968
// Inspector
962969
// ---------
963970

@@ -1015,7 +1022,6 @@ char* v8_inspector__Client__IMPL__valueSubtype(
10151022
char* v8_inspector__Client__IMPL__descriptionForValueSubtype(
10161023
InspectorClientImpl* self, Context context, Value value);
10171024

1018-
10191025
// RemoteObject
10201026
typedef struct RemoteObject RemoteObject;
10211027
typedef struct WebDriverValue WebDriverValue;
@@ -1032,6 +1038,16 @@ RemoteObject* v8_inspector__Session__wrapObject(
10321038
const Context* ctx, const Value* val,
10331039
const char *grpname, usize grpname_len, bool generatepreview);
10341040

1041+
bool v8_inspector__Session__unwrapObject(
1042+
InspectorSession *session,
1043+
const void* allocator,
1044+
CZigString* out_error,
1045+
CZigString in_objectId,
1046+
Value** out_value,
1047+
Context** out_context,
1048+
CZigString* out_objectGroup
1049+
);
1050+
10351051
// Inspector
10361052
typedef struct Inspector Inspector;
10371053
Inspector* v8_inspector__Inspector__Create(Isolate* isolate, InspectorClientImpl* client);

src/v8.zig

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2719,6 +2719,51 @@ pub const InspectorSession = struct {
27192719
).?;
27202720
return RemoteObject{ .handle = remote_object };
27212721
}
2722+
2723+
pub fn unwrapObject(self: InspectorSession, allocator: std.mem.Allocator, objectId: []const u8) !UnwrappedObject {
2724+
const in_objectId = c.CZigString{
2725+
.ptr = objectId.ptr,
2726+
.len = objectId.len,
2727+
};
2728+
var out_error: c.CZigString = .{ .ptr = null, .len = 0 };
2729+
var out_value_handle: ?*c.Value = null;
2730+
var out_context_handle: ?*c.Context = null;
2731+
var out_objectGroup: c.CZigString = .{ .ptr = null, .len = 0 };
2732+
2733+
const result = c.v8_inspector__Session__unwrapObject(
2734+
self.handle,
2735+
&allocator,
2736+
&out_error,
2737+
in_objectId,
2738+
&out_value_handle,
2739+
&out_context_handle,
2740+
&out_objectGroup,
2741+
);
2742+
if (!result) {
2743+
if (CZigStringToString(out_error)) |err| {
2744+
if (std.mem.eql(u8, err, "Invalid remote object id")) return error.InvalidRemoteObjectId;
2745+
if (std.mem.eql(u8, err, "Cannot find context with specified id")) return error.CannotFindContextWithSpecifiedId;
2746+
if (std.mem.eql(u8, err, "Could not find object with given id")) return error.CouldNotFindObjectWithGivenId;
2747+
return error.NewUnwrapErrorPleaseReport;
2748+
}
2749+
return error.V8AllocFailed;
2750+
}
2751+
return .{
2752+
.value = Value{ .handle = out_value_handle.? },
2753+
.context = Context{ .handle = out_context_handle.? },
2754+
.objectGroup = CZigStringToString(out_objectGroup),
2755+
};
2756+
}
2757+
};
2758+
2759+
pub fn CZigStringToString(slice: c.CZigString) ?[]const u8 {
2760+
return if (slice.ptr == null) null else slice.ptr[0..slice.len];
2761+
}
2762+
2763+
pub const UnwrappedObject = struct {
2764+
value: Value,
2765+
context: Context,
2766+
objectGroup: ?[]const u8,
27222767
};
27232768

27242769
/// Note: Some getters return owned memory (strings), while others return memory owned by V8 (objects).

0 commit comments

Comments
 (0)