#![doc(html_root_url = "https://docs.rs/cql_nullable_f64/0.2.2")]
use std::fs::{ File, OpenOptions };
use std::io;
use std::io::{ Read, Write, Cursor, SeekFrom, Seek };
use byteorder::{ ReadBytesExt, WriteBytesExt, LittleEndian };
use cql_model::{ CqlType, CqlWritable, CqlReadable, CqlStreamReadable };
const HAS_VALUE_FLAG: u8 = 1;
const NULL_FLAG: u8 = 0;
const CONTENT_SIZE: usize = 8;
const HAS_VALUE_SIZE: usize = 1;
pub struct NullableF64;
impl CqlType for NullableF64 {
type ValueType = Option<f64>;
const VALUE_SIZE: usize = HAS_VALUE_SIZE + CONTENT_SIZE;
}
impl CqlWritable for NullableF64 {
fn write_to_db(db_location: &str, value_location: u64, input_value: Self::ValueType) -> io::Result<()> {
let mut file = OpenOptions::new().write(true).open(db_location)?;
file.seek(SeekFrom::Start(value_location * Self::VALUE_SIZE as u64)).unwrap();
match input_value {
None => {
file.write_all(&[NULL_FLAG; HAS_VALUE_SIZE])
}
Some(value) => {
let mut buffer = vec![HAS_VALUE_FLAG];
buffer.write_f64::<LittleEndian>(value)?;
file.write_all(&buffer)
}
}
}
}
impl CqlReadable for NullableF64 {
fn read_from_db(db_location: &str, value_location: u64) -> io::Result<Self::ValueType> {
let mut file = File::open(&db_location)?;
file.seek(SeekFrom::Start(value_location * Self::VALUE_SIZE as u64)).unwrap();
let mut null_buffer = [0; HAS_VALUE_SIZE];
match file.read_exact(&mut null_buffer) {
Err(e) => {
if e.kind() != io::ErrorKind::UnexpectedEof {
return Err(e)
}
}
_ => { }
}
if null_buffer[0] == NULL_FLAG {
return Ok(None)
}
let mut value_buffer = [0; CONTENT_SIZE];
file.read_exact(&mut value_buffer)?;
let mut rdr = Cursor::new(value_buffer);
Ok(Some(rdr.read_f64::<LittleEndian>()?))
}
}
impl CqlStreamReadable for NullableF64 {
fn read_to_stream(db_location: &str, stream: &mut dyn Write, value_location: u64, n_values: u64) -> io::Result<()> {
let mut file = File::open(&db_location)?;
file.seek(SeekFrom::Start(value_location * Self::VALUE_SIZE as u64)).unwrap();
for _i in 0..n_values {
let mut buffer = [0; Self::VALUE_SIZE];
match file.read_exact(&mut buffer) {
Err(e) => {
if e.kind() != io::ErrorKind::UnexpectedEof {
return Err(e)
}
}
_ => { }
}
stream.write_all(&mut buffer)?;
}
stream.flush()
}
}
pub fn unpack_stream<F>(stream: &mut Cursor<Vec<u8>>, n_values: usize, mut value_handler: F) -> io::Result<()> where F: FnMut(usize, Option<f64>) {
for index in 0..n_values {
let mut buffer = [0; NullableF64::VALUE_SIZE];
stream.read_exact(&mut buffer)?;
if buffer[0] == NULL_FLAG {
value_handler(index, None);
} else {
let mut rdr = Cursor::new(&buffer[1..NullableF64::VALUE_SIZE]);
value_handler(index, Some(rdr.read_f64::<LittleEndian>()?));
}
}
Ok(())
}