12 个版本
0.2.0 | 2024 年 7 月 30 日 |
---|---|
0.2.0-alpha.8 | 2024 年 7 月 2 日 |
0.2.0-alpha.7 | 2024 年 6 月 21 日 |
0.2.0-alpha.5 | 2024 年 4 月 17 日 |
0.1.2 |
|
#158 in 编码
319,322 每月下载量
用于 45 个 crate (10 直接)
130KB
2.5K SLoC
fluent-uri
符合 RFC 3986 的完整功能 URI 引用处理库。
- 快速: 零拷贝解析。经过基准测试,性能极高。[^bench-res]
- 简单: 设计和文档精心。方便的百分比编码工具。
- 正确: 禁止不安全代码。广泛针对其他实现进行模糊测试。
[^bench-res]: 在 基准测试 中,在 Intel Core i5-11300H 处理器上,fluent-uri
解析 URI 的时间为 49ns,而 iref
为 89ns,iri-string
为 135ns。
术语
一个 URI 引用 是一个 URI 或一个 相对引用。如果它以一个 方案(如 http
、ftp
、mailto
等)开头,后跟一个冒号(:
),则它是一个 URI。例如,http://example.com/
和 mailto:user@example.com
是 URI。否则,它是一个相对引用。例如,//example.org/
、/index.html
、../
、foo
、?bar
和 #baz
是相对引用。
示例
-
从 URI 引用中解析和提取组件,零拷贝
const SCHEME_FOO: &Scheme = Scheme::new_or_panic("foo"); let uri_ref = UriRef::parse("foo://[email protected]:8042/over/there?name=ferret#nose")?; assert_eq!(uri_ref.scheme().unwrap(), SCHEME_FOO); let auth = uri_ref.authority().unwrap(); assert_eq!(auth.as_str(), "[email protected]:8042"); assert_eq!(auth.userinfo().unwrap(), "user"); assert_eq!(auth.host(), "example.com"); assert!(matches!(auth.host_parsed(), Host::RegName(name) if name == "example.com")); assert_eq!(auth.port().unwrap(), "8042"); assert_eq!(auth.port_to_u16(), Ok(Some(8042))); assert_eq!(uri_ref.path(), "/over/there"); assert_eq!(uri_ref.query().unwrap(), "name=ferret"); assert_eq!(uri_ref.fragment().unwrap(), "nose");
-
使用构建器模式构建 URI 引用
const SCHEME_FOO: &Scheme = Scheme::new_or_panic("foo"); let uri_ref = UriRef::builder() .scheme(SCHEME_FOO) .authority_with(|b| { b.userinfo(EStr::new_or_panic("user")) .host(EStr::new_or_panic("example.com")) .port(8042) }) .path(EStr::new_or_panic("/over/there")) .query(EStr::new_or_panic("name=ferret")) .fragment(EStr::new_or_panic("nose")) .build() .unwrap(); assert_eq!( uri_ref.as_str(), "foo://[email protected]:8042/over/there?name=ferret#nose" );
-
相对于基 URI 解析 URI 引用
let base = UriRef::parse("http://example.com/foo/bar")?; let uri_ref = UriRef::parse("baz")?; assert_eq!(uri_ref.resolve_against(&base).unwrap(), "http://example.com/foo/baz"); let uri_ref = UriRef::parse("../baz")?; assert_eq!(uri_ref.resolve_against(&base).unwrap(), "http://example.com/baz"); let uri_ref = UriRef::parse("?baz")?; assert_eq!(uri_ref.resolve_against(&base).unwrap(), "http://example.com/foo/bar?baz");
-
规范化 URI 引用
let uri_ref = UriRef::parse("eXAMPLE://a/./b/../b/%63/%7bfoo%7d")?; assert_eq!(uri_ref.normalize(), "example://a/b/c/%7Bfoo%7D");
-
EStr
(百分比编码字符串切片)URI 中所有可能进行百分编码的组件都被解析为
EStr
,这使得它们可以轻松地进行分割和解码。let s = "?name=%E5%BC%A0%E4%B8%89&speech=%C2%A1Ol%C3%A9%21"; let query = UriRef::parse(s).unwrap().query().unwrap(); let map: HashMap<_, _> = query .split('&') .map(|s| s.split_once('=').unwrap_or((s, EStr::EMPTY))) .map(|(k, v)| (k.decode().into_string_lossy(), v.decode().into_string_lossy())) .collect(); assert_eq!(map["name"], "张三"); assert_eq!(map["speech"], "¡Olé!");
-
EString
(一个百分编码的可增长字符串)您可以将键值对编码成查询字符串,并使用它来构建一个
UriRef
。let pairs = [("name", "张三"), ("speech", "¡Olé!")]; let mut buf = EString::<Query>::new(); for (k, v) in pairs { if !buf.is_empty() { buf.push_byte(b'&'); } buf.encode::<Data>(k); buf.push_byte(b'='); buf.encode::<Data>(v); } assert_eq!(buf, "name=%E5%BC%A0%E4%B8%89&speech=%C2%A1Ol%C3%A9%21"); let uri_ref = UriRef::builder() .path(EStr::EMPTY) .query(&buf) .build() .unwrap(); assert_eq!(uri_ref.as_str(), "?name=%E5%BC%A0%E4%B8%89&speech=%C2%A1Ol%C3%A9%21");
依赖关系
~265–770KB
~18K SLoC