Skip to content
This repository has been archived by the owner on Jan 11, 2021. It is now read-only.

Commit

Permalink
Add Decimal support 2 (#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
sadikovi authored and sunchao committed Apr 30, 2018
1 parent cdfca93 commit a851c94
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 9 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ thrift = "0.0.4"
x86intrin = "0.4.3"
chrono = "0.4"
lz4 = "1.22"
num-bigint = "0.1"

[dev-dependencies]
lazy_static = "1"
Expand Down
109 changes: 108 additions & 1 deletion src/data_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use std::mem;

use basic::Type;
use byteorder::{BigEndian, ByteOrder};
use rand::{Rand, Rng};
use util::memory::{ByteBuffer, ByteBufferPtr};

Expand Down Expand Up @@ -147,7 +148,6 @@ impl Default for ByteArray {
}
}


impl PartialEq for ByteArray {
fn eq(&self, other: &ByteArray) -> bool {
self.data() == other.data()
Expand All @@ -167,6 +167,83 @@ impl Rand for ByteArray {
}
}

/// Rust representation for Decimal values.
///
/// This is not a representation of Parquet physical type, but rather a wrapper for
/// DECIMAL logical type, and serves as container for raw parts of decimal values:
/// unscaled value in bytes, precision and scale.
#[derive(Clone, Debug)]
pub enum Decimal {
/// Decimal backed by `i32`.
Int32 { value: [u8; 4], precision: i32, scale: i32 },
/// Decimal backed by `i64`.
Int64 { value: [u8; 8], precision: i32, scale: i32 },
/// Decimal backed by byte array.
Bytes { value: ByteArray, precision: i32, scale: i32 }
}

impl Decimal {
/// Creates new decimal value from `i32`.
pub fn from_i32(value: i32, precision: i32, scale: i32) -> Self {
let mut bytes = [0; 4];
BigEndian::write_i32(&mut bytes, value);
Decimal::Int32 { value: bytes, precision: precision, scale: scale }
}

/// Creates new decimal value from `i64`.
pub fn from_i64(value: i64, precision: i32, scale: i32) -> Self {
let mut bytes = [0; 8];
BigEndian::write_i64(&mut bytes, value);
Decimal::Int64 { value: bytes, precision: precision, scale: scale }
}

/// Creates new decimal value from `ByteArray`.
pub fn from_bytes(value: ByteArray, precision: i32, scale: i32) -> Self {
Decimal::Bytes { value: value, precision: precision, scale: scale }
}

/// Returns bytes of unscaled value.
pub fn data(&self) -> &[u8] {
match *self {
Decimal::Int32 { ref value, .. } => value,
Decimal::Int64 { ref value, .. } => value,
Decimal::Bytes { ref value, .. } => value.data()
}
}

/// Returns decimal precision.
pub fn precision(&self) -> i32 {
match *self {
Decimal::Int32 { precision, .. } => precision,
Decimal::Int64 { precision, .. } => precision,
Decimal::Bytes { precision, .. } => precision
}
}

/// Returns decimal scale.
pub fn scale(&self) -> i32 {
match *self {
Decimal::Int32 { scale, .. } => scale,
Decimal::Int64 { scale, .. } => scale,
Decimal::Bytes { scale, .. } => scale
}
}
}

impl Default for Decimal {
fn default() -> Self {
Self::from_i32(0, 0, 0)
}
}

impl PartialEq for Decimal {
fn eq(&self, other: &Decimal) -> bool {
self.precision() == other.precision() && self.scale() == other.scale() &&
self.data() == other.data()
}
}


/// Converts an instance of data type to a slice of bytes as `u8`.
pub trait AsBytes {
/// Returns slice of bytes for this data type.
Expand Down Expand Up @@ -210,6 +287,12 @@ impl AsBytes for ByteArray {
}
}

impl AsBytes for Decimal {
fn as_bytes(&self) -> &[u8] {
self.data()
}
}

impl AsBytes for Vec<u8> {
fn as_bytes(&self) -> &[u8] {
self.as_slice()
Expand Down Expand Up @@ -306,6 +389,14 @@ mod tests {
// Test ByteArray
let ba = ByteArray::from(vec![1, 2, 3]);
assert_eq!(ba.as_bytes(), &[1, 2, 3]);

// Test Decimal
let decimal = Decimal::from_i32(123, 5, 2);
assert_eq!(decimal.as_bytes(), &[0, 0, 0, 123]);
let decimal = Decimal::from_i64(123, 5, 2);
assert_eq!(decimal.as_bytes(), &[0, 0, 0, 0, 0, 0, 0, 123]);
let decimal = Decimal::from_bytes(ByteArray::from(vec![1, 2, 3]), 5, 2);
assert_eq!(decimal.as_bytes(), &[1, 2, 3]);
}

#[test]
Expand All @@ -328,4 +419,20 @@ mod tests {
buf.set_data(vec![6u8, 7u8, 8u8, 9u8, 10u8]);
assert_eq!(ByteArray::from(buf).data(), &[6u8, 7u8, 8u8, 9u8, 10u8]);
}

#[test]
fn test_decimal_partial_eq() {
assert_eq!(Decimal::default(), Decimal::from_i32(0, 0, 0));
assert_eq!(Decimal::from_i32(222, 5, 2), Decimal::from_i32(222, 5, 2));
assert_eq!(
Decimal::from_bytes(ByteArray::from(vec![0, 0, 0, 3]), 5, 2),
Decimal::from_i32(3, 5, 2)
);

assert!(Decimal::from_i32(222, 5, 2) != Decimal::from_i32(111, 5, 2));
assert!(Decimal::from_i32(222, 5, 2) != Decimal::from_i32(222, 6, 2));
assert!(Decimal::from_i32(222, 5, 2) != Decimal::from_i32(222, 5, 3));

assert!(Decimal::from_i64(222, 5, 2) != Decimal::from_i32(222, 5, 2));
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ extern crate x86intrin;
extern crate parquet_format;
extern crate chrono;
extern crate lz4;
extern crate num_bigint;

#[macro_use]
pub mod errors;
Expand Down
Loading

0 comments on commit a851c94

Please sign in to comment.