signalis-eb/godot/addons/serde/serde.gd
2025-06-06 01:49:16 -04:00

228 lines
9.5 KiB
GDScript

class_name Serde
const SerializeMethod = &"serialize"
const DeserializeMethod = &"deserialize"
enum SerdeType {
Nil,
Bool,
Int,
Float,
String,
Seq,
Dict,
Object
}
static func to_serde_type(godot_type: int) -> Result:
match godot_type:
TYPE_NIL: return Result.ok(Result.ok(SerdeType.Nil))
TYPE_BOOL: return Result.ok(Result.ok(SerdeType.Bool))
TYPE_INT: return Result.ok(Result.ok(SerdeType.Int))
TYPE_FLOAT: return Result.ok(SerdeType.Float)
TYPE_STRING: return Result.ok(SerdeType.String)
TYPE_STRING_NAME: return Result.ok(SerdeType.String)
TYPE_NODE_PATH: return Result.ok(SerdeType.String)
TYPE_VECTOR2: return Result.ok(SerdeType.Seq)
TYPE_VECTOR2I: return Result.ok(SerdeType.Seq)
TYPE_VECTOR3: return Result.ok(SerdeType.Seq)
TYPE_VECTOR3I: return Result.ok(SerdeType.Seq)
TYPE_VECTOR4I: return Result.ok(SerdeType.Seq)
TYPE_VECTOR4I: return Result.ok(SerdeType.Seq)
TYPE_RECT2: return Result.ok(SerdeType.Object)
TYPE_RECT2I: return Result.ok(SerdeType.Object)
TYPE_AABB: return Result.ok(SerdeType.Object)
TYPE_TRANSFORM2D: return Result.ok(SerdeType.Object)
TYPE_BASIS: return Result.ok(SerdeType.Object)
TYPE_TRANSFORM3D: return Result.ok(SerdeType.Object)
TYPE_PLANE: return Result.ok(SerdeType.Object)
TYPE_PROJECTION: return Result.ok(SerdeType.Object)
TYPE_QUATERNION: return Result.ok(SerdeType.Seq)
TYPE_COLOR: return Result.ok(SerdeType.Seq)
TYPE_RID: return Result.ok(SerdeType.Int)
TYPE_OBJECT: return Result.ok(SerdeType.Object)
TYPE_DICTIONARY: return Result.ok(SerdeType.Dict)
TYPE_ARRAY: return Result.ok(SerdeType.Seq)
TYPE_PACKED_BYTE_ARRAY: return Result.ok(SerdeType.Seq)
TYPE_PACKED_COLOR_ARRAY: return Result.ok(SerdeType.Seq)
TYPE_PACKED_INT32_ARRAY: return Result.ok(SerdeType.Seq)
TYPE_PACKED_INT64_ARRAY: return Result.ok(SerdeType.Seq)
TYPE_PACKED_STRING_ARRAY: return Result.ok(SerdeType.Seq)
TYPE_PACKED_FLOAT32_ARRAY: return Result.ok(SerdeType.Seq)
TYPE_PACKED_FLOAT64_ARRAY: return Result.ok(SerdeType.Seq)
TYPE_PACKED_VECTOR2_ARRAY: return Result.ok(SerdeType.Seq)
TYPE_PACKED_VECTOR3_ARRAY: return Result.ok(SerdeType.Seq)
TYPE_PACKED_VECTOR4_ARRAY: return Result.ok(SerdeType.Seq)
TYPE_SIGNAL: return Result.err("Refusing to (de)serialize Signal")
TYPE_CALLABLE: return Result.err("Refusing to (de)serialize Callable")
_: return Result.err(Error.InvalidArgument.new(godot_type))
static func _serialize_seq(serializer: Serializer, value: Variant) -> Variant:
var ser = serializer.serialize_seq(len(value))
for element in value:
ser.serialize_element(element)
return ser.end()
static func _serialize_dict(serializer: Serializer, value: Dictionary) -> Variant:
var ser: SerializeMap = serializer.serialize_dict(value.size())
for key in value.keys():
ser.serialize_entry(key, value[key])
return ser.end()
static func get_object_name(value: Variant) -> Option:
var name: Option = Option.none
if value.has_method("get_script"):
var script_name = value.get_script().get_global_name()
if script_name != null: name = Option.some(script_name)
if name == null and value.has_method("get_class"):
var native_name = value.get_class()
if native_name != null: name = Option.some(native_name)
return name
static func _serialize_object(serializer: Serializer, value: Variant) -> Variant:
var object_name = get_object_name(value).unwrap()
var ser = serializer.serialize_object(object_name, len(value.get_property_list()))
ser.serialize(value)
return ser.end()
static func default_serialize(serializer: Serializer, value: Variant, allow_eval: bool = false) -> Variant:
match to_serde_type(typeof(value)).unwrap():
SerdeType.Nil: return serializer.serialize_nil()
SerdeType.Bool: return serializer.serialize_bool(value)
SerdeType.Int: return serializer.serialize_int(value)
SerdeType.Float: return serializer.serialize_float(value)
SerdeType.String: return serializer.serialize_string(value)
SerdeType.Seq: return _serialize_seq(serializer, value)
SerdeType.Dict: return _serialize_dict(serializer, value)
SerdeType.Object: return _serialize_object(serializer, value)
return Result.err("could not deserialize type %s" % typeof(value))
static func serialize(serializer: Serializer, value: Variant, allow_eval: bool = false) -> Variant:
if typeof(value) == TYPE_OBJECT and value.has_method(SerializeMethod):
return value.call(serializer, value, allow_eval)
else:
return default_serialize(serializer, value, allow_eval)
class SerializeSeq extends RefCounted:
func serialize_element(element: Variant): Error.NotImplemented.raise('serialize_element')
func end(): Error.NotImplemented.raise('end')
class SerializeMap extends RefCounted:
func serialize_key(key: Variant): Error.NotImplemented.raise('serialize_key')
func serialize_value(value: Variant): Error.NotImplemented.raise('serialize_value')
func end(): Error.NotImplemented.raise('end')
func serialize_entry(key: Variant, value: Variant):
return Result.collect_ok([serialize_key(key), serialize_value(value)])
class SerializeObject extends RefCounted:
func serialize_field(name: StringName, value: Variant): Error.NotImplemented.raise('serialize_field')
func serialize(object: Variant): Error.NotImplemented.raise('serialize')
func end(): Error.NotImplemented.raise('end')
class Serializer extends RefCounted:
func serialize_nil(): Error.NotImplemented.raise('serialize_nil')
func serialize_bool(_value: bool): Error.NotImplemented.raise('serialize_bool')
func serialize_int(_value: int): Error.NotImplemented.raise('serialize_int')
func serialize_float(_value: float): Error.NotImplemented.raise('serialize_float')
func serialize_string(_value: String): Error.NotImplemented.raise('serialize_string')
func serialize_seq(_len: int): Error.NotImplemented.raise('serialize_string')
func serialize_dict(_len: int): Error.NotImplemented.raise('serialize_string')
func serialize_object(_name: StringName, _len: int): Error.NotImplemented.raise('serialize_string')
class Visitor extends RefCounted:
func visit_nil(): Error.NotImplemented.raise('visit_nil')
func visit_bool(_value: bool): Error.NotImplemented.raise('visit_bool')
func visit_int(_value: int): Error.NotImplemented.raise('visit_int')
func visit_float(_value: float): Error.NotImplemented.raise('visit_float')
func visit_string(_value: String): Error.NotImplemented.raise('visit_string')
func visit_seq(_access: SeqAccess): Error.NotImplemented.raise('visit_seq')
func visit_dict(_access: MapAccess): Error.NotImplemented.raise('visit_dict')
class GenericVisitor extends Visitor:
func visit_nil(): return null
func visit_bool(value: bool):
print('bool', value)
return value
func visit_int(value: int):
print('int', value)
return value
func visit_float(value: float):
print('float', value)
return value
func visit_string(value: String):
print('str', value)
return value
func visit_seq(access: SeqAccess):
print('seq', access)
return access.collect()
func visit_dict(access: MapAccess):
var a = access.collect()
print('dict', a)
return a
class AccessIterable extends Iterator:
var _next: Callable
func _init(next: Callable) -> void:
_next = next
func next() -> Option:
return _next.call().to_option().flatten()
class SeqAccess extends RefCounted:
func next_element(): Error.NotImplemented.raise('next_element')
func iterate() -> AccessIterable:
return AccessIterable.new(next_element)
func collect() -> Array:
var list = []
for item in iterate():
list.append(item)
return list
class MapAccess extends RefCounted:
func next_key(): Error.NotImplemented.raise('next_key')
func next_value(): Error.NotImplemented.raise('next_value')
func next_entry() -> Result:
var key = next_key()
var val = next_value()
return Result.collect_ok([key, val])
func iterate() -> AccessIterable:
return AccessIterable.new(next_entry)
func collect() -> Dictionary:
var dict: Dictionary = {}
print('collecting map')
for entry in iterate():
print('entry', entry)
dict.set(entry[0], entry[1])
return dict
class Deserializer extends RefCounted:
func deserialize_any(_visitor: Visitor): Error.NotImplemented.raise('deserialize_any')
func deserialize_nil(_visitor: Visitor): Error.NotImplemented.raise('deserialize_nil')
func deserialize_bool(_visitor: Visitor): Error.NotImplemented.raise('deserialize_bool')
func deserialize_int(_visitor: Visitor): Error.NotImplemented.raise('deserialize_int')
func deserialize_float(_visitor: Visitor): Error.NotImplemented.raise('deserialize_float')
func deserialize_string(_visitor: Visitor): Error.NotImplemented.raise('deserialize_string')
func deserialize_seq(_visitor: Visitor): Error.NotImplemented.raise('deserialize_seq')
func deserialize_dict(_visitor: Visitor): Error.NotImplemented.raise('deserialize_dict')
func deserialize_object(_name: StringName, _fields: Array[StringName], _visitor: Visitor): Error.NotImplemented.raise('deserialize_object')