Skip to main content

struct_to_enum/
lib.rs

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