sift_query_core/codecs/
mod.rs1use crate::{FieldMeta, RowValue, ScalarValue};
3use sift_query_algorithm::StableHasher64;
4use std::fmt;
5use std::sync::Arc;
6
7mod business;
8mod list;
9#[cfg(feature = "chrono")]
10mod temporal;
11#[cfg(feature = "chrono")]
12pub use business::DateCodec;
13#[cfg(feature = "json")]
14pub use business::JsonValueCodec;
15pub use business::{BooleanCodec, EnumCodec, ScalarTextCodec, StringCodec};
16pub use list::ListResultCodec;
17#[cfg(feature = "chrono")]
18pub use temporal::{DateTimeCodec, TimeCodec, TimestampCodec};
19
20pub trait Codec: Send + Sync + fmt::Debug {
22 fn name(&self) -> &'static str;
24
25 fn supports(&self, field: &FieldMeta) -> bool;
27
28 fn parse(&self, field: &FieldMeta, input: &str) -> Result<ScalarValue, String>;
30
31 fn format_input(&self, field: &FieldMeta, value: &ScalarValue) -> Result<String, String> {
34 self.format_result(field, value.clone().into())
35 .map(|value| value.to_external_text())
36 }
37
38 fn format_result(&self, _field: &FieldMeta, value: RowValue) -> Result<RowValue, String> {
40 Ok(value)
41 }
42
43 fn fingerprint(&self) -> u64 {
45 let mut hash = StableHasher64::default();
46 hash.write_delimited(self.name());
47 hash.finish()
48 }
49}
50
51pub trait FieldConvertor: Codec {}
54impl<T: Codec + ?Sized> FieldConvertor for T {}
55
56#[derive(Clone, Default)]
58pub struct CodecRegistry {
59 codecs: Vec<Arc<dyn Codec>>,
60}
61
62impl fmt::Debug for CodecRegistry {
63 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
64 formatter
65 .debug_list()
66 .entries(self.codecs.iter().map(|codec| codec.name()))
67 .finish()
68 }
69}
70
71impl CodecRegistry {
72 #[must_use]
73 pub fn with_codec<C: Codec + 'static>(mut self, codec: C) -> Self {
74 self.codecs.push(Arc::new(codec));
75 self
76 }
77
78 pub fn push<C: Codec + 'static>(&mut self, codec: C) {
79 self.codecs.push(Arc::new(codec));
80 }
81
82 #[must_use]
83 pub fn is_empty(&self) -> bool {
84 self.codecs.is_empty()
85 }
86
87 pub fn iter(&self) -> impl Iterator<Item = &Arc<dyn Codec>> {
88 self.codecs.iter()
89 }
90
91 pub(crate) fn find(&self, field: &FieldMeta) -> Option<&dyn Codec> {
92 self.codecs
93 .iter()
94 .find(|codec| codec.supports(field))
95 .map(Arc::as_ref)
96 }
97
98 pub(crate) fn find_arc(&self, field: &FieldMeta) -> Option<Arc<dyn Codec>> {
99 self.codecs
100 .iter()
101 .find(|codec| codec.supports(field))
102 .cloned()
103 }
104
105 pub(crate) fn fingerprint(&self) -> u64 {
106 let mut hash = StableHasher64::default();
107 for codec in &self.codecs {
108 hash.write(codec.fingerprint().to_le_bytes());
109 }
110 hash.finish()
111 }
112}