embind

package
v1.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 17, 2024 License: MIT Imports: 18 Imported by: 0

Documentation

Index

Constants

View Source
const GenericWireTypeSize = 8

Variables

View Source
var CreateInheritingConstructor = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	constructorNamePtr := api.DecodeI32(stack[0])
	wrapperTypePtr := api.DecodeI32(stack[1])
	propertiesId := api.DecodeI32(stack[2])

	constructorName, err := engine.readCString(uint32(constructorNamePtr))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	wrapperType, err := engine.requireRegisteredType(ctx, wrapperTypePtr, "wrapper")
	if err != nil {
		panic(fmt.Errorf("could not require registered type: %w", err))
	}

	properties, err := engine.emvalEngine.toValue(propertiesId)
	if err != nil {
		panic(fmt.Errorf("could not get properties val: %w", err))
	}

	if _, ok := properties.(IClassBase); !ok {
		panic(fmt.Errorf("could not register class %s with type %T, it does not embed embind.ClassBase", constructorName, properties))
	}

	reflectClassType := reflect.TypeOf(properties)
	if reflectClassType.Kind() != reflect.Ptr {
		panic(fmt.Errorf("could not register class %s with type %T, given value should be a pointer type", constructorName, properties))
	}

	registeredPointerType := wrapperType.(*registeredPointerType)
	registeredClass := registeredPointerType.registeredClass

	legalFunctionName := engine.makeLegalFunctionName(constructorName)
	err = engine.exposePublicSymbol(legalFunctionName, func(ctx context.Context, this any, arguments ...any) (any, error) {
		innerClass := registeredClass.baseClass
		implement, ok := innerClass.methods["implement"]
		if !ok {
			return nil, fmt.Errorf("base class %s does not have implement method", innerClass.name)
		}

		classBase := &ClassBase{}

		args := append([]any{classBase}, arguments...)
		inner, err := implement.fn(ctx, nil, args...)

		if err != nil {
			return nil, err
		}

		innerTyped := inner.(IClassBase)
		ptrTypeRecord := innerTyped.getRegisteredPtrTypeRecord()

		_, err = innerTyped.CallInstanceMethod(ctx, inner, "notifyOnDestruction")
		if err != nil {
			return nil, err
		}

		ptrTypeRecord.preservePointerOnDelete = true

		classBase.classType = registeredClass
		classBase.ptr = ptrTypeRecord.ptr
		classBase.ptrType = ptrTypeRecord.ptrType
		classBase.registeredPtrTypeRecord = ptrTypeRecord
		classBase.engine = engine

		typeElem := reflectClassType.Elem()
		newElem := reflect.New(typeElem)
		f := newElem.Elem().FieldByName("ClassBase")
		if f.IsValid() && f.CanSet() {
			f.Set(reflect.ValueOf(classBase))
		}

		result := newElem.Interface()

		resultClassBase := result.(IClassBase)

		err = engine.registerInheritedInstance(ctx, registeredClass, ptrTypeRecord.ptr, resultClassBase)
		if err != nil {
			return nil, err
		}

		return result, nil
	}, nil)
	if err != nil {
		panic(fmt.Errorf("could not expose public symbol: %w", err))
	}

	newFn := func(ctx context.Context, arguments ...any) (any, error) {
		return engine.publicSymbols[legalFunctionName].fn(ctx, nil, arguments...)
	}

	stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(newFn))
})
View Source
var EmvalAs = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	id := api.DecodeI32(stack[0])
	destructorsRef := uint32(api.DecodeI32(stack[2]))

	returnType, err := engine.requireRegisteredType(ctx, api.DecodeI32(stack[1]), "emval::as")
	if err != nil {
		panic(fmt.Errorf("could not require registered type: %w", err))
	}

	handle, err := engine.emvalEngine.toValue(id)
	if err != nil {
		panic(fmt.Errorf("could not get value of handle: %w", err))
	}

	returnVal, err := EmvalReturnValue(ctx, mod, returnType, destructorsRef, handle)
	if err != nil {
		panic(fmt.Errorf("could not get emval return value: %w", err))
	}

	stack[0] = api.EncodeF64(returnType.ToF64(returnVal))
})
View Source
var EmvalAsInt64 = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	id := api.DecodeI32(stack[0])
	handle, err := engine.emvalEngine.toValue(id)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	returnType, err := engine.requireRegisteredType(ctx, api.DecodeI32(stack[1]), "emval::as")
	if err != nil {
		panic(fmt.Errorf("could not require registered type: %w", err))
	}

	returnVal, err := returnType.ToWireType(ctx, mod, nil, handle)
	if err != nil {
		panic(fmt.Errorf("could not call toWireType on _emval_as: %w", err))
	}

	stack[0] = returnVal
})
View Source
var EmvalAsUint64 = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	id := api.DecodeI32(stack[0])
	handle, err := engine.emvalEngine.toValue(id)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	returnType, err := engine.requireRegisteredType(ctx, api.DecodeI32(stack[1]), "emval::as")
	if err != nil {
		panic(fmt.Errorf("could not require registered type: %w", err))
	}

	returnVal, err := returnType.ToWireType(ctx, mod, nil, handle)
	if err != nil {
		panic(fmt.Errorf("could not call toWireType on _emval_as: %w", err))
	}

	stack[0] = returnVal
})
View Source
var EmvalAwait = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalAwait call unimplemented")
})
View Source
var EmvalCall = func(hasF64Return bool) api.GoModuleFunc {
	return api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
		engine := MustGetEngineFromContext(ctx, mod).(*engine)
		if hasF64Return {
			caller := api.DecodeI32(stack[0])
			id := api.DecodeI32(stack[1])
			destructorsRef := uint32(api.DecodeI32(stack[2]))
			argsBase := uint32(api.DecodeI32(stack[3]))

			handle, err := engine.emvalEngine.toValue(id)
			if err != nil {
				panic(fmt.Errorf("could not find handle: %w", err))
			}

			registeredMethod, ok := engine.emvalEngine.registeredMethods[caller]
			if !ok {
				panic(fmt.Errorf("could not call method with ID %d", caller))
			}

			res, err := engine.emvalEngine.callMethod(ctx, mod, registeredMethod, handle, nil, destructorsRef, argsBase, false)
			if err != nil {
				panic(fmt.Errorf("could not call %s on %T: %w", registeredMethod.name, handle, err))
			}
			stack[0] = api.EncodeF64(float64(res))
		} else {
			id := api.DecodeI32(stack[0])
			argCount := api.DecodeI32(stack[1])
			argTypes := api.DecodeI32(stack[2])
			argv := api.DecodeI32(stack[3])

			handle, err := engine.emvalEngine.toValue(id)
			if err != nil {
				panic(fmt.Errorf("could not find handle: %w", err))
			}

			registeredArgTypes, err := engine.lookupTypes(ctx, argCount, argTypes)
			if err != nil {
				panic(fmt.Errorf("could not load required types: %w", err))
			}

			args := make([]any, argCount)
			for i := 0; i < int(argCount); i++ {
				requiredType := registeredArgTypes[i]
				args[i], err = requiredType.ReadValueFromPointer(ctx, mod, uint32(argv))
				if err != nil {
					panic(fmt.Errorf("could not load argument value: %w", err))
				}

				argv += requiredType.ArgPackAdvance()
			}

			reflectValues := make([]reflect.Value, argCount)
			for i := range args {
				reflectValues[i] = reflect.ValueOf(args[i])
			}

			value := reflect.ValueOf(handle)
			result := value.Call(reflectValues)

			var resultVal any = types.Undefined
			if len(result) > 0 {
				resultVal = result[0].Interface()
			}

			newHandle := engine.emvalEngine.toHandle(resultVal)
			stack[0] = api.EncodeI32(newHandle)
		}
	})
}
View Source
var EmvalCallMethod = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	caller := api.DecodeI32(stack[0])

	registeredMethod, ok := engine.emvalEngine.registeredMethods[caller]
	if !ok {
		panic(fmt.Errorf("could not call method with ID %d", caller))
	}

	id := api.DecodeI32(stack[1])
	handle, err := engine.emvalEngine.toValue(id)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	methodName, err := engine.getStringOrSymbol(uint32(api.DecodeI32(stack[2])))
	if err != nil {
		panic(fmt.Errorf("could not get symbol name"))
	}

	argsBase := uint32(api.DecodeI32(stack[4]))
	destructorsRef := uint32(api.DecodeI32(stack[3]))

	method, injectCtx, err := EmvalGetMethodOnObject(handle, registeredMethod, methodName)
	if err != nil {
		panic(fmt.Errorf("could not call %s on %T: %w", methodName, handle, err))
	}

	res, err := engine.emvalEngine.callMethod(ctx, mod, registeredMethod, handle, method, destructorsRef, argsBase, injectCtx)
	if err != nil {
		panic(fmt.Errorf("could not call %s on %T: %w", methodName, handle, err))
	}
	stack[0] = api.EncodeF64(float64(res))
})
View Source
var EmvalCallVoidMethod = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	caller := api.DecodeI32(stack[0])

	registeredMethod, ok := engine.emvalEngine.registeredMethods[caller]
	if !ok {
		panic(fmt.Errorf("could not call method with ID %d", caller))
	}

	id := api.DecodeI32(stack[1])
	handle, err := engine.emvalEngine.toValue(id)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	methodName, err := engine.getStringOrSymbol(uint32(api.DecodeI32(stack[2])))
	if err != nil {
		panic(fmt.Errorf("could not get symbol name"))
	}

	argsBase := uint32(api.DecodeI32(stack[3]))

	method, injectCtx, err := EmvalGetMethodOnObject(handle, registeredMethod, methodName)
	if err != nil {
		panic(fmt.Errorf("could not call %s on %T: %w", methodName, handle, err))
	}

	_, err = engine.emvalEngine.callMethod(ctx, mod, registeredMethod, handle, method, 0, argsBase, injectCtx)
	if err != nil {
		panic(fmt.Errorf("could not call %s on %T: %w", methodName, handle, err))
	}
})

This function is not used anymore since 3.1.48, it has been integrated into emval_call.

