use crate::{FieldMeta, RowValue, ScalarValue};
use sift_query_algorithm::StableHasher64;
use std::fmt;
use std::sync::Arc;
mod business;
mod list;
#[cfg(feature = "chrono")]
mod temporal;
#[cfg(feature = "chrono")]
pub use business::DateCodec;
#[cfg(feature = "json")]
pub use business::JsonValueCodec;
pub use business::{BooleanCodec, EnumCodec, ScalarTextCodec, StringCodec};
pub use list::ListResultCodec;
#[cfg(feature = "chrono")]
pub use temporal::{DateTimeCodec, TimeCodec, TimestampCodec};
pub trait Codec: Send + Sync + fmt::Debug {
fn name(&self) -> &'static str;
fn supports(&self, field: &FieldMeta) -> bool;
fn parse(&self, field: &FieldMeta, input: &str) -> Result<ScalarValue, String>;
fn format_input(&self, field: &FieldMeta, value: &ScalarValue) -> Result<String, String> {
self.format_result(field, value.clone().into())
.map(|value| value.to_external_text())
}
fn format_result(&self, _field: &FieldMeta, value: RowValue) -> Result<RowValue, String> {
Ok(value)
}
fn fingerprint(&self) -> u64 {
let mut hash = StableHasher64::default();
hash.write_delimited(self.name());
hash.finish()
}
}
pub trait FieldConvertor: Codec {}
impl<T: Codec + ?Sized> FieldConvertor for T {}
#[derive(Clone, Default)]
pub struct CodecRegistry {
codecs: Vec<Arc<dyn Codec>>,
}
impl fmt::Debug for CodecRegistry {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_list()
.entries(self.codecs.iter().map(|codec| codec.name()))
.finish()
}
}
impl CodecRegistry {
#[must_use]
pub fn with_codec<C: Codec + 'static>(mut self, codec: C) -> Self {
self.codecs.push(Arc::new(codec));
self
}
pub fn push<C: Codec + 'static>(&mut self, codec: C) {
self.codecs.push(Arc::new(codec));
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.codecs.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &Arc<dyn Codec>> {
self.codecs.iter()
}
pub(crate) fn find(&self, field: &FieldMeta) -> Option<&dyn Codec> {
self.codecs
.iter()
.find(|codec| codec.supports(field))
.map(Arc::as_ref)
}
pub(crate) fn find_arc(&self, field: &FieldMeta) -> Option<Arc<dyn Codec>> {
self.codecs
.iter()
.find(|codec| codec.supports(field))
.cloned()
}
pub(crate) fn fingerprint(&self) -> u64 {
let mut hash = StableHasher64::default();
for codec in &self.codecs {
hash.write(codec.fingerprint().to_le_bytes());
}
hash.finish()
}
}