use super::{Config, Configure, FvWrite};
use crate::buffer::Buffer;
use crate::dict;
use crate::dict::IsFieldDefinition;
use crate::fix_values::CheckSum;
use crate::FixValue;
use crate::TagU16;
use std::ops::Range;
#[derive(Debug, Clone, Default)]
pub struct Encoder<C = Config>
where
C: Configure,
{
config: C,
}
impl<C> Encoder<C>
where
C: Configure,
{
pub fn new(config: C) -> Self {
Self { config }
}
pub fn config(&self) -> &C {
&self.config
}
pub fn config_mut(&mut self) -> &mut C {
&mut self.config
}
pub fn start_message<'a>(
&'a mut self,
begin_string: &[u8],
buffer: &'a mut Vec<u8>,
msg_type: &[u8],
) -> EncoderHandle<'a, Vec<u8>, C> {
let mut state = EncoderHandle {
raw_encoder: self,
buffer,
body_start_i: 0,
};
state.set_fv(&8, begin_string);
let tag = TagU16::new(10 as u16).unwrap();
state.set_fv(&9, b"000000" as &[u8]);
state.body_start_i = state.buffer.len();
state.set_fv(&35, msg_type);
state
}
}
#[derive(Debug)]
pub struct EncoderHandle<'a, B, C = Config>
where
B: Buffer,
C: Configure,
{
raw_encoder: &'a mut Encoder<C>,
buffer: &'a mut B,
body_start_i: usize,
}
impl<'a, B, C> FvWrite<'a, u32> for EncoderHandle<'a, B, C>
where
B: Buffer,
C: Configure,
{
fn set_fv<'b, V>(&'b mut self, field: &u32, value: V)
where
V: FixValue<'b>,
{
let tag = TagU16::new(*field as u16).unwrap();
self.set_any(tag, value)
}
}
impl<'a, B, C, F> FvWrite<'a, F> for EncoderHandle<'a, B, C>
where
B: Buffer,
C: Configure,
F: IsFieldDefinition,
{
fn set_fv<'b, V>(&'b mut self, field: &F, value: V)
where
V: FixValue<'b>,
{
self.set(field, value)
}
}
impl<'a, B, C> EncoderHandle<'a, B, C>
where
B: Buffer,
C: Configure,
{
pub fn set<'b, F, T>(&mut self, field: &F, value: T)
where
F: dict::IsFieldDefinition,
T: FixValue<'b>,
{
self.set_any(field.tag(), value)
}
pub fn set_any<'b, T>(&mut self, tag: TagU16, value: T)
where
T: FixValue<'b>,
{
tag.serialize(self.buffer);
self.buffer.extend_from_slice(b"=" as &[u8]);
value.serialize(self.buffer);
self.buffer
.extend_from_slice(&[self.raw_encoder.config().separator()]);
}
pub fn raw(&mut self, raw: &[u8]) {
self.buffer.extend_from_slice(raw);
}
pub fn wrap(mut self) -> &'a [u8] {
self.write_body_length();
self.write_checksum();
self.buffer.as_slice()
}
fn body_length_writable_range(&self) -> Range<usize> {
self.body_start_i - 7..self.body_start_i - 1
}
fn body_length(&self) -> usize {
self.buffer.as_slice().len() - self.body_start_i
}
fn write_body_length(&mut self) {
let body_length = self.body_length();
let body_length_range = self.body_length_writable_range();
let slice = &mut self.buffer.as_mut_slice()[body_length_range];
slice[0] = to_digit((body_length / 100000) as u8 % 10);
slice[1] = to_digit((body_length / 10000) as u8 % 10);
slice[2] = to_digit((body_length / 1000) as u8 % 10);
slice[3] = to_digit((body_length / 100) as u8 % 10);
slice[4] = to_digit((body_length / 10) as u8 % 10);
slice[5] = to_digit((body_length / 1) as u8 % 10);
}
fn write_checksum(&mut self) {
let checksum = CheckSum::compute(self.buffer.as_slice());
self.set_fv(&10, checksum);
}
}
fn to_digit(byte: u8) -> u8 {
byte + b'0'
}