extends Object
class_name NetworkSchemas

## Provides various schema serializers
##
## While some method names are abbreviated, they use a few naming schemes. For 
## example: [br][br]
## [method uint16] - unsigned integer, 16 bits[br]
## [method vec2t] - [Vector2], component of specified [i]type[/i][br]
## [method vec3f32] - [Vector3], each component as a [method float32][br]
## [br]
## To handle collections, see [method array_of] and [method dictionary].
##
## @tutorial(Network schemas): https://foxssake.github.io/netfox/latest/netfox/guides/network-schemas/

## Serialize any data type supported by [method @GlobalScope.var_to_bytes].
## [br][br]
## Final size depends on the value.
static func variant() -> NetworkSchemaSerializer:
	return _VariantSerializer.new()

## Serialize strings in UTF-8 encoding.
## [br][br]
## Final size depends on the string, the string itself is zero-terminated.
static func string() -> NetworkSchemaSerializer:
	return _StringSerializer.new()

## Serialize booleans as 8 bits.
## [br][br]
## Final size is 1 byte.
static func bool8() -> NetworkSchemaSerializer:
	return _BoolSerializer.new()

## Serialize unsigned integers as 8 bits.
## [br][br]
## Final size is 1 byte.
static func uint8() -> NetworkSchemaSerializer:
	return _Uint8Serializer.new()

## Serialize unsigned integers as 16 bits.
## [br][br]
## Final size is 2 bytes.
static func uint16() -> NetworkSchemaSerializer:
	return _Uint16Serializer.new()

## Serialize unsigned integers as 32 bits.
## [br][br]
## Final size is 4 bytes.
static func uint32() -> NetworkSchemaSerializer:
	return _Uint32Serializer.new()

## Serialize unsigned integers as 64 bits.
## [br][br]
## Final size is 8 bytes.
static func uint64() -> NetworkSchemaSerializer:
	return _Uint64Serializer.new()

## Serialize an unsigned integer as a variable amount of bytes.
## [br][br]
## Each byte contains 7 bits of data. The 8th bit indicates whether there are
## more bytes left. Thus, small numbers fitting into 7 bits will be encoded as
## a single byte, while larger numbers take more space as they increase.
## [br][br]
## Final size is 1 byte for every 7 bits of numeric data.
static func varuint() -> NetworkSchemaSerializer:
	return _VaruintSerializer.instance

static func _varbits() -> NetworkSchemaSerializer:
	return _VariableBitsetSerializer.instance

## Serialize signed integers as 8 bits.
## [br][br]
## Final size is 1 byte.
static func int8() -> NetworkSchemaSerializer:
	return _Int8Serializer.new()

## Serialize signed integers as 16 bits.
## [br][br]
## Final size is 2 bytes.
static func int16() -> NetworkSchemaSerializer:
	return _Int16Serializer.new()

## Serialize signed integers as 32 bits.
## [br][br]
## Final size is 4 bytes.
static func int32() -> NetworkSchemaSerializer:
	return _Int32Serializer.new()

## Serialize signed integers as 64 bits.
## [br][br]
## Final size is 8 bytes.
static func int64() -> NetworkSchemaSerializer:
	return _Int64Serializer.new()

## Serialize floats in half-precision, as 16 bits.
## [br][br]
## This is only supported in Godot 4.4 and up, earlier versions fall back to
## [method float32].
## [br][br]
## Final size is 2 bytes, 4 if using fallback.
static func float16() -> NetworkSchemaSerializer:
	return _Float16Serializer.new()

## Serialize floats in single-precision, as 32 bits.
## [br][br]
## Final size is 4 bytes.
static func float32() -> NetworkSchemaSerializer:
	return _Float32Serializer.new()

## Serialize floats in double-precision, as 64 bits.
## [br][br]
## Final size is 8 bytes.
static func float64() -> NetworkSchemaSerializer:
	return _Float64Serializer.new()

