1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::io::Write;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::TemplateSpec;
use crate::engine::IThrottledTemplateWriterControl;
use crate::exceptions::TemplateEngineException;
use crate::util::{Charset, TemplateWriter, Utf16String};
/// 节流模板处理调用的统一错误结果。
///
/// Java API 通过 `TemplateOutputException`、`TemplateProcessingException` 等运行时
/// 异常保留具体子类型;Rust 使用公共 `TemplateEngineException` trait object 保持
/// 同样的动态错误分类。
pub type ThrottledTemplateResult<T> =
Result<T, Box<dyn TemplateEngineException + Send + Sync + 'static>>;
/// 节流处理器完成状态的线程安全观察句柄。
///
/// Java 允许在处理线程之外并发调用
/// `IThrottledTemplateProcessor#isFinished()`。Rust 的事件处理链保持线程亲和,因此
/// 通过可克隆句柄提供同一可观察能力:处理器仍由单线程非交错驱动,任意观察线程可
/// 无锁检查完成状态。
///
/// 对应 Java: `IThrottledTemplateProcessor#isFinished()` 的跨线程观察能力。
#[derive(Clone, Debug)]
pub struct ThrottledTemplateStatus {
finished: Arc<AtomicBool>,
}
impl ThrottledTemplateStatus {
/// 从处理器共享的完成标志创建观察句柄。
#[must_use]
/// 对应 Java 语义:`IThrottledTemplateProcessor` 的 `new` 行为(Rust 侧辅助/私有路径)。
pub(crate) fn new(finished: Arc<AtomicBool>) -> Self {
Self { finished }
}
/// 判断模板处理是否已经全部完成。
///
/// 返回 `true` 时,创建该句柄的处理器已经完成全部事件、待处理工作和溢出输出。
/// Acquire 读取与处理器的 Release 写入配对,保证此前结果对观察线程可见。
#[must_use]
/// 对应 Java: `IThrottledTemplateProcessor#isFinished()`。
pub fn is_finished(&self) -> bool {
self.finished.load(Ordering::Acquire)
}
}
/// 调节模板引擎输出速率的处理器合同。
///
/// 调用方为每次执行提供能够接收的最大字符数或字节数,从而对模板执行施加背压。
/// 同一处理器的 `process` 调用不得并发,但 `is_finished` 必须支持跨线程可见性。
///
/// 对应 Java: `org.thymeleaf.IThrottledTemplateProcessor`。
pub trait IThrottledTemplateProcessor {
/// 返回与当前处理器共享同一 Writer 状态的控制器。
///
/// 数据驱动迭代器使用该控制器观察溢出状态,并在 SSE 模式下标记事件边界。
/// 对应 Java: `ThrottledTemplateProcessor#getThrottledTemplateWriterControl()`。
fn get_throttled_template_writer_control(
&self,
) -> Box<dyn IThrottledTemplateWriterControl + Send>;
/// 返回用于跨线程追踪处理器执行的稳定标识。
///
/// 不要求构造级绝对唯一,但必须足以区分日志中的不同处理器执行。
/// 对应 Java: `IThrottledTemplateProcessor#getProcessorIdentifier()`。
fn get_processor_identifier(&self) -> &Utf16String;
/// 返回本处理器正在执行的模板规格。
///
/// 对应 Java: `IThrottledTemplateProcessor#getTemplateSpec()`。
fn get_template_spec(&self) -> &TemplateSpec;
/// 判断全部模板事件、待处理器工作和 Writer 溢出是否已经完成。
///
/// 该观察允许与非并发的处理调用来自不同线程,实现必须保证完成状态的跨线程
/// 可见性。返回 `true` 后继续处理必须返回零且不得重复输出。
/// 对应 Java: `IThrottledTemplateProcessor#isFinished()`。
fn is_finished(&self) -> bool;
/// 返回可由其他线程并发观察的完成状态句柄。
///
/// Rust 的处理器内部事件链保持线程亲和;调用方在开始处理前取得此句柄,即可
/// 保留 Java `isFinished()` 的并发短路检查能力,而不允许并发执行 `process`。
fn get_completion_status(&self) -> ThrottledTemplateStatus;
/// 不限制字符数,处理全部剩余模板并返回本次写出的 UTF-16 代码单元数。
///
/// `writer` 接收输出并在本次调用结束时刷新;输出或模板处理失败时返回保留具体
/// 子类型的引擎错误。对应 Java: `IThrottledTemplateProcessor#processAll(Writer)`。
fn process_all_writer(
&mut self,
writer: Box<dyn TemplateWriter>,
) -> ThrottledTemplateResult<i32>;
/// 不限制字节数,按指定字符集处理全部剩余模板并返回写出字节数。
///
/// `output_stream` 接收编码后的字节,`charset` 决定编码;输出或模板处理失败时
/// 返回保留具体子类型的引擎错误。
/// 对应 Java: `IThrottledTemplateProcessor#processAll(OutputStream, Charset)`。
fn process_all_output_stream(
&mut self,
output_stream: Box<dyn Write + Send>,
charset: &Charset,
) -> ThrottledTemplateResult<i32>;
/// 最多写出 `max_output_in_chars` 个 UTF-16 代码单元。
///
/// 负数或 `i32::MAX` 表示不设上限;零表示本次不推进。
/// 返回本次实际写出的 UTF-16 代码单元数。
/// 对应 Java: `IThrottledTemplateProcessor#process(int, Writer)`。
fn process_writer(
&mut self,
max_output_in_chars: i32,
writer: Box<dyn TemplateWriter>,
) -> ThrottledTemplateResult<i32>;
/// 最多按指定字符集写出 `max_output_in_bytes` 个字节。
///
/// 负数或 `i32::MAX` 表示不设上限;零表示本次不推进。
/// 返回本次实际写出的字节数;同一处理器不能在字符输出与字节输出之间切换。
/// 对应 Java: `IThrottledTemplateProcessor#process(int, OutputStream, Charset)`。
fn process_output_stream(
&mut self,
max_output_in_bytes: i32,
output_stream: Box<dyn Write + Send>,
charset: &Charset,
) -> ThrottledTemplateResult<i32>;
}