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,DerefMutDeref实现了std::ops::Deref for Outer。DerefMut实现了std::ops::DerefMut for Outer。
Into{Arc,Box,Inner,Rc},FromInnerIntoArc实现了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的反向(操作数顺序颠倒)版本。
- 这是
OrdOrd实现了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://open-source.org.cn/licenses/MIT )
。
贡献
除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交以包含在该作品中的任何贡献,将双重许可如上所述,没有任何附加条款或条件。
依赖项
~2.5MB
~53K SLoC