Skip to main content

lisette_syntax/
attributes.rs

1//! Canonical catalog of recognized attributes, shared by the `unknown_attribute`
2//! lint and LSP completions.
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum AttributeTarget {
6    Struct,
7    StructField,
8    Enum,
9    /// A function or an `impl`/`interface` method.
10    Function,
11}
12
13pub struct AttributeInfo {
14    pub name: &'static str,
15    pub detail: &'static str,
16    targets: &'static [AttributeTarget],
17}
18
19impl AttributeInfo {
20    pub fn applies_to(&self, target: AttributeTarget) -> bool {
21        self.targets.contains(&target)
22    }
23}
24
25use AttributeTarget::*;
26
27pub const SERIALIZATION_KEYS: &[&str] = &[
28    "json",
29    "xml",
30    "yaml",
31    "toml",
32    "db",
33    "bson",
34    "mapstructure",
35    "msgpack",
36];
37
38/// In `unknown_attribute` display order. `#[go(...)]` is accepted (see
39/// [`is_known_attribute`]) but deliberately not advertised here.
40pub const ATTRIBUTES: &[AttributeInfo] = &[
41    AttributeInfo {
42        name: "json",
43        detail: "JSON serialization tag",
44        // Enums support `#[json]` (Marshal/UnmarshalJSON); other keys do not.
45        targets: &[Struct, StructField, Enum],
46    },
47    AttributeInfo {
48        name: "xml",
49        detail: "XML serialization tag",
50        targets: &[Struct, StructField],
51    },
52    AttributeInfo {
53        name: "yaml",
54        detail: "YAML serialization tag",
55        targets: &[Struct, StructField],
56    },
57    AttributeInfo {
58        name: "toml",
59        detail: "TOML serialization tag",
60        targets: &[Struct, StructField],
61    },
62    AttributeInfo {
63        name: "db",
64        detail: "database column tag",
65        targets: &[Struct, StructField],
66    },
67    AttributeInfo {
68        name: "bson",
69        detail: "BSON serialization tag",
70        targets: &[Struct, StructField],
71    },
72    AttributeInfo {
73        name: "mapstructure",
74        detail: "mapstructure decoding tag",
75        targets: &[Struct, StructField],
76    },
77    AttributeInfo {
78        name: "msgpack",
79        detail: "MessagePack serialization tag",
80        targets: &[Struct, StructField],
81    },
82    AttributeInfo {
83        name: "tag",
84        detail: "Go struct tag (struct-level defaults or per-field)",
85        targets: &[Struct, StructField],
86    },
87    AttributeInfo {
88        name: "allow",
89        detail: "suppress a lint",
90        targets: &[Function],
91    },
92    AttributeInfo {
93        name: "iterate",
94        detail: "synthesize `variants` for an enum",
95        targets: &[Enum],
96    },
97    AttributeInfo {
98        name: "display",
99        detail: "derive `to_string`",
100        targets: &[Struct, Enum],
101    },
102];
103
104/// `go` is accepted but absent from [`ATTRIBUTES`] (the Go-interop rail).
105pub fn is_known_attribute(name: &str) -> bool {
106    name == "go" || ATTRIBUTES.iter().any(|a| a.name == name)
107}
108
109pub fn is_serialization_key(key: &str) -> bool {
110    SERIALIZATION_KEYS.contains(&key)
111}
112
113pub fn known_attribute_names() -> Vec<&'static str> {
114    ATTRIBUTES.iter().map(|a| a.name).collect()
115}
116
117pub fn attributes_for(target: AttributeTarget) -> impl Iterator<Item = &'static AttributeInfo> {
118    ATTRIBUTES.iter().filter(move |a| a.applies_to(target))
119}