View Source
var EmvalDecref = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	handle := api.DecodeI32(stack[0])
	err := engine.emvalEngine.allocator.decref(handle)
	if err != nil {
		panic(fmt.Errorf("could not emval incref: %w", err))
	}
})
View Source
var EmvalDelete = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalDelete call unimplemented")
})
View Source
var EmvalEquals = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	id1 := api.DecodeI32(stack[0])
	first, err := engine.emvalEngine.toValue(id1)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	id2 := api.DecodeI32(stack[1])
	second, err := engine.emvalEngine.toValue(id2)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	ret := int32(0)
	if first == second {
		ret = 1
	}

	stack[0] = api.EncodeI32(ret)
})
View Source
var EmvalGetGlobal = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	name := api.DecodeI32(stack[0])

	if name == 0 {
		stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(engine.emvalEngine.getGlobal(nil)))
	} else {
		name, err := engine.getStringOrSymbol(uint32(name))
		if err != nil {
			panic(fmt.Errorf("could not get symbol name"))
		}
		stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(engine.emvalEngine.getGlobal(&name)))
	}
})
View Source
var EmvalGetMethodCaller = func(hasKind bool) api.GoModuleFunc {
	return api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
		engine := MustGetEngineFromContext(ctx, mod).(*engine)

		argCount := int(api.DecodeI32(stack[0]))
		argsTypeBase := uint32(api.DecodeI32(stack[1]))

		typeNames := make([]string, argCount)
		argTypes := make([]registeredType, argCount)
		for i := 0; i < argCount; i++ {
			argType, ok := mod.Memory().ReadUint32Le(argsTypeBase + (4 * uint32(i)))
			if !ok {
				panic(fmt.Errorf("could not read arg type for arg %d from memory", i))
			}

			registeredType, err := engine.requireRegisteredType(ctx, int32(argType), fmt.Sprintf("argument %d", i))
			if err != nil {
				panic(fmt.Errorf("could not require registered type: %w", err))
			}

			typeNames[i] = registeredType.Name()
			argTypes[i] = registeredType
		}

		signatureName := typeNames[0] + "_$" + strings.Join(typeNames[1:], "_") + "$"

		id, ok := engine.emvalEngine.registeredMethodIds[signatureName]
		if ok {
			stack[0] = api.EncodeI32(id)
			return
		}

		newID := engine.emvalEngine.registeredMethodCount
		newRegisteredMethod := &emvalRegisteredMethod{
			id:       newID,
			argTypes: argTypes,
			name:     signatureName,
		}

		if hasKind {
			kind := api.DecodeI32(stack[2])
			newRegisteredMethod.kind = &kind
		}

		engine.emvalEngine.registeredMethodIds[signatureName] = newID
		engine.emvalEngine.registeredMethods[newID] = newRegisteredMethod
		engine.emvalEngine.registeredMethodCount++

		stack[0] = api.EncodeI32(newID)
		return
	})
}
View Source
var EmvalGetModuleProperty = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalGetModuleProperty call unimplemented")
})
View Source
var EmvalGetProperty = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	handle, err := engine.emvalEngine.toValue(api.DecodeI32(stack[0]))
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	key, err := engine.emvalEngine.toValue(api.DecodeI32(stack[1]))
	if err != nil {
		panic(fmt.Errorf("could not find key: %w", err))
	}

	keyInt, ok := key.(int32)
	if ok {
		arrayHandle, isAnyArray := handle.([]any)
		if !isAnyArray {
			panic(fmt.Errorf("could not get property on emval %T: %w", handle, errors.New("key is of type int32 but handle is not an array")))
		}

		if keyInt >= int32(len(arrayHandle)) {
			panic(fmt.Errorf("could not get property on emval %T: %w", handle, fmt.Errorf("invalid index %d requested", keyInt)))
		}

		stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(arrayHandle[keyInt]))
		return
	}

	keyString, ok := key.(string)
	if !ok {
		panic(fmt.Errorf("could not get property on emval %T: %w", handle, errors.New("key is not of type string")))
	}

	handleMap, isMap := handle.(map[string]any)
	if isMap {
		stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(handleMap[keyString]))
		return
	}

	f, err := engine.emvalEngine.getElemField(handle, keyString)
	if err != nil {
		panic(fmt.Errorf("could not get property %s on emval %T: %w", keyString, handle, err))
	}

	defer func() {
		if err := recover(); err != nil {
			realError, ok := err.(error)
			if ok {
				panic(fmt.Errorf("could not get property %s on emval %T: %w", keyString, handle, realError))
			}
			panic(fmt.Errorf("could not get property %s on emval %T: %v", keyString, handle, err))
		}
	}()

	stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(f.Interface()))
})
View Source
var EmvalGreaterThan = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalGreaterThan call unimplemented")
})
View Source
var EmvalIn = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalIn call unimplemented")
})
View Source
var EmvalIncref = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	handle := api.DecodeI32(stack[0])
	err := engine.emvalEngine.allocator.incref(handle)
	if err != nil {
		panic(fmt.Errorf("could not emval incref: %w", err))
	}
})
View Source
var EmvalInstanceof = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalInstanceof call unimplemented")
})
View Source
var EmvalIsNumber = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalIsNumber call unimplemented")
})
View Source
var EmvalIsString = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalIsString call unimplemented")
})
View Source
var EmvalIterBegin = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	handle := api.DecodeI32(stack[0])
	iterable, err := engine.emvalEngine.toValue(handle)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	if reflect.TypeOf(iterable).Kind() != reflect.Slice {
		panic(fmt.Errorf("handle is not a slice so can't be iterated over"))
	}

	s := reflect.ValueOf(iterable)
	stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(&emvalIterable{
		val: s,
		cur: 0,
		len: s.Len(),
	}))
})
View Source
var EmvalIterNext = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	handle := api.DecodeI32(stack[0])
	iterable, err := engine.emvalEngine.toValue(handle)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	typedIterable, isIterable := iterable.(*emvalIterable)
	if !isIterable {
		panic(fmt.Errorf("handle is not iterable but %T", iterable))
	}

	if typedIterable.cur >= typedIterable.len {
		stack[0] = 0
		return
	}

	item := typedIterable.val.Index(typedIterable.cur).Interface()
	typedIterable.cur++

	stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(item))
})
View Source
var EmvalLessThan = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalLessThan call unimplemented")
})
View Source
var EmvalNew = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	id := api.DecodeI32(stack[0])

	handle, err := engine.emvalEngine.toValue(id)
	if err != nil {
		panic(fmt.Errorf("could not get value of handle: %w", err))
	}

	argCount := int(api.DecodeI32(stack[1]))
	argsTypeBase := uint32(api.DecodeI32(stack[2]))
	argsBase := uint32(api.DecodeI32(stack[3]))

	args := make([]any, argCount)
	argTypeNames := make([]string, argCount)
	for i := 0; i < argCount; i++ {
		argType, ok := mod.Memory().ReadUint32Le(argsTypeBase + (4 * uint32(i)))
		if !ok {
			panic(fmt.Errorf("could not read arg type for arg %d from memory", i))
		}

		registeredArgType, err := engine.requireRegisteredType(ctx, int32(argType), fmt.Sprintf("argument %d", i))
		if err != nil {
			panic(fmt.Errorf("could not require registered type: %w", err))
		}

		args[i], err = registeredArgType.ReadValueFromPointer(ctx, mod, argsBase)
		if err != nil {
			panic(fmt.Errorf("could not read arg value from pointer for arg %d, %w", i, err))
		}

		argsBase += uint32(registeredArgType.ArgPackAdvance())

		argTypeNames[i] = registeredArgType.Name()
	}

	var res any
	c, ok := handle.(IEmvalConstructor)
	if ok {
		res, err = c.New(argTypeNames, args...)
		if err != nil {
			panic(fmt.Errorf("could not instaniate new value on %T with New(): %w", handle, err))
		}
	} else {
		typeElem := reflect.TypeOf(handle)

		if typeElem.Kind() == reflect.Pointer {
			typeElem = typeElem.Elem()
		}

		newElem := reflect.New(typeElem)

		if argCount > 0 {
			if typeElem.Kind() != reflect.Struct {
				panic(fmt.Errorf("could not instaniate new value of %T: arguments required but can only be set on a struct", handle))
			}

			for i := 0; i < argCount; i++ {
				argSet := false
				for fieldI := 0; fieldI < typeElem.NumField(); fieldI++ {
					var err error
					func() {
						defer func() {
							if recoverErr := recover(); recoverErr != nil {
								realError, ok := recoverErr.(error)
								if ok {
									err = fmt.Errorf("could not set arg %d with embind_arg tag on emval %T: %w", i, handle, realError)
								}
								err = fmt.Errorf("could not set arg %d with embind_arg tag on emval %T: %v", i, handle, recoverErr)
							}
						}()

						val := typeElem.Field(fieldI)
						if val.Tag.Get("embind_arg") == strconv.Itoa(i) {
							f := newElem.Elem().FieldByName(val.Name)
							if f.IsValid() && f.CanSet() {
								f.Set(reflect.ValueOf(args[i]))
								argSet = true
							}
						}
					}()
					if err != nil {
						panic(fmt.Errorf("could not instaniate new value of %T: %w", handle, err))
					}
				}
				if !argSet {
					panic(fmt.Errorf("could not instaniate new value of %T: could not bind arg %d", handle, i))
				}
			}
		}

		if reflect.TypeOf(handle).Kind() == reflect.Pointer {
			res = newElem.Interface()
		} else {
			res = newElem.Elem().Interface()
		}
	}

	stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(res))
})

This function is not used anymore since 3.1.48, it has been integrated into emval_call and emval_get_method_caller.

