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/// A data element, which may have one or more component values.
254///
255/// Uses [`SmallVec`] with an inline capacity of 4 to avoid heap allocation
256/// for the common case (≤ 4 components).  Component values borrow from the
257/// original input; if the value contained a release-character sequence the
258/// resolved string is stored as an owned [`Cow::Owned`] variant instead of
259/// using `Box::leak`.
260///
261/// Each entry is a `(value, span)` pair, guaranteeing that the component
262/// string and its byte span are always in sync.
263#[derive(Debug, Clone, PartialEq, Eq)]
264pub struct Element<'a> {
265    /// Span covering the whole element.
266    pub span: Span,
267    /// Element components in positional order, each paired with its byte span.
268    pub components: SmallVec<[(Cow<'a, str>, Span); 4]>,
269}
270
271impl<'a> Element<'a> {
272    /// Return the component at position `n` (0-indexed), if it exists.
273    #[inline]
274    pub fn get_component(&self, n: usize) -> Option<&str> {
275        self.components.get(n).map(|(c, _)| c.as_ref())
276    }
277
278    /// Return the component at position `n`, or `""` if absent.
279    #[inline]
280    pub fn component_or_empty(&self, n: usize) -> &str {
281        self.components
282            .get(n)
283            .map(|(c, _)| c.as_ref())
284            .unwrap_or("")
285    }
286
287    /// Return the byte span of the component at position `n`, if it exists.
288    #[inline]
289    pub fn component_span(&self, n: usize) -> Option<Span> {
290        self.components.get(n).map(|(_, s)| *s)
291    }
292
293    /// Convenience constructor: wraps string literals as borrowed components.
294    ///
295    /// Useful in tests and when constructing segments for writing.
296    pub fn of(components: &[&'a str]) -> Self {
297        Self {
298            span: Span::default(),
299            components: components
300                .iter()
301                .copied()
302                .map(|c| (Cow::Borrowed(c), Span::default()))
303                .collect(),
304        }
305    }
306}
307
308/// Owned data element used by reader-based parsing APIs.
309///
310/// Each entry in `components` is a `(value, span)` pair, keeping the string
311/// and its byte span structurally in sync.
312#[derive(Debug, Clone, PartialEq, Eq)]
313pub struct OwnedElement {
314    /// Span covering the whole element.
315    pub span: Span,
316    /// Owned element components in positional order, each paired with its byte span.
317    pub components: SmallVec<[(String, Span); 4]>,
318}
319
320impl OwnedElement {
321    #[inline]
322    /// Shift all stored spans by `delta` bytes.
323    pub fn offset(mut self, delta: usize) -> Self {
324        self.span = self.span.offset(delta);
325        for (_, span) in &mut self.components {
326            *span = span.offset(delta);
327        }
328        self
329    }
330}
331
332impl<'a> From<Element<'a>> for OwnedElement {
333    fn from(value: Element<'a>) -> Self {
334        Self {
335            span: value.span,
336            components: value
337                .components
338                .into_iter()
339                .map(|(c, s)| (c.into_owned(), s))
340                .collect(),
341        }
342    }
343}
344
345/// Owned segment used by reader-based parsing APIs.
346#[derive(Debug, Clone, PartialEq, Eq)]
347pub struct OwnedSegment {
348    /// Segment tag, usually three uppercase letters.
349    pub tag: String,
350    /// Span covering the whole segment payload.
351    pub span: Span,
352    /// Span covering only the segment tag.
353    pub tag_span: Span,
354    /// Owned segment elements in positional order.
355    pub elements: Vec<OwnedElement>,
356}
357
358/// Zero-allocation view of an [`OwnedElement`].
359///
360/// Implements the same accessor methods as [`Element`] without constructing
361/// any intermediate `SmallVec` or `Cow` values.  Use this when you hold an
362/// `&OwnedSegment` reference and want to inspect element data without the
363/// `Vec<Element>` allocation that [`OwnedSegment::as_borrowed`] incurs.
364///
365/// Construct via `BorrowedElement::from(&owned_element)` or through
366/// [`BorrowedSegment::get_element`].
367#[derive(Debug, Clone, Copy)]
368pub struct BorrowedElement<'a>(pub(crate) &'a OwnedElement);
369
370impl<'a> From<&'a OwnedElement> for BorrowedElement<'a> {
371    #[inline]
372    fn from(elem: &'a OwnedElement) -> Self {
373        BorrowedElement(elem)
374    }
375}
376
377impl<'a> BorrowedElement<'a> {
378    /// Return the component at position `n` (0-indexed), if it exists.
379    #[inline]
380    pub fn get_component(&self, n: usize) -> Option<&'a str> {
381        self.0.components.get(n).map(|(s, _)| s.as_str())
382    }
383
384    /// Return the component at position `n`, or `""` if absent.
385    #[inline]
386    pub fn component_or_empty(&self, n: usize) -> &'a str {
387        self.0
388            .components
389            .get(n)
390            .map(|(s, _)| s.as_str())
391            .unwrap_or("")
392    }
393
394    /// Return the byte span of the component at position `n`, if it exists.
395    #[inline]
396    pub fn component_span(&self, n: usize) -> Option<Span> {
397        self.0.components.get(n).map(|(_, s)| *s)
398    }
399
400    /// The byte span covering the whole element.
401    #[inline]
402    pub fn span(&self) -> Span {
403        self.0.span
404    }
405
406    /// Number of components in this element.
407    #[inline]
408    pub fn len(&self) -> usize {
409        self.0.components.len()
410    }
411
412    /// Returns `true` if this element has no components.
413    #[inline]
414    pub fn is_empty(&self) -> bool {
415        self.0.components.is_empty()
416    }
417
418    /// Iterate over all component strings.
419    #[inline]
420    pub fn iter(&self) -> impl Iterator<Item = &'a str> {
421        self.0.components.iter().map(|(c, _)| c.as_str())
422    }
423}
424
425/// Zero-allocation view of an [`OwnedSegment`].
426///
427/// Implements the same accessor methods as [`Segment`] without constructing
428/// a `Vec<Element>`.  Use this when you hold an `&OwnedSegment` reference and
429/// want to read data without the allocations incurred by
430/// [`OwnedSegment::as_borrowed`].
431///
432/// # Construction
433///
434/// The idiomatic way to obtain a `BorrowedSegment` is via [`OwnedSegment::borrow`]
435/// or the [`From`] impl:
436///
437/// ```rust
438/// use edifact_rs::{BorrowedSegment, OwnedSegment, Span};
439///
440/// let seg = OwnedSegment {
441///     tag: "BGM".into(),
442///     span: Span::new(0, 3),
443///     tag_span: Span::new(0, 3),
444///     elements: vec![],
445/// };
446/// let borrowed = BorrowedSegment::from(&seg);
447/// assert_eq!(borrowed.tag(), "BGM");
448/// ```
449///
450/// The `'a` lifetime is tied to the referent — you cannot outlive the
451/// `OwnedSegment` you borrowed from.
452#[derive(Debug, Clone, Copy)]
453pub struct BorrowedSegment<'a>(pub(crate) &'a OwnedSegment);
454
455impl<'a> From<&'a OwnedSegment> for BorrowedSegment<'a> {
456    #[inline]
457    fn from(seg: &'a OwnedSegment) -> Self {
458        BorrowedSegment(seg)
459    }
460}
461
462impl<'a> BorrowedSegment<'a> {
463    /// The segment tag (e.g. `"BGM"`).
464    #[inline]
465    pub fn tag(&self) -> &'a str {
466        &self.0.tag
467    }
468
469    /// Byte span covering the whole segment.
470    #[inline]
471    pub fn span(&self) -> Span {
472        self.0.span
473    }
474
475    /// Byte span covering only the segment tag.
476    #[inline]
477    pub fn tag_span(&self) -> Span {
478        self.0.tag_span
479    }
480
481    /// Return the element at position `n` (0-indexed), if it exists.
482    #[inline]
483    pub fn get_element(&self, n: usize) -> Option<BorrowedElement<'a>> {
484        self.0.elements.get(n).map(BorrowedElement)
485    }
486
487    /// Shorthand: first component of element `n` — the most common access pattern.
488    #[inline]
489    pub fn element_str(&self, n: usize) -> Option<&'a str> {
490        self.0
491            .elements
492            .get(n)?
493            .components
494            .first()
495            .map(|(c, _)| c.as_str())
496    }
497
498    /// Get component `comp` of element `elem` (both 0-based), or `None` if absent.
499    ///
500    /// Mirrors [`OwnedSegment::component_str`].
501    #[inline]
502    pub fn component_str(&self, elem: usize, comp: usize) -> Option<&'a str> {
503        self.0
504            .elements
505            .get(elem)?
506            .components
507            .get(comp)
508            .map(|(c, _)| c.as_str())
509    }
510
511    /// Return the byte span of the element at position `n`, if it exists.
512    #[inline]
513    pub fn element_span(&self, n: usize) -> Option<Span> {
514        Some(self.0.elements.get(n)?.span)
515    }
516
517    /// Iterate over all elements as zero-allocation views.
518    #[inline]
519    pub fn elements(&self) -> impl Iterator<Item = BorrowedElement<'a>> {
520        self.0.elements.iter().map(BorrowedElement)
521    }
522
523    // ── code-addressed access ─────────────────────────────────────────────────
524
525    /// Read the value at an already-resolved [`ElementPath`].
526    #[inline]
527    pub fn value_at(&self, path: ElementPath) -> Option<&'a str> {
528        self.0
529            .elements
530            .get(path.element)?
531            .components
532            .get(path.component_index())
533            .map(|(c, _)| c.as_str())
534    }
535
536    /// Byte span of the value at an already-resolved [`ElementPath`].
537    #[inline]
538    pub fn span_at(&self, path: ElementPath) -> Option<Span> {
539        let element = self.0.elements.get(path.element)?;
540        match path.component {
541            Some(c) => element.components.get(c).map(|(_, s)| *s),
542            None => Some(element.span),
543        }
544    }
545
546    /// Read a value by its UN/EDIFACT data element identifier.
547    ///
548    /// Zero-allocation counterpart of [`Segment::value_by_code`].
549    ///
550    /// # Errors
551    ///
552    /// As [`Segment::value_by_code`].
553    pub fn value_by_code<L: SegmentLayout + ?Sized>(
554        &self,
555        layout: &L,
556        data_element: &str,
557    ) -> Result<Option<&'a str>, EdifactError> {
558        check_layout_tag(layout, &self.0.tag)?;
559        Ok(self.value_at(layout.resolve_code(data_element)?))
560    }
561
562    /// Byte span of a value addressed by its UN/EDIFACT data element identifier.
563    ///
564    /// # Errors
565    ///
566    /// As [`Segment::value_by_code`].
567    pub fn span_by_code<L: SegmentLayout + ?Sized>(
568        &self,
569        layout: &L,
570        data_element: &str,
571    ) -> Result<Option<Span>, EdifactError> {
572        check_layout_tag(layout, &self.0.tag)?;
573        Ok(self.span_at(layout.resolve_code(data_element)?))
574    }
575
576    /// Return the whole element addressed by a data element identifier.
577    ///
578    /// When the identifier names a component inside a composite, the enclosing
579    /// composite element is returned.
580    ///
581    /// # Errors
582    ///
583    /// As [`Segment::value_by_code`].
584    pub fn element_by_code<L: SegmentLayout + ?Sized>(
585        &self,
586        layout: &L,
587        data_element: &str,
588    ) -> Result<Option<BorrowedElement<'a>>, EdifactError> {
589        check_layout_tag(layout, &self.0.tag)?;
590        let path = layout.resolve_code(data_element)?;
591        Ok(self.0.elements.get(path.element).map(BorrowedElement))
592    }
593}
594
595impl OwnedSegment {
596    /// Get the first component of element `n`, or `None` if absent.
597    ///
598    /// This is the zero-allocation equivalent of `as_borrowed().element_str(n)`.
599    /// Used internally by [`crate::find_segment_owned`] and the derived
600    /// [`crate::EdifactDeserialize::edifact_deserialize_owned`] implementations.
601    #[inline]
602    pub fn element_str(&self, n: usize) -> Option<&str> {
603        self.elements
604            .get(n)?
605            .components
606            .first()
607            .map(|(s, _)| s.as_str())
608    }
609
610    /// Get component `comp` of element `elem`, or `None` if absent.
611    ///
612    /// Zero-allocation equivalent of `as_borrowed().get_element(elem)?.get_component(comp)`.
613    #[inline]
614    pub fn component_str(&self, elem: usize, comp: usize) -> Option<&str> {
615        self.elements
616            .get(elem)?
617            .components
618            .get(comp)
619            .map(|(s, _)| s.as_str())
620    }
621
622    #[inline]
623    /// Shift all stored spans by `delta` bytes.
624    pub fn offset(mut self, delta: usize) -> Self {
625        self.span = self.span.offset(delta);
626        self.tag_span = self.tag_span.offset(delta);
627        for element in &mut self.elements {
628            element.span = element.span.offset(delta);
629            for (_, span) in &mut element.components {
630                *span = span.offset(delta);
631            }
632        }
633        self
634    }
635
636    #[inline]
637    /// View this owned segment as a borrowed [`Segment`].
638    ///
639    /// **Performance note**: allocates a `Vec<Element<'_>>` on every call.
640    /// When only individual field access is needed, prefer
641    /// [`OwnedSegment::borrow`] → [`BorrowedSegment`] which is O(1).
642    /// `as_borrowed` remains necessary when the callee requires `&[Segment<'_>]`.
643    pub fn as_borrowed(&self) -> Segment<'_> {
644        Segment {
645            tag: self.tag.as_str(),
646            span: self.span,
647            tag_span: self.tag_span,
648            elements: self
649                .elements
650                .iter()
651                .map(|elem| Element {
652                    span: elem.span,
653                    components: elem
654                        .components
655                        .iter()
656                        .map(|(c, s)| (Cow::Borrowed(c.as_str()), *s))
657                        .collect(),
658                })
659                .collect(),
660        }
661    }
662
663    /// Return a zero-allocation view of this segment.
664    ///
665    /// Unlike [`as_borrowed`][OwnedSegment::as_borrowed], this is `O(1)` and
666    /// performs no heap allocation.  The view cannot be passed to APIs that
667    /// require `&[Segment<'_>]`; use [`as_borrowed`][OwnedSegment::as_borrowed]
668    /// for those call sites.
669    #[inline]
670    pub fn borrow(&self) -> BorrowedSegment<'_> {
671        BorrowedSegment(self)
672    }
673
674    // ── code-addressed access ─────────────────────────────────────────────────
675
676    /// Read the value at an already-resolved [`ElementPath`].
677    #[inline]
678    pub fn value_at(&self, path: ElementPath) -> Option<&str> {
679        self.elements
680            .get(path.element)?
681            .components
682            .get(path.component_index())
683            .map(|(s, _)| s.as_str())
684    }
685
686    /// Byte span of the value at an already-resolved [`ElementPath`].
687    #[inline]
688    pub fn span_at(&self, path: ElementPath) -> Option<Span> {
689        let element = self.elements.get(path.element)?;
690        match path.component {
691            Some(c) => element.components.get(c).map(|(_, s)| *s),
692            None => Some(element.span),
693        }
694    }
695
696    /// Read a value by its UN/EDIFACT data element identifier.
697    ///
698    /// Owned-storage counterpart of [`Segment::value_by_code`]; allocates nothing.
699    ///
700    /// # Errors
701    ///
702    /// As [`Segment::value_by_code`].
703    pub fn value_by_code<L: SegmentLayout + ?Sized>(
704        &self,
705        layout: &L,
706        data_element: &str,
707    ) -> Result<Option<&str>, EdifactError> {
708        check_layout_tag(layout, &self.tag)?;
709        Ok(self.value_at(layout.resolve_code(data_element)?))
710    }
711
712    /// Byte span of a value addressed by its UN/EDIFACT data element identifier.
713    ///
714    /// # Errors
715    ///
716    /// As [`Segment::value_by_code`].
717    pub fn span_by_code<L: SegmentLayout + ?Sized>(
718        &self,
719        layout: &L,
720        data_element: &str,
721    ) -> Result<Option<Span>, EdifactError> {
722        check_layout_tag(layout, &self.tag)?;
723        Ok(self.span_at(layout.resolve_code(data_element)?))
724    }
725
726    /// Return the whole [`OwnedElement`] addressed by a data element identifier.
727    ///
728    /// When the identifier names a component inside a composite, the enclosing
729    /// composite element is returned.
730    ///
731    /// # Errors
732    ///
733    /// As [`Segment::value_by_code`].
734    pub fn element_by_code<L: SegmentLayout + ?Sized>(
735        &self,
736        layout: &L,
737        data_element: &str,
738    ) -> Result<Option<&OwnedElement>, EdifactError> {
739        check_layout_tag(layout, &self.tag)?;
740        let path = layout.resolve_code(data_element)?;
741        Ok(self.elements.get(path.element))
742    }
743}
744
745impl<'a> From<Segment<'a>> for OwnedSegment {
746    fn from(value: Segment<'a>) -> Self {
747        Self {
748            tag: value.tag.to_string(),
749            span: value.span,
750            tag_span: value.tag_span,
751            elements: value.elements.into_iter().map(OwnedElement::from).collect(),
752        }
753    }
754}