struct_to_enum/lib.rs
1#![no_std]
2
3#[cfg(feature = "derive")]
4pub use struct_to_enum_macros::*;
5
6/// Implemented by structs that have a `FieldName` enum generated by the [`FieldName`] derive macro.
7///
8/// `N` is the number of non-skipped fields + nested fields, resolved at compile time. Deriving `FieldName` on a
9/// struct `Foo` with `N` non-skipped fields generates:
10///
11/// ```ignore
12/// impl FieldNames<N> for Foo {
13/// type FieldName = FooFieldName;
14/// fn field_names() -> [FooFieldName; N] { ... }
15/// }
16/// ```
17///
18/// Call [`field_names`](FieldNames::field_names) to get an ordered array of all field-name
19/// variants without needing a struct instance.
20/// Ordered by field declaration order.
21///
22/// # Example
23///
24/// ```rust
25/// use struct_to_enum::{FieldName, FieldNames};
26///
27/// #[derive(FieldName)]
28/// struct Point {
29/// x: f32,
30/// y: f32,
31/// }
32///
33/// let names: [PointFieldName; 2] = Point::field_names();
34/// assert_eq!(names, [PointFieldName::X, PointFieldName::Y]);
35/// ```
36pub trait FieldNames<const N: usize> {
37 type FieldName;
38
39 // can't use const generics in trait bounds yet (requires nightly)
40 // #![feature(generic_const_exprs)]
41 // const N: usize;
42
43 /// Returns all field-name enum variants in field declaration order.
44 ///
45 /// NOTE: This method will be made `const` once `const_trait_impl` is stabilised.
46 /// Tracking issue: <https://github.com/rust-lang/rust/issues/67792>
47 fn field_names() -> [Self::FieldName; N];
48}
49
50#[cfg(test)]
51mod tests {
52 use crate::FieldNames;
53
54 #[derive(Debug, PartialEq, Clone, Copy)]
55 pub struct Test {
56 pub a: i32,
57 pub b: i32,
58 }
59
60 #[derive(Debug, PartialEq, Clone, Copy)]
61 pub enum TestFieldName {
62 A,
63 B,
64 }
65
66 impl FieldNames<2> for Test {
67 type FieldName = TestFieldName;
68 fn field_names() -> [Self::FieldName; 2] {
69 [TestFieldName::A, TestFieldName::B]
70 }
71 }
72
73 #[test]
74 pub fn test_field_names() {
75 let _test = Test { a: 0, b: 0 };
76 let _a: TestFieldName = <Test as FieldNames<2>>::FieldName::A;
77 assert_eq!(Test::field_names(), [TestFieldName::A, TestFieldName::B]);
78 }
79}