bpmn_engine/model/
format.rs1use crate::model::ProcessDefinition;
6use thiserror::Error;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum BpmnFormat {
13 Json,
15 Xml,
17}
18
19#[derive(Debug, Error)]
21pub enum DetectionError {
22 #[error("Unable to detect format: input is empty or ambiguous")]
23 UnableToDetect,
24 #[error("Invalid format: {0}")]
25 InvalidFormat(String),
26}
27
28pub struct FormatDetector;
32
33impl FormatDetector {
34 pub fn detect(input: &str) -> Result<BpmnFormat, DetectionError> {
43 let trimmed = input.trim();
44
45 if trimmed.is_empty() {
46 return Err(DetectionError::UnableToDetect);
47 }
48
49 if trimmed.starts_with("<?xml") || trimmed.starts_with("<bpmn2:") || trimmed.starts_with("<bpmn:") {
51 return Ok(BpmnFormat::Xml);
52 }
53
54 if trimmed.starts_with('{') || trimmed.starts_with('[') {
56 return Ok(BpmnFormat::Json);
57 }
58
59 if trimmed.contains('<') && trimmed.contains('>') {
61 if trimmed.contains("bpmn2:") || trimmed.contains("bpmn:") || trimmed.contains("definitions") {
63 return Ok(BpmnFormat::Xml);
64 }
65 }
66
67 if trimmed.starts_with('{') {
69 return Ok(BpmnFormat::Json);
70 }
71
72 Err(DetectionError::UnableToDetect)
73 }
74
75 pub fn detect_with_confidence(input: &str) -> Result<(BpmnFormat, f64), DetectionError> {
79 let format = Self::detect(input)?;
80
81 let confidence = match format {
82 BpmnFormat::Xml => {
83 if input.trim().starts_with("<?xml") {
84 1.0
85 } else if input.contains("bpmn2:") || input.contains("bpmn:") {
86 0.9
87 } else {
88 0.7
89 }
90 }
91 BpmnFormat::Json => {
92 if input.trim().starts_with('{') && input.trim().ends_with('}') {
93 0.95
94 } else {
95 0.8
96 }
97 }
98 };
99
100 Ok((format, confidence))
101 }
102}
103
104#[derive(Debug, Error)]
108pub enum ParseError {
109 #[error("JSON parse error: {0}")]
110 Json(#[from] serde_json::Error),
111 #[error("XML parse error: {0}")]
112 Xml(String),
113 #[error("Format detection error: {0}")]
114 Detection(#[from] DetectionError),
115 #[error("Unsupported format")]
116 UnsupportedFormat,
117}
118
119#[derive(Debug, Error)]
123pub enum SerializeError {
124 #[error("JSON serialize error: {0}")]
125 Json(#[from] serde_json::Error),
126 #[error("XML serialize error: {0}")]
127 Xml(String),
128 #[error("Unsupported format")]
129 UnsupportedFormat,
130}
131
132pub trait BpmnParser: Send + Sync {
136 fn parse(&self, input: &str) -> Result<ProcessDefinition, ParseError>;
138
139 fn format(&self) -> BpmnFormat;
141}
142
143pub struct JsonParser;
147
148impl BpmnParser for JsonParser {
149 fn parse(&self, input: &str) -> Result<ProcessDefinition, ParseError> {
150 ProcessDefinition::from_json(input).map_err(ParseError::Json)
151 }
152
153 fn format(&self) -> BpmnFormat {
154 BpmnFormat::Json
155 }
156}
157
158pub struct XmlParser;
162
163impl BpmnParser for XmlParser {
164 fn parse(&self, input: &str) -> Result<ProcessDefinition, ParseError> {
165 ProcessDefinition::from_xml(input)
166 }
167
168 fn format(&self) -> BpmnFormat {
169 BpmnFormat::Xml
170 }
171}
172
173pub struct AutoParser;
177
178impl AutoParser {
179 pub fn parse(input: &str) -> Result<(ProcessDefinition, BpmnFormat), ParseError> {
181 let format = FormatDetector::detect(input)?;
182
183 let definition = match format {
184 BpmnFormat::Json => ProcessDefinition::from_json(input).map_err(ParseError::Json)?,
185 BpmnFormat::Xml => ProcessDefinition::from_xml(input)?,
186 };
187
188 Ok((definition, format))
189 }
190}
191