use crate::client::Client;
use crate::constants;
use crate::error::Error;
use crate::messages::Message;
use crate::response::Response;
use crate::write_buffer::WriteBuffer;
use std::borrow::Cow;
pub(crate) enum LobOp<'a> {
Close,
GetChunkSize,
GetLength,
IsOpen,
Open(u64),
Read(u64, u64),
Trim(u64),
Write(u64, Cow<'a, [u8]>),
}
impl LobOp<'_> {
fn amount(&self) -> u64 {
match self {
LobOp::Open(mode) => *mode,
LobOp::Read(_, amount) => *amount,
LobOp::Trim(new_size) => *new_size,
_ => 0,
}
}
fn data_to_send(&self) -> Option<&[u8]> {
match self {
LobOp::Write(_, data) => Some(data.as_ref()),
_ => None,
}
}
fn operation(&self) -> u32 {
match self {
LobOp::Close => constants::TTC_LOB_OP_CLOSE,
LobOp::GetChunkSize => constants::TTC_LOB_OP_GET_CHUNK_SIZE,
LobOp::GetLength => constants::TTC_LOB_OP_GET_LENGTH,
LobOp::IsOpen => constants::TTC_LOB_OP_IS_OPEN,
LobOp::Open(_) => constants::TTC_LOB_OP_OPEN,
LobOp::Read(_, _) => constants::TTC_LOB_OP_READ,
LobOp::Trim(_) => constants::TTC_LOB_OP_TRIM,
LobOp::Write(_, _) => constants::TTC_LOB_OP_WRITE,
}
}
fn returns_bool(&self) -> bool {
matches!(self, LobOp::IsOpen)
}
fn sends_amount(&self) -> bool {
matches!(
self,
LobOp::GetChunkSize
| LobOp::GetLength
| LobOp::Open(_)
| LobOp::Read(_, _)
| LobOp::Trim(_)
)
}
fn source_offset(&self) -> u64 {
match self {
LobOp::Read(offset, _) | LobOp::Write(offset, _) => *offset,
_ => 0,
}
}
}
pub(crate) struct LobOpMessage<'a> {
op: LobOp<'a>,
source_locator: Vec<u8>,
returned_locator: Option<Vec<u8>>,
returned_amount: i64,
returned_bool: bool,
data: Vec<u8>,
}
impl<'a> LobOpMessage<'a> {
pub(crate) fn new(locator: &[u8], op: LobOp<'a>) -> LobOpMessage<'a> {
LobOpMessage {
op,
source_locator: locator.to_vec(),
returned_locator: None,
returned_amount: 0,
returned_bool: false,
data: Vec::new(),
}
}
pub(crate) fn returned_amount(&self) -> i64 {
self.returned_amount
}
pub(crate) fn returned_bool(&self) -> bool {
self.returned_bool
}
pub(crate) fn take_data(&mut self) -> Vec<u8> {
std::mem::take(&mut self.data)
}
pub(crate) fn take_returned_locator(&mut self) -> Option<Vec<u8>> {
self.returned_locator.take()
}
}
impl Message for LobOpMessage<'_> {
fn deserialize_lob_data(
&mut self,
_client: &Client,
resp: &mut Response,
) -> Result<(), Error> {
let bytes = resp.read_bytes_with_length()?;
self.data.extend_from_slice(&bytes);
Ok(())
}
fn deserialize_return_parameters(
&mut self,
_client: &Client,
resp: &mut Response,
) -> Result<(), Error> {
let new_locator = resp.read_bytes(self.source_locator.len())?.to_vec();
self.returned_locator = Some(new_locator);
if self.op.sends_amount() {
self.returned_amount = resp.read_sb8()?;
}
if self.op.returns_bool() {
self.returned_bool = resp.read_u8()? > 0;
}
Ok(())
}
fn serialize(&self, client: &Client, buf: &mut WriteBuffer) {
buf.write_function_header(client, constants::TTC_RPC_LOB_OP);
buf.write_u8(1); buf.write_ub4(self.source_locator.len().try_into().unwrap());
buf.write_u8(0); buf.write_ub4(0); buf.write_ub4(0); buf.write_ub4(0); buf.write_u8(0); buf.write_u8(0); if self.op.returns_bool() {
buf.write_u8(1); } else {
buf.write_u8(0); }
buf.write_ub4(self.op.operation());
buf.write_u8(0); buf.write_u8(0); buf.write_ub8(self.op.source_offset());
buf.write_ub8(0); if self.op.sends_amount() {
buf.write_u8(1); } else {
buf.write_u8(0); }
for _ in 0..3 {
buf.write_u16be(0); }
buf.write_bytes(&self.source_locator);
if let Some(data) = self.op.data_to_send() {
buf.write_u8(constants::TTC_MSG_TYPE_LOB_DATA);
buf.write_bytes_with_length(data);
}
if self.op.sends_amount() {
buf.write_ub8(self.op.amount());
}
}
}