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
use std::error::Error;
use std::fmt::{Display, Formatter};
use crate::web::IWebExchange;
use super::{IContext, IEngineContext, IWebContext};
/// 上下文运行时 capability 检查与安全转换工具。
///
/// Rust 通过 `IContext` 显式 capability 复现 Java `instanceof` 和强制转换;错误
/// 转换与 Java `ClassCastException` 一样立即失败。
///
/// 对应 Java: `org.thymeleaf.context.Contexts`。
pub struct Contexts;
/// Context capability 强制转换失败。
///
/// 对应 Java: `java.lang.ClassCastException`。Rust 引用不能表示 Java `null`,而不兼容
/// capability 的强制转换仍按 Java unchecked runtime failure 抛出本错误。
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ContextsError {
/// 当前 Context 不实现目标 engine/Web capability。
ContextCast {
/// 目标 Java 接口的简单名称。
target: &'static str,
},
/// 当前 Web exchange 不具备 Servlet capability。
ServletExchangeCast,
}
impl ContextsError {
/// 返回 Java 对应异常全限定名。
#[must_use]
pub const fn class_name(&self) -> &'static str {
"java.lang.ClassCastException"
}
}
impl Display for ContextsError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::ContextCast { target } => write!(formatter, "Context cannot be cast to {target}"),
Self::ServletExchangeCast => {
formatter.write_str("Web exchange cannot be cast to IServletWebExchange")
}
}
}
}
impl Error for ContextsError {}
impl Contexts {
/// 判断上下文是否为引擎内部上下文。
///
/// 对应 Java: `Contexts#isEngineContext(IContext)`。
#[must_use]
pub fn is_engine_context(context: &dyn IContext) -> bool {
context.as_engine_context().is_some()
}
/// 转换为引擎内部上下文;类型不匹配时失败。
///
/// 对应 Java: `Contexts#asEngineContext(IContext)`。
#[must_use]
pub fn as_engine_context(context: &dyn IContext) -> &dyn IEngineContext {
context.as_engine_context().unwrap_or_else(|| {
std::panic::panic_any(ContextsError::ContextCast {
target: "IEngineContext",
})
})
}
/// 判断上下文是否具有 Web capability。
///
/// 对应 Java: `Contexts#isWebContext(IContext)`。
#[must_use]
pub fn is_web_context(context: &dyn IContext) -> bool {
context.as_web_context().is_some()
}
/// 转换为 Web 上下文;类型不匹配时失败。
///
/// 对应 Java: `Contexts#asWebContext(IContext)`。
#[must_use]
pub fn as_web_context(context: &dyn IContext) -> &dyn IWebContext {
context.as_web_context().unwrap_or_else(|| {
std::panic::panic_any(ContextsError::ContextCast {
target: "IWebContext",
})
})
}
/// 返回 Web exchange;非 Web 上下文时失败。
///
/// 对应 Java: `Contexts#getWebExchange(IContext)`。
#[must_use]
pub fn get_web_exchange(context: &dyn IContext) -> &dyn IWebExchange {
Self::as_web_context(context).get_exchange()
}
/// 判断上下文是否由 Rust Web 宿主 exchange 支撑。
///
/// 对应 Java: `Contexts#isServletWebContext(IContext)`;Rust 将 Servlet capability
/// 映射为中立 `IWebExchange`,实际宿主类型留在 `thymeleaf-{framework}`。
#[must_use]
pub fn is_servlet_web_context(context: &dyn IContext) -> bool {
context.as_web_context().is_some_and(|web_context| {
web_context
.get_exchange()
.as_servlet_web_exchange()
.is_some()
})
}
/// 返回中立宿主 exchange;类型不匹配时失败。
///
/// 对应 Java: `Contexts#getServletWebExchange(IContext)` 的 Rust Host 映射。
#[must_use]
pub fn get_servlet_web_exchange(context: &dyn IContext) -> &dyn IWebExchange {
Self::get_web_exchange(context)
.as_servlet_web_exchange()
.unwrap_or_else(|| std::panic::panic_any(ContextsError::ServletExchangeCast))
}
}