#iri #identifier #resources #slice #uri #path-query

已删除 iref__bbqsrc

国际化资源标识符(IRI)和引用,借用和所有

1.1.5 2020年9月9日

#13 in #iri

MIT/Apache

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

此仓库提供了四种类型IriIriBufIriRefIriRefBuf来操作字/字符串切片和缓冲区作为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");

详细用法

路径操作

通过 pathpath_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 引用

此库提供了两种类型 IriRefIriRefBuf 来表示 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.orghttp://example.org:80 仍然 不等价

每个 / 都计数

路径 /foo/bar/foo/bar/ 不等价

路径规范化

在比较过程中,通过删除点段(...)对路径进行规范化。这意味着例如,路径 a/b/ca/../a/./b/../b/c 是等价的。请注意,然而,此库实现了关于相对路径中点段异常使用的 Errata 4547。这意味着例如,IRI http:a/b/../../../ 等价于 http:../,而不是 http:

百分编码字符

多亏了 pct-str,百分编码字符被正确处理。两个 IRI http://example.orghttp://exa%6dple.org 是等价的

缺少什么

目前,这个crate缺乏一种正确的方式来以不区分大小写的方式比较字符串。因此,IRIs http://example.orghtTp://ExAmpLe.Org 应该是等效的,但它们并不相同。

接下来是什么?

我正在等待 自定义DST 可用,以便将类型 IriIriRef (以及 PathAuthority 等)转换为与 strOsStr 等一样动态大小的类型。这将允许缓冲类型(如 IriBufPathBuf 等)Deref 到这些DST,并且使用起来更加简单,同时简化了API。

我们只需等待...

许可证

根据您的选择,以下任一许可证

贡献

除非您明确声明,否则根据Apache-2.0许可证定义,您提交的任何有意包含在作品中的贡献将按照上述方式双重许可,不附加任何额外条款或条件。

依赖项

~115KB