#opaque #derive #strong #typedef

opaque_typedef_macros

支持定义不透明类型定义

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

Download history 28/week @ 2023-11-26 31/week @ 2023-12-03 23/week @ 2023-12-10 37/week @ 2023-12-17 3/week @ 2023-12-24 3/week @ 2024-01-07 8/week @ 2024-01-14 5/week @ 2024-01-21 18/week @ 2024-02-11 29/week @ 2024-02-18 41/week @ 2024-02-25 43/week @ 2024-03-03 24/week @ 2024-03-10

139 每月下载量

MIT/Apache

170KB
3.5K SLoC

opaque_typedef

Build Status
opaque_typedef: 最新版本 文档
opaque_typedef_macros: 最新版本

这是一个针对 Rust编程语言 的进程宏crate。

此crate帮助开发者轻松定义不透明类型定义(强类型定义)类型,减少样板代码。

注意:此库处于开发中且不稳定。

不透明类型定义

您可能希望定义一个新的类型,其内部表示与其它类型相同,但没有隐式类型转换。实际例子

这些类型通常对内部类型(例如,UncasedStr 具有较宽松的比较函数,而 NotNan 不能包含 NaN)有额外的限制,并且你可能想实现一些特质,而不想实现其他特质(例如,你可能想实现 From<&str> for &UncasedStr,但不想为 Deref<Target=str> for UncasedStr 实现)。

opaque_typedef crate 帮助您为您的类型“推导”特定的特质(即重用为内部类型实现的特质)。

要查看示例,请参阅 opaque_typedef_tests/src/ 目录下的文件。

术语

考虑以下代码:

  • 内部类型表示 Inner 类型。
  • 外部类型表示 Outer 类型。
  • OuterInneropaque typedef(强类型别名)。
  • 无大小类型表示 str[i32] 或其他(通常是切片类型)。
  • 有大小类型表示 Stringi32&u8 或其他。

如何使用

示例在 opaque_typedef_tests/src/

1. 指定 "extern crate"

Cargo.toml:

[dependencies]
opaque_typedef = "^0.0.4"
opaque_typedef_macros = "^0.0.4"

lib.rsmain.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 继承可能返回内部值可变引用的特质(例如 DerefMutAsMut)或可能修改内部值的特质(例如 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. 指定解引用目标(可选)

如果您指定了 DerefDerefMutAsRefDeref 或与 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.rsopaque_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. 指定自定义比较器(可选)

您可以使用自定义实现来为PartialEqPartialOrd

要使用自定义比较器,请指定以下属性:

  • 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.rsopaque_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
  • DerefDerefMut
    • 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> 以及类似的接口。
    • PartialEqSelfCowRevPartialEqSelfCow 的反向版本(操作数顺序颠倒)。
      • 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

待办事项

  • 更多特质
    • 夜间仅有的特质(TryFromTryInto,...) (#6)
  • 支持具有多个字段的数据类型 (#9)

许可证

根据您的选择,许可协议为以下之一

贡献

除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交以包含在该作品中的任何贡献,将双重许可如上所述,没有任何附加条款或条件。

依赖项

~2.5MB
~53K SLoC