5 个版本
使用旧的 Rust 2015
0.0.5 | 2019 年 3 月 31 日 |
---|---|
0.0.4 | 2018 年 5 月 30 日 |
0.0.3 | 2018 年 4 月 28 日 |
0.0.2 | 2018 年 4 月 10 日 |
0.0.1 | 2017 年 12 月 5 日 |
#572 in Rust 模式
7,941 每月下载量
23KB
opaque_typedef
opaque_typedef:
opaque_typedef_macros:
这是一个用于 Rust 编程语言的 proc-macro 仓库。
这个仓库帮助开发者轻松定义不透明类型定义(强类型定义)类型,减少样板代码。
注意:这个库正在开发中且不稳定。
不透明类型定义
你可能想定义一个新的类型,与其它类型具有相同的内部表示,但没有隐式类型转换。现实世界例子
UncasedStr
在 rocket 仓库中(其内部表示为str
)NotNaN
在 ordered_float 仓库中(其内部表示为浮点数字类型(通常是f32
和f64
))
这些类型通常对内部类型有额外的限制(例如,UncasedStr
具有较宽松的比较函数,而 NotNan
不允许 NaN),你可能想实现一些特性而不想实现其他特性(例如,你可能想实现 From<&str> for &UncasedStr
但不希望 Deref<Target=str> for UncasedStr
)。
opaque_typedef 仓库帮助你为你的类型“推导”特定的特性(即重用内部类型实现的特性)。
要查看示例,请参阅 opaque_typedef_tests/src/
目录下的文件。
术语
Think structOuter(Inner);
- 内部类型指的是
Inner
类型。 - 外部类型指的是
Outer
类型。 Outer
是Inner
的不透明类型定义(强类型定义)。- 未指定大小的类型意味着
str
、[i32]
或类似的东西(通常是切片类型)。 - 指定大小的类型意味着
String
、i32
、&u8
或类似的东西。
使用方法
示例可以在opaque_typedef_tests/src/
中找到。
1. 指定 "extern crate"
Cargo.toml
:
[dependencies]
opaque_typedef = "^0.0.4"
opaque_typedef_macros = "^0.0.4"
lib.rs
或main.rs
extern crate opaque_typedef;
#[macro_use]
extern crate opaque_typedef_macros;
2. 对于有大小类型,派生OpaqueTypedef
,对于无大小类型,派生OpaqueTypedefUnsized
有大小类型
/// My owned string.
#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, OpaqueTypedef)]
pub struct MyString(String);
无大小类型
/// My string slice.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, OpaqueTypedefUnsized)]
#[repr(C)]
pub struct MyStr(str);
注意,对于无大小类型,必须使用#[repr(C)]
(或#[repr(transparent)]
)。
然后您可以使用OpaqueTypedef
特质或OpaqueTypedefUnsized
特质。这将有助于为您自己的类型实现方法!
关于使用#[repr(*)]
的必要性,请参阅https://github.com/lo48576/opaque_typedef/issues/1。
3. 指定是否可以使用可变引用派生特质(可选)
如果您想让opaque_typedef派生可能返回内部值可变引用的特质(如DerefMut
、AsMut
)或可能修改内部值的特质(如AddAssign
),则应指定#[opaque_typedef(allow_mut_ref)]
。
/// My string slice.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, OpaqueTypedefUnsized)]
#[repr(C)]
#[opaque_typedef(allow_mut_ref)]
pub struct MyStr(str);
如果您不指定它,opaque_typedef将拒绝派生如#[opaque_typedef(derive(DerefMut))]
之类的操作。
4. 派生更多特质
您可以使用以下格式指定特性:#[opaque_typedef(derive(Trait1, Trait2, ...))]
。
例如
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, OpaqueTypedefUnsized)]
#[repr(C)]
#[opaque_typedef(derive(AsciiExt, AsMut(Deref, Self), AsRef(Deref, Self), DefaultRef, Deref,
DerefMut, Display, FromInner, Into(Arc, Box, Rc, Inner),
PartialEq(Inner, InnerRev, InnerCow, InnerCowRev, SelfCow, SelfCowRev),
PartialOrd(Inner, InnerRev, InnerCow, InnerCowRev, SelfCow, SelfCowRev)))]
#[opaque_typedef(allow_mut_ref)]
pub struct MyStr(str);
注意,某些特性可以被缩短。例如
AsMutDeref
可以写成AsMut(Deref)
AsRefSelf
可以写成AsRef(Self)
IntoRc
可以写成Into(Rc)
PartialEqInner
可以写成PartialEq(Inner)
PartialOrdInner, PartialOrdSelfCow
可以写成PartialOrd(Inner, SelfCow)
要查看“derive”可用项的列表,请阅读文档的其余部分或查看源代码(Derive
枚举在 opaque_typedef_macros/src/derives/mod.rs
)。
要查看“derive”可用项的完整缩短表示法列表,请查看Derive::append_from_nested_names
方法在 opaque_typedef_macros/src/derives/mod.rs
)。
4.1. 指定解引用目标(可选)
如果您指定了Deref
、DerefMut
、AsRefDeref
或与Deref
相关的其他内容,您还可以通过以下格式指定“解引用目标”:#[opaque_typedef(deref(...))]
。
/// My owned string.
#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, OpaqueTypedef)]
#[opaque_typedef(derive(AsMut(Deref, Inner), AsRef(Deref, Inner), Deref, DerefMut, Display,
FromInner, IntoInner, PartialEq(Inner, InnerRev),
PartialOrd(Inner, InnerRev)))]
#[opaque_typedef(deref(target = "str", deref = "String::as_str",
deref_mut = "String::as_mut_str"))]
#[opaque_typedef(allow_mut_ref)]
pub struct MyString {
inner: String,
}
Opaque_typedef使用内部类型作为默认解引用目标类型,但您可以使用不同的类型,如上述示例所示。
target
:- 解引用目标类型。
deref
:- 从对内部类型的引用到对外部类型的引用的转换函数。
- 该函数应实现
Fn(&Inner) -> &DerefTarget
。
deref_mut
:- 从对内部类型的可变引用到对外部类型的可变引用的转换函数。
- 该函数应实现
Fn(&mut Inner) -> &mut DerefTarget
。
在示例中,AsMutInner
实现了 AsMut<String> for MyString
,而 AsMutDeref
实现了 AsMut<str> for MyString
。
如果您未指定 #[opaque_typedef(allow_mut_ref)]
,则 deref_mut
不会被使用,您可以省略它。
5. 指定自定义验证器(可选)
您可以选择指定自定义验证器。在将内部类型转换为外部类型时,会验证内部类型的值。通过自定义验证器,您可以限制内部值。
要使用自定义验证器,请指定以下属性
validator
- 验证器函数。这应该具有如
Inner -> Result<Inner, Error>
的类型。- 对于有大小类型,
Inner -> Result<Inner, Error>
。验证器可以修改给定的值并返回修改后的值。 - 对于无大小类型,
&Inner -> Result<&Inner, Error>
。
- 对于有大小类型,
- 验证器函数。这应该具有如
error_type
- 验证错误类型。通过
validator
指定的验证器应使用此类型作为错误。 - 这不能是泛型,并且不能使用外部类型的任何类型参数。
- 验证错误类型。通过
error_msg
(可选)- 当验证失败时,在恐慌中显示错误信息。此值用于恐慌性转换失败时,例如,当将无效值传递给
Outer::from_inner
(不是Outer::try_from_inner
)时。 - 内部,如果
error_msg
缺失,则将使用unwrap()
撒慌,如果指定了error_msg
,则将使用expect(error_msg)
。
- 当验证失败时,在恐慌中显示错误信息。此值用于恐慌性转换失败时,例如,当将无效值传递给
以下示例来自 opaque_typedef_tests/src/even32.rs
和 opaque_typedef_tests/tests/even32.rs
。
/// Even `i32`.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, OpaqueTypedef)]
#[opaque_typedef(derive(Binary, Deref, Display, FromInner, PartialEq(Inner, InnerRev),
PartialOrd(Inner, InnerRev), LowerHex, Octal, UpperHex))]
#[opaque_typedef(validation(validator = "validate_even32", error_type = "OddError",
error_msg = "Failed to create `Even32`"))]
pub struct Even32(i32);
impl Even32 {
/// Returns the inner `i32` even value.
pub fn to_i32(&self) -> i32 {
self.0
}
}
/// A type of an error indicating the integer is an odd number, not even.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OddError;
fn validate_even32(v: i32) -> Result<i32, OddError> {
if v % 2 == 0 {
Ok(v)
} else {
Err(OddError)
}
}
#[cfg(test)]
mod tests {
#[test]
fn ok() {
let v = Even32::from(42);
assert_eq!(v.to_i32(), 42);
}
#[test]
#[should_panic]
fn from_odd() {
// Panics with message "Failed to create `Even32`: OddError".
let _ = Even32::from(3);
}
}
6. 指定自定义比较器(可选)
您可以为 PartialEq
和 PartialOrd
使用自定义实现。
要使用自定义比较器,请指定以下属性
partial_eq
- 部分相等函数。这应该具有如
&Inner -> &Inner -> bool
的类型。
- 部分相等函数。这应该具有如
partial_ord
- 部分顺序函数。它应该具有以下类型的函数,例如
&Inner -> &Inner -> Option<::std::cmp::Ordering>
.
- 部分顺序函数。它应该具有以下类型的函数,例如
ord
- 全序函数。它应该具有以下类型的函数,例如
&Inner -> &Inner -> ::std::cmp::Ordering
. #[derive(Ord)]
没有使用PartialOrd::partial_cmp
实现,因此它们可能会因错误而不一致。请记住要 保持它们(包括PartialEq::eq
)的一致性。
- 全序函数。它应该具有以下类型的函数,例如
下面的示例取自 opaque_typedef_tests/src/reverse_order.rs
和 opaque_typedef_tests/tests/reverse_order.rs
.
/// A wrapper type with reverse order.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Ord, Hash, OpaqueTypedef)]
#[opaque_typedef(derive(AsciiExt, AsMut(Deref), AsRef(Deref), Binary, Deref, DerefMut, Display,
FromInner, LowerHex, Octal, PartialOrdSelf, UpperHex))]
#[opaque_typedef(cmp(partial_ord = "(|a, b| PartialOrd::partial_cmp(a, b).map(|o| o.reverse()))",
ord = "(|a, b| Ord::cmp(a, b).reverse())"))]
#[opaque_typedef(allow_mut_ref)]
pub struct ReverseOrderSized<T>(pub T);
#[test]
fn reverse_i32() {
use std::cmp::Ordering;
assert_eq!(ReverseOrderSized(3i32).partial_cmp(&ReverseOrderSized(2i32)), Some(Ordering::Less));
assert!(ReverseOrderSized(3i32) < ReverseOrderSized(2i32));
assert_eq!(ReverseOrderSized(3i32).cmp(&ReverseOrderSized(2i32)), Ordering::Less);
assert_eq!(ReverseOrderSized(3i32).cmp(&ReverseOrderSized(3i32)), Ordering::Equal);
assert_eq!(ReverseOrderSized(3i32).cmp(&ReverseOrderSized(4i32)), Ordering::Greater);
}
特性
定义基本构造和转换
对于有大小类型
#[derive(OpaqueTypedef)]
实现了 opaque_typedef::OpaqueTypedef
特性,并有一些基本且有用的方法。
请参阅 https://docs.rs/opaque_typedef/*/opaque_typedef/trait.OpaqueTypedef.html 以获取详细信息。
对于无大小类型
#[derive(OpaqueTypedefUnsized)]
实现了 opaque_typedef::OpaqueTypedefUnsized
特性,并有一些基本且有用的方法。特别是 OpaqueTypedefUnsized::from_inner()
会非常有用。
请参阅 https://docs.rs/opaque_typedef/*/opaque_typedef/trait.OpaqueTypedefUnsized.html 以获取详细信息。
自动派生许多 std 特性
以下特性得到支持。
请注意,某些特性(如 DefaultRef
)仅适用于有大小类型。
std::convert
,类型转换
As{Mut,Ref}{Deref,Inner,Self}
AsMutDeref
为AsMut<DerefTarget> for Outer
实现。AsMutInner
实现了AsMut<Inner> for Outer
.AsMutSelf
实现了AsMut<Outer> for Outer
.AsRefDeref
实现了AsRef<DerefTarget> for Outer
.AsRefInner
实现了AsRef<Inner> for Outer
.AsRefSelf
实现了AsRef<Self> for Outer
.
Deref
,DerefMut
Deref
实现了std::ops::Deref for Outer
.DerefMut
实现了std::ops::DerefMut for Outer
.
Into{Arc,Box,Inner,Rc}
,FromInner
IntoArc
实现了From<Outer> for Arc<Outer>
(如果可能)或Into<Arc<Outer>> for Outer
.IntoBox
实现了From<Outer> for Box<Outer>
(如果可能)或Into<Box<Outer>> for Outer
.IntoInner
实现了From<Outer> for Inner
.IntoRc
实现了From<Outer> for Rc<Outer>
(如果可能)或Into<Rc<Outer>> for Outer
.FromInner
实现了From<Inner> for Outer
.
std::fmt
std::fmt::*
Binary
实现了std::fmt::Binary for Outer
。Display
实现了std::fmt::Display for Outer
。LowerExp
实现了std::fmt::LowerExp for Outer
。LowerHex
实现了std::fmt::LowerHex for Outer
。Octal
实现了std::fmt::Octal for Outer
。Pointer
实现了std::fmt::Pointer for Outer
。UpperExp
实现了std::fmt::UpperExp for Outer
。UpperHex
实现了std::fmt::UpperHex for Outer
。
std::cmp
Partial{Eq,Ord}{Inner,InnerCow,SelfCow}{,Rev}
PartialEqInner
实现了PartialEq<Inner> for Outer
和类似的实现。PartialEqInnerRev
实现了PartialEq<Outer> for Inner
和类似的实现。- 这是
PartialEqInner
的反转(操作数顺序交换)版本。
- 这是
PartialEqInnerCow
实现了PartialEq<Cow<Inner>> for Outer
和类似的实现。PartialEqInnerCowRev
实现了PartialEq<Outer> for Cow<Inner>
和类似的实现。- 这是
PartialEqInnerCow
的反转(操作数顺序交换)版本。
- 这是
PartialEqSelf
实现了PartialEq<Outer> for Outer
和类似的实现。- 这与
#[derive(PartialEq)]
非常相似,但它在自定义比较时非常有用。
- 这与
PartialEqSelfCow
实现了PartialEq<Cow<Outer>> for Outer
和类似的实现。PartialEqSelfCowRev
实现了PartialEq<Outer> for Cow<Outer>
和类似的实现。- 这是
PartialEqSelfCow
的反向版本(操作数顺序交换)。
- 这是
PartialEqSelfCowAndInner
实现了PartialEq<Cow<Outer>> for Inner
和类似的实现。PartialEqSelfCowAndInnerCow
实现了PartialEq<Inner> for Cow<Outer>
和类似的实现。- 这是
PartialEqSelfCowAndInner
的反向版本(操作数顺序交换)。
- 这是
PartialOrdInner
实现了PartialOrd<Inner> for Outer
和类似的实现。PartialOrdInnerRev
实现了PartialOrd<Outer> for Inner
和类似的实现。- 这是
PartialOrdInner
的反向版本(操作数顺序交换)。
- 这是
PartialOrdInnerCow
实现了PartialOrd<Cow<Inner>> for Outer
和类似的实现。PartialOrdInnerCowRev
实现了PartialOrd<Outer> for Cow<Inner>
和类似的实现。- 这是
PartialOrdInnerCow
的反向版本(操作数顺序交换)。
- 这是
PartialOrdSelf
实现了PartialOrd<Outer> for Outer
和类似的实现。- 这与
#[derive(PartialOrd)]
非常相似,但它将在自定义比较中非常有用。
- 这与
PartialOrdSelfCow
实现了PartialOrd<Cow<Outer>> for Outer
和类似的实现。PartialOrdSelfCowRev
实现了PartialOrd<Outer> for Cow<Outer>
和类似的实现。- 这是
PartialOrdSelfCow
的反向版本(操作数顺序交换)。
- 这是
PartialOrdSelfCowAndInner
实现了PartialOrd<Cow<Outer>>> for Inner
和类似的功能。PartialOrdSelfCowAndInnerCow
实现了PartialOrd<Inner> for Cow<Outer>
和类似的功能。- 这是
PartialOrdSelfCowAndInner
的反向(操作数顺序颠倒)版本。
- 这是
Ord
Ord
实现了std::cmp::Ord for Outer
。- 这与
#[derive(Ord)]
非常相似,但它将适用于自定义比较。
- 这与
std::ops
- 一元运算符
取负{,Ref}
非{,Ref}
- 二元运算符
{加,按位与,按位或,按位异或,除,乘,取余,左移,右移,减}{,赋值}{,Ref}{Self,Inner,内部反转}
其他
AsciiExt
实现了std::ascii::AsciiExt for Outer
。DefaultRef
实现了Default for &Outer
。
待办事项
许可证
根据您的选择,许可协议为以下之一:
- Apache License,版本 2.0,(LICENSE-APACHE.txt 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证(LICENSE-MIT.txt 或 https://opensource.org/licenses/MIT)
。
贡献
除非您明确声明,否则根据 Apache-2.0 许可证定义,您有意提交的任何贡献,包括但不限于工作内容,都应作为上述双重许可发布,不附加任何额外条款或条件。