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
437 .into_iter()
438 .map(|jv| json_to_value(jv))
439 .collect();
440 Value::Array(items)
441 }
442 Err(_) => Value::Array(vec![Value::Json(s)]),
443 }
444 }
445 Value::String(s) => {
446 match serde_json::from_str::<Vec<serde_json::Value>>(&s) {
448 Ok(json_arr) => {
449 let items: Vec<Value> = json_arr
450 .into_iter()
451 .map(|jv| json_to_value(jv))
452 .collect();
453 Value::Array(items)
454 }
455 Err(_) => Value::Array(vec![Value::String(s)]),
456 }
457 }
458 Value::Null => Value::Null,
459 other => Value::Array(vec![other]),
460 }
461 }
462
463 fn to_array_storage(value: Value) -> Value {
464 match value {
465 Value::Array(items) => {
466 let json_arr: Vec<serde_json::Value> =
468 items.iter().map(|v| value_to_json(&v)).collect();
469 Value::Json(serde_json::to_string(&json_arr).unwrap_or_else(|_| "[]".to_string()))
470 }
471 other => Value::Json(value_to_json_string(&other)),
472 }
473 }
474}
475
476fn value_to_json(value: &Value) -> serde_json::Value {
480 match value {
481 Value::Null => serde_json::Value::Null,
482 Value::Bool(b) => serde_json::Value::Bool(*b),
483 Value::I8(v) => serde_json::Value::Number((*v).into()),
484 Value::I16(v) => serde_json::Value::Number((*v).into()),
485 Value::I32(v) => serde_json::Value::Number((*v).into()),
486 Value::I64(v) => serde_json::Value::Number((*v).into()),
487 Value::U8(v) => serde_json::Value::Number((*v).into()),
488 Value::U16(v) => serde_json::Value::Number((*v).into()),
489 Value::U32(v) => serde_json::Value::Number((*v).into()),
490 Value::U64(v) => serde_json::Value::Number((*v).into()),
491 Value::F32(v) => {
492 serde_json::Number::from_f64(*v as f64).map(serde_json::Value::Number)
493 .unwrap_or(serde_json::Value::Null)
494 }
495 Value::F64(v) => {
496 serde_json::Number::from_f64(*v).map(serde_json::Value::Number)
497 .unwrap_or(serde_json::Value::Null)
498 }
499 Value::Decimal(s) => {
500 serde_json::from_str(s).unwrap_or_else(|_| serde_json::Value::String(s.clone()))
502 }
503 Value::String(s) => serde_json::Value::String(s.clone()),
504 Value::Bytes(b) => {
505 use std::fmt::Write;
507 let mut s = String::with_capacity(b.len() * 2);
508 for byte in b {
509 write!(&mut s, "{:02x}", byte).unwrap();
510 }
511 serde_json::Value::String(s)
512 }
513 Value::Uuid(s) => serde_json::Value::String(s.clone()),
514 Value::Date(s) => serde_json::Value::String(s.clone()),
515 Value::DateTime(s) => serde_json::Value::String(s.clone()),
516 Value::Time(s) => serde_json::Value::String(s.clone()),
517 Value::Json(s) => {
518 serde_json::from_str(s).unwrap_or(serde_json::Value::String(s.clone()))
519 }
520 Value::Array(items) => {
521 serde_json::Value::Array(items.iter().map(value_to_json).collect())
522 }
523 Value::Object(map) => {
524 let mut obj = serde_json::Map::new();
525 for (k, v) in map {
526 obj.insert(k.clone(), value_to_json(v));
527 }
528 serde_json::Value::Object(obj)
529 }
530 }
531}
532
533fn value_to_json_string(value: &Value) -> String {
535 serde_json::to_string(&value_to_json(value)).unwrap_or_else(|_| "null".to_string())
536}
537
538fn json_to_value(jv: serde_json::Value) -> Value {
542 match jv {
543 serde_json::Value::Null => Value::Null,
544 serde_json::Value::Bool(b) => Value::Bool(b),
545 serde_json::Value::Number(n) => {
546 if let Some(i) = n.as_i64() {
547 Value::I64(i)
548 } else if let Some(u) = n.as_u64() {
549 Value::U64(u)
550 } else if let Some(f) = n.as_f64() {
551 Value::F64(f)
552 } else {
553 Value::Null
554 }
555 }
556 serde_json::Value::String(s) => Value::String(s),
557 serde_json::Value::Array(arr) => {
558 Value::Array(arr.into_iter().map(json_to_value).collect())
559 }
560 serde_json::Value::Object(obj) => {
561 let mut map = std::collections::HashMap::new();
562 for (k, v) in obj {
563 map.insert(k, json_to_value(v));
564 }
565 Value::Object(map)
566 }
567 }
568}
569
570pub struct AccessorRegistry {
578 accessors: HashMap<String, Box<dyn Accessor>>,
580 mutators: HashMap<String, Box<dyn Mutator>>,
582 casts: HashMap<String, CastType>,
584}
585
586impl Default for AccessorRegistry {
587 fn default() -> Self {
588 Self::new()
589 }
590}
591
592impl AccessorRegistry {
593 pub fn new() -> Self {
595 Self {
596 accessors: HashMap::new(),
597 mutators: HashMap::new(),
598 casts: HashMap::new(),
599 }
600 }
601
602 pub fn register_accessor(&mut self, accessor: Box<dyn Accessor>) {
604 let field = accessor.field().to_string();
605 self.accessors.insert(field, accessor);
606 }
607
608 pub fn register_mutator(&mut self, mutator: Box<dyn Mutator>) {
610 let field = mutator.field().to_string();
611 self.mutators.insert(field, mutator);
612 }
613
614 pub fn register_cast(&mut self, field: impl Into<String>, cast: CastType) {
616 self.casts.insert(field.into(), cast);
617 }
618
619 pub fn read(&self, field: &str, value: Value) -> Value {
621 let v1 = if let Some(cast) = self.casts.get(field) {
622 AttributeCaster::cast_read(value, *cast)
623 } else {
624 value
625 };
626 if let Some(accessor) = self.accessors.get(field) {
627 accessor.read(v1)
628 } else {
629 v1
630 }
631 }
632
633 pub fn write(&self, field: &str, value: Value) -> Value {
635 let v1 = if let Some(mutator) = self.mutators.get(field) {
636 mutator.write(value)
637 } else {
638 value
639 };
640 if let Some(cast) = self.casts.get(field) {
641 AttributeCaster::cast_write(v1, *cast)
642 } else {
643 v1
644 }
645 }
646
647 pub fn cast_read(&self, field: &str, value: Value) -> Value {
649 if let Some(cast) = self.casts.get(field) {
650 AttributeCaster::cast_read(value, *cast)
651 } else {
652 value
653 }
654 }
655
656 pub fn cast_write(&self, field: &str, value: Value) -> Value {
658 if let Some(cast) = self.casts.get(field) {
659 AttributeCaster::cast_write(value, *cast)
660 } else {
661 value
662 }
663 }
664
665 pub fn has_accessor(&self, field: &str) -> bool {
667 self.accessors.contains_key(field)
668 }
669
670 pub fn has_mutator(&self, field: &str) -> bool {
672 self.mutators.contains_key(field)
673 }
674
675 pub fn has_cast(&self, field: &str) -> bool {
677 self.casts.contains_key(field)
678 }
679
680 pub fn get_cast(&self, field: &str) -> Option<CastType> {
682 self.casts.get(field).copied()
683 }
684
685 pub fn accessor_count(&self) -> usize {
687 self.accessors.len()
688 }
689
690 pub fn mutator_count(&self) -> usize {
692 self.mutators.len()
693 }
694
695 pub fn cast_count(&self) -> usize {
697 self.casts.len()
698 }
699}
700
701#[cfg(test)]
706mod tests {
707 use super::*;
708
709 #[test]
712 fn test_cast_type_name() {
713 assert_eq!(CastType::Integer.name(), "integer");
714 assert_eq!(CastType::Boolean.name(), "boolean");
715 assert_eq!(CastType::Json.name(), "json");
716 assert_eq!(CastType::DateTime.name(), "datetime");
717 }
718
719 #[test]
722 fn test_cast_to_integer_from_string() {
723 let v = AttributeCaster::cast_read(Value::String("42".to_string()), CastType::Integer);
724 assert_eq!(v, Value::I64(42));
725 }
726
727 #[test]
728 fn test_cast_to_integer_from_invalid_string() {
729 let v = AttributeCaster::cast_read(Value::String("abc".to_string()), CastType::Integer);
730 assert_eq!(v, Value::Null);
731 }
732
733 #[test]
734 fn test_cast_to_integer_from_bool() {
735 let v = AttributeCaster::cast_read(Value::Bool(true), CastType::Integer);
736 assert_eq!(v, Value::I64(1));
737 }
738
739 #[test]
740 fn test_cast_to_integer_from_float() {
741 let v = AttributeCaster::cast_read(Value::F64(3.7), CastType::Integer);
742 assert_eq!(v, Value::I64(3));
743 }
744
745 #[test]
746 fn test_cast_to_integer_preserves_i64() {
747 let v = AttributeCaster::cast_read(Value::I64(100), CastType::Integer);
748 assert_eq!(v, Value::I64(100));
749 }
750
751 #[test]
754 fn test_cast_to_float_from_string() {
755 let v = AttributeCaster::cast_read(Value::String("3.15".to_string()), CastType::Float);
756 assert_eq!(v, Value::F64(3.15));
757 }
758
759 #[test]
760 fn test_cast_to_float_from_i64() {
761 let v = AttributeCaster::cast_read(Value::I64(42), CastType::Float);
762 assert_eq!(v, Value::F64(42.0));
763 }
764
765 #[test]
768 fn test_cast_to_boolean_from_i64_one() {
769 let v = AttributeCaster::cast_read(Value::I64(1), CastType::Boolean);
770 assert_eq!(v, Value::Bool(true));
771 }
772
773 #[test]
774 fn test_cast_to_boolean_from_i64_zero() {
775 let v = AttributeCaster::cast_read(Value::I64(0), CastType::Boolean);
776 assert_eq!(v, Value::Bool(false));
777 }
778
779 #[test]
780 fn test_cast_to_boolean_from_string_true() {
781 let v = AttributeCaster::cast_read(Value::String("true".to_string()), CastType::Boolean);
782 assert_eq!(v, Value::Bool(true));
783 }
784
785 #[test]
786 fn test_cast_to_boolean_from_string_yes() {
787 let v = AttributeCaster::cast_read(Value::String("yes".to_string()), CastType::Boolean);
788 assert_eq!(v, Value::Bool(true));
789 }
790
791 #[test]
792 fn test_cast_to_boolean_from_string_on() {
793 let v = AttributeCaster::cast_read(Value::String("on".to_string()), CastType::Boolean);
794 assert_eq!(v, Value::Bool(true));
795 }
796
797 #[test]
798 fn test_cast_to_boolean_from_string_random() {
799 let v = AttributeCaster::cast_read(Value::String("random".to_string()), CastType::Boolean);
800 assert_eq!(v, Value::Bool(false));
801 }
802
803 #[test]
804 fn test_cast_to_boolean_preserves_bool() {
805 let v = AttributeCaster::cast_read(Value::Bool(true), CastType::Boolean);
806 assert_eq!(v, Value::Bool(true));
807 }
808
809 #[test]
812 fn test_cast_to_boolean_storage_from_bool() {
813 let v = AttributeCaster::cast_write(Value::Bool(true), CastType::Boolean);
814 assert_eq!(v, Value::I64(1));
815 }
816
817 #[test]
818 fn test_cast_to_boolean_storage_from_string() {
819 let v = AttributeCaster::cast_write(Value::String("yes".to_string()), CastType::Boolean);
820 assert_eq!(v, Value::I64(1));
821 }
822
823 #[test]
826 fn test_cast_to_string_from_i64() {
827 let v = AttributeCaster::cast_read(Value::I64(42), CastType::String);
828 assert_eq!(v, Value::String("42".to_string()));
829 }
830
831 #[test]
832 fn test_cast_to_string_from_bool() {
833 let v = AttributeCaster::cast_read(Value::Bool(true), CastType::String);
834 assert_eq!(v, Value::String("true".to_string()));
835 }
836
837 #[test]
838 fn test_cast_to_string_preserves_string() {
839 let v = AttributeCaster::cast_read(Value::String("hello".to_string()), CastType::String);
840 assert_eq!(v, Value::String("hello".to_string()));
841 }
842
843 #[test]
846 fn test_cast_to_json_from_string() {
847 let v = AttributeCaster::cast_read(
848 Value::String(r#"{"key":"value"}"#.to_string()),
849 CastType::Json,
850 );
851 assert!(matches!(v, Value::Json(_)));
853 if let Value::Json(s) = v {
854 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
856 assert_eq!(parsed["key"], "value");
857 }
858 }
859
860 #[test]
861 fn test_cast_to_json_from_invalid_string() {
862 let v = AttributeCaster::cast_read(
863 Value::String("not a json".to_string()),
864 CastType::Json,
865 );
866 assert!(matches!(v, Value::String(_)));
868 }
869
870 #[test]
871 fn test_cast_to_json_from_other() {
872 let v = AttributeCaster::cast_read(Value::I64(42), CastType::Json);
873 assert!(matches!(v, Value::Json(_)));
874 if let Value::Json(s) = v {
875 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
877 assert_eq!(parsed, serde_json::Value::Number(42.into()));
878 }
879 }
880
881 #[test]
884 fn test_cast_to_datetime_from_string() {
885 let v = AttributeCaster::cast_read(
886 Value::String("2026-07-19T10:00:00Z".to_string()),
887 CastType::DateTime,
888 );
889 assert_eq!(v, Value::DateTime("2026-07-19T10:00:00Z".to_string()));
890 }
891
892 #[test]
893 fn test_cast_to_date_from_string() {
894 let v = AttributeCaster::cast_read(Value::String("2026-07-19".to_string()), CastType::Date);
895 assert_eq!(v, Value::Date("2026-07-19".to_string()));
896 }
897
898 #[test]
899 fn test_cast_to_time_from_string() {
900 let v = AttributeCaster::cast_read(Value::String("10:30:00".to_string()), CastType::Time);
901 assert_eq!(v, Value::Time("10:30:00".to_string()));
902 }
903
904 #[test]
907 fn test_cast_to_bytes_from_string() {
908 let v = AttributeCaster::cast_read(Value::String("hello".to_string()), CastType::Bytes);
909 assert_eq!(v, Value::Bytes(b"hello".to_vec()));
910 }
911
912 #[test]
913 fn test_cast_to_bytes_preserves_bytes() {
914 let v = AttributeCaster::cast_read(Value::Bytes(b"data".to_vec()), CastType::Bytes);
915 assert_eq!(v, Value::Bytes(b"data".to_vec()));
916 }
917
918 #[test]
921 fn test_cast_to_array_from_string() {
922 let v = AttributeCaster::cast_read(Value::String("item".to_string()), CastType::Array);
923 assert!(matches!(v, Value::Array(_)));
924 if let Value::Array(arr) = v {
925 assert_eq!(arr.len(), 1);
926 }
927 }
928
929 #[test]
930 fn test_cast_to_array_from_json_string() {
931 let v = AttributeCaster::cast_read(
933 Value::String("[1, 2, 3]".to_string()),
934 CastType::Array,
935 );
936 assert!(matches!(v, Value::Array(_)));
937 if let Value::Array(arr) = v {
938 assert_eq!(arr.len(), 3);
939 assert_eq!(arr[0], Value::I64(1));
940 assert_eq!(arr[1], Value::I64(2));
941 assert_eq!(arr[2], Value::I64(3));
942 }
943 }
944
945 #[test]
946 fn test_cast_to_array_from_json_value() {
947 let v = AttributeCaster::cast_read(
949 Value::Json(r#"["a", "b"]"#.to_string()),
950 CastType::Array,
951 );
952 assert!(matches!(v, Value::Array(_)));
953 if let Value::Array(arr) = v {
954 assert_eq!(arr.len(), 2);
955 assert_eq!(arr[0], Value::String("a".to_string()));
956 assert_eq!(arr[1], Value::String("b".to_string()));
957 }
958 }
959
960 #[test]
961 fn test_cast_to_array_preserves_array() {
962 let arr = vec![Value::I64(1), Value::I64(2)];
963 let v = AttributeCaster::cast_read(Value::Array(arr.clone()), CastType::Array);
964 assert_eq!(v, Value::Array(arr));
965 }
966
967 #[test]
968 fn test_cast_to_array_storage_serializes_to_json() {
969 let v = AttributeCaster::cast_write(
970 Value::Array(vec![Value::I64(1), Value::I64(2)]),
971 CastType::Array,
972 );
973 assert!(matches!(v, Value::Json(_)));
974 if let Value::Json(s) = v {
975 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
977 assert!(parsed.is_array());
978 assert_eq!(parsed[0], serde_json::Value::Number(1.into()));
979 assert_eq!(parsed[1], serde_json::Value::Number(2.into()));
980 }
981 }
982
983 #[test]
984 fn test_cast_to_array_storage_not_debug_format() {
985 let v = AttributeCaster::cast_write(
987 Value::Array(vec![Value::I64(1), Value::I64(2)]),
988 CastType::Array,
989 );
990 if let Value::Json(s) = v {
991 assert!(!s.contains("I64"), "JSON 不应包含 Debug 格式 I64: {}", s);
993 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
995 assert!(parsed.is_array());
996 }
997 }
998
999 #[test]
1000 fn test_cast_to_json_storage_from_other() {
1001 let v = AttributeCaster::cast_write(Value::I64(42), CastType::Json);
1002 assert!(matches!(v, Value::Json(_)));
1003 if let Value::Json(s) = v {
1004 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
1006 assert_eq!(parsed, serde_json::Value::Number(42.into()));
1007 }
1008 }
1009
1010 #[test]
1013 fn test_closure_accessor() {
1014 let accessor = ClosureAccessor::new("name", |v| match v {
1015 Value::String(s) => Value::String(s.to_uppercase()),
1016 other => other,
1017 });
1018 let v = accessor.read(Value::String("alice".to_string()));
1019 assert_eq!(v, Value::String("ALICE".to_string()));
1020 assert_eq!(accessor.field(), "name");
1021 }
1022
1023 #[test]
1024 fn test_closure_mutator() {
1025 let mutator = ClosureMutator::new("email", |v| match v {
1026 Value::String(s) => Value::String(s.to_lowercase()),
1027 other => other,
1028 });
1029 let v = mutator.write(Value::String("ALICE@EXAMPLE.COM".to_string()));
1030 assert_eq!(v, Value::String("alice@example.com".to_string()));
1031 assert_eq!(mutator.field(), "email");
1032 }
1033
1034 #[test]
1037 fn test_registry_empty() {
1038 let r = AccessorRegistry::new();
1039 assert_eq!(r.accessor_count(), 0);
1040 assert_eq!(r.mutator_count(), 0);
1041 assert_eq!(r.cast_count(), 0);
1042 }
1043
1044 #[test]
1045 fn test_registry_register_cast() {
1046 let mut r = AccessorRegistry::new();
1047 r.register_cast("is_admin", CastType::Boolean);
1048 assert!(r.has_cast("is_admin"));
1049 assert_eq!(r.get_cast("is_admin"), Some(CastType::Boolean));
1050 assert_eq!(r.cast_count(), 1);
1051 }
1052
1053 #[test]
1054 fn test_registry_register_accessor() {
1055 let mut r = AccessorRegistry::new();
1056 r.register_accessor(Box::new(ClosureAccessor::new("name", |v| match v {
1057 Value::String(s) => Value::String(s.to_uppercase()),
1058 other => other,
1059 })));
1060 assert!(r.has_accessor("name"));
1061 assert_eq!(r.accessor_count(), 1);
1062 }
1063
1064 #[test]
1065 fn test_registry_register_mutator() {
1066 let mut r = AccessorRegistry::new();
1067 r.register_mutator(Box::new(ClosureMutator::new("email", |v| match v {
1068 Value::String(s) => Value::String(s.to_lowercase()),
1069 other => other,
1070 })));
1071 assert!(r.has_mutator("email"));
1072 assert_eq!(r.mutator_count(), 1);
1073 }
1074
1075 #[test]
1078 fn test_registry_read_applies_cast_then_accessor() {
1079 let mut r = AccessorRegistry::new();
1080 r.register_cast("is_admin", CastType::Boolean);
1081 r.register_accessor(Box::new(ClosureAccessor::new("is_admin", |v| {
1082 if v == Value::Bool(true) {
1083 Value::String("管理员".to_string())
1084 } else {
1085 Value::String("普通用户".to_string())
1086 }
1087 })));
1088
1089 let v = r.read("is_admin", Value::I64(1));
1091 assert_eq!(v, Value::String("管理员".to_string()));
1092 }
1093
1094 #[test]
1095 fn test_registry_write_applies_mutator_then_cast() {
1096 let mut r = AccessorRegistry::new();
1097 r.register_cast("is_admin", CastType::Boolean);
1098 r.register_mutator(Box::new(ClosureMutator::new("is_admin", |v| match v {
1099 Value::String(s) => {
1100 let lower = s.to_lowercase();
1101 Value::Bool(lower == "admin" || lower == "true")
1102 }
1103 other => other,
1104 })));
1105
1106 let v = r.write("is_admin", Value::String("admin".to_string()));
1108 assert_eq!(v, Value::I64(1));
1109 }
1110
1111 #[test]
1112 fn test_registry_read_without_cast_or_accessor() {
1113 let r = AccessorRegistry::new();
1114 let v = r.read("any_field", Value::I64(42));
1115 assert_eq!(v, Value::I64(42));
1116 }
1117
1118 #[test]
1119 fn test_registry_write_without_cast_or_mutator() {
1120 let r = AccessorRegistry::new();
1121 let v = r.write("any_field", Value::I64(42));
1122 assert_eq!(v, Value::I64(42));
1123 }
1124
1125 #[test]
1126 fn test_registry_cast_read_only() {
1127 let mut r = AccessorRegistry::new();
1128 r.register_cast("is_admin", CastType::Boolean);
1129
1130 let v = r.cast_read("is_admin", Value::I64(1));
1131 assert_eq!(v, Value::Bool(true));
1132 }
1133
1134 #[test]
1135 fn test_registry_cast_write_only() {
1136 let mut r = AccessorRegistry::new();
1137 r.register_cast("is_admin", CastType::Boolean);
1138
1139 let v = r.cast_write("is_admin", Value::Bool(true));
1140 assert_eq!(v, Value::I64(1));
1141 }
1142
1143 #[test]
1146 fn test_complex_user_model_scenario() {
1147 let mut r = AccessorRegistry::new();
1148
1149 r.register_cast("is_admin", CastType::Boolean);
1151
1152 r.register_mutator(Box::new(ClosureMutator::new("email", |v| match v {
1154 Value::String(s) => Value::String(s.to_lowercase()),
1155 other => other,
1156 })));
1157
1158 r.register_accessor(Box::new(ClosureAccessor::new(
1160 "full_name",
1161 |v| v, )));
1163
1164 r.register_cast("settings", CastType::Json);
1166
1167 r.register_cast("created_at", CastType::DateTime);
1169
1170 let v = r.read("is_admin", Value::I64(1));
1172 assert_eq!(v, Value::Bool(true));
1173
1174 let v = r.write("email", Value::String("Alice@Example.COM".to_string()));
1176 assert_eq!(v, Value::String("alice@example.com".to_string()));
1177
1178 let v = r.read("settings", Value::String(r#"{"theme":"dark"}"#.to_string()));
1180 assert!(matches!(v, Value::Json(_)));
1181
1182 assert_eq!(r.accessor_count(), 1);
1183 assert_eq!(r.mutator_count(), 1);
1184 assert_eq!(r.cast_count(), 3);
1185 }
1186
1187 #[test]
1190 fn test_default_is_empty() {
1191 let r = AccessorRegistry::default();
1192 assert_eq!(r.accessor_count(), 0);
1193 assert_eq!(r.mutator_count(), 0);
1194 assert_eq!(r.cast_count(), 0);
1195 }
1196}