## Serialize signed fractions in the [code][-1.0, +1.0][/code] range as 8 bits.
## [br][br]
## Final size is 1 byte.
static func sfrac8() -> NetworkSchemaSerializer:
	return _QuantizingSerializer.new(uint8(), -1., 1., 0, 0xFF)

## Serialize signed fractions in the [code][-1.0, +1.0][/code] range as 16 bits.
## [br][br]
## Final size is 2 bytes.
static func sfrac16() -> NetworkSchemaSerializer:
	return _QuantizingSerializer.new(uint16(), -1., 1., 0, 0xFFFF)

## Serialize signed fractions in the [code][-1.0, +1.0][/code] range as 32 bits.
## [br][br]
## Final size is 4 bytes.
static func sfrac32() -> NetworkSchemaSerializer:
	return _QuantizingSerializer.new(uint32(), -1., 1., 0, 0xFFFFFFFF)

## Serialize signed fractions in the [code][0.0, 1.0][/code] range as 8 bits.
## [br][br]
## Final size is 1 byte.
static func ufrac8() -> NetworkSchemaSerializer:
	return _QuantizingSerializer.new(uint8(), 0., 1., 0, 0xFF)

## Serialize signed fractions in the [code][0.0, 1.0][/code] range as 16 bits.
## [br][br]
## Final size is 2 bytes.
static func ufrac16() -> NetworkSchemaSerializer:
	return _QuantizingSerializer.new(uint16(), 0., 1., 0, 0xFFFF)

## Serialize signed fractions in the [code][0.0, 1.0][/code] range as 32 bits.
## [br][br]
## Final size is 4 bytes.
static func ufrac32() -> NetworkSchemaSerializer:
	return _QuantizingSerializer.new(uint32(), 0., 1., 0, 0xFFFFFFFF)

## Serialize degrees as 8 bits. The value will always decode to the
## [code][0.0, 360.0)[/code] range.
## [br][br]
## Final size is 1 byte.
static func degrees8() -> NetworkSchemaSerializer:
	return _ModuloSerializer.new(uint8(), 360., 0xFF)

## Serialize degrees as 16 bits. The value will always decode to the
## [code][0.0, 360.0)[/code] range.
## [br][br]
## Final size is 2 bytes.
static func degrees16() -> NetworkSchemaSerializer:
	return _ModuloSerializer.new(uint16(), 360., 0xFFFF)

## Serialize degrees as 32 bits. The value will always decode to the
## [code][0.0, 360.0)[/code] range.
## [br][br]
## Final size is 4 bytes.
static func degrees32() -> NetworkSchemaSerializer:
	return _ModuloSerializer.new(uint32(), 360., 0xFFFFFFFF)

## Serialize radians as 8 bits. The value will always decode to the
## [code][0.0, TAU)[/code] range.
## [br][br]
## Final size is 1 byte.
static func radians8() -> NetworkSchemaSerializer:
	return _ModuloSerializer.new(uint8(), TAU, 0xFF)

## Serialize radians as 16 bits. The value will always decode to the
## [code][0.0, TAU)[/code] range.
## [br][br]
## Final size is 2 bytes.
static func radians16() -> NetworkSchemaSerializer:
	return _ModuloSerializer.new(uint16(), TAU, 0xFFFF)

## Serialize radians as 32 bits. The value will always decode to the
## [code][0.0, TAU)[/code] range.
## [br][br]
## Final size is 4 bytes.
static func radians32() -> NetworkSchemaSerializer:
	return _ModuloSerializer.new(uint32(), TAU, 0xFFFFFFFF)

## Serialize [Vector2] objects, using [param component_serializer] to
## serialize each component of the vector.
## [br][br]
## Serializes 2 components, size depends on the [param component_serializer].
static func vec2t(component_serializer: NetworkSchemaSerializer) -> NetworkSchemaSerializer:
	return _GenericVec2Serializer.new(component_serializer)

