228 lines
9.5 KiB
GDScript
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')
|