github.com/vugu/vugu@v0.3.5/js/impl-js.go (about) 1 // +build js 2 3 package js 4 5 // IMPLEMENTATION NOTE: (7 Apr 2019, bgp) 6 // Right now (as of Go 1.12), syscall/js essentially interacts with a big map of values 7 // on the JS side of things in the browser. "Value" is alias for "ref" which is basically 8 // a map key with some bit swizzling to stuff it into a float64, presumably so it's both 9 // easy to send back and forth between wasm and browser and also to encode info about the 10 // type in there so things like Truthy() and Type(), etc. can be answered without 11 // having to reach back out to the browser. As such, Values and refs and everything else 12 // don't appear to have any internal pointers or memory concerns at least on the Go side. 13 // So the approach here is we just alias syscall/js.Value in each appropriate place and then 14 // delegate all the calls using either casting or unsafe pointers to treat our js.Value exactly like 15 // a syscall/js.Value. (FuncOf and friends handled slightly differently.) 16 // This works with the current implementation. However if significant 17 // changes are made to syscall/js (probable), it could very well break this package. 18 // Since the future of Go-Wasm integration is unclear at this point, I'm just rolling 19 // forward with the approach above and if 1.13 or later breaks things, I'll just have to 20 // deal with it then. If Wasm gains standardized support for GC and DOM references, 21 // (see https://github.com/WebAssembly/proposals/issues/16) the odds are this package would 22 // end up just being completely rewritten to use that API+instruction set. 23 // It's also possible a WASI interface could address this functionality and/or make this entire package 24 // go away, can't really tell; my crystal ball is broken. 25 // See: https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/ 26 27 import sjs "syscall/js" 28 29 // import "unsafe" 30 31 // Error alias to syscall/js 32 type Error struct { 33 // Value is the underlying JavaScript error value. 34 Value 35 } 36 37 // Error alias to syscall/js 38 func (e Error) Error() string { 39 return sjs.Error{Value: sjs.Value(e.Value)}.Error() 40 // return (*(*sjs.Error)(unsafe.Pointer(&e))).Error() 41 } 42 43 // Func alias to syscall/js 44 type Func struct { 45 Value 46 f sjs.Func // proxy for this func from syscall/js 47 } 48 49 // FuncOf alias to syscall/js 50 func FuncOf(fn func(Value, []Value) interface{}) Func { 51 52 fn2 := func(this sjs.Value, args []sjs.Value) interface{} { 53 args2 := make([]Value, len(args)) 54 for i := range args { 55 args2[i] = Value(args[i]) 56 } 57 return fn(Value(this), args2) 58 } 59 60 f := sjs.FuncOf(fn2) 61 62 ret := Func{ 63 Value: Value(f.Value), 64 f: f, 65 } 66 67 return ret 68 } 69 70 // Release alias to syscall/js 71 func (c Func) Release() { 72 // return (*(*sjs.Func)(unsafe.Pointer(&c))).Release() 73 c.f.Release() 74 } 75 76 // Type alias to syscall/js 77 type Type int 78 79 const ( 80 TypeUndefined = Type(sjs.TypeUndefined) 81 TypeNull = Type(sjs.TypeNull) 82 TypeBoolean = Type(sjs.TypeBoolean) 83 TypeNumber = Type(sjs.TypeNumber) 84 TypeString = Type(sjs.TypeString) 85 TypeSymbol = Type(sjs.TypeSymbol) 86 TypeObject = Type(sjs.TypeObject) 87 TypeFunction = Type(sjs.TypeFunction) 88 ) 89 90 // String alias to syscall/js 91 func (t Type) String() string { 92 return sjs.Type(t).String() 93 } 94 95 // Undefined alias to syscall/js 96 func Undefined() Value { 97 return Value(sjs.Undefined()) 98 } 99 100 // Null alias to syscall/js 101 func Null() Value { 102 return Value(sjs.Null()) 103 } 104 105 // Global alias to syscall/js 106 func Global() Value { 107 return Value(sjs.Global()) 108 } 109 110 // ValueOf alias to syscall/js 111 func ValueOf(x interface{}) Value { 112 return Value(sjs.ValueOf(x)) 113 } 114 115 // CopyBytesToGo alias to syscall/js 116 func CopyBytesToGo(dst []byte, src Value) int { 117 return sjs.CopyBytesToGo(dst, sjs.Value(src)) 118 } 119 120 // CopyBytesToJS alias to syscall/js 121 func CopyBytesToJS(dst Value, src []byte) int { 122 return sjs.CopyBytesToJS(sjs.Value(dst), src) 123 } 124 125 // // TypedArray alias to syscall/js 126 // type TypedArray struct { 127 // Value 128 // } 129 130 // // TypedArrayOf alias to syscall/js 131 // func TypedArrayOf(slice interface{}) TypedArray { 132 // return TypedArray{Value: Value(sjs.TypedArrayOf(slice).Value)} 133 // } 134 135 // // Release alias to syscall/js 136 // func (a TypedArray) Release() { 137 // sjs.TypedArray{Value: sjs.Value(a.Value)}.Release() 138 // } 139 140 // ValueError alias to syscall/js 141 type ValueError struct { 142 Method string 143 Type Type 144 } 145 146 // Error alias to syscall/js 147 func (e *ValueError) Error() string { 148 e2 := sjs.ValueError{Method: e.Method, Type: sjs.Type(e.Type)} 149 return e2.Error() 150 } 151 152 // Wrapper alias to syscall/js 153 type Wrapper interface { 154 JSValue() Value 155 } 156 157 // Value alias to syscall/js 158 type Value sjs.Value 159 160 // JSValue alias to syscall/js 161 func (v Value) JSValue() Value { 162 return v 163 } 164 165 // Type alias to syscall/js 166 func (v Value) Type() Type { 167 return Type(sjs.Value(v).Type()) 168 } 169 170 func (v Value) Get(p string) Value { 171 return Value(sjs.Value(v).Get(p)) 172 } 173 174 func (v Value) Set(p string, x interface{}) { 175 sjs.Value(v).Set(p, x) 176 } 177 178 func (v Value) Index(i int) Value { 179 return Value(sjs.Value(v).Index(i)) 180 } 181 182 func (v Value) SetIndex(i int, x interface{}) { 183 sjs.Value(v).SetIndex(i, x) 184 } 185 186 func (v Value) Length() int { 187 return sjs.Value(v).Length() 188 } 189 190 func (v Value) Call(m string, args ...interface{}) Value { 191 return Value(sjs.Value(v).Call(m, fixArgsToSjs(args)...)) 192 } 193 194 func (v Value) Invoke(args ...interface{}) Value { 195 return Value(sjs.Value(v).Invoke(fixArgsToSjs(args)...)) 196 } 197 198 func (v Value) New(args ...interface{}) Value { 199 return Value(sjs.Value(v).New(fixArgsToSjs(args)...)) 200 } 201 202 func (v Value) Float() float64 { 203 return sjs.Value(v).Float() 204 } 205 206 func (v Value) Int() int { 207 return sjs.Value(v).Int() 208 } 209 210 func (v Value) Bool() bool { 211 return sjs.Value(v).Bool() 212 } 213 214 func (v Value) Truthy() bool { 215 return sjs.Value(v).Truthy() 216 } 217 218 func (v Value) String() string { 219 return sjs.Value(v).String() 220 } 221 222 func (v Value) InstanceOf(t Value) bool { 223 return sjs.Value(v).InstanceOf(sjs.Value(t)) 224 } 225 226 func (v Value) IsUndefined() bool { 227 return sjs.Value(v).IsUndefined() 228 } 229 230 func (v Value) IsNull() bool { 231 return sjs.Value(v).IsNull() 232 } 233 234 func fixArgsToSjs(args []interface{}) []interface{} { 235 for i := 0; i < len(args); i++ { 236 v := args[i] 237 if val, ok := v.(Value); ok { 238 args[i] = sjs.Value(val) // convert to sjs.Value 239 } 240 if f, ok := v.(Func); ok { 241 args[i] = f.f 242 } 243 // if ta, ok := v.(TypedArray); ok { 244 // args[i] = sjs.TypedArray{Value: sjs.Value(ta.Value)} 245 // } 246 } 247 return args 248 }