arrow_json/reader/
decimal_array.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::marker::PhantomData;
19
20use arrow_array::builder::PrimitiveBuilder;
21use arrow_array::types::DecimalType;
22use arrow_array::Array;
23use arrow_cast::parse::parse_decimal;
24use arrow_data::ArrayData;
25use arrow_schema::ArrowError;
26
27use crate::reader::tape::{Tape, TapeElement};
28use crate::reader::ArrayDecoder;
29
30pub struct DecimalArrayDecoder<D: DecimalType> {
31    precision: u8,
32    scale: i8,
33    // Invariant and Send
34    phantom: PhantomData<fn(D) -> D>,
35}
36
37impl<D: DecimalType> DecimalArrayDecoder<D> {
38    pub fn new(precision: u8, scale: i8) -> Self {
39        Self {
40            precision,
41            scale,
42            phantom: PhantomData,
43        }
44    }
45}
46
47impl<D> ArrayDecoder for DecimalArrayDecoder<D>
48where
49    D: DecimalType,
50{
51    fn decode(&mut self, tape: &Tape<'_>, pos: &[u32]) -> Result<ArrayData, ArrowError> {
52        let mut builder = PrimitiveBuilder::<D>::with_capacity(pos.len());
53
54        for p in pos {
55            match tape.get(*p) {
56                TapeElement::Null => builder.append_null(),
57                TapeElement::String(idx) => {
58                    let s = tape.get_string(idx);
59                    let value = parse_decimal::<D>(s, self.precision, self.scale)?;
60                    builder.append_value(value)
61                }
62                TapeElement::Number(idx) => {
63                    let s = tape.get_string(idx);
64                    let value = parse_decimal::<D>(s, self.precision, self.scale)?;
65                    builder.append_value(value)
66                }
67                TapeElement::I64(high) => match tape.get(*p + 1) {
68                    TapeElement::I32(low) => {
69                        let val = (((high as i64) << 32) | (low as u32) as i64).to_string();
70                        let value = parse_decimal::<D>(&val, self.precision, self.scale)?;
71                        builder.append_value(value)
72                    }
73                    _ => unreachable!(),
74                },
75                TapeElement::I32(val) => {
76                    let s = val.to_string();
77                    let value = parse_decimal::<D>(&s, self.precision, self.scale)?;
78                    builder.append_value(value)
79                }
80                TapeElement::F64(high) => match tape.get(*p + 1) {
81                    TapeElement::F32(low) => {
82                        let val = f64::from_bits(((high as u64) << 32) | low as u64).to_string();
83                        let value = parse_decimal::<D>(&val, self.precision, self.scale)?;
84                        builder.append_value(value)
85                    }
86                    _ => unreachable!(),
87                },
88                TapeElement::F32(val) => {
89                    let s = f32::from_bits(val).to_string();
90                    let value = parse_decimal::<D>(&s, self.precision, self.scale)?;
91                    builder.append_value(value)
92                }
93                _ => return Err(tape.error(*p, "decimal")),
94            }
95        }
96
97        Ok(builder
98            .finish()
99            .with_precision_and_scale(self.precision, self.scale)?
100            .into_data())
101    }
102}