systemd_unit_edit/
parse.rs1use crate::unit::{ParseError, PositionedParseError, SystemdUnit};
4use rowan::ast::AstNode;
5use rowan::{GreenNode, SyntaxNode};
6use std::marker::PhantomData;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct Parse<T> {
14 green: GreenNode,
15 errors: Vec<String>,
16 positioned_errors: Vec<PositionedParseError>,
17 _ty: PhantomData<T>,
18}
19
20impl<T> Parse<T> {
21 pub fn new(green: GreenNode, errors: Vec<String>) -> Self {
23 Parse {
24 green,
25 errors,
26 positioned_errors: Vec::new(),
27 _ty: PhantomData,
28 }
29 }
30
31 pub fn new_with_positioned_errors(
33 green: GreenNode,
34 errors: Vec<String>,
35 positioned_errors: Vec<PositionedParseError>,
36 ) -> Self {
37 Parse {
38 green,
39 errors,
40 positioned_errors,
41 _ty: PhantomData,
42 }
43 }
44
45 pub fn green(&self) -> &GreenNode {
47 &self.green
48 }
49
50 pub fn errors(&self) -> &[String] {
52 &self.errors
53 }
54
55 pub fn positioned_errors(&self) -> &[PositionedParseError] {
57 &self.positioned_errors
58 }
59
60 pub fn error_messages(&self) -> Vec<String> {
62 self.positioned_errors
63 .iter()
64 .map(|e| e.message.clone())
65 .collect()
66 }
67
68 pub fn ok(&self) -> bool {
70 self.errors.is_empty()
71 }
72
73 pub fn to_result(self) -> Result<T, ParseError>
75 where
76 T: AstNode<Language = crate::unit::Lang>,
77 {
78 if self.errors.is_empty() {
79 let node = SyntaxNode::new_root_mut(self.green);
80 Ok(T::cast(node).expect("root node has wrong type"))
81 } else {
82 Err(ParseError(self.errors))
83 }
84 }
85
86 pub fn tree(&self) -> T
88 where
89 T: AstNode<Language = crate::unit::Lang>,
90 {
91 assert!(
92 self.errors.is_empty(),
93 "tried to get tree with errors: {:?}",
94 self.errors
95 );
96 let node = SyntaxNode::new_root_mut(self.green.clone());
97 T::cast(node).expect("root node has wrong type")
98 }
99
100 pub fn syntax_node(&self) -> SyntaxNode<crate::unit::Lang> {
102 SyntaxNode::new_root_mut(self.green.clone())
103 }
104}
105
106unsafe impl<T> Send for Parse<T> {}
108unsafe impl<T> Sync for Parse<T> {}
109
110impl Parse<SystemdUnit> {
111 pub fn parse_unit(text: &str) -> Self {
113 let parsed = crate::unit::parse(text);
114 Parse::new_with_positioned_errors(
115 parsed.green_node,
116 parsed.errors,
117 parsed.positioned_errors,
118 )
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test_parse_success() {
128 let input = "[Unit]\nDescription=Test\n";
129 let parsed = Parse::<SystemdUnit>::parse_unit(input);
130
131 assert!(parsed.ok());
132 assert!(parsed.errors().is_empty());
133
134 let unit = parsed.tree();
135 assert_eq!(unit.sections().count(), 1);
136 }
137
138 #[test]
139 fn test_parse_with_errors() {
140 let input = "Invalid line without section\n[Unit]\n";
141 let parsed = Parse::<SystemdUnit>::parse_unit(input);
142
143 assert!(!parsed.ok());
144 assert!(!parsed.errors().is_empty());
145 }
146}