edifact_rs/model.rs
1use crate::directory_validator::{ElementPath, SegmentLayout};
2use crate::error::EdifactError;
3use smallvec::SmallVec;
4use std::borrow::Cow;
5
6/// Reject a layout whose tag does not describe `segment_tag`.
7///
8/// Resolving `"3055"` against the wrong definition would silently address a
9/// different element — the exact failure mode code-addressed access exists to
10/// eliminate — so the mismatch is an error rather than a lookup miss.
11#[inline]
12fn check_layout_tag<L: SegmentLayout + ?Sized>(
13 layout: &L,
14 segment_tag: &str,
15) -> Result<(), EdifactError> {
16 if layout.layout_tag() != segment_tag {
17 return Err(EdifactError::SegmentLayoutMismatch {
18 expected: layout.layout_tag().to_owned(),
19 actual: segment_tag.to_owned(),
20 });
21 }
22 Ok(())
23}
24
25/// A half-open byte span within an EDIFACT payload.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28pub struct Span {
29 /// Start byte offset (inclusive).
30 pub start: usize,
31 /// End byte offset (exclusive).
32 pub end: usize,
33}
34
35impl Span {
36 #[inline]
37 /// Construct a span from inclusive start and exclusive end offsets.
38 pub const fn new(start: usize, end: usize) -> Self {
39 Self { start, end }
40 }
41
42 #[inline]
43 /// Shift the span by `delta` bytes.
44 ///
45 /// Uses saturating addition to avoid integer overflow on malformed input.
46 pub const fn offset(self, delta: usize) -> Self {
47 Self {
48 start: self.start.saturating_add(delta),
49 end: self.end.saturating_add(delta),
50 }
51 }
52
53 /// Length of the span in bytes.
54 ///
55 /// In debug builds, asserts `end >= start` (inverted spans are a bug).
56 /// In release builds, returns 0 for inverted spans rather than panicking,
57 /// so a single corrupt span does not abort an entire validation run.
58 #[inline]
59 pub fn len(self) -> usize {
60 debug_assert!(
61 self.end >= self.start,
62 "Span::len: end ({}) < start ({})",
63 self.end,
64 self.start
65 );
66 self.end.saturating_sub(self.start)
67 }
68
69 /// Returns `true` if the span covers zero bytes.
70 #[inline]
71 pub const fn is_empty(self) -> bool {
72 self.start == self.end
73 }
74}
75
76impl std::fmt::Display for Span {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 write!(f, "{}..{}", self.start, self.end)
79 }
80}
81
82/// A single EDIFACT segment, borrowing its data from the source input.
83#[derive(Debug, Clone, PartialEq, Eq)]
84pub struct Segment<'a> {
85 /// Segment tag, usually three uppercase letters.
86 pub tag: &'a str,
87 /// Span covering the whole segment payload.
88 pub span: Span,
89 /// Span covering only the segment tag.
90 pub tag_span: Span,
91 /// Segment elements in positional order.
92 pub elements: Vec<Element<'a>>,
93}
94
95impl<'a> Segment<'a> {
96 #[inline]
97 /// Construct a segment with default spans.
98 pub fn new(tag: &'a str, elements: Vec<Element<'a>>) -> Self {
99 Self {
100 tag,
101 span: Span::default(),
102 tag_span: Span::default(),
103 elements,
104 }
105 }
106
107 /// Return the element at position `n` (0-indexed), if it exists.
108 #[inline]
109 pub fn get_element(&self, n: usize) -> Option<&Element<'a>> {
110 self.elements.get(n)
111 }
112
113 /// Shorthand: get component 0 of element `n` — the most common access pattern.
114 #[inline]
115 pub fn element_str(&self, n: usize) -> Option<&str> {
116 self.elements.get(n)?.get_component(0)
117 }
118
119 /// Get component `comp` of element `elem` (both 0-based), or `None` if absent.
120 ///
121 /// Mirrors [`OwnedSegment::component_str`], eliminating the need to chain
122 /// `get_element(elem)?.get_component(comp)` in rule closures.
123 #[inline]
124 pub fn component_str(&self, elem: usize, comp: usize) -> Option<&str> {
125 self.elements.get(elem)?.get_component(comp)
126 }
127
128 /// Return the byte span of the element at position `n`, if it exists.
129 #[inline]
130 pub fn element_span(&self, n: usize) -> Option<Span> {
131 Some(self.elements.get(n)?.span)
132 }
133
134 // ── code-addressed access ─────────────────────────────────────────────────
135
136 /// Read the value at an already-resolved [`ElementPath`].
137 ///
138 /// Use this when the same path is reused across many segments — resolve once
139 /// with [`SegmentLayout::resolve_code`], then read without repeating the
140 /// lookup.
141 #[inline]
142 pub fn value_at(&self, path: ElementPath) -> Option<&str> {
143 self.elements
144 .get(path.element)?
145 .get_component(path.component_index())
146 }
147
148 /// Byte span of the value at an already-resolved [`ElementPath`].
149 #[inline]
150 pub fn span_at(&self, path: ElementPath) -> Option<Span> {
151 let element = self.elements.get(path.element)?;
152 match path.component {
153 Some(c) => element.component_span(c),
154 None => Some(element.span),
155 }
156 }
157
158 /// Read a value by its UN/EDIFACT data element identifier.
159 ///
160 /// Positional access (`seg.element_str(4)`) fails silently when the index is
161 /// wrong: it reads a different, usually still-plausible value. Code-addressed
162 /// access cannot — a stale or mistyped identifier is a
163 /// [`EdifactError::UnknownDataElement`], checked against the directory.
164 ///
165 /// `Ok(None)` means the identifier is valid for this segment but the value is
166 /// absent from *this* instance, which is the normal state for a conditional
167 /// element.
168 ///
169 /// # Performance
170 ///
171 /// Each call scans the layout for the identifier. That is a handful of short
172 /// string comparisons and fine for one-off reads, but when pulling the same
173 /// identifier out of many segments, resolve once with
174 /// [`SegmentLayout::resolve_code`] and read with [`value_at`](Self::value_at).
175 ///
176 /// # Example
177 ///
178 /// ```rust
179 /// use edifact_rs::{ComponentRef, ElementRef, SegmentDefinition, Status};
180 ///
181 /// static C507: &[ComponentRef] = &[
182 /// ComponentRef::new(1, "2005", Status::Mandatory),
183 /// ComponentRef::new(2, "2380", Status::Conditional),
184 /// ComponentRef::new(3, "2379", Status::Conditional),
185 /// ];
186 /// static DTM_ELEMENTS: &[ElementRef] =
187 /// &[ElementRef::composite(1, "C507", Status::Mandatory, 1, C507)];
188 /// static DTM: SegmentDefinition =
189 /// SegmentDefinition::new("DTM", "Date/time/period", DTM_ELEMENTS);
190 ///
191 /// let segments: Vec<_> = edifact_rs::from_bytes(b"DTM+137:20260101:102'")
192 /// .collect::<Result<Vec<_>, _>>()?;
193 /// let dtm = &segments[0];
194 ///
195 /// assert_eq!(dtm.value_by_code(&DTM, "2380")?, Some("20260101"));
196 /// // A data element that this segment does not define is a hard error,
197 /// // not a wrong-but-quiet read.
198 /// assert!(dtm.value_by_code(&DTM, "3055").is_err());
199 /// # Ok::<(), edifact_rs::EdifactError>(())
200 /// ```
201 ///
202 /// # Errors
203 ///
204 /// Returns [`EdifactError::SegmentLayoutMismatch`] when `layout` describes a
205 /// different segment tag, [`EdifactError::UnknownDataElement`] when the
206 /// identifier is not in the definition, and
207 /// [`EdifactError::AmbiguousDataElement`] when it appears more than once.
208 pub fn value_by_code<L: SegmentLayout + ?Sized>(
209 &self,
210 layout: &L,
211 data_element: &str,
212 ) -> Result<Option<&str>, EdifactError> {
213 check_layout_tag(layout, self.tag)?;
214 Ok(self.value_at(layout.resolve_code(data_element)?))
215 }
216
217 /// Byte span of a value addressed by its UN/EDIFACT data element identifier.
218 ///
219 /// Use this to attach a precise [`Span`] to a
220 /// [`ValidationIssue`][crate::ValidationIssue] without hand-counting indices.
221 ///
222 /// # Errors
223 ///
224 /// As [`value_by_code`][Self::value_by_code].
225 pub fn span_by_code<L: SegmentLayout + ?Sized>(
226 &self,
227 layout: &L,
228 data_element: &str,
229 ) -> Result<Option<Span>, EdifactError> {
230 check_layout_tag(layout, self.tag)?;
231 Ok(self.span_at(layout.resolve_code(data_element)?))
232 }
233
234 /// Return the whole [`Element`] addressed by a data element identifier.
235 ///
236 /// When the identifier names a component inside a composite, the enclosing
237 /// composite element is returned.
238 ///
239 /// # Errors
240 ///
241 /// As [`value_by_code`][Self::value_by_code].
242 pub fn element_by_code<L: SegmentLayout + ?Sized>(
243 &self,
244 layout: &L,
245 data_element: &str,
246 ) -> Result<Option<&Element<'a>>, EdifactError> {
247 check_layout_tag(layout, self.tag)?;
248 let path = layout.resolve_code(data_element)?;
249 Ok(self.elements.get(path.element))
250 }
251}
252
253/// Components of one repetition of a data element, each paired with its span.
254pub type Components<'a> = SmallVec<[(Cow<'a, str>, Span); 4]>;
255
256/// Components of one repetition of an owned data element.
257pub type OwnedComponents = SmallVec<[(String, Span); 4]>;
258
259/// A data element, which may have one or more component values.
260///
261/// Uses [`SmallVec`] with an inline capacity of 4 to avoid heap allocation
262/// for the common case (≤ 4 components). Component values borrow from the
263/// original input; if the value contained a release-character sequence the
264/// resolved string is stored as an owned [`Cow::Owned`] variant instead of
265/// using `Box::leak`.
266///
267/// Each entry is a `(value, span)` pair, guaranteeing that the component
268/// string and its byte span are always in sync.
269///
270/// # Repetition (ISO 9735-4 §3.1)
271///
272/// [`components`][Self::components] holds the **first** repetition, which is the
273/// only one for every interchange that does not declare a repetition separator
274/// in its `UNA` — that is, virtually all of them. Further repetitions land in
275/// [`repeats`][Self::repeats]; read them together with
276/// [`repetitions`][Self::repetitions].
277#[derive(Debug, Clone, PartialEq, Eq)]
278pub struct Element<'a> {
279 /// Span covering the whole element, including every repetition.
280 pub span: Span,
281 /// Components of the first repetition, in positional order.
282 pub components: Components<'a>,
283 /// Second and subsequent repetitions of this data element.
284 ///
285 /// Empty — and therefore unallocated — unless the interchange declares a
286 /// repetition separator and the element actually repeats.
287 pub repeats: Vec<Components<'a>>,
288}
289
290impl<'a> Element<'a> {
291 /// Return the component at position `n` (0-indexed) of the first repetition.
292 #[inline]
293 pub fn get_component(&self, n: usize) -> Option<&str> {
294 self.components.get(n).map(|(c, _)| c.as_ref())
295 }
296
297 /// Number of repetitions of this data element — always at least 1.
298 #[inline]
299 pub fn repeat_count(&self) -> usize {
300 1 + self.repeats.len()
301 }
302
303 /// Components of repetition `n` (0-indexed), if it exists.
304 #[inline]
305 pub fn repetition(&self, n: usize) -> Option<&[(Cow<'a, str>, Span)]> {
306 match n {
307 0 => Some(&self.components),
308 _ => self.repeats.get(n - 1).map(|r| r.as_slice()),
309 }
310 }
311
312 /// Iterate over every repetition of this element, first one included.
313 ///
314 /// # Example
315 ///
316 /// ```
317 /// // `UNA` byte 7 declares `*` as the repetition separator.
318 /// let segments: Vec<_> = edifact_rs::from_bytes(b"UNA:+.?*'RFF+ON:1*ON:2'")
319 /// .collect::<Result<Vec<_>, _>>()?;
320 /// let rff = segments[0].get_element(0).unwrap();
321 ///
322 /// let refs: Vec<&str> = rff
323 /// .repetitions()
324 /// .map(|components| components[1].0.as_ref())
325 /// .collect();
326 /// assert_eq!(refs, ["1", "2"]);
327 /// # Ok::<(), edifact_rs::EdifactError>(())
328 /// ```
329 #[inline]
330 pub fn repetitions(&self) -> impl Iterator<Item = &[(Cow<'a, str>, Span)]> {
331 std::iter::once(self.components.as_slice()).chain(self.repeats.iter().map(|r| r.as_slice()))
332 }
333
334 /// Return the component at position `n`, or `""` if absent.
335 #[inline]
336 pub fn component_or_empty(&self, n: usize) -> &str {
337 self.components
338 .get(n)
339 .map(|(c, _)| c.as_ref())
340 .unwrap_or("")
341 }
342
343 /// Return the byte span of the component at position `n`, if it exists.
344 #[inline]
345 pub fn component_span(&self, n: usize) -> Option<Span> {
346 self.components.get(n).map(|(_, s)| *s)
347 }
348
349 /// Convenience constructor: wraps string literals as borrowed components.
350 ///
351 /// Useful in tests and when constructing segments for writing.
352 pub fn of(components: &[&'a str]) -> Self {
353 Self {
354 span: Span::default(),
355 components: components
356 .iter()
357 .copied()
358 .map(|c| (Cow::Borrowed(c), Span::default()))
359 .collect(),
360 repeats: Vec::new(),
361 }
362 }
363
364 /// Append a further repetition of this data element (ISO 9735-4 §3.1).
365 ///
366 /// Useful when building segments for [`Writer::write_segment`][crate::Writer::write_segment];
367 /// the writer joins repetitions with the active repetition separator.
368 #[must_use]
369 pub fn and_repeat(mut self, components: &[&'a str]) -> Self {
370 self.repeats.push(
371 components
372 .iter()
373 .copied()
374 .map(|c| (Cow::Borrowed(c), Span::default()))
375 .collect(),
376 );
377 self
378 }
379}
380
381/// Owned data element used by reader-based parsing APIs.
382///
383/// Each entry in `components` is a `(value, span)` pair, keeping the string
384/// and its byte span structurally in sync.
385#[derive(Debug, Clone, PartialEq, Eq)]
386pub struct OwnedElement {
387 /// Span covering the whole element, including every repetition.
388 pub span: Span,
389 /// Components of the first repetition, in positional order.
390 pub components: OwnedComponents,
391 /// Second and subsequent repetitions (ISO 9735-4 §3.1); usually empty.
392 pub repeats: Vec<OwnedComponents>,
393}
394
395impl OwnedElement {
396 #[inline]
397 /// Shift all stored spans by `delta` bytes.
398 pub fn offset(mut self, delta: usize) -> Self {
399 self.span = self.span.offset(delta);
400 for (_, span) in &mut self.components {
401 *span = span.offset(delta);
402 }
403 for repeat in &mut self.repeats {
404 for (_, span) in repeat {
405 *span = span.offset(delta);
406 }
407 }
408 self
409 }
410
411 /// Number of repetitions of this data element — always at least 1.
412 #[inline]
413 pub fn repeat_count(&self) -> usize {
414 1 + self.repeats.len()
415 }
416
417 /// Components of repetition `n` (0-indexed), if it exists.
418 #[inline]
419 pub fn repetition(&self, n: usize) -> Option<&[(String, Span)]> {
420 match n {
421 0 => Some(&self.components),
422 _ => self.repeats.get(n - 1).map(|r| r.as_slice()),
423 }
424 }
425
426 /// Iterate over every repetition of this element, first one included.
427 #[inline]
428 pub fn repetitions(&self) -> impl Iterator<Item = &[(String, Span)]> {
429 std::iter::once(self.components.as_slice()).chain(self.repeats.iter().map(|r| r.as_slice()))
430 }
431}
432
433impl<'a> From<Element<'a>> for OwnedElement {
434 fn from(value: Element<'a>) -> Self {
435 fn own(components: Components<'_>) -> OwnedComponents {
436 components
437 .into_iter()
438 .map(|(c, s)| (c.into_owned(), s))
439 .collect()
440 }
441 Self {
442 span: value.span,
443 components: own(value.components),
444 repeats: value.repeats.into_iter().map(own).collect(),
445 }
446 }
447}
448
449/// Owned segment used by reader-based parsing APIs.
450#[derive(Debug, Clone, PartialEq, Eq)]
451pub struct OwnedSegment {
452 /// Segment tag, usually three uppercase letters.
453 pub tag: String,
454 /// Span covering the whole segment payload.
455 pub span: Span,
456 /// Span covering only the segment tag.
457 pub tag_span: Span,
458 /// Owned segment elements in positional order.
459 pub elements: Vec<OwnedElement>,
460}
461
462/// Zero-allocation view of an [`OwnedElement`].
463///
464/// Implements the same accessor methods as [`Element`] without constructing
465/// any intermediate `SmallVec` or `Cow` values. Use this when you hold an
466/// `&OwnedSegment` reference and want to inspect element data without the
467/// `Vec<Element>` allocation that [`OwnedSegment::as_borrowed`] incurs.
468///
469/// Construct via `BorrowedElement::from(&owned_element)` or through
470/// [`BorrowedSegment::get_element`].
471#[derive(Debug, Clone, Copy)]
472pub struct BorrowedElement<'a>(pub(crate) &'a OwnedElement);
473
474impl<'a> From<&'a OwnedElement> for BorrowedElement<'a> {
475 #[inline]
476 fn from(elem: &'a OwnedElement) -> Self {
477 BorrowedElement(elem)
478 }
479}
480
481impl<'a> BorrowedElement<'a> {
482 /// Return the component at position `n` (0-indexed), if it exists.
483 #[inline]
484 pub fn get_component(&self, n: usize) -> Option<&'a str> {
485 self.0.components.get(n).map(|(s, _)| s.as_str())
486 }
487
488 /// Return the component at position `n`, or `""` if absent.
489 #[inline]
490 pub fn component_or_empty(&self, n: usize) -> &'a str {
491 self.0
492 .components
493 .get(n)
494 .map(|(s, _)| s.as_str())
495 .unwrap_or("")
496 }
497
498 /// Return the byte span of the component at position `n`, if it exists.
499 #[inline]
500 pub fn component_span(&self, n: usize) -> Option<Span> {
501 self.0.components.get(n).map(|(_, s)| *s)
502 }
503
504 /// The byte span covering the whole element.
505 #[inline]
506 pub fn span(&self) -> Span {
507 self.0.span
508 }
509
510 /// Number of components in this element.
511 #[inline]
512 pub fn len(&self) -> usize {
513 self.0.components.len()
514 }
515
516 /// Returns `true` if this element has no components.
517 #[inline]
518 pub fn is_empty(&self) -> bool {
519 self.0.components.is_empty()
520 }
521
522 /// Iterate over all component strings.
523 #[inline]
524 pub fn iter(&self) -> impl Iterator<Item = &'a str> {
525 self.0.components.iter().map(|(c, _)| c.as_str())
526 }
527
528 /// Number of repetitions of this data element — always at least 1.
529 #[inline]
530 pub fn repeat_count(&self) -> usize {
531 self.0.repeat_count()
532 }
533
534 /// Components of repetition `n` (0-indexed), if it exists.
535 #[inline]
536 pub fn repetition(&self, n: usize) -> Option<&'a [(String, Span)]> {
537 match n {
538 0 => Some(&self.0.components),
539 _ => self.0.repeats.get(n - 1).map(|r| r.as_slice()),
540 }
541 }
542
543 /// Iterate over every repetition of this element, first one included.
544 #[inline]
545 pub fn repetitions(&self) -> impl Iterator<Item = &'a [(String, Span)]> {
546 std::iter::once(self.0.components.as_slice())
547 .chain(self.0.repeats.iter().map(|r| r.as_slice()))
548 }
549}
550
551/// Zero-allocation view of an [`OwnedSegment`].
552///
553/// Implements the same accessor methods as [`Segment`] without constructing
554/// a `Vec<Element>`. Use this when you hold an `&OwnedSegment` reference and
555/// want to read data without the allocations incurred by
556/// [`OwnedSegment::as_borrowed`].
557///
558/// # Construction
559///
560/// The idiomatic way to obtain a `BorrowedSegment` is via [`OwnedSegment::borrow`]
561/// or the [`From`] impl:
562///
563/// ```rust
564/// use edifact_rs::{BorrowedSegment, OwnedSegment, Span};
565///
566/// let seg = OwnedSegment {
567/// tag: "BGM".into(),
568/// span: Span::new(0, 3),
569/// tag_span: Span::new(0, 3),
570/// elements: vec![],
571/// };
572/// let borrowed = BorrowedSegment::from(&seg);
573/// assert_eq!(borrowed.tag(), "BGM");
574/// ```
575///
576/// The `'a` lifetime is tied to the referent — you cannot outlive the
577/// `OwnedSegment` you borrowed from.
578#[derive(Debug, Clone, Copy)]
579pub struct BorrowedSegment<'a>(pub(crate) &'a OwnedSegment);
580
581impl<'a> From<&'a OwnedSegment> for BorrowedSegment<'a> {
582 #[inline]
583 fn from(seg: &'a OwnedSegment) -> Self {
584 BorrowedSegment(seg)
585 }
586}
587
588impl<'a> BorrowedSegment<'a> {
589 /// The segment tag (e.g. `"BGM"`).
590 #[inline]
591 pub fn tag(&self) -> &'a str {
592 &self.0.tag
593 }
594
595 /// Byte span covering the whole segment.
596 #[inline]
597 pub fn span(&self) -> Span {
598 self.0.span
599 }
600
601 /// Byte span covering only the segment tag.
602 #[inline]
603 pub fn tag_span(&self) -> Span {
604 self.0.tag_span
605 }
606
607 /// Return the element at position `n` (0-indexed), if it exists.
608 #[inline]
609 pub fn get_element(&self, n: usize) -> Option<BorrowedElement<'a>> {
610 self.0.elements.get(n).map(BorrowedElement)
611 }
612
613 /// Shorthand: first component of element `n` — the most common access pattern.
614 #[inline]
615 pub fn element_str(&self, n: usize) -> Option<&'a str> {
616 self.0
617 .elements
618 .get(n)?
619 .components
620 .first()
621 .map(|(c, _)| c.as_str())
622 }
623
624 /// Get component `comp` of element `elem` (both 0-based), or `None` if absent.
625 ///
626 /// Mirrors [`OwnedSegment::component_str`].
627 #[inline]
628 pub fn component_str(&self, elem: usize, comp: usize) -> Option<&'a str> {
629 self.0
630 .elements
631 .get(elem)?
632 .components
633 .get(comp)
634 .map(|(c, _)| c.as_str())
635 }
636
637 /// Return the byte span of the element at position `n`, if it exists.
638 #[inline]
639 pub fn element_span(&self, n: usize) -> Option<Span> {
640 Some(self.0.elements.get(n)?.span)
641 }
642
643 /// Iterate over all elements as zero-allocation views.
644 #[inline]
645 pub fn elements(&self) -> impl Iterator<Item = BorrowedElement<'a>> {
646 self.0.elements.iter().map(BorrowedElement)
647 }
648
649 // ── code-addressed access ─────────────────────────────────────────────────
650
651 /// Read the value at an already-resolved [`ElementPath`].
652 #[inline]
653 pub fn value_at(&self, path: ElementPath) -> Option<&'a str> {
654 self.0
655 .elements
656 .get(path.element)?
657 .components
658 .get(path.component_index())
659 .map(|(c, _)| c.as_str())
660 }
661
662 /// Byte span of the value at an already-resolved [`ElementPath`].
663 #[inline]
664 pub fn span_at(&self, path: ElementPath) -> Option<Span> {
665 let element = self.0.elements.get(path.element)?;
666 match path.component {
667 Some(c) => element.components.get(c).map(|(_, s)| *s),
668 None => Some(element.span),
669 }
670 }
671
672 /// Read a value by its UN/EDIFACT data element identifier.
673 ///
674 /// Zero-allocation counterpart of [`Segment::value_by_code`].
675 ///
676 /// # Errors
677 ///
678 /// As [`Segment::value_by_code`].
679 pub fn value_by_code<L: SegmentLayout + ?Sized>(
680 &self,
681 layout: &L,
682 data_element: &str,
683 ) -> Result<Option<&'a str>, EdifactError> {
684 check_layout_tag(layout, &self.0.tag)?;
685 Ok(self.value_at(layout.resolve_code(data_element)?))
686 }
687
688 /// Byte span of a value addressed by its UN/EDIFACT data element identifier.
689 ///
690 /// # Errors
691 ///
692 /// As [`Segment::value_by_code`].
693 pub fn span_by_code<L: SegmentLayout + ?Sized>(
694 &self,
695 layout: &L,
696 data_element: &str,
697 ) -> Result<Option<Span>, EdifactError> {
698 check_layout_tag(layout, &self.0.tag)?;
699 Ok(self.span_at(layout.resolve_code(data_element)?))
700 }
701
702 /// Return the whole element addressed by a data element identifier.
703 ///
704 /// When the identifier names a component inside a composite, the enclosing
705 /// composite element is returned.
706 ///
707 /// # Errors
708 ///
709 /// As [`Segment::value_by_code`].
710 pub fn element_by_code<L: SegmentLayout + ?Sized>(
711 &self,
712 layout: &L,
713 data_element: &str,
714 ) -> Result<Option<BorrowedElement<'a>>, EdifactError> {
715 check_layout_tag(layout, &self.0.tag)?;
716 let path = layout.resolve_code(data_element)?;
717 Ok(self.0.elements.get(path.element).map(BorrowedElement))
718 }
719}
720
721impl OwnedSegment {
722 /// Get the first component of element `n`, or `None` if absent.
723 ///
724 /// This is the zero-allocation equivalent of `as_borrowed().element_str(n)`.
725 /// Used internally by [`crate::find_segment_owned`] and the derived
726 /// [`crate::EdifactDeserialize::edifact_deserialize_owned`] implementations.
727 #[inline]
728 pub fn element_str(&self, n: usize) -> Option<&str> {
729 self.elements
730 .get(n)?
731 .components
732 .first()
733 .map(|(s, _)| s.as_str())
734 }
735
736 /// Get component `comp` of element `elem`, or `None` if absent.
737 ///
738 /// Zero-allocation equivalent of `as_borrowed().get_element(elem)?.get_component(comp)`.
739 #[inline]
740 pub fn component_str(&self, elem: usize, comp: usize) -> Option<&str> {
741 self.elements
742 .get(elem)?
743 .components
744 .get(comp)
745 .map(|(s, _)| s.as_str())
746 }
747
748 #[inline]
749 /// Shift all stored spans by `delta` bytes.
750 pub fn offset(mut self, delta: usize) -> Self {
751 self.span = self.span.offset(delta);
752 self.tag_span = self.tag_span.offset(delta);
753 for element in &mut self.elements {
754 element.span = element.span.offset(delta);
755 for (_, span) in &mut element.components {
756 *span = span.offset(delta);
757 }
758 }
759 self
760 }
761
762 #[inline]
763 /// View this owned segment as a borrowed [`Segment`].
764 ///
765 /// **Performance note**: allocates a `Vec<Element<'_>>` on every call.
766 /// When only individual field access is needed, prefer
767 /// [`OwnedSegment::borrow`] → [`BorrowedSegment`] which is O(1).
768 /// `as_borrowed` remains necessary when the callee requires `&[Segment<'_>]`.
769 pub fn as_borrowed(&self) -> Segment<'_> {
770 Segment {
771 tag: self.tag.as_str(),
772 span: self.span,
773 tag_span: self.tag_span,
774 elements: self
775 .elements
776 .iter()
777 .map(|elem| {
778 fn borrow(components: &OwnedComponents) -> Components<'_> {
779 components
780 .iter()
781 .map(|(c, s)| (Cow::Borrowed(c.as_str()), *s))
782 .collect()
783 }
784 Element {
785 span: elem.span,
786 components: borrow(&elem.components),
787 repeats: elem.repeats.iter().map(borrow).collect(),
788 }
789 })
790 .collect(),
791 }
792 }
793
794 /// Return a zero-allocation view of this segment.
795 ///
796 /// Unlike [`as_borrowed`][OwnedSegment::as_borrowed], this is `O(1)` and
797 /// performs no heap allocation. The view cannot be passed to APIs that
798 /// require `&[Segment<'_>]`; use [`as_borrowed`][OwnedSegment::as_borrowed]
799 /// for those call sites.
800 #[inline]
801 pub fn borrow(&self) -> BorrowedSegment<'_> {
802 BorrowedSegment(self)
803 }
804
805 // ── code-addressed access ─────────────────────────────────────────────────
806
807 /// Read the value at an already-resolved [`ElementPath`].
808 #[inline]
809 pub fn value_at(&self, path: ElementPath) -> Option<&str> {
810 self.elements
811 .get(path.element)?
812 .components
813 .get(path.component_index())
814 .map(|(s, _)| s.as_str())
815 }
816
817 /// Byte span of the value at an already-resolved [`ElementPath`].
818 #[inline]
819 pub fn span_at(&self, path: ElementPath) -> Option<Span> {
820 let element = self.elements.get(path.element)?;
821 match path.component {
822 Some(c) => element.components.get(c).map(|(_, s)| *s),
823 None => Some(element.span),
824 }
825 }
826
827 /// Read a value by its UN/EDIFACT data element identifier.
828 ///
829 /// Owned-storage counterpart of [`Segment::value_by_code`]; allocates nothing.
830 ///
831 /// # Errors
832 ///
833 /// As [`Segment::value_by_code`].
834 pub fn value_by_code<L: SegmentLayout + ?Sized>(
835 &self,
836 layout: &L,
837 data_element: &str,
838 ) -> Result<Option<&str>, EdifactError> {
839 check_layout_tag(layout, &self.tag)?;
840 Ok(self.value_at(layout.resolve_code(data_element)?))
841 }
842
843 /// Byte span of a value addressed by its UN/EDIFACT data element identifier.
844 ///
845 /// # Errors
846 ///
847 /// As [`Segment::value_by_code`].
848 pub fn span_by_code<L: SegmentLayout + ?Sized>(
849 &self,
850 layout: &L,
851 data_element: &str,
852 ) -> Result<Option<Span>, EdifactError> {
853 check_layout_tag(layout, &self.tag)?;
854 Ok(self.span_at(layout.resolve_code(data_element)?))
855 }
856
857 /// Return the whole [`OwnedElement`] addressed by a data element identifier.
858 ///
859 /// When the identifier names a component inside a composite, the enclosing
860 /// composite element is returned.
861 ///
862 /// # Errors
863 ///
864 /// As [`Segment::value_by_code`].
865 pub fn element_by_code<L: SegmentLayout + ?Sized>(
866 &self,
867 layout: &L,
868 data_element: &str,
869 ) -> Result<Option<&OwnedElement>, EdifactError> {
870 check_layout_tag(layout, &self.tag)?;
871 let path = layout.resolve_code(data_element)?;
872 Ok(self.elements.get(path.element))
873 }
874}
875
876impl<'a> From<Segment<'a>> for OwnedSegment {
877 fn from(value: Segment<'a>) -> Self {
878 Self {
879 tag: value.tag.to_string(),
880 span: value.span,
881 tag_span: value.tag_span,
882 elements: value.elements.into_iter().map(OwnedElement::from).collect(),
883 }
884 }
885}