mirror of
				https://github.com/mochi-mqtt/server.git
				synced 2025-10-31 19:42:38 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			190 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package json
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"errors"
 | |
| 
 | |
| 	"github.com/yuin/gopher-lua"
 | |
| )
 | |
| 
 | |
| // Preload adds json to the given Lua state's package.preload table. After it
 | |
| // has been preloaded, it can be loaded using require:
 | |
| //
 | |
| //  local json = require("json")
 | |
| func Preload(L *lua.LState) {
 | |
| 	L.PreloadModule("json", Loader)
 | |
| }
 | |
| 
 | |
| // Loader is the module loader function.
 | |
| func Loader(L *lua.LState) int {
 | |
| 	t := L.NewTable()
 | |
| 	L.SetFuncs(t, api)
 | |
| 	L.Push(t)
 | |
| 	return 1
 | |
| }
 | |
| 
 | |
| var api = map[string]lua.LGFunction{
 | |
| 	"decode": apiDecode,
 | |
| 	"encode": apiEncode,
 | |
| }
 | |
| 
 | |
| func apiDecode(L *lua.LState) int {
 | |
| 	if L.GetTop() != 1 {
 | |
| 		L.Error(lua.LString("bad argument #1 to decode"), 1)
 | |
| 		return 0
 | |
| 	}
 | |
| 	str := L.CheckString(1)
 | |
| 
 | |
| 	value, err := Decode(L, []byte(str))
 | |
| 	if err != nil {
 | |
| 		L.Push(lua.LNil)
 | |
| 		L.Push(lua.LString(err.Error()))
 | |
| 		return 2
 | |
| 	}
 | |
| 	L.Push(value)
 | |
| 	return 1
 | |
| }
 | |
| 
 | |
| func apiEncode(L *lua.LState) int {
 | |
| 	if L.GetTop() != 1 {
 | |
| 		L.Error(lua.LString("bad argument #1 to encode"), 1)
 | |
| 		return 0
 | |
| 	}
 | |
| 	value := L.CheckAny(1)
 | |
| 
 | |
| 	data, err := Encode(value)
 | |
| 	if err != nil {
 | |
| 		L.Push(lua.LNil)
 | |
| 		L.Push(lua.LString(err.Error()))
 | |
| 		return 2
 | |
| 	}
 | |
| 	L.Push(lua.LString(string(data)))
 | |
| 	return 1
 | |
| }
 | |
| 
 | |
| var (
 | |
| 	errNested      = errors.New("cannot encode recursively nested tables to JSON")
 | |
| 	errSparseArray = errors.New("cannot encode sparse array")
 | |
| 	errInvalidKeys = errors.New("cannot encode mixed or invalid key types")
 | |
| )
 | |
| 
 | |
| type invalidTypeError lua.LValueType
 | |
| 
 | |
| func (i invalidTypeError) Error() string {
 | |
| 	return `cannot encode ` + lua.LValueType(i).String() + ` to JSON`
 | |
| }
 | |
| 
 | |
| // Encode returns the JSON encoding of value.
 | |
| func Encode(value lua.LValue) ([]byte, error) {
 | |
| 	return json.Marshal(jsonValue{
 | |
| 		LValue:  value,
 | |
| 		visited: make(map[*lua.LTable]bool),
 | |
| 	})
 | |
| }
 | |
| 
 | |
| type jsonValue struct {
 | |
| 	lua.LValue
 | |
| 	visited map[*lua.LTable]bool
 | |
| }
 | |
| 
 | |
| func (j jsonValue) MarshalJSON() (data []byte, err error) {
 | |
| 	switch converted := j.LValue.(type) {
 | |
| 	case lua.LBool:
 | |
| 		data, err = json.Marshal(bool(converted))
 | |
| 	case lua.LNumber:
 | |
| 		data, err = json.Marshal(float64(converted))
 | |
| 	case *lua.LNilType:
 | |
| 		data = []byte(`null`)
 | |
| 	case lua.LString:
 | |
| 		data, err = json.Marshal(string(converted))
 | |
| 	case *lua.LTable:
 | |
| 		if j.visited[converted] {
 | |
| 			return nil, errNested
 | |
| 		}
 | |
| 		j.visited[converted] = true
 | |
| 
 | |
| 		key, value := converted.Next(lua.LNil)
 | |
| 
 | |
| 		switch key.Type() {
 | |
| 		case lua.LTNil: // empty table
 | |
| 			data = []byte(`[]`)
 | |
| 		case lua.LTNumber:
 | |
| 			arr := make([]jsonValue, 0, converted.Len())
 | |
| 			expectedKey := lua.LNumber(1)
 | |
| 			for key != lua.LNil {
 | |
| 				if key.Type() != lua.LTNumber {
 | |
| 					err = errInvalidKeys
 | |
| 					return
 | |
| 				}
 | |
| 				if expectedKey != key {
 | |
| 					err = errSparseArray
 | |
| 					return
 | |
| 				}
 | |
| 				arr = append(arr, jsonValue{value, j.visited})
 | |
| 				expectedKey++
 | |
| 				key, value = converted.Next(key)
 | |
| 			}
 | |
| 			data, err = json.Marshal(arr)
 | |
| 		case lua.LTString:
 | |
| 			obj := make(map[string]jsonValue)
 | |
| 			for key != lua.LNil {
 | |
| 				if key.Type() != lua.LTString {
 | |
| 					err = errInvalidKeys
 | |
| 					return
 | |
| 				}
 | |
| 				obj[key.String()] = jsonValue{value, j.visited}
 | |
| 				key, value = converted.Next(key)
 | |
| 			}
 | |
| 			data, err = json.Marshal(obj)
 | |
| 		default:
 | |
| 			err = errInvalidKeys
 | |
| 		}
 | |
| 	default:
 | |
| 		err = invalidTypeError(j.LValue.Type())
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Decode converts the JSON encoded data to Lua values.
 | |
| func Decode(L *lua.LState, data []byte) (lua.LValue, error) {
 | |
| 	var value interface{}
 | |
| 	err := json.Unmarshal(data, &value)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return DecodeValue(L, value), nil
 | |
| }
 | |
| 
 | |
| // DecodeValue converts the value to a Lua value.
 | |
| //
 | |
| // This function only converts values that the encoding/json package decodes to.
 | |
| // All other values will return lua.LNil.
 | |
| func DecodeValue(L *lua.LState, value interface{}) lua.LValue {
 | |
| 	switch converted := value.(type) {
 | |
| 	case bool:
 | |
| 		return lua.LBool(converted)
 | |
| 	case float64:
 | |
| 		return lua.LNumber(converted)
 | |
| 	case string:
 | |
| 		return lua.LString(converted)
 | |
| 	case json.Number:
 | |
| 		return lua.LString(converted)
 | |
| 	case []interface{}:
 | |
| 		arr := L.CreateTable(len(converted), 0)
 | |
| 		for _, item := range converted {
 | |
| 			arr.Append(DecodeValue(L, item))
 | |
| 		}
 | |
| 		return arr
 | |
| 	case map[string]interface{}:
 | |
| 		tbl := L.CreateTable(0, len(converted))
 | |
| 		for key, item := range converted {
 | |
| 			tbl.RawSetH(lua.LString(key), DecodeValue(L, item))
 | |
| 		}
 | |
| 		return tbl
 | |
| 	case nil:
 | |
| 		return lua.LNil
 | |
| 	}
 | |
| 
 | |
| 	return lua.LNil
 | |
| }
 | 
