1mod parser;
59
60use std::{fmt::Display, str::FromStr};
61
62pub use parser::QueryParseError;
63use thiserror::Error;
64
65use crate::{
66 message::{Component, Field, Repeat, Segment, Separators, Subcomponent},
67 parser::Span,
68};
69
70#[derive(Debug, Clone, PartialEq, Eq, Hash)]
79#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
80pub struct LocationQuery {
81 pub segment: String,
82 pub segment_index: Option<usize>,
83 pub field: Option<usize>,
84 pub repeat: Option<usize>,
85 pub component: Option<usize>,
86 pub subcomponent: Option<usize>,
87}
88
89pub fn parse_location_query(query: &str) -> Result<LocationQuery, QueryParseError> {
114 parser::parse_query(Span::new(query))
115 .map(|(_, m)| m)
116 .map_err(|e| e.into())
117}
118
119impl FromStr for LocationQuery {
120 type Err = QueryParseError;
121
122 fn from_str(s: &str) -> Result<Self, Self::Err> {
123 parse_location_query(s)
124 }
125}
126
127impl TryFrom<&str> for LocationQuery {
128 type Error = QueryParseError;
129
130 fn try_from(value: &str) -> Result<Self, Self::Error> {
131 parse_location_query(value)
132 }
133}
134
135impl TryFrom<String> for LocationQuery {
136 type Error = QueryParseError;
137
138 fn try_from(value: String) -> Result<Self, Self::Error> {
139 parse_location_query(&value)
140 }
141}
142
143impl TryFrom<&String> for LocationQuery {
144 type Error = QueryParseError;
145
146 fn try_from(value: &String) -> Result<Self, Self::Error> {
147 parse_location_query(value)
148 }
149}
150
151impl Display for LocationQuery {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 write!(f, "{}", self.segment)?;
154 if let Some(i) = self.segment_index {
155 write!(f, "[{}]", i)?;
156 }
157 if let Some(i) = self.field {
158 write!(f, ".{}", i)?;
159 } else {
160 return Ok(());
161 }
162 if let Some(i) = self.repeat {
163 write!(f, "[{}]", i)?;
164 }
165 if let Some(i) = self.component {
166 write!(f, ".{}", i)?;
167 } else {
168 return Ok(());
169 }
170 if let Some(i) = self.subcomponent {
171 write!(f, ".{}", i)?;
172 }
173 Ok(())
174 }
175}
176
177impl LocationQuery {
178 pub fn parse(query: &str) -> Result<Self, QueryParseError> {
180 parse_location_query(query)
181 }
182}
183
184#[derive(Debug, Clone)]
186pub struct LocationQueryBuilder {
187 segment: Option<String>,
188 segment_index: Option<usize>,
189 field: Option<usize>,
190 repeat: Option<usize>,
191 component: Option<usize>,
192 subcomponent: Option<usize>,
193}
194
195#[derive(Debug, Clone, Error)]
197pub enum LocationQueryBuildError {
198 #[error("Missing segment: segment is required")]
200 MissingSegment,
201 #[error("Invalid segment length: segments must be 3 characters long")]
203 InvalidSegmentLength,
204 #[error("Invalid segment name: segments must be ASCII uppercase")]
206 InvalidSegmentName,
207 #[error("Invalid segment index: segment index must be greater than 0")]
209 InvalidSegmentIndex,
210 #[error("Invalid field index: field index must be greater than 0")]
212 InvalidFieldIndex,
213 #[error("Invalid repeat index: repeat index must be greater than 0")]
215 InvalidRepeatIndex,
216 #[error("Invalid component index: component index must be greater than 0")]
218 InvalidComponentIndex,
219 #[error("Invalid subcomponent index: subcomponent index must be greater than 0")]
221 InvalidSubcomponentIndex,
222}
223
224impl Default for LocationQueryBuilder {
225 fn default() -> Self {
226 Self::new()
227 }
228}
229
230impl LocationQueryBuilder {
231 pub fn new() -> Self {
232 Self {
233 segment: None,
234 segment_index: None,
235 field: None,
236 repeat: None,
237 component: None,
238 subcomponent: None,
239 }
240 }
241
242 pub fn segment<S: ToString>(mut self, segment: S) -> Self {
245 self.segment = Some(segment.to_string());
246 self
247 }
248
249 pub fn segment_index(mut self, index: usize) -> Self {
252 self.segment_index = Some(index);
253 self
254 }
255
256 pub fn field(mut self, index: usize) -> Self {
259 self.field = Some(index);
260 self
261 }
262
263 pub fn repeat(mut self, index: usize) -> Self {
266 self.repeat = Some(index);
267 self
268 }
269
270 pub fn component(mut self, index: usize) -> Self {
273 self.component = Some(index);
274 self
275 }
276
277 pub fn subcomponent(mut self, index: usize) -> Self {
280 self.subcomponent = Some(index);
281 self
282 }
283
284 pub fn build(self) -> Result<LocationQuery, LocationQueryBuildError> {
286 let segment = if let Some(segment) = self.segment {
287 if segment.len() != 3 {
288 return Err(LocationQueryBuildError::InvalidSegmentLength);
289 }
290 if !segment.chars().all(|c| c.is_ascii_uppercase()) {
291 return Err(LocationQueryBuildError::InvalidSegmentName);
292 }
293 segment
294 } else {
295 return Err(LocationQueryBuildError::MissingSegment);
296 };
297
298 let segment_index = if let Some(segment_index) = self.segment_index {
299 if segment_index == 0 {
300 return Err(LocationQueryBuildError::InvalidSegmentIndex);
301 }
302 Some(segment_index)
303 } else {
304 None
305 };
306
307 let field = if let Some(field) = self.field {
308 if field == 0 {
309 return Err(LocationQueryBuildError::InvalidFieldIndex);
310 }
311 Some(field)
312 } else {
313 None
314 };
315
316 let repeat = if let Some(repeat) = self.repeat {
317 if repeat == 0 {
318 return Err(LocationQueryBuildError::InvalidRepeatIndex);
319 }
320 Some(repeat)
321 } else {
322 None
323 };
324
325 let component = if let Some(component) = self.component {
326 if component == 0 {
327 return Err(LocationQueryBuildError::InvalidComponentIndex);
328 }
329 Some(component)
330 } else {
331 None
332 };
333
334 let subcomponent = if let Some(subcomponent) = self.subcomponent {
335 if subcomponent == 0 {
336 return Err(LocationQueryBuildError::InvalidSubcomponentIndex);
337 }
338 Some(subcomponent)
339 } else {
340 None
341 };
342
343 Ok(LocationQuery {
344 segment,
345 segment_index,
346 field,
347 repeat,
348 component,
349 subcomponent,
350 })
351 }
352}
353
354#[derive(Debug, Clone, PartialEq, Eq)]
359#[cfg_attr(feature = "serde", derive(serde::Serialize))]
360pub enum LocationQueryResult<'m> {
361 Segment(&'m Segment<'m>),
362 Field(&'m Field<'m>),
363 Repeat(&'m Repeat<'m>),
364 Component(&'m Component<'m>),
365 Subcomponent(&'m Subcomponent<'m>),
366}
367
368impl<'m> LocationQueryResult<'m> {
369 pub fn raw_value(&self) -> &'m str {
377 match self {
378 LocationQueryResult::Segment(seg) => seg.raw_value(),
379 LocationQueryResult::Field(field) => field.raw_value(),
380 LocationQueryResult::Repeat(repeat) => repeat.raw_value(),
381 LocationQueryResult::Component(component) => component.raw_value(),
382 LocationQueryResult::Subcomponent(subcomponent) => subcomponent.raw_value(),
383 }
384 }
385
386 pub fn range(&self) -> std::ops::Range<usize> {
389 match self {
390 LocationQueryResult::Segment(seg) => seg.range.clone(),
391 LocationQueryResult::Field(field) => field.range.clone(),
392 LocationQueryResult::Repeat(repeat) => repeat.range.clone(),
393 LocationQueryResult::Component(component) => component.range.clone(),
394 LocationQueryResult::Subcomponent(subcomponent) => subcomponent.range.clone(),
395 }
396 }
397
398 pub fn display(&self, separators: &'m Separators) -> LocationQueryResultDisplay<'m> {
402 LocationQueryResultDisplay {
403 value: self.raw_value(),
404 separators,
405 }
406 }
407}
408
409pub struct LocationQueryResultDisplay<'m> {
411 value: &'m str,
412 separators: &'m Separators,
413}
414
415impl<'m> Display for LocationQueryResultDisplay<'m> {
416 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
417 if f.alternate() {
418 write!(f, "{}", self.value)
419 } else {
420 write!(f, "{}", self.separators.decode(self.value))
421 }
422 }
423}
424
425#[cfg(test)]
426mod tests {
427 use super::*;
428 use pretty_assertions_sorted::assert_eq;
429
430 #[test]
431 fn can_display_location_query() {
432 let query = LocationQuery {
433 segment: "MSH".to_string(),
434 segment_index: Some(1),
435 field: Some(2),
436 repeat: Some(3),
437 component: Some(4),
438 subcomponent: Some(5),
439 };
440 assert_eq!(query.to_string(), "MSH[1].2[3].4.5");
441
442 let query = LocationQuery {
443 segment: "MSH".to_string(),
444 segment_index: None,
445 field: Some(2),
446 repeat: None,
447 component: Some(4),
448 subcomponent: None,
449 };
450 assert_eq!(query.to_string(), "MSH.2.4");
451
452 let query = LocationQuery {
453 segment: "MSH".to_string(),
454 segment_index: None,
455 field: None,
456 repeat: None,
457 component: Some(4),
458 subcomponent: Some(5),
459 };
460 assert_eq!(query.to_string(), "MSH");
461 }
462}