use yrs::{Transact, ReadTxn, Map};
pub use crate::mapping_v2::{
TypedStepConverter,
ConversionContext,
ErasedConverter,
StaticConverterRegistry,
global_registry,
convert_step_global as convert_step,
register_global_converter,
get_global_performance_stats,
PerformanceStats,
TypeConversionStats,
ConversionError,
ConversionResult,
SimpleNodeAddConverter,
SimpleNodeRemoveConverter,
SimpleAttrConverter,
SimpleMarkAddConverter,
SimpleMarkRemoveConverter,
};
pub fn convert_steps_batch(
steps: &[&dyn mf_transform::step::Step],
txn: &mut yrs::TransactionMut,
context: &ConversionContext,
) -> Vec<ConversionResult<crate::types::StepResult>> {
match global_registry().read() {
Ok(registry) => registry.convert_steps_batch(steps, txn, context),
Err(e) => {
tracing::error!("无法获取全局注册表读锁进行批量转换: {}", e);
steps
.iter()
.map(|_| {
Err(ConversionError::Custom {
message: format!("全局注册表锁获取失败: {e}"),
})
})
.collect()
},
}
}
pub fn create_context(
client_id: String,
user_id: String,
) -> ConversionContext {
ConversionContext::new(client_id, user_id)
}
pub fn register_converter<T, C>()
where
T: mf_transform::step::Step + 'static,
C: TypedStepConverter<T> + Default + 'static,
{
register_global_converter::<T, C>();
}
#[derive(Debug)]
pub struct Mapper;
impl Mapper {
pub fn global_registry()
-> &'static std::sync::RwLock<StaticConverterRegistry> {
global_registry()
}
pub fn get_yrs_doc_version(doc: &yrs::Doc) -> u64 {
let txn = doc.transact();
txn.state_vector().len() as u64
}
pub fn is_yrs_doc_empty(doc: &yrs::Doc) -> bool {
let txn = doc.transact();
let nodes_map = txn.get_map("nodes");
nodes_map.is_none_or(|map| map.len(&txn) == 0)
}
pub fn get_performance_stats() -> String {
match global_registry().read() {
Ok(registry) => {
let stats = registry.get_performance_stats();
format!(
"性能统计:\n\
- 总转换次数: {}\n\
- 成功率: {:.2}%\n\
- 运行时间: {:?}",
stats.get_total_conversions(),
stats.get_success_rate() * 100.0,
stats.get_uptime()
)
},
Err(e) => {
tracing::error!("无法获取全局注册表读锁以获取性能统计: {}", e);
format!("性能统计: 无法获取(锁错误: {e})")
},
}
}
pub fn converter_count() -> usize {
match global_registry().read() {
Ok(registry) => registry.converter_count(),
Err(e) => {
tracing::error!(
"无法获取全局注册表读锁以获取转换器数量: {}",
e
);
0 },
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use mf_transform::attr_step::AttrStep;
use std::time::Instant;
use rpds::HashTrieMapSync;
#[test]
fn test_api_simplicity() {
let context =
create_context("test_client".to_string(), "test_user".to_string());
assert_eq!(context.client_id, "test_client");
assert_eq!(context.user_id, "test_user");
}
#[test]
fn test_registry_access() {
let registry = Mapper::global_registry();
assert!(registry.read().is_ok());
}
#[tokio::test]
async fn test_performance_tracking() {
let start = Instant::now();
let doc = yrs::Doc::new();
let mut txn = doc.transact_mut();
let context =
create_context("perf_client".to_string(), "perf_user".to_string());
let mut attrs = HashTrieMapSync::new_sync();
attrs.insert("test_attr".to_string(), serde_json::json!("test_value"));
let step = AttrStep { id: "test_node".into(), values: attrs };
let result = convert_step(&step, &mut txn, &context);
let duration = start.elapsed();
println!("静态分发转换耗时: {duration:?}");
match result {
Ok(step_result) => {
assert_eq!(step_result.step_name, "attr_step");
assert!(!step_result.step_id.is_empty());
},
Err(e) => {
println!("转换失败(测试环境预期): {e}");
},
}
}
#[test]
fn test_performance_stats() {
let stats_str = Mapper::get_performance_stats();
assert!(!stats_str.is_empty());
assert!(stats_str.contains("性能统计"));
println!("{stats_str}");
}
}