1use crate::value::Value;
41use std::collections::HashMap;
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51pub enum CastType {
52 Integer,
54 Float,
56 Boolean,
58 String,
60 Json,
62 DateTime,
64 Date,
66 Time,
68 Bytes,
70 Array,
72}
73
74impl CastType {
75 pub fn name(&self) -> &'static str {
77 match self {
78 CastType::Integer => "integer",
79 CastType::Float => "float",
80 CastType::Boolean => "boolean",
81 CastType::String => "string",
82 CastType::Json => "json",
83 CastType::DateTime => "datetime",
84 CastType::Date => "date",
85 CastType::Time => "time",
86 CastType::Bytes => "bytes",
87 CastType::Array => "array",
88 }
89 }
90}
91
92pub trait Accessor: Send + Sync {
100 fn field(&self) -> &str;
102
103 fn read(&self, value: Value) -> Value;
105}
106
107pub trait Mutator: Send + Sync {
111 fn field(&self) -> &str;
113
114 fn write(&self, value: Value) -> Value;
116}
117
118pub struct ClosureAccessor {
124 pub field_name: String,
126 pub reader: Box<dyn Fn(Value) -> Value + Send + Sync>,
128}
129
130impl ClosureAccessor {
131 pub fn new(
133 field: impl Into<String>,
134 reader: impl Fn(Value) -> Value + Send + Sync + 'static,
135 ) -> Self {
136 Self {
137 field_name: field.into(),
138 reader: Box::new(reader),
139 }
140 }
141}
142
143impl Accessor for ClosureAccessor {
144 fn field(&self) -> &str {
145 &self.field_name
146 }
147
148 fn read(&self, value: Value) -> Value {
149 (self.reader)(value)
150 }
151}
152
153pub struct ClosureMutator {
155 pub field_name: String,
157 pub writer: Box<dyn Fn(Value) -> Value + Send + Sync>,
159}
160
161impl ClosureMutator {
162 pub fn new(
164 field: impl Into<String>,
165 writer: impl Fn(Value) -> Value + Send + Sync + 'static,
166 ) -> Self {
167 Self {
168 field_name: field.into(),
169 writer: Box::new(writer),
170 }
171 }
172}
173
174impl Mutator for ClosureMutator {
175 fn field(&self) -> &str {
176 &self.field_name
177 }
178
179 fn write(&self, value: Value) -> Value {
180 (self.writer)(value)
181 }
182}
183
184pub struct AttributeCaster;
192
193impl AttributeCaster {
194 pub fn cast_read(value: Value, target: CastType) -> Value {
196 match target {
197 CastType::Integer => Self::to_integer(value),
198 CastType::Float => Self::to_float(value),
199 CastType::Boolean => Self::to_boolean(value),
200 CastType::String => Self::to_string_value(value),
201 CastType::Json => Self::to_json(value),
202 CastType::DateTime => Self::to_datetime(value),
203 CastType::Date => Self::to_date(value),
204 CastType::Time => Self::to_time(value),
205 CastType::Bytes => Self::to_bytes(value),
206 CastType::Array => Self::to_array(value),
207 }
208 }
209
210 pub fn cast_write(value: Value, target: CastType) -> Value {
212 match target {
213 CastType::Integer => Self::to_integer(value),
214 CastType::Float => Self::to_float(value),
215 CastType::Boolean => Self::to_boolean_storage(value),
216 CastType::String => Self::to_string_value(value),
217 CastType::Json => Self::to_json_storage(value),
218 CastType::DateTime => Self::to_datetime_storage(value),
219 CastType::Date => Self::to_date_storage(value),
220 CastType::Time => Self::to_time_storage(value),
221 CastType::Bytes => Self::to_bytes(value),
222 CastType::Array => Self::to_array_storage(value),
223 }
224 }
225
226 fn to_integer(value: Value) -> Value {
229 match value {
230 Value::I64(_) | Value::I32(_) | Value::I8(_) | Value::I16(_) => value,
231 Value::U32(v) => Value::I64(v as i64),
232 Value::U64(v) => Value::I64(v as i64),
233 Value::U8(v) => Value::I64(v as i64),
234 Value::U16(v) => Value::I64(v as i64),
235 Value::F32(v) => Value::I64(v as i64),
236 Value::F64(v) => Value::I64(v as i64),
237 Value::Bool(b) => Value::I64(if b { 1 } else { 0 }),
238 Value::String(s) => {
239 if let Ok(n) = s.trim().parse::<i64>() {
240 Value::I64(n)
241 } else {
242 Value::Null
243 }
244 }
245 Value::Null => Value::Null,
246 _ => Value::Null,
247 }
248 }
249
250 fn to_float(value: Value) -> Value {
251 match value {
252 Value::F32(_) | Value::F64(_) => value,
253 Value::I64(v) => Value::F64(v as f64),
254 Value::I32(v) => Value::F64(v as f64),
255 Value::I8(v) => Value::F64(v as f64),
256 Value::I16(v) => Value::F64(v as f64),
257 Value::U32(v) => Value::F64(v as f64),
258 Value::U64(v) => Value::F64(v as f64),
259 Value::U8(v) => Value::F64(v as f64),
260 Value::U16(v) => Value::F64(v as f64),
261 Value::Bool(b) => Value::F64(if b { 1.0 } else { 0.0 }),
262 Value::String(s) => {
263 if let Ok(n) = s.trim().parse::<f64>() {
264 Value::F64(n)
265 } else {
266 Value::Null
267 }
268 }
269 Value::Null => Value::Null,
270 _ => Value::Null,
271 }
272 }
273
274 fn to_boolean(value: Value) -> Value {
275 match value {
276 Value::Bool(_) => value,
277 Value::I64(v) => Value::Bool(v != 0),
278 Value::I32(v) => Value::Bool(v != 0),
279 Value::I8(v) => Value::Bool(v != 0),
280 Value::I16(v) => Value::Bool(v != 0),
281 Value::U32(v) => Value::Bool(v != 0),
282 Value::U64(v) => Value::Bool(v != 0),
283 Value::U8(v) => Value::Bool(v != 0),
284 Value::U16(v) => Value::Bool(v != 0),
285 Value::F32(v) => Value::Bool(v != 0.0),
286 Value::F64(v) => Value::Bool(v != 0.0),
287 Value::String(s) => {
288 let lower = s.trim().to_lowercase();
289 Value::Bool(matches!(
290 lower.as_str(),
291 "1" | "true" | "yes" | "on" | "y" | "t"
292 ))
293 }
294 Value::Null => Value::Null,
295 _ => Value::Null,
296 }
297 }
298
299 fn to_boolean_storage(value: Value) -> Value {
300 match value {
301 Value::Bool(b) => Value::I64(if b { 1 } else { 0 }),
302 Value::I64(_) | Value::I32(_) | Value::I8(_) | Value::I16(_) => value,
303 Value::U32(v) => Value::I64(if v != 0 { 1 } else { 0 }),
304 Value::U64(v) => Value::I64(if v != 0 { 1 } else { 0 }),
305 Value::U8(v) => Value::I64(if v != 0 { 1 } else { 0 }),
306 Value::U16(v) => Value::I64(if v != 0 { 1 } else { 0 }),
307 Value::F32(v) => Value::I64(if v != 0.0 { 1 } else { 0 }),
308 Value::F64(v) => Value::I64(if v != 0.0 { 1 } else { 0 }),
309 Value::String(s) => {
310 let lower = s.trim().to_lowercase();
311 Value::I64(
312 if matches!(lower.as_str(), "1" | "true" | "yes" | "on" | "y" | "t") {
313 1
314 } else {
315 0
316 },
317 )
318 }
319 Value::Null => Value::Null,
320 _ => Value::Null,
321 }
322 }
323
324 fn to_string_value(value: Value) -> Value {
325 match value {
326 Value::String(_) => value,
327 Value::I64(v) => Value::String(v.to_string()),
328 Value::I32(v) => Value::String(v.to_string()),
329 Value::I8(v) => Value::String(v.to_string()),
330 Value::I16(v) => Value::String(v.to_string()),
331 Value::U32(v) => Value::String(v.to_string()),
332 Value::U64(v) => Value::String(v.to_string()),
333 Value::U8(v) => Value::String(v.to_string()),
334 Value::U16(v) => Value::String(v.to_string()),
335 Value::F32(v) => Value::String(v.to_string()),
336 Value::F64(v) => Value::String(v.to_string()),
337 Value::Bool(b) => Value::String(b.to_string()),
338 Value::Null => Value::Null,
339 other => Value::String(format!("{:?}", other)),
340 }
341 }
342
343 fn to_json(value: Value) -> Value {
344 match value {
345 Value::String(s) => {
346 if serde_json::from_str::<serde_json::Value>(&s).is_ok() {
348 Value::Json(s)
349 } else {
350 Value::String(s)
351 }
352 }
353 Value::Json(s) => Value::Json(s),
354 other => Value::Json(value_to_json_string(&other)),
355 }
356 }
357
358 fn to_json_storage(value: Value) -> Value {
359 match value {
360 Value::Json(s) => Value::Json(s),
361 Value::String(s) => Value::Json(s),
362 other => Value::Json(value_to_json_string(&other)),
363 }
364 }
365
366 fn to_datetime(value: Value) -> Value {
367 match value {
368 Value::DateTime(s) => Value::DateTime(s),
369 Value::String(s) => Value::DateTime(s),
370 Value::Null => Value::Null,
371 other => Value::DateTime(format!("{:?}", other)),
372 }
373 }
374
375 fn to_datetime_storage(value: Value) -> Value {
376 match value {
377 Value::DateTime(s) => Value::DateTime(s),
378 Value::String(s) => Value::DateTime(s),
379 Value::Null => Value::Null,
380 other => Value::DateTime(format!("{:?}", other)),
381 }
382 }
383
384 fn to_date(value: Value) -> Value {
385 match value {
386 Value::Date(s) => Value::Date(s),
387 Value::String(s) => Value::Date(s),
388 Value::Null => Value::Null,
389 other => Value::Date(format!("{:?}", other)),
390 }
391 }
392
393 fn to_date_storage(value: Value) -> Value {
394 match value {
395 Value::Date(s) => Value::Date(s),
396 Value::String(s) => Value::Date(s),
397 Value::Null => Value::Null,
398 other => Value::Date(format!("{:?}", other)),
399 }
400 }
401
402 fn to_time(value: Value) -> Value {
403 match value {
404 Value::Time(s) => Value::Time(s),
405 Value::String(s) => Value::Time(s),
406 Value::Null => Value::Null,
407 other => Value::Time(format!("{:?}", other)),
408 }
409 }
410
411 fn to_time_storage(value: Value) -> Value {
412 match value {
413 Value::Time(s) => Value::Time(s),
414 Value::String(s) => Value::Time(s),
415 Value::Null => Value::Null,
416 other => Value::Time(format!("{:?}", other)),
417 }
418 }
419
420 fn to_bytes(value: Value) -> Value {
421 match value {
422 Value::Bytes(_) => value,
423 Value::String(s) => Value::Bytes(s.into_bytes()),
424 Value::Null => Value::Null,
425 _ => Value::Null,
426 }
427 }
428
429 fn to_array(value: Value) -> Value {
430 match value {
431 Value::Array(_) => value,
432 Value::Json(s) => {
433 match serde_json::from_str::<Vec<serde_json::Value>>(&s) {
435 Ok(json_arr) => {
436 let items: Vec<Value> = json_arr.into_iter().map(json_to_value).collect();
437 Value::Array(items)
438 }
439 Err(_) => Value::Array(vec![Value::Json(s)]),
440 }
441 }
442 Value::String(s) => {
443 match serde_json::from_str::<Vec<serde_json::Value>>(&s) {
445 Ok(json_arr) => {
446 let items: Vec<Value> = json_arr.into_iter().map(json_to_value).collect();
447 Value::Array(items)
448 }
449 Err(_) => Value::Array(vec![Value::String(s)]),
450 }
451 }
452 Value::Null => Value::Null,
453 other => Value::Array(vec![other]),
454 }
455 }
456
457 fn to_array_storage(value: Value) -> Value {
458 match value {
459 Value::Array(items) => {
460 let json_arr: Vec<serde_json::Value> = items.iter().map(value_to_json).collect();
462 Value::Json(serde_json::to_string(&json_arr).unwrap_or_else(|_| "[]".to_string()))
463 }
464 other => Value::Json(value_to_json_string(&other)),
465 }
466 }
467}
468
469fn value_to_json(value: &Value) -> serde_json::Value {
473 match value {
474 Value::Null => serde_json::Value::Null,
475 Value::Bool(b) => serde_json::Value::Bool(*b),
476 Value::I8(v) => serde_json::Value::Number((*v).into()),
477 Value::I16(v) => serde_json::Value::Number((*v).into()),
478 Value::I32(v) => serde_json::Value::Number((*v).into()),
479 Value::I64(v) => serde_json::Value::Number((*v).into()),
480 Value::U8(v) => serde_json::Value::Number((*v).into()),
481 Value::U16(v) => serde_json::Value::Number((*v).into()),
482 Value::U32(v) => serde_json::Value::Number((*v).into()),
483 Value::U64(v) => serde_json::Value::Number((*v).into()),
484 Value::F32(v) => serde_json::Number::from_f64(*v as f64)
485 .map(serde_json::Value::Number)
486 .unwrap_or(serde_json::Value::Null),
487 Value::F64(v) => serde_json::Number::from_f64(*v)
488 .map(serde_json::Value::Number)
489 .unwrap_or(serde_json::Value::Null),
490 Value::Decimal(s) => {
491 serde_json::from_str(s).unwrap_or_else(|_| serde_json::Value::String(s.clone()))
493 }
494 Value::String(s) => serde_json::Value::String(s.clone()),
495 #[cfg(feature = "perf-box-str")]
496 Value::BoxedStr(s) => serde_json::Value::String(s.to_string()),
497 Value::Bytes(b) => {
498 use std::fmt::Write;
500 let mut s = String::with_capacity(b.len() * 2);
501 for byte in b {
502 let _ = write!(&mut s, "{:02x}", byte);
503 }
504 serde_json::Value::String(s)
505 }
506 Value::Uuid(s) => serde_json::Value::String(s.clone()),
507 Value::Date(s) => serde_json::Value::String(s.clone()),
508 Value::DateTime(s) => serde_json::Value::String(s.clone()),
509 Value::Time(s) => serde_json::Value::String(s.clone()),
510 Value::Json(s) => serde_json::from_str(s).unwrap_or(serde_json::Value::String(s.clone())),
511 Value::Array(items) => serde_json::Value::Array(items.iter().map(value_to_json).collect()),
512 Value::Object(map) => {
513 let mut obj = serde_json::Map::new();
514 for (k, v) in map {
515 obj.insert(k.clone(), value_to_json(v));
516 }
517 serde_json::Value::Object(obj)
518 }
519 }
520}
521
522fn value_to_json_string(value: &Value) -> String {
524 serde_json::to_string(&value_to_json(value)).unwrap_or_else(|_| "null".to_string())
525}
526
527fn json_to_value(jv: serde_json::Value) -> Value {
531 match jv {
532 serde_json::Value::Null => Value::Null,
533 serde_json::Value::Bool(b) => Value::Bool(b),
534 serde_json::Value::Number(n) => {
535 if let Some(i) = n.as_i64() {
536 Value::I64(i)
537 } else if let Some(u) = n.as_u64() {
538 Value::U64(u)
539 } else if let Some(f) = n.as_f64() {
540 Value::F64(f)
541 } else {
542 Value::Null
543 }
544 }
545 serde_json::Value::String(s) => Value::String(s),
546 serde_json::Value::Array(arr) => Value::Array(arr.into_iter().map(json_to_value).collect()),
547 serde_json::Value::Object(obj) => {
548 let mut map = std::collections::HashMap::new();
549 for (k, v) in obj {
550 map.insert(k, json_to_value(v));
551 }
552 Value::Object(map)
553 }
554 }
555}
556
557pub struct AccessorRegistry {
565 accessors: HashMap<String, Box<dyn Accessor>>,
567 mutators: HashMap<String, Box<dyn Mutator>>,
569 casts: HashMap<String, CastType>,
571}
572
573impl Default for AccessorRegistry {
574 fn default() -> Self {
575 Self::new()
576 }
577}
578
579impl AccessorRegistry {
580 pub fn new() -> Self {
582 Self {
583 accessors: HashMap::new(),
584 mutators: HashMap::new(),
585 casts: HashMap::new(),
586 }
587 }
588
589 pub fn register_accessor(&mut self, accessor: Box<dyn Accessor>) {
591 let field = accessor.field().to_string();
592 self.accessors.insert(field, accessor);
593 }
594
595 pub fn register_mutator(&mut self, mutator: Box<dyn Mutator>) {
597 let field = mutator.field().to_string();
598 self.mutators.insert(field, mutator);
599 }
600
601 pub fn register_cast(&mut self, field: impl Into<String>, cast: CastType) {
603 self.casts.insert(field.into(), cast);
604 }
605
606 pub fn read(&self, field: &str, value: Value) -> Value {
608 let v1 = if let Some(cast) = self.casts.get(field) {
609 AttributeCaster::cast_read(value, *cast)
610 } else {
611 value
612 };
613 if let Some(accessor) = self.accessors.get(field) {
614 accessor.read(v1)
615 } else {
616 v1
617 }
618 }
619
620 pub fn write(&self, field: &str, value: Value) -> Value {
622 let v1 = if let Some(mutator) = self.mutators.get(field) {
623 mutator.write(value)
624 } else {
625 value
626 };
627 if let Some(cast) = self.casts.get(field) {
628 AttributeCaster::cast_write(v1, *cast)
629 } else {
630 v1
631 }
632 }
633
634 pub fn cast_read(&self, field: &str, value: Value) -> Value {
636 if let Some(cast) = self.casts.get(field) {
637 AttributeCaster::cast_read(value, *cast)
638 } else {
639 value
640 }
641 }
642
643 pub fn cast_write(&self, field: &str, value: Value) -> Value {
645 if let Some(cast) = self.casts.get(field) {
646 AttributeCaster::cast_write(value, *cast)
647 } else {
648 value
649 }
650 }
651
652 pub fn has_accessor(&self, field: &str) -> bool {
654 self.accessors.contains_key(field)
655 }
656
657 pub fn has_mutator(&self, field: &str) -> bool {
659 self.mutators.contains_key(field)
660 }
661
662 pub fn has_cast(&self, field: &str) -> bool {
664 self.casts.contains_key(field)
665 }
666
667 pub fn get_cast(&self, field: &str) -> Option<CastType> {
669 self.casts.get(field).copied()
670 }
671
672 pub fn accessor_count(&self) -> usize {
674 self.accessors.len()
675 }
676
677 pub fn mutator_count(&self) -> usize {
679 self.mutators.len()
680 }
681
682 pub fn cast_count(&self) -> usize {
684 self.casts.len()
685 }
686}
687
688#[cfg(test)]
693mod tests {
694 use super::*;
695
696 #[test]
699 fn test_cast_type_name() {
700 assert_eq!(CastType::Integer.name(), "integer");
701 assert_eq!(CastType::Boolean.name(), "boolean");
702 assert_eq!(CastType::Json.name(), "json");
703 assert_eq!(CastType::DateTime.name(), "datetime");
704 }
705
706 #[test]
709 fn test_cast_to_integer_from_string() {
710 let v = AttributeCaster::cast_read(Value::String("42".to_string()), CastType::Integer);
711 assert_eq!(v, Value::I64(42));
712 }
713
714 #[test]
715 fn test_cast_to_integer_from_invalid_string() {
716 let v = AttributeCaster::cast_read(Value::String("abc".to_string()), CastType::Integer);
717 assert_eq!(v, Value::Null);
718 }
719
720 #[test]
721 fn test_cast_to_integer_from_bool() {
722 let v = AttributeCaster::cast_read(Value::Bool(true), CastType::Integer);
723 assert_eq!(v, Value::I64(1));
724 }
725
726 #[test]
727 fn test_cast_to_integer_from_float() {
728 let v = AttributeCaster::cast_read(Value::F64(3.7), CastType::Integer);
729 assert_eq!(v, Value::I64(3));
730 }
731
732 #[test]
733 fn test_cast_to_integer_preserves_i64() {
734 let v = AttributeCaster::cast_read(Value::I64(100), CastType::Integer);
735 assert_eq!(v, Value::I64(100));
736 }
737
738 #[test]
741 fn test_cast_to_float_from_string() {
742 let v = AttributeCaster::cast_read(Value::String("3.15".to_string()), CastType::Float);
743 assert_eq!(v, Value::F64(3.15));
744 }
745
746 #[test]
747 fn test_cast_to_float_from_i64() {
748 let v = AttributeCaster::cast_read(Value::I64(42), CastType::Float);
749 assert_eq!(v, Value::F64(42.0));
750 }
751
752 #[test]
755 fn test_cast_to_boolean_from_i64_one() {
756 let v = AttributeCaster::cast_read(Value::I64(1), CastType::Boolean);
757 assert_eq!(v, Value::Bool(true));
758 }
759
760 #[test]
761 fn test_cast_to_boolean_from_i64_zero() {
762 let v = AttributeCaster::cast_read(Value::I64(0), CastType::Boolean);
763 assert_eq!(v, Value::Bool(false));
764 }
765
766 #[test]
767 fn test_cast_to_boolean_from_string_true() {
768 let v = AttributeCaster::cast_read(Value::String("true".to_string()), CastType::Boolean);
769 assert_eq!(v, Value::Bool(true));
770 }
771
772 #[test]
773 fn test_cast_to_boolean_from_string_yes() {
774 let v = AttributeCaster::cast_read(Value::String("yes".to_string()), CastType::Boolean);
775 assert_eq!(v, Value::Bool(true));
776 }
777
778 #[test]
779 fn test_cast_to_boolean_from_string_on() {
780 let v = AttributeCaster::cast_read(Value::String("on".to_string()), CastType::Boolean);
781 assert_eq!(v, Value::Bool(true));
782 }
783
784 #[test]
785 fn test_cast_to_boolean_from_string_random() {
786 let v = AttributeCaster::cast_read(Value::String("random".to_string()), CastType::Boolean);
787 assert_eq!(v, Value::Bool(false));
788 }
789
790 #[test]
791 fn test_cast_to_boolean_preserves_bool() {
792 let v = AttributeCaster::cast_read(Value::Bool(true), CastType::Boolean);
793 assert_eq!(v, Value::Bool(true));
794 }
795
796 #[test]
799 fn test_cast_to_boolean_storage_from_bool() {
800 let v = AttributeCaster::cast_write(Value::Bool(true), CastType::Boolean);
801 assert_eq!(v, Value::I64(1));
802 }
803
804 #[test]
805 fn test_cast_to_boolean_storage_from_string() {
806 let v = AttributeCaster::cast_write(Value::String("yes".to_string()), CastType::Boolean);
807 assert_eq!(v, Value::I64(1));
808 }
809
810 #[test]
813 fn test_cast_to_string_from_i64() {
814 let v = AttributeCaster::cast_read(Value::I64(42), CastType::String);
815 assert_eq!(v, Value::String("42".to_string()));
816 }
817
818 #[test]
819 fn test_cast_to_string_from_bool() {
820 let v = AttributeCaster::cast_read(Value::Bool(true), CastType::String);
821 assert_eq!(v, Value::String("true".to_string()));
822 }
823
824 #[test]
825 fn test_cast_to_string_preserves_string() {
826 let v = AttributeCaster::cast_read(Value::String("hello".to_string()), CastType::String);
827 assert_eq!(v, Value::String("hello".to_string()));
828 }
829
830 #[test]
833 fn test_cast_to_json_from_string() {
834 let v = AttributeCaster::cast_read(
835 Value::String(r#"{"key":"value"}"#.to_string()),
836 CastType::Json,
837 );
838 assert!(matches!(v, Value::Json(_)));
840 if let Value::Json(s) = v {
841 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
843 assert_eq!(parsed["key"], "value");
844 }
845 }
846
847 #[test]
848 fn test_cast_to_json_from_invalid_string() {
849 let v = AttributeCaster::cast_read(Value::String("not a json".to_string()), CastType::Json);
850 assert!(matches!(v, Value::String(_)));
852 }
853
854 #[test]
855 fn test_cast_to_json_from_other() {
856 let v = AttributeCaster::cast_read(Value::I64(42), CastType::Json);
857 assert!(matches!(v, Value::Json(_)));
858 if let Value::Json(s) = v {
859 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
861 assert_eq!(parsed, serde_json::Value::Number(42.into()));
862 }
863 }
864
865 #[test]
868 fn test_cast_to_datetime_from_string() {
869 let v = AttributeCaster::cast_read(
870 Value::String("2026-07-19T10:00:00Z".to_string()),
871 CastType::DateTime,
872 );
873 assert_eq!(v, Value::DateTime("2026-07-19T10:00:00Z".to_string()));
874 }
875
876 #[test]
877 fn test_cast_to_date_from_string() {
878 let v = AttributeCaster::cast_read(Value::String("2026-07-19".to_string()), CastType::Date);
879 assert_eq!(v, Value::Date("2026-07-19".to_string()));
880 }
881
882 #[test]
883 fn test_cast_to_time_from_string() {
884 let v = AttributeCaster::cast_read(Value::String("10:30:00".to_string()), CastType::Time);
885 assert_eq!(v, Value::Time("10:30:00".to_string()));
886 }
887
888 #[test]
891 fn test_cast_to_bytes_from_string() {
892 let v = AttributeCaster::cast_read(Value::String("hello".to_string()), CastType::Bytes);
893 assert_eq!(v, Value::Bytes(b"hello".to_vec()));
894 }
895
896 #[test]
897 fn test_cast_to_bytes_preserves_bytes() {
898 let v = AttributeCaster::cast_read(Value::Bytes(b"data".to_vec()), CastType::Bytes);
899 assert_eq!(v, Value::Bytes(b"data".to_vec()));
900 }
901
902 #[test]
905 fn test_cast_to_array_from_string() {
906 let v = AttributeCaster::cast_read(Value::String("item".to_string()), CastType::Array);
907 assert!(matches!(v, Value::Array(_)));
908 if let Value::Array(arr) = v {
909 assert_eq!(arr.len(), 1);
910 }
911 }
912
913 #[test]
914 fn test_cast_to_array_from_json_string() {
915 let v = AttributeCaster::cast_read(Value::String("[1, 2, 3]".to_string()), CastType::Array);
917 assert!(matches!(v, Value::Array(_)));
918 if let Value::Array(arr) = v {
919 assert_eq!(arr.len(), 3);
920 assert_eq!(arr[0], Value::I64(1));
921 assert_eq!(arr[1], Value::I64(2));
922 assert_eq!(arr[2], Value::I64(3));
923 }
924 }
925
926 #[test]
927 fn test_cast_to_array_from_json_value() {
928 let v =
930 AttributeCaster::cast_read(Value::Json(r#"["a", "b"]"#.to_string()), CastType::Array);
931 assert!(matches!(v, Value::Array(_)));
932 if let Value::Array(arr) = v {
933 assert_eq!(arr.len(), 2);
934 assert_eq!(arr[0], Value::String("a".to_string()));
935 assert_eq!(arr[1], Value::String("b".to_string()));
936 }
937 }
938
939 #[test]
940 fn test_cast_to_array_preserves_array() {
941 let arr = vec![Value::I64(1), Value::I64(2)];
942 let v = AttributeCaster::cast_read(Value::Array(arr.clone()), CastType::Array);
943 assert_eq!(v, Value::Array(arr));
944 }
945
946 #[test]
947 fn test_cast_to_array_storage_serializes_to_json() {
948 let v = AttributeCaster::cast_write(
949 Value::Array(vec![Value::I64(1), Value::I64(2)]),
950 CastType::Array,
951 );
952 assert!(matches!(v, Value::Json(_)));
953 if let Value::Json(s) = v {
954 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
956 assert!(parsed.is_array());
957 assert_eq!(parsed[0], serde_json::Value::Number(1.into()));
958 assert_eq!(parsed[1], serde_json::Value::Number(2.into()));
959 }
960 }
961
962 #[test]
963 fn test_cast_to_array_storage_not_debug_format() {
964 let v = AttributeCaster::cast_write(
966 Value::Array(vec![Value::I64(1), Value::I64(2)]),
967 CastType::Array,
968 );
969 if let Value::Json(s) = v {
970 assert!(!s.contains("I64"), "JSON 不应包含 Debug 格式 I64: {}", s);
972 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
974 assert!(parsed.is_array());
975 }
976 }
977
978 #[test]
979 fn test_cast_to_json_storage_from_other() {
980 let v = AttributeCaster::cast_write(Value::I64(42), CastType::Json);
981 assert!(matches!(v, Value::Json(_)));
982 if let Value::Json(s) = v {
983 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
985 assert_eq!(parsed, serde_json::Value::Number(42.into()));
986 }
987 }
988
989 #[test]
992 fn test_closure_accessor() {
993 let accessor = ClosureAccessor::new("name", |v| match v {
994 Value::String(s) => Value::String(s.to_uppercase()),
995 other => other,
996 });
997 let v = accessor.read(Value::String("alice".to_string()));
998 assert_eq!(v, Value::String("ALICE".to_string()));
999 assert_eq!(accessor.field(), "name");
1000 }
1001
1002 #[test]
1003 fn test_closure_mutator() {
1004 let mutator = ClosureMutator::new("email", |v| match v {
1005 Value::String(s) => Value::String(s.to_lowercase()),
1006 other => other,
1007 });
1008 let v = mutator.write(Value::String("ALICE@EXAMPLE.COM".to_string()));
1009 assert_eq!(v, Value::String("alice@example.com".to_string()));
1010 assert_eq!(mutator.field(), "email");
1011 }
1012
1013 #[test]
1016 fn test_registry_empty() {
1017 let r = AccessorRegistry::new();
1018 assert_eq!(r.accessor_count(), 0);
1019 assert_eq!(r.mutator_count(), 0);
1020 assert_eq!(r.cast_count(), 0);
1021 }
1022
1023 #[test]
1024 fn test_registry_register_cast() {
1025 let mut r = AccessorRegistry::new();
1026 r.register_cast("is_admin", CastType::Boolean);
1027 assert!(r.has_cast("is_admin"));
1028 assert_eq!(r.get_cast("is_admin"), Some(CastType::Boolean));
1029 assert_eq!(r.cast_count(), 1);
1030 }
1031
1032 #[test]
1033 fn test_registry_register_accessor() {
1034 let mut r = AccessorRegistry::new();
1035 r.register_accessor(Box::new(ClosureAccessor::new("name", |v| match v {
1036 Value::String(s) => Value::String(s.to_uppercase()),
1037 other => other,
1038 })));
1039 assert!(r.has_accessor("name"));
1040 assert_eq!(r.accessor_count(), 1);
1041 }
1042
1043 #[test]
1044 fn test_registry_register_mutator() {
1045 let mut r = AccessorRegistry::new();
1046 r.register_mutator(Box::new(ClosureMutator::new("email", |v| match v {
1047 Value::String(s) => Value::String(s.to_lowercase()),
1048 other => other,
1049 })));
1050 assert!(r.has_mutator("email"));
1051 assert_eq!(r.mutator_count(), 1);
1052 }
1053
1054 #[test]
1057 fn test_registry_read_applies_cast_then_accessor() {
1058 let mut r = AccessorRegistry::new();
1059 r.register_cast("is_admin", CastType::Boolean);
1060 r.register_accessor(Box::new(ClosureAccessor::new("is_admin", |v| {
1061 if v == Value::Bool(true) {
1062 Value::String("管理员".to_string())
1063 } else {
1064 Value::String("普通用户".to_string())
1065 }
1066 })));
1067
1068 let v = r.read("is_admin", Value::I64(1));
1070 assert_eq!(v, Value::String("管理员".to_string()));
1071 }
1072
1073 #[test]
1074 fn test_registry_write_applies_mutator_then_cast() {
1075 let mut r = AccessorRegistry::new();
1076 r.register_cast("is_admin", CastType::Boolean);
1077 r.register_mutator(Box::new(ClosureMutator::new("is_admin", |v| match v {
1078 Value::String(s) => {
1079 let lower = s.to_lowercase();
1080 Value::Bool(lower == "admin" || lower == "true")
1081 }
1082 other => other,
1083 })));
1084
1085 let v = r.write("is_admin", Value::String("admin".to_string()));
1087 assert_eq!(v, Value::I64(1));
1088 }
1089
1090 #[test]
1091 fn test_registry_read_without_cast_or_accessor() {
1092 let r = AccessorRegistry::new();
1093 let v = r.read("any_field", Value::I64(42));
1094 assert_eq!(v, Value::I64(42));
1095 }
1096
1097 #[test]
1098 fn test_registry_write_without_cast_or_mutator() {
1099 let r = AccessorRegistry::new();
1100 let v = r.write("any_field", Value::I64(42));
1101 assert_eq!(v, Value::I64(42));
1102 }
1103
1104 #[test]
1105 fn test_registry_cast_read_only() {
1106 let mut r = AccessorRegistry::new();
1107 r.register_cast("is_admin", CastType::Boolean);
1108
1109 let v = r.cast_read("is_admin", Value::I64(1));
1110 assert_eq!(v, Value::Bool(true));
1111 }
1112
1113 #[test]
1114 fn test_registry_cast_write_only() {
1115 let mut r = AccessorRegistry::new();
1116 r.register_cast("is_admin", CastType::Boolean);
1117
1118 let v = r.cast_write("is_admin", Value::Bool(true));
1119 assert_eq!(v, Value::I64(1));
1120 }
1121
1122 #[test]
1125 fn test_complex_user_model_scenario() {
1126 let mut r = AccessorRegistry::new();
1127
1128 r.register_cast("is_admin", CastType::Boolean);
1130
1131 r.register_mutator(Box::new(ClosureMutator::new("email", |v| match v {
1133 Value::String(s) => Value::String(s.to_lowercase()),
1134 other => other,
1135 })));
1136
1137 r.register_accessor(Box::new(ClosureAccessor::new(
1139 "full_name",
1140 |v| v, )));
1142
1143 r.register_cast("settings", CastType::Json);
1145
1146 r.register_cast("created_at", CastType::DateTime);
1148
1149 let v = r.read("is_admin", Value::I64(1));
1151 assert_eq!(v, Value::Bool(true));
1152
1153 let v = r.write("email", Value::String("Alice@Example.COM".to_string()));
1155 assert_eq!(v, Value::String("alice@example.com".to_string()));
1156
1157 let v = r.read("settings", Value::String(r#"{"theme":"dark"}"#.to_string()));
1159 assert!(matches!(v, Value::Json(_)));
1160
1161 assert_eq!(r.accessor_count(), 1);
1162 assert_eq!(r.mutator_count(), 1);
1163 assert_eq!(r.cast_count(), 3);
1164 }
1165
1166 #[test]
1169 fn test_default_is_empty() {
1170 let r = AccessorRegistry::default();
1171 assert_eq!(r.accessor_count(), 0);
1172 assert_eq!(r.mutator_count(), 0);
1173 assert_eq!(r.cast_count(), 0);
1174 }
1175}