View Source
var EmvalNewArray = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	e := MustGetEngineFromContext(ctx, mod).(*engine)
	stack[0] = api.EncodeI32(e.emvalEngine.toHandle([]any{}))
})
View Source
var EmvalNewArrayFromMemoryView = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	handle := api.DecodeI32(stack[0])
	view, err := engine.emvalEngine.toValue(handle)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	if reflect.TypeOf(view).Kind() != reflect.Slice {
		panic(fmt.Errorf("handle is not a slice so can't be iterated over"))
	}

	s := reflect.ValueOf(view)
	newArray := make([]any, s.Len())
	for i := 0; i < s.Len(); i++ {
		newArray[i] = s.Index(i).Interface()
	}

	stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(newArray))
})
View Source
var EmvalNewCString = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	v := api.DecodeI32(stack[0])
	name, err := engine.getStringOrSymbol(uint32(v))
	if err != nil {
		panic(fmt.Errorf("could not get symbol name"))
	}
	stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(name))
})
View Source
var EmvalNewObject = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	e := MustGetEngineFromContext(ctx, mod).(*engine)
	stack[0] = api.EncodeI32(e.emvalEngine.toHandle(map[string]any{}))
})
View Source
var EmvalNewU16string = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalNewU16string call unimplemented")
})
View Source
var EmvalNewU8string = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalNewU8string call unimplemented")
})
View Source
var EmvalNot = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalNot call unimplemented")
})
View Source
var EmvalRegisterSymbol = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	address := uint32(api.DecodeI32(stack[0]))
	name, err := engine.readCString(address)
	if err != nil {
		panic(fmt.Errorf("could not get symbol name"))
	}
	engine.emvalEngine.symbols[address] = name
})
View Source
var EmvalRunDestructors = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	id := api.DecodeI32(stack[0])

	if id == 0 {
		return
	}

	destructorsVal, err := engine.emvalEngine.toValue(id)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	destructors := destructorsVal.(*[]*destructorFunc)

	err = engine.runDestructors(ctx, *destructors)
	if err != nil {
		panic(fmt.Errorf("could not run destructors: %w", err))
	}

	err = engine.emvalEngine.allocator.decref(id)
	if err != nil {
		panic(fmt.Errorf("could not run decref id %d: %w", id, err))
	}
})
View Source
var EmvalSetProperty = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	id := api.DecodeI32(stack[0])
	handle, err := engine.emvalEngine.toValue(id)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	key, err := engine.emvalEngine.toValue(api.DecodeI32(stack[1]))
	if err != nil {
		panic(fmt.Errorf("could not find key: %w", err))
	}

	val, err := engine.emvalEngine.toValue(api.DecodeI32(stack[2]))
	if err != nil {
		panic(fmt.Errorf("could not find val: %w", err))
	}

	keyInt, ok := key.(int32)
	if ok {
		arrayHandle, isAnyArray := handle.([]any)
		if !isAnyArray {
			panic(fmt.Errorf("could not set property on emval %T: %w", handle, errors.New("key is of type int32 but handle is not an array")))
		}

		if keyInt >= int32(len(arrayHandle)) {
			newArray := make([]any, keyInt+1)
			copy(newArray, arrayHandle)
			arrayHandle = newArray
		}

		arrayHandle[keyInt] = val
		engine.emvalEngine.allocator.allocated[id].value = arrayHandle
		return
	}

	keyString, ok := key.(string)
	if !ok {
		panic(fmt.Errorf("could not set property on emval %T: %w", handle, errors.New("key is not of type string")))
	}

	handleMap, isMap := handle.(map[string]any)
	if isMap {
		handleMap[keyString] = val
		engine.emvalEngine.allocator.allocated[id].value = handleMap
		return
	}

	f, err := engine.emvalEngine.getElemField(handle, keyString)
	if err != nil {
		panic(fmt.Errorf("could not set property %s on emval %T: %w", keyString, handle, err))
	}

	defer func() {
		if err := recover(); err != nil {
			realError, ok := err.(error)
			if ok {
				panic(fmt.Errorf("could not set property %s on emval %T: %w", keyString, handle, realError))
			}
			panic(fmt.Errorf("could not set property %s on emval %T: %v", keyString, handle, err))
		}
	}()

	f.Set(reflect.ValueOf(val))
})
View Source
var EmvalStrictlyEquals = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	id1 := api.DecodeI32(stack[0])
	first, err := engine.emvalEngine.toValue(id1)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	id2 := api.DecodeI32(stack[1])
	second, err := engine.emvalEngine.toValue(id2)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	ret := int32(0)
	if first == second {
		ret = 1
	}

	stack[0] = api.EncodeI32(ret)
})
View Source
var EmvalTakeValue = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	rawType := api.DecodeI32(stack[0])

	registeredType, ok := engine.registeredTypes[rawType]
	if !ok {
		typeName, err := engine.getTypeName(ctx, rawType)
		if err != nil {
			panic(err)
		}
		panic(fmt.Errorf("_emval_take_value has unknown type %s", typeName))
	}

	arg := api.DecodeI32(stack[1])
	value, err := registeredType.ReadValueFromPointer(ctx, mod, uint32(arg))
	if err != nil {
		panic(fmt.Errorf("could not take value for _emval_take_value: %w", err))
	}

	id := engine.emvalEngine.toHandle(value)
	stack[0] = api.EncodeI32(id)
})
View Source
var EmvalThrow = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {

	panic("EmvalThrow call unimplemented")
})
View Source
var EmvalTypeof = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	id := api.DecodeI32(stack[0])
	handle, err := engine.emvalEngine.toValue(id)
	if err != nil {
		panic(fmt.Errorf("could not find handle: %w", err))
	}

	typeOf := "object"

	if handle != nil {
		reflectTypeOf := reflect.TypeOf(handle)
		switch reflectTypeOf.Kind() {
		case reflect.Func:
			typeOf = "function"
		case reflect.String:
			typeOf = "string"
		case reflect.Bool:
			typeOf = "boolean"
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
			reflect.Uintptr, reflect.Float32, reflect.Float64:
			typeOf = "number"
		case reflect.Int64, reflect.Uint64:
			typeOf = "bigint"
		}

		if handle == types.Undefined {
			typeOf = "undefined"
		}
	}

	stack[0] = api.EncodeI32(engine.emvalEngine.toHandle(typeOf))
})
View Source
var FinalizeValueArray = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	rawTupleType := api.DecodeI32(stack[0])
	reg := engine.registeredTuples[rawTupleType]
	delete(engine.registeredTuples, rawTupleType)
	elements := reg.elements
	elementsLength := len(elements)

	elementTypes := make([]int32, len(elements)*2)
	for i := range elements {
		elementTypes[i] = elements[i].getterReturnType
		elementTypes[i+len(elements)] = elements[i].setterArgumentType
	}

	err := engine.whenDependentTypesAreResolved([]int32{rawTupleType}, elementTypes, func(types []registeredType) ([]registeredType, error) {
		for i := range elements {
			element := elements[i]
			getterReturnType := types[i]

			getterFunc, err := engine.newInvokeFunc(element.getterSignature, element.getter, []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{getterReturnType.NativeType()})
			if err != nil {
				return nil, fmt.Errorf("could not create getterFunc: %w", err)
			}

			setterArgumentType := types[i+len(elements)]
			setterFunc, err := engine.newInvokeFunc(element.setterSignature, element.setter, []api.ValueType{api.ValueTypeI32, api.ValueTypeI32, setterArgumentType.NativeType()}, []api.ValueType{})
			if err != nil {
				return nil, fmt.Errorf("could not create setterFunc: %w", err)
			}

			element.read = func(ctx context.Context, mod api.Module, ptr int32) (any, error) {
				res, err := getterFunc.Call(ctx, api.EncodeI32(element.getterContext), api.EncodeI32(ptr))
				if err != nil {
					return nil, err
				}
				return getterReturnType.FromWireType(ctx, mod, res[0])
			}
			element.write = func(ctx context.Context, mod api.Module, ptr int32, o any) error {
				destructors := &[]*destructorFunc{}
				res, err := setterArgumentType.ToWireType(ctx, mod, destructors, o)
				if err != nil {
					return err
				}

				_, err = setterFunc.Call(ctx, api.EncodeI32(element.setterContext), api.EncodeI32(ptr), res)
				if err != nil {
					return err
				}

				err = engine.runDestructors(ctx, *destructors)
				if err != nil {
					return err
				}

				return nil
			}
		}

		return []registeredType{
			&arrayType{
				baseType: baseType{
					rawType:        rawTupleType,
					name:           reg.name,
					argPackAdvance: GenericWireTypeSize,
				},
				reg:            reg,
				elementsLength: elementsLength,
			},
		}, nil
	})
	if err != nil {
		panic(fmt.Errorf("could not call whenDependentTypesAreResolved: %w", err))
	}
})
View Source
var FinalizeValueObject = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	structType := api.DecodeI32(stack[0])
	reg := engine.registeredObjects[structType]
	delete(engine.registeredObjects, structType)
	fieldRecords := reg.fields

	fieldTypes := make([]int32, len(fieldRecords)*2)
	for i := range fieldRecords {
		fieldTypes[i] = fieldRecords[i].getterReturnType
		fieldTypes[i+len(fieldRecords)] = fieldRecords[i].setterArgumentType
	}

	err := engine.whenDependentTypesAreResolved([]int32{structType}, fieldTypes, func(types []registeredType) ([]registeredType, error) {
		for i := range fieldRecords {
			fieldRecord := fieldRecords[i]
			getterReturnType := types[i]
			getterFunc, err := engine.newInvokeFunc(fieldRecord.getterSignature, fieldRecord.getter, []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{getterReturnType.NativeType()})
			if err != nil {
				panic(fmt.Errorf("could not create getterFunc: %w", err))
			}

			fieldRecord.read = func(ctx context.Context, mod api.Module, ptr int32) (any, error) {
				res, err := getterFunc.Call(ctx, api.EncodeI32(fieldRecord.getterContext), api.EncodeI32(ptr))
				if err != nil {
					return nil, err
				}
				return getterReturnType.FromWireType(ctx, mod, res[0])
			}

			setterArgumentType := types[i+len(fieldRecords)]
			setterFunc, err := engine.newInvokeFunc(fieldRecord.setterSignature, fieldRecord.setter, []api.ValueType{api.ValueTypeI32, api.ValueTypeI32, setterArgumentType.NativeType()}, []api.ValueType{})
			if err != nil {
				panic(fmt.Errorf("could not create setterFunc: %w", err))
			}

			fieldRecord.write = func(ctx context.Context, mod api.Module, ptr int32, o any) error {
				destructors := &[]*destructorFunc{}
				res, err := setterArgumentType.ToWireType(ctx, mod, destructors, o)
				if err != nil {
					return err
				}

				_, err = setterFunc.Call(ctx, api.EncodeI32(fieldRecord.setterContext), api.EncodeI32(ptr), res)
				if err != nil {
					return err
				}

				err = engine.runDestructors(ctx, *destructors)
				if err != nil {
					return err
				}

				return nil
			}
		}

		return []registeredType{
			&objectType{
				baseType: baseType{
					rawType:        structType,
					name:           reg.name,
					argPackAdvance: GenericWireTypeSize,
				},
				reg: reg,
			},
		}, nil
	})
	if err != nil {
		panic(fmt.Errorf("could not call whenDependentTypesAreResolved: %w", err))
	}
})
View Source
var RegisterBigInt = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	rawType := api.DecodeI32(stack[0])
	name, err := engine.readCString(uint32(api.DecodeI32(stack[1])))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	err = engine.registerType(rawType, &bigintType{
		baseType: baseType{
			rawType:        rawType,
			name:           name,
			argPackAdvance: GenericWireTypeSize,
		},
		size:   api.DecodeI32(stack[2]),
		signed: !strings.HasPrefix(name, "u"),
	}, nil)
	if err != nil {
		panic(fmt.Errorf("could not register: %w", err))
	}
})
View Source
var RegisterBool = func(hasSize bool) api.GoModuleFunc {
	return api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
		engine := MustGetEngineFromContext(ctx, mod).(*engine)

		rawType := api.DecodeI32(stack[0])

		name, err := engine.readCString(uint32(api.DecodeI32(stack[1])))
		if err != nil {
			panic(fmt.Errorf("could not read name: %w", err))
		}

		var size, trueVal, falseVal int32

		if hasSize {
			size = api.DecodeI32(stack[2])
			trueVal = api.DecodeI32(stack[3])
			falseVal = api.DecodeI32(stack[4])
		} else {
			size = int32(1)
			trueVal = api.DecodeI32(stack[2])
			falseVal = api.DecodeI32(stack[3])
		}

		err = engine.registerType(rawType, &boolType{
			baseType: baseType{
				rawType:        rawType,
				name:           name,
				argPackAdvance: GenericWireTypeSize,
			},
			size:     size,
			trueVal:  trueVal,
			falseVal: falseVal,
		}, nil)
		if err != nil {
			panic(fmt.Errorf("could not register: %w", err))
		}
	})
}
View Source
var RegisterClass = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	rawType := api.DecodeI32(stack[0])
	rawPointerType := api.DecodeI32(stack[1])
	rawConstPointerType := api.DecodeI32(stack[2])
	baseClassRawType := api.DecodeI32(stack[3])
	getActualTypeSignature := api.DecodeI32(stack[4])
	getActualType := api.DecodeI32(stack[5])
	upcastSignature := api.DecodeI32(stack[6])
	upcast := api.DecodeI32(stack[7])
	downcastSignature := api.DecodeI32(stack[8])
	downcast := api.DecodeI32(stack[9])
	namePtr := api.DecodeI32(stack[10])
	destructorSignature := api.DecodeI32(stack[11])
	rawDestructor := api.DecodeI32(stack[12])

	name, err := engine.readCString(uint32(namePtr))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	getActualTypeFunc, err := engine.newInvokeFunc(getActualTypeSignature, getActualType, []api.ValueType{api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32})
	if err != nil {
		panic(fmt.Errorf("could not read getActualType: %w", err))
	}

	var upcastFunc api.Function
	if upcast > 0 {
		upcastFunc, err = engine.newInvokeFunc(upcastSignature, upcast, []api.ValueType{api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32})
		if err != nil {
			panic(fmt.Errorf("could not read upcast: %w", err))
		}
	}

	var downcastFunc api.Function
	if downcast > 0 {
		downcastFunc, err = engine.newInvokeFunc(downcastSignature, downcast, []api.ValueType{api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32})
		if err != nil {
			panic(fmt.Errorf("could not read downcast: %w", err))
		}
	}

	rawDestructorFunc, err := engine.newInvokeFunc(destructorSignature, rawDestructor, []api.ValueType{api.ValueTypeI32}, []api.ValueType{})
	if err != nil {
		panic(fmt.Errorf("could not read rawDestructor: %w", err))
	}

	legalFunctionName := engine.makeLegalFunctionName(name)

	err = engine.exposePublicSymbol(legalFunctionName, func(ctx context.Context, this any, arguments ...any) (any, error) {
		return nil, engine.createUnboundTypeError(ctx, fmt.Sprintf("Cannot call %s due to unbound types", name), []int32{baseClassRawType})
	}, nil)
	if err != nil {
		panic(fmt.Errorf("could not expose public symbol: %w", err))
	}

	dependentTypes := make([]int32, 0)
	if baseClassRawType > 0 {
		dependentTypes = append(dependentTypes, baseClassRawType)
	}

	err = engine.whenDependentTypesAreResolved([]int32{rawType, rawPointerType, rawConstPointerType}, dependentTypes, func(resolvedTypes []registeredType) ([]registeredType, error) {
		existingClass, ok := engine.registeredClasses[name]
		if ok {
			if existingClass.baseType.rawType != 0 {
				return nil, fmt.Errorf("could not register class %s, already registered as raw type %d", name, existingClass.baseType.rawType)
			}
		} else {
			engine.registeredClasses[name] = &classType{
				baseType: baseType{
					rawType: rawType,
					name:    name,
				},
				pureVirtualFunctions: []string{},
				methods:              map[string]*publicSymbol{},
				properties:           map[string]*classProperty{},
			}
		}

		engine.registeredClasses[name].hasCppClass = true
		engine.registeredClasses[name].legalFunctionName = legalFunctionName
		engine.registeredClasses[name].rawDestructor = rawDestructorFunc
		engine.registeredClasses[name].getActualType = getActualTypeFunc
		engine.registeredClasses[name].upcast = upcastFunc
		engine.registeredClasses[name].downcast = downcastFunc

		if baseClassRawType > 0 {
			engine.registeredClasses[name].baseClass = resolvedTypes[0].(*registeredPointerType).registeredClass
			if engine.registeredClasses[name].baseClass.derivedClasses == nil {
				engine.registeredClasses[name].baseClass.derivedClasses = []*classType{engine.registeredClasses[name]}
			} else {
				engine.registeredClasses[name].baseClass.derivedClasses = append(engine.registeredClasses[name].baseClass.derivedClasses, engine.registeredClasses[name])
			}
		}

		referenceConverter := &registeredPointerType{
			baseType: baseType{
				argPackAdvance: GenericWireTypeSize,
				name:           name,
			},
			registeredClass: engine.registeredClasses[name],
			isReference:     true,
			isConst:         false,
			isSmartPointer:  false,
		}

		pointerConverter := &registeredPointerType{
			baseType: baseType{
				argPackAdvance: GenericWireTypeSize,
				name:           name + "*",
			},
			registeredClass: engine.registeredClasses[name],
			isReference:     false,
			isConst:         false,
			isSmartPointer:  false,
		}

		constPointerConverter := &registeredPointerType{
			baseType: baseType{
				argPackAdvance: GenericWireTypeSize,
				name:           name + " const*",
			},
			registeredClass: engine.registeredClasses[name],
			isReference:     false,
			isConst:         true,
			isSmartPointer:  false,
		}

		engine.registeredPointers[rawType] = &registeredPointer{
			pointerType:      pointerConverter,
			constPointerType: constPointerConverter,
		}

		err := engine.registeredClasses[name].validate()
		if err != nil {
			return nil, err
		}

		err = engine.replacePublicSymbol(legalFunctionName, func(ctx context.Context, _ any, arguments ...any) (any, error) {
			if engine.registeredClasses[name].constructors == nil {
				return nil, fmt.Errorf("%s has no accessible constructor", name)
			}

			constructor, ok := engine.registeredClasses[name].constructors[int32(len(arguments))]
			if !ok {
				availableLengths := make([]string, 0)
				for i := range engine.registeredClasses[name].constructors {
					availableLengths = append(availableLengths, strconv.Itoa(int(i)))
				}
				sort.Strings(availableLengths)
				return nil, fmt.Errorf("tried to invoke ctor of %s with invalid number of parameters (%d) - expected (%s) parameters instead", name, len(arguments), strings.Join(availableLengths, " or "))
			}

			return constructor.fn(ctx, nil, arguments...)
		}, nil, nil, referenceConverter)

		if err != nil {
			panic(fmt.Errorf("could not replace public symbol: %w", err))
		}

		return []registeredType{referenceConverter, pointerConverter, constPointerConverter}, nil
	})

	if err != nil {
		panic(fmt.Errorf("could not call whenDependentTypesAreResolved: %w", err))
	}
})
View Source
var RegisterClassClassFunction = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	rawClassType := api.DecodeI32(stack[0])
	methodNamePtr := api.DecodeI32(stack[1])
	argCount := api.DecodeI32(stack[2])
	rawArgTypesAddr := api.DecodeI32(stack[3])
	invokerSignature := api.DecodeI32(stack[4])
	rawInvoker := api.DecodeI32(stack[5])
	fn := api.DecodeI32(stack[6])
	isAsync := api.DecodeI32(stack[7])

	rawArgTypes, err := engine.heap32VectorToArray(argCount, rawArgTypesAddr)
	if err != nil {
		panic(fmt.Errorf("could not read arg types: %w", err))
	}

	methodName, err := engine.readCString(uint32(methodNamePtr))
	if err != nil {
		panic(fmt.Errorf("could not read method name: %w", err))
	}

	methodName, err = getFunctionName(methodName)
	if err != nil {
		panic(fmt.Errorf("could not read method name: %w", err))
	}

	err = engine.whenDependentTypesAreResolved([]int32{}, []int32{rawClassType}, func(classTypes []registeredType) ([]registeredType, error) {
		classType := classTypes[0].(*registeredPointerType)
		humanName := classType.Name() + "." + methodName

		if strings.HasPrefix(methodName, "@@") {
			return nil, fmt.Errorf("could not get class function name %s: well-known symbols are not supported in Go", methodName)
		}

		unboundTypesHandler := &publicSymbol{
			name:     methodName,
			isStatic: true,
			fn: func(ctx context.Context, this any, arguments ...any) (any, error) {
				return nil, engine.createUnboundTypeError(ctx, fmt.Sprintf("Cannot call %s due to unbound types", humanName), rawArgTypes)
			},
			argumentTypes: createAnyTypeArray(argCount - 1),
			resultType:    &anyType{},
		}

		newArgCount := argCount - 1
		_, ok := classType.registeredClass.methods[methodName]
		if !ok {

			unboundTypesHandler.argCount = &newArgCount
			classType.registeredClass.methods[methodName] = unboundTypesHandler
		} else {

			engine.ensureOverloadTable(classType.registeredClass.methods, methodName, humanName)
			classType.registeredClass.methods[methodName].overloadTable[argCount-1] = unboundTypesHandler
		}

		err = engine.whenDependentTypesAreResolved([]int32{}, rawArgTypes, func(argTypes []registeredType) ([]registeredType, error) {
			invokerArgsArray := []registeredType{argTypes[0], nil}
			invokerArgsArray = append(invokerArgsArray, argTypes[1:]...)

			expectedParamTypes := make([]api.ValueType, len(invokerArgsArray[2:])+1)
			expectedParamTypes[0] = api.ValueTypeI32
			for i := range invokerArgsArray[2:] {
				expectedParamTypes[i+1] = invokerArgsArray[i+2].NativeType()
			}

			rawInvokerFunc, err := engine.newInvokeFunc(invokerSignature, rawInvoker, expectedParamTypes, []api.ValueType{argTypes[0].NativeType()})
			if err != nil {
				panic(fmt.Errorf("could not create raw invoke func: %w", err))
			}

			fn := engine.craftInvokerFunction(humanName, invokerArgsArray, nil, rawInvokerFunc, fn, isAsync > 0)
			memberFunction := &publicSymbol{
				name:          methodName,
				argumentTypes: argTypes[1:],
				resultType:    argTypes[0],
				isStatic:      true,
				fn:            fn,
			}

			if classType.registeredClass.methods[methodName].overloadTable == nil {

				memberFunction.argCount = &newArgCount
				classType.registeredClass.methods[methodName] = memberFunction
			} else {
				memberFunction.isOverload = true
				classType.registeredClass.methods[methodName].overloadTable[argCount-1] = memberFunction
			}

			derivesClasses := classType.registeredClass.getDerivedClassesRecursive()
			if derivesClasses != nil {
				for i := range derivesClasses {
					derivedMemberFunction := &publicSymbol{
						name:          methodName,
						argumentTypes: argTypes[1:],
						resultType:    argTypes[0],
						isStatic:      true,
						fn:            fn,
					}

					derivedClass := derivesClasses[i]
					_, ok := derivedClass.methods[methodName]
					if !ok {

						derivedMemberFunction.argCount = &newArgCount
						derivedClass.methods[methodName] = derivedMemberFunction
					} else {

						engine.ensureOverloadTable(derivedClass.methods, methodName, humanName)
						derivedMemberFunction.isOverload = true

						_, ok := derivedClass.methods[methodName].overloadTable[argCount-1]
						if !ok {
							derivedClass.methods[methodName].overloadTable[argCount-1] = derivedMemberFunction
						}
					}
				}
			}

			return []registeredType{}, nil
		})

		return []registeredType{}, err
	})
	if err != nil {
		panic(fmt.Errorf("could not call whenDependentTypesAreResolved: %w", err))
	}
})
View Source
var RegisterClassClassProperty = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	rawClassType := api.DecodeI32(stack[0])
	fieldNamePtr := api.DecodeI32(stack[1])
	rawFieldType := api.DecodeI32(stack[2])
	rawFieldPtr := api.DecodeI32(stack[3])
	getterSignaturePtr := api.DecodeI32(stack[4])
	getter := api.DecodeI32(stack[5])
	setterSignaturePtr := api.DecodeI32(stack[6])
	setter := api.DecodeI32(stack[7])

	fieldName, err := engine.readCString(uint32(fieldNamePtr))
	if err != nil {
		panic(fmt.Errorf("could not read method name: %w", err))
	}

	getterFunc, err := engine.newInvokeFunc(getterSignaturePtr, getter, []api.ValueType{api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32})
	if err != nil {
		panic(fmt.Errorf("could not read getter: %w", err))
	}

	err = engine.whenDependentTypesAreResolved([]int32{}, []int32{rawClassType}, func(classTypes []registeredType) ([]registeredType, error) {
		classType := classTypes[0].(*registeredPointerType)

		humanName := classType.Name() + "." + fieldName

		desc := &classProperty{
			name:     fieldName,
			isStatic: true,
			get: func(ctx context.Context, this any) (any, error) {
				return nil, engine.createUnboundTypeError(ctx, fmt.Sprintf("Cannot access %s due to unbound types", humanName), []int32{rawFieldType})
			},
			getterType:   &anyType{},
			enumerable:   true,
			configurable: true,
		}

		if setter > 0 {
			desc.setterType = &anyType{}
			desc.set = func(ctx context.Context, this any, v any) error {
				return engine.createUnboundTypeError(ctx, fmt.Sprintf("Cannot access %s due to unbound types", humanName), []int32{rawFieldType})
			}
		} else {
			desc.readOnly = true
			desc.set = func(ctx context.Context, this any, v any) error {
				return fmt.Errorf("%s is a read-only property", humanName)
			}
		}

		classType.registeredClass.properties[fieldName] = desc
		err = engine.whenDependentTypesAreResolved([]int32{}, []int32{rawFieldType}, func(fieldTypes []registeredType) ([]registeredType, error) {
			fieldType := fieldTypes[0]

			desc := &classProperty{
				name:       fieldName,
				getterType: fieldType,
				isStatic:   true,
				get: func(ctx context.Context, this any) (any, error) {
					res, err := getterFunc.Call(ctx, api.EncodeI32(rawFieldPtr))
					if err != nil {
						return nil, err
					}
					return fieldType.FromWireType(ctx, engine.mod, res[0])
				},
				enumerable: true,
				readOnly:   true,
			}

			if setter > 0 {
				setterFunc, err := engine.newInvokeFunc(setterSignaturePtr, setter, []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{})
				if err != nil {
					return nil, fmt.Errorf("could not create _embind_register_class_class_property setterFunc: %w", err)
				}

				desc.readOnly = false
				desc.setterType = fieldType
				desc.set = func(ctx context.Context, this any, v any) error {
					destructors := &[]*destructorFunc{}
					setterRes, err := fieldType.ToWireType(ctx, engine.mod, destructors, v)
					if err != nil {
						return err
					}

					_, err = setterFunc.Call(ctx, api.EncodeI32(rawFieldPtr), setterRes)
					if err != nil {
						return err
					}

					err = engine.runDestructors(ctx, *destructors)
					if err != nil {
						return err
					}

					return nil
				}
			}

			classType.registeredClass.properties[fieldName] = desc

			derivesClasses := classType.registeredClass.getDerivedClassesRecursive()
			if derivesClasses != nil {
				for i := range derivesClasses {
					derivedClass := derivesClasses[i]

					_, ok := derivedClass.properties[fieldName]
					if !ok {
						derivedClass.properties[fieldName] = desc
					}
				}
			}

			return []registeredType{}, err
		})
		return []registeredType{}, err
	})

	if err != nil {
		panic(fmt.Errorf("could not call whenDependentTypesAreResolved: %w", err))
	}
})
View Source
var RegisterClassConstructor = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	rawClassType := api.DecodeI32(stack[0])
	argCount := api.DecodeI32(stack[1])
	rawArgTypesAddr := api.DecodeI32(stack[2])
	invokerSignature := api.DecodeI32(stack[3])
	invoker := api.DecodeI32(stack[4])
	rawConstructor := api.DecodeI32(stack[5])

	rawArgTypes, err := engine.heap32VectorToArray(argCount, rawArgTypesAddr)
	if err != nil {
		panic(fmt.Errorf("could not read arg types: %w", err))
	}

	err = engine.whenDependentTypesAreResolved([]int32{}, []int32{rawClassType}, func(resolvedTypes []registeredType) ([]registeredType, error) {
		classType := resolvedTypes[0].(*registeredPointerType)
		humanName := "constructor " + classType.name

		if classType.registeredClass.constructors == nil {
			classType.registeredClass.constructors = map[int32]*classConstructor{}
		}

		if _, ok := classType.registeredClass.constructors[argCount-1]; ok {
			return nil, fmt.Errorf("cannot register multiple constructors with identical number of parameters (%d) for class '%s'! Overload resolution is currently only performed using the parameter count, not actual type info", argCount-1, classType.name)
		}

		classType.registeredClass.constructors[argCount-1] = &classConstructor{
			fn: func(ctx context.Context, this any, arguments ...any) (any, error) {
				return nil, engine.createUnboundTypeError(ctx, fmt.Sprintf("Cannot call %s due to unbound types", classType.name), rawArgTypes)
			},
			argumentTypes: createAnyTypeArray(argCount - 1),
			resultType:    &anyType{},
		}

		err := engine.whenDependentTypesAreResolved([]int32{}, rawArgTypes, func(argTypes []registeredType) ([]registeredType, error) {

			newArgTypes := []registeredType{argTypes[0], nil}
			if len(argTypes) > 1 {
				newArgTypes = append(newArgTypes, argTypes[1:]...)
			}

			expectedParamTypes := make([]api.ValueType, len(newArgTypes[2:])+1)
			expectedParamTypes[0] = api.ValueTypeI32
			for i := range newArgTypes[2:] {
				expectedParamTypes[i+1] = newArgTypes[i+2].NativeType()
			}

			invokerFunc, err := engine.newInvokeFunc(invokerSignature, invoker, expectedParamTypes, []api.ValueType{argTypes[0].NativeType()})
			if err != nil {
				return nil, fmt.Errorf("could not create invoke func: %w", err)
			}

			classType.registeredClass.constructors[argCount-1].resultType = argTypes[0]
			classType.registeredClass.constructors[argCount-1].argumentTypes = argTypes[1:]
			classType.registeredClass.constructors[argCount-1].fn = engine.craftInvokerFunction(humanName, newArgTypes, nil, invokerFunc, rawConstructor, false)
			return []registeredType{}, err
		})

		return []registeredType{}, err
	})

	if err != nil {
		panic(fmt.Errorf("could not call whenDependentTypesAreResolved: %w", err))
	}
})
View Source
var RegisterClassFunction = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	rawClassType := api.DecodeI32(stack[0])
	methodNamePtr := api.DecodeI32(stack[1])
	argCount := api.DecodeI32(stack[2])
	rawArgTypesAddr := api.DecodeI32(stack[3])
	invokerSignature := api.DecodeI32(stack[4])
	rawInvoker := api.DecodeI32(stack[5])
	contextPtr := api.DecodeI32(stack[6])
	isPureVirtual := api.DecodeI32(stack[7])
	isAsync := api.DecodeI32(stack[8])

	rawArgTypes, err := engine.heap32VectorToArray(argCount, rawArgTypesAddr)
	if err != nil {
		panic(fmt.Errorf("could not read arg types: %w", err))
	}

	methodName, err := engine.readCString(uint32(methodNamePtr))
	if err != nil {
		panic(fmt.Errorf("could not read method name: %w", err))
	}

	methodName, err = getFunctionName(methodName)
	if err != nil {
		panic(fmt.Errorf("could not read method name: %w", err))
	}

	err = engine.whenDependentTypesAreResolved([]int32{}, []int32{rawClassType}, func(classTypes []registeredType) ([]registeredType, error) {
		classType := classTypes[0].(*registeredPointerType)
		humanName := classType.Name() + "." + methodName

		if strings.HasPrefix(methodName, "@@") {
			return nil, fmt.Errorf("could not get function name %s: well-known symbols are not supported in Go", methodName)
		}

		if isPureVirtual > 0 {
			classType.registeredClass.pureVirtualFunctions = append(classType.registeredClass.pureVirtualFunctions, methodName)
		}

		unboundTypesHandler := &publicSymbol{
			name: methodName,
			fn: func(ctx context.Context, this any, arguments ...any) (any, error) {
				return nil, engine.createUnboundTypeError(ctx, fmt.Sprintf("Cannot call %s due to unbound types", humanName), rawArgTypes)
			},
			argumentTypes: createAnyTypeArray(argCount - 2),
			resultType:    &anyType{},
		}

		newMethodArgCount := argCount - 2
		existingMethod, ok := classType.registeredClass.methods[methodName]
		if !ok || (existingMethod.overloadTable == nil && existingMethod.className != classType.name && *existingMethod.argCount == newMethodArgCount) {

			unboundTypesHandler.argCount = &newMethodArgCount
			unboundTypesHandler.className = classType.name
			unboundTypesHandler.isOverload = true
			classType.registeredClass.methods[methodName] = unboundTypesHandler
		} else {

			engine.ensureOverloadTable(classType.registeredClass.methods, methodName, humanName)
			classType.registeredClass.methods[methodName].overloadTable[argCount-2] = unboundTypesHandler
		}

		err = engine.whenDependentTypesAreResolved([]int32{}, rawArgTypes, func(argTypes []registeredType) ([]registeredType, error) {
			expectedResultTypes := make([]api.ValueType, len(argTypes))
			expectedResultTypes[0] = api.ValueTypeI32
			for i := range argTypes[1:] {
				expectedResultTypes[i+1] = argTypes[i+1].NativeType()
			}

			rawInvokerFunc, err := engine.newInvokeFunc(invokerSignature, rawInvoker, expectedResultTypes, []api.ValueType{argTypes[0].NativeType()})
			if err != nil {
				panic(fmt.Errorf("could not create _embind_register_class_function raw invoke func: %w", err))
			}

			fn := engine.craftInvokerFunction(humanName, argTypes, classType, rawInvokerFunc, contextPtr, isAsync > 0)

			memberFunction := &publicSymbol{
				name:          methodName,
				resultType:    argTypes[0],
				argumentTypes: argTypes[2:],
				fn:            fn,
			}

			if classType.registeredClass.methods[methodName].overloadTable == nil {

				memberFunction.argCount = &newMethodArgCount
				classType.registeredClass.methods[methodName] = memberFunction
			} else {
				memberFunction.isOverload = true
				classType.registeredClass.methods[methodName].overloadTable[argCount-2] = memberFunction
			}

			derivesClasses := classType.registeredClass.getDerivedClassesRecursive()
			if derivesClasses != nil {
				for i := range derivesClasses {
					derivedMemberFunction := &publicSymbol{
						name:          methodName,
						resultType:    argTypes[0],
						argumentTypes: argTypes[2:],
						fn:            fn,
					}

					derivedClass := derivesClasses[i]
					_, ok := derivedClass.methods[methodName]
					if !ok {
						derivedMemberFunction.argCount = &newMethodArgCount

						derivedClass.methods[methodName] = derivedMemberFunction
					} else {

						engine.ensureOverloadTable(derivedClass.methods, methodName, humanName)
						derivedMemberFunction.isOverload = true

						_, ok := derivedClass.methods[methodName].overloadTable[argCount-2]
						if !ok {
							derivedClass.methods[methodName].overloadTable[argCount-2] = derivedMemberFunction
						}
					}
				}
			}

			return []registeredType{}, nil
		})

		return []registeredType{}, err
	})

	if err != nil {
		panic(fmt.Errorf("could not call whenDependentTypesAreResolved: %w", err))
	}
})
View Source
var RegisterClassProperty = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	classType := api.DecodeI32(stack[0])
	fieldNamePtr := api.DecodeI32(stack[1])
	getterReturnType := api.DecodeI32(stack[2])
	getterSignature := api.DecodeI32(stack[3])
	getter := api.DecodeI32(stack[4])
	getterContext := api.DecodeI32(stack[5])
	setterArgumentType := api.DecodeI32(stack[6])
	setterSignature := api.DecodeI32(stack[7])
	setter := api.DecodeI32(stack[8])
	setterContext := api.DecodeI32(stack[9])

	fieldName, err := engine.readCString(uint32(fieldNamePtr))
	if err != nil {
		panic(fmt.Errorf("could not read method name: %w", err))
	}

	err = engine.whenDependentTypesAreResolved([]int32{}, []int32{classType}, func(classTypes []registeredType) ([]registeredType, error) {
		classType := classTypes[0].(*registeredPointerType)
		humanName := classType.Name() + "." + fieldName

		desc := &classProperty{
			name: fieldName,
			get: func(ctx context.Context, this any) (any, error) {
				return nil, engine.createUnboundTypeError(ctx, fmt.Sprintf("Cannot access %s due to unbound types", humanName), []int32{getterReturnType, setterArgumentType})
			},
			getterType:   &anyType{},
			enumerable:   true,
			configurable: true,
		}

		if setter > 0 {
			desc.setterType = &anyType{}
			desc.set = func(ctx context.Context, this any, v any) error {
				return engine.createUnboundTypeError(ctx, fmt.Sprintf("Cannot access %s due to unbound types", humanName), []int32{getterReturnType, setterArgumentType})
			}
		} else {
			desc.readOnly = true
			desc.set = func(ctx context.Context, this any, v any) error {
				return fmt.Errorf("%s is a read-only property", humanName)
			}
		}

		classType.registeredClass.properties[fieldName] = desc

		requiredTypes := []int32{getterReturnType}
		if setter > 0 {
			requiredTypes = append(requiredTypes, setterArgumentType)
		}

		err = engine.whenDependentTypesAreResolved([]int32{}, requiredTypes, func(types []registeredType) ([]registeredType, error) {
			getterReturnType := types[0]

			getterFunc, err := engine.newInvokeFunc(getterSignature, getter, []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{getterReturnType.NativeType()})
			if err != nil {
				return nil, fmt.Errorf("could not create _embind_register_class_property getterFunc: %w", err)
			}

			desc := &classProperty{
				name:       fieldName,
				getterType: getterReturnType,
				get: func(ctx context.Context, this any) (any, error) {
					ptr, err := engine.validateThis(ctx, this, classType, humanName+" getter")
					if err != nil {
						return nil, err
					}

					res, err := getterFunc.Call(ctx, api.EncodeI32(getterContext), api.EncodeU32(ptr))
					if err != nil {
						return nil, err
					}
					return getterReturnType.FromWireType(ctx, engine.mod, res[0])
				},
				enumerable: true,
				readOnly:   true,
			}

			if setter > 0 {
				setterArgumentType := types[1]
				setterFunc, err := engine.newInvokeFunc(setterSignature, setter, []api.ValueType{api.ValueTypeI32, api.ValueTypeI32, setterArgumentType.NativeType()}, []api.ValueType{})
				if err != nil {
					return nil, fmt.Errorf("could not create _embind_register_class_property setterFunc: %w", err)
				}

				desc.readOnly = false
				desc.setterType = setterArgumentType
				desc.set = func(ctx context.Context, this any, v any) error {
					ptr, err := engine.validateThis(ctx, this, classType, humanName+" setter")
					if err != nil {
						return err
					}

					destructors := &[]*destructorFunc{}
					setterRes, err := setterArgumentType.ToWireType(ctx, engine.mod, destructors, v)
					if err != nil {
						return err
					}

					_, err = setterFunc.Call(ctx, api.EncodeI32(setterContext), api.EncodeU32(ptr), setterRes)
					if err != nil {
						return err
					}

					err = engine.runDestructors(ctx, *destructors)
					if err != nil {
						return err
					}

					return nil
				}
			}

			classType.registeredClass.properties[fieldName] = desc

			derivesClasses := classType.registeredClass.getDerivedClassesRecursive()
			if derivesClasses != nil {
				for i := range derivesClasses {
					derivedClass := derivesClasses[i]

					_, ok := derivedClass.properties[fieldName]
					if !ok {
						derivedClass.properties[fieldName] = desc
					}
				}
			}

			return []registeredType{}, err
		})

		return []registeredType{}, err
	})
	if err != nil {
		panic(fmt.Errorf("could not call whenDependentTypesAreResolved: %w", err))
	}
})
View Source
var RegisterConstant = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	name, err := engine.readCString(uint32(api.DecodeI32(stack[0])))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	rawType := api.DecodeI32(stack[1])
	constantValue := api.DecodeF64(stack[2])

	err = engine.whenDependentTypesAreResolved([]int32{}, []int32{rawType}, func(argTypes []registeredType) ([]registeredType, error) {
		registeredType := argTypes[0]

		cppValue := registeredType.FromF64(constantValue)
		val, err := registeredType.FromWireType(ctx, engine.mod, cppValue)
		if err != nil {
			return nil, fmt.Errorf("could not initialize constant %s: %w", name, err)
		}

		_, ok := engine.registeredConstants[name]
		if !ok {
			engine.registeredConstants[name] = &registeredConstant{
				name: name,
			}
		}

		engine.registeredConstants[name].registeredType = registeredType
		engine.registeredConstants[name].hasCppValue = true
		engine.registeredConstants[name].cppValue = val
		engine.registeredConstants[name].rawCppValue = cppValue

		return nil, engine.registeredConstants[name].validate()
	})

	if err != nil {
		panic(err)
	}
})
View Source
var RegisterEmval = func(hasName bool) api.GoModuleFunc {
	return api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
		engine := MustGetEngineFromContext(ctx, mod).(*engine)

		rawType := api.DecodeI32(stack[0])

		name := "emscripten::val"
		var err error
		if hasName {
			name, err = engine.readCString(uint32(api.DecodeI32(stack[1])))
			if err != nil {
				panic(fmt.Errorf("could not read name: %w", err))
			}
		}

		err = engine.registerType(rawType, &emvalType{
			baseType: baseType{
				rawType:        rawType,
				name:           name,
				argPackAdvance: GenericWireTypeSize,
			},
		}, &registerTypeOptions{
			ignoreDuplicateRegistrations: true,
		})
		if err != nil {
			panic(fmt.Errorf("could not register: %w", err))
		}
	})
}
View Source
var RegisterEnum = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	rawType := api.DecodeI32(stack[0])
	name, err := engine.readCString(uint32(api.DecodeI32(stack[1])))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	_, ok := engine.registeredEnums[name]
	if !ok {
		engine.registeredEnums[name] = &enumType{
			valuesByName:     map[string]*enumValue{},
			valuesByCppValue: map[any]*enumValue{},
			valuesByGoValue:  map[any]*enumValue{},
		}
	}

	engine.registeredEnums[name].baseType = baseType{
		rawType:        rawType,
		name:           name,
		argPackAdvance: GenericWireTypeSize,
	}

	engine.registeredEnums[name].intHelper = intType{
		size:   api.DecodeI32(stack[2]),
		signed: api.DecodeI32(stack[3]) > 0,
	}

	err = engine.registerType(rawType, engine.registeredEnums[name], nil)
	if err != nil {
		panic(fmt.Errorf("could not register: %w", err))
	}
})
View Source
var RegisterEnumValue = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	rawType := api.DecodeI32(stack[0])
	name, err := engine.readCString(uint32(api.DecodeI32(stack[1])))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	registeredType, ok := engine.registeredTypes[rawType]
	if !ok {
		typeName, err := engine.getTypeName(ctx, rawType)
		if err != nil {
			panic(err)
		}
		panic(fmt.Errorf("%s has unknown type %s", name, typeName))
	}

	enumType := registeredType.(*enumType)
	enumWireValue, err := enumType.intHelper.FromWireType(ctx, mod, stack[2])
	if err != nil {
		panic(fmt.Errorf("could not read value for enum %s", name))
	}

	_, ok = enumType.valuesByName[name]
	if !ok {
		enumType.valuesByName[name] = &enumValue{
			name: name,
		}
	}

	if enumType.valuesByName[name].hasCppValue {
		panic(fmt.Errorf("enum value %s for enum %s was already registered", name, enumType.name))
	}

	enumType.valuesByName[name].hasCppValue = true
	enumType.valuesByName[name].cppValue = enumWireValue
	enumType.valuesByCppValue[enumWireValue] = enumType.valuesByName[name]
})
View Source
var RegisterFloat = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	rawType := api.DecodeI32(stack[0])
	name, err := engine.readCString(uint32(api.DecodeI32(stack[1])))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	err = engine.registerType(rawType, &floatType{
		baseType: baseType{
			rawType:        rawType,
			name:           name,
			argPackAdvance: GenericWireTypeSize,
		},
		size: api.DecodeI32(stack[2]),
	}, nil)
	if err != nil {
		panic(fmt.Errorf("could not register: %w", err))
	}
})
View Source
var RegisterFunction = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	namePtr := api.DecodeI32(stack[0])
	argCount := api.DecodeI32(stack[1])
	rawArgTypesAddr := api.DecodeI32(stack[2])
	signaturePtr := api.DecodeI32(stack[3])
	rawInvoker := api.DecodeI32(stack[4])
	fn := api.DecodeI32(stack[5])
	isAsync := api.DecodeI32(stack[6]) != 0

	argTypes, err := engine.heap32VectorToArray(argCount, rawArgTypesAddr)
	if err != nil {
		panic(fmt.Errorf("could not read arg types: %w", err))
	}

	name, err := engine.readCString(uint32(namePtr))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	name, err = getFunctionName(name)
	if err != nil {
		panic(fmt.Errorf("could not read function name: %w", err))
	}

	publicSymbolArgs := argCount - 1

	err = engine.exposePublicSymbol(name, func(ctx context.Context, this any, arguments ...any) (any, error) {
		return nil, engine.createUnboundTypeError(ctx, fmt.Sprintf("Cannot call _embind_register_function %s due to unbound types", name), argTypes)
	}, &publicSymbolArgs)
	if err != nil {
		panic(fmt.Errorf("could not expose public symbol: %w", err))
	}

	err = engine.whenDependentTypesAreResolved([]int32{}, argTypes, func(argTypes []registeredType) ([]registeredType, error) {
		invokerArgsArray := []registeredType{argTypes[0], nil}
		invokerArgsArray = append(invokerArgsArray, argTypes[1:]...)

		expectedParamTypes := make([]api.ValueType, len(invokerArgsArray[2:])+1)
		expectedParamTypes[0] = api.ValueTypeI32
		for i := range invokerArgsArray[2:] {
			expectedParamTypes[i+1] = invokerArgsArray[i+2].NativeType()
		}

		invokerFunc, err := engine.newInvokeFunc(signaturePtr, rawInvoker, expectedParamTypes, []api.ValueType{argTypes[0].NativeType()})
		if err != nil {
			return nil, fmt.Errorf("could not create _embind_register_function invoke func: %w", err)
		}

		err = engine.replacePublicSymbol(name, engine.craftInvokerFunction(name, invokerArgsArray, nil, invokerFunc, fn, isAsync), &publicSymbolArgs, argTypes[1:], argTypes[0])
		if err != nil {
			return nil, err
		}

		return []registeredType{}, nil
	})
	if err != nil {
		panic(fmt.Errorf("could not setup type dependenant lookup callbacks: %w", err))
	}
})
View Source
var RegisterInteger = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	rawType := api.DecodeI32(stack[0])
	name, err := engine.readCString(uint32(api.DecodeI32(stack[1])))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	err = engine.registerType(rawType, &intType{
		baseType: baseType{
			rawType:        rawType,
			name:           name,
			argPackAdvance: GenericWireTypeSize,
		},
		size:   api.DecodeI32(stack[2]),
		signed: !strings.Contains(name, "unsigned"),
	}, nil)
	if err != nil {
		panic(fmt.Errorf("could not register: %w", err))
	}
})
View Source
var RegisterMemoryView = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	rawType := api.DecodeI32(stack[0])
	dataTypeIndex := api.DecodeI32(stack[1])
	name, err := engine.readCString(uint32(api.DecodeI32(stack[2])))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	typeMapping := []any{
		int8(0),
		uint8(0),
		int16(0),
		uint16(0),
		int32(0),
		uint32(0),
		float32(0),
		float64(0),
		int64(0),
		uint64(0),
	}

	if dataTypeIndex < 0 || int(dataTypeIndex) >= len(typeMapping) {
		panic(fmt.Errorf("invalid memory view data type index: %d", dataTypeIndex))
	}

	sizeMapping := []uint32{
		1,
		1,
		2,
		2,
		4,
		4,
		4,
		8,
		8,
		8,
	}

	err = engine.registerType(rawType, &memoryViewType{
		baseType: baseType{
			rawType:        rawType,
			name:           name,
			argPackAdvance: GenericWireTypeSize,
		},
		dataTypeIndex: dataTypeIndex,
		nativeSize:    sizeMapping[dataTypeIndex],
		nativeType:    typeMapping[dataTypeIndex],
	}, &registerTypeOptions{
		ignoreDuplicateRegistrations: true,
	})
	if err != nil {
		panic(fmt.Errorf("could not register: %w", err))
	}
})
View Source
var RegisterSmartPtr = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	rawType := api.DecodeI32(stack[0])
	rawPointeeType := api.DecodeI32(stack[1])
	namePtr := api.DecodeI32(stack[2])
	sharingPolicy := api.DecodeI32(stack[3])
	getPointeeSignature := api.DecodeI32(stack[4])
	rawGetPointee := api.DecodeI32(stack[5])
	constructorSignature := api.DecodeI32(stack[6])
	rawConstructor := api.DecodeI32(stack[7])
	shareSignature := api.DecodeI32(stack[8])
	rawShare := api.DecodeI32(stack[9])
	destructorSignature := api.DecodeI32(stack[10])
	rawDestructor := api.DecodeI32(stack[11])

	name, err := engine.readCString(uint32(namePtr))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	rawGetPointeeFunc, err := engine.newInvokeFunc(getPointeeSignature, rawGetPointee, []api.ValueType{api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32})
	if err != nil {
		panic(fmt.Errorf("could not read rawGetPointee: %w", err))
	}

	rawConstructorFunc, err := engine.newInvokeFunc(constructorSignature, rawConstructor, []api.ValueType{}, []api.ValueType{api.ValueTypeI32})
	if err != nil {
		panic(fmt.Errorf("could not read constructorSignature: %w", err))
	}

	rawShareFunc, err := engine.newInvokeFunc(shareSignature, rawShare, []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32})
	specialShare := false
	if err != nil {

		rawShareFunc, err = engine.newInvokeFunc(shareSignature, rawShare, []api.ValueType{api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{})
		if err != nil {
			panic(fmt.Errorf("could not read rawShare: %w", err))
		}
		specialShare = true
	}

	rawDestructorFunc, err := engine.newInvokeFunc(destructorSignature, rawDestructor, []api.ValueType{api.ValueTypeI32}, []api.ValueType{})
	if err != nil {
		panic(fmt.Errorf("could not read rawDestructor: %w", err))
	}

	err = engine.whenDependentTypesAreResolved([]int32{rawType}, []int32{rawPointeeType}, func(types []registeredType) ([]registeredType, error) {
		pointeeType := types[0]

		smartPointerType := &registeredPointerType{
			baseType: baseType{
				argPackAdvance: GenericWireTypeSize,
				name:           name,
			},
			registeredClass: pointeeType.(*registeredPointerType).registeredClass,
			isReference:     false,
			isConst:         false,
			isSmartPointer:  true,
			pointeeType:     pointeeType.(*registeredPointerType),
			sharingPolicy:   sharingPolicy,
			rawGetPointee:   rawGetPointeeFunc,
			rawConstructor:  rawConstructorFunc,
			rawShare:        rawShareFunc,
			rawDestructor:   rawDestructorFunc,
			specialShare:    specialShare,
		}

		return []registeredType{smartPointerType}, nil
	})

	if err != nil {
		panic(fmt.Errorf("could not call whenDependentTypesAreResolved: %w", err))
	}
})
View Source
var RegisterStdString = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	rawType := api.DecodeI32(stack[0])
	name, err := engine.readCString(uint32(api.DecodeI32(stack[1])))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	err = engine.registerType(rawType, &stdStringType{
		baseType: baseType{
			rawType:        rawType,
			name:           name,
			argPackAdvance: GenericWireTypeSize,
		},
		stdStringIsUTF8: name == "std::string",
	}, nil)
	if err != nil {
		panic(fmt.Errorf("could not register: %w", err))
	}
})
View Source
var RegisterStdWString = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	rawType := api.DecodeI32(stack[0])
	name, err := engine.readCString(uint32(api.DecodeI32(stack[2])))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	err = engine.registerType(rawType, &stdWStringType{
		baseType: baseType{
			rawType:        rawType,
			name:           name,
			argPackAdvance: GenericWireTypeSize,
		},
		charSize: api.DecodeI32(stack[1]),
	}, nil)
	if err != nil {
		panic(fmt.Errorf("could not register: %w", err))
	}
})
View Source
var RegisterValueArray = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	rawType := api.DecodeI32(stack[0])
	namePtr := api.DecodeI32(stack[1])
	constructorSignature := api.DecodeI32(stack[2])
	rawConstructor := api.DecodeI32(stack[3])
	destructorSignature := api.DecodeI32(stack[4])
	rawDestructor := api.DecodeI32(stack[5])

	name, err := engine.readCString(uint32(namePtr))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	rawConstructorFunc, err := engine.newInvokeFunc(constructorSignature, rawConstructor, []api.ValueType{}, []api.ValueType{api.ValueTypeI32})
	if err != nil {
		panic(fmt.Errorf("could not create rawConstructorFunc: %w", err))
	}

	rawDestructorFunc, err := engine.newInvokeFunc(destructorSignature, rawDestructor, []api.ValueType{api.ValueTypeI32}, []api.ValueType{})
	if err != nil {
		panic(fmt.Errorf("could not create rawDestructorFunc: %w", err))
	}

	engine.registeredTuples[rawType] = &registeredTuple{
		name:           name,
		rawConstructor: rawConstructorFunc,
		rawDestructor:  rawDestructorFunc,
		elements:       []*registeredTupleElement{},
	}
})
View Source
var RegisterValueArrayElement = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	rawTupleType := api.DecodeI32(stack[0])
	getterReturnType := api.DecodeI32(stack[1])
	getterSignature := api.DecodeI32(stack[2])
	getter := api.DecodeI32(stack[3])
	getterContext := api.DecodeI32(stack[4])
	setterArgumentType := api.DecodeI32(stack[5])
	setterSignature := api.DecodeI32(stack[6])
	setter := api.DecodeI32(stack[7])
	setterContext := api.DecodeI32(stack[8])

	engine.registeredTuples[rawTupleType].elements = append(engine.registeredTuples[rawTupleType].elements, &registeredTupleElement{
		getter:             getter,
		getterSignature:    getterSignature,
		getterReturnType:   getterReturnType,
		getterContext:      getterContext,
		setter:             setter,
		setterSignature:    setterSignature,
		setterArgumentType: setterArgumentType,
		setterContext:      setterContext,
	})
})
View Source
var RegisterValueObject = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	rawType := api.DecodeI32(stack[0])
	namePtr := api.DecodeI32(stack[1])
	constructorSignature := api.DecodeI32(stack[2])
	rawConstructor := api.DecodeI32(stack[3])
	destructorSignature := api.DecodeI32(stack[4])
	rawDestructor := api.DecodeI32(stack[5])

	name, err := engine.readCString(uint32(namePtr))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	rawConstructorFunc, err := engine.newInvokeFunc(constructorSignature, rawConstructor, []api.ValueType{}, []api.ValueType{api.ValueTypeI32})
	if err != nil {
		panic(fmt.Errorf("could not create rawConstructorFunc: %w", err))
	}

	rawDestructorFunc, err := engine.newInvokeFunc(destructorSignature, rawDestructor, []api.ValueType{api.ValueTypeI32}, []api.ValueType{})
	if err != nil {
		panic(fmt.Errorf("could not create rawDestructorFunc: %w", err))
	}

	engine.registeredObjects[rawType] = &registeredObject{
		name:           name,
		rawConstructor: rawConstructorFunc,
		rawDestructor:  rawDestructorFunc,
		fields:         []*registeredObjectField{},
	}
})
View Source
var RegisterValueObjectField = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)
	structType := api.DecodeI32(stack[0])
	fieldNamePtr := api.DecodeI32(stack[1])
	getterReturnType := api.DecodeI32(stack[2])
	getterSignature := api.DecodeI32(stack[3])
	getter := api.DecodeI32(stack[4])
	getterContext := api.DecodeI32(stack[5])
	setterArgumentType := api.DecodeI32(stack[6])
	setterSignature := api.DecodeI32(stack[7])
	setter := api.DecodeI32(stack[8])
	setterContext := api.DecodeI32(stack[9])

	fieldName, err := engine.readCString(uint32(fieldNamePtr))
	if err != nil {
		panic(fmt.Errorf("could not read field name: %w", err))
	}

	engine.registeredObjects[structType].fields = append(engine.registeredObjects[structType].fields, &registeredObjectField{
		fieldName:          fieldName,
		getterReturnType:   getterReturnType,
		getter:             getter,
		getterSignature:    getterSignature,
		getterContext:      getterContext,
		setterArgumentType: setterArgumentType,
		setter:             setter,
		setterSignature:    setterSignature,
		setterContext:      setterContext,
	})
})
View Source
var RegisterVoid = api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
	engine := MustGetEngineFromContext(ctx, mod).(*engine)

	rawType := api.DecodeI32(stack[0])
	name, err := engine.readCString(uint32(api.DecodeI32(stack[1])))
	if err != nil {
		panic(fmt.Errorf("could not read name: %w", err))
	}

	err = engine.registerType(rawType, &voidType{
		baseType: baseType{
			rawType:        rawType,
			name:           name,
			argPackAdvance: 0,
		},
	}, nil)
	if err != nil {
		panic(fmt.Errorf("could not register: %w", err))
	}
})

