///|
/// HTTP 请求方法。
///
/// 这里独立定义一份枚举,而不是直接复用 `moonbitlang/async/http` 的 `RequestMethod`,
/// 是为了让 config / headers / merge / url 这几个包保持纯逻辑、不依赖 async 运行时;
/// 两者之间的转换被隔离在 transport 包里。
///
/// 派生 `Hash` 是必须的:`Config.method_headers` 用 `Map[Method, Headers]` 存
/// 「按方法分层的默认头」,而 Map 的 key 需要 `Hash + Eq`。
///
/// `Other` 承载自定义方法(WebDAV 的 `PROPFIND`、`REPORT` 等):**存原样、发原样**
/// ——HTTP 方法 token 按 RFC 7230 区分大小写,大写惯例由调用方保证,
/// `to_string` 对它返回载荷本身。传输层原样发送(httpconn 为缺省实现),
/// 发送前校验 token 合法性,非法 token 在建连之前报 `Unsupported`。
pub(all) enum Method {
Get
Head
Post
Put
Delete
Connect
Options
Trace
Patch
Other(String)
} derive(Eq, Hash, Debug)
///|
pub extend Method with Eq::{equal, not_equal}
///|
pub extend Method with Hash::{hash, hash_combine}
///|
pub extend Method with @debug.Debug::{to_repr}
///|
/// 请求行里使用的大写方法名,例如 `GET`。用于拼出可读的请求行与日志。
/// `Other` 返回载荷本身:方法 token 区分大小写,存的是什么就发什么。
pub fn Method::to_string(self : Method) -> String {
match self {
Get => "GET"
Head => "HEAD"
Post => "POST"
Put => "PUT"
Delete => "DELETE"
Connect => "CONNECT"
Options => "OPTIONS"
Trace => "TRACE"
Patch => "PATCH"
Other(name) => name
}
}
///|
/// 解析方法名,大小写不敏感;无法识别时返回 `None`。
///
/// 不在这里抛错:调用方(传输层或用户代码)才知道该报什么错,
/// 保持这个纯函数只有「找到/没找到」两种结果。
///
/// 注意它**不**把未知名字解析成 `Other`:九个标准方法之外的名字一律 `None`。
/// `Other` 是调用方显式构造的「我要原样发这个 token」,而 `parse` 的语义是
/// 「这名字是不是标准方法」——把两者混起来,拼错的标准方法名(`GT` 想写 `GET`)
/// 就会被当成自定义方法静默发出去,错误从「一眼看出的笔误」变成「线上 405」。
pub fn Method::parse(name : StringView) -> Method? {
for meth in [Get, Head, Post, Put, Delete, Connect, Options, Trace, Patch] {
// compare_ignore_ascii_case 比先大小写折叠再比较更直接,也少一次分配。
if name.compare_ignore_ascii_case(meth.to_string()) == 0 {
return Some(meth)
}
}
None
}