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日 |
#6 在 #typedef
139 每月下载量
170KB
3.5K SLoC
opaque_typedef
opaque_typedef:
opaque_typedef_macros:
这是一个针对 Rust编程语言 的进程宏crate。
此crate帮助开发者轻松定义不透明类型定义(强类型定义)类型,减少样板代码。
注意:此库处于开发中且不稳定。
不透明类型定义
您可能希望定义一个新的类型,其内部表示与其它类型相同,但没有隐式类型转换。实际例子
UncasedStr
在 rocket crate 中(其内部表示为str
)NotNaN
在 ordered_float crate 中(其内部表示为浮点数字类型(通常是f32
和f64
)
这些类型通常对内部类型(例如,UncasedStr
具有较宽松的比较函数,而 NotNan
不能包含 NaN)有额外的限制,并且你可能想实现一些特质,而不想实现其他特质(例如,你可能想实现 From<&str> for &UncasedStr
,但不想为 Deref<Target=str> for UncasedStr
实现)。
opaque_typedef crate 帮助您为您的类型“推导”特定的特质(即重用为内部类型实现的特质)。
要查看示例,请参阅 opaque_typedef_tests/src/
目录下的文件。
术语
考虑以下代码:
- 内部类型表示
Inner
类型。 - 外部类型表示
Outer
类型。 Outer
是Inner
的 opaque typedef(强类型别名)。- 无大小类型表示
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))]
的 "derive"。
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(...))]
指定 "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 使用内部类型作为默认解引用目标类型,但您可以使用不同的类型,如上例所示。
目标
:- 解引用目标类型。
deref
:- 将内部类型引用转换为外部类型引用的转换函数。
- 该函数应实现
Fn(&Inner) -> &DerefTarget
。
deref_mut
:- 将内部类型可变引用转换为外部类型可变引用的转换函数。
- 该函数应实现
Fn(&mut Inner) -> &mut DerefTarget
。
在示例中,AsMutInner
实现 AsMut<String> for MyString
,而 AsMutDeref
实现 AsMut<str> for MyString
。
如果不指定 #[opaque_typedef)
,则不会使用 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
,类型转换
如{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
的反向版本(操作数顺序颠倒)。
- 这是
PartialEqSelfCowRev
实现了PartialEq<Outer> for Cow<Outer>
以及类似的接口。PartialEqSelfCowRev
是PartialEqSelfCow
的反向版本(操作数顺序颠倒)。PartialEqSelfCowRev
实现了PartialEq<Outer> for Cow<Outer>
以及类似的接口。
- 这是
PartialEqSelfCowRev
的反向版本(操作数顺序颠倒)。 PartialEqSelfCowRev
实现了PartialEq<Outer> for Cow<Outer>
以及类似的接口。- 这是
PartialEqSelfCowRev
的反向版本(操作数顺序颠倒)。
- 这是
PartialEqSelfCowRev
实现了PartialEq<Outer> for Cow<Outer>
以及类似的接口。- 这是
PartialEqSelfCowRev
的反向版本(操作数顺序颠倒)。PartialEqSelfCowRev
实现了PartialEq<Outer> for Cow<Outer>
以及类似的接口。
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://www.apache.org/licenses/LICENSE-2.0 )
- MIT 许可证 (LICENSE-MIT.txt 或 https://opensource.org/licenses/MIT )
。
贡献
除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交以包含在该作品中的任何贡献,将双重许可如上所述,没有任何附加条款或条件。
依赖项
~2.5MB
~53K SLoC