capnp 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 71ef797c99d9b126f104b4d4ea36c776ca8dd870d6fc721314710e8e74b7f133
4
+ data.tar.gz: 96cba73c43bd3d9656f88c21a9c7b745bac8cdeb66cee4ba84ad90ba63bdf573
5
+ SHA512:
6
+ metadata.gz: 284eefe7ac8c07d0eb9c390d2efdeef4d26464a095b13d87aa568c8da35c5ffb228d2a33e078769fe526861782de066281ca5d6405e30d63657a64416fd3b805
7
+ data.tar.gz: 9726a5775467dd15e6d2455de023d5d7743a59c6475564b63e3903edb130161883bc6cdc3825820fa969db93477b3ec90502909c52168cfad94fb679eb635ffd
data/bin/capnpc-ruby ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # typed: strict
3
+
4
+ require "capnp"
5
+ require "capnp/generator"
6
+
7
+ begin
8
+ buffer = Capnp::IOBuffer.new(IO::Buffer.for(STDIN.read))
9
+ message = Capnp::StreamMessage.new(buffer)
10
+ generator = Capnp::Generator.new(message.root)
11
+ generator.generate
12
+ rescue => e
13
+ warn "#{e.class}: #{e.message}"
14
+ e.backtrace.to_a.reject { |line| line.include?("/gems/sorbet-runtime-") }.each { |line| warn(line) }
15
+ end
@@ -0,0 +1,568 @@
1
+ # typed: strict
2
+
3
+ require "sorbet-runtime"
4
+ require "capnp"
5
+ require_relative "schema.capnp"
6
+
7
+ class Capnp::Generator
8
+ extend T::Sig
9
+
10
+ sig { params(request_ref: Capnp::Reference).void }
11
+ def initialize(request_ref)
12
+ request = Schema::CodeGeneratorRequest.from_pointer(request_ref)
13
+ raise "Invalid CodeGeneratorRequest" if request.nil?
14
+
15
+ nodes = request.nodes
16
+ raise "No nodes found" if nodes.nil?
17
+
18
+ requested_files = request.requested_files
19
+ raise "No requested files found" if requested_files.nil?
20
+
21
+ requested_file_ids = requested_files.map(&:id)
22
+
23
+ # Build a hash of nodes by id and gather all requested file nodes
24
+ @nodes_by_id = T.let({}, T::Hash[Integer, Schema::Node])
25
+ @files = T.let([], T::Array[Schema::Node])
26
+ nodes.each do |node|
27
+ @nodes_by_id[node.id] = node
28
+ if node.is_file? && requested_file_ids.include?(node.id)
29
+ @files << node
30
+ end
31
+ end
32
+
33
+ # Gather all nodes that will become classes
34
+ @node_to_class_path = T.let({}, T::Hash[Integer, T::Array[String]])
35
+ @files.each do |file|
36
+ name = file_to_module_name(file)
37
+ @node_to_class_path.merge!(find_classes(file, [name]))
38
+ end
39
+ end
40
+
41
+ sig { params(node: Schema::Node, path: T::Array[String]).returns(T::Hash[Integer, T::Array[String]]) }
42
+ def find_classes(node, path)
43
+ # Skip constants and annotations
44
+ return {} if node.is_const? || node.is_annotation?
45
+
46
+ result = T.let({node.id => path}, T::Hash[Integer, T::Array[String]])
47
+
48
+ nested_nodes = node.nested_nodes
49
+ return result if nested_nodes.nil?
50
+
51
+ # Recurse into nested nodes
52
+ nested_nodes.each do |nestednode|
53
+ name = nestednode.name&.to_s
54
+ raise "Node without a name" if name.nil?
55
+
56
+ new_path = path + [name]
57
+ result.merge!(find_classes(@nodes_by_id.fetch(nestednode.id), new_path))
58
+ end
59
+
60
+ result
61
+ end
62
+
63
+ # Convert from camelCase to CapitalCase
64
+ sig { params(name: String).returns(String) }
65
+ def class_name(name) = "#{name[0]&.upcase}#{name[1..]}"
66
+
67
+ # Convert from camelCase to snake_case
68
+ sig { params(name: String).returns(String) }
69
+ def method_name(name) = name.gsub(/([^A-Z])([A-Z]+)/, '\1_\2').downcase
70
+
71
+ # Convert from camelCase to SCREAMING_SNAKE_CASE
72
+ sig { params(name: String).returns(String) }
73
+ def const_name(name) = name.gsub(/([^A-Z])([A-Z]+)/, '\1_\2').upcase
74
+
75
+ sig { params(file: Schema::Node).returns(String) }
76
+ def file_to_module_name(file) = class_name(file.display_name&.to_s&.split("/")&.last&.sub(".capnp", "") || "")
77
+
78
+ sig { void }
79
+ def generate
80
+ @files.each do |file|
81
+ nested_nodes = file.nested_nodes
82
+ next "" if nested_nodes.nil?
83
+
84
+ nested_nodes_code = nested_nodes.flat_map do |nestednode|
85
+ name = nestednode.name&.to_s
86
+ raise "Node without a name" if name.nil?
87
+ node = @nodes_by_id[nestednode.id]
88
+ raise "Node not found" if node.nil?
89
+ process_node(name, node)
90
+ end
91
+
92
+ code = [
93
+ "# typed: strict",
94
+ "",
95
+ 'require "capnp"',
96
+ 'require "sorbet-runtime"',
97
+ "module #{file_to_module_name(file)}",
98
+ *nested_nodes_code.map { " #{_1}" }[1..],
99
+ "end",
100
+ ""
101
+ ].map(&:rstrip).join("\n")
102
+
103
+ # TODO: Use RedquestedFile.filename
104
+ path = "#{file.display_name&.to_s}.rb"
105
+ File.write(path, code)
106
+ end
107
+ end
108
+
109
+ sig { params(name: String, node: Schema::Node).returns(T::Array[String]) }
110
+ def process_node(name, node)
111
+ which_val = node.which?
112
+ case which_val
113
+ when Schema::Node::Which::Struct
114
+ process_struct(name, node)
115
+ when Schema::Node::Which::Enum
116
+ process_enum(name, node)
117
+ when Schema::Node::Which::Interface
118
+ warn "Ignoring interface node"
119
+ []
120
+ when Schema::Node::Which::Const
121
+ value = node.const.value
122
+ raise "Const without a value" if value.nil?
123
+ ["#{const_name(name)} = #{process_value(value)}"]
124
+ when Schema::Node::Which::Annotation
125
+ warn "Ignoring annotation node"
126
+ []
127
+ when Schema::Node::Which::File
128
+ raise "Unexpected file node"
129
+ else
130
+ T.absurd(which_val)
131
+ end
132
+ end
133
+
134
+ sig { params(name: String, node: Schema::Node).returns(T::Array[String]) }
135
+ def process_struct(name, node)
136
+ raise "Generic structs are not supported" if node.is_generic
137
+
138
+ fields = node.struct.fields
139
+ raise "No fields found" if fields.nil?
140
+
141
+ field_code = fields.sort_by(&:code_order).flat_map do |field|
142
+ process_field(field)
143
+ end
144
+
145
+ nested_node_code = node.nested_nodes&.flat_map do |nestednode|
146
+ nested_node_name = nestednode.name&.to_s
147
+ raise "Node without a name" if nested_node_name.nil?
148
+ nested_node = @nodes_by_id.fetch(nestednode.id)
149
+
150
+ process_node(nested_node_name, nested_node)
151
+ end
152
+ nested_node_code ||= []
153
+
154
+ name = class_name(name)
155
+
156
+ list_class_code = if node.struct.is_group
157
+ []
158
+ else
159
+ [
160
+ "",
161
+ " class List < Capnp::StructList",
162
+ " Elem = type_member { {fixed: #{name}} }",
163
+ " sig { override.returns(T.class_of(#{name})) }",
164
+ " def element_class = #{name}",
165
+ " end"
166
+ ]
167
+ end
168
+
169
+ # Create Which enum class for unions
170
+ which_code = if node.struct.discriminant_count.zero?
171
+ []
172
+ else
173
+ discriminant_offset = node.struct.discriminant_offset * 2
174
+ enumerants = fields
175
+ .reject { _1.discriminant_value == Schema::Field::NO_DISCRIMINANT }
176
+ .sort_by(&:discriminant_value)
177
+ .map { _1.name&.to_s || "" }
178
+ [
179
+ "sig { returns(Which) }",
180
+ "def which? = Which.from_integer(read_u16(#{discriminant_offset}, 0))",
181
+ *process_enumeration("Which", enumerants)
182
+ ]
183
+ end
184
+
185
+ # Create to_obj method
186
+ to_obj_code = create_struct_to_obj(fields)
187
+
188
+ [
189
+ "",
190
+ "class #{name} < Capnp::Struct",
191
+ *field_code.map { " #{_1}" },
192
+ *nested_node_code.map { " #{_1}" },
193
+ *list_class_code,
194
+ *which_code.map { " #{_1}" },
195
+ *to_obj_code.map { " #{_1}" },
196
+ "end"
197
+ ]
198
+ end
199
+
200
+ sig { params(fields: T::Enumerable[Schema::Field]).returns(T::Array[[String, String]]) }
201
+ def create_struct_to_obj_assignments(fields)
202
+ fields.map do |field|
203
+ name = field.name&.to_s
204
+ raise "Field without a name" if name.nil?
205
+
206
+ mname = method_name(name)
207
+
208
+ assignment = if field.is_group?
209
+ # Group "fields" are treated as nested structs
210
+ "res[#{mname.inspect}] = #{mname}.to_obj"
211
+ else
212
+ # Normal (non-group) fields
213
+ type = field.slot.type
214
+ raise "Field without a type" if type.nil?
215
+
216
+ case type.which?
217
+ when Schema::Type::Which::Text, Schema::Type::Which::Data, Schema::Type::Which::List, Schema::Type::Which::Struct
218
+ "res[#{mname.inspect}] = #{mname}&.to_obj"
219
+ when Schema::Type::Which::Interface, Schema::Type::Which::AnyPointer
220
+ warn "Interfaces and AnyPointers cannot be converted to objects"
221
+ "res[#{mname.inspect}] = #{mname}"
222
+ else
223
+ "res[#{mname.inspect}] = #{mname}"
224
+ end
225
+ end
226
+
227
+ [name, assignment]
228
+ end
229
+ end
230
+
231
+ sig { params(fields: T::Enumerable[Schema::Field]).returns(T::Array[String]) }
232
+ def create_struct_to_obj(fields)
233
+ # Split up union and non-union fields
234
+ normal, union = fields
235
+ .sort_by(&:code_order)
236
+ .partition { _1.discriminant_value == Schema::Field::NO_DISCRIMINANT }
237
+
238
+ # Process normal fields
239
+ assignments = create_struct_to_obj_assignments(normal).map { " #{_2}" }
240
+
241
+ # Process union fields with a case statement
242
+ union_assignments = if union.empty?
243
+ []
244
+ else
245
+ whens = create_struct_to_obj_assignments(union).map do |name, assignment|
246
+ " when Which::#{class_name(name)} then #{assignment}"
247
+ end
248
+ [
249
+ " case which?",
250
+ *whens,
251
+ " end"
252
+ ]
253
+ end
254
+
255
+ [
256
+ "sig { override.returns(Object) }",
257
+ "def to_obj",
258
+ " res = {}",
259
+ *assignments,
260
+ *union_assignments,
261
+ " res",
262
+ "end"
263
+ ]
264
+ end
265
+
266
+ sig { params(field: Schema::Field).returns(T::Array[String]) }
267
+ def process_field(field)
268
+ # TODO: Check union discriminant values
269
+ warn "Ignoring annotations" unless field.annotations&.length.to_i.zero?
270
+
271
+ name = field.name&.to_s
272
+ raise "Field without a name" if name.nil?
273
+
274
+ mname = method_name(name)
275
+
276
+ getter_def = if field.is_group?
277
+ group_node = @nodes_by_id.fetch(field.group.type_id)
278
+ class_name = "Group#{class_name(name)}"
279
+ group_class_code = process_struct(class_name, group_node)
280
+ [
281
+ "sig { returns(#{class_name}) }",
282
+ "def #{mname} = #{class_name}.new(@data, @data_size, @pointers, @pointers_size)",
283
+ *group_class_code
284
+ ]
285
+ else
286
+ type = field.slot.type
287
+ raise "Field without a type" if type.nil?
288
+
289
+ default_variable = "DEFAULT_#{const_name(name)}"
290
+
291
+ which_type = type.which?
292
+ case which_type
293
+ when Schema::Type::Which::Void
294
+ [
295
+ "sig { returns(NilClass) }",
296
+ "def #{mname} = nil"
297
+ ]
298
+ when Schema::Type::Which::Bool
299
+ default_value = field.slot.default_value&.bool ? "0xFF" : "0x00"
300
+ offset = field.slot.offset / 8
301
+ mask = (1 << (field.slot.offset % 8)).to_s(16)
302
+ [
303
+ "#{default_variable} = #{field.slot.default_value&.bool == true}",
304
+ "sig { returns(T::Boolean) }",
305
+ "def #{mname} = (read_u8(#{offset}, #{default_value}) & 0x#{mask}) != 0"
306
+ ]
307
+ when Schema::Type::Which::Int8
308
+ default_value = field.slot.default_value&.int8 || 0
309
+ [
310
+ "#{default_variable} = #{default_value}",
311
+ "sig { returns(Integer) }",
312
+ "def #{mname} = read_s8(#{field.slot.offset}, #{default_value})"
313
+ ]
314
+ when Schema::Type::Which::Int16
315
+ default_value = field.slot.default_value&.int16 || 0
316
+ offset = field.slot.offset * 2
317
+ [
318
+ "#{default_variable} = #{default_value}",
319
+ "sig { returns(Integer) }",
320
+ "def #{mname} = read_s16(#{offset}, #{default_value})"
321
+ ]
322
+ when Schema::Type::Which::Int32
323
+ default_value = field.slot.default_value&.int32 || 0
324
+ offset = field.slot.offset * 4
325
+ [
326
+ "#{default_variable} = #{default_value}",
327
+ "sig { returns(Integer) }",
328
+ "def #{mname} = read_s32(#{offset}, #{default_value})"
329
+ ]
330
+ when Schema::Type::Which::Int64
331
+ default_value = field.slot.default_value&.int64 || 0
332
+ offset = field.slot.offset * 8
333
+ [
334
+ "#{default_variable} = #{default_value}",
335
+ "sig { returns(Integer) }",
336
+ "def #{mname} = read_s64(#{offset}, #{default_value})"
337
+ ]
338
+ when Schema::Type::Which::Uint8
339
+ default_value = field.slot.default_value&.uint8 || 0
340
+ [
341
+ "#{default_variable} = #{default_value}",
342
+ "sig { returns(Integer) }",
343
+ "def #{mname} = read_u8(#{field.slot.offset}, #{default_value})"
344
+ ]
345
+ when Schema::Type::Which::Uint16
346
+ default_value = field.slot.default_value&.uint16 || 0
347
+ offset = field.slot.offset * 2
348
+ [
349
+ "#{default_variable} = #{default_value}",
350
+ "sig { returns(Integer) }",
351
+ "def #{mname} = read_u16(#{offset}, #{default_value})"
352
+ ]
353
+ when Schema::Type::Which::Uint32
354
+ default_value = field.slot.default_value&.uint32 || 0
355
+ offset = field.slot.offset * 4
356
+ [
357
+ "#{default_variable} = #{default_value}",
358
+ "sig { returns(Integer) }",
359
+ "def #{mname} = read_u32(#{offset}, #{default_value})"
360
+ ]
361
+ when Schema::Type::Which::Uint64
362
+ default_value = field.slot.default_value&.uint64 || 0
363
+ offset = field.slot.offset * 8
364
+ [
365
+ "#{default_variable} = #{default_value}",
366
+ "sig { returns(Integer) }",
367
+ "def #{mname} = read_u64(#{offset}, #{default_value})"
368
+ ]
369
+ when Schema::Type::Which::Float32
370
+ default_value = field.slot.default_value&.float32 || 0.0
371
+ offset = field.slot.offset * 4
372
+ [
373
+ "#{default_variable} = #{default_value}",
374
+ "sig { returns(Float) }",
375
+ "def #{mname} = read_f32(#{offset}, #{default_value})"
376
+ ]
377
+ when Schema::Type::Which::Float64
378
+ default_value = field.slot.default_value&.float64 || 0.0
379
+ offset = field.slot.offset * 8
380
+ [
381
+ "#{default_variable} = #{default_value}",
382
+ "sig { returns(Float) }",
383
+ "def #{mname} = read_f64(#{offset}, #{default_value})"
384
+ ]
385
+ when Schema::Type::Which::Text
386
+ default_value = field.slot.default_value&.text&.to_s.inspect
387
+ apply_default = field.slot.had_explicit_default ? " || Capnp::ObjectString.new(#{default_variable})" : ""
388
+ [
389
+ "#{default_variable} = #{default_value}",
390
+ "sig { returns(T.nilable(Capnp::String)) }",
391
+ "def #{mname} = Capnp::BufferString.from_pointer(read_pointer(#{field.slot.offset}))#{apply_default}"
392
+ ]
393
+ when Schema::Type::Which::Data
394
+ default_value = field.slot.default_value&.data&.value.inspect
395
+ apply_default = field.slot.had_explicit_default ? " || #{default_variable}" : ""
396
+ [
397
+ "#{default_variable} = #{default_value}",
398
+ "sig { returns(T.nilable(Capnp::Data)) }",
399
+ "def #{mname} = Capnp::Data.from_pointer(read_pointer(#{field.slot.offset}))#{apply_default}"
400
+ ]
401
+ when Schema::Type::Which::List
402
+ raise "List default values not supported" if field.slot.had_explicit_default
403
+ element_class = type.list.element_type
404
+ raise "List without an element type" if element_class.nil?
405
+ which_element_type = element_class.which?
406
+ case which_element_type
407
+ when Schema::Type::Which::Void
408
+ raise "Void list elements not supported"
409
+ when Schema::Type::Which::Bool
410
+ raise "Bool list elements not supported"
411
+ when Schema::Type::Which::Int8, Schema::Type::Which::Int16, Schema::Type::Which::Int32, Schema::Type::Which::Int64
412
+ list_class = "Capnp::SignedIntegerList"
413
+ element_class = "Integer"
414
+ when Schema::Type::Which::Uint8, Schema::Type::Which::Uint16, Schema::Type::Which::Uint32, Schema::Type::Which::Uint64
415
+ list_class = "Capnp::UnsignedIntegerList"
416
+ element_class = "Integer"
417
+ when Schema::Type::Which::Float32, Schema::Type::Which::Float64
418
+ list_class = "Capnp::FloatList"
419
+ element_class = "Float"
420
+ when Schema::Type::Which::Text
421
+ raise "Text list elements not supported"
422
+ when Schema::Type::Which::Data
423
+ raise "Data list elements not supported"
424
+ when Schema::Type::Which::List
425
+ raise "List list elements not supported"
426
+ when Schema::Type::Which::Enum
427
+ raise "Enum list elements not supported"
428
+ when Schema::Type::Which::Struct
429
+ raise "List[Struct] default values not supported" if field.slot.had_explicit_default
430
+ element_class = @node_to_class_path.fetch(element_class.struct.type_id).join("::")
431
+ list_class = "#{element_class}::List"
432
+ when Schema::Type::Which::Interface
433
+ raise "Interface list elements not supported"
434
+ when Schema::Type::Which::AnyPointer
435
+ raise "AnyPointer list elements not supported"
436
+ else
437
+ T.absurd(which_element_type)
438
+ end
439
+
440
+ [
441
+ "sig { returns(T.nilable(Capnp::List[#{element_class}])) }",
442
+ "def #{mname} = #{list_class}.from_pointer(read_pointer(#{field.slot.offset}))"
443
+ ]
444
+ when Schema::Type::Which::Enum
445
+ enumerants = @nodes_by_id.fetch(type.enum.type_id).enum.enumerants
446
+ raise "No enumerants found" if enumerants.nil?
447
+
448
+ default_num = field.slot.default_value&.enum || 0
449
+ default_value = class_name(enumerants[default_num]&.name&.to_s || "")
450
+
451
+ offset = field.slot.offset * 2
452
+ class_path = @node_to_class_path.fetch(type.enum.type_id).join("::")
453
+ [
454
+ # TODO: This doesn't work if the enum class is declared after this field
455
+ "# #{default_variable} = #{class_path}::#{default_value}",
456
+ "sig { returns(#{class_path}) }",
457
+ "def #{mname} = #{class_path}.from_integer(read_u16(#{offset}, #{default_num}))"
458
+ ]
459
+ when Schema::Type::Which::Struct
460
+ raise "Struct default values not supported" if field.slot.had_explicit_default
461
+ class_path = @node_to_class_path.fetch(type.struct.type_id).join("::")
462
+ [
463
+ "sig { returns(T.nilable(#{class_path})) }",
464
+ "def #{mname} = #{class_path}.from_pointer(read_pointer(#{field.slot.offset}))"
465
+ ]
466
+ when Schema::Type::Which::Interface
467
+ raise "Interface fields not supported"
468
+ when Schema::Type::Which::AnyPointer
469
+ raise "Only unconstrained AnyPointers are supported" unless type.any_pointer.is_unconstrained?
470
+ [
471
+ "sig { returns(Capnp::Reference) }",
472
+ "def #{mname} = read_pointer(#{field.slot.offset})"
473
+ ]
474
+ else
475
+ T.absurd(which_type)
476
+ end
477
+ end
478
+
479
+ # Add type checking methods for union fields
480
+ if field.discriminant_value != Schema::Field::NO_DISCRIMINANT
481
+ getter_def += [
482
+ "sig { returns(T::Boolean) }",
483
+ "def is_#{mname}? = which? == Which::#{class_name(name)}"
484
+ ]
485
+ end
486
+
487
+ getter_def
488
+ end
489
+
490
+ sig { params(name: String, node: Schema::Node).returns(T::Array[String]) }
491
+ def process_enum(name, node)
492
+ raise "Nested nodes not supported in enum" unless node.nested_nodes&.length.to_i.zero?
493
+ raise "Generic structs are not supported" if node.is_generic
494
+
495
+ enumerants = node.enum.enumerants
496
+ raise "No enumerants found" if enumerants.nil?
497
+
498
+ # Enumerants are ordered by their numeric value
499
+ enums = enumerants.map do |enumerant|
500
+ warn "Ignoring annotations" unless enumerant.annotations&.length.to_i.zero?
501
+
502
+ enumerant_name = enumerant.name&.to_s
503
+ raise "Enumerant without a name" if enumerant_name.nil?
504
+ enumerant_name
505
+ end
506
+
507
+ process_enumeration(name, enums)
508
+ end
509
+
510
+ sig { params(name: String, enumerants: T::Array[String]).returns(T::Array[String]) }
511
+ def process_enumeration(name, enumerants)
512
+ definitions = T.let([], T::Array[String])
513
+ from_int = T.let([], T::Array[String])
514
+
515
+ # Enumerants are ordered by their numeric value
516
+ enumerants.each_with_index do |enumerant_name, ix|
517
+ ename = class_name(enumerant_name)
518
+ definitions << " #{ename} = new(#{enumerant_name.inspect})"
519
+ from_int << " when #{ix} then #{ename}"
520
+ end
521
+
522
+ # TODO: Define an Capnp::Enum class
523
+ class_name = class_name(name)
524
+ [
525
+ "",
526
+ "class #{class_name} < T::Enum",
527
+ " extend T::Sig",
528
+ " enums do",
529
+ *definitions,
530
+ " end",
531
+ " sig { params(value: Integer).returns(#{class_name}) }",
532
+ " def self.from_integer(value)",
533
+ " case value",
534
+ *from_int,
535
+ " else raise \"Unknown #{name} value: \#{value}\"",
536
+ " end",
537
+ " end",
538
+ "end"
539
+ ]
540
+ end
541
+
542
+ sig { params(value: Schema::Value).returns(T.any(String, T::Boolean, Numeric, NilClass)) }
543
+ def process_value(value)
544
+ which_value = value.which?
545
+ case which_value
546
+ when Schema::Value::Which::Void then nil
547
+ when Schema::Value::Which::Bool then value.bool
548
+ when Schema::Value::Which::Int8 then value.int8
549
+ when Schema::Value::Which::Int16 then value.int16
550
+ when Schema::Value::Which::Int32 then value.int32
551
+ when Schema::Value::Which::Int64 then value.int64
552
+ when Schema::Value::Which::Uint8 then value.uint8
553
+ when Schema::Value::Which::Uint16 then value.uint16
554
+ when Schema::Value::Which::Uint32 then value.uint32
555
+ when Schema::Value::Which::Uint64 then value.uint64
556
+ when Schema::Value::Which::Float32 then value.float32
557
+ when Schema::Value::Which::Float64 then value.float64
558
+ when Schema::Value::Which::Text then value.text&.to_s.inspect
559
+ when Schema::Value::Which::Data then value.data&.value.inspect
560
+ when Schema::Value::Which::List then raise "List values not supported"
561
+ when Schema::Value::Which::Enum then value.enum # TODO: Convert to enum class
562
+ when Schema::Value::Which::Struct then raise "Struct values not supported"
563
+ when Schema::Value::Which::Interface then nil
564
+ when Schema::Value::Which::AnyPointer then raise "AnyPointer values not supported"
565
+ else T.absurd(which_value)
566
+ end
567
+ end
568
+ end