Skip to main content

mf_collab_client/
mapping.rs

1/// 静态分发 StepConverter 实现
2/// 使用静态分发替代动态分发,提供更好的性能和类型安全性
3use yrs::{Transact, ReadTxn, Map};
4
5// 重新导出所有核心组件
6pub use crate::mapping_v2::{
7    // 核心 traits 和类型
8    TypedStepConverter,
9    ConversionContext,
10    ErasedConverter,
11
12    // 注册表和全局函数
13    StaticConverterRegistry,
14    global_registry,
15    convert_step_global as convert_step,
16    register_global_converter,
17    get_global_performance_stats,
18    PerformanceStats,
19    TypeConversionStats,
20
21    // 错误处理
22    ConversionError,
23    ConversionResult,
24
25    // 转换器实现
26    SimpleNodeAddConverter,
27    SimpleNodeRemoveConverter,
28    SimpleAttrConverter,
29    SimpleMarkAddConverter,
30    SimpleMarkRemoveConverter,
31};
32
33/// 便捷函数:批量转换步骤
34pub fn convert_steps_batch(
35    steps: &[&dyn mf_transform::step::Step],
36    txn: &mut yrs::TransactionMut,
37    context: &ConversionContext,
38) -> Vec<ConversionResult<crate::types::StepResult>> {
39    match global_registry().read() {
40        Ok(registry) => registry.convert_steps_batch(steps, txn, context),
41        Err(e) => {
42            // 如果锁获取失败,返回所有步骤的错误结果
43            tracing::error!("无法获取全局注册表读锁进行批量转换: {}", e);
44            steps
45                .iter()
46                .map(|_| {
47                    Err(ConversionError::Custom {
48                        message: format!("全局注册表锁获取失败: {e}"),
49                    })
50                })
51                .collect()
52        },
53    }
54}
55
56/// 便捷函数:创建转换上下文
57pub fn create_context(
58    client_id: String,
59    user_id: String,
60) -> ConversionContext {
61    ConversionContext::new(client_id, user_id)
62}
63
64/// 便捷函数:注册转换器
65pub fn register_converter<T, C>()
66where
67    T: mf_transform::step::Step + 'static,
68    C: TypedStepConverter<T> + Default + 'static,
69{
70    register_global_converter::<T, C>();
71}
72
73/// 映射器工具类
74#[derive(Debug)]
75pub struct Mapper;
76
77impl Mapper {
78    /// 获取全局注册表
79    pub fn global_registry()
80    -> &'static std::sync::RwLock<StaticConverterRegistry> {
81        global_registry()
82    }
83
84    /// 获取 Yrs 文档的版本信息
85    pub fn get_yrs_doc_version(doc: &yrs::Doc) -> u64 {
86        let txn = doc.transact();
87        txn.state_vector().len() as u64
88    }
89
90    /// 检查 Yrs 文档是否为空
91    pub fn is_yrs_doc_empty(doc: &yrs::Doc) -> bool {
92        let txn = doc.transact();
93        let nodes_map = txn.get_map("nodes");
94        nodes_map.is_none_or(|map| map.len(&txn) == 0)
95    }
96
97    /// 获取性能统计信息
98    pub fn get_performance_stats() -> String {
99        match global_registry().read() {
100            Ok(registry) => {
101                let stats = registry.get_performance_stats();
102                format!(
103                    "性能统计:\n\
104                     - 总转换次数: {}\n\
105                     - 成功率: {:.2}%\n\
106                     - 运行时间: {:?}",
107                    stats.get_total_conversions(),
108                    stats.get_success_rate() * 100.0,
109                    stats.get_uptime()
110                )
111            },
112            Err(e) => {
113                tracing::error!("无法获取全局注册表读锁以获取性能统计: {}", e);
114                format!("性能统计: 无法获取(锁错误: {e})")
115            },
116        }
117    }
118
119    /// 获取注册的转换器数量
120    pub fn converter_count() -> usize {
121        match global_registry().read() {
122            Ok(registry) => registry.converter_count(),
123            Err(e) => {
124                tracing::error!(
125                    "无法获取全局注册表读锁以获取转换器数量: {}",
126                    e
127                );
128                0 // 返回 0 作为失败时的默认值
129            },
130        }
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137    use mf_transform::attr_step::AttrStep;
138    use std::time::Instant;
139    use rpds::HashTrieMapSync;
140
141    #[test]
142    fn test_api_simplicity() {
143        let context =
144            create_context("test_client".to_string(), "test_user".to_string());
145
146        assert_eq!(context.client_id, "test_client");
147        assert_eq!(context.user_id, "test_user");
148    }
149
150    #[test]
151    fn test_registry_access() {
152        let registry = Mapper::global_registry();
153        assert!(registry.read().is_ok());
154    }
155
156    #[tokio::test]
157    async fn test_performance_tracking() {
158        let start = Instant::now();
159
160        let doc = yrs::Doc::new();
161        let mut txn = doc.transact_mut();
162
163        let context =
164            create_context("perf_client".to_string(), "perf_user".to_string());
165
166        let mut attrs = HashTrieMapSync::new_sync();
167        attrs.insert("test_attr".to_string(), serde_json::json!("test_value"));
168
169        let step = AttrStep { id: "test_node".into(), values: attrs };
170
171        let result = convert_step(&step, &mut txn, &context);
172        let duration = start.elapsed();
173
174        println!("静态分发转换耗时: {duration:?}");
175
176        // 验证结果格式
177        match result {
178            Ok(step_result) => {
179                assert_eq!(step_result.step_name, "attr_step");
180                assert!(!step_result.step_id.is_empty());
181            },
182            Err(e) => {
183                println!("转换失败(测试环境预期): {e}");
184            },
185        }
186    }
187
188    #[test]
189    fn test_performance_stats() {
190        let stats_str = Mapper::get_performance_stats();
191        assert!(!stats_str.is_empty());
192        assert!(stats_str.contains("性能统计"));
193        println!("{stats_str}");
194    }
195}