Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS/Demo Gen: Array of Strings Support #624

Merged
merged 12 commits into from
Aug 12, 2024
18 changes: 18 additions & 0 deletions example/demo_gen/demo/rendering/rendering.mjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions example/demo_gen/demo/rendering/template.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 42 additions & 6 deletions example/js/lib/api/diplomat-runtime.mjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion feature_tests/js/api/MyString.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion feature_tests/js/api/MyString.mjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 42 additions & 6 deletions feature_tests/js/api/diplomat-runtime.mjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions feature_tests/js/test/slices-ts.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ test("MyString functionality", (t) => {
let str = MyString.new_("This is a test value.");
t.is(str.str, "This is a test value.");
});
test("String List", (t) => {
let str = MyString.newFromFirst(["This", "is", "a", "test."]);
t.is(str.str, "This");
});
9 changes: 7 additions & 2 deletions feature_tests/js/test/slices-ts.mts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import test from 'ava';
import { MyString } from "diplomat-wasm-js-feature-tests";

test("MyString functionality", (t) => {
let str = MyString.new_("This is a test value.");
t.is(str.str, "This is a test value.");
let str = MyString.new_("This is a test value.");
t.is(str.str, "This is a test value.");
});

test("String List", (t) => {
let str = MyString.newFromFirst(["This", "is", "a", "test."]);
t.is(str.str, "This");
});
9 changes: 7 additions & 2 deletions feature_tests/js/test/slices.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import test from 'ava';
import { MyString } from "diplomat-wasm-js-feature-tests";

test("MyString functionality", (t) => {
let str = MyString.new_("This is a test value.");
t.is(str.str, "This is a test value.");
let str = MyString.new_("This is a test value.");
t.is(str.str, "This is a test value.");
});

