avrocadabra 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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +6 -0
  3. data/Cargo.lock +923 -0
  4. data/Cargo.toml +8 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +131 -0
  7. data/docs/avro_turf.md +61 -0
  8. data/docs/licenses/crates/quad-rand-0.2.3/DECLARED-LICENSE.txt +32 -0
  9. data/docs/licenses/gcc-16.2.0/COPYING +340 -0
  10. data/docs/licenses/gcc-16.2.0/COPYING.RUNTIME +73 -0
  11. data/docs/licenses/mingw-w64-14.0.0/AUTHORS +73 -0
  12. data/docs/licenses/mingw-w64-14.0.0/COPYING +43 -0
  13. data/docs/licenses/rust-1.99.0/COMPILER-BUILTINS.txt +275 -0
  14. data/docs/licenses/rust-1.99.0/COPYRIGHT-library.html +29357 -0
  15. data/docs/licenses/rust-1.99.0/LIBM.txt +258 -0
  16. data/docs/licenses/rust-1.99.0/LLVM-LIBUNWIND.txt +311 -0
  17. data/docs/licenses/rust-1.99.0/RUST-LICENSE-APACHE.txt +176 -0
  18. data/docs/licenses/rust-1.99.0/RUST-LICENSE-MIT.txt +25 -0
  19. data/docs/licenses/rust-1.99.0/STDLIB-BACKTRACE-MIT.txt +25 -0
  20. data/docs/licenses/rust-1.99.0/STDLIB-PORTABLE-SIMD-MIT.txt +19 -0
  21. data/docs/licenses/rust-1.99.0/STDLIB-STDARCH-MIT.txt +25 -0
  22. data/docs/licenses/rust-1.99.0/licenses/Apache-2.0.txt +73 -0
  23. data/docs/licenses/rust-1.99.0/licenses/BSD-2-Clause.txt +9 -0
  24. data/docs/licenses/rust-1.99.0/licenses/CC-BY-SA-4.0.txt +427 -0
  25. data/docs/licenses/rust-1.99.0/licenses/GCC-exception-3.1.txt +30 -0
  26. data/docs/licenses/rust-1.99.0/licenses/GPL-2.0-only.txt +133 -0
  27. data/docs/licenses/rust-1.99.0/licenses/GPL-3.0-or-later.txt +202 -0
  28. data/docs/licenses/rust-1.99.0/licenses/ISC.txt +7 -0
  29. data/docs/licenses/rust-1.99.0/licenses/LLVM-exception.txt +15 -0
  30. data/docs/licenses/rust-1.99.0/licenses/MIT.txt +9 -0
  31. data/docs/licenses/rust-1.99.0/licenses/NCSA.txt +28 -0
  32. data/docs/licenses/rust-1.99.0/licenses/OFL-1.1.txt +43 -0
  33. data/docs/licenses/rust-1.99.0/licenses/Unicode-3.0.txt +39 -0
  34. data/docs/releasing.md +71 -0
  35. data/docs/third_party.md +5922 -0
  36. data/ext/avrocadabra/Cargo.toml +29 -0
  37. data/ext/avrocadabra/build.rs +4 -0
  38. data/ext/avrocadabra/extconf.rb +9 -0
  39. data/ext/avrocadabra/src/big_decimal.rs +107 -0
  40. data/ext/avrocadabra/src/callback.rs +106 -0
  41. data/ext/avrocadabra/src/convert.rs +617 -0
  42. data/ext/avrocadabra/src/decode_value.rs +473 -0
  43. data/ext/avrocadabra/src/guard.rs +680 -0
  44. data/ext/avrocadabra/src/lib.rs +670 -0
  45. data/ext/avrocadabra/src/mapping.rs +63 -0
  46. data/ext/avrocadabra/src/memory.rs +194 -0
  47. data/ext/avrocadabra/src/prepare.rs +819 -0
  48. data/ext/avrocadabra/src/resolution.rs +1932 -0
  49. data/ext/avrocadabra/src/schema_state.rs +60 -0
  50. data/ext/avrocadabra/src/validation.rs +174 -0
  51. data/ext/avrocadabra/src/wire.rs +269 -0
  52. data/lib/avrocadabra/avro_turf/cache.rb +28 -0
  53. data/lib/avrocadabra/avro_turf/codec.rb +69 -0
  54. data/lib/avrocadabra/avro_turf/datum_reader.rb +17 -0
  55. data/lib/avrocadabra/avro_turf/datum_writer.rb +14 -0
  56. data/lib/avrocadabra/avro_turf/mapping.rb +48 -0
  57. data/lib/avrocadabra/avro_turf/messaging.rb +12 -0
  58. data/lib/avrocadabra/avro_turf/ractor_support.rb +154 -0
  59. data/lib/avrocadabra/avro_turf/routing.rb +15 -0
  60. data/lib/avrocadabra/avro_turf/schema_state.rb +70 -0
  61. data/lib/avrocadabra/avro_turf/validation.rb +33 -0
  62. data/lib/avrocadabra/avro_turf.rb +25 -0
  63. data/lib/avrocadabra/logical.rb +71 -0
  64. data/lib/avrocadabra/schema.rb +48 -0
  65. data/lib/avrocadabra/version.rb +5 -0
  66. data/lib/avrocadabra.rb +34 -0
  67. metadata +183 -0