Functions

func EmvalGetMethodOnObject added in v1.3.1

func EmvalGetMethodOnObject(obj any, registeredMethod *emvalRegisteredMethod, methodName string) (*reflect.Value, bool, error)

func EmvalReturnValue added in v1.3.1

func EmvalReturnValue(ctx context.Context, mod api.Module, returnType registeredType, destructorsRef uint32, handle any) (uint64, error)

Types

type ClassBase

type ClassBase struct {
	// contains filtered or unexported fields
}

func (*ClassBase) CallInstanceMethod added in v1.1.0

func (ecb *ClassBase) CallInstanceMethod(ctx context.Context, this any, name string, arguments ...any) (any, error)

func (*ClassBase) CloneInstance added in v1.1.0

func (ecb *ClassBase) CloneInstance(ctx context.Context, this IClassBase) (IClassBase, error)

func (*ClassBase) DeleteInheritedInstance added in v1.2.0

func (ecb *ClassBase) DeleteInheritedInstance(ctx context.Context) error

func (*ClassBase) DeleteInstance added in v1.1.0

func (ecb *ClassBase) DeleteInstance(ctx context.Context, this IClassBase) error

func (*ClassBase) DeleteInstanceLater added in v1.1.0

func (ecb *ClassBase) DeleteInstanceLater(ctx context.Context, this IClassBase) (IClassBase, error)

