use tokio::net::tcp::{OwnedWriteHalf};
use std::io::Error;
use tokio::io::{AsyncWriteExt};
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum OrderOptions{
LittleEndian,
BigEndian
}
#[derive(Debug, Clone, Copy)]
pub enum BytesOptions {
U8,
U16,
U32,
U64,
U128,
I8,
I16,
I32,
I64,
I128,
F32,
F64,
}
#[derive(Debug)]
pub enum ReadValue {
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
F32(f32),
F64(f64),
}
pub fn read_value_to_usize(value: ReadValue) -> usize {
match value {
ReadValue::U8(v) => v as usize,
ReadValue::U16(v) => v as usize,
ReadValue::U32(v) => v as usize,
ReadValue::U64(v) => v as usize,
ReadValue::U128(v) => v as usize,
ReadValue::I8(v) => v as usize,
ReadValue::I16(v) => v as usize,
ReadValue::I32(v) => v as usize,
ReadValue::I64(v) => v as usize,
ReadValue::I128(v) => v as usize,
ReadValue::F32(v) => v as usize,
ReadValue::F64(v) => v as usize,
}
}
pub fn value_from_number(number: f64, bytes: BytesOptions) -> ReadValue {
match bytes {
BytesOptions::U8 => ReadValue::U8(number as u8),
BytesOptions::U16 => ReadValue::U16(number as u16),
BytesOptions::U32 => ReadValue::U32(number as u32),
BytesOptions::U64 => ReadValue::U64(number as u64),
BytesOptions::U128 => ReadValue::U128(number as u128),
BytesOptions::I8 => ReadValue::I8(number as i8),
BytesOptions::I16 => ReadValue::I16(number as i16),
BytesOptions::I32 => ReadValue::I32(number as i32),
BytesOptions::I64 => ReadValue::I64(number as i64),
BytesOptions::I128 => ReadValue::I128(number as i128),
BytesOptions::F32 => ReadValue::F32(number as f32),
BytesOptions::F64 => ReadValue::F64(number),
}
}
pub async fn write_from_settings(
write_half: &mut OwnedWriteHalf,
value: &ReadValue,
order: &OrderOptions,
) -> Result<(), Error> {
match value {
ReadValue::U8(v) => write_half.write_u8(*v).await?,
ReadValue::U16(v) => match order {
OrderOptions::LittleEndian => write_half.write_u16_le(*v).await?,
OrderOptions::BigEndian => write_half.write_u16(*v).await?,
},
ReadValue::U32(v) => match order {
OrderOptions::LittleEndian => write_half.write_u32_le(*v).await?,
OrderOptions::BigEndian => write_half.write_u32(*v).await?,
},
ReadValue::U64(v) => match order {
OrderOptions::LittleEndian => write_half.write_u64_le(*v).await?,
OrderOptions::BigEndian => write_half.write_u64(*v).await?,
},
ReadValue::U128(v) => match order {
OrderOptions::LittleEndian => write_half.write_u128_le(*v).await?,
OrderOptions::BigEndian => write_half.write_u128(*v).await?,
},
ReadValue::I8(v) => write_half.write_i8(*v).await?,
ReadValue::I16(v) => match order {
OrderOptions::LittleEndian => write_half.write_i16_le(*v).await?,
OrderOptions::BigEndian => write_half.write_i16(*v).await?,
},
ReadValue::I32(v) => match order {
OrderOptions::LittleEndian => write_half.write_i32_le(*v).await?,
OrderOptions::BigEndian => write_half.write_i32(*v).await?,
},
ReadValue::I64(v) => match order {
OrderOptions::LittleEndian => write_half.write_i64_le(*v).await?,
OrderOptions::BigEndian => write_half.write_i64(*v).await?,
},
ReadValue::I128(v) => match order {
OrderOptions::LittleEndian => write_half.write_i128_le(*v).await?,
OrderOptions::BigEndian => write_half.write_i128(*v).await?,
},
ReadValue::F32(v) => match order {
OrderOptions::LittleEndian => write_half.write_f32_le(*v).await?,
OrderOptions::BigEndian => write_half.write_f32(*v).await?,
},
ReadValue::F64(v) => match order {
OrderOptions::LittleEndian => write_half.write_f64_le(*v).await?,
OrderOptions::BigEndian => write_half.write_f64(*v).await?,
},
}
Ok(())
}
pub fn get_bytes_size(options: &BytesOptions) -> usize {
match options {
BytesOptions::U8 | BytesOptions::I8 => 1,
BytesOptions::U16 | BytesOptions::I16 => 2,
BytesOptions::U32 | BytesOptions::I32 | BytesOptions::F32 => 4,
BytesOptions::U64 | BytesOptions::I64 | BytesOptions::F64 => 8,
BytesOptions::U128 | BytesOptions::I128 => 16,
}
}
fn parse_value_from_bytes(bytes: &[u8], opt: &BytesOptions, order: &OrderOptions) -> ReadValue {
match opt {
BytesOptions::U8 => ReadValue::U8(bytes[0]),
BytesOptions::U16 => {
let v = if *order == OrderOptions::LittleEndian {
u16::from_le_bytes(bytes.try_into().unwrap())
} else {
u16::from_be_bytes(bytes.try_into().unwrap())
};
ReadValue::U16(v)
}
BytesOptions::U32 => {
let v = if *order == OrderOptions::LittleEndian {
u32::from_le_bytes(bytes.try_into().unwrap())
} else {
u32::from_be_bytes(bytes.try_into().unwrap())
};
ReadValue::U32(v)
}
_ => todo!("Implementar os outros tipos de BytesOptions conforme necessário"),
}
}
pub fn extract_messages_from_buffer(
buffer: &mut Vec<u8>,
bytes_opt: &BytesOptions,
order: &OrderOptions,
) -> Vec<Vec<u8>> {
let mut messages = Vec::new();
let header_size = get_bytes_size(bytes_opt);
loop {
if buffer.len() < header_size {
break;
}
let msg_len = {
let header_bytes = &buffer[..header_size];
let read_val = parse_value_from_bytes(header_bytes, bytes_opt, order);
read_value_to_usize(read_val)
};
if buffer.len() >= header_size + msg_len {
buffer.drain(..header_size);
let message = buffer.drain(..msg_len).collect();
messages.push(message);
} else {
break;
}
}
messages
}