#![doc(html_root_url = "https://docs.rs/cql_tiny_text/0.2.1")]
pub mod errors;
pub mod interop;
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 CONTENT_SIZE: usize = (255 * 4);
const LENGTH_SIZE: usize = 2;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
pub struct TinyText(String);
impl CqlType for TinyText {
type ValueType = Self;
const VALUE_SIZE: usize = CONTENT_SIZE + LENGTH_SIZE;
}
impl TinyText {
pub fn new() -> Self {
TinyText(String::new())
}
}
impl CqlWritable for TinyText {
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();
let input_length: u16 = input_value.0.len() as u16;
let mut buffer = vec![];
buffer.write_u16::<LittleEndian>(input_length)?;
buffer.extend(&input_value.0.into_bytes());
file.write_all(&buffer)
}
}
impl CqlReadable for TinyText {
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 size_buffer = [0; LENGTH_SIZE];
file.read_exact(&mut size_buffer)?;
let mut size_rdr = Cursor::new(size_buffer);
let size = usize::from(size_rdr.read_u16::<LittleEndian>()?);
if size == 0 {
return Ok(TinyText::new())
}
let mut value_buffer = Vec::with_capacity(size);
file.take(size as u64).read_to_end(&mut value_buffer)?;
Ok(
TinyText(
String::from_utf8(value_buffer).unwrap()
)
)
}
}
impl CqlStreamReadable for TinyText {
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();
let mut value_buffer = [0; CONTENT_SIZE];
for _i in 0..n_values {
let mut size_buffer = [0; LENGTH_SIZE];
match file.read_exact(&mut size_buffer) {
Err(e) => {
if e.kind() != io::ErrorKind::UnexpectedEof {
return Err(e)
}
}
_ => { }
}
let mut size_rdr = Cursor::new(size_buffer);
let size = usize::from(size_rdr.read_u16::<LittleEndian>()?);
match file.read_exact(&mut value_buffer) {
Err(e) => {
if e.kind() != io::ErrorKind::UnexpectedEof {
return Err(e)
}
}
_ => { }
}
let mut write_buffer = Vec::with_capacity(LENGTH_SIZE + size);
write_buffer.extend(&size_buffer);
for i in 0..size {
write_buffer.push(value_buffer[i]);
}
stream.write_all(&mut write_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, TinyText) {
let mut size_buffer = [0; LENGTH_SIZE];
for index in 0..n_values {
stream.read_exact(&mut size_buffer)?;
let mut size_rdr = Cursor::new(size_buffer);
let size = usize::from(size_rdr.read_u16::<LittleEndian>()?);
if size == 0 {
value_handler(index, TinyText::new());
} else {
let mut value_buffer = vec![0; size];
stream.read_exact(&mut value_buffer)?;
value_handler(index, TinyText(String::from_utf8(value_buffer).unwrap()));
}
}
Ok(())
}