lex_extension/wire/
ctx.rs1use serde::{Deserialize, Serialize};
4
5use super::ast::WireNode;
6use super::range::Range;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11pub struct LabelCtx {
12 pub label: String,
14 pub params: serde_json::Value,
18 pub body: AnnotationBody,
20 pub node: NodeRef,
22}
23
24#[derive(Debug, Clone, PartialEq)]
27pub enum AnnotationBody {
28 None,
30 Text(String),
32 Lex { children: Vec<WireNode> },
35}
36
37impl AnnotationBody {
38 pub fn is_none(&self) -> bool {
40 matches!(self, Self::None)
41 }
42}
43
44impl Serialize for AnnotationBody {
45 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
46 where
47 S: serde::Serializer,
48 {
49 use serde::ser::SerializeMap;
50 match self {
51 Self::None => serializer.serialize_none(),
52 Self::Text(s) => serializer.serialize_str(s),
53 Self::Lex { children } => {
54 let mut map = serializer.serialize_map(Some(2))?;
55 map.serialize_entry("kind", "block")?;
56 map.serialize_entry("children", children)?;
57 map.end()
58 }
59 }
60 }
61}
62
63impl<'de> Deserialize<'de> for AnnotationBody {
64 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
65 where
66 D: serde::Deserializer<'de>,
67 {
68 let value = serde_json::Value::deserialize(deserializer)?;
69 match value {
70 serde_json::Value::Null => Ok(Self::None),
71 serde_json::Value::String(s) => Ok(Self::Text(s)),
72 serde_json::Value::Object(map) => {
73 let kind = map.get("kind").and_then(|v| v.as_str());
74 if kind != Some("block") {
75 return Err(serde::de::Error::custom(
76 "annotation body object must have kind: \"block\"",
77 ));
78 }
79 let children_value = map
80 .get("children")
81 .cloned()
82 .unwrap_or_else(|| serde_json::Value::Array(Vec::new()));
83 let children: Vec<WireNode> =
84 serde_json::from_value(children_value).map_err(serde::de::Error::custom)?;
85 Ok(Self::Lex { children })
86 }
87 _ => Err(serde::de::Error::custom(
88 "annotation body must be null, a string, or an object",
89 )),
90 }
91 }
92}
93
94#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
99pub struct NodeRef {
100 pub kind: String,
102 pub range: Range,
103 #[serde(skip_serializing_if = "Option::is_none")]
104 pub origin: Option<String>,
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 use crate::wire::range::Position;
111
112 fn r(s_l: u32, s_c: u32, e_l: u32, e_c: u32) -> Range {
113 Range::new(Position::new(s_l, s_c), Position::new(e_l, e_c))
114 }
115
116 fn nref() -> NodeRef {
117 NodeRef {
118 kind: "annotation".into(),
119 range: r(0, 0, 0, 12),
120 origin: None,
121 }
122 }
123
124 #[test]
125 fn none_body_serialises_as_null() {
126 let c = LabelCtx {
127 label: "foo".into(),
128 params: serde_json::json!({}),
129 body: AnnotationBody::None,
130 node: nref(),
131 };
132 let s = serde_json::to_string(&c).unwrap();
133 assert!(s.contains(r#""body":null"#));
134 let back: LabelCtx = serde_json::from_str(&s).unwrap();
135 assert_eq!(back, c);
136 }
137
138 #[test]
139 fn text_body_serialises_as_string() {
140 let c = LabelCtx {
141 label: "foo".into(),
142 params: serde_json::json!({}),
143 body: AnnotationBody::Text("raw".into()),
144 node: nref(),
145 };
146 let s = serde_json::to_string(&c).unwrap();
147 assert!(s.contains(r#""body":"raw""#));
148 let back: LabelCtx = serde_json::from_str(&s).unwrap();
149 assert_eq!(back, c);
150 }
151
152 #[test]
153 fn lex_body_serialises_as_block() {
154 let c = LabelCtx {
155 label: "foo".into(),
156 params: serde_json::json!({"k": 1}),
157 body: AnnotationBody::Lex { children: vec![] },
158 node: nref(),
159 };
160 let s = serde_json::to_string(&c).unwrap();
161 assert!(s.contains(r#""body":{"kind":"block","children":[]}"#));
162 let back: LabelCtx = serde_json::from_str(&s).unwrap();
163 assert_eq!(back, c);
164 }
165}