blob: ee3a360473e4a91457df5e68898567eae50d2f0a [file] [log] [blame]
module Thrift
module Struct
def initialize(d={})
each_field do |fid, type, name, default|
instance_variable_set("@#{name}", d[name.to_s] || d[name.intern] || default)
end
end
def struct_fields
self.class.const_get(:FIELDS)
end
def each_field
struct_fields.each do |fid, data|
yield fid, data[:type], data[:name], data[:default]
end
end
def read(iprot)
iprot.read_struct_begin()
loop do
fname, ftype, fid = iprot.read_field_begin()
break if (ftype === Types::STOP)
handle_message(iprot, fid, ftype)
iprot.read_field_end()
end
iprot.read_struct_end()
end
def write(oprot)
oprot.write_struct_begin(self.class.name)
each_field do |fid, type, name|
if ((value = instance_variable_get("@#{name}")) != nil)
if is_container? type
oprot.write_field_begin(name, type, fid)
write_container(oprot, value, struct_fields[fid])
oprot.write_field_end
else
oprot.write_field(name, type, fid, value)
end
end
end
oprot.write_field_stop()
oprot.write_struct_end()
end
protected
def handle_message(iprot, fid, ftype)
field = struct_fields[fid]
if field && field[:type] == ftype
value = read_field(iprot, field)
instance_variable_set("@#{field[:name]}", value)
else
iprot.skip(ftype)
end
end
def read_field(iprot, field = {})
if field[:type] == Types::STRUCT
value = field[:class].new
value.read(iprot)
elsif field[:type] == Types::MAP
key_type, val_type, size = iprot.readMapBegin
value = {}
size.times do
k = read_field(iprot, field_info(field[:key]))
v = read_field(iprot, field_info(field[:value]))
value[k] = v
end
iprot.readMapEnd
elsif field[:type] == Types::LIST
e_type, size = iprot.readListBegin
value = Array.new(size) do |n|
read_field(iprot, field_info(field[:element]))
end
iprot.readListEnd
elsif field[:type] == Types::SET
e_type, size = iprot.readSetBegin
value = {}
size.times do
element = read_field(iprot, field_info(field[:element]))
value[element] = true
end
iprot.readSetEnd
else
value = iprot.read_type(field[:type])
end
value
end
def write_data(oprot, value, field)
if is_container? field[:type]
write_container(oprot, value, field)
else
oprot.write_type(field[:type], value)
end
end
def write_container(oprot, value, field = {})
if field[:type] == Types::MAP
oprot.write_map_begin(field[:key][:type], field[:value][:type], value.size)
value.each do |k, v|
write_data(oprot, k, field[:key])
write_data(oprot, v, field[:value])
end
oprot.write_map_end
elsif field[:type] == Types::LIST
oprot.write_list_begin(field[:element][:type], value.size)
value.each do |elem|
write_data(oprot, elem, field[:element])
end
oprot.write_list_end
elsif field[:type] == Types::SET
oprot.write_set_begin(field[:element][:type], value.size)
value.each do |k, v|
write_data(oprot, k, field[:element])
end
oprot.write_set_end
else
raise "Not a container type: #{field[:type]}"
end
end
def is_container?(type)
[Types::LIST, Types::MAP, Types::SET].include? type
end
def field_info(field)
{ :type => field[:type],
:class => field[:class],
:key => field[:key],
:value => field[:value],
:element => field[:element] }
end
end
deprecate_class! :ThriftStruct => Struct
end