## Serialize [Vector2] objects, with each component being a half-precision
## float.
## [br][br]
## This is only supported in Godot 4.4 and up. Earlier versions fall back to
## [method vec2f32].
## [br][br]
## Final size is 4 bytes, 8 if using fallback.
static func vec2f16() -> NetworkSchemaSerializer:
	return vec2t(float16())

## Serialize [Vector2] objects, with each component being a single-precision
## float.
## [br][br]
## Final size is 8 bytes.
static func vec2f32() -> NetworkSchemaSerializer:
	return vec2t(float32())

## Serialize [Vector2] objects, with each component being a double-precision
## float.
## [br][br]
## Final size is 16 bytes.
static func vec2f64() -> NetworkSchemaSerializer:
	return vec2t(float64())

## Serialize [Vector3] objects, using [param component_serializer] to
## serialize each component of the vector.
## [br][br]
## Serializes 3 components, size depends on the [param component_serializer].
static func vec3t(component_serializer: NetworkSchemaSerializer) -> NetworkSchemaSerializer:
	return _GenericVec3Serializer.new(component_serializer)
	
## Serialize [Vector3] objects, with each component being a half-precision
## float.
## [br][br]
## This is only supported in Godot 4.4 and up. Earlier versions fall back to
## [method vec3f32].
## [br][br]
## Final size is 6 bytes, 12 if using fallback.
static func vec3f16() -> NetworkSchemaSerializer:
	return vec3t(float16())

## Serialize [Vector3] objects, with each component being a double-precision
## float.
## [br][br]
## Final size is 12 bytes.
static func vec3f32() -> NetworkSchemaSerializer:
	return vec3t(float32())

## Serialize [Vector3] objects, with each component being a double-precision
## float.
## [br][br]
## Final size is 24 bytes.
static func vec3f64() -> NetworkSchemaSerializer:
	return vec3t(float64())

## Serialize [Vector4] objects, using [param component_serializer] to
## serialize each component of the vector.
## [br][br]
## Serializes 4 components, size depends on the [param component_serializer].
static func vec4t(component_serializer: NetworkSchemaSerializer) -> NetworkSchemaSerializer:
	return _GenericVec4Serializer.new(component_serializer)

## Serialize [Vector4] objects, with each component being a half-precision
## float.
## [br][br]
## This is only supported in Godot 4.4 and up. Earlier versions fall back to
## [method vec4f32].
## [br][br]
## Final size is 8 bytes, 16 if using fallback.
static func vec4f16() -> NetworkSchemaSerializer:
	return vec4t(float16())

## Serialize [Vector4] objects, with each component being a double-precision
## float.
## [br][br]
## Final size is 16 bytes.
static func vec4f32() -> NetworkSchemaSerializer:
	return vec4t(float32())

## Serialize [Vector4] objects, with each component being a double-precision
## float.
## [br][br]
## Final size is 32 bytes.
static func vec4f64() -> NetworkSchemaSerializer:
	return vec4t(float64())

# Normals
## Serialize normalized [Vector2] objects, using [param component_serializer] to
## serialize each component of the vector.
## [br][br]
## Serializes 1 component, size depends on the [param component_serializer].
static func normal2t(component_serializer: NetworkSchemaSerializer) -> NetworkSchemaSerializer:
	return _Normal2Serializer.new(component_serializer)

## Serialize normalized [Vector2] objects, with each component being a
## half-precision float.
## [br][br]
## This is only supported in Godot 4.4 and up. Earlier versions fall back to
## [method normal2f32].
## [br][br]
## Final size is 2 bytes, 4 if using fallback.
static func normal2f16() -> NetworkSchemaSerializer:
	return normal2t(float16())

## Serialize normalized [Vector2] objects, with each component being a
## single-precision float.
## [br][br]
## Final size is 4 bytes.
static func normal2f32() -> NetworkSchemaSerializer:
	return normal2t(float32())

