Class: Protobug::Field

Inherits:
Object
  • Object
show all
Defined in:
lib/protobug/field.rb

Defined Under Namespace

Classes: BoolField, BytesField, DoubleField, EnumField, Fixed32Field, Fixed64Field, FloatField, GroupField, Int32Field, Int64Field, IntegerField, MapField, MessageField, SFixed32Field, SFixed64Field, SInt32Field, SInt64Field, StringField, UInt32Field, UInt64Field

Constant Summary collapse

PACKABLE_WIRE_TYPES =
[0, 1, 5].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(number, name, json_name: nil, cardinality: :optional, oneof: nil, packed: false, proto3_optional: cardinality == :optional) ⇒ Field

Returns a new instance of Field.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/protobug/field.rb', line 12

def initialize(number, name, json_name: nil, cardinality: :optional, oneof: nil, packed: false,
               proto3_optional: cardinality == :optional)
  @number = number
  @name = name.to_sym
  @json_name = json_name || name.to_s
  @cardinality = cardinality || raise(ArgumentError, "cardinality is required")
  @oneof = oneof
  @setter = :"#{name}="
  @adder = :"add_#{name}" if repeated?
  @ivar = :"@#{name}"
  @clearer = :"clear_#{name}"
  @haser = :"#{name}?"
  @packed = packed
  @proto3_optional = proto3_optional
end

Instance Attribute Details

#adderObject

Returns the value of attribute adder.



9
10
11
# File 'lib/protobug/field.rb', line 9

def adder
  @adder
end

#cardinalityObject

Returns the value of attribute cardinality.



9
10
11
# File 'lib/protobug/field.rb', line 9

def cardinality
  @cardinality
end

#clearerObject

Returns the value of attribute clearer.



9
10
11
# File 'lib/protobug/field.rb', line 9

def clearer
  @clearer
end

#haserObject

Returns the value of attribute haser.



9
10
11
# File 'lib/protobug/field.rb', line 9

def haser
  @haser
end

#ivarObject

Returns the value of attribute ivar.



9
10
11
# File 'lib/protobug/field.rb', line 9

def ivar
  @ivar
end

#json_nameObject

Returns the value of attribute json_name.



9
10
11
# File 'lib/protobug/field.rb', line 9

def json_name
  @json_name
end

#nameObject

Returns the value of attribute name.



9
10
11
# File 'lib/protobug/field.rb', line 9

def name
  @name
end

#numberObject

Returns the value of attribute number.



9
10
11
# File 'lib/protobug/field.rb', line 9

def number
  @number
end

#oneofObject

Returns the value of attribute oneof.



9
10
11
# File 'lib/protobug/field.rb', line 9

def oneof
  @oneof
end

#setterObject

Returns the value of attribute setter.



9
10
11
# File 'lib/protobug/field.rb', line 9

def setter
  @setter
end

Instance Method Details

#adder_method_definition(str) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/protobug/field.rb', line 104

def adder_method_definition(str)
  str << "def #{adder}(value)\n"
  str << "  existing = #{ivar}\n"
  str << "  field = self.class.fields_by_name.fetch(#{name.to_s.dump})\n"
  str << "  if ::Protobug::UNSET == existing\n"
  str << "    existing = field.default\n"
  str << "    #{ivar} = existing\n"
  str << "  end\n"
  str << "  field.validate!(value, self)\n"
  str << "  existing << value\n"
  str << "end\n"
end

#binary_decode(binary, message, registry, wire_type) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/protobug/field.rb', line 148

def binary_decode(binary, message, registry, wire_type)
  own_wire_type = self.wire_type
  if repeated? && wire_type == 2 && PACKABLE_WIRE_TYPES.include?(own_wire_type)
    len = StringIO.new(BinaryEncoding.decode_length(binary))
    len.binmode

    message.send(adder, binary_decode_one(len, message, registry, own_wire_type)) until len.eof?
  elsif wire_type != own_wire_type
    raise DecodeError, "wrong wire type for #{self}: #{wire_type.inspect}"
  else
    message.send(adder || setter, binary_decode_one(binary, message, registry, wire_type))
  end
end

#binary_encode(value, outbuf) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/protobug/field.rb', line 130

def binary_encode(value, outbuf)
  if repeated?
    if packed?
      binary_encode_packed(value, outbuf)
    else
      value.each do |v|
        BinaryEncoding.encode_varint (number << 3) | wire_type, outbuf
        binary_encode_one(v, outbuf)
      end
    end
  elsif (!optional? || !proto3_optional?) && !oneof && default == value
    # omit
  else
    BinaryEncoding.encode_varint (number << 3) | wire_type, outbuf
    binary_encode_one(value, outbuf)
  end
end

#json_decode(value, message, ignore_unknown_fields, registry) ⇒ Object



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/protobug/field.rb', line 187

