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}