## Serialize normalized [Vector2] objects, with each component being a
## double-precision float.
## [br][br]
## Final size is 8 bytes.
static func normal2f64() -> NetworkSchemaSerializer:
	return normal2t(float64())

## Serialize normalized [Vector3] objects, using [param component_serializer] to
## serialize each component of the vector.
## [br][br]
## Serializes 2 components, size depends on the [param component_serializer].
static func normal3t(component_serializer: NetworkSchemaSerializer) -> NetworkSchemaSerializer:
	return _Normal3Serializer.new(component_serializer)

## Serialize normalized [Vector3] objects, with each component being a
## half-precision float.
## [br][br]
## This is only supported in Godot 4.4 and up. Earlier versions fall back to
## [method normal3f32].
## [br][br]
## Final size is 4 bytes, 8 if using fallback.
static func normal3f16() -> NetworkSchemaSerializer:
	return normal3t(float16())

## Serialize normalized [Vector3] objects, with each component being a
## single-precision float.
## [br][br]
## Final size is 8 bytes.
static func normal3f32() -> NetworkSchemaSerializer:
	return normal3t(float32())

## Serialize normalized [Vector3] objects, with each component being a
## double-precision float.
## [br][br]
## Final size is 16 bytes.
static func normal3f64() -> NetworkSchemaSerializer:
	return normal3t(float64())

# Quaternion
## Serialize [Quaternion] objects, using [param component_serializer] to
## serialize each component of the quaternion.
## [br][br]
## Serializes 4 components, size depends on the [param component_serializer].
static func quatt(component_serializer: NetworkSchemaSerializer) -> NetworkSchemaSerializer:
	return _GenericQuaternionSerializer.new(component_serializer)

## Serialize [Quaternion] objects, with each component being a half-precision
## float.
## [br][br]
## This is only supported in Godot 4.4 and up. Earlier versions fall back to
## [method quat32f].
## [br][br]
## Final size is 8 bytes, 16 if using fallback.
static func quatf16() -> NetworkSchemaSerializer:
	return quatt(float16())

## Serialize [Quaternion] objects, with each component being a single-precision
## float.
## [br][br]
## Final size is 16 bytes.
static func quatf32() -> NetworkSchemaSerializer:
	return quatt(float32())

## Serialize [Quaternion] objects, with each component being a double-precision
## float.
## [br][br]
## Final size is 32 bytes.
static func quatf64() -> NetworkSchemaSerializer:
	return quatt(float64())

# Transforms
## Serialize [Transform2D] objects, using [param component_serializer] to
## serialize each component of the transform.
## [br][br]
## Serializes a 2x3 matrix in 6 components, final size depends on [param 
## component_serializer].
static func transform2t(component_serializer: NetworkSchemaSerializer) -> NetworkSchemaSerializer:
	return _GenericTransform2DSerializer.new(component_serializer)

## Serialize [Transform2D] objects, with each component being a half-precision
## float.
## [br][br]
## This is only supported in Godot 4.4 and up. Earlier versions fall back to
## [method transform2f32].
## [br][br]
## Final size is 12 bytes, 24 if using fallback.
static func transform2f16() -> NetworkSchemaSerializer:
	return transform2t(float16())

## Serialize [Transform2D] objects, with each component being a single-precision
## float.
## [br][br]
## Final size is 24 bytes.
static func transform2f32() -> NetworkSchemaSerializer:
	return transform2t(float32())

## Serialize [Transform2D] objects, with each component being a double-precision
## float.
## [br][br]
## Final size is 48 bytes.
static func transform2f64() -> NetworkSchemaSerializer:
	return transform2t(float64())

## Serialize [Transform3D] objects, using [param component_serializer] to
## serialize each component of the transform.
## [br][br]
## Serializes a 3x4 matrix in 12 components, final size depends on [param 
## component_serializer].
static func transform3t(component_serializer: NetworkSchemaSerializer) -> NetworkSchemaSerializer:
	return _GenericTransform3DSerializer.new(component_serializer)
	