def json_decode(value, message, ignore_unknown_fields, registry)
  if repeated?
    return if value.nil?

    unless value.is_a?(Array)
      raise DecodeError,
            "expected Array for #{inspect}, got #{value.inspect}"
    end

    value.map do |v|
      message.send(adder, json_decode_one(v, ignore_unknown_fields, registry))
    end
  else
    value = json_decode_one(value, ignore_unknown_fields, registry)
    message.send(setter, value) unless UNSET == value
  end
end

#json_encode(value, print_unknown_fields:) ⇒ Object



162
163
164
165
166
167
168
169
170
# File 'lib/protobug/field.rb', line 162

def json_encode(value, print_unknown_fields:)
  if repeated?
    value.map { |v| json_encode_one(v, print_unknown_fields: print_unknown_fields) }
  elsif (!optional? || !proto3_optional?) && !oneof && default == value
    # omit
  else
    json_encode_one(value, print_unknown_fields: print_unknown_fields)
  end
end

#json_key_encode(value) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/protobug/field.rb', line 172

def json_key_encode(value)
  case value
  when String
    value
  when Integer, Float
    value.to_s
  when TrueClass
    "true"
  when FalseClass
    "false"
  else
    raise EncodeError, "unexpected type for map key: #{value.inspect}"
  end
end

#method_definitionsObject



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/protobug/field.rb', line 66

def method_definitions
  str = +""

  str << "def #{setter}(value)\n"
  str << "  return #{ivar} = ::Protobug::UNSET if value.nil?\n" if optional? && proto3_optional?
  str << "  field = self.class.fields_by_name.fetch(#{name.to_s.dump})\n"
  str << "  field.validate!(value, self)\n"
  str << "  #{ivar} = value\n"
  str << "end\n"

  str << "def #{name}\n"
  str << "  value = #{ivar}\n"
  str << "  ::Protobug::UNSET == value ? self.class.fields_by_name.fetch(#{name.to_s.dump}).default : value\n"
  str << "end\n"

  str << "def #{haser}\n"
  str << "  value = #{ivar}\n"
  str << "  return false if ::Protobug::UNSET == value\n"
  if (!optional? || !proto3_optional?) && !oneof
    str << "  field = self.class.fields_by_name.fetch(#{name.to_s.dump})\n"
    str << "  return false if field.default == value\n"
  end
  str << if repeated?
           "  !value.empty?\n"
         else
           "  true\n"
         end
  str << "end\n"

  str << "def #{clearer}\n"
  str << "  #{ivar} = ::Protobug::UNSET\n"
  str << "end\n"

  adder_method_definition(str) if repeated?

  str
end

#optional?Boolean

Returns:

  • (Boolean)


58
59
60
# File 'lib/protobug/field.rb', line 58

def optional?
  cardinality == :optional
end

#packed?Boolean

Returns:

  • (Boolean)


54
55
56
# File 'lib/protobug/field.rb', line 54

def packed?
  @packed
end

#pretty_print(pp) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/protobug/field.rb', line 28

def pretty_print(pp)
  pp.group 0, "#{self.class}.new(", ")" do
    pp.text @number.to_s
    pp.breakable(", ")
    pp.text(@name.inspect)
    pp.breakable(", ")
    if json_name != name.name
      pp.breakable(", ")
      pp.text("json_name: ")
      pp.text(@json_name.inspect)
    end
    pp.breakable(", ")
    pp.text("cardinality: ")
    pp.pp(@cardinality)
    if oneof
      pp.breakable(", ")
      pp.text("oneof: ")
      pp.text(@oneof.inspect)
    end
  end
end

#proto3_optional?Boolean

Returns:

  • (Boolean)


62
63
64
# File 'lib/protobug/field.rb', line 62

def proto3_optional?
  @proto3_optional
end

#repeated?Boolean

Returns:

  • (Boolean)


50
51
52
# File 'lib/protobug/field.rb', line 50

def repeated?
  cardinality == :repeated
end

#to_text(value) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/protobug/field.rb', line 117

def to_text(value)
  case [cardinality, json_scalar?]
  when [:repeated, true]
    Array(value).map { |v| "#{name}: #{scalar_to_text(v)}" }.join("\n")
  when [:repeated, false]
    Array(value).map { |v| "#{name} {\n#{v.to_text.gsub(/^/, "  ")}\n}" }.join("\n")
  when [:optional, true]
    "#{name}: #{scalar_to_text(value)}"
  when [:optional, false]
    "#{name} {\n#{value.to_text.gsub(/^/, "  ")}\n}"
  end
end

#validate!(value, message) ⇒ Object

Raises:



205
206
207
208
209
210
211
212
213
214
215
# File 'lib/protobug/field.rb', line 205

def validate!(value, message)
  raise DecodeError, "nil is invalid for #{name} in #{message}" if UNSET == value

  return unless oneof

  message.class.oneofs[oneof].each do |f|
    next if f == self

    message.send(f.clearer)
  end
end