Skip to content

Commit 2cb9ef0

Browse files
authored
feat!: support decoding js arguments into structs (#6)
1 parent 48f557d commit 2cb9ef0

File tree

2 files changed

+50
-14
lines changed

2 files changed

+50
-14
lines changed

examples/call_odin.odin

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ DOC :: `<!DOCTYPE html>
3232
<br>
3333
<button onclick="webui.handleBool(true, false);">Call handleBool()</button>
3434
<br>
35+
<button onclick="webui.handleObj(JSON.stringify({ name: 'Bob', age: 30 }), JSON.stringify({ email: '[email protected]', hash: 'abc' }));">Call handleObj()</button>
36+
<br>
3537
<p>Call an Odin function that returns a response</p>
3638
<button onclick="getRespFromOdin();">Call getResponse()</button>
3739
<div>Double: <input type="text" id="my-input" value="2"></div>
@@ -49,8 +51,10 @@ DOC :: `<!DOCTYPE html>
4951
// JavaScript: `webui.handleStr('Hello', 'World');`
5052
handle_string :: proc "c" (e: ^ui.Event) {
5153
context = runtime.default_context()
52-
str1 := ui.get_arg(string, e)
53-
str2 := ui.get_arg(string, e, 1)
54+
str1, _ := ui.get_arg(string, e)
55+
str2, _ := ui.get_arg(string, e, 1)
56+
_, err := ui.get_arg(string, e, 3)
57+
assert(err == .No_Argument)
5458

5559
fmt.println("handle_string 1:", str1) // Hello
5660
fmt.println("handle_string 2:", str2) // World
@@ -59,9 +63,9 @@ handle_string :: proc "c" (e: ^ui.Event) {
5963
// JavaScript: `webui.handleInt(123, 456, 789);`
6064
handle_int :: proc "c" (e: ^ui.Event) {
6165
context = runtime.default_context()
62-
num1 := ui.get_arg(int, e)
63-
num2 := ui.get_arg(int, e, 1)
64-
num3 := ui.get_arg(int, e, 2)
66+
num1, _ := ui.get_arg(int, e)
67+
num2, _ := ui.get_arg(int, e, 1)
68+
num3, _ := ui.get_arg(int, e, 2)
6569

6670
fmt.println("handle_int 1:", num1) // 123
6771
fmt.println("handle_int 2:", num2) // 456
@@ -71,17 +75,36 @@ handle_int :: proc "c" (e: ^ui.Event) {
7175
// JavaScript: webui.handleBool(true, false);
7276
handle_bool :: proc "c" (e: ^ui.Event) {
7377
context = runtime.default_context()
74-
status1 := ui.get_arg(bool, e)
75-
status2 := ui.get_arg(bool, e, 1)
78+
status1, _ := ui.get_arg(bool, e)
79+
status2, _ := ui.get_arg(bool, e, 1)
7680

7781
fmt.println("handle_bool 1:", status1) // true
7882
fmt.println("handle_bool 2:", status2) // false
7983
}
8084

85+
// JavaScript: webui.handleObj(JSON.stringify({ name: 'Bob', age: 30 }), JSON.stringify({ email: '[email protected]', hash: 'abc' }));
86+
handle_struct :: proc "c" (e: ^ui.Event) {
87+
context = runtime.default_context()
88+
Person :: struct {
89+
name: string,
90+
age: int,
91+
}
92+
struct1, _ := ui.get_arg(Person, e)
93+
struct2, err := ui.get_arg(struct {
94+
email, hash: string,
95+
}, e, 1)
96+
if err != nil {
97+
fmt.println("Failed to get arg: ", err)
98+
}
99+
100+
fmt.println("handle_struct 1:", struct1)
101+
fmt.println("handle_struct 2:", struct2)
102+
}
103+
81104
// JavaScript: `const result = await webui.getResponse(number);`
82105
get_response :: proc "c" (e: ^ui.Event) {
83106
context = runtime.default_context()
84-
num := ui.get_arg(int, e)
107+
num, _ := ui.get_arg(int, e)
85108

86109
resp := num * 2
87110
fmt.println("handle_response:", resp)
@@ -98,6 +121,7 @@ main :: proc() {
98121
ui.bind(w, "handleStr", handle_string)
99122
ui.bind(w, "handleInt", handle_int)
100123
ui.bind(w, "handleBool", handle_bool)
124+
ui.bind(w, "handleObj", handle_struct)
101125
ui.bind(w, "getResponse", get_response)
102126

103127
// Show the HTML UI.

webui.odin

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package webui
33
import "base:intrinsics"
44
import "base:runtime"
55
import "core:c"
6+
import "core:encoding/json"
67
import "core:fmt"
78
import "core:strings"
89
import "core:time"
@@ -214,17 +215,28 @@ script :: proc(
214215
return strings.string_from_ptr(buf, int(buffer_len)), .None
215216
}
216217

218+
GetArgError :: union {
219+
enum {
220+
None,
221+
No_Argument,
222+
},
223+
json.Unmarshal_Error,
224+
}
225+
217226
// Parse a JS argument as Odin data type.
218-
get_arg :: proc($T: typeid, e: ^Event, idx: uint = 0) -> T {
227+
get_arg :: proc($T: typeid, e: ^Event, idx: uint = 0) -> (res: T, err: GetArgError) {
228+
if get_size_at(e, idx) == 0 {
229+
return res, .No_Argument
230+
}
219231
when intrinsics.type_is_numeric(T) {
220-
return auto_cast get_int_at(e, idx)
232+
return auto_cast get_int_at(e, idx), nil
221233
} else when T == string {
222-
return string(get_string_at(e, idx))
234+
return string(get_string_at(e, idx)), nil
223235
} else when T == bool {
224-
return get_bool_at(e, idx)
236+
return get_bool_at(e, idx), nil
225237
}
226-
// TODO: unmarshal other types from JSON
227-
return {}
238+
json.unmarshal_string(string(get_string_at(e, idx)), &res) or_return
239+
return
228240
}
229241

230242
// Return the response to JavaScript.

0 commit comments

Comments
 (0)