## Serialize [Transform3D] objects, with each component being a half-precision
## float.
## [br][br]
## This is only supported in Godot 4.4 and up. Earlier versions fall back to
## [method transform3f32].
## [br][br]
## Final size is 24 bytes, 48 if using fallback.
static func transform3f16() -> NetworkSchemaSerializer:
	return transform3t(float16())

## Serialize [Transform3D] objects, with each component being a single-precision
## float.
## [br][br]
## Final size is 48 bytes.
static func transform3f32() -> NetworkSchemaSerializer:
	return transform3t(float32())

## Serialize [Transform2D] objects, with each component being a double-precision
## float.
## [br][br]
## Final size is 96 bytes.
static func transform3f64() -> NetworkSchemaSerializer:
	return transform3t(float64())

# Collections

## Serialize homogenoeous arrays, using [param item_serializer] to
## serialize each item, and [param size_serializer] to serialize the array's
## size.
## [br][br]
## To serialize heterogenoeous arrays, use [method variant] as the item
## serializer.
## [br][br]
## Final size is [code]sizeof(size_serializer) + array.size() * sizeof(item_serializer)[/code]
static func array_of(item_serializer: NetworkSchemaSerializer = variant(), size_serializer: NetworkSchemaSerializer = uint16()) -> NetworkSchemaSerializer:
	return _ArraySerializer.new(item_serializer, size_serializer)

## Serialize homogenoeous dictionaries, using [param key_serialize] and
## [param value_serializer] to serialize key-value pairs, and
## [param size_serializer] to serialize the number of entries.
## [br][br]
## If either the keys or values are not homogenoeous, use [method variant].
## [br][br]
## Final size is [code]sizeof(size_serializer) + dictionary.size() * (sizeof(key_serializer) + sizeof(value_serializer))[/code]
static func dictionary(key_serializer: NetworkSchemaSerializer = variant(),
	value_serializer: NetworkSchemaSerializer = variant(),
	size_serializer: NetworkSchemaSerializer = uint16()) -> NetworkSchemaSerializer:
	return _DictionarySerializer.new(key_serializer, value_serializer, size_serializer)

# Serializes [_NetworkIdentityReference] objects
static func _netref() -> NetworkSchemaSerializer:
	return _NetworkIdentityReferenceSerializer.new()

# Serializer classes

class _VariantSerializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		b.put_var(v, false)
	
	func decode(b: StreamPeerBuffer) -> Variant:
		return b.get_var(false)

class _StringSerializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		b.put_utf8_string(str(v))

	func decode(b: StreamPeerBuffer) -> Variant:
		return b.get_utf8_string()

class _BoolSerializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		b.put_u8(1 if v else 0)
	
	func decode(b: StreamPeerBuffer) -> Variant:
		return b.get_u8() > 0

class _Uint8Serializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void: b.put_u8(v)
	func decode(b: StreamPeerBuffer) -> Variant: return b.get_u8()

class _Uint16Serializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void: b.put_u16(v)
	func decode(b: StreamPeerBuffer) -> Variant: return b.get_u16()

class _Uint32Serializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void: b.put_u32(v)
	func decode(b: StreamPeerBuffer) -> Variant: return b.get_u32()

class _Uint64Serializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void: b.put_u64(v)
	func decode(b: StreamPeerBuffer) -> Variant: return b.get_u64()

class _Int8Serializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void: b.put_8(v)
	func decode(b: StreamPeerBuffer) -> Variant: return b.get_8()

class _Int16Serializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void: b.put_16(v)
	func decode(b: StreamPeerBuffer) -> Variant: return b.get_16()

class _Int32Serializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void: b.put_32(v)
	func decode(b: StreamPeerBuffer) -> Variant: return b.get_32()

class _Int64Serializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void: b.put_64(v)
	func decode(b: StreamPeerBuffer) -> Variant: return b.get_64()

