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
125
126
127
128
129
130
131
132
133
134
135
136
//! 特定于 Windows 的 [`std::ffi`] 模块中原语的扩展。
//!
//! # Overview
//!
//! 由于历史原因,Windows API 对字符串使用了一种格式可能不正确的 UTF-16 编码。具体来说,Windows 字符串中的 16 位代码单元可能包含 [未配对在一起的孤立代理代码点][ill-formed-utf-16]。
//! Unicode 标准要求代理代码点 (在 U+D800 到 U+DFFF 范围内的代码点) 总是成对的,因为在 UTF-16 编码中,*surrogate code 单元对 `*` 用于编码单个字符。
//! 为了与不强制执行这些配对的代码兼容,Windows 也不强制执行它们。
//!
//! 虽然不一定总是可以无损地将这样的字符串转换为有效的 UTF-16 字符串 (甚至 UTF-8),但是通常希望能够无损地将这样的字符串往返于 Windows API 之间。
//! 例如,某些 Rust 代码可能与某些 Windows API 一起成为 "bridging",仅在这些 API 之间传递 `WCHAR` 字符串,而无需真正研究这些字符串。
//!
//! 如果确实需要 Rust 代码查看这些字符串,则可以通过用 [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] 替换无效的序列来将它们转换为有效的 UTF-8,这可能是有损的,就像在其他处理字符串编码的 Rust API 中所做的那样。
//!
//!
//! # `OsStringExt` 和 `OsStrExt`
//!
//! [`OsString`] 是 Rust 包装器,用于操作系统首选表示中的拥有所有权的字符串。
//! 在 Windows 上,此结构体通过 [`OsStringExt`] trait 的实现得到了增强,该实现具有 [`OsStringExt::from_wide`] 方法。这使您可以从 `&[u16]` 切片创建 [`OsString`]。大概是从 `WCHAR` Windows API 中得到的切片。
//!
//! 同样,[`OsStr`] 是 Rust 包装器,用于从操作系统的首选表示形式中借用字符串。在 Windows 上,[`OsStrExt`] trait 提供了 [`OsStrExt::encode_wide`] 方法,该方法输出 [`EncodeWide`] 迭代器。
//! 例如,您可以 [`collect`] 这个迭代器,以获得一个 `Vec<u16>`; 您以后可以获取指向此 vector 内容的指针,并将其提供给 Windows API。
//!
//! 这些 traits 与 [`OsString`] 和 [`OsStr`] 一起工作,这样就可以在 Windows 和后面往返字符串,而不会丢失数据,即使字符串是格式错误的 UTF-16。
//!
//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16
//! [`collect`]: crate::iter::Iterator::collect
//! [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
//! [`std::ffi`]: crate::ffi
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!

#![stable(feature = "rust1", since = "1.0.0")]

use crate::ffi::{OsStr, OsString};
use crate::sealed::Sealed;
use crate::sys::os_str::Buf;
use crate::sys_common::wtf8::Wtf8Buf;
use crate::sys_common::{AsInner, FromInner};

#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys_common::wtf8::EncodeWide;

/// 特定于 Windows 的 [`OsString`] 扩展。
///
/// 这个 trait 是封闭的:它不能在标准库之外实现。
/// 这是为了将来的附加方法不会破坏更改。
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt: Sealed {
    /// 从可能是格式不正确的 UTF-16 切片创建 `OsString`
    /// 16 位代码单元。
    ///
    /// 这是无损的:在结果字符串上调用 [`OsStrExt::encode_wide`] 将始终返回原始代码单元。
    ///
    ///
    /// # Examples
    ///
    /// ```
    /// use std::ffi::OsString;
    /// use std::os::windows::prelude::*;
    ///
    /// // "Unicode" 的 UTF-16 编码。
    /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
    ///
    /// let string = OsString::from_wide(&source[..]);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from_wide(wide: &[u16]) -> Self;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl OsStringExt for OsString {
    fn from_wide(wide: &[u16]) -> OsString {
        FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) })
    }
}

/// 特定于 Windows 的 [`OsStr`] 扩展。
///
/// 这个 trait 是封闭的:它不能在标准库之外实现。
/// 这是为了将来的附加方法不会破坏更改。
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt: Sealed {
    /// 将 `OsStr` 重新编码为宽字符序列,即可能格式不正确的 UTF-16。
    ///
    /// 这是无损的:在结果上调用 [`OsStringExt::from_wide`],然后调用 `encode_wide`,将产生原始代码单元。
    ///
    /// 请注意,编码不会添加最终的空终止符。
    ///
    /// # Examples
    ///
    /// ```
    /// use std::ffi::OsString;
    /// use std::os::windows::prelude::*;
    ///
    /// // "Unicode" 的 UTF-16 编码。
    /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
    ///
    /// let string = OsString::from_wide(&source[..]);
    ///
    /// let result: Vec<u16> = string.encode_wide().collect();
    /// assert_eq!(&source[..], &result[..]);
    /// ```
    ///
    #[stable(feature = "rust1", since = "1.0.0")]
    fn encode_wide(&self) -> EncodeWide<'_>;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl OsStrExt for OsStr {
    #[inline]
    fn encode_wide(&self) -> EncodeWide<'_> {
        self.as_inner().inner.encode_wide()
    }
}