func (*ClassBase) GetInstanceProperty added in v1.1.0

func (ecb *ClassBase) GetInstanceProperty(ctx context.Context, this any, name string) (any, error)

func (*ClassBase) IsAliasOfInstance added in v1.1.0

func (ecb *ClassBase) IsAliasOfInstance(ctx context.Context, this IClassBase, second IClassBase) (bool, error)

func (*ClassBase) IsInstanceDeleted added in v1.1.0

func (ecb *ClassBase) IsInstanceDeleted(ctx context.Context, this IClassBase) bool

func (*ClassBase) SetInstanceProperty added in v1.1.0

func (ecb *ClassBase) SetInstanceProperty(ctx context.Context, this any, name string, value any) error

func (*ClassBase) String added in v1.1.0

func (ecb *ClassBase) String() string

type DelayFunction added in v1.1.0

type DelayFunction func(func(ctx context.Context) error) error

type EngineConfig

type EngineConfig struct {
}

type EngineKey

type EngineKey struct{}

EngineKey Use this key to add the engine to your context: ctx = context.WithValue(ctx, embind.EngineKey{}, engine)

type IClassBase

type IClassBase interface {
	CloneInstance(ctx context.Context, this IClassBase) (IClassBase, error)
	DeleteInstance(ctx context.Context, this IClassBase) error
	DeleteInstanceLater(ctx context.Context, this IClassBase) (IClassBase, error)
	IsInstanceDeleted(ctx context.Context, this IClassBase) bool
	IsAliasOfInstance(ctx context.Context, this IClassBase, second IClassBase) (bool, error)
	CallInstanceMethod(ctx context.Context, this any, name string, arguments ...any) (any, error)
	SetInstanceProperty(ctx context.Context, this any, name string, value any) error
	GetInstanceProperty(ctx context.Context, this any, name string) (any, error)
	// contains filtered or unexported methods
}

