1.1.5 |
|
---|
#13 in #iri
115KB
3K SLoC
国际化资源标识符和引用
文档 | 仓库信息 | 仓库 |
这个仓库实现了根据国际化资源标识符(IRI)和RFC 3987以及RFC 3986定义的互联网工程任务组(IETF),对国际化资源标识符(IRI)和IRI引用的实现。IRI是统一资源标识符(URI)和统一资源定位符(URL)的超类,用于在网络上唯一标识对象。IRI被定义为具有可区分组件的字符序列:方案、授权、路径、查询和片段。
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
此仓库提供了四种类型Iri
、IriBuf
、IriRef
和IriRefBuf
来操作字/字符串切片和缓冲区作为IRI和IRI引用。这允许轻松访问和操作每个组件。
基本用法
通过将以下行添加到Cargo.toml
文件的dependencies
部分来导入此仓库
[dependencies]
iref = "1.1"
您可以通过将一个Iri
实例包装在str
切片周围来解析IRI字符串。请注意,使用Iri
不会发生内存分配,它仅借用输入数据。访问每个组件的操作是在常数时间内完成的。
extern crate iref;
use iref::Iri;
let iri = Iri::new("https://rust-lang.net.cn/foo/bar?query#frag")?;
println!("scheme: {}", iri.scheme());
println!("authority: {}", iri.authority().unwrap());
println!("path: {}", iri.path());
println!("query: {}", iri.query().unwrap());
println!("fragment: {}", iri.fragment().unwrap());
可以使用IriBuf
类型创建和修改IRI。使用此类型,IRI存储在单个缓冲区中,原地修改以减少内存分配并优化内存访问。这还允许将IriBuf
转换为Iri
。
extern crate iref;
use std::convert::TryInto;
use iref::IriBuf;
let mut iri = IriBuf::new("https://rust-lang.net.cn")?;
iri.authority_mut().unwrap().set_port(Some("40".try_into()?));
iri.set_path("/foo".try_into()?);
iri.path_mut().push("bar".try_into()?);
iri.set_query(Some("query".try_into()?));
iri.set_fragment(Some("fragment".try_into()?));
assert_eq!(iri, "https://rust-lang.net.cn:40/foo/bar?query#fragment");
使用try_into
方法来确保每个字符串与其相应组件在语法上是正确的(例如,不可能将“query”替换为“query?”,因为“?”不是有效的查询字符)。
static-iri
库提供了两个宏,iri!
和 iref!
,用于在编译时构建具有 'static
生命周期的 IRIs 和 IRI 引用。
extern crate iref;
#[macro_use]
extern crate static_iref;
use iref::{Iri, IriRef};
const IRI: Iri<'static> = iri!("https://rust-lang.net.cn/foo/bar#frag");
const IREF: IriRef<'static> = iref!("/foo/bar#frag");
详细用法
路径操作
通过 path
或 path_mut
方法访问 IRI 路径。可以使用 segments
方法返回的迭代器访问路径的各个部分。
for segment in iri.path().segments() {
println!("{}", segment);
}
可以使用 normalized_segments
方法遍历路径的正常化版本,其中已删除点段(.
和 ..
)。此外,可以使用相应的方法向路径中推送或弹出段。
let mut iri = IriBuf::new("https://rust-lang.net.cn/a/c");
let mut path = iri.path_mut();
path.pop();
path.push("b".try_into()?);
path.push("c/".try_into()?); // a `/` character is allowed at the end of a segment.
assert_eq!(iri.path(), "/a/b/c/")
IRI 引用
此库提供了两种类型 IriRef
和 IriRefBuf
来表示 IRI 引用。IRI 引用可以是 IRI 或相对 IRI。与常规 IRIs 不同,相对 IRI 引用可能没有方案。
let mut iri_ref = IriRefBuf::default(); // an IRI reference can be empty.
// An IRI reference with a scheme is a valid IRI.
iri_ref.set_scheme(Some("https".try_into()?));
let iri: Iri = iri_ref.as_iri()?;
// An IRI can be safely converted into an IRI reference.
let iri_ref: IriRef = iri.into();
给定一个基本 IRI,可以使用在 RFC 3986 中定义的引用解析算法将引用解析为常规 IRI。此库提供了此算法的 严格 实现。
let base_iri = Iri::new("http://a/b/c/d;p?q")?;
let mut iri_ref = IriRefBuf::new("g;x=1/../y")?;
// non mutating resolution.
assert_eq!(iri_ref.resolved(base_iri), "http://a/b/c/y");
// in-place resolution.
iri_ref.resolve(base_iri);
assert_eq!(iri_ref, "http://a/b/c/y");
此库实现了关于相对路径中点段异常使用的 Errata 4547。这意味着例如,路径 a/b/../../../
被规范化为 ../
。
IRI 比较
以下是此库中实现的 IRI 比较方法的特点。
协议无关
此实现对现有协议一无所知。例如,即使 HTTP 协议 将 80
定义为默认端口,两个 IRI http://example.org
和 http://example.org:80
仍然 不等价。
每个 /
都计数
路径 /foo/bar
与 /foo/bar/
不等价。
路径规范化
在比较过程中,通过删除点段(.
和 ..
)对路径进行规范化。这意味着例如,路径 a/b/c
和 a/../a/./b/../b/c
是等价的。请注意,然而,此库实现了关于相对路径中点段异常使用的 Errata 4547。这意味着例如,IRI http:a/b/../../../
等价于 http:../
,而不是 http:
。
百分编码字符
多亏了 pct-str
库,百分编码字符被正确处理。两个 IRI http://example.org
和 http://exa%6dple.org
是等价的。
缺少什么
目前,这个crate缺乏一种正确的方式来以不区分大小写的方式比较字符串。因此,IRIs http://example.org
和 htTp://ExAmpLe.Org
应该是等效的,但它们并不相同。
接下来是什么?
我正在等待 自定义DST 可用,以便将类型 Iri
和 IriRef
(以及 Path
、Authority
等)转换为与 str
、OsStr
等一样动态大小的类型。这将允许缓冲类型(如 IriBuf
、PathBuf
等)Deref
到这些DST,并且使用起来更加简单,同时简化了API。
我们只需等待...
许可证
根据您的选择,以下任一许可证
- Apache许可证,版本2.0(《LICENSE-APACHE》或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT许可证(《LICENSE-MIT》或 http://opensource.org/licenses/MIT)
。
贡献
除非您明确声明,否则根据Apache-2.0许可证定义,您提交的任何有意包含在作品中的贡献将按照上述方式双重许可,不附加任何额外条款或条件。
依赖项
~115KB