Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions bindings/napi/to_napi_value.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ pub fn sszValueToNapiValue(env: napi.Env, comptime ST: type, value: *const ST.Ty
return try env.getBoolean(value.*);
},
.vector => {
if (comptime ssz.isByteVectorType(ST)) {
if (comptime ssz.isBitVectorType(ST)) {
return try bitArrayToNapiValue(env, value.data[0..], ST.length);
} else if (comptime ssz.isByteVectorType(ST)) {
var bytes: [*]u8 = undefined;
const buf = try env.createArrayBuffer(ST.length, &bytes);
@memcpy(bytes[0..ST.length], value);
Expand All @@ -30,7 +32,9 @@ pub fn sszValueToNapiValue(env: napi.Env, comptime ST: type, value: *const ST.Ty
}
},
.list => {
if (comptime ssz.isByteListType(ST)) {
if (comptime ssz.isBitListType(ST)) {
return try bitArrayToNapiValue(env, value.data.items, value.bit_len);
} else if (comptime ssz.isByteListType(ST)) {
var bytes: [*]u8 = undefined;
const buf = try env.createArrayBuffer(value.items.len, &bytes);
@memcpy(bytes[0..value.items.len], value.items);
Expand All @@ -56,6 +60,22 @@ pub fn sszValueToNapiValue(env: napi.Env, comptime ST: type, value: *const ST.Ty
}
}

/// Converts a bit array into a `napi.Value`.
///
/// The napi value matches the shape of `ssz-ts` for interoperability.
fn bitArrayToNapiValue(env: napi.Env, data: []const u8, bit_len: usize) !napi.Value {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest to create known type under bindings/napi/js_types.zig and then reuse here.

pub const BitArray = js.Object(struct {
    uint8Array: js.Uint8Array,
    bitLen: js.Number,
});

This will reduce the code to following, will later be further optimized, as I will introduce an interface Object.init that will help to do BitArray.init syntax.

fn bitArrayToNapiValue(env: napi.Env, data: []const u8, bit_len: usize) !napi.Value {
    std.debug.assert(data.len == (bit_len + 7) / 8);

    const obj = js_types.BitArray{ .val = try env.createObject() }; // wrap an empty {}
    try obj.set(.{
        .uint8Array = js.Uint8Array.from(data),       // copies bytes into fresh V8 buffer
        .bitLen = js.Number.from(bit_len),
    });
    return obj.toValue();                              // unwrap back to napi.Value
}

std.debug.assert(data.len == (bit_len + 7) / 8);
var bytes: [*]u8 = undefined;
const buf = try env.createArrayBuffer(data.len, &bytes);
@memcpy(bytes[0..data.len], data);
const uint8_array = try env.createTypedarray(.uint8, data.len, buf, 0);

const obj = try env.createObject();
try obj.setNamedProperty("uint8Array", uint8_array);
try obj.setNamedProperty("bitLen", try env.createInt64(@intCast(bit_len)));
return obj;
}
Comment on lines +66 to +77

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The bitArrayToNapiValue function is missing assertions for its arguments, which is a requirement of the repository's style guide (based on TigerStyle). Specifically, it should assert that bit_len is within the range of i64 (since it is cast to it for the N-API call) and that the data slice length is consistent with the provided bit_len.

According to the style guide:

  • "Assert all function arguments and return values, pre/postconditions and invariants."
  • "The assertion density of the code must average a minimum of two assertions per function."
  • "Split compound assertions: prefer assert(a); assert(b); over assert(a and b);."
fn bitArrayToNapiValue(env: napi.Env, data: []const u8, bit_len: usize) !napi.Value {
    std.debug.assert(bit_len <= std.math.maxInt(i64));
    std.debug.assert(data.len == (bit_len + 7) / 8);

    var bytes: [*]u8 = undefined;
    const buf = try env.createArrayBuffer(data.len, &bytes);
    @memcpy(bytes[0..data.len], data);
    const uint8_array = try env.createTypedarray(.uint8, data.len, buf, 0);

    const obj = try env.createObject();
    try obj.setNamedProperty("uint8Array", uint8_array);
    try obj.setNamedProperty("bitLen", try env.createInt64(@intCast(bit_len)));
    return obj;
}
References
  1. Assert all function arguments and return values, pre/postconditions and invariants. The assertion density of the code must average a minimum of two assertions per function. Split compound assertions: prefer assert(a); assert(b); over assert(a and b);. (link)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accepted the assertion for data.len


const NumberSliceOpts = struct {
typed_array: ?napi.value_types.TypedarrayType = null,
};
Expand Down
Loading