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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
use std::any::Any;
use std::sync::Arc;
use crate::expression::TemplateValue;
use crate::util::{Locale, Utf16String};
use crate::web::IWebExchange;
/// `IContext#getVariableNames()` 返回的可变 Set 视图合同。
///
/// Java `Map#keySet()` 是由原 Map 支撑的实时视图,移除名称也会删除变量。该
/// Rust 合同保留实时查询与删除能力,同时用快照方法支持安全迭代。
/// 对应 Java 语义:`IContext` 的 Rust 侧类型 `IContextVariableNames`。
pub trait IContextVariableNames: Send + Sync {
/// 返回当前变量名数量。
///
/// # 返回值
///
/// 返回调用瞬间支撑 Context 中的变量数量。
fn len(&self) -> usize;
/// 判断当前名称集合是否为空。
///
/// # 返回值
///
/// 当前没有变量时返回 `true`。
fn is_empty(&self) -> bool {
self.len() == 0
}
/// 判断集合是否包含可空名称。
///
/// # 参数
///
/// - `name`:待查询的可空 Java 变量名。
///
/// # 返回值
///
/// 支撑 Context 包含该名称时返回 `true`,包括显式 null 名称。
fn contains(&self, name: Option<&Utf16String>) -> bool;
/// 返回当前迭代顺序的独立名称快照。
///
/// # 返回值
///
/// 返回保留 Java Set 迭代顺序的独立快照;后续 Context 修改不会改变该 Vec。
fn snapshot(&self) -> Vec<Option<Utf16String>>;
/// 从支撑 Context 删除名称及其变量。
///
/// # 返回
///
/// 名称原先存在时返回 `true`。
fn remove(&self, name: Option<&Utf16String>) -> bool;
/// 判断视图是否包含给定全部名称。
///
/// 对应 Java `Set#containsAll(Collection)`;空输入返回 `true`。
fn contains_all(&self, names: &[Option<Utf16String>]) -> bool {
names.iter().all(|name| self.contains(name.as_ref()))
}
/// 从支撑 Context 删除给定全部名称。
///
/// 对应 Java `Map#keySet().removeAll(Collection)`。
///
/// # 返回值
///
/// 至少删除一个变量时返回 `true`。
fn remove_all(&self, names: &[Option<Utf16String>]) -> bool {
let mut changed = false;
for name in names {
changed |= self.remove(name.as_ref());
}
changed
}
/// 只保留给定名称并删除其余变量。
///
/// 对应 Java `Map#keySet().retainAll(Collection)`。
///
/// # 返回值
///
/// 变量集合发生变化时返回 `true`。
fn retain_all(&self, names: &[Option<Utf16String>]) -> bool {
let mut changed = false;
for current in self.snapshot() {
if !names.contains(¤t) {
changed |= self.remove(current.as_ref());
}
}
changed
}
/// 清空支撑 Context 的全部变量。
///
/// 对应 Java `Map#keySet().clear()`。
fn clear(&self) {
for name in self.snapshot() {
self.remove(name.as_ref());
}
}
}
/// 模板执行所需 Locale 与变量的基础上下文合同。
///
/// 对应 Java: `org.thymeleaf.context.IContext`。
///
/// Context 刻意不继承 Map,表达式访问必须经过引擎控制层,从而避免自定义 Map
/// 实现绕过安全限制。
pub trait IContext: Any + Send + Sync {
/// 返回 `Any` 视图,供 `Contexts` 复现 Java `instanceof`/强制转换。
fn as_any(&self) -> &dyn Any;
/// 返回模板处理使用的 Locale 快照。
///
/// # 返回值
///
/// 返回当前 Context Locale;调用方获得独立值,不得借此修改 Context。
fn get_locale(&self) -> Locale;
/// 判断指定可空变量名是否已存在。
///
/// # 参数
///
/// - `name`:待查询的可空 Java 变量名。
///
/// # 返回值
///
/// 变量 Map 包含该键时返回 `true`;即使对应值是显式 Java null 也返回 `true`。
fn contains_variable(&self, name: Option<&Utf16String>) -> bool;
/// 返回由 Context 变量 Map 支撑的实时名称视图。
///
/// # 返回值
///
/// 返回共享实时视图。`AbstractContext` 与 Java `HashMap#keySet()` 一样在多次调用
/// 间保持同一视图身份;主动构造名称集合的 EngineContext 实现可返回新视图。
fn get_variable_names(&self) -> Arc<dyn IContextVariableNames + '_>;
/// 返回指定变量的可空值。
///
/// `None` 表示变量不存在;显式 Java null 返回
/// `Some(TemplateValue::Null)`,最终 Java API 边界可重新折叠两者。
///
/// # 参数
///
/// - `name`:待读取的可空 Java 变量名。
///
/// # 返回值
///
/// 返回共享变量值;键不存在时返回 `None`。
fn get_variable(&self, name: Option<&Utf16String>) -> Option<Arc<TemplateValue>>;
/// 返回可选 Web exchange capability。
///
/// Java 通过 `context instanceof IWebContext` 发现该能力;Rust 用显式 capability
/// 避免丢失 trait object 的动态接口信息。普通上下文默认不具备 Web 能力。
fn get_web_exchange(&self) -> Option<&dyn IWebExchange> {
None
}
/// 返回可共享的 Web exchange 身份。
///
/// EngineContext 工厂需要把 exchange 转移到整个渲染生命周期;普通上下文默认
/// 不具备该能力。
fn get_web_exchange_arc(&self) -> Option<Arc<dyn IWebExchange>> {
None
}
/// 返回可选 Web Context capability。
///
/// 对应 Java `context instanceof IWebContext` 后的安全强制转换。
fn as_web_context(&self) -> Option<&dyn super::IWebContext> {
None
}
/// 返回可选 Engine Context capability。
///
/// 对应 Java `context instanceof IEngineContext` 后的安全强制转换。
fn as_engine_context(&self) -> Option<&dyn super::IEngineContext> {
None
}
/// 返回可共享的 Engine Context 身份。
///
/// 嵌套模板处理用它复用现有上下文,而不是克隆变量。普通上下文默认不具备该
/// 能力。
fn get_engine_context_arc(&self) -> Option<Arc<dyn super::IEngineContext>> {
None
}
/// 返回可选模板处理上下文 capability。
///
/// Java 通过 `context instanceof ITemplateContext` 判定 Message、Link 和 Fragment
/// 表达式是否位于模板处理链。Rust trait object 不能可靠执行横向接口强转,因此
/// 由实现显式暴露同一能力。
fn as_template_context(&self) -> Option<&dyn super::ITemplateContext> {
None
}
}