Skip to main content

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}