use super::Config;
use crate::dict::IsFieldDefinition;
use crate::field_types::CheckSum;
use crate::{Buffer, BufferWriter, FieldType, GetConfig, SetField, TagU32};
use std::fmt::Write;
use std::ops::Range;
pub(crate) trait IntoTag {
fn into_tag(self) -> u32;
}
impl IntoTag for u32 {
fn into_tag(self) -> u32 {
self
}
}
impl IntoTag for TagU32 {
fn into_tag(self) -> u32 {
self.get()
}
}
impl<F: IsFieldDefinition> IntoTag for &F {
fn into_tag(self) -> u32 {
self.tag().get()
}
}
#[derive(Debug, Clone, Default)]
pub struct Encoder {
config: Config,
}
impl Encoder {
pub fn new() -> Self {
Self::default()
}
pub fn start_message<'a, B>(
&'a mut self,
begin_string: &[u8],
buffer: &'a mut B,
msg_type: &[u8],
) -> EncoderHandle<'a, B>
where
B: Buffer,
{
let initial_buffer_len = buffer.len();
let mut state = EncoderHandle {
encoder: self,
buffer,
initial_buffer_len,
body_start_i: 0,
};
state.set(8, begin_string);
state.set(9, b"00000000" as &[u8]);
state.body_start_i = state.buffer.len();
state.set(35, msg_type);
state
}
}
impl GetConfig for Encoder {
type Config = Config;
fn config(&self) -> &Self::Config {
&self.config
}
fn config_mut(&mut self) -> &mut Self::Config {
&mut self.config
}
}
#[derive(Debug)]
pub struct EncoderHandle<'a, B> {
encoder: &'a mut Encoder,
buffer: &'a mut B,
initial_buffer_len: usize,
body_start_i: usize,
}
impl<'a, B> EncoderHandle<'a, B>
where
B: Buffer,
{
pub fn done(mut self) -> (&'a [u8], usize) {
self.write_body_length();
self.write_checksum();
(self.buffer.as_slice(), self.initial_buffer_len)
}
fn body_length_writable_range(&self) -> Range<usize> {
self.body_start_i - 9..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) {
use std::io::Write;
let body_length = self.body_length();
let body_length_range = self.body_length_writable_range();
let mut slice = &mut self.buffer.as_mut_slice()[body_length_range];
write!(slice, "{:08}", body_length).unwrap();
}
fn write_checksum(&mut self) {
let checksum = CheckSum::compute(self.buffer.as_slice());
self.set(10, checksum);
}
}
impl<'a, B, T> SetField<T> for EncoderHandle<'a, B>
where
B: Buffer,
T: IntoTag,
{
fn set_with<'s, V>(
&'s mut self,
tag: T,
value: V,
settings: V::SerializeSettings,
) where
V: FieldType<'s>,
{
let tag_u32 = tag.into_tag();
write!(BufferWriter(self.buffer), "{}=", tag_u32).unwrap();
value.serialize_with(self.buffer, settings);
self.buffer.extend_from_slice(&[self.encoder.config().separator]);
}
}