use super::{Config, Configure, DecodeError};
use crate::dict::FieldLocation;
use crate::dict::IsFieldDefinition;
use crate::tagvalue::{FieldAccess, RepeatingGroup};
use crate::{Dictionary, FixValue, GetConfig};
use serde::{Deserialize, Serialize};
use std::borrow::{Borrow, Cow};
use std::collections::HashMap;
#[derive(Debug, Copy, Clone)]
pub struct Message<'a> {
internal: &'a MessageInternal<'a>,
group_map: Option<&'a FieldMap<'a>>,
}
impl<'a> Message<'a> {
pub fn iter_fields(&self) -> MessageFieldsIter<'a> {
MessageFieldsIter {
fields: self.internal.std_header.iter(),
}
}
fn field_map<F>(&self, field: &F) -> &'a FieldMap<'a>
where
F: IsFieldDefinition,
{
if let Some(context) = self.group_map {
context
} else {
match field.location() {
FieldLocation::Body => &self.internal.body,
FieldLocation::Header => &self.internal.std_header,
FieldLocation::Trailer => &self.internal.std_trailer,
}
}
}
}
impl<'a, F> FieldAccess<F> for Message<'a>
where
F: IsFieldDefinition,
{
type Group = MessageGroup<'a>;
fn group_opt(&self, field: &F) -> Option<Result<Self::Group, <usize as FixValue<'a>>::Error>> {
self.field_map(field)
.get(field.name())
.and_then(|field_or_group| {
if let FieldOrGroup::Group(ref entries) = field_or_group {
Some(Ok(MessageGroup {
message: Message {
internal: &self.internal,
group_map: None,
},
entries,
}))
} else {
None
}
})
}
fn fv_raw(&self, field: &F) -> Option<&[u8]> {
self.field_map(field)
.get(field.name())
.and_then(|field_or_group| {
if let FieldOrGroup::Field(value) = field_or_group {
let s: &str = value.borrow();
Some(s.as_bytes())
} else {
None
}
})
}
}
#[derive(Debug, Copy, Clone)]
pub struct MessageGroup<'a> {
message: Message<'a>,
entries: &'a [FieldMap<'a>],
}
impl<'a> RepeatingGroup for MessageGroup<'a> {
type Entry = Message<'a>;
fn len(&self) -> usize {
self.entries.len()
}
fn entry(&self, i: usize) -> Self::Entry {
self.entries
.get(i)
.map(|context| Message {
internal: self.message.internal,
group_map: Some(context),
})
.unwrap()
}
}
#[derive(Debug)]
pub struct MessageFieldsIter<'a> {
fields: std::collections::hash_map::Iter<'a, Cow<'a, str>, FieldOrGroup<'a>>,
}
impl<'a> Iterator for MessageFieldsIter<'a> {
type Item = (&'a str, &'a FieldOrGroup<'a>);
fn next(&mut self) -> Option<Self::Item> {
self.fields.next().map(|x| (x.0.borrow(), x.1))
}
}
#[derive(Debug, Clone)]
pub struct Decoder<C = Config> {
dictionaries: HashMap<String, Dictionary>,
message_builder: MessageInternal<'static>,
config: C,
}
impl<C> Decoder<C>
where
C: Configure,
{
pub fn new(dict: Dictionary) -> Self {
let mut dictionaries = HashMap::new();
dictionaries.insert(dict.get_version().to_string(), dict);
Self {
dictionaries,
message_builder: MessageInternal::default(),
config: C::default(),
}
}
pub fn decode<'a>(&'a mut self, data: &'a [u8]) -> Result<Message<'a>, DecodeError> {
let mut deserilizer = serde_json::Deserializer::from_slice(data);
let msg = self.message_builder();
MessageInternal::deserialize_in_place(&mut deserilizer, msg).map_err(|err| {
if err.is_syntax() || err.is_eof() || err.is_io() {
DecodeError::Syntax
} else {
DecodeError::Schema
}
})?;
Ok(Message {
internal: msg,
group_map: None,
})
}
fn message_builder<'a>(&'a mut self) -> &'a mut MessageInternal<'a> {
self.message_builder.clear();
unsafe {
std::mem::transmute::<&'a mut MessageInternal<'static>, &'a mut MessageInternal<'a>>(
&mut self.message_builder,
)
}
}
}
impl<C> GetConfig for Decoder<C> {
type Config = C;
fn config(&self) -> &Self::Config {
&self.config
}
fn config_mut(&mut self) -> &mut Self::Config {
&mut self.config
}
}
type FieldMap<'a> = HashMap<Cow<'a, str>, FieldOrGroup<'a>>;
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(untagged)]
pub enum FieldOrGroup<'a> {
Field(Cow<'a, str>),
#[serde(borrow)]
Group(Vec<FieldMap<'a>>),
}
#[derive(Deserialize, Serialize, Debug, Clone, Default)]
struct MessageInternal<'a> {
#[serde(borrow, rename = "Header")]
std_header: FieldMap<'a>,
#[serde(borrow, rename = "Body")]
body: FieldMap<'a>,
#[serde(borrow, rename = "Trailer")]
std_trailer: FieldMap<'a>,
}
impl<'a> std::ops::Drop for MessageInternal<'a> {
fn drop(&mut self) {
self.clear();
}
}
impl<'a> MessageInternal<'a> {
fn clear(&mut self) {
self.std_header.clear();
self.body.clear();
self.std_trailer.clear();
}
}
#[cfg(test)]
mod test {
use super::*;
const MESSAGE_SIMPLE: &str = include_str!("test_data/message_simple.json");
const MESSAGE_WITHOUT_HEADER: &str = include_str!("test_data/message_without_header.json");
fn encoder_fix44() -> Decoder {
Decoder::new(Dictionary::fix44())
}
#[test]
fn message_without_header() {
let mut encoder = encoder_fix44();
let result = encoder.decode(&mut MESSAGE_WITHOUT_HEADER.as_bytes());
match result {
Err(DecodeError::Schema) => (),
_ => panic!(),
};
}
#[test]
fn simple_message() {
let mut encoder = encoder_fix44();
let result = encoder.decode(&mut MESSAGE_SIMPLE.as_bytes());
assert!(result.is_ok());
}
#[test]
fn invalid_json() {
let mut encoder = encoder_fix44();
let result = encoder.decode(&mut "this is invalid JSON".as_bytes());
match result {
Err(DecodeError::Syntax) => (),
_ => panic!(),
};
}
}