use parking_lot::RwLock;
use rustc_hash::FxHashMap;
use smartstring::{LazyCompact, SmartString};
type FixString = SmartString<LazyCompact>;
use std::sync::Arc;
pub const DEFAULT_MAX_MESSAGE_SIZE: usize = 64 * 1024;
pub const DEFAULT_MAX_RECURSION_DEPTH: u32 = 32;
pub const DEFAULT_STREAM_BUFFER_SIZE: usize = 8 * 1024;
pub const LOW_LATENCY_MAX_MESSAGE_SIZE: usize = 16 * 1024;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum EncodingRule {
BER,
DER,
OER,
}
impl EncodingRule {
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::BER => "BER",
Self::DER => "DER",
Self::OER => "OER",
}
}
#[must_use]
pub const fn is_self_describing(&self) -> bool {
matches!(self, Self::BER | Self::DER)
}
#[must_use]
pub const fn requires_schema(&self) -> bool {
matches!(self, Self::OER)
}
}
impl Default for EncodingRule {
fn default() -> Self {
Self::DER
}
}
#[derive(Clone)]
pub struct Config {
pub encoding_rule: EncodingRule,
pub max_message_size: usize,
pub max_recursion_depth: u32,
pub validate_checksums: bool,
pub strict_type_checking: bool,
pub stream_buffer_size: usize,
pub enable_zero_copy: bool,
pub message_options: Arc<RwLock<FxHashMap<FixString, MessageOptions>>>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MessageOptions {
pub encoding_rule: Option<EncodingRule>,
pub compress: bool,
pub max_size: Option<usize>,
}
impl Default for Config {
fn default() -> Self {
Self {
encoding_rule: EncodingRule::default(),
max_message_size: DEFAULT_MAX_MESSAGE_SIZE,
max_recursion_depth: DEFAULT_MAX_RECURSION_DEPTH,
validate_checksums: true,
strict_type_checking: true,
stream_buffer_size: DEFAULT_STREAM_BUFFER_SIZE,
enable_zero_copy: true,
message_options: Arc::new(RwLock::new(FxHashMap::default())),
}
}
}
impl Config {
#[must_use]
pub fn new(encoding_rule: EncodingRule) -> Self {
Self {
encoding_rule,
..Default::default()
}
}
#[must_use]
pub fn low_latency() -> Self {
Self {
encoding_rule: EncodingRule::OER, max_message_size: LOW_LATENCY_MAX_MESSAGE_SIZE, validate_checksums: false, strict_type_checking: false, enable_zero_copy: true, ..Default::default()
}
}
#[must_use]
pub fn high_reliability() -> Self {
Self {
encoding_rule: EncodingRule::DER, validate_checksums: true, strict_type_checking: true, enable_zero_copy: false, ..Default::default()
}
}
pub fn set_message_options(&self, message_type: impl Into<FixString>, options: MessageOptions) {
self.message_options
.write()
.insert(message_type.into(), options);
}
pub fn get_message_options(&self, message_type: &str) -> Option<MessageOptions> {
self.message_options.read().get(message_type).cloned()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encoding_rule_properties() {
assert!(EncodingRule::BER.is_self_describing());
assert!(EncodingRule::DER.is_self_describing());
assert!(!EncodingRule::OER.is_self_describing());
assert!(EncodingRule::OER.requires_schema());
assert!(!EncodingRule::BER.requires_schema());
}
#[test]
fn test_config_presets() {
let low_latency = Config::low_latency();
assert_eq!(low_latency.encoding_rule, EncodingRule::OER);
assert!(!low_latency.validate_checksums);
let high_reliability = Config::high_reliability();
assert_eq!(high_reliability.encoding_rule, EncodingRule::DER);
assert!(high_reliability.validate_checksums);
}
#[test]
fn test_message_options() {
let config = Config::default();
let options = MessageOptions {
encoding_rule: Some(EncodingRule::OER),
compress: true,
max_size: Some(1024),
};
config.set_message_options("NewOrderSingle", options.clone());
let retrieved = config
.get_message_options("NewOrderSingle")
.expect("Failed to retrieve message options for test");
assert_eq!(retrieved.encoding_rule, Some(EncodingRule::OER));
assert!(retrieved.compress);
}
}