#struct #nested #api-response #macro #syntax #serde #named-fields

nestify

Nestify 提供了一个宏,用于简化并美化 Rust 中嵌套结构体的定义,使代码结构更清晰、可读性更高,减少了冗余。它特别适用于处理 API 响应。

6 个版本

0.3.3 2024 年 3 月 31 日
0.3.2 2024 年 3 月 29 日
0.2.1 2023 年 10 月 15 日
0.1.1 2023 年 9 月 28 日

#91 in 过程宏

Download history 178/week @ 2024-04-14 276/week @ 2024-04-21 253/week @ 2024-04-28 147/week @ 2024-05-05 162/week @ 2024-05-12 264/week @ 2024-05-19 143/week @ 2024-05-26 172/week @ 2024-06-02 501/week @ 2024-06-09 365/week @ 2024-06-16 352/week @ 2024-06-23 499/week @ 2024-06-30 870/week @ 2024-07-07 671/week @ 2024-07-14 749/week @ 2024-07-21 558/week @ 2024-07-28

2,862 每月下载量
用于 3 crates

MIT 许可证

81KB
1.5K SLoC

Nestify

Nestify 是一个 Rust 库,提供强大的宏来简化嵌套结构和枚举的定义。旨在提高代码的可读性和可维护性

crates.io github License

摘要

Nestify 使用“类型即定义”的方法重新构想 Rust 的结构体和枚举定义,简化了处理嵌套结构的方式。不再需要频繁地在类型定义之间切换——Nestify 统一了您的代码库,使您的代码更整洁、更易于阅读。

Nestify 旨在易于学习,其语法专为 Rust 开发者量身定制。目标是让任何人在初次看到 Nest 宏时就能迅速掌握其概念。

功能

  • 简化 Rust 中嵌套结构体和枚举的定义。
  • 使代码库更易于阅读,减少冗余。
  • 非常适合模拟复杂的 API 响应。
  • 高级属性修饰符。
  • 与 Serde 兼容。
  • 直观的语法

安装

将此添加到您的 Cargo.toml

[dependencies]
nestify = "0.3.3"

然后使用宏

use nestify::nest;

[!NOTE] 夜间工具链可能提供更好的错误诊断

快速示例

简单的嵌套结构体

以下是一个快速示例,展示 Nestify 如何简化嵌套结构体的定义

// Define a user profile with nested address and preferences structures
nest! {
    struct UserProfile {
        name: String,
        address: struct Address {
            street: String,
            city: String,
        },
        preferences: struct Preferences {
            newsletter: bool,
        },
    }
}
展开
struct UserProfile {
    name: String,
    address: Address,
    preferences: Preferences,
}

struct Address {
    street: String,
    city: String,
}

struct Preferences {
    newsletter: bool,
}

简单的嵌套枚举

// Define a task with a nested status enum
nest! {
    struct Task {
        id: i32,
        description: String,
        status: enum Status {
            Pending,
            InProgress,
            Completed,
        },
    }
}
展开
struct Task {
    id: i32,
    description: String,
    status: Status,
}

enum Status {
    Pending,
    InProgress,
    Completed,
}

支持的定义

Nestify 支持结构体和枚举。

// field structs (named)
nest! {
    struct Named {
        f: struct Nested {}
    }
}

// tuple structs (unnamed)
nest! {
    struct Unnamed(struct Nested())
}

// unit structs
nest! {
    struct Unit {
        unit: struct UnitStruct
    }
}


// enums
nest! {
    enum EnumVariants {
        Unit,
        Tuple(i32, struct TupleNested),
        Struct {
            f1: i32,

        }
        DiscriminantVariant = 1,
    }
}
// note: any variant can have a discriminant
// just as in normal rust
展开
// field structs (named)
struct Named {
    f: Nested,
}
struct Nested {}

// tuple structs (unnamed)
struct Unnamed(Nested,);
struct Nested();

// unit structs
struct Unit {
    unit: UnitStruct,
}
struct UnitStruct;


