8个版本
0.3.5 | 2021年3月13日 |
---|---|
0.3.4 | 2020年7月21日 |
0.3.2 | 2020年1月11日 |
0.3.1 | 2019年5月25日 |
0.1.0 | 2019年1月21日 |
#491 in 过程宏
24每月下载量
19KB
151 行
tylift
通过添加属性tylift
简单地将枚举变体提升到类型级别。这对于类型级别编程非常有用。
重要提示:此库提供的机制与尚未完全实现的实验性功能const泛型/min const泛型几乎相同。有关更多信息,请参阅以下相应部分。
该属性将枚举变体提升为其自己的类型。枚举类型变为一个种类——类型的类型——通过一个特质来模拟,替换了原始类型声明。在Rust中,特质界限(:
)的语法与类型注解的语法完美地对应。因此,代码片段B: Bool
也可以读作“种类为Bool
的类型参数B
”。
表示种类的特质是密封的,这意味着没有人能够向种类添加新的类型。变体可以持有给定种类类型的(未命名的)字段。应用于项目本身及其变体的属性(特别是文档注释)将被保留。展开的代码在#![no_std]
环境中工作。
目前,没有自动化的方法来具体化提升的变体(即将它们映射到它们的项级别对应物)。提升的枚举类型不能对种类进行泛型。
第一个示例
use tylift::tylift;
use std::marker::PhantomData;
#[tylift]
pub enum Mode {
Safe,
Fast,
}
pub struct Text<M: Mode> {
content: String,
_marker: PhantomData<M>,
}
impl<M: Mode> Text<M> {
pub fn into_inner(self) -> String {
self.content
}
}
impl Text<Safe> {
pub fn from(content: Vec<u8>) -> Option<Self> {
Some(Self {
content: String::from_utf8(content).ok()?,
_marker: PhantomData,
})
}
}
impl Text<Fast> {
pub unsafe fn from(content: Vec<u8>) -> Self {
Self {
content: unsafe { String::from_utf8_unchecked(content) },
_marker: PhantomData,
}
}
}
fn main() {
let safe = Text::<Safe>::from(vec![0x73, 0x61, 0x66, 0x65]);
let fast = unsafe { Text::<Fast>::from(vec![0x66, 0x61, 0x73, 0x74]) };
assert_eq!(safe.map(Text::into_inner), Some("safe".to_owned()));
assert_eq!(fast.into_inner(), "fast".to_owned());
}
安装
将这些行添加到您的Cargo.toml
[dependencies]
tylift = "0.3.5"
目前尚未验证与较旧版本的rustc
的兼容性。此crate的较旧版本(≤ 0.3.2)仅依赖于rustc
1.32的功能。因此,您可能想查看它们。
Cargo功能
功能标志 span_errors
通过利用标记的跨度信息,极大地改进了错误信息。它使用了实验性功能 proc_macro_diagnostic
,因此需要使用夜间的 rustc
。
更多示例
宏展开前的代码
use tylift::tylift;
#[tylift]
pub enum Bool {
False,
True,
}
#[tylift]
pub(crate) enum Nat {
Zero,
Succ(Nat),
}
#[tylift]
enum BinaryTree {
Leaf,
Branch(BinaryTree, Nat, BinaryTree),
}
#[tylift(mod)] // put all 3 items into the module `Power`
pub enum Power {
On,
Off,
}
#[tylift(mod direction)] // put all 3 items into the module `direction`
pub(crate) enum Direction {
/// Higher and higher!
Up,
/// Lower and lower...
Down,
}
以及展开后的代码。它部分符合卫生宏;由于当前 proc_macro
API 的限制,生成的标识符可能是不卫生的,因此使用双下划线(__
)作为前缀以降低名称冲突的可能性。
use tylift::tylift;
pub use __kind_Bool::*;
mod __kind_Bool {
use super::*;
pub trait Bool: sealed::Sealed {}
pub struct False(::core::marker::PhantomData<()>);
impl Bool for False {}
pub struct True(::core::marker::PhantomData<()>);
impl Bool for True {}
mod sealed {
use super::*;
pub trait Sealed {}
impl Sealed for False {}
impl Sealed for True {}
}
}
pub(crate) use __kind_Nat::*;
mod __kind_Nat {
use super::*;
pub trait Nat: sealed::Sealed {}
pub struct Zero(::core::marker::PhantomData<()>);
impl Nat for Zero {}
pub struct Succ<T0: Nat>(::core::marker::PhantomData<(T0)>);
impl<T0: Nat> Nat for Succ<T0> {}
mod sealed {
use super::*;
pub trait Sealed {}
impl Sealed for Zero {}
impl<T0: Nat> Sealed for Succ<T0> {}
}
}
use __kind_BinaryTree::*;
mod __kind_BinaryTree {
use super::*;
pub trait BinaryTree: sealed::Sealed {}
pub struct Leaf(::core::marker::PhantomData<()>);
impl BinaryTree for Leaf {}
pub struct Branch<T0: BinaryTree, T1: Nat, T2: BinaryTree>(
::core::marker::PhantomData<(T0, T1, T2)>,
);
impl<T0: BinaryTree, T1: Nat, T2: BinaryTree> BinaryTree for Branch<T0, T1, T2> {}
mod sealed {
use super::*;
pub trait Sealed {}
impl Sealed for Leaf {}
impl<T0: BinaryTree, T1: Nat, T2: BinaryTree> Sealed for Branch<T0, T1, T2> {}
}
}
pub mod Power {
use super::*;
pub trait Power: sealed::Sealed {}
pub struct On(::core::marker::PhantomData<()>);
impl Power for On {}
pub struct Off(::core::marker::PhantomData<()>);
impl Power for Off {}
mod sealed {
use super::*;
pub trait Sealed {}
impl Sealed for On {}
impl Sealed for Off {}
}
}
pub(crate) mod direction {
use super::*;
pub trait Direction: sealed::Sealed {}
/// Higher and higher!
pub struct Up(::core::marker::PhantomData<()>);
impl Direction for Up {}
/// Lower and lower...
pub struct Down(::core::marker::PhantomData<()>);
impl Direction for Down {}
mod sealed {
use super::*;
pub trait Sealed {}
impl Sealed for Up {}
impl Sealed for Down {}
}
}
手动编写类型级别函数
从类型 Bool
到 Bool
的类型级别函数 Not
(在上一个部分中定义的类型)
type Not<B> = <B as NotImpl>::Result;
trait NotImpl: Bool { type Result: Bool; }
impl NotImpl for False { type Result = True; }
impl NotImpl for True { type Result = False; }
从两个 Nat
到 Nat
的类型级别函数 Add
(在上一个部分中定义的类型)
type Add<N, M> = <N as AddImpl<M>>::Result;
trait AddImpl<M: Nat>: Nat { type Result: Nat }
impl<M: Nat> AddImpl<M> for Zero { type Result = M; }
impl<N: Nat, M: Nat> AddImpl<M> for Succ<N>
// where clause necessary because the type system does not know that
// the trait is sealed (only the module system knows)
where N: AddImpl<Succ<M>>
{
type Result = Add<N, Succ<M>>;
}
tylift 与 Const Generics 的比较
此 crate 与 const generics 相比的优势
- 递归类型,这些类型目前无法用 const generics 来表示。后者还需要 显式装箱
- 与旧版 rust 版本的兼容性
显然,这些并不是 非常 有说服力的论据。请将此 crate 视为一个 研究,而不是有价值的东西。也许你可以从其代码中学习到一些东西。
缺点:
- 需要额外的依赖项(
tylift
),并且对syn
有重的传递依赖 - 较差的工具支持
- 与兼容 const generics 的
const fn
相比,类型级别的函数非常复杂,参见const 可评估检查
未来计划
- 用更合理的示例替换入门示例
- 创建测试
- 添加其他功能,例如
- 一个属性,用于将函数提升到类型级别
- 生成实现函数
- 一旦
proc_macro_diagnostic
变得稳定,就移除功能门span_errors
依赖项
~1.5MB
~36K SLoC