Skip to content

Commit

Permalink
feat: implement TextEncoder and TextDecoder classes with encoding/dec…
Browse files Browse the repository at this point in the history
…oding methods
  • Loading branch information
XuJiandong committed Jan 24, 2025
1 parent 0a6f5ad commit 95802bd
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 3 deletions.
3 changes: 1 addition & 2 deletions packages/core/src/molecule/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,7 @@ export abstract class Entity {
}

abstract toBytes(): Bytes;
// TODO
// abstract hash(): Hex;
abstract hash(): Bytes;
abstract clone(): Entity;
}

Expand Down
78 changes: 78 additions & 0 deletions src/misc_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,62 @@ static const JSCFunctionListEntry js_misc_funcs[] = {
JS_CFUNC_DEF("printf", 1, js_std_printf),
};

// TextDecoder decode method
static JSValue js_text_decoder_decode(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
size_t data_len;
uint8_t *data;

data = JS_GetArrayBuffer(ctx, &data_len, argv[0]);

if (!data) {
return JS_ThrowTypeError(ctx, "Failed to get array buffer data");
}

// UTF-8 decoding
return JS_NewStringLen(ctx, (char *)data, data_len);
}

// TextEncoder encode method
static JSValue js_text_encoder_encode(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
size_t str_len;
const char *str = JS_ToCStringLen(ctx, &str_len, argv[0]);
if (!str) {
return JS_ThrowTypeError(ctx, "Expected string");
}
JSValue uint8_array = JS_NewArrayBufferCopy(ctx, (uint8_t *)str, str_len);
JS_FreeCString(ctx, str);
return uint8_array;
}

// TextDecoder constructor
static JSValue js_text_decoder_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv) {
return JS_NewObjectClass(ctx, js_text_decoder_class_id);
}

// TextEncoder constructor
static JSValue js_text_encoder_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv) {
return JS_NewObjectClass(ctx, js_text_encoder_class_id);
}

// TextDecoder class definition
static const JSCFunctionListEntry js_text_decoder_proto_funcs[] = {
JS_CFUNC_DEF("decode", 1, js_text_decoder_decode),
};

static const JSClassDef js_text_decoder_class = {
"TextDecoder",
};

// TextEncoder class definition
static const JSCFunctionListEntry js_text_encoder_proto_funcs[] = {
JS_CFUNC_DEF("encode", 1, js_text_encoder_encode),
};

static const JSClassDef js_text_encoder_class = {
"TextEncoder",
};

// Update the init function to include TextEncoder and TextDecoder
int qjs_init_module_misc_lazy(JSContext *ctx, JSModuleDef *m) {
JSValue proto, obj;

Expand Down Expand Up @@ -534,6 +590,26 @@ int qjs_init_module_misc_lazy(JSContext *ctx, JSModuleDef *m) {
JS_SetPropertyFunctionList(ctx, base64, js_base64_funcs, countof(js_base64_funcs));
JS_SetModuleExport(ctx, m, "base64", base64);

// Initialize TextDecoder class
JS_NewClassID(&js_text_decoder_class_id);
JS_NewClass(JS_GetRuntime(ctx), js_text_decoder_class_id, &js_text_decoder_class);
proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, proto, js_text_decoder_proto_funcs, countof(js_text_decoder_proto_funcs));
obj = JS_NewCFunction2(ctx, js_text_decoder_constructor, "TextDecoder", 0, JS_CFUNC_constructor, 0);
JS_SetConstructor(ctx, obj, proto);
JS_SetClassProto(ctx, js_text_decoder_class_id, proto);
JS_SetModuleExport(ctx, m, "TextDecoder", obj);

// Initialize TextEncoder class
JS_NewClassID(&js_text_encoder_class_id);
JS_NewClass(JS_GetRuntime(ctx), js_text_encoder_class_id, &js_text_encoder_class);
proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, proto, js_text_encoder_proto_funcs, countof(js_text_encoder_proto_funcs));
obj = JS_NewCFunction2(ctx, js_text_encoder_constructor, "TextEncoder", 0, JS_CFUNC_constructor, 0);
JS_SetConstructor(ctx, obj, proto);
JS_SetClassProto(ctx, js_text_encoder_class_id, proto);
JS_SetModuleExport(ctx, m, "TextEncoder", obj);

// functions without submodule
JS_SetModuleExportList(ctx, m, js_misc_funcs, countof(js_misc_funcs));

Expand All @@ -544,6 +620,8 @@ int qjs_init_module_misc(JSContext *ctx, JSModuleDef *m) {
JS_AddModuleExport(ctx, m, "Smt");
JS_AddModuleExport(ctx, m, "hex");
JS_AddModuleExport(ctx, m, "base64");
JS_AddModuleExport(ctx, m, "TextDecoder");
JS_AddModuleExport(ctx, m, "TextEncoder");
JS_AddModuleExportList(ctx, m, js_misc_funcs, countof(js_misc_funcs));
return 0;
}
4 changes: 3 additions & 1 deletion src/misc_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
#include "quickjs.h"

// Class ID for Smt
static JSClassID js_smt_class_id;
JSClassID js_smt_class_id;
JSClassID js_text_decoder_class_id;
JSClassID js_text_encoder_class_id;

// Module initialization
int qjs_init_module_misc(JSContext* ctx, JSModuleDef* m);
Expand Down
24 changes: 24 additions & 0 deletions tests/module/test_misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,32 @@ function test_require() {
}


function test_text_encoder() {
const encoder = new misc.TextEncoder();
const encoded = encoder.encode("你好世界");
// Each Chinese character takes 3 bytes in UTF-8
const expected = new Uint8Array([
0xe4, 0xbd, 0xa0, // 你
0xe5, 0xa5, 0xbd, // 好
0xe4, 0xb8, 0x96, // 世
0xe7, 0x95, 0x8c // 界
]);
console.assert(
encoded.byteLength === expected.length, 'Encoded length mismatch');
for (let i = 0; i < encoded.length; i++) {
console.assert(encoded[i] === expected[i], `Byte mismatch at position ${i}`);
}
console.log('test_text_encoder ok');

const decoder = new misc.TextDecoder();
const decoded = decoder.decode(encoded);
console.assert(decoded === "你好世界", 'TextDecoder failed');
console.log('test_text_decoder ok');
}

// Add the new test cases to the main execution
console.log('test_misc.js ...');
test_text_encoder();
test_printf();
test_require();
test_ckb_smt_verify1(true);
Expand Down

0 comments on commit 95802bd

Please sign in to comment.