class _VaruintSerializer extends NetworkSchemaSerializer:
	static var instance := _VaruintSerializer.new()

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		var value := v as int
		for __ in 8:									# Bounded while loop
			var nominator := value & 0b0111_1111		# Grab the lowest 7 bits
			var continuator := value > 0b0111_1111		# Continue if more bits
			var cont_bit := 0b1000_0000 if continuator else 0
			var byte := nominator | cont_bit			# Combine into 1 byte
			value = value >> 7							# Discard lower 7 bits
			b.put_u8(byte)								# Save byte

			# Stop if no more bytes to write
			if not continuator:
				break

	func decode(b: StreamPeerBuffer) -> Variant:
		var value := 0
		for i in 8:
			var byte := b.get_u8()
			var nominator := byte & 0b0111_1111
			var continuator := (byte & 0b1000_0000) != 0
			value += nominator << (i * 7)
			
			if not continuator:
				break
		return value

class _VariableBitsetSerializer extends NetworkSchemaSerializer:
	static var instance := _VariableBitsetSerializer.new()
	
	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		var bitset := v as _Bitset
		if bitset.is_empty():
			b.put_u8(0)
			return

		for i in range(0, bitset.bit_count(), 7):
			var byte := 0

			# Set bits
			if bitset.bit_count() > i + 0 and bitset.get_bit(i + 0): byte |= 0x01
			if bitset.bit_count() > i + 1 and bitset.get_bit(i + 1): byte |= 0x02
			if bitset.bit_count() > i + 2 and bitset.get_bit(i + 2): byte |= 0x04
			if bitset.bit_count() > i + 3 and bitset.get_bit(i + 3): byte |= 0x08
			if bitset.bit_count() > i + 4 and bitset.get_bit(i + 4): byte |= 0x10
			if bitset.bit_count() > i + 5 and bitset.get_bit(i + 5): byte |= 0x20
			if bitset.bit_count() > i + 6 and bitset.get_bit(i + 6): byte |= 0x40
			
			# Set highest bit if there's more bytes to read
			if bitset.bit_count() > i + 7: byte |= 80

			b.put_u8(byte)

	func decode(b: StreamPeerBuffer) -> Variant:
		var bools := []
		
		while true:
			var byte := b.get_u8()
			
			bools.append(byte & 0x01)
			bools.append(byte & 0x02)
			bools.append(byte & 0x04)
			bools.append(byte & 0x08)
			bools.append(byte & 0x10)
			bools.append(byte & 0x20)
			bools.append(byte & 0x40)
			
			# Stop if no more data to read
			if byte & 0x80 == 0:
				break

		return _Bitset.of_bools(bools)

class _Float16Serializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		if Engine.get_version_info().hex >= 0x040400:
			b.put_half(v)
		else:
			b.put_float(v)

	func decode(b: StreamPeerBuffer) -> Variant:
		if Engine.get_version_info().hex >= 0x040400:
			return b.get_half()
		else:
			return b.get_float()

class _Float32Serializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void: b.put_float(v)
	func decode(b: StreamPeerBuffer) -> Variant: return b.get_float()

class _Float64Serializer extends NetworkSchemaSerializer:
	func encode(v: Variant, b: StreamPeerBuffer) -> void: b.put_double(v)
	func decode(b: StreamPeerBuffer) -> Variant: return b.get_double()

class _GenericVec2Serializer extends NetworkSchemaSerializer:
	var component: NetworkSchemaSerializer
	
	func _init(p_component: NetworkSchemaSerializer):
		component = p_component

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		component.encode(v.x, b)
		component.encode(v.y, b)
	
	func decode(b: StreamPeerBuffer) -> Variant:
		return Vector2(component.decode(b), component.decode(b))

class _GenericVec3Serializer extends NetworkSchemaSerializer:
	var component: NetworkSchemaSerializer
	
	func _init(p_component: NetworkSchemaSerializer):
		component = p_component

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		component.encode(v.x, b)
		component.encode(v.y, b)
		component.encode(v.z, b)
	
	func decode(b: StreamPeerBuffer) -> Variant:
		return Vector3(
			component.decode(b), component.decode(b), component.decode(b)
		)

