codama_nodes/value_nodes/
enum_value_node.rs

1use crate::{CamelCaseString, DefinedTypeLinkNode, StructValueNode, TupleValueNode};
2use codama_nodes_derive::{node, node_union};
3
4#[node]
5pub struct EnumValueNode {
6    // Data.
7    pub variant: CamelCaseString,
8
9    // Children.
10    pub r#enum: DefinedTypeLinkNode,
11    #[serde(skip_serializing_if = "crate::is_default")]
12    pub value: Option<EnumVariantData>,
13}
14
15impl From<EnumValueNode> for crate::Node {
16    fn from(val: EnumValueNode) -> Self {
17        crate::Node::Value(val.into())
18    }
19}
20
21impl EnumValueNode {
22    pub fn new<T, U>(r#enum: T, variant: U, value: Option<EnumVariantData>) -> Self
23    where
24        T: Into<DefinedTypeLinkNode>,
25        U: Into<CamelCaseString>,
26    {
27        Self {
28            variant: variant.into(),
29            r#enum: r#enum.into(),
30            value,
31        }
32    }
33
34    pub fn empty<T, U>(r#enum: T, variant: U) -> Self
35    where
36        T: Into<DefinedTypeLinkNode>,
37        U: Into<CamelCaseString>,
38    {
39        Self {
40            variant: variant.into(),
41            r#enum: r#enum.into(),
42            value: None,
43        }
44    }
45
46    pub fn fields<T, U, V>(r#enum: T, variant: U, value: V) -> Self
47    where
48        T: Into<DefinedTypeLinkNode>,
49        U: Into<CamelCaseString>,
50        V: Into<StructValueNode>,
51    {
52        Self {
53            variant: variant.into(),
54            r#enum: r#enum.into(),
55            value: Some(EnumVariantData::Struct(value.into())),
56        }
57    }
58
59    pub fn tuple<T, U, V>(r#enum: T, variant: U, value: V) -> Self
60    where
61        T: Into<DefinedTypeLinkNode>,
62        U: Into<CamelCaseString>,
63        V: Into<TupleValueNode>,
64    {
65        Self {
66            variant: variant.into(),
67            r#enum: r#enum.into(),
68            value: Some(EnumVariantData::Tuple(value.into())),
69        }
70    }
71}
72
73#[node_union]
74pub enum EnumVariantData {
75    Struct(StructValueNode),
76    Tuple(TupleValueNode),
77}
78
79#[cfg(test)]
80mod tests {
81    use crate::{NumberValueNode, StringValueNode, StructFieldValueNode};
82
83    use super::*;
84
85    #[test]
86    fn new() {
87        let node = EnumValueNode::new("direction", "north", None);
88        assert_eq!(node.r#enum, DefinedTypeLinkNode::new("direction"));
89        assert_eq!(node.variant, CamelCaseString::from("north"));
90        assert_eq!(node.value, None);
91    }
92
93    #[test]
94    fn empty() {
95        let node = EnumValueNode::empty("command", "exit");
96        assert_eq!(node.r#enum, DefinedTypeLinkNode::new("command"));
97        assert_eq!(node.variant, CamelCaseString::from("exit"));
98        assert_eq!(node.value, None);
99    }
100
101    #[test]
102    fn fields() {
103        let node = EnumValueNode::fields(
104            "command",
105            "move",
106            vec![
107                StructFieldValueNode::new("x", NumberValueNode::new(10)),
108                StructFieldValueNode::new("y", NumberValueNode::new(20)),
109            ],
110        );
111        assert_eq!(node.r#enum, DefinedTypeLinkNode::new("command"));
112        assert_eq!(node.variant, CamelCaseString::from("move"));
113        assert_eq!(
114            node.value,
115            Some(EnumVariantData::Struct(StructValueNode::new(vec![
116                StructFieldValueNode::new("x", NumberValueNode::new(10)),
117                StructFieldValueNode::new("y", NumberValueNode::new(20)),
118            ])))
119        );
120    }
121
122    #[test]
123    fn tuple() {
124        let node = EnumValueNode::tuple(
125            "command",
126            "write",
127            vec![StringValueNode::new("Hello World").into()],
128        );
129        assert_eq!(node.r#enum, DefinedTypeLinkNode::new("command"));
130        assert_eq!(node.variant, CamelCaseString::from("write"));
131        assert_eq!(
132            node.value,
133            Some(EnumVariantData::Tuple(TupleValueNode::new(vec![
134                StringValueNode::new("Hello World").into()
135            ])))
136        );
137    }
138
139    #[test]
140    fn to_json() {
141        let node = EnumValueNode::empty("command", "exit");
142        let json = serde_json::to_string(&node).unwrap();
143        assert_eq!(
144            json,
145            r#"{"kind":"enumValueNode","variant":"exit","enum":{"kind":"definedTypeLinkNode","name":"command"}}"#
146        );
147    }
148
149    #[test]
150    fn from_json() {
151        let json = r#"{"kind":"enumValueNode","variant":"exit","enum":{"kind":"definedTypeLinkNode","name":"command"}}"#;
152        let node: EnumValueNode = serde_json::from_str(json).unwrap();
153        assert_eq!(node, EnumValueNode::empty("command", "exit"));
154    }
155}