Rev 30 | Blame | Compare with Previous | Last modification | View Log | RSS feed
## Licensed to the Apache Software Foundation (ASF) under one# or more contributor license agreements. See the NOTICE file# distributed with this work for additional information# regarding copyright ownership. The ASF licenses this file# to you under the Apache License, Version 2.0 (the# "License"); you may not use this file except in compliance# with the License. You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing,# software distributed under the License is distributed on an# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY# KIND, either express or implied. See the License for the# specific language governing permissions and limitations# under the License.#require 'set'module Thriftmodule Structdef initialize(d={})# get a copy of the default values to work on, removing defaults in favor of argumentsfields_with_defaults = fields_with_default_values.dup# check if the defaults is empty, or if there are no parameters for this# instantiation, and if so, don't bother overriding defaults.unless fields_with_defaults.empty? || d.empty?d.each_key do |name|fields_with_defaults.delete(name.to_s)endend# assign all the user-specified argumentsunless d.empty?d.each do |name, value|unless name_to_id(name.to_s)raise Exception, "Unknown key given to #{self.class}.new: #{name}"endThrift.check_type(value, struct_fields[name_to_id(name.to_s)], name) if Thrift.type_checkinginstance_variable_set("@#{name}", value)endend# assign all the default valuesunless fields_with_defaults.empty?fields_with_defaults.each do |name, default_value|instance_variable_set("@#{name}", (default_value.dup rescue default_value))endendenddef fields_with_default_valuesfields_with_default_values = self.class.instance_variable_get("@fields_with_default_values")unless fields_with_default_valuesfields_with_default_values = {}struct_fields.each do |fid, field_def|unless field_def[:default].nil?fields_with_default_values[field_def[:name]] = field_def[:default]endendself.class.instance_variable_set("@fields_with_default_values", fields_with_default_values)endfields_with_default_valuesenddef name_to_id(name)names_to_ids = self.class.instance_variable_get("@names_to_ids")unless names_to_idsnames_to_ids = {}struct_fields.each do |fid, field_def|names_to_ids[field_def[:name]] = fidendself.class.instance_variable_set("@names_to_ids", names_to_ids)endnames_to_ids[name]enddef each_fieldstruct_fields.keys.sort.each do |fid|data = struct_fields[fid]yield fid, dataendenddef inspect(skip_optional_nulls = true)fields = []each_field do |fid, field_info|name = field_info[:name]value = instance_variable_get("@#{name}")unless skip_optional_nulls && field_info[:optional] && value.nil?fields << "#{name}:#{value.inspect}"endend"<#{self.class} #{fields.join(", ")}>"enddef read(iprot)iprot.read_struct_beginloop dofname, ftype, fid = iprot.read_field_beginbreak if (ftype == Types::STOP)handle_message(iprot, fid, ftype)iprot.read_field_endendiprot.read_struct_endvalidateenddef write(oprot)validateoprot.write_struct_begin(self.class.name)each_field do |fid, field_info|name = field_info[:name]type = field_info[:type]if (value = instance_variable_get("@#{name}"))if is_container? typeoprot.write_field_begin(name, type, fid)write_container(oprot, value, field_info)oprot.write_field_endelseoprot.write_field(name, type, fid, value)endendendoprot.write_field_stopoprot.write_struct_endenddef ==(other)each_field do |fid, field_info|name = field_info[:name]return false unless self.instance_variable_get("@#{name}") == other.instance_variable_get("@#{name}")endtrueenddef eql?(other)self.class == other.class && self == otherenddef hashfield_values = []each_field do |fid, field_info|name = field_info[:name]field_values << self.instance_variable_get("@#{name}")endfield_values.hashenddef differences(other)diffs = []unless other.is_a?(self.class)diffs << "Different class!"elseeach_field do |fid, field_info|name = field_info[:name]diffs << "#{name} differs!" unless self.instance_variable_get("@#{name}") == other.instance_variable_get("@#{name}")endenddiffsenddef self.field_accessor(klass, *fields)fields.each do |field|klass.send :attr_reader, fieldklass.send :define_method, "#{field}=" do |value|Thrift.check_type(value, klass::FIELDS.values.find { |f| f[:name].to_s == field.to_s }, field) if Thrift.type_checkinginstance_variable_set("@#{field}", value)endendendprotecteddef self.append_features(mod)if mod.ancestors.include? ::Exceptionmod.send :class_variable_set, :'@@__thrift_struct_real_initialize', mod.instance_method(:initialize)super# set up our custom initializer so `raise Xception, 'message'` worksmod.send :define_method, :struct_initialize, mod.instance_method(:initialize)mod.send :define_method, :initialize, mod.instance_method(:exception_initialize)elsesuperendenddef exception_initialize(*args, &block)if args.size == 1 and args.first.is_a? Hash# looks like it's a regular Struct initializemethod(:struct_initialize).call(args.first)else# call the Struct initializer first with no args# this will set our field default valuesmethod(:struct_initialize).call()# now give it to the exceptionself.class.send(:class_variable_get, :'@@__thrift_struct_real_initialize').bind(self).call(*args, &block) if args.size > 0# self.class.instance_method(:initialize).bind(self).call(*args, &block)endenddef handle_message(iprot, fid, ftype)field = struct_fields[fid]if field and field[:type] == ftypevalue = read_field(iprot, field)instance_variable_set("@#{field[:name]}", value)elseiprot.skip(ftype)endenddef read_field(iprot, field = {})case field[:type]when Types::STRUCTvalue = field[:class].newvalue.read(iprot)when Types::MAPkey_type, val_type, size = iprot.read_map_beginvalue = {}size.times dok = read_field(iprot, field_info(field[:key]))v = read_field(iprot, field_info(field[:value]))value[k] = vendiprot.read_map_endwhen Types::LISTe_type, size = iprot.read_list_beginvalue = Array.new(size) do |n|read_field(iprot, field_info(field[:element]))endiprot.read_list_endwhen Types::SETe_type, size = iprot.read_set_beginvalue = Set.newsize.times doelement = read_field(iprot, field_info(field[:element]))value << elementendiprot.read_set_endelsevalue = iprot.read_type(field[:type])endvalueenddef write_data(oprot, value, field)if is_container? field[:type]write_container(oprot, value, field)elseoprot.write_type(field[:type], value)endenddef write_container(oprot, value, field = {})case field[:type]when Types::MAPoprot.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])endoprot.write_map_endwhen Types::LISToprot.write_list_begin(field[:element][:type], value.size)value.each do |elem|write_data(oprot, elem, field[:element])endoprot.write_list_endwhen Types::SEToprot.write_set_begin(field[:element][:type], value.size)value.each do |v,| # the , is to preserve compatibility with the old Hash-style setswrite_data(oprot, v, field[:element])endoprot.write_set_endelseraise "Not a container type: #{field[:type]}"endendCONTAINER_TYPES = []CONTAINER_TYPES[Types::LIST] = trueCONTAINER_TYPES[Types::MAP] = trueCONTAINER_TYPES[Types::SET] = truedef is_container?(type)CONTAINER_TYPES[type]enddef field_info(field){ :type => field[:type],:class => field[:class],:key => field[:key],:value => field[:value],:element => field[:element] }endendend