use crate::types::FieldType;
use crate::varint::decode_varint;
fn write_int_to_point(point: &mut [u8], offset: usize, value: i64, size: usize) {
let bytes = value.to_le_bytes();
point[offset..offset + size].copy_from_slice(&bytes[..size]);
}
pub enum FieldDecoder {
Copy { offset: usize, size: usize },
Int {
offset: usize,
size: usize,
prev: i64,
},
Float32Lossy {
offset: usize,
multiplier: f32,
prev: i64,
},
Float64Lossy {
offset: usize,
multiplier: f64,
prev: i64,
},
Float64Xor { offset: usize, prev_bits: u64 },
FloatNLossy {
offsets: [usize; 4],
multipliers: [f32; 4],
prev: [i32; 4],
count: usize,
},
}
impl FieldDecoder {
pub fn reset(&mut self) {
match self {
FieldDecoder::Int { prev, .. } => *prev = 0,
FieldDecoder::Float32Lossy { prev, .. } => *prev = 0,
FieldDecoder::Float64Lossy { prev, .. } => *prev = 0,
FieldDecoder::Float64Xor { prev_bits, .. } => *prev_bits = 0,
FieldDecoder::FloatNLossy { prev, .. } => *prev = [0i32; 4],
FieldDecoder::Copy { .. } => {}
}
}
pub fn min_input_bytes(&self) -> usize {
match self {
FieldDecoder::Copy { size, .. } => *size,
FieldDecoder::Int { .. } => 1,
FieldDecoder::Float32Lossy { .. } => 1,
FieldDecoder::Float64Lossy { .. } => 1,
FieldDecoder::Float64Xor { .. } => 8,
FieldDecoder::FloatNLossy { count, .. } => *count,
}
}
pub fn decode(&mut self, input: &[u8], point: &mut [u8]) -> crate::Result<usize> {
match self {
FieldDecoder::Copy { offset, size } => {
point[*offset..*offset + *size].copy_from_slice(&input[..*size]);
Ok(*size)
}
FieldDecoder::Int { offset, size, prev } => {
let (diff, consumed) = decode_varint(input)?;
let value = *prev + diff;
*prev = value;
write_int_to_point(point, *offset, value, *size);
Ok(consumed)
}
FieldDecoder::Float32Lossy {
offset,
multiplier,
prev,
} => {
if input[0] == 0 {
point[*offset..*offset + 4].copy_from_slice(&f32::NAN.to_le_bytes());
*prev = 0;
return Ok(1);
}
let (diff, consumed) = decode_varint(input)?;
let value = *prev + diff;
*prev = value;
let float_val = value as f32 * *multiplier;
point[*offset..*offset + 4].copy_from_slice(&float_val.to_le_bytes());
Ok(consumed)
}
FieldDecoder::Float64Lossy {
offset,
multiplier,
prev,
} => {
if input[0] == 0 {
point[*offset..*offset + 8].copy_from_slice(&f64::NAN.to_le_bytes());
*prev = 0;
return Ok(1);
}
let (diff, consumed) = decode_varint(input)?;
let value = *prev + diff;
*prev = value;
let float_val = value as f64 * *multiplier;
point[*offset..*offset + 8].copy_from_slice(&float_val.to_le_bytes());
Ok(consumed)
}
FieldDecoder::Float64Xor { offset, prev_bits } => {
let residual = u64::from_le_bytes(input[..8].try_into().unwrap());
let current = residual ^ *prev_bits;
*prev_bits = current;
point[*offset..*offset + 8].copy_from_slice(¤t.to_le_bytes());
Ok(8)
}
FieldDecoder::FloatNLossy {
offsets,
multipliers,
prev,
count,
} => {
let n = *count;
let mut consumed = 0;
for i in 0..n {
if consumed >= input.len() {
return Err(crate::Error::Truncated("FloatNLossy: truncated".into()));
}
let b0 = input[consumed];
if b0 == 0 {
prev[i] = 0;
point[offsets[i]..offsets[i] + 4].copy_from_slice(&f32::NAN.to_le_bytes());
consumed += 1;
} else if b0 & 0x80 == 0 {
let uval = (b0 as u32) - 1;
let diff = ((uval >> 1) as i32) ^ -((uval & 1) as i32);
let new_val = diff.wrapping_add(prev[i]);
prev[i] = new_val;
let float_val = new_val as f32 * multipliers[i];
point[offsets[i]..offsets[i] + 4].copy_from_slice(&float_val.to_le_bytes());
consumed += 1;
} else {
let (diff, n_bytes) = decode_varint(&input[consumed..])?;
let new_val = (diff as i32).wrapping_add(prev[i]);
prev[i] = new_val;
let float_val = new_val as f32 * multipliers[i];
point[offsets[i]..offsets[i] + 4].copy_from_slice(&float_val.to_le_bytes());
consumed += n_bytes;
}
}
Ok(consumed)
}
}
}
}
pub fn build_decoders(
fields: &[crate::types::PointField],
encoding_opt: crate::types::EncodingOptions,
) -> Vec<FieldDecoder> {
use crate::types::EncodingOptions;
let mut decoders: Vec<FieldDecoder> = Vec::new();
let mut start_index = 0;
if encoding_opt == EncodingOptions::None {
for field in fields {
decoders.push(FieldDecoder::Copy {
offset: field.offset as usize,
size: field.field_type.size_of(),
});
}
return decoders;
}
if encoding_opt == EncodingOptions::Lossy {
let floats_count = fields
.iter()
.take_while(|f| f.field_type == FieldType::Float32 && f.resolution.is_some())
.count();
if floats_count == 3 || floats_count == 4 {
let mut offsets = [0usize; 4];
let mut multipliers = [0.0f32; 4];
for i in 0..floats_count {
offsets[i] = fields[i].offset as usize;
multipliers[i] = fields[i].resolution.unwrap(); }
decoders.push(FieldDecoder::FloatNLossy {
offsets,
multipliers,
prev: [0i32; 4],
count: floats_count,
});
start_index = floats_count;
}
}
for field in &fields[start_index..] {
let offset = field.offset as usize;
let decoder = match field.field_type {
FieldType::Float32 => {
if let Some(res) = field.resolution {
FieldDecoder::Float32Lossy {
offset,
multiplier: res,
prev: 0,
}
} else {
FieldDecoder::Copy { offset, size: 4 }
}
}
FieldType::Float64 => {
if let Some(res) = field.resolution {
FieldDecoder::Float64Lossy {
offset,
multiplier: res as f64,
prev: 0,
}
} else {
FieldDecoder::Float64Xor {
offset,
prev_bits: 0,
}
}
}
FieldType::Int8 | FieldType::Uint8 => FieldDecoder::Copy { offset, size: 1 },
FieldType::Int16 => FieldDecoder::Int {
offset,
size: 2,
prev: 0,
},
FieldType::Uint16 => FieldDecoder::Int {
offset,
size: 2,
prev: 0,
},
FieldType::Int32 => FieldDecoder::Int {
offset,
size: 4,
prev: 0,
},
FieldType::Uint32 => FieldDecoder::Int {
offset,
size: 4,
prev: 0,
},
FieldType::Int64 => FieldDecoder::Int {
offset,
size: 8,
prev: 0,
},
FieldType::Uint64 => FieldDecoder::Int {
offset,
size: 8,
prev: 0,
},
_ => panic!("Unsupported field type in decoder"),
};
decoders.push(decoder);
}
decoders
}