Skip to content

Instantly share code, notes, and snippets.

@snluu
Created March 12, 2022 16:53
Show Gist options
  • Save snluu/1efe97038a0fdb44c6e0bb73dd18fe58 to your computer and use it in GitHub Desktop.
Save snluu/1efe97038a0fdb44c6e0bb73dd18fe58 to your computer and use it in GitHub Desktop.
require "common"
require "./types"
require "./serializer"
require "./annotations"
macro rpc_object(name, &block)
class {{name}}
extend TxtRPC::Object
extend BuilderPattern
{{ yield }}
end
end
# Define getter and setter for an RPC property.
macro rpc_property(position, name, property_type)
@[TxtRPC::Annotations::RPCProperty(position: {{position}}_i64, property_type: {{property_type}})]
property {{name}} : {{property_type}}
end
module TxtRPC::Object
macro extended
def initialize
{% verbatim do %}
{% for m in @type.instance_vars %}
{% if ann = m.annotation(TxtRPC::Annotations::RPCProperty) %}
@{{m.name}} = {{ann[:property_type]}}.rpc_default
{% end %}
{% end %}
{% end %}
end
def shallow_copy
copy = new()
{% verbatim do %}
{% for m in @type.instance_vars %}
{% if ann = m.annotation(TxtRPC::Annotations::RPCProperty) %}
copy.{{m.name}} = @{{m.name}}
{% end %}
{% end %}
{% end %}
return copy
end
def rpc_serialize
{% verbatim do %}
{% begin %}
{% field_count = 0 %}
{% for m in @type.instance_vars %}
{% if ann = m.annotation(TxtRPC::Annotations::RPCProperty) %}
{% field_count = field_count + 1 %}
{% end %}
{% end %}
String.build 512 do |b|
b << 'O'
b << {{field_count}}
b << "\n"
{% for m in @type.instance_vars %}
{% if ann = m.annotation(TxtRPC::Annotations::RPCProperty) %}
b << {{ann[:position]}}.rpc_serialize('p') # property
b << {{m.name}}.rpc_serialize
{% end %}
{% end %}
end
{% end %}
{% end %}
end
def self.rpc_deserialize(input : Bytes) : {self, BytesRead}
{% verbatim do %}
{% begin %}
{% type_field_count = 0 %}
{% for m in @type.instance_vars %}
{% if ann = m.annotation(TxtRPC::Annotations::RPCProperty) %}
{% type_field_count = type_field_count + 1 %}
{% end %}
{% end %}
ret = new()
pos = 0
{% if type_field_count > 0 %}
field_count, pos = Int64.rpc_deserialize(input, 'O')
field_count.times do
field_position, bytes_read = Int64.rpc_deserialize(input[pos..], 'p')
pos += bytes_read
case field_position
{% for m in @type.instance_vars %}
{% if ann = m.annotation(TxtRPC::Annotations::RPCProperty) %}
when {{ann[:position]}}
# puts "Deserializing {{m.name}}"
# puts "Input: #{String.new(input[pos..]).inspect_unquoted}"
val, bytes_read = {{ann[:property_type]}}.rpc_deserialize(input[pos..])
pos += bytes_read
ret.{{m.name}} = val
# puts "{{m.name}} = #{val}"
{% end %}
{% end %}
else
# puts "Unrecognized field position #{field_position}"
pos += TxtRPC.deserialize_discard(input[pos..])
end
end
{% end %} # end if
return {ret, pos}
{% end %} # end begin
{% end %} # end verbatim
end
def self.from_rpc(input : String) : self
ret, _ = rpc_deserialize(input.to_slice)
return ret
end
def self.rpc_default : self
new
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment