#不透明 #强类型 #推导 #类型定义 #过程宏

opaque_typedef

支持定义不透明类型定义

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 模式

Download history 1530/week @ 2023-12-04 1746/week @ 2023-12-11 1436/week @ 2023-12-18 820/week @ 2023-12-25 979/week @ 2024-01-01 1662/week @ 2024-01-08 1928/week @ 2024-01-15 1491/week @ 2024-01-22 2266/week @ 2024-01-29 1865/week @ 2024-02-05 2497/week @ 2024-02-12 2392/week @ 2024-02-19 2216/week @ 2024-02-26 1897/week @ 2024-03-04 2062/week @ 2024-03-11 1637/week @ 2024-03-18

7,941 每月下载量

MIT/Apache

23KB

opaque_typedef

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

这是一个用于 Rust 编程语言的 proc-macro 仓库。

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

注意:这个库正在开发中且不稳定。

不透明类型定义

你可能想定义一个新的类型,与其它类型具有相同的内部表示,但没有隐式类型转换。现实世界例子

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

opaque_typedef 仓库帮助你为你的类型“推导”特定的特性(即重用内部类型实现的特性)。

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

术语

Think structOuter(Inner);

  • 内部类型指的是Inner类型。
  • 外部类型指的是Outer类型。
  • OuterInner不透明类型定义(强类型定义)。
  • 未指定大小的类型意味着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))]之类的操作。

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(...))]

/// 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.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,类型转换

  • As{Mut,Ref}{Deref,Inner,Self}
    • AsMutDerefAsMut<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

待办事项

  • 更多特性
    • 仅在夜间可用的特性(TryFromTryInto 等)(#6
  • 支持具有多个字段的类型(#9

许可证

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

贡献

除非您明确声明,否则根据 Apache-2.0 许可证定义,您有意提交的任何贡献,包括但不限于工作内容,都应作为上述双重许可发布,不附加任何额外条款或条件。

无运行时依赖