test("String List", (t) => {
let str = MyString.newFromFirst(["This", "is", "a", "test."]);
t.is(str.str, "This");
});
2 changes: 1 addition & 1 deletion tool/src/demo_gen/terminus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ impl<'ctx, 'tcx> RenderTerminusContext<'ctx, 'tcx> {
);
}
Type::Slice(hir::Slice::Strs(..)) => {
self.append_out_param(param_name, "Array<String>".to_string(), node, attrs);
self.append_out_param(param_name, "Array<string>".to_string(), node, attrs);
}
// Types we can't easily coerce into out parameters:
Type::Opaque(o) => {
Expand Down
20 changes: 13 additions & 7 deletions tool/src/js/type_generation/converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl<'jsctx, 'tcx> TyGenContext<'jsctx, 'tcx> {
Type::Slice(hir::Slice::Primitive(_, p)) => {
self.formatter.fmt_primitive_list_type(p).into()
}
Type::Slice(hir::Slice::Strs(..)) => "Array<String>".into(),
Type::Slice(hir::Slice::Strs(..)) => "Array<string>".into(),
_ => unreachable!("AST/HIR variant {:?} unknown", ty),
}
}
Expand Down Expand Up @@ -527,14 +527,20 @@ impl<'jsctx, 'tcx> TyGenContext<'jsctx, 'tcx> {
Type::Opaque(ref op) if op.is_optional() => format!("{js_name}.ffiValue ?? 0").into(),
Type::Enum(..) | Type::Opaque(..) => format!("{js_name}.ffiValue").into(),
Type::Struct(..) => self.gen_js_to_c_for_struct_type(js_name, struct_borrow_info),
Type::Slice(hir::Slice::Str(_, encoding) | hir::Slice::Strs(encoding)) => {
Type::Slice(hir::Slice::Str(_, encoding)) => match encoding {
hir::StringEncoding::UnvalidatedUtf8 | hir::StringEncoding::Utf8 => {
format!("diplomatRuntime.DiplomatBuf.str8(wasm, {js_name})").into()
}
_ => format!("diplomatRuntime.DiplomatBuf.str16(wasm, {js_name})").into(),
},
Type::Slice(hir::Slice::Strs(encoding)) => format!(
r#"diplomatRuntime.DiplomatBuf.strs(wasm, {js_name}, "{}")"#,
match encoding {
hir::StringEncoding::UnvalidatedUtf8 | hir::StringEncoding::Utf8 => {
format!("diplomatRuntime.DiplomatBuf.str8(wasm, {js_name})").into()
}
_ => format!("diplomatRuntime.DiplomatBuf.str16(wasm, {js_name})").into(),
hir::StringEncoding::UnvalidatedUtf16 => "string16",
_ => "string8",
}
}
)
.into(),
Type::Slice(hir::Slice::Primitive(_, p)) => format!(
r#"diplomatRuntime.DiplomatBuf.slice(wasm, {js_name}, "{}")"#,
self.formatter.fmt_primitive_list_view(p)
Expand Down
18 changes: 18 additions & 0 deletions tool/templates/demo_gen/default_renderer/rendering.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,20 @@ class StringTemplate extends ParameterTemplate {

customElements.define("terminus-param-string", StringTemplate);

class StringArrayTemplate extends ParameterTemplate {
default = [];
static template;
constructor() {
super(StringArrayTemplate, "template#string-array");
}

getEventValue(event) {
return event.target.value.split(",");
}
}

customElements.define("terminus-param-string-array", StringArrayTemplate);

class EnumOption extends HTMLElement {
static template;
constructor(optionText) {
Expand Down Expand Up @@ -149,6 +163,10 @@ class TerminusParams extends HTMLElement {
newChild = new NumberTemplate();
this.#params[i] = 0;
break;
case "Array<string>":
newChild = new StringArrayTemplate();
this.#params[i] = [];
break;
default:
if (param.type in library && "values" in library[param.type]) {
newChild = new EnumTemplate(library[param.type]);
Expand Down
4 changes: 4 additions & 0 deletions tool/templates/demo_gen/default_renderer/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ <h1><slot name="func-name"></slot></h1>
<input type="text" data-oninput/>
</template>

<template id="string-array">
<textarea data-oninput></textarea>
</template>

<template id="number">
<!-- Floats not supported by the example ICU4XFixedDecimal type for whatever reason. -->
<input type="number" data-oninput/>
Expand Down
48 changes: 42 additions & 6 deletions tool/templates/js/runtime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,33 @@ export class DiplomatBuf {
return new DiplomatBuf(ptr, list.length, () => wasm.diplomat_free(ptr, byteLength, elementSize));
}


static strs = (wasm, strings, encoding) => {
let encodeStr = (encoding === "string16") ? DiplomatBuf.str16 : DiplomatBuf.str8;

const byteLength = strings.length * 4 * 2;

const ptr = wasm.diplomat_alloc(byteLength, 4);

const destination = new Uint32Array(wasm.memory.buffer, ptr, byteLength);

const stringsAlloc = [];

for (let i = 0; i < strings.length; i++) {
stringsAlloc.push(encodeStr(wasm, strings[i]));

destination[2 * i] = stringsAlloc[i].ptr;
destination[(2 * i) + 1] = stringsAlloc[i].size;
}

return new DiplomatBuf(ptr, strings.length, () => {
wasm.diplomat_free(ptr, byteLength, 4);
for (let i = 0; i < stringsAlloc.length; i++) {
stringsAlloc[i].free();
}
});
}

/**
* Generated code calls one of methods these for each allocation, to either
* free directly after the FFI call, to leak (to create a &'static), or to
Expand Down Expand Up @@ -267,9 +294,8 @@ export class DiplomatReceiveBuf {
* @param {number} buffer Buffer to use. Only used by `getStrings`, other wise {@link DiplomatReceiveBuf.buffer} is used.
* @returns {string} String with encoding of the provided `stringEncoding`.
*/
getString(stringEncoding, buffer=null) {
let buf = buffer === null? this.#buffer : buffer;
const [ptr, size] = new Uint32Array(this.#wasm.memory.buffer, buf, 2);
getString(stringEncoding) {
const [ptr, size] = new Uint32Array(this.#wasm.memory.buffer, this.#buffer, 2);
switch (stringEncoding) {
case "string8":
return readString8(wasm, ptr, size);
Expand All @@ -289,10 +315,20 @@ export class DiplomatReceiveBuf {
getStrings(stringEncoding) {
const [ptr, size] = new Uint32Array(this.#wasm.memory.buffer, this.#buffer, 2);

let strPtrs = new Uint32Array(this.#wasm.memory.buffer, ptr, size);
let strings = [];
for (var arrayPtr = ptr; arrayPtr < size; arrayPtr += 1) {
var out = stringFromPtr(stringEncoding, arrayPtr);
strings.push(out);

for (let arrayPtr = 0; arrayPtr < strPtrs.length; arrayPtr += 2) {
const [strPtr, strSize] = [strPtrs[arrayPtr], strPtrs[arrayPtr + 1]];
switch (stringEncoding) {
case "string8":
strings.push(readString8(this.#wasm, strPtr, strSize));
case "string16":
strings.push(readString16(this.#wasm, strPtr, strSize));
default:
console.error("Unrecognized stringEncoding ", stringEncoding);
break;
}
}
return strings;
}
Expand Down
Loading