type IClassType

type IClassType interface {
	Name() string
	Type() IType
	Properties() []IClassTypeProperty
	StaticProperties() []IClassTypeProperty
	Constructors() []IClassTypeConstructor
	Methods() []IClassTypeMethod
	StaticMethods() []IClassTypeMethod
}

type IClassTypeConstructor

type IClassTypeConstructor interface {
	Name() string
	Symbol() string
	ArgumentTypes() []IType
}

type IClassTypeMethod

type IClassTypeMethod interface {
	Symbol() string
	ReturnType() IType
	ArgumentTypes() []IType
	IsOverload() bool
	OverloadCount() int
}

type IClassTypeProperty

type IClassTypeProperty interface {
	Name() string
	GetterType() IType
	SetterType() IType
	ReadOnly() bool
}

type IConstant

type IConstant interface {
	Name() string
	Value() any
	Type() IType
}

type IEmvalConstructor

type IEmvalConstructor interface {
	New(argTypes []string, args ...any) (any, error)
}

type IEmvalFunctionMapper

type IEmvalFunctionMapper interface {
	MapFunction(name string, returnType string, argTypes []string) (string, error)
}

type IEngine

type IEngine interface {
	Attach(ctx context.Context) context.Context
	CallPublicSymbol(ctx context.Context, name string, arguments ...any) (any, error)
	GetSymbols() []ISymbol
	RegisterConstant(name string, val any) error
	GetConstants() []IConstant
	RegisterEnum(name string, enum IEnum) error
	GetEnums() []IEnumType
	RegisterClass(name string, class any) error
	GetClasses() []IClassType
	CallStaticClassMethod(ctx context.Context, className, name string, arguments ...any) (any, error)
	GetStaticClassProperty(ctx context.Context, className, name string) (any, error)
	SetStaticClassProperty(ctx context.Context, className, name string, value any) error
	RegisterEmvalSymbol(name string, symbol any) error
	EmvalToHandle(value any) int32
	EmvalToValue(handle int32) (any, error)
	CountEmvalHandles() int
	GetInheritedInstanceCount() int
	GetLiveInheritedInstances() []IClassBase
	FlushPendingDeletes(ctx context.Context) error
	SetDelayFunction(fn DelayFunction) error
}

func CreateEngine

func CreateEngine(config IEngineConfig) IEngine

CreateEngine returns a new embind engine to attach to your context. Be sure to attach it before you run InstantiateModule on the runtime, unless you run the _start/_initialize function manually.

func GetEngineFromContext

func GetEngineFromContext(ctx context.Context) (IEngine, error)

func MustGetEngineFromContext

func MustGetEngineFromContext(ctx context.Context, mod api.Module) IEngine

type IEngineConfig

type IEngineConfig interface {
}

type IEnum

type IEnum interface {
	Type() any
	Values() map[string]any
}

type IEnumType

type IEnumType interface {
	Name() string
	Type() IType
	Values() []IEnumTypeValue
}

type IEnumTypeValue

type IEnumTypeValue interface {
	Name() string
	Value() any
}

type ISymbol

type ISymbol interface {
	Symbol() string
	ReturnType() IType
	ArgumentTypes() []IType
	IsOverload() bool
	OverloadCount() int
}

type IType

type IType interface {
	Name() string
	Type() string
	IsClass() bool
	IsEnum() bool
}

type PublicSymbol

type PublicSymbol interface {
	Call(ctx context.Context, this any, arguments ...any) (any, error)
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL