blob: aebea2222a4c83cb86986ac60a11e2b4e98960aa [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use std::io;
use crate::varint;
#[derive(Debug, Clone)]
pub enum Value {
Null,
Boolean(bool),
TinyInt(i8),
SmallInt(i16),
Integer(i32),
BigInt(i64),
Float(f32),
Double(f64),
Date(i32),
Time(i32),
String(Vec<u8>),
Bytes(Vec<u8>),
DecimalCompact(i64),
DecimalLarge(Vec<u8>),
TimestampMillis(i64),
TimestampMicros(i64),
TimestampNanos { millis: i64, nanos_of_milli: i32 },
}
impl Value {
pub fn is_null(&self) -> bool {
matches!(self, Value::Null)
}
pub fn to_be_bytes(&self) -> Vec<u8> {
match self {
Value::Null => Vec::new(),
Value::Boolean(v) => vec![if *v { 1 } else { 0 }],
Value::TinyInt(v) => vec![*v as u8],
Value::SmallInt(v) => v.to_be_bytes().to_vec(),
Value::Integer(v) | Value::Date(v) | Value::Time(v) => v.to_be_bytes().to_vec(),
Value::BigInt(v)
| Value::DecimalCompact(v)
| Value::TimestampMillis(v)
| Value::TimestampMicros(v) => v.to_be_bytes().to_vec(),
Value::Float(v) => v.to_bits().to_be_bytes().to_vec(),
Value::Double(v) => v.to_bits().to_be_bytes().to_vec(),
Value::TimestampNanos {
millis,
nanos_of_milli,
} => {
let mut buf = millis.to_be_bytes().to_vec();
buf.extend_from_slice(&nanos_of_milli.to_be_bytes());
buf
}
Value::String(b) | Value::Bytes(b) | Value::DecimalLarge(b) => b.clone(),
}
}
}
fn type_mismatch(expected: &str, value: &Value) -> io::Error {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("type mismatch: expected {}, got {:?}", expected, value),
)
}
pub fn write_fixed(buf: &mut Vec<u8>, value: &Value, width: i32) -> io::Result<()> {
match width {
1 => match value {
Value::Boolean(v) => buf.push(if *v { 1 } else { 0 }),
Value::TinyInt(v) => buf.push(*v as u8),
_ => return Err(type_mismatch("Boolean or TinyInt", value)),
},
2 => match value {
Value::SmallInt(v) => buf.extend_from_slice(&v.to_be_bytes()),
_ => return Err(type_mismatch("SmallInt", value)),
},
4 => match value {
Value::Integer(v) | Value::Date(v) | Value::Time(v) => {
buf.extend_from_slice(&v.to_be_bytes());
}
Value::Float(v) => {
buf.extend_from_slice(&v.to_bits().to_be_bytes());
}
_ => return Err(type_mismatch("Integer/Date/Time/Float", value)),
},
8 => match value {
Value::BigInt(v)
| Value::DecimalCompact(v)
| Value::TimestampMillis(v)
| Value::TimestampMicros(v) => {
buf.extend_from_slice(&v.to_be_bytes());
}
Value::Double(v) => {
buf.extend_from_slice(&v.to_bits().to_be_bytes());
}
_ => return Err(type_mismatch("BigInt/Decimal/Timestamp/Double", value)),
},
12 => match value {
Value::TimestampNanos {
millis,
nanos_of_milli,
} => {
buf.extend_from_slice(&millis.to_be_bytes());
buf.extend_from_slice(&nanos_of_milli.to_be_bytes());
}
_ => return Err(type_mismatch("TimestampNanos", value)),
},
_ => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("unsupported fixed width {}", width),
))
}
}
Ok(())
}
pub fn write_variable(buf: &mut Vec<u8>, value: &Value) -> io::Result<()> {
match value {
Value::String(bytes) | Value::Bytes(bytes) | Value::DecimalLarge(bytes) => {
varint::encode(buf, bytes.len() as u32);
buf.extend_from_slice(bytes);
Ok(())
}
_ => Err(type_mismatch("String/Bytes/DecimalLarge", value)),
}
}
pub fn extract_fixed_key(buf: &[u8], pos: usize, width: i32) -> u64 {
match width {
1 => buf[pos] as u64,
2 => u16::from_be_bytes([buf[pos], buf[pos + 1]]) as u64,
4 => u32::from_be_bytes([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]]) as u64,
8 => u64::from_be_bytes([
buf[pos],
buf[pos + 1],
buf[pos + 2],
buf[pos + 3],
buf[pos + 4],
buf[pos + 5],
buf[pos + 6],
buf[pos + 7],
]),
_ => 0,
}
}