// enums
enum EnumVariants {
    Unit,
    Tuple(i32, TupleNested),
    Struct { 
        f1: i32 
    },
    DiscriminantVariant = 1,
}
struct TupleNested;

泛型

Nestify 完全支持 Rust 的泛型参数。这种兼容性确保您可以在嵌套结构体定义中结合生命周期和类型参数,就像在标准 Rust 代码中一样。

nest! {
    struct Example<'a, T> {
        s: &'a str,
        t: T
    }
}
展开
struct Example<'a, T> { 
    s: &'a str, 
    t: T, 
}

嵌套泛型

在定义嵌套泛型时,您需要将泛型添加到类型中。使用 "FishHook" 语法。要在字段上定义泛型,请使用以下代码:||<...>。这将允许您指定嵌套泛型类型。如果需要,它也可以与生命周期一起使用。

nest! {
    struct Parent<'a> {
        child : struct Child<'c, C> {
            s: &'c str,
            f: C
        } ||<'a, i32>
    }
}
展开
struct Parent<'a> {
    child: Child<'a, i32>,
    //           ^^^^^^^^ FishHook expands to this part
}

struct Child<'c, C> {
    s: &'c str,
    f: C,
}

属性

您可以使用与普通结构体相同的方式应用属性。

nest! {
    #[derive(Clone)]
    struct CloneMe {}
}

let x = CloneMe {};
let cl = x.clone();

递归属性 #[meta]*

使用 * 语法,您可以轻松地将属性继承到子结构中。该属性将传播到每个嵌套结构或枚举。

nest! {
    #[apply_all]*
    struct One {
        two: struct Two {
            three: struct Three {
                payload: ()
            }
        }
    }
}
展开
#[apply_all]
struct One {
    two: Tow,
}

#[apply_all]
struct Two {
    three: Three,
}

#[apply_all]
struct Three {
    payload: (),
}

删除语法

禁用传播 #[meta]/

您可以使用 / 属性修饰符结束属性的递归。它将从当前结构及其所有嵌套结构中删除递归属性。

nest! {
    #[nest]*
    struct One {
        two: struct Two {
            three: #[nest]/ 
            struct Three {
                four: struct Four { }
            }
        }
    }
}
展开
#[nest]
struct One {
    two: Two,
}

#[nest]
struct Two {
    three: Three,
}

struct Three {
    four: Four,
}

struct Four {}

禁用单个 #[meta]-

使用 - 修饰符将删除单个结构中的递归属性。要使用前面的示例,请用 - 替换 /

nest! {
    #[nest]*
    struct One {
        two: struct Two {
            three: #[nest]- 
            struct Three {
                four: struct Four { }
            }
        }
    }
}
展开
#[nest]
struct One {
    two: Two,
}

#[nest]
struct Two {
    three: Three,
}

struct Three {
    four: Four,
}

#[nest]
struct Four {}

字段属性 #>[meta]

如果您的结构体定义了多个属性,那么在嵌套结构之前定义属性可能会变得很尴尬。为了解决这个问题,您可以在字段和枚举变体之前定义应用于嵌套对象的属性。这可以通过使用 #>[meta] 语法来实现。这将把属性应用到下一个结构体。

nest! {
    struct MyStruct {
        #>[derive(Debug)]
        f: struct DebugableStruct { } 
        // equivlent to: 
        // f: #[derive(Debug)]
        // struct DebugableStruct { }
    }
}
展开
struct MyStruct {
    f: DebugableStruct,
}

#[derive(Debug)]
//       ^^^^^ applied to structure and not field `f`
struct DebugableStruct {}

枚举变体属性

字段属性也可以应用到枚举变体上。如果在一个单一的变体中定义了多个项,则属性将应用到每一个上。

nest! {
    enum MyEnum {
        #>[derive(Debug)]
        Variant {
            // #[derive(Debug)
            one: struct One,
            // #[derive(Debug)
            two: struct Two
        }
    }
}
展开
enum MyEnum {
    Variant {
        one: One,
        two: Two,
    }
}

