use once_cell::sync::Lazy;
use proc_macro2::TokenStream as TokenStream2;
use std::sync::{Arc, RwLock};
use syn::{Field, Type};
use crate::common::{MacroError, MacroResult};
use super::{
type_converter::TypeConverter,
builtin_converters::{get_all_builtin_converters},
};
static GLOBAL_REGISTRY: Lazy<Arc<RwLock<ConverterRegistryImpl>>> =
Lazy::new(|| {
let registry = ConverterRegistryImpl::new();
Arc::new(RwLock::new(registry))
});
pub trait ConverterRegistry {
fn register_converter(
&mut self,
converter: Box<dyn TypeConverter>,
);
fn find_converter_for_type(
&self,
field_type: &Type,
) -> Option<&dyn TypeConverter>;
fn convert_field(
&self,
field: &Field,
) -> MacroResult<TokenStream2>;
fn converter_count(&self) -> usize;
fn clear_converters(&mut self);
fn reload_default_converters(&mut self);
}
pub struct ConverterRegistryImpl {
converters: Vec<Box<dyn TypeConverter>>,
}
impl ConverterRegistryImpl {
pub fn new() -> Self {
let mut registry = Self { converters: Vec::new() };
registry.load_builtin_converters();
registry
}
fn load_builtin_converters(&mut self) {
let builtin_converters = get_all_builtin_converters();
for converter in builtin_converters {
self.register_converter_internal(converter);
}
}
fn register_converter_internal(
&mut self,
converter: Box<dyn TypeConverter>,
) {
let priority = converter.priority();
let insert_pos = self
.converters
.iter()
.position(|c| c.priority() < priority)
.unwrap_or(self.converters.len());
self.converters.insert(insert_pos, converter);
}
}
impl Default for ConverterRegistryImpl {
fn default() -> Self {
Self::new()
}
}
impl ConverterRegistry for ConverterRegistryImpl {
fn register_converter(
&mut self,
converter: Box<dyn TypeConverter>,
) {
self.register_converter_internal(converter);
}
fn find_converter_for_type(
&self,
field_type: &Type,
) -> Option<&dyn TypeConverter> {
self.converters
.iter()
.find(|converter| converter.supports_type(field_type))
.map(|boxed| boxed.as_ref())
}
fn convert_field(
&self,
field: &Field,
) -> MacroResult<TokenStream2> {
if let Some(converter) = self.find_converter_for_type(&field.ty) {
converter.convert_field_to_json_value(field)
} else {
let type_name = crate::common::utils::extract_type_name(&field.ty);
let field_name = field
.ident
.as_ref()
.map(|i| i.to_string())
.unwrap_or_else(|| "匿名字段".to_string());
Err(MacroError::unsupported_field_type(
&field_name,
&type_name,
field,
))
}
}
fn converter_count(&self) -> usize {
self.converters.len()
}
fn clear_converters(&mut self) {
self.converters.clear();
}
fn reload_default_converters(&mut self) {
self.clear_converters();
self.load_builtin_converters();
}
}
pub struct GlobalConverterRegistry;
impl GlobalConverterRegistry {
pub fn register(converter: Box<dyn TypeConverter>) -> Result<(), String> {
match GLOBAL_REGISTRY.write() {
Ok(mut registry) => {
registry.register_converter(converter);
Ok(())
},
Err(e) => Err(format!("无法获取注册表写锁: {e}")),
}
}
pub fn convert_field(field: &Field) -> MacroResult<TokenStream2> {
match GLOBAL_REGISTRY.read() {
Ok(registry) => registry.convert_field(field),
Err(e) => Err(MacroError::GenerationError {
message: format!("无法获取注册表读锁: {e}"),
span: None,
}),
}
}
pub fn converter_count() -> Result<usize, String> {
match GLOBAL_REGISTRY.read() {
Ok(registry) => Ok(registry.converter_count()),
Err(e) => Err(format!("无法获取注册表读锁: {e}")),
}
}
pub fn clear_all() -> Result<(), String> {
match GLOBAL_REGISTRY.write() {
Ok(mut registry) => {
registry.clear_converters();
Ok(())
},
Err(e) => Err(format!("无法获取注册表写锁: {e}")),
}
}
pub fn reload_defaults() -> Result<(), String> {
match GLOBAL_REGISTRY.write() {
Ok(mut registry) => {
registry.reload_default_converters();
Ok(())
},
Err(e) => Err(format!("无法获取注册表写锁: {e}")),
}
}
pub fn supports_type(field_type: &Type) -> Result<bool, String> {
match GLOBAL_REGISTRY.read() {
Ok(registry) => {
Ok(registry.find_converter_for_type(field_type).is_some())
},
Err(e) => Err(format!("无法获取注册表读锁: {e}")),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use syn::parse_quote;
use crate::converter::{
type_converter::BuiltinTypeConverter,
builtin_converters::{StringConverter, NumericConverter},
};
#[test]
fn test_registry_creation() {
let registry = ConverterRegistryImpl::new();
assert!(registry.converter_count() > 0);
let string_type: Type = parse_quote! { String };
assert!(registry.find_converter_for_type(&string_type).is_some());
let i32_type: Type = parse_quote! { i32 };
assert!(registry.find_converter_for_type(&i32_type).is_some());
}
#[test]
fn test_converter_registration() {
let mut registry = ConverterRegistryImpl::new();
let initial_count = registry.converter_count();
let custom_converter = Box::new(BuiltinTypeConverter::new());
registry.register_converter(custom_converter);
assert_eq!(registry.converter_count(), initial_count + 1);
}
#[test]
fn test_converter_priority_ordering() {
let mut registry = ConverterRegistryImpl::new();
registry.clear_converters();
registry.register_converter(Box::new(StringConverter::new())); registry.register_converter(Box::new(NumericConverter::new()));
let i32_type: Type = parse_quote! { i32 };
let converter = registry.find_converter_for_type(&i32_type).unwrap();
assert_eq!(converter.name(), "NumericConverter");
}
#[test]
fn test_field_conversion() {
let registry = ConverterRegistryImpl::new();
let string_field: syn::Field = parse_quote! {
name: String
};
let result = registry.convert_field(&string_field);
assert!(result.is_ok());
let code = result.unwrap();
let code_str = code.to_string();
assert!(code_str.contains("serde_json::to_value"));
assert!(code_str.contains("name"));
}
#[test]
fn test_unsupported_type_error() {
let registry = ConverterRegistryImpl::new();
let unsupported_field: syn::Field = parse_quote! {
data: std::collections::BTreeMap<String, i32>
};
let result = registry.convert_field(&unsupported_field);
assert!(result.is_err());
if let Err(MacroError::UnsupportedFieldType { field_name, .. }) = result
{
assert_eq!(field_name, "data");
} else {
panic!("期望 UnsupportedFieldType 错误");
}
}
#[test]
fn test_clear_and_reload() {
let mut registry = ConverterRegistryImpl::new();
let initial_count = registry.converter_count();
registry.clear_converters();
assert_eq!(registry.converter_count(), 0);
registry.reload_default_converters();
assert_eq!(registry.converter_count(), initial_count);
}
#[test]
fn test_global_registry() {
let initial_count = GlobalConverterRegistry::converter_count().unwrap();
let custom_converter = Box::new(BuiltinTypeConverter::new());
let result = GlobalConverterRegistry::register(custom_converter);
assert!(result.is_ok());
let new_count = GlobalConverterRegistry::converter_count().unwrap();
assert_eq!(new_count, initial_count + 1);
let field: syn::Field = parse_quote! {
test: String
};
let conversion_result = GlobalConverterRegistry::convert_field(&field);
assert!(conversion_result.is_ok());
GlobalConverterRegistry::reload_defaults().unwrap();
}
#[test]
fn test_type_support_checking() {
let string_type: Type = parse_quote! { String };
let supports_string =
GlobalConverterRegistry::supports_type(&string_type).unwrap();
assert!(supports_string);
let i32_type: Type = parse_quote! { i32 };
let supports_i32 =
GlobalConverterRegistry::supports_type(&i32_type).unwrap();
assert!(supports_i32);
let unsupported_type: Type =
parse_quote! { std::collections::BTreeSet<String> };
let supports_unsupported =
GlobalConverterRegistry::supports_type(&unsupported_type).unwrap();
assert!(!supports_unsupported);
}
#[test]
fn test_registry_default() {
let registry = ConverterRegistryImpl::default();
assert!(registry.converter_count() > 0);
}
#[test]
fn test_converter_finding_accuracy() {
let registry = ConverterRegistryImpl::new();
let test_cases = vec![
(parse_quote! { String }, "StringConverter"),
(parse_quote! { i32 }, "NumericConverter"),
(parse_quote! { bool }, "BooleanConverter"),
];
for (ty, _expected_name) in test_cases {
if let Some(converter) = registry.find_converter_for_type(&ty) {
assert!(
converter.supports_type(&ty),
"找到的转换器应该支持该类型"
);
} else {
panic!("应该能找到支持 {ty:?} 的转换器");
}
}
}
}