class _Normal2Serializer extends NetworkSchemaSerializer:
	var component: NetworkSchemaSerializer
	
	func _init(p_component: NetworkSchemaSerializer):
		component = p_component

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		component.encode((v as Vector2).angle(), b)
	
	func decode(b: StreamPeerBuffer) -> Variant:
		return Vector2.RIGHT.rotated(component.decode(b))

class _Normal3Serializer extends NetworkSchemaSerializer:
	var component: NetworkSchemaSerializer
	
	func _init(p_component: NetworkSchemaSerializer):
		component = p_component

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		var uv := (v as Vector3).octahedron_encode()
		component.encode(uv.x, b)
		component.encode(uv.y, b)
	
	func decode(b: StreamPeerBuffer) -> Variant:
		return Vector3.octahedron_decode(
			Vector2(component.decode(b), component.decode(b))
		)

class _GenericVec4Serializer extends NetworkSchemaSerializer:
	var component: NetworkSchemaSerializer
	
	func _init(p_component: NetworkSchemaSerializer):
		component = p_component

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		component.encode(v.x, b)
		component.encode(v.y, b)
		component.encode(v.z, b)
		component.encode(v.w, b)
	
	func decode(b: StreamPeerBuffer) -> Variant:
		return Vector4(
			component.decode(b), component.decode(b), component.decode(b), component.decode(b)
		)

class _GenericQuaternionSerializer extends NetworkSchemaSerializer:
	var component: NetworkSchemaSerializer
	
	func _init(p_component: NetworkSchemaSerializer):
		component = p_component

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		component.encode(v.x, b)
		component.encode(v.y, b)
		component.encode(v.z, b)
		component.encode(v.w, b)
	
	func decode(b: StreamPeerBuffer) -> Variant:
		return Quaternion(
			component.decode(b), component.decode(b), component.decode(b), component.decode(b)
		)

class _GenericTransform2DSerializer extends NetworkSchemaSerializer:
	var component: NetworkSchemaSerializer
	
	func _init(p_component: NetworkSchemaSerializer):
		component = p_component

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		var t := v as Transform2D
		
		component.encode(t.x.x, b); component.encode(t.x.y, b)
		component.encode(t.y.x, b); component.encode(t.y.y, b)
		component.encode(t.origin.x, b); component.encode(t.origin.y, b)

	func decode(b: StreamPeerBuffer) -> Variant:
		return Transform2D(
			Vector2(component.decode(b), component.decode(b)),
			Vector2(component.decode(b), component.decode(b)),
			Vector2(component.decode(b), component.decode(b)),
		)

class _GenericTransform3DSerializer extends NetworkSchemaSerializer:
	var component: NetworkSchemaSerializer
	
	func _init(p_component: NetworkSchemaSerializer):
		component = p_component

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		var t := v as Transform3D

		component.encode(t.basis.x.x, b); component.encode(t.basis.x.y, b); component.encode(t.basis.x.z, b)
		component.encode(t.basis.y.x, b); component.encode(t.basis.y.y, b); component.encode(t.basis.y.z, b)
		component.encode(t.basis.z.x, b); component.encode(t.basis.z.y, b); component.encode(t.basis.z.z, b)
		component.encode(t.origin.x, b); component.encode(t.origin.y, b); component.encode(t.origin.z, b)

	func decode(b: StreamPeerBuffer) -> Variant:
		return Transform3D(
			Basis(
				Vector3(component.decode(b), component.decode(b), component.decode(b)),
				Vector3(component.decode(b), component.decode(b), component.decode(b)),
				Vector3(component.decode(b), component.decode(b), component.decode(b)),
			),
			Vector3(component.decode(b), component.decode(b), component.decode(b))
		)