#[derive(Debug)]
struct One;

#[derive(Debug)]
struct Two;

分号

Rust 强制使用分号来标记元组和单元结构声明的结束。然而,Nestify 通过使该分号可选,引入了灵活性。

Rust 标准

  • 元组结构体:struct MyTuple;
  • 单元结构体:struct MyUnit;

内嵌灵活性

使用 Nestify,您可以省略分号而不影响任何内容。

// Unit struct without a semicolon
nest! {
    struct MyUnit
}

// Tuple struct without a semicolon
nest! {
    struct MyTuple(i32, String)
}
展开
struct MyUnit;
//           ^ automaticly added

struct MyTuple(i32, String);
//                         ^ automaticly added

这种调整简化了语法,特别是在定义嵌套结构时,与 Nestify 的目标——提高代码的可读性和可维护性相一致。无论是否包含分号,Nestify 都能正确处理定义,这得益于其领域特定的优化。

可见性

可见性可以在父结构和嵌套结构中改变。它表现出以下行为

命名字段可见性

在使用命名字段时,您必须在字段和定义之前指定所需的可见性。

nest! {
    pub struct One {
        pub two: pub struct Two
        //|      ^^^ visibility applied to definition (b)
        //|> visibility applied to field (a)
    }
}
展开
pub struct One { 
    pub two: Two,
    //^ (a)
}

pub struct Two;
//^ (b)

未命名字段可见性

未命名字段将可见性应用于字段和项目。

nest! {
    pub struct One(pub struct Two)
    //             ^^^ visibility applied to both field and struct
}
展开
pub struct One(pub Two);
//             ^^^ applied here

pub struct Two;
//^ and here

枚举变体

枚举变体的可见性仅应用于结构。这是因为变体继承了枚举的基本可见性。有关更多信息,请参阅 E0449

nest! {
    pub enum One {
        Two(pub struct Two)
        //  ^^^ will apply to the structure
    }
}
展开
pub enum One { 
    Two(Two) 
}

pub struct Two;
//^ applied to structure

泛型容器

Nestify 还支持在泛型容器内部定义嵌套结构,例如 Vec<T>Option<T>Result<T, E>

struct One(Vec<struct Two { field: i32 }>);
展开
struct One(Vec<Two>);

struct Two {
    field: i32,
}

在此,struct Two 是在 Vec<T> 的泛型参数内直接定义的。

另一个示例

为了进一步说明,考虑一个场景,您想在另一个结构中包含一个可选的配置结构

struct AppConfig(Option<struct DatabaseConfig { url: String }>);
展开
struct AppConfig(Option<DatabaseConfig>);

struct DatabaseConfig {
    url: String,
}

在此示例中,struct DatabaseConfig 是在 AppConfig 的声明中直接在 Option<T> 泛型类型内定义的。

限制

不支持其他类型的间接引用,例如在 &&mut 之后,在固定大小数组 [_, N] 或动态大小数组 [_] 内部,元组和可能还有很多其他情况。如果您需要此类间接引用,请随时贡献以添加对其的支持。


贡献

我喜欢贡献者!此外,我是个糟糕的作家,所以我非常希望社区支持来改进这份指南。

[!IMPORTANT] 虽然不是必需的,但强烈建议您在实现功能之前先 提交一个问题联系我,以提高被接受的最佳机会

进行代码更改

  1. 分支存储库。
  2. 为您的功能或错误修复创建一个新分支。
  3. 为您的更改编写测试。
  4. 确保所有测试通过。
  5. 提交一个拉取请求。

标准操作!

许可证

本项目采用 MIT 许可证。如果您需要其他许可证,请 联系我。MIT 许可证支持将始终得到维护。不要害怕!

联系我

查看 GitHub 以获取信息 @snowfoxsh

依赖项

~305–760KB
~18K SLoC