codama_nodes/type_nodes/
sentinel_type_node.rs1use crate::{
2 ConstantValueNode, NestedTypeNode, NestedTypeNodeTrait, TypeNode, TypeNodeTrait,
3 TypeNodeUnionTrait,
4};
5use codama_errors::{CodamaError, CodamaResult};
6use codama_nodes_derive::nestable_type_node;
7
8#[nestable_type_node]
9pub struct SentinelTypeNode<T: TypeNodeUnionTrait> {
10 #[serde(bound = "T: TypeNodeUnionTrait")]
12 pub r#type: Box<T>,
13 pub sentinel: ConstantValueNode,
14}
15
16impl From<SentinelTypeNode<crate::TypeNode>> for crate::Node {
17 fn from(val: SentinelTypeNode<crate::TypeNode>) -> Self {
18 crate::Node::Type(val.into())
19 }
20}
21
22impl<T: TypeNodeTrait> From<SentinelTypeNode<NestedTypeNode<T>>> for SentinelTypeNode<TypeNode> {
23 fn from(node: SentinelTypeNode<NestedTypeNode<T>>) -> Self {
24 SentinelTypeNode {
25 r#type: Box::new(TypeNode::from(*node.r#type)),
26 sentinel: node.sentinel,
27 }
28 }
29}
30
31impl<T: TypeNodeTrait> TryFrom<SentinelTypeNode<TypeNode>> for SentinelTypeNode<NestedTypeNode<T>> {
32 type Error = CodamaError;
33 fn try_from(node: SentinelTypeNode<TypeNode>) -> CodamaResult<Self> {
34 Ok(SentinelTypeNode {
35 r#type: Box::new(NestedTypeNode::try_from(*node.r#type)?),
36 sentinel: node.sentinel,
37 })
38 }
39}
40
41impl<T: TypeNodeUnionTrait> SentinelTypeNode<T> {
42 pub fn new<U>(r#type: U, sentinel: ConstantValueNode) -> Self
43 where
44 U: Into<T>,
45 {
46 Self {
47 r#type: Box::new(r#type.into()),
48 sentinel,
49 }
50 }
51}
52
53impl<T: TypeNodeTrait> NestedTypeNodeTrait<T> for SentinelTypeNode<NestedTypeNode<T>> {
54 type Mapped<U: TypeNodeTrait> = SentinelTypeNode<NestedTypeNode<U>>;
55
56 fn get_nested_type_node(&self) -> &T {
57 self.r#type.get_nested_type_node()
58 }
59
60 fn try_map_nested_type_node<U: TypeNodeTrait, F: FnOnce(T) -> CodamaResult<U>>(
61 self,
62 f: F,
63 ) -> CodamaResult<Self::Mapped<U>> {
64 Ok(SentinelTypeNode {
65 r#type: Box::new(self.r#type.try_map_nested_type_node(f)?),
66 sentinel: self.sentinel,
67 })
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use crate::{Base16, NestedTypeNode, StringTypeNode, TypeNode};
75
76 #[test]
77 fn new_type_node() {
78 let node = SentinelTypeNode::<TypeNode>::new(
79 StringTypeNode::utf8(),
80 ConstantValueNode::bytes(Base16, "ffff"),
81 );
82 assert_eq!(*node.r#type, TypeNode::String(StringTypeNode::utf8()));
83 assert_eq!(node.sentinel, ConstantValueNode::bytes(Base16, "ffff"));
84 }
85
86 #[test]
87 fn new_nested_type_node() {
88 let node = SentinelTypeNode::<NestedTypeNode<StringTypeNode>>::new(
89 StringTypeNode::utf8(),
90 ConstantValueNode::bytes(Base16, "ffff"),
91 );
92 assert_eq!(*node.r#type, NestedTypeNode::Value(StringTypeNode::utf8()));
93 assert_eq!(node.get_nested_type_node(), &StringTypeNode::utf8());
94 assert_eq!(node.sentinel, ConstantValueNode::bytes(Base16, "ffff"));
95 }
96
97 #[test]
98 fn to_json() {
99 let node = SentinelTypeNode::<TypeNode>::new(
100 StringTypeNode::utf8(),
101 ConstantValueNode::bytes(Base16, "ffff"),
102 );
103 let json = serde_json::to_string(&node).unwrap();
104 assert_eq!(
105 json,
106 r#"{"kind":"sentinelTypeNode","type":{"kind":"stringTypeNode","encoding":"utf8"},"sentinel":{"kind":"constantValueNode","type":{"kind":"bytesTypeNode"},"value":{"kind":"bytesValueNode","data":"ffff","encoding":"base16"}}}"#
107 );
108 }
109
110 #[test]
111 fn from_json() {
112 let json = r#"{"kind":"sentinelTypeNode","type":{"kind":"stringTypeNode","encoding":"utf8"},"sentinel":{"kind":"constantValueNode","type":{"kind":"bytesTypeNode"},"value":{"kind":"bytesValueNode","data":"ffff","encoding":"base16"}}}"#;
113 let node: SentinelTypeNode<TypeNode> = serde_json::from_str(json).unwrap();
114 assert_eq!(
115 node,
116 SentinelTypeNode::<TypeNode>::new(
117 StringTypeNode::utf8(),
118 ConstantValueNode::bytes(Base16, "ffff"),
119 )
120 );
121 }
122}