use std::ptr;
use reifydb_type::value::{duration::Duration, r#type::Type};
use crate::encoded::{row::EncodedRow, shape::RowShape};
impl RowShape {
pub fn set_duration(&self, row: &mut EncodedRow, index: usize, value: Duration) {
let field = &self.fields()[index];
debug_assert!(row.len() >= self.total_static_size());
debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Duration);
row.set_valid(index, true);
let months = value.get_months();
let days = value.get_days();
let nanos = value.get_nanos();
unsafe {
ptr::write_unaligned(
row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut i32,
months,
);
ptr::write_unaligned(
row.make_mut().as_mut_ptr().add(field.offset as usize + 4) as *mut i32,
days,
);
ptr::write_unaligned(
row.make_mut().as_mut_ptr().add(field.offset as usize + 8) as *mut i64,
nanos,
);
}
}
pub fn get_duration(&self, row: &EncodedRow, index: usize) -> Duration {
let field = &self.fields()[index];
debug_assert!(row.len() >= self.total_static_size());
debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Duration);
unsafe {
let months = (row.as_ptr().add(field.offset as usize) as *const i32).read_unaligned();
let days = (row.as_ptr().add(field.offset as usize + 4) as *const i32).read_unaligned();
let nanos = (row.as_ptr().add(field.offset as usize + 8) as *const i64).read_unaligned();
Duration::new(months, days, nanos).expect("stored duration must be valid")
}
}
pub fn try_get_duration(&self, row: &EncodedRow, index: usize) -> Option<Duration> {
if row.is_defined(index) && self.fields()[index].constraint.get_type() == Type::Duration {
Some(self.get_duration(row, index))
} else {
None
}
}
}
#[cfg(test)]
pub mod tests {
use reifydb_type::value::{duration::Duration, r#type::Type};
use crate::encoded::shape::RowShape;
#[test]
fn test_set_get_duration() {
let shape = RowShape::testing(&[Type::Duration]);
let mut row = shape.allocate();
let value = Duration::from_seconds(-7200).unwrap();
shape.set_duration(&mut row, 0, value.clone());
assert_eq!(shape.get_duration(&row, 0), value);
}
#[test]
fn test_try_get_duration() {
let shape = RowShape::testing(&[Type::Duration]);
let mut row = shape.allocate();
assert_eq!(shape.try_get_duration(&row, 0), None);
let test_duration = Duration::from_days(30).unwrap();
shape.set_duration(&mut row, 0, test_duration.clone());
assert_eq!(shape.try_get_duration(&row, 0), Some(test_duration));
}
#[test]
fn test_zero() {
let shape = RowShape::testing(&[Type::Duration]);
let mut row = shape.allocate();
let zero = Duration::default(); shape.set_duration(&mut row, 0, zero.clone());
assert_eq!(shape.get_duration(&row, 0), zero);
}
#[test]
fn test_various_durations() {
let shape = RowShape::testing(&[Type::Duration]);
let test_durations = [
Duration::from_seconds(0).unwrap(), Duration::from_seconds(60).unwrap(), Duration::from_seconds(3600).unwrap(), Duration::from_seconds(86400).unwrap(), Duration::from_days(7).unwrap(), Duration::from_days(30).unwrap(), Duration::from_weeks(52).unwrap(), ];
for duration in test_durations {
let mut row = shape.allocate();
shape.set_duration(&mut row, 0, duration.clone());
assert_eq!(shape.get_duration(&row, 0), duration);
}
}
#[test]
fn test_negative_durations() {
let shape = RowShape::testing(&[Type::Duration]);
let negative_durations = [
Duration::from_seconds(-60).unwrap(), Duration::from_seconds(-3600).unwrap(), Duration::from_seconds(-86400).unwrap(), Duration::from_days(-7).unwrap(), Duration::from_weeks(-4).unwrap(), ];
for duration in negative_durations {
let mut row = shape.allocate();
shape.set_duration(&mut row, 0, duration.clone());
assert_eq!(shape.get_duration(&row, 0), duration);
}
}
#[test]
fn test_complex_parts() {
let shape = RowShape::testing(&[Type::Duration]);
let mut row = shape.allocate();
let complex_duration = Duration::new(
6, 15, 123456789, )
.unwrap();
shape.set_duration(&mut row, 0, complex_duration.clone());
assert_eq!(shape.get_duration(&row, 0), complex_duration);
}
#[test]
fn test_mixed_with_other_types() {
let shape = RowShape::testing(&[Type::Duration, Type::Boolean, Type::Duration, Type::Int8]);
let mut row = shape.allocate();
let duration1 = Duration::from_hours(24).unwrap();
let duration2 = Duration::from_minutes(-30).unwrap();
shape.set_duration(&mut row, 0, duration1.clone());
shape.set_bool(&mut row, 1, true);
shape.set_duration(&mut row, 2, duration2.clone());
shape.set_i64(&mut row, 3, 987654321);
assert_eq!(shape.get_duration(&row, 0), duration1);
assert_eq!(shape.get_bool(&row, 1), true);
assert_eq!(shape.get_duration(&row, 2), duration2);
assert_eq!(shape.get_i64(&row, 3), 987654321);
}
#[test]
fn test_undefined_handling() {
let shape = RowShape::testing(&[Type::Duration, Type::Duration]);
let mut row = shape.allocate();
let duration = Duration::from_days(100).unwrap();
shape.set_duration(&mut row, 0, duration.clone());
assert_eq!(shape.try_get_duration(&row, 0), Some(duration));
assert_eq!(shape.try_get_duration(&row, 1), None);
shape.set_none(&mut row, 0);
assert_eq!(shape.try_get_duration(&row, 0), None);
}
#[test]
fn test_large_values() {
let shape = RowShape::testing(&[Type::Duration]);
let mut row = shape.allocate();
let large_duration = Duration::new(
120, 3650, 123456789012345, )
.unwrap();
shape.set_duration(&mut row, 0, large_duration.clone());
assert_eq!(shape.get_duration(&row, 0), large_duration);
}
#[test]
fn test_precision_preservation() {
let shape = RowShape::testing(&[Type::Duration]);
let mut row = shape.allocate();
let precise_duration = Duration::new(
5, 20, 999999999, )
.unwrap();
shape.set_duration(&mut row, 0, precise_duration.clone());
let retrieved = shape.get_duration(&row, 0);
assert_eq!(retrieved, precise_duration);
let orig_months = precise_duration.get_months();
let orig_days = precise_duration.get_days();
let orig_nanos = precise_duration.get_nanos();
let ret_months = retrieved.get_months();
let ret_days = retrieved.get_days();
let ret_nanos = retrieved.get_nanos();
assert_eq!(orig_months, ret_months);
assert_eq!(orig_days, ret_days);
assert_eq!(orig_nanos, ret_nanos);
}
#[test]
fn test_common_durations() {
let shape = RowShape::testing(&[Type::Duration]);
let common_durations = [
Duration::from_seconds(1).unwrap(), Duration::from_seconds(30).unwrap(), Duration::from_minutes(5).unwrap(), Duration::from_minutes(15).unwrap(), Duration::from_hours(1).unwrap(), Duration::from_hours(8).unwrap(), Duration::from_days(1).unwrap(), Duration::from_weeks(1).unwrap(), Duration::from_weeks(2).unwrap(), ];
for duration in common_durations {
let mut row = shape.allocate();
shape.set_duration(&mut row, 0, duration.clone());
assert_eq!(shape.get_duration(&row, 0), duration);
}
}
#[test]
fn test_boundary_values() {
let shape = RowShape::testing(&[Type::Duration]);
let boundary_durations = [
Duration::new(i32::MAX, 0, 0).unwrap(), Duration::new(i32::MIN, 0, 0).unwrap(), Duration::new(0, i32::MAX, 0).unwrap(), Duration::new(0, i32::MIN, 0).unwrap(), Duration::new(0, 0, i64::MAX).unwrap(), Duration::new(0, 0, i64::MIN).unwrap(), ];
for duration in boundary_durations {
let mut row = shape.allocate();
shape.set_duration(&mut row, 0, duration.clone());
assert_eq!(shape.get_duration(&row, 0), duration);
}
}
#[test]
fn test_try_get_duration_wrong_type() {
let shape = RowShape::testing(&[Type::Boolean]);
let mut row = shape.allocate();
shape.set_bool(&mut row, 0, true);
assert_eq!(shape.try_get_duration(&row, 0), None);
}
}