1use std::sync::Arc;
2
3use alloy_dyn_abi::{DynSolCall, DynSolEvent, DynSolType, DynSolValue, Specifier};
4use alloy_primitives::{I256, U256};
5use anyhow::{anyhow, Context, Result};
6use arrow::{
7 array::{builder, Array, ArrowPrimitiveType, BinaryArray, ListArray, RecordBatch, StructArray},
8 buffer::{NullBuffer, OffsetBuffer},
9 datatypes::{
10 DataType, Field, Fields, Int16Type, Int32Type, Int64Type, Int8Type, Schema, UInt16Type,
11 UInt32Type, UInt64Type, UInt8Type,
12 },
13};
14
15pub fn signature_to_topic0(signature: &str) -> Result<[u8; 32]> {
17 let event = alloy_json_abi::Event::parse(signature).context("parse event signature")?;
18 Ok(event.selector().into())
19}
20
21pub fn decode_call_inputs(
28 signature: &str,
29 data: &BinaryArray,
30 allow_decode_fail: bool,
31) -> Result<RecordBatch> {
32 decode_call_impl::<true>(signature, data, allow_decode_fail)
33}
34
35pub fn decode_call_outputs(
42 signature: &str,
43 data: &BinaryArray,
44 allow_decode_fail: bool,
45) -> Result<RecordBatch> {
46 decode_call_impl::<false>(signature, data, allow_decode_fail)
47}
48
49fn decode_call_impl<const IS_INPUT: bool>(
52 signature: &str,
53 data: &BinaryArray,
54 allow_decode_fail: bool,
55) -> Result<RecordBatch> {
56 let (call, resolved) = resolve_function_signature(signature)?;
57
58 let schema = function_signature_to_arrow_schemas_impl(&call, &resolved)
59 .context("convert event signature to arrow schema")?;
60 let schema = if IS_INPUT { schema.0 } else { schema.1 };
61
62 let mut arrays: Vec<Arc<dyn Array + 'static>> = Vec::with_capacity(schema.fields().len());
63
64 let mut decoded = Vec::<Option<DynSolValue>>::with_capacity(data.len());
65
66 for blob in data.iter() {
67 match blob {
68 Some(blob) => {
69 let decode_res = if IS_INPUT {
70 resolved.abi_decode_input(blob, false)
71 } else {
72 resolved.abi_decode_output(blob, false)
73 };
74 match decode_res {
75 Ok(data) => decoded.push(Some(DynSolValue::Tuple(data))),
76 Err(e) if allow_decode_fail => {
77 log::debug!("failed to decode function call data: {}", e);
78 decoded.push(None);
79 }
80 Err(e) => {
81 return Err(anyhow!("failed to decode function call data: {}", e));
82 }
83 }
84 }
85 None => decoded.push(None),
86 }
87 }
88
89 let sol_type = if IS_INPUT {
90 DynSolType::Tuple(resolved.types().to_vec())
91 } else {
92 DynSolType::Tuple(resolved.returns().types().to_vec())
93 };
94
95 let array = to_arrow(&sol_type, decoded).context("map params to arrow")?;
96 match array.data_type() {
97 DataType::Struct(_) => {
98 let arr = array.as_any().downcast_ref::<StructArray>().unwrap();
99
100 for f in arr.columns().iter() {
101 arrays.push(f.clone());
102 }
103 }
104 _ => unreachable!(),
105 }
106
107 RecordBatch::try_new(Arc::new(schema), arrays).context("construct arrow batch")
108}
109
110pub fn function_signature_to_arrow_schemas(signature: &str) -> Result<(Schema, Schema)> {
112 let (func, resolved) = resolve_function_signature(signature)?;
113 function_signature_to_arrow_schemas_impl(&func, &resolved)
114}
115
116fn function_signature_to_arrow_schemas_impl(
117 func: &alloy_json_abi::Function,
118 call: &DynSolCall,
119) -> Result<(Schema, Schema)> {
120 let mut input_fields = Vec::with_capacity(call.types().len());
121 let mut output_fields = Vec::with_capacity(call.returns().types().len());
122
123 for (i, (sol_t, param)) in call.types().iter().zip(func.inputs.iter()).enumerate() {
124 let dtype = to_arrow_dtype(sol_t).context("map to arrow type")?;
125 let name = if param.name() == "" {
126 format!("param{}", i)
127 } else {
128 param.name().to_owned()
129 };
130 input_fields.push(Arc::new(Field::new(name, dtype, true)));
131 }
132
133 for (i, (sol_t, param)) in call
134 .returns()
135 .types()
136 .iter()
137 .zip(func.outputs.iter())
138 .enumerate()
139 {
140 let dtype = to_arrow_dtype(sol_t).context("map to arrow type")?;
141 let name = if param.name() == "" {
142 format!("param{}", i)
143 } else {
144 param.name().to_owned()
145 };
146 output_fields.push(Arc::new(Field::new(name, dtype, true)));
147 }
148
149 Ok((Schema::new(input_fields), Schema::new(output_fields)))
150}
151
152fn resolve_function_signature(signature: &str) -> Result<(alloy_json_abi::Function, DynSolCall)> {
153 let event = alloy_json_abi::Function::parse(signature).context("parse function signature")?;
154 let resolved = event.resolve().context("resolve function signature")?;
155
156 Ok((event, resolved))
157}
158
159pub fn decode_events(
166 signature: &str,
167 data: &RecordBatch,
168 allow_decode_fail: bool,
169) -> Result<RecordBatch> {
170 let (event, resolved) = resolve_event_signature(signature)?;
171
172 let schema = event_signature_to_arrow_schema_impl(&event, &resolved)
173 .context("convert event signature to arrow schema")?;
174
175 let mut arrays: Vec<Arc<dyn Array + 'static>> = Vec::with_capacity(schema.fields().len());
176
177 for (sol_type, topic_name) in resolved
178 .indexed()
179 .iter()
180 .zip(["topic1", "topic2", "topic3"].iter())
181 {
182 let col = data
183 .column_by_name(topic_name)
184 .context("get topic column")?
185 .as_any()
186 .downcast_ref::<BinaryArray>()
187 .context("get topic column as binary")?;
188
189 let mut decoded = Vec::<Option<DynSolValue>>::with_capacity(col.len());
190
191 for blob in col.iter() {
192 match blob {
193 Some(blob) => match sol_type.abi_decode(blob) {
194 Ok(data) => decoded.push(Some(data)),
195 Err(e) if allow_decode_fail => {
196 log::debug!("failed to decode a topic: {}", e);
197 decoded.push(None);
198 }
199 Err(e) => {
200 return Err(anyhow!("failed to decode a topic: {}", e));
201 }
202 },
203 None => decoded.push(None),
204 }
205 }
206
207 arrays.push(to_arrow(sol_type, decoded).context("map topic to arrow")?);
208 }
209
210 let body_col = data
211 .column_by_name("data")
212 .context("get data column")?
213 .as_any()
214 .downcast_ref::<BinaryArray>()
215 .context("get data column as binary")?;
216 let body_sol_type = DynSolType::Tuple(resolved.body().to_vec());
217
218 let mut body_decoded = Vec::<Option<DynSolValue>>::with_capacity(body_col.len());
219
220 for blob in body_col.iter() {
221 match blob {
222 Some(blob) => match body_sol_type.abi_decode_sequence(blob) {
223 Ok(data) => body_decoded.push(Some(data)),
224 Err(e) if allow_decode_fail => {
225 log::debug!("failed to decode body: {}", e);
226 body_decoded.push(None);
227 }
228 Err(e) => {
229 return Err(anyhow!("failed to decode body: {}", e));
230 }
231 },
232 None => body_decoded.push(None),
233 }
234 }
235
236 let body_array = to_arrow(&body_sol_type, body_decoded).context("map body to arrow")?;
237 match body_array.data_type() {
238 DataType::Struct(_) => {
239 let arr = body_array.as_any().downcast_ref::<StructArray>().unwrap();
240
241 for f in arr.columns().iter() {
242 arrays.push(f.clone());
243 }
244 }
245 _ => unreachable!(),
246 }
247
248 RecordBatch::try_new(Arc::new(schema), arrays).context("construct arrow batch")
249}
250
251pub fn event_signature_to_arrow_schema(signature: &str) -> Result<Schema> {
253 let (resolved, event) = resolve_event_signature(signature)?;
254 event_signature_to_arrow_schema_impl(&resolved, &event)
255}
256
257fn event_signature_to_arrow_schema_impl(
258 sig: &alloy_json_abi::Event,
259 event: &DynSolEvent,
260) -> Result<Schema> {
261 let num_fields = event.indexed().len() + event.body().len();
262 let mut fields = Vec::<Arc<Field>>::with_capacity(num_fields);
263 let mut names = Vec::with_capacity(num_fields);
264
265 for (i, input) in sig.inputs.iter().enumerate() {
266 if input.indexed {
267 let name = if input.name.is_empty() {
268 format!("param{}", i)
269 } else {
270 input.name.clone()
271 };
272 names.push(name);
273 }
274 }
275 for (i, input) in sig.inputs.iter().enumerate() {
276 if !input.indexed {
277 let name = if input.name.is_empty() {
278 format!("param{}", i)
279 } else {
280 input.name.clone()
281 };
282 names.push(name);
283 }
284 }
285
286 for (sol_t, name) in event.indexed().iter().chain(event.body()).zip(names) {
287 let dtype = to_arrow_dtype(sol_t).context("map to arrow type")?;
288 fields.push(Arc::new(Field::new(name, dtype, true)));
289 }
290
291 Ok(Schema::new(fields))
292}
293
294fn resolve_event_signature(signature: &str) -> Result<(alloy_json_abi::Event, DynSolEvent)> {
295 let event = alloy_json_abi::Event::parse(signature).context("parse event signature")?;
296 let resolved = event.resolve().context("resolve event signature")?;
297
298 Ok((event, resolved))
299}
300
301fn to_arrow_dtype(sol_type: &DynSolType) -> Result<DataType> {
302 match sol_type {
303 DynSolType::Bool => Ok(DataType::Boolean),
304 DynSolType::Bytes => Ok(DataType::Binary),
305 DynSolType::String => Ok(DataType::Utf8),
306 DynSolType::Address => Ok(DataType::Binary),
307 DynSolType::Int(num_bits) => Ok(num_bits_to_int_type(*num_bits)),
308 DynSolType::Uint(num_bits) => Ok(num_bits_to_uint_type(*num_bits)),
309 DynSolType::Array(inner_type) => {
310 let inner_type = to_arrow_dtype(inner_type).context("map inner")?;
311 Ok(DataType::List(Arc::new(Field::new("", inner_type, true))))
312 }
313 DynSolType::Function => Err(anyhow!(
314 "decoding 'Function' typed value in function signature isn't supported."
315 )),
316 DynSolType::FixedArray(inner_type, _) => {
317 let inner_type = to_arrow_dtype(inner_type).context("map inner")?;
318 Ok(DataType::List(Arc::new(Field::new("", inner_type, true))))
319 }
320 DynSolType::Tuple(fields) => {
321 let mut arrow_fields = Vec::<Arc<Field>>::with_capacity(fields.len());
322
323 for (i, f) in fields.iter().enumerate() {
324 let inner_dt = to_arrow_dtype(f).context("map field dt")?;
325 arrow_fields.push(Arc::new(Field::new(format!("param{}", i), inner_dt, true)));
326 }
327
328 Ok(DataType::Struct(Fields::from(arrow_fields)))
329 }
330 DynSolType::FixedBytes(_) => Ok(DataType::Binary),
331 }
332}
333
334fn num_bits_to_uint_type(num_bits: usize) -> DataType {
335 if num_bits <= 8 {
336 DataType::UInt8
337 } else if num_bits <= 16 {
338 DataType::UInt16
339 } else if num_bits <= 32 {
340 DataType::UInt32
341 } else if num_bits <= 64 {
342 DataType::UInt64
343 } else if num_bits <= 128 {
344 DataType::Decimal128(38, 0)
345 } else if num_bits <= 256 {
346 DataType::Decimal256(76, 0)
347 } else {
348 unreachable!()
349 }
350}
351
352fn num_bits_to_int_type(num_bits: usize) -> DataType {
353 if num_bits <= 8 {
354 DataType::Int8
355 } else if num_bits <= 16 {
356 DataType::Int16
357 } else if num_bits <= 32 {
358 DataType::Int32
359 } else if num_bits <= 64 {
360 DataType::Int64
361 } else if num_bits <= 128 {
362 DataType::Decimal128(38, 0)
363 } else if num_bits <= 256 {
364 DataType::Decimal256(76, 0)
365 } else {
366 unreachable!()
367 }
368}
369
370fn to_arrow(sol_type: &DynSolType, sol_values: Vec<Option<DynSolValue>>) -> Result<Arc<dyn Array>> {
371 match sol_type {
372 DynSolType::Bool => to_bool(&sol_values),
373 DynSolType::Bytes => to_binary(&sol_values),
374 DynSolType::String => to_string(&sol_values),
375 DynSolType::Address => to_binary(&sol_values),
376 DynSolType::Int(num_bits) => to_int(*num_bits, &sol_values),
377 DynSolType::Uint(num_bits) => to_uint(*num_bits, &sol_values),
378 DynSolType::Array(inner_type) => to_list(inner_type, sol_values),
379 DynSolType::Function => Err(anyhow!(
380 "decoding 'Function' typed value in function signature isn't supported."
381 )),
382 DynSolType::FixedArray(inner_type, _) => to_list(inner_type, sol_values),
383 DynSolType::Tuple(fields) => to_struct(fields, sol_values),
384 DynSolType::FixedBytes(_) => to_binary(&sol_values),
385 }
386}
387
388fn to_int(num_bits: usize, sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>> {
389 match num_bits_to_int_type(num_bits) {
390 DataType::Int8 => to_int_impl::<Int8Type>(num_bits, sol_values),
391 DataType::Int16 => to_int_impl::<Int16Type>(num_bits, sol_values),
392 DataType::Int32 => to_int_impl::<Int32Type>(num_bits, sol_values),
393 DataType::Int64 => to_int_impl::<Int64Type>(num_bits, sol_values),
394 DataType::Decimal128(_, _) => to_decimal128(num_bits, sol_values),
395 DataType::Decimal256(_, _) => to_decimal256(num_bits, sol_values),
396 _ => unreachable!(),
397 }
398}
399
400fn to_uint(num_bits: usize, sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>> {
401 match num_bits_to_int_type(num_bits) {
402 DataType::UInt8 => to_int_impl::<UInt8Type>(num_bits, sol_values),
403 DataType::UInt16 => to_int_impl::<UInt16Type>(num_bits, sol_values),
404 DataType::UInt32 => to_int_impl::<UInt32Type>(num_bits, sol_values),
405 DataType::UInt64 => to_int_impl::<UInt64Type>(num_bits, sol_values),
406 DataType::Decimal128(_, _) => to_decimal128(num_bits, sol_values),
407 DataType::Decimal256(_, _) => to_decimal256(num_bits, sol_values),
408 _ => unreachable!(),
409 }
410}
411
412fn to_decimal128(num_bits: usize, sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>> {
413 let mut builder = builder::Decimal128Builder::new();
414
415 for val in sol_values.iter() {
416 match val {
417 Some(val) => match val {
418 DynSolValue::Int(v, nb) => {
419 assert_eq!(num_bits, *nb);
420
421 let v = i128::try_from(*v).context("convert to i128")?;
422
423 builder.append_value(v);
424 }
425 DynSolValue::Uint(v, nb) => {
426 assert_eq!(num_bits, *nb);
427
428 let v = i128::try_from(*v).context("convert to i128")?;
429
430 builder.append_value(v);
431 }
432 _ => {
433 return Err(anyhow!(
434 "found unexpected value. Expected: bool, Found: {:?}",
435 val
436 ));
437 }
438 },
439 None => {
440 builder.append_null();
441 }
442 }
443 }
444
445 builder = builder.with_data_type(DataType::Decimal128(38, 0));
446
447 Ok(Arc::new(builder.finish()))
448}
449
450fn to_decimal256(num_bits: usize, sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>> {
451 let mut builder = builder::Decimal256Builder::new();
452
453 for val in sol_values.iter() {
454 match val {
455 Some(val) => match val {
456 DynSolValue::Int(v, nb) => {
457 assert_eq!(num_bits, *nb);
458
459 let v = arrow::datatypes::i256::from_be_bytes(v.to_be_bytes::<32>());
460
461 builder.append_value(v);
462 }
463 DynSolValue::Uint(v, nb) => {
464 assert_eq!(num_bits, *nb);
465 let v = I256::try_from(*v).context("map u256 to i256")?;
466
467 builder
468 .append_value(arrow::datatypes::i256::from_be_bytes(v.to_be_bytes::<32>()));
469 }
470 _ => {
471 return Err(anyhow!(
472 "found unexpected value. Expected: bool, Found: {:?}",
473 val
474 ));
475 }
476 },
477 None => {
478 builder.append_null();
479 }
480 }
481 }
482
483 builder = builder.with_data_type(DataType::Decimal256(76, 0));
484
485 Ok(Arc::new(builder.finish()))
486}
487
488fn to_int_impl<T>(num_bits: usize, sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>>
489where
490 T: ArrowPrimitiveType,
491 T::Native: TryFrom<I256> + TryFrom<U256>,
492{
493 let mut builder = builder::PrimitiveBuilder::<T>::new();
494
495 for val in sol_values.iter() {
496 match val {
497 Some(val) => match val {
498 DynSolValue::Int(v, nb) => {
499 assert_eq!(num_bits, *nb);
500 builder.append_value(match T::Native::try_from(*v) {
501 Ok(v) => v,
502 Err(_) => unreachable!(),
503 });
504 }
505 DynSolValue::Uint(v, nb) => {
506 assert_eq!(num_bits, *nb);
507 builder.append_value(match T::Native::try_from(*v) {
508 Ok(v) => v,
509 Err(_) => unreachable!(),
510 });
511 }
512 _ => {
513 return Err(anyhow!(
514 "found unexpected value. Expected: bool, Found: {:?}",
515 val
516 ));
517 }
518 },
519 None => {
520 builder.append_null();
521 }
522 }
523 }
524
525 Ok(Arc::new(builder.finish()))
526}
527
528fn to_list(sol_type: &DynSolType, sol_values: Vec<Option<DynSolValue>>) -> Result<Arc<dyn Array>> {
529 let mut lengths = Vec::with_capacity(sol_values.len());
530 let mut values = Vec::with_capacity(sol_values.len() * 2);
531 let mut validity = Vec::with_capacity(sol_values.len() * 2);
532
533 let mut all_valid = true;
534
535 for val in sol_values {
536 match val {
537 Some(val) => match val {
538 DynSolValue::Array(inner_vals) | DynSolValue::FixedArray(inner_vals) => {
539 lengths.push(inner_vals.len());
540 values.extend(inner_vals.into_iter().map(Some));
541 validity.push(true);
542 }
543 _ => {
544 return Err(anyhow!(
545 "found unexpected value. Expected list type, Found: {:?}",
546 val
547 ));
548 }
549 },
550 None => {
551 lengths.push(0);
552 validity.push(false);
553 all_valid = false;
554 }
555 }
556 }
557
558 let values = to_arrow(sol_type, values).context("map inner")?;
559 let field = Field::new(
560 "",
561 to_arrow_dtype(sol_type).context("construct data type")?,
562 true,
563 );
564 let list_arr = ListArray::try_new(
565 Arc::new(field),
566 OffsetBuffer::from_lengths(lengths),
567 values,
568 if all_valid {
569 None
570 } else {
571 Some(NullBuffer::from(validity))
572 },
573 )
574 .context("construct list array")?;
575 Ok(Arc::new(list_arr))
576}
577
578fn to_struct(
579 fields: &[DynSolType],
580 sol_values: Vec<Option<DynSolValue>>,
581) -> Result<Arc<dyn Array>> {
582 let mut values = vec![Vec::with_capacity(sol_values.len()); fields.len()];
583
584 for val in sol_values.iter() {
588 match val {
589 Some(val) => match val {
590 DynSolValue::Tuple(inner_vals) => {
591 if values.len() != inner_vals.len() {
592 return Err(anyhow!(
593 "found unexpected length tuple value. Expected: {}, Found: {}",
594 values.len(),
595 inner_vals.len()
596 ));
597 }
598 for (v, inner) in values.iter_mut().zip(inner_vals) {
599 v.push(Some(inner.clone()));
600 }
601 }
602 _ => {
603 return Err(anyhow!(
604 "found unexpected value. Expected: tuple, Found: {:?}",
605 val
606 ));
607 }
608 },
609 None => {
610 for v in values.iter_mut() {
611 v.push(None);
612 }
613 }
614 }
615 }
616
617 let mut arrays = Vec::with_capacity(fields.len());
618
619 for (sol_type, arr_vals) in fields.iter().zip(values.into_iter()) {
620 arrays.push(to_arrow(sol_type, arr_vals)?);
621 }
622
623 let fields = arrays
624 .iter()
625 .enumerate()
626 .map(|(i, arr)| Field::new(format!("param{}", i), arr.data_type().clone(), true))
627 .collect::<Vec<_>>();
628 let schema = Arc::new(Schema::new(fields));
629
630 let batch = RecordBatch::try_new(schema, arrays).context("construct record batch")?;
631
632 Ok(Arc::new(StructArray::from(batch)))
633}
634
635fn to_bool(sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>> {
636 let mut builder = builder::BooleanBuilder::new();
637
638 for val in sol_values.iter() {
639 match val {
640 Some(val) => match val {
641 DynSolValue::Bool(b) => {
642 builder.append_value(*b);
643 }
644 _ => {
645 return Err(anyhow!(
646 "found unexpected value. Expected: bool, Found: {:?}",
647 val
648 ));
649 }
650 },
651 None => {
652 builder.append_null();
653 }
654 }
655 }
656
657 Ok(Arc::new(builder.finish()))
658}
659
660fn to_binary(sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>> {
661 let mut builder = builder::BinaryBuilder::new();
662
663 for val in sol_values.iter() {
664 match val {
665 Some(val) => match val {
666 DynSolValue::Bytes(data) => {
667 builder.append_value(data);
668 }
669 DynSolValue::FixedBytes(data, _) => {
670 builder.append_value(data);
671 }
672 DynSolValue::Address(data) => {
673 builder.append_value(data);
674 }
675 DynSolValue::Uint(v, _) => {
676 builder.append_value(v.to_be_bytes::<32>());
677 }
678 DynSolValue::Int(v, _) => {
679 builder.append_value(v.to_be_bytes::<32>());
680 }
681 _ => {
682 return Err(anyhow!(
683 "found unexpected value. Expected a binary type, Found: {:?}",
684 val
685 ));
686 }
687 },
688 None => {
689 builder.append_null();
690 }
691 }
692 }
693
694 Ok(Arc::new(builder.finish()))
695}
696
697fn to_string(sol_values: &[Option<DynSolValue>]) -> Result<Arc<dyn Array>> {
698 let mut builder = builder::StringBuilder::new();
699
700 for val in sol_values.iter() {
701 match val {
702 Some(val) => match val {
703 DynSolValue::String(s) => {
704 builder.append_value(s);
705 }
706 _ => {
707 return Err(anyhow!(
708 "found unexpected value. Expected string, Found: {:?}",
709 val
710 ));
711 }
712 },
713 None => {
714 builder.append_null();
715 }
716 }
717 }
718
719 Ok(Arc::new(builder.finish()))
720}
721
722#[cfg(test)]
723mod tests {
724 use super::*;
725
726 #[test]
727 fn nested_event_signature_to_schema() {
728 let sig = "ConfiguredQuests(address editor, uint256[][], address indexed my_addr, (bool,bool[],(bool, uint256[]))[] questDetails)";
729
730 let schema = event_signature_to_arrow_schema(sig).unwrap();
731
732 let expected_schema = Schema::new(vec![
733 Arc::new(Field::new("my_addr", DataType::Binary, true)),
734 Arc::new(Field::new("editor", DataType::Binary, true)),
735 Arc::new(Field::new(
736 "param1",
737 DataType::List(Arc::new(Field::new(
738 "",
739 DataType::List(Arc::new(Field::new("", DataType::Decimal256(76, 0), true))),
740 true,
741 ))),
742 true,
743 )),
744 Arc::new(Field::new(
745 "questDetails",
746 DataType::List(Arc::new(Field::new(
747 "",
748 DataType::Struct(Fields::from(vec![
749 Arc::new(Field::new("param0", DataType::Boolean, true)),
750 Arc::new(Field::new(
751 "param1",
752 DataType::List(Arc::new(Field::new("", DataType::Boolean, true))),
753 true,
754 )),
755 Arc::new(Field::new(
756 "param2",
757 DataType::Struct(Fields::from(vec![
758 Arc::new(Field::new("param0", DataType::Boolean, true)),
759 Arc::new(Field::new(
760 "param1",
761 DataType::List(Arc::new(Field::new(
762 "",
763 DataType::Decimal256(76, 0),
764 true,
765 ))),
766 true,
767 )),
768 ])),
769 true,
770 )),
771 ])),
772 true,
773 ))),
774 true,
775 )),
776 ]);
777
778 assert_eq!(schema, expected_schema);
779 }
780
781 #[test]
782 fn i256_to_arrow_i256() {
783 for val in [
784 I256::MIN,
785 I256::MAX,
786 I256::MAX / I256::try_from(2i32).unwrap(),
787 ] {
788 let out = arrow::datatypes::i256::from_be_bytes(val.to_be_bytes::<32>());
789
790 assert_eq!(val.to_string(), out.to_string());
791 }
792 }
793}