ruby-dbus 0.18.0.beta3 → 0.18.0.beta6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/dbus/type.rb CHANGED
@@ -29,14 +29,12 @@ module DBus
29
29
  # For documentation purposes only.
30
30
  class Prototype < String; end
31
31
 
32
- # = D-Bus type module
33
- #
34
- # This module containts the constants of the types specified in the D-Bus
35
- # protocol.
32
+ # Represents the D-Bus types.
36
33
  #
37
34
  # Corresponds to {SingleCompleteType}.
35
+ # Instances are immutable/frozen once fully constructed.
38
36
  #
39
- # See also {DBus::Data::Signature}
37
+ # See also {DBus::Data::Signature} which is "type on the wire".
40
38
  class Type
41
39
  # Mapping from type number to name and alignment.
42
40
  TYPE_MAPPING = {
@@ -104,8 +102,32 @@ module DBus
104
102
  end
105
103
  end
106
104
 
107
- @sigtype = sigtype
108
- @members = []
105
+ @sigtype = sigtype.freeze
106
+ @members = [] # not frozen yet, Parser#parse_one or Factory will do it
107
+ freeze
108
+ end
109
+
110
+ # A Type is equal to
111
+ # - another Type with the same string representation
112
+ # - a String ({SingleCompleteType}) describing the type
113
+ def ==(other)
114
+ case other
115
+ when ::String
116
+ to_s == other
117
+ else
118
+ eql?(other)
119
+ end
120
+ end
121
+
122
+ # A Type is eql? to
123
+ # - another Type with the same string representation
124
+ #
125
+ # Hash key equality
126
+ # See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F
127
+ def eql?(other)
128
+ return false unless other.is_a?(Type)
129
+
130
+ @sigtype == other.sigtype && @members == other.members
109
131
  end
110
132
 
111
133
  # Return the required alignment for the type.
@@ -124,16 +146,15 @@ module DBus
124
146
  when DICT_ENTRY
125
147
  "{#{@members.collect(&:to_s).join}}"
126
148
  else
127
- if !TYPE_MAPPING.keys.member?(@sigtype)
128
- raise NotImplementedError
129
- end
130
-
131
149
  @sigtype.chr
132
150
  end
133
151
  end
134
152
 
135
153
  # Add a new member type _item_.
154
+ # @param item [Type]
136
155
  def <<(item)
156
+ raise ArgumentError unless item.is_a?(Type)
157
+
137
158
  if ![STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
138
159
  raise SignatureException
139
160
  end
@@ -159,7 +180,7 @@ module DBus
159
180
 
160
181
  def inspect
161
182
  s = TYPE_MAPPING[@sigtype].first
162
- if [STRUCT, ARRAY].member?(@sigtype)
183
+ if [STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
163
184
  s += ": #{@members.inspect}"
164
185
  end
165
186
  s
@@ -232,6 +253,7 @@ module DBus
232
253
  else
233
254
  res = Type.new(char)
234
255
  end
256
+ res.members.freeze
235
257
  res
236
258
  end
237
259
 
@@ -243,7 +265,7 @@ module DBus
243
265
  while (c = nextchar)
244
266
  ret << parse_one(c)
245
267
  end
246
- ret
268
+ ret.freeze
247
269
  end
248
270
 
249
271
  # Parse one {SingleCompleteType}
@@ -255,9 +277,116 @@ module DBus
255
277
  t = parse_one(c)
256
278
  raise SignatureException, "Has more than a Single Complete Type: #{@signature}" unless nextchar.nil?
257
279
 
280
+ t.freeze
281
+ end
282
+ end
283
+
284
+ class Factory
285
+ # @param type [Type,SingleCompleteType,Class]
286
+ # @see from_plain_class
287
+ # @return [Type] (frozen)
288
+ def self.make_type(type)
289
+ case type
290
+ when Type
291
+ type
292
+ when String
293
+ DBus.type(type)
294
+ when Class
295
+ from_plain_class(type)
296
+ else
297
+ msg = "Expecting DBus::Type, DBus::SingleCompleteType(aka ::String), or Class, got #{type.inspect}"
298
+ raise ArgumentError, msg
299
+ end
300
+ end
301
+
302
+ # Make a {Type} corresponding to some plain classes:
303
+ # - String
304
+ # - Float
305
+ # - DBus::ObjectPath
306
+ # - DBus::Signature, DBus::SingleCompleteType
307
+ # @param klass [Class]
308
+ # @return [Type] (frozen)
309
+ def self.from_plain_class(klass)
310
+ @signature_type ||= DBus.type(SIGNATURE)
311
+ @class_to_type ||= {
312
+ DBus::ObjectPath => DBus.type(OBJECT_PATH),
313
+ DBus::Signature => @signature_type,
314
+ DBus::SingleCompleteType => @signature_type,
315
+ String => DBus.type(STRING),
316
+ Float => DBus.type(DOUBLE)
317
+ }
318
+ t = @class_to_type[klass]
319
+ raise ArgumentError, "Cannot convert plain class #{klass} to a D-Bus type" if t.nil?
320
+
258
321
  t
259
322
  end
260
323
  end
324
+
325
+ # Syntactic helper for constructing an array Type.
326
+ # You may be looking for {Data::Array} instead.
327
+ # @example
328
+ # t = Type::Array[Type::INT16]
329
+ class ArrayFactory < Factory
330
+ # @param member_type [Type,SingleCompleteType]
331
+ # @return [Type] (frozen)
332
+ def self.[](member_type)
333
+ t = Type.new(ARRAY)
334
+ t << make_type(member_type)
335
+ t.members.freeze
336
+ t
337
+ end
338
+ end
339
+
340
+ # @example
341
+ # t = Type::Array[Type::INT16]
342
+ Array = ArrayFactory
343
+
344
+ # Syntactic helper for constructing a hash Type.
345
+ # You may be looking for {Data::Array} and {Data::DictEntry} instead.
346
+ # @example
347
+ # t = Type::Hash[Type::STRING, Type::VARIANT]
348
+ class HashFactory < Factory
349
+ # @param key_type [Type,SingleCompleteType]
350
+ # @param value_type [Type,SingleCompleteType]
351
+ # @return [Type] (frozen)
352
+ def self.[](key_type, value_type)
353
+ t = Type.new(ARRAY)
354
+ de = Type.new(DICT_ENTRY, abstract: true)
355
+ de << make_type(key_type)
356
+ de << make_type(value_type)
357
+ de.members.freeze
358
+ t << de
359
+ t.members.freeze
360
+ t
361
+ end
362
+ end
363
+
364
+ # @example
365
+ # t = Type::Hash[Type::INT16]
366
+ Hash = HashFactory
367
+
368
+ # Syntactic helper for constructing a struct Type.
369
+ # You may be looking for {Data::Struct} instead.
370
+ # @example
371
+ # t = Type::Struct[Type::INT16, Type::STRING]
372
+ class StructFactory < Factory
373
+ # @param member_types [::Array<Type,SingleCompleteType>]
374
+ # @return [Type] (frozen)
375
+ def self.[](*member_types)
376
+ raise ArgumentError if member_types.empty?
377
+
378
+ t = Type.new(STRUCT, abstract: true)
379
+ member_types.each do |mt|
380
+ t << make_type(mt)
381
+ end
382
+ t.members.freeze
383
+ t
384
+ end
385
+ end
386
+
387
+ # @example
388
+ # t = Type::Struct[Type::INT16, Type::STRING]
389
+ Struct = StructFactory
261
390
  end
262
391
 
263
392
  # shortcuts
@@ -266,7 +395,7 @@ module DBus
266
395
  # This is prefered to {Type#initialize} which allows
267
396
  # incomplete or invalid types.
268
397
  # @param string_type [SingleCompleteType]
269
- # @return [DBus::Type]
398
+ # @return [DBus::Type] (frozen)
270
399
  # @raise SignatureException
271
400
  def type(string_type)
272
401
  Type::Parser.new(string_type).parse1
@@ -275,7 +404,7 @@ module DBus
275
404
 
276
405
  # Parse a String to zero or more {DBus::Type}s.
277
406
  # @param string_type [Signature]
278
- # @return [Array<DBus::Type>]
407
+ # @return [Array<DBus::Type>] (frozen)
279
408
  # @raise SignatureException
280
409
  def types(string_type)
281
410
  Type::Parser.new(string_type).parse
@@ -1534,6 +1534,34 @@
1534
1534
  - [0xDE, 0xAD, 0xBE, 0xEF]
1535
1535
  exc: DBus::InvalidPacketException
1536
1536
  msg: ''
1537
+ - sig: a{oq}
1538
+ end: little
1539
+ buf:
1540
+ # body size
1541
+ - [0, 0, 0, 0]
1542
+ # padding
1543
+ - [0, 0, 0, 0]
1544
+ val: {}
1545
+ - sig: a{oq}
1546
+ end: little
1547
+ buf:
1548
+ # body size
1549
+ - [26, 0, 0, 0]
1550
+ # dict_entry padding
1551
+ - [0, 0, 0, 0]
1552
+ # key, padding, value
1553
+ - [2, 0, 0, 0, "/7", 0]
1554
+ - 0
1555
+ - [7, 0]
1556
+ # dict_entry padding
1557
+ - [0, 0, 0, 0, 0, 0]
1558
+ # key, padding, value
1559
+ - [2, 0, 0, 0, "/9", 0]
1560
+ - 0
1561
+ - [9, 0]
1562
+ val:
1563
+ /7: 7
1564
+ /9: 9
1537
1565
  - sig: "(qq)"
1538
1566
  end: little
1539
1567
  buf: