Skip to main content

EvaluationContext

Struct EvaluationContext 

Source
pub struct EvaluationContext<'a> {
    pub pruefidentifikator: &'a str,
    pub external: &'a dyn ExternalConditionProvider,
    pub segments: &'a [OwnedSegment],
    pub navigator: Option<&'a dyn GroupNavigator>,
    pub resolved_value: Option<&'a str>,
    pub resolved_segment: Option<&'a [Vec<String>]>,
    pub codelist: &'a ArtikelIdCodelist,
    pub ebd_clusters: &'a EbdClusterLookup,
    pub scope: Option<GroupScope<'a>>,
}
Expand description

Context passed to condition evaluators during evaluation.

Carries references to the transaction data and external condition provider needed to evaluate AHB conditions.

Fields§

§pruefidentifikator: &'a str

The Pruefidentifikator (e.g., “11001”, “55001”) that identifies the specific AHB workflow being validated against.

§external: &'a dyn ExternalConditionProvider

Provider for external conditions that depend on business context outside the EDIFACT message.

§segments: &'a [OwnedSegment]

Parsed EDIFACT segments for direct segment inspection by condition evaluators. Conditions often need to check specific segment values.

§navigator: Option<&'a dyn GroupNavigator>

Optional group navigator for group-scoped condition queries. When None, group-scoped methods return empty / false / 0.

§resolved_value: Option<&'a str>

The resolved value of the data element currently being validated.

Set per-field during tree-based validation from AhbNode.value. Format/value conditions (e.g., [931] “ZZZ=+00”, [932] “HHMM=2200”) check this first instead of searching message-wide. When None, conditions fall back to message-wide segment searches.

§resolved_segment: Option<&'a [Vec<String>]>

The full segment elements for the segment being validated.

Allows cross-element access within the same segment (e.g., check qualifier in element 0 while validating value in element 1). When None, conditions fall back to message-wide segment searches.

§codelist: &'a ArtikelIdCodelist

BDEW Artikel-ID / Artikelnummer codelist, used by conditions like [73] and [284] that reference “Codeliste der Gruppenartikel- und Artikel-ID”. Defaults to ArtikelIdCodelist::embedded.

§ebd_clusters: &'a EbdClusterLookup

Per-EBD answer-code cluster lookup, used by conditions like [359] / [360] / [366] / [368] that restrict STS response codes to the Zustimmung or Ablehnung cluster of a specific EBD. Defaults to EbdClusterLookup::embedded.

§scope: Option<GroupScope<'a>>

Optional group scope — when Some, scope-aware helpers like scoped_find_segments narrow lookups to that group instance. When None, scoped helpers fall back to message-wide semantics.

Implementations§

Source§

impl<'a> EvaluationContext<'a>

Source

pub fn new( pruefidentifikator: &'a str, external: &'a dyn ExternalConditionProvider, segments: &'a [OwnedSegment], ) -> Self

Create a new evaluation context (without group navigator).

Source

pub fn with_navigator( pruefidentifikator: &'a str, external: &'a dyn ExternalConditionProvider, segments: &'a [OwnedSegment], navigator: &'a dyn GroupNavigator, ) -> Self

Create a new evaluation context with a group navigator.

Source

pub fn with_codelist(self, codelist: &'a ArtikelIdCodelist) -> Self

Override the codelist (tests only — defaults to embedded).

Source

pub fn with_ebd_clusters(self, ebd_clusters: &'a EbdClusterLookup) -> Self

Override the EBD cluster lookup (tests only — defaults to embedded).

Source

pub fn with_scope(&self, scope: GroupScope<'a>) -> Self

Attach a group scope; returns a fresh context without consuming self. Mirrors with_resolved’s &self shape so validate_tree can build a scoped context inside a loop without moving the outer one.

Source

pub fn with_resolved( &self, value: Option<&'a str>, segment: Option<&'a [Vec<String>]>, ) -> Self

Create a context with a resolved field value for tree-based validation.

The resolved value comes from the ValidatedTree — the specific data element value at the current tree position. Conditions check this first.

Source

pub fn navigator(&self) -> Option<&'a dyn GroupNavigator>

Get the group navigator, if one is set.

Source

pub fn find_segment(&self, segment_id: &str) -> Option<&'a OwnedSegment>

Find the first segment with the given ID.

Source

pub fn find_segments(&self, segment_id: &str) -> Vec<&'a OwnedSegment>

Find all segments with the given ID.

Source

pub fn find_segments_with_qualifier( &self, segment_id: &str, element_index: usize, qualifier: &str, ) -> Vec<&'a OwnedSegment>

Find segments with a specific qualifier value on a given element.

Source

pub fn scoped_find_segments(&self, tag: &str) -> Vec<OwnedSegment>

Find segments tag within the current scope, or message-wide if no scope is set. Scope + navigator required for per-instance narrowing; falls back to find_segments when either is absent.

Returns owned OwnedSegment values because GroupNavigator::find_segments_in_group returns owned values — the navigator may synthesise segments from an assembled tree rather than borrowing from ctx.segments. Callers that only need a &OwnedSegment should use find_segments directly when they know message-wide is correct.

Source

pub fn scoped_find_segments_with_qualifier( &self, tag: &str, element_index: usize, qualifier: &str, ) -> Vec<OwnedSegment>

Find segments tag with a qualifier value on element element_index, narrowed to the current scope or message-wide.

Source

pub fn format_check( &self, tag: &str, elem: usize, comp: usize, validate: impl FnOnce(&str) -> ConditionResult, ) -> ConditionResult

Validate a format condition on the current field value.

Prefers resolved_value (exact field from tree-based validation). Falls back to searching segments by tag and extracting elements[elem][comp], but only when exactly one segment of that tag exists — otherwise the fallback would pick an arbitrary occurrence and validate the wrong field. Returns ConditionResult::Unknown when no unambiguous value is available.

Usage: ctx.format_check("DTM", 0, 1, validate_timezone_utc)

Source

pub fn format_check_qualified( &self, tag: &str, qual_elem: usize, qualifier: &str, val_elem: usize, val_comp: usize, validate: impl FnOnce(&str) -> ConditionResult, ) -> ConditionResult

Validate a format condition with qualifier-filtered segment fallback.

Like format_check, but the fallback searches for segments matching tag where elements[qual_elem][0] == qualifier, then extracts elements[val_elem][val_comp]. Returns Unknown when the qualifier filter doesn’t narrow down to exactly one segment.

Usage: ctx.format_check_qualified("DTM", 0, "163", 0, 1, |v| validate_hhmm_equals(v, "2200"))

Source

pub fn self_segment_value( &self, tag: &str, elem: usize, comp: usize, ) -> Option<&str>

Read a value at elements[elem][comp] of the segment currently being validated (“im selben Segment” conditions).

Prefers resolved_segment (the exact segment the field lives in, bound per-field during tree-based validation). Falls back to the first message-wide segment matching tag when no tree context is available — matches the prior find_segments(tag).first() behavior.

Conditions phrased “Wenn im selben Segment im DE2379 der Code 303 vorhanden ist” should use this instead of iterating every tag segment in the message, which finds spurious matches elsewhere.

Source

pub fn self_segment_value_equals( &self, tag: &str, elem: usize, comp: usize, expected: &str, ) -> bool

Convenience wrapper — returns true when self_segment_value equals expected. The common shape for “im selben Segment” code-equality conditions.

Source

pub fn has_segment(&self, segment_id: &str) -> bool

Check if a segment with the given ID exists.

Source

pub fn count_sg8_obis_matches<F>(&self, obis_pred: F) -> usize
where F: Fn(&str) -> bool,

Count SG8 instances whose PIA+5 OBIS code satisfies obis_pred, restricted to SG8 instances with:

  • SEQ qualifier (DE1229) == current SEQ’s qualifier, AND
  • SEQ DE1050 (Zeitraum-ID in C286) == current SEQ’s DE1050.

“Current” is taken from resolved_segment (tree-based validation), which must point at a SEQ segment with a qualifier in {Z02, ZA1, ZA2} (OBIS-Daten der Marktlokation). Returns 0 when the context isn’t anchored to such a SEQ.

Used by UTILMD_Strom conditions [413]/[414]/[415]/[416] which ask “does another SG8 with matching Zeitraum-ID + qualifier have a Wirkarbeit kumuliert / 1/4 Stunde OBIS?”

Implementation: linear scan of self.segments. Each encountered SEQ defines the “current group’s” matching state; subsequent PIA+5 segments (before the next SEQ) belong to that SG8 instance and are tested against obis_pred when the SEQ matches current’s qualifier + Zeitraum-ID. This relies on the standard EDIFACT group layout where SEQ is SG8’s entry segment and child segments (SG9 PIA …) appear consecutively after it.

Source

pub fn find_segments_in_group( &self, segment_id: &str, group_path: &[&str], instance_index: usize, ) -> Vec<OwnedSegment>

Find all segments with the given tag within a specific group instance. Returns empty if no navigator is set.

Source

pub fn find_segments_with_qualifier_in_group( &self, segment_id: &str, element_index: usize, qualifier: &str, group_path: &[&str], instance_index: usize, ) -> Vec<OwnedSegment>

Find segments matching a tag + qualifier within a group instance. Returns empty if no navigator is set.

Source

pub fn has_segment_in_group( &self, segment_id: &str, group_path: &[&str], instance_index: usize, ) -> bool

Check if a segment exists in a specific group instance. Returns false if no navigator is set.

Source

pub fn group_instance_count(&self, group_path: &[&str]) -> usize

Count repetitions of a group at the given path. Returns 0 if no navigator is set.

Source

pub fn child_group_instance_count( &self, parent_path: &[&str], parent_instance: usize, child_group_id: &str, ) -> usize

Count child group repetitions within a specific parent group instance. Returns 0 if no navigator is set.

Source

pub fn find_segments_in_child_group( &self, segment_id: &str, parent_path: &[&str], parent_instance: usize, child_group_id: &str, child_instance: usize, ) -> Vec<OwnedSegment>

Find segments in a child group within a specific parent group instance. Returns empty if no navigator is set.

Source

pub fn extract_value_in_group( &self, segment_id: &str, element_index: usize, component_index: usize, group_path: &[&str], instance_index: usize, ) -> Option<String>

Extract a single value from the first matching segment in a group instance. Returns None if no navigator is set or value not found.

Source

pub fn has_qualifier( &self, tag: &str, element_index: usize, qualifier: &str, ) -> ConditionResult

Check if any segment with the given tag + qualifier exists (message-wide). Returns True if found, False if not.

Source

pub fn lacks_qualifier( &self, tag: &str, element_index: usize, qualifier: &str, ) -> ConditionResult

Check if a segment with given tag + qualifier does NOT exist (message-wide). Returns True if absent, False if present.

Source

pub fn has_qualified_value( &self, tag: &str, qual_elem: usize, qualifier: &str, value_elem: usize, value_comp: usize, values: &[&str], ) -> ConditionResult

Check if any segment with the given tag + qualifier has a specific sub-element value.

Finds segments matching tag with elements[qual_elem][0] == qualifier, then checks if elements[value_elem][value_comp] matches any of values.

Source

pub fn any_group_has_qualifier( &self, tag: &str, element_index: usize, qualifier: &str, group_path: &[&str], ) -> ConditionResult

Group-scoped qualifier existence check with message-wide fallback.

Checks if any group instance at group_path contains a segment matching tag with elements[element_index][0] == qualifier. Falls back to message-wide search if no group navigator is available.

Source

pub fn any_group_has_any_qualifier( &self, tag: &str, element_index: usize, qualifiers: &[&str], group_path: &[&str], ) -> ConditionResult

Group-scoped segment existence check (any tag match, no qualifier).

Checks if any group instance at group_path contains a segment with elements[element_index][0] matching any of qualifiers. Falls back to message-wide search if no group navigator is available.

Source

pub fn any_group_has_qualified_value( &self, tag: &str, qual_elem: usize, qualifier: &str, value_elem: usize, value_comp: usize, values: &[&str], group_path: &[&str], ) -> ConditionResult

Group-scoped check for sub-element value within qualified segments.

For each group instance at group_path, checks if a segment matching tag with elements[qual_elem][0] == qualifier has elements[value_elem][value_comp] in values. Falls back to message-wide.

Source

pub fn filtered_parent_child_has_qualifier( &self, parent_path: &[&str], parent_tag: &str, parent_elem: usize, parent_qual: &str, child_group_id: &str, child_tag: &str, child_elem: usize, child_qual: &str, ) -> ConditionResult

Pattern A: Check if parent group instances matching a qualifier have a child group containing a specific qualifier.

Example: “In the SG8 with SEQ+Z98, does its SG10 child have CCI+Z23?”

Falls back to message-wide search if no navigator is available.

Source

pub fn any_group_has_qualifier_without( &self, present_tag: &str, present_elem: usize, present_qual: &str, absent_tag: &str, absent_elem: usize, absent_qual: &str, group_path: &[&str], ) -> ConditionResult

Pattern B: Check if any group instance has one qualifier present but another absent.

Example: “In any SG8, SEQ+Z59 is present but CCI+11 is absent”

Falls back to message-wide search if no navigator is available.

Source

pub fn collect_group_values( &self, tag: &str, elem: usize, comp: usize, group_path: &[&str], ) -> Vec<(usize, String)>

Pattern C helper: Collect all values at a specific element+component across group instances.

Returns (instance_index, value) pairs for non-empty values.

Source

pub fn groups_share_qualified_value( &self, source_tag: &str, source_qual_elem: usize, source_qual: &str, source_value_elem: usize, source_value_comp: usize, source_path: &[&str], target_tag: &str, target_elem: usize, target_comp: usize, target_path: &[&str], ) -> ConditionResult

Pattern C: Check if a value from one group path matches a value in another group path.

Example: “Zeitraum-ID in SG6 RFF+Z49 matches reference in SG8 SEQ.c286”

Finds qualified segments in source_path, extracts their value, then checks if any instance in target_path has the same value at the target position.

Falls back to message-wide search if no navigator is available.

Source

pub fn any_group_has_co_occurrence( &self, tag_a: &str, elem_a: usize, quals_a: &[&str], tag_b: &str, elem_b: usize, comp_b: usize, vals_b: &[&str], group_path: &[&str], ) -> ConditionResult

Group-scoped co-occurrence check: two segment conditions must both be true in the same group instance.

For each group instance, checks that:

  1. A segment with tag_a has elements[elem_a][0] in quals_a
  2. A segment with tag_b has elements[elem_b][comp_b] in vals_b

Falls back to message-wide search.

Source

pub fn has_segment_matching( &self, tag: &str, checks: &[(usize, usize, &str)], ) -> ConditionResult

Check if any segment with the given tag has ALL specified element/component values.

Each check is (element_index, component_index, expected_value). Returns True if a matching segment exists, False if segments exist but none match, Unknown if no segments with the tag exist.

Example: ctx.has_segment_matching("STS", &[(0, 0, "Z20"), (1, 0, "Z32"), (2, 0, "A99")])

Source

pub fn has_segment_matching_in_group( &self, tag: &str, checks: &[(usize, usize, &str)], group_path: &[&str], ) -> ConditionResult

Group-scoped multi-element match with message-wide fallback.

Checks if any group instance at group_path contains a segment with tag where ALL element/component checks match.

Source

pub fn dtm_ge(&self, qualifier: &str, threshold: &str) -> ConditionResult

Check if a DTM segment with the given qualifier has a value >= threshold.

Both the DTM value and threshold should be in EDIFACT format 303 (CCYYMMDDHHMM). Returns Unknown if no DTM with the qualifier exists.

Source

pub fn dtm_lt(&self, qualifier: &str, threshold: &str) -> ConditionResult

Check if a DTM segment with the given qualifier has a value < threshold.

Source

pub fn dtm_le(&self, qualifier: &str, threshold: &str) -> ConditionResult

Check if a DTM segment with the given qualifier has a value <= threshold.

Source

pub fn count_qualified_in_group( &self, tag: &str, element_index: usize, qualifier: &str, group_path: &[&str], ) -> usize

Count segments matching tag + qualifier within a group path (across all instances).

Returns the total count across all group instances. Falls back to message-wide count if no navigator.

Source

pub fn count_in_group(&self, tag: &str, group_path: &[&str]) -> usize

Count segments matching tag (any qualifier) within a group path.

Auto Trait Implementations§

§

impl<'a> !RefUnwindSafe for EvaluationContext<'a>

§

impl<'a> !UnwindSafe for EvaluationContext<'a>

§

impl<'a> Freeze for EvaluationContext<'a>

§

impl<'a> Send for EvaluationContext<'a>

§

impl<'a> Sync for EvaluationContext<'a>

§

impl<'a> Unpin for EvaluationContext<'a>

§

impl<'a> UnsafeUnpin for EvaluationContext<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.