@@ -0,0 +1,473 @@
1
+ use apache_avro::{
2
+ Schema,
3
+ schema::{NamesRef, RecordSchema},
4
+ types::Value as AvroValue,
5
+ };
6
+ use magnus::{Error, RArray, RModule, RString, Ruby, Value, prelude::*};
7
+ use serde_json::Value as Json;
8
+ use std::collections::HashMap;
9
+ use std::sync::Arc;
10
+
11
+ use crate::{
12
+ guard::Limits,
13
+ mapping::{self, Mapping},
14
+ };
15
+
16
+ pub struct Options {
17
+ pub limits: Limits,
18
+ pub tagged_unions: bool,
19
+ pub mapping: Option<Mapping>,
20
+ pub defaults: Vec<(usize, Arc<Json>)>,
21
+ pub adapters: Vec<(usize, usize)>,
22
+ pub failure: Option<(usize, String)>,
23
+ }
24
+
25
+ pub fn decode<'schema>(
26
+ ruby: &Ruby,
27
+ schema: &'schema Schema,
28
+ names: &NamesRef<'schema>,
29
+ value: AvroValue,
30
+ keys: RArray,
31
+ fields: &HashMap<String, usize>,
32
+ options: Options,
33
+ ) -> Result<Value, Error> {
34
+ Decoder {
35
+ ruby,
36
+ names,
37
+ keys,
38
+ fields,
39
+ limits: options.limits,
40
+ tagged_unions: options.tagged_unions,
41
+ remaining: options.limits.max_items,
42
+ path: "$".into(),
43
+ logical: None,
44
+ defaults: options.defaults.into_iter().peekable(),
45
+ adapters: options.adapters.into_iter().peekable(),
46
+ field_position: 0,
47
+ read_position: 0,
48
+ failure: options.failure,
49
+ }
50
+ .value(schema, value, None, 0, options.mapping)
51
+ }
52
+
53
+ struct Decoder<'context, 'schema> {
54
+ ruby: &'context Ruby,
55
+ names: &'context NamesRef<'schema>,
56
+ keys: RArray,
57
+ fields: &'context HashMap<String, usize>,
58
+ limits: Limits,
59
+ remaining: usize,
60
+ path: String,
61
+ logical: Option<RModule>,
62
+ tagged_unions: bool,
63
+ defaults: std::iter::Peekable<std::vec::IntoIter<(usize, Arc<Json>)>>,
64
+ adapters: std::iter::Peekable<std::vec::IntoIter<(usize, usize)>>,
65
+ field_position: usize,
66
+ read_position: usize,
67
+ failure: Option<(usize, String)>,
68
+ }
69
+
70
+ impl<'schema> Decoder<'_, 'schema> {
71
+ fn error(&self, message: impl std::fmt::Display) -> Error {
72
+ crate::error(
73
+ self.ruby,
74
+ "DecodeError",
75
+ format!("{}: {message}", self.path),
76
+ )
77
+ }
78
+
79
+ fn enter(&mut self, depth: usize) -> Result<(), Error> {
80
+ if depth > self.limits.max_depth {
81
+ return Err(self.error("decoded value exceeds maximum depth"));
82
+ }
83
+ self.remaining = self
84
+ .remaining
85
+ .checked_sub(1)
86
+ .ok_or_else(|| self.error("decoded value exceeds maximum item count"))?;
87
+ Ok(())
88
+ }
89
+
90
+ fn logical(&mut self) -> Result<RModule, Error> {
91
+ if let Some(module) = self.logical {
92
+ return Ok(module);
93
+ }
94
+ let namespace: RModule = self.ruby.class_object().const_get("Avrocadabra")?;
95
+ let module = namespace.const_get("Logical")?;
96
+ self.logical = Some(module);
97
+ Ok(module)
98
+ }
99
+
100
+ fn value(
101
+ &mut self,
102
+ schema: &'schema Schema,
103
+ value: AvroValue,
104
+ namespace: Option<&str>,
105
+ depth: usize,
106
+ mapping: Option<Mapping>,
107
+ ) -> Result<Value, Error> {
108
+ if let Some((position, error)) = &self.failure
109
+ && *position == self.read_position
110
+ {
111
+ return Err(crate::error(self.ruby, "ResolutionError", error));
112
+ }
113
+ self.enter(depth)?;
114
+ let adapters = self
115
+ .adapters
116
+ .next_if(|(position, _)| *position == self.read_position)
117
+ .map_or(1, |(_, count)| count);
118
+ self.read_position += 1;
119
+ let mut value = self.physical(schema, value, namespace, depth, mapping)?;
120
+ if let Some(mapping) = mapping {
121
+ for _ in 0..adapters {
122
+ value = mapping.convert("decode", value)?;
123
+ }
124
+ }
125
+ Ok(value)
126
+ }
127
+
128
+ fn physical(
129
+ &mut self,
130
+ mut schema: &'schema Schema,
131
+ value: AvroValue,
132
+ namespace: Option<&str>,
133
+ depth: usize,
134
+ mapping: Option<Mapping>,
135
+ ) -> Result<Value, Error> {
136
+ let mut hops = 0;
137
+ while let Schema::Ref { name } = schema {
138
+ if hops > self.names.len() {
139
+ return Err(self.error("cyclic unresolved schema reference"));
140
+ }
141
+ schema = self
142
+ .names
143
+ .get(name.fully_qualified_name(namespace).as_ref())
144
+ .or_else(|| self.names.get(name))
145
+ .copied()
146
+ .ok_or_else(|| self.error(format_args!("unresolved schema reference {name}")))?;
147
+ hops += 1;
148
+ }
149
+
150
+ match (schema, value) {
151
+ (Schema::Null, AvroValue::Null) => Ok(self.ruby.qnil().as_value()),
152
+ (Schema::Boolean, AvroValue::Boolean(value)) => Ok(self.ruby.into_value(value)),
153
+ (
154
+ Schema::Int | Schema::Long | Schema::Float | Schema::Double,
155
+ AvroValue::Int(value),
156
+ ) => Ok(self.ruby.into_value(value)),
157
+ (Schema::Long | Schema::Float | Schema::Double, AvroValue::Long(value)) => {
158
+ Ok(self.ruby.into_value(value))
159
+ }
160
+ (Schema::Float | Schema::Double, AvroValue::Float(value)) => {
161
+ Ok(self.ruby.into_value(f64::from(value)))
162
+ }
163
+ (Schema::Float | Schema::Double, AvroValue::Double(value)) => {
164
+ Ok(self.ruby.into_value(value))
165
+ }
166
+ (Schema::String | Schema::Bytes, AvroValue::String(value)) => self.string(&value),
167
+ (Schema::Bytes | Schema::String, AvroValue::Bytes(value)) => self.bytes(&value),
168
+ (Schema::Fixed(fixed), AvroValue::String(value)) if value.len() == fixed.size => {
169
+ self.string(&value)
170
+ }
171
+ (Schema::Fixed(fixed), AvroValue::Fixed(size, value))
172
+ if size == fixed.size && value.len() == fixed.size =>
173
+ {
174
+ self.bytes(&value)
175
+ }
176
+ (Schema::Enum(_), AvroValue::Enum(_, symbol)) => self.string(&symbol),
177
+ (Schema::Union(union), AvroValue::Union(index, value)) => {
178
+ let branch = union
179
+ .variants()
180
+ .get(index as usize)
181
+ .ok_or_else(|| self.error("decoded union branch index is invalid"))?;
182
+ let value = self.value(
183
+ branch,
184
+ *value,
185
+ namespace,
186
+ depth,
187
+ mapping::child(mapping, index as usize)?,
188
+ )?;
189
+ if self.tagged_unions {
190
+ let union: magnus::RClass = crate::namespace(self.ruby)?.const_get("Union")?;
191
+ union.funcall("new", (index, value))
192
+ } else {
193
+ Ok(value)
194
+ }
195
+ }
196
+ (Schema::Record(record), AvroValue::Record(values)) => {
197
+ self.record(record, values, namespace, depth, mapping)
198
+ }
199
+ (Schema::Array(array), AvroValue::Array(values)) => {
200
+ self.collection_size(values.len())?;
201
+ let output = self.ruby.ary_new_capa(values.len());
202
+ let child = mapping::child(mapping, 0)?;
203
+ for (index, value) in values.into_iter().enumerate() {
204
+ let path_length = self.path.len();
205
+ crate::push_index(&mut self.path, index);
206
+ let value = self.value(&array.items, value, namespace, depth + 1, child);
207
+ self.path.truncate(path_length);
208
+ output.push(value?)?;
209
+ }
210
+ Ok(output.as_value())
211
+ }
212
+ (Schema::Map(map), AvroValue::Record(values)) => {
213
+ self.collection_size(values.len())?;
214
+ let output = self.ruby.hash_new_capa(values.len());
215
+ let child = mapping::child(mapping, 0)?;
216
+ for (index, (name, value)) in values.into_iter().enumerate() {
217
+ let path_length = self.path.len();
218
+ crate::push_index(&mut self.path, index);
219
+ let key = self.ruby.str_new(&name);
220
+ key.freeze();
221
+ let value = self.value(&map.types, value, namespace, depth + 1, child);
222
+ self.path.truncate(path_length);
223
+ output.aset(key, value?)?;
224
+ }
225
+ Ok(output.as_value())
226
+ }
227
+ (Schema::Decimal(decimal), AvroValue::Decimal(value)) => {
228
+ let unscaled = apache_avro::BigDecimal::new(value.into(), 0).to_string();
229
+ if unscaled.trim_start_matches('-').len() > decimal.precision {
230
+ return Err(self.error("decimal exceeds schema precision"));
231
+ }
232
+ self.logical()?
233
+ .funcall("decimal_value", (unscaled, decimal.scale))
234
+ }
235
+ (Schema::BigDecimal, AvroValue::BigDecimal(value)) => {
236
+ let (coefficient, scale) = value.as_bigint_and_exponent();
237
+ self.logical()?
238
+ .funcall("decimal_value", (coefficient.to_str_radix(10), scale))
239
+ }
240
+ (Schema::Date, AvroValue::Date(days)) => self.logical()?.funcall("date_value", (days,)),
241
+ (Schema::TimeMillis, AvroValue::TimeMillis(ticks))
242
+ if (0..86_400_000).contains(&ticks) =>
243
+ {
244
+ Ok(self.ruby.into_value(ticks))
245
+ }
246
+ (Schema::TimeMicros, AvroValue::TimeMicros(ticks))
247
+ if (0..86_400_000_000).contains(&ticks) =>
248
+ {
249
+ Ok(self.ruby.into_value(ticks))
250
+ }
251
+ (Schema::TimestampMillis, AvroValue::TimestampMillis(ticks)) => {
252
+ self.logical()?.funcall("timestamp_value", (ticks, 1_000))
253
+ }
254
+ (Schema::TimestampMicros, AvroValue::TimestampMicros(ticks)) => self
255
+ .logical()?
256
+ .funcall("timestamp_value", (ticks, 1_000_000)),
257
+ (Schema::TimestampNanos, AvroValue::TimestampNanos(ticks)) => self
258
+ .logical()?
259
+ .funcall("timestamp_value", (ticks, 1_000_000_000)),
260
+ (Schema::LocalTimestampMillis, AvroValue::LocalTimestampMillis(ticks))
261
+ | (Schema::LocalTimestampMicros, AvroValue::LocalTimestampMicros(ticks))
262
+ | (Schema::LocalTimestampNanos, AvroValue::LocalTimestampNanos(ticks)) => {
263
+ Ok(self.ruby.into_value(ticks))
264
+ }
265
+ (Schema::Uuid(_), AvroValue::Uuid(value)) => self.string(&value.to_string()),
266
+ (Schema::Duration(fixed), AvroValue::Duration(value)) if fixed.size == 12 => {
267
+ let namespace: RModule = self.ruby.class_object().const_get("Avrocadabra")?;
268
+ let duration: magnus::RClass = namespace.const_get("Duration")?;
269
+ duration.funcall(
270
+ "new",
271
+ (
272
+ u32::from(value.months()),
273
+ u32::from(value.days()),
274
+ u32::from(value.millis()),
275
+ ),
276
+ )
277
+ }
278
+ _ => Err(self.error("decoded value does not match the prepared schema")),
279
+ }
280
+ }
281
+
282
+ fn collection_size(&self, length: usize) -> Result<(), Error> {
283
+ if length > self.remaining {
284
+ return Err(self.error("decoded collection exceeds maximum item count"));
285
+ }
286
+ Ok(())
287
+ }
288
+
289
+ fn string(&self, value: &str) -> Result<Value, Error> {
290
+ if value.len() > self.limits.max_bytes {
291
+ return Err(self.error("decoded string exceeds maximum byte count"));
292
+ }
293
+ Ok(self.ruby.str_new(value).as_value())
294
+ }
295
+
296
+ fn bytes(&self, value: &[u8]) -> Result<Value, Error> {
297
+ if value.len() > self.limits.max_bytes {
298
+ return Err(self.error("decoded bytes exceed maximum byte count"));
299
+ }
300
+ Ok(self.ruby.str_from_slice(value).as_value())
301
+ }
302
+
303
+ fn record(
304
+ &mut self,
305
+ record: &'schema RecordSchema,
306
+ values: Vec<(String, AvroValue)>,
307
+ namespace: Option<&str>,
308
+ depth: usize,
309
+ mapping: Option<Mapping>,
310
+ ) -> Result<Value, Error> {
311
+ self.collection_size(values.len())?;
312
+ let output = self.ruby.hash_new_capa(record.fields.len());
313
+ for (name, value) in values {
314
+ let &field_index = record
315
+ .lookup
316
+ .get(&name)
317
+ .ok_or_else(|| self.error("decoded record field is missing from schema"))?;
318
+ let field = &record.fields[field_index];
319
+ let index = self
320
+ .fields
321
+ .get(&field.name)
322
+ .ok_or_else(|| self.error("prepared field name is missing"))?;
323
+ let key: RString = self.keys.entry((index * 2) as isize)?;
324
+ let path_length = self.path.len();
325
+ self.path.push('.');
326
+ self.path.push_str(&field.name);
327
+ let default = self
328
+ .defaults
329
+ .next_if(|(position, _)| *position == self.field_position)
330
+ .map(|(_, default)| default);
331
+ self.field_position += 1;
332
+ let value = match (default, mapping) {
333
+ (Some(_), Some(mapping)) => mapping.default_value(key),
334
+ (Some(default), None) => self.default_value(
335
+ &field.schema,
336
+ Some(&default),
337
+ record.name.namespace().or(namespace),
338
+ depth + 1,
339
+ ),
340
+ (None, _) => self.value(
341
+ &field.schema,
342
+ value,
343
+ record.name.namespace().or(namespace),
344
+ depth + 1,
345
+ mapping::child(mapping, field_index)?,
346
+ ),
347
+ };
348
+ self.path.truncate(path_length);
349
+ output.aset(key, value?)?;
350
+ }
351
+ if output.len() != record.fields.len() {
352
+ return Err(self.error("decoded record has incorrect field count"));
353
+ }
354
+ Ok(output.as_value())
355
+ }
356
+
357
+ fn default_value(
358
+ &mut self,
359
+ schema: &'schema Schema,
360
+ json: Option<&Json>,
361
+ namespace: Option<&str>,
362
+ depth: usize,
363
+ ) -> Result<Value, Error> {
364
+ self.enter(depth)?;
365
+ let schema = crate::resolution::dereference(schema, self.names)
366
+ .map_err(|error| self.error(error))?;
367
+ match schema {
368
+ Schema::Record(record) => {
369
+ let object = json
370
+ .and_then(Json::as_object)
371
+ .ok_or_else(|| self.error("record default must be an object"))?;
372
+ self.collection_size(record.fields.len())?;
373
+ let output = self.ruby.hash_new_capa(record.fields.len());
374
+ for field in &record.fields {
375
+ let json = object
376
+ .get(&field.name)
377
+ .filter(|value| !matches!(value, Json::Null | Json::Bool(false)))
378
+ .or(field.default.as_ref());
379
+ let path_length = self.path.len();
380
+ self.path.push('.');
381
+ self.path.push_str(&field.name);
382
+ let value = self.default_value(
383
+ &field.schema,
384
+ json,
385
+ record.name.namespace().or(namespace),
386
+ depth + 1,
387
+ );
388
+ self.path.truncate(path_length);
389
+ let index = self.fields[&field.name];
390
+ let key: RString = self.keys.entry((index * 2) as isize)?;
391
+ output.aset(key, value?)?;
392
+ }
393
+ Ok(output.as_value())
394
+ }
395
+ Schema::Array(array) => {
396
+ let values = json
397
+ .and_then(Json::as_array)
398
+ .ok_or_else(|| self.error("array default must be an array"))?;
399
+ self.collection_size(values.len())?;
400
+ let output = self.ruby.ary_new_capa(values.len());
401
+ for (index, value) in values.iter().enumerate() {
402
+ let path_length = self.path.len();
403
+ crate::push_index(&mut self.path, index);
404
+ let value = self.default_value(&array.items, Some(value), namespace, depth + 1);
405
+ self.path.truncate(path_length);
406
+ output.push(value?)?;
407
+ }
408
+ Ok(output.as_value())
409
+ }
410
+ Schema::Map(map) => {
411
+ let values = json
412
+ .and_then(Json::as_object)
413
+ .ok_or_else(|| self.error("map default must be an object"))?;
414
+ self.collection_size(values.len())?;
415
+ let output = self.ruby.hash_new_capa(values.len());
416
+ for (key, value) in values {
417
+ let key = self.ruby.str_new(key);
418
+ let value =
419
+ self.default_value(&map.types, Some(value), namespace, depth + 1)?;
420
+ output.aset(key, value)?;
421
+ }
422
+ Ok(output.as_value())
423
+ }
424
+ Schema::Union(union) => {
425
+ let value = self.default_value(&union.variants()[0], json, namespace, depth)?;
426
+ if self.tagged_unions {
427
+ let union: magnus::RClass = crate::namespace(self.ruby)?.const_get("Union")?;
428
+ union.funcall("new", (0, value))
429
+ } else {
430
+ Ok(value)
431
+ }
432
+ }
433
+ Schema::Null => Ok(self.ruby.qnil().as_value()),
434
+ Schema::Int | Schema::Long => {
435
+ let value = self.default_scalar(json)?;
436
+ self.ruby.module_kernel().funcall("Integer", (value,))
437
+ }
438
+ Schema::Float | Schema::Double => {
439
+ let value = self.default_scalar(json)?;
440
+ self.ruby.module_kernel().funcall("Float", (value,))
441
+ }
442
+ Schema::Boolean
443
+ | Schema::String
444
+ | Schema::Bytes
445
+ | Schema::Fixed(_)
446
+ | Schema::Enum(_) => self.default_scalar(json),
447
+ _ => {
448
+ let json = json.ok_or_else(|| self.error("missing logical default"))?;
449
+ let value = crate::resolution::default_datum(json, schema, self.names, self.limits)
450
+ .map_err(|error| self.error(error))?;
451
+ self.physical(schema, value, namespace, depth, None)
452
+ }
453
+ }
454
+ }
455
+
456
+ fn default_scalar(&self, json: Option<&Json>) -> Result<Value, Error> {
457
+ match json {
458
+ None => Ok(self.ruby.to_symbol("no_default").as_value()),
459
+ Some(Json::Null) => Ok(self.ruby.qnil().as_value()),
460
+ Some(Json::Bool(value)) => Ok(self.ruby.into_value(*value)),
461
+ Some(Json::String(value)) => self.string(value),
462
+ Some(Json::Number(value)) => Ok(match value.as_i64() {
463
+ Some(value) => self.ruby.into_value(value),
464
+ None => self.ruby.into_value(
465
+ value
466
+ .as_f64()
467
+ .ok_or_else(|| self.error("invalid default number"))?,
468
+ ),
469
+ }),
470
+ _ => Err(self.error("invalid scalar default")),
471
+ }
472
+ }
473
+ }