1use hl7v2_model::{Atom, Message, Presence, Segment};
30
31pub fn get<'a>(msg: &'a Message, path: &str) -> Option<&'a str> {
59 let mut parts = path.split('.');
64 let segment_id = parts.next()?;
65
66 let segment = msg
68 .segments
69 .iter()
70 .find(|s| std::str::from_utf8(&s.id) == Ok(segment_id))?;
71
72 let field_part = parts.next()?;
74 let (field_index, rep_index) = parse_field_and_rep(field_part)?;
75
76 if segment_id == "MSH" {
78 get_msh_field(msg, segment, field_index, rep_index, parts)
79 } else {
80 get_field(segment, field_index, rep_index, parts)
81 }
82}
83
84pub fn get_presence(msg: &Message, path: &str) -> Presence {
116 let mut parts = path.split('.');
118 let segment_id = match parts.next() {
119 Some(id) => id,
120 None => return Presence::Missing,
121 };
122
123 let segment = match msg
125 .segments
126 .iter()
127 .find(|s| std::str::from_utf8(&s.id) == Ok(segment_id))
128 {
129 Some(seg) => seg,
130 None => return Presence::Missing,
131 };
132
133 let field_part = match parts.next() {
135 Some(part) => part,
136 None => return Presence::Missing,
137 };
138
139 let (field_index, rep_index) = match parse_field_and_rep(field_part) {
140 Some(indices) => indices,
141 None => return Presence::Missing,
142 };
143
144 if segment_id == "MSH" {
146 get_msh_field_presence(msg, segment, field_index, rep_index, parts)
147 } else {
148 get_field_presence(segment, field_index, rep_index, parts)
149 }
150}
151
152fn parse_field_and_rep(field_str: &str) -> Option<(usize, usize)> {
158 if let Some(bracket_pos) = field_str.find('[') {
159 let field_index = field_str[..bracket_pos].parse::<usize>().ok()?;
161 let rep_part = &field_str[bracket_pos + 1..];
162 if let Some(end_bracket) = rep_part.find(']') {
163 let rep_index = rep_part[..end_bracket].parse::<usize>().ok()?;
164 Some((field_index, rep_index))
165 } else {
166 None
167 }
168 } else {
169 let field_index = field_str.parse::<usize>().ok()?;
171 Some((field_index, 1))
172 }
173}
174
175fn get_field<'a>(
177 segment: &'a Segment,
178 field_index: usize,
179 rep_index: usize,
180 mut parts: std::str::Split<char>,
181) -> Option<&'a str> {
182 if field_index == 0 {
184 return None;
185 }
186 let zero_based_field_index = field_index - 1;
187
188 if zero_based_field_index >= segment.fields.len() {
190 return None;
191 }
192 let field = &segment.fields[zero_based_field_index];
193
194 if rep_index == 0 || rep_index > field.reps.len() {
196 return None;
197 }
198 let rep = &field.reps[rep_index - 1];
199
200 let comp_index = if let Some(comp_part) = parts.next() {
202 comp_part.parse::<usize>().ok()?
203 } else {
204 1 };
206
207 if comp_index == 0 || comp_index > rep.comps.len() {
209 return None;
210 }
211 let comp = &rep.comps[comp_index - 1];
212
213 if comp.subs.is_empty() {
215 return None;
216 }
217
218 match &comp.subs[0] {
219 Atom::Text(text) => Some(text.as_str()),
220 Atom::Null => None,
221 }
222}
223
224fn get_msh_field<'a>(
226 _msg: &'a Message,
227 segment: &'a Segment,
228 field_index: usize,
229 rep_index: usize,
230 mut parts: std::str::Split<char>,
231) -> Option<&'a str> {
232 if field_index == 1 {
233 None } else if field_index == 2 {
236 if segment.fields.is_empty() {
238 return None;
239 }
240 let field = &segment.fields[0];
241 if rep_index == 0 || rep_index > field.reps.len() {
242 return None;
243 }
244 let rep = &field.reps[rep_index - 1];
245 let comp_index = if let Some(comp_part) = parts.next() {
246 comp_part.parse::<usize>().ok()?
247 } else {
248 1
249 };
250 if comp_index == 0 || comp_index > rep.comps.len() {
251 return None;
252 }
253 let comp = &rep.comps[comp_index - 1];
254 if comp.subs.is_empty() {
255 return None;
256 }
257 match &comp.subs[0] {
258 Atom::Text(text) => Some(text.as_str()),
259 Atom::Null => None,
260 }
261 } else {
262 let adjusted_field_index = field_index - 2;
264 if adjusted_field_index >= segment.fields.len() {
265 return None;
266 }
267 let field = &segment.fields[adjusted_field_index];
268 if rep_index == 0 || rep_index > field.reps.len() {
269 return None;
270 }
271 let rep = &field.reps[rep_index - 1];
272 let comp_index = if let Some(comp_part) = parts.next() {
273 comp_part.parse::<usize>().ok()?
274 } else {
275 1
276 };
277 if comp_index == 0 || comp_index > rep.comps.len() {
278 return None;
279 }
280 let comp = &rep.comps[comp_index - 1];
281 if comp.subs.is_empty() {
282 return None;
283 }
284 match &comp.subs[0] {
285 Atom::Text(text) => Some(text.as_str()),
286 Atom::Null => None,
287 }
288 }
289}
290
291fn get_field_presence(
293 segment: &Segment,
294 field_index: usize,
295 rep_index: usize,
296 mut parts: std::str::Split<char>,
297) -> Presence {
298 if field_index == 0 {
299 return Presence::Missing;
300 }
301 let zero_based_field_index = field_index - 1;
302
303 if zero_based_field_index >= segment.fields.len() {
304 return Presence::Missing;
305 }
306 let field = &segment.fields[zero_based_field_index];
307
308 if rep_index == 0 || rep_index > field.reps.len() {
309 return Presence::Missing;
310 }
311 let rep = &field.reps[rep_index - 1];
312
313 let comp_index = if let Some(comp_part) = parts.next() {
314 match comp_part.parse::<usize>() {
315 Ok(index) => index,
316 Err(_) => return Presence::Missing,
317 }
318 } else {
319 1
320 };
321
322 if comp_index == 0 || comp_index > rep.comps.len() {
323 return Presence::Missing;
324 }
325 let comp = &rep.comps[comp_index - 1];
326
327 if comp.subs.is_empty() {
328 return Presence::Missing;
329 }
330
331 match &comp.subs[0] {
332 Atom::Text(text) => {
333 if text.is_empty() {
334 Presence::Empty
335 } else {
336 Presence::Value(text.clone())
337 }
338 }
339 Atom::Null => Presence::Null,
340 }
341}
342
343fn get_msh_field_presence(
345 msg: &Message,
346 segment: &Segment,
347 field_index: usize,
348 rep_index: usize,
349 mut parts: std::str::Split<char>,
350) -> Presence {
351 if field_index == 1 {
352 Presence::Value(msg.delims.field.to_string())
354 } else if field_index == 2 {
355 if segment.fields.is_empty() {
356 return Presence::Missing;
357 }
358 let field = &segment.fields[0];
359 if rep_index == 0 || rep_index > field.reps.len() {
360 return Presence::Missing;
361 }
362 let rep = &field.reps[rep_index - 1];
363 let comp_index = if let Some(comp_part) = parts.next() {
364 match comp_part.parse::<usize>() {
365 Ok(index) => index,
366 Err(_) => return Presence::Missing,
367 }
368 } else {
369 1
370 };
371 if comp_index == 0 || comp_index > rep.comps.len() {
372 return Presence::Missing;
373 }
374 let comp = &rep.comps[comp_index - 1];
375 if comp.subs.is_empty() {
376 return Presence::Missing;
377 }
378 match &comp.subs[0] {
379 Atom::Text(text) => {
380 if text.is_empty() {
381 Presence::Empty
382 } else {
383 Presence::Value(text.clone())
384 }
385 }
386 Atom::Null => Presence::Null,
387 }
388 } else {
389 let adjusted_field_index = field_index - 2;
390 if adjusted_field_index >= segment.fields.len() {
391 return Presence::Missing;
392 }
393 let field = &segment.fields[adjusted_field_index];
394 if rep_index == 0 || rep_index > field.reps.len() {
395 return Presence::Missing;
396 }
397 let rep = &field.reps[rep_index - 1];
398 let comp_index = if let Some(comp_part) = parts.next() {
399 match comp_part.parse::<usize>() {
400 Ok(index) => index,
401 Err(_) => return Presence::Missing,
402 }
403 } else {
404 1
405 };
406 if comp_index == 0 || comp_index > rep.comps.len() {
407 return Presence::Missing;
408 }
409 let comp = &rep.comps[comp_index - 1];
410 if comp.subs.is_empty() {
411 return Presence::Missing;
412 }
413 match &comp.subs[0] {
414 Atom::Text(text) => {
415 if text.is_empty() {
416 Presence::Empty
417 } else {
418 Presence::Value(text.clone())
419 }
420 }
421 Atom::Null => Presence::Null,
422 }
423 }
424}
425
426#[cfg(test)]
427mod tests;