class _QuantizingSerializer extends NetworkSchemaSerializer:
	var component: NetworkSchemaSerializer
	var from_min: Variant
	var from_max: Variant
	var to_min: Variant
	var to_max: Variant
	
	func _init(
		p_component: NetworkSchemaSerializer, p_from_min: Variant,
		p_from_max: Variant, p_to_min: Variant, p_to_max: Variant
	):
		component = p_component
		from_min = p_from_min
		from_max = p_from_max
		to_min = p_to_min
		to_max = p_to_max

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		var f := inverse_lerp(from_min, from_max, v)
		var s := lerp(to_min, to_max, f)
		component.encode(s, b)

	func decode(b: StreamPeerBuffer) -> Variant:
		var s := component.decode(b)
		var f := inverse_lerp(to_min, to_max, s)
		return lerp(from_min, from_max, f)

class _ModuloSerializer extends NetworkSchemaSerializer:
	var component: NetworkSchemaSerializer
	var value_max: Variant
	var component_max: Variant

	func _init(p_component: NetworkSchemaSerializer, p_value_max: Variant, p_component_max: Variant):
		component = p_component
		value_max = p_value_max
		component_max = p_component_max

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		var f = fposmod(float(v), value_max) / value_max
		var s = f * component_max
		component.encode(s, b)

	func decode(b: StreamPeerBuffer) -> Variant:
		var s = float(component.decode(b))
		return (s / component_max) * value_max

class _ArraySerializer extends NetworkSchemaSerializer:
	var component: NetworkSchemaSerializer
	var size: NetworkSchemaSerializer
	
	func _init(p_component: NetworkSchemaSerializer, p_size: NetworkSchemaSerializer):
		component = p_component
		size = p_size
	
	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		var array := v as Array

		size.encode(array.size(), b)
		for item in array:
			component.encode(item, b)
	
	func decode(b: StreamPeerBuffer) -> Variant:
		var array := []
		
		var item_count = size.decode(b)
		array.resize(item_count)
		for i in item_count:
			array[i] = component.decode(b)
		
		return array

class _DictionarySerializer extends NetworkSchemaSerializer:
	var key_serializer: NetworkSchemaSerializer
	var value_serializer: NetworkSchemaSerializer
	var size_serializer: NetworkSchemaSerializer
	
	func _init(p_key_serializer: NetworkSchemaSerializer, p_value_serializer: NetworkSchemaSerializer, p_size_serializer: NetworkSchemaSerializer):
		key_serializer = p_key_serializer
		value_serializer = p_value_serializer
		size_serializer = p_size_serializer
	
	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		var dictionary := v as Dictionary

		size_serializer.encode(dictionary.size(), b)
		for key in dictionary:
			var value = dictionary[key]
			key_serializer.encode(key, b)
			value_serializer.encode(value, b)
	
	func decode(b: StreamPeerBuffer) -> Variant:
		var dictionary := {}
		
		var size = size_serializer.decode(b)
		for i in size:
			var key = key_serializer.decode(b)
			var value = value_serializer.decode(b)
			dictionary[key] = value
		
		return dictionary

class _NetworkIdentityReferenceSerializer extends NetworkSchemaSerializer:
	static var varuint := _VaruintSerializer.new()

	func encode(v: Variant, b: StreamPeerBuffer) -> void:
		var ref := v as _NetworkIdentityReference
		if ref.has_id():
			varuint.encode(ref.get_id(), b)
		else:
			b.put_u8(0)
			# TODO(#562): Get rid of Godot's prepended 32 bits of string length
			# TODO(#562): Write is easy, prefer not manually iterating till \0 on read
			b.put_utf8_string(ref.get_full_name())

	func decode(b: StreamPeerBuffer) -> Variant:
		var id := varuint.decode(b) as int
		if id == 0:
			var full_name := b.get_utf8_string()
			return _NetworkIdentityReference.of_full_name(full_name)
		else:
			return _NetworkIdentityReference.of_id(id)
