1use serde::{Serialize, de::DeserializeOwned};
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum ValueKind {
27 Json,
29 Binary,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
44pub enum SerializerError {
45 EncodeFailed(String),
47 DecodeFailed(String),
49 FormatMismatch {
51 expected: &'static str,
53 actual: &'static str,
55 },
56 VersionIncompatible,
58}
59
60impl std::fmt::Display for SerializerError {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 match self {
63 Self::EncodeFailed(msg) => write!(f, "Serialization encoding failed: {msg}"),
64 Self::DecodeFailed(msg) => write!(f, "Serialization decoding failed: {msg}"),
65 Self::FormatMismatch { expected, actual } => {
66 write!(f, "Format mismatch: expected {expected}, got {actual}")
67 }
68 Self::VersionIncompatible => {
69 write!(f, "Version incompatible: stored data version is too new")
70 }
71 }
72 }
73}
74
75impl std::error::Error for SerializerError {}
76
77pub trait SaSerializer: Send + Sync {
83 fn name(&self) -> &'static str;
85
86 fn kind(&self, raw: &str) -> ValueKind;
88
89 fn encode<T: Serialize + ?Sized>(&self, value: &T) -> Result<String, SerializerError>;
93
94 fn decode<T: DeserializeOwned>(&self, raw: &str) -> Result<T, SerializerError>;
98
99 #[inline]
101 fn encode_bytes<T: Serialize + ?Sized>(&self, value: &T) -> Result<Vec<u8>, SerializerError> {
102 self.encode(value).map(|s| s.into_bytes())
103 }
104
105 #[inline]
107 fn decode_bytes<T: DeserializeOwned>(&self, bytes: &[u8]) -> Result<T, SerializerError> {
108 let s = std::str::from_utf8(bytes)
109 .map_err(|e| SerializerError::DecodeFailed(format!("Invalid UTF-8: {e}")))?;
110 self.decode(s)
111 }
112}
113
114pub const BINARY_MAGIC: &str = "\u{0001}STF";
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
119pub struct JsonSerializerConfig {
120 pub pretty_print: bool,
122 pub escape_unicode: bool,
124}
125
126#[derive(Debug, Clone, Copy, Default)]
128pub struct JsonSerializer {
129 config: JsonSerializerConfig,
130}
131
132impl JsonSerializer {
133 pub fn with_config(config: JsonSerializerConfig) -> Self {
135 Self { config }
136 }
137}
138
139impl SaSerializer for JsonSerializer {
140 #[inline]
141 fn name(&self) -> &'static str {
142 "json"
143 }
144
145 #[inline]
146 fn kind(&self, raw: &str) -> ValueKind {
147 if raw.starts_with(BINARY_MAGIC) {
148 ValueKind::Binary
149 } else {
150 ValueKind::Json
151 }
152 }
153
154 #[inline]
155 fn encode<T: Serialize + ?Sized>(&self, value: &T) -> Result<String, SerializerError> {
156 if self.config.pretty_print {
157 serde_json::to_string_pretty(value)
158 .map_err(|e| SerializerError::EncodeFailed(e.to_string()))
159 } else {
160 serde_json::to_string(value).map_err(|e| SerializerError::EncodeFailed(e.to_string()))
161 }
162 }
163
164 #[inline]
165 fn decode<T: DeserializeOwned>(&self, raw: &str) -> Result<T, SerializerError> {
166 if raw.starts_with(BINARY_MAGIC) {
167 return Err(SerializerError::FormatMismatch {
168 expected: "json",
169 actual: "binary",
170 });
171 }
172 serde_json::from_str(raw).map_err(|e| SerializerError::DecodeFailed(e.to_string()))
173 }
174
175 #[inline]
176 fn encode_bytes<T: Serialize + ?Sized>(&self, value: &T) -> Result<Vec<u8>, SerializerError> {
177 if self.config.pretty_print {
178 serde_json::to_vec_pretty(value)
179 .map_err(|e| SerializerError::EncodeFailed(e.to_string()))
180 } else {
181 serde_json::to_vec(value).map_err(|e| SerializerError::EncodeFailed(e.to_string()))
182 }
183 }
184}
185
186#[cfg(feature = "fory")]
187mod fory_impl {
188 use super::*;
189 use base64::{Engine as _, engine::general_purpose::STANDARD};
190 use fory::Fory;
191 use std::sync::OnceLock;
192
193 fn fory_runtime() -> &'static Fory {
194 static RUNTIME: OnceLock<Fory> = OnceLock::new();
195 RUNTIME.get_or_init(Fory::default)
196 }
197
198 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
200 pub struct ForySerializerConfig {
201 pub compression_level: u8,
203 }
204
205 impl Default for ForySerializerConfig {
206 fn default() -> Self {
207 Self {
208 compression_level: 6,
209 }
210 }
211 }
212
213 #[derive(Debug, Clone, Copy, Default)]
215 pub struct ForySerializer {
216 #[allow(dead_code)]
217 config: ForySerializerConfig,
218 }
219
220 impl ForySerializer {
221 pub fn with_config(config: ForySerializerConfig) -> Self {
223 Self { config }
224 }
225 }
226
227 impl SaSerializer for ForySerializer {
228 #[inline]
229 fn name(&self) -> &'static str {
230 "fory"
231 }
232
233 #[inline]
234 fn kind(&self, raw: &str) -> ValueKind {
235 if raw.starts_with(BINARY_MAGIC) {
236 ValueKind::Binary
237 } else {
238 ValueKind::Json
239 }
240 }
241
242 fn encode<T: Serialize + ?Sized>(&self, value: &T) -> Result<String, SerializerError> {
243 let json = serde_json::to_string(value)
244 .map_err(|e| SerializerError::EncodeFailed(e.to_string()))?;
245 let bytes = fory_runtime()
246 .serialize(&json)
247 .map_err(|e| SerializerError::EncodeFailed(e.to_string()))?;
248 Ok(format!("{}{}", super::BINARY_MAGIC, STANDARD.encode(bytes)))
249 }
250
251 fn decode<T: DeserializeOwned>(&self, raw: &str) -> Result<T, SerializerError> {
252 if raw.starts_with(BINARY_MAGIC) {
253 let b64 = &raw[super::BINARY_MAGIC.len()..];
254 let bytes = STANDARD
255 .decode(b64)
256 .map_err(|e| SerializerError::DecodeFailed(e.to_string()))?;
257 let json: String = fory_runtime()
258 .deserialize(&bytes)
259 .map_err(|e| SerializerError::DecodeFailed(e.to_string()))?;
260 serde_json::from_str(&json)
261 .map_err(|e| SerializerError::DecodeFailed(e.to_string()))
262 } else {
263 serde_json::from_str(raw).map_err(|e| SerializerError::DecodeFailed(e.to_string()))
265 }
266 }
267
268 fn encode_bytes<T: Serialize + ?Sized>(
269 &self,
270 value: &T,
271 ) -> Result<Vec<u8>, SerializerError> {
272 let json = serde_json::to_string(value)
273 .map_err(|e| SerializerError::EncodeFailed(e.to_string()))?;
274 fory_runtime()
275 .serialize(&json)
276 .map_err(|e| SerializerError::EncodeFailed(e.to_string()))
277 }
278
279 fn decode_bytes<T: DeserializeOwned>(&self, bytes: &[u8]) -> Result<T, SerializerError> {
280 let json: String = fory_runtime()
281 .deserialize(bytes)
282 .map_err(|e| SerializerError::DecodeFailed(e.to_string()))?;
283 serde_json::from_str(&json).map_err(|e| SerializerError::DecodeFailed(e.to_string()))
284 }
285 }
286}
287
288#[cfg(feature = "fory")]
289pub use fory_impl::{ForySerializer, ForySerializerConfig};
290
291#[derive(Clone)]
293pub enum SharedSerializer {
294 Json(JsonSerializer),
296 #[cfg(feature = "fory")]
298 Fory(ForySerializer),
299}
300
301impl Default for SharedSerializer {
302 fn default() -> Self {
303 Self::Json(JsonSerializer::default())
304 }
305}
306
307impl std::fmt::Debug for SharedSerializer {
308 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
309 write!(f, "SharedSerializer({})", self.name())
310 }
311}
312
313impl SharedSerializer {
314 #[inline]
316 pub fn name(&self) -> &'static str {
317 match self {
318 Self::Json(s) => s.name(),
319 #[cfg(feature = "fory")]
320 Self::Fory(s) => s.name(),
321 }
322 }
323
324 #[inline]
326 pub fn kind(&self, raw: &str) -> ValueKind {
327 match self {
328 Self::Json(s) => s.kind(raw),
329 #[cfg(feature = "fory")]
330 Self::Fory(s) => s.kind(raw),
331 }
332 }
333
334 #[inline]
336 pub fn encode<T: Serialize + ?Sized>(&self, value: &T) -> Result<String, SerializerError> {
337 match self {
338 Self::Json(s) => s.encode(value),
339 #[cfg(feature = "fory")]
340 Self::Fory(s) => s.encode(value),
341 }
342 }
343
344 #[inline]
346 pub fn decode<T: DeserializeOwned>(&self, raw: &str) -> Result<T, SerializerError> {
347 match self {
348 Self::Json(s) => s.decode(raw),
349 #[cfg(feature = "fory")]
350 Self::Fory(s) => s.decode(raw),
351 }
352 }
353
354 #[inline]
356 pub fn encode_bytes<T: Serialize + ?Sized>(
357 &self,
358 value: &T,
359 ) -> Result<Vec<u8>, SerializerError> {
360 match self {
361 Self::Json(s) => s.encode_bytes(value),
362 #[cfg(feature = "fory")]
363 Self::Fory(s) => s.encode_bytes(value),
364 }
365 }
366
367 #[inline]
369 pub fn decode_bytes<T: DeserializeOwned>(&self, bytes: &[u8]) -> Result<T, SerializerError> {
370 match self {
371 Self::Json(s) => s.decode_bytes(bytes),
372 #[cfg(feature = "fory")]
373 Self::Fory(s) => s.decode_bytes(bytes),
374 }
375 }
376
377 #[inline]
379 pub fn as_json(&self) -> Option<&JsonSerializer> {
380 match self {
381 Self::Json(s) => Some(s),
382 #[cfg(feature = "fory")]
383 _ => None,
384 }
385 }
386
387 #[cfg(feature = "fory")]
389 #[inline]
390 pub fn as_fory(&self) -> Option<&ForySerializer> {
391 match self {
392 Self::Fory(s) => Some(s),
393 _ => None,
394 }
395 }
396}
397
398impl From<JsonSerializer> for SharedSerializer {
399 fn from(value: JsonSerializer) -> Self {
400 Self::Json(value)
401 }
402}
403
404#[cfg(feature = "fory")]
405impl From<ForySerializer> for SharedSerializer {
406 fn from(value: ForySerializer) -> Self {
407 Self::Fory(value)
408 }
409}
410
411#[cfg(test)]
412mod tests {
413 use super::*;
414
415 #[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)]
416 struct Sample {
417 id: u32,
418 name: String,
419 }
420
421 #[test]
422 fn json_roundtrip() {
423 let ser = SharedSerializer::default();
424 let sample = Sample {
425 id: 1,
426 name: "alice".into(),
427 };
428 let raw = ser.encode(&sample).unwrap();
429 assert_eq!(ser.kind(&raw), ValueKind::Json);
430 assert_eq!(ser.decode::<Sample>(&raw).unwrap(), sample);
431 }
432
433 #[test]
434 fn json_rejects_binary_magic() {
435 let ser = SharedSerializer::default();
436 let err = ser
437 .decode::<Sample>(&format!("{BINARY_MAGIC}xxx"))
438 .unwrap_err();
439 assert!(matches!(
440 err,
441 SerializerError::FormatMismatch {
442 expected: "json",
443 actual: "binary"
444 }
445 ));
446 }
447
448 #[cfg(feature = "fory")]
449 #[test]
450 fn fory_roundtrip() {
451 let ser = SharedSerializer::from(ForySerializer::default());
452 let sample = Sample {
453 id: 2,
454 name: "bob".into(),
455 };
456 let raw = ser.encode(&sample).unwrap();
457 assert_eq!(ser.kind(&raw), ValueKind::Binary);
458 assert!(raw.starts_with(BINARY_MAGIC));
459 assert_eq!(ser.decode::<Sample>(&raw).unwrap(), sample);
460 }
461
462 #[cfg(feature = "fory")]
463 #[test]
464 fn fory_reads_legacy_json() {
465 let ser = SharedSerializer::from(ForySerializer::default());
466 let json = r#"{"id":3,"name":"carol"}"#;
467 assert_eq!(ser.kind(json), ValueKind::Json);
468 assert_eq!(
469 ser.decode::<Sample>(json).unwrap(),
470 Sample {
471 id: 3,
472 name: "carol".into(),
473 }
474 );
475 }
476}