use serde_json::Value;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct SerializerMethodField {
pub method_name: String,
pub custom_method_name: Option<String>,
pub read_only: bool,
}
impl SerializerMethodField {
pub fn new(method_name: impl Into<String>) -> Self {
Self {
method_name: method_name.into(),
custom_method_name: None,
read_only: true,
}
}
pub fn method_name(mut self, name: impl Into<String>) -> Self {
self.custom_method_name = Some(name.into());
self
}
pub fn get_value(&self, context: &HashMap<String, Value>) -> Result<Value, MethodFieldError> {
let lookup_name = self
.custom_method_name
.as_ref()
.unwrap_or(&self.method_name);
context
.get(lookup_name)
.cloned()
.ok_or_else(|| MethodFieldError::MethodNotFound(lookup_name.clone()))
}
pub fn get_method_name(&self) -> &str {
self.custom_method_name
.as_ref()
.unwrap_or(&self.method_name)
}
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum MethodFieldError {
#[error("Method '{0}' not found in serializer context")]
MethodNotFound(String),
#[error("Error computing method value: {0}")]
ComputationError(String),
}
pub trait MethodFieldProvider {
fn compute_method_fields(&self, instance: &Value) -> HashMap<String, Value>;
fn compute_method(&self, method_name: &str, instance: &Value) -> Option<Value>;
}
#[derive(Debug, Clone)]
pub struct MethodFieldRegistry {
fields: HashMap<String, SerializerMethodField>,
}
impl MethodFieldRegistry {
pub fn new() -> Self {
Self {
fields: HashMap::new(),
}
}
pub fn register(&mut self, name: impl Into<String>, field: SerializerMethodField) {
self.fields.insert(name.into(), field);
}
pub fn get(&self, name: &str) -> Option<&SerializerMethodField> {
self.fields.get(name)
}
pub fn all(&self) -> &HashMap<String, SerializerMethodField> {
&self.fields
}
pub fn contains(&self, name: &str) -> bool {
self.fields.contains_key(name)
}
}
impl Default for MethodFieldRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_serializer_method_field_new() {
let field = SerializerMethodField::new("get_full_name");
assert_eq!(field.method_name, "get_full_name");
assert!(field.custom_method_name.is_none());
assert!(field.read_only);
}
#[test]
fn test_serializer_method_field_custom_method_name() {
let field = SerializerMethodField::new("full_name").method_name("compute_full_name");
assert_eq!(field.method_name, "full_name");
assert_eq!(
field.custom_method_name,
Some("compute_full_name".to_string())
);
assert_eq!(field.get_method_name(), "compute_full_name");
}
#[test]
fn test_get_value_success() {
let mut context = HashMap::new();
context.insert("full_name".to_string(), json!("John Doe"));
let field = SerializerMethodField::new("full_name");
let value = field.get_value(&context).unwrap();
assert_eq!(value, json!("John Doe"));
}
#[test]
fn test_get_value_with_custom_method() {
let mut context = HashMap::new();
context.insert("compute_name".to_string(), json!("Jane Smith"));
let field = SerializerMethodField::new("full_name").method_name("compute_name");
let value = field.get_value(&context).unwrap();
assert_eq!(value, json!("Jane Smith"));
}
#[test]
fn test_get_value_method_not_found() {
let context = HashMap::new();
let field = SerializerMethodField::new("missing_method");
let result = field.get_value(&context);
assert!(result.is_err());
if let Err(MethodFieldError::MethodNotFound(name)) = result {
assert_eq!(name, "missing_method");
} else {
panic!("Expected MethodNotFound error");
}
}
#[test]
fn test_method_field_registry() {
let mut registry = MethodFieldRegistry::new();
let field1 = SerializerMethodField::new("full_name");
let field2 = SerializerMethodField::new("email");
registry.register("full_name", field1);
registry.register("email", field2);
assert!(registry.contains("full_name"));
assert!(registry.contains("email"));
assert!(!registry.contains("nonexistent"));
let retrieved = registry.get("full_name").unwrap();
assert_eq!(retrieved.method_name, "full_name");
}
#[test]
fn test_method_field_with_complex_value() {
let mut context = HashMap::new();
context.insert(
"user_stats".to_string(),
json!({
"post_count": 42,
"follower_count": 128,
"engagement_rate": 0.15
}),
);
let field = SerializerMethodField::new("user_stats");
let value = field.get_value(&context).unwrap();
assert_eq!(value["post_count"], 42);
assert_eq!(value["follower_count"], 128);
}
}