mig-types 0.19.1

Generated MIG-tree types for EDIFACT messages — shared segments, composites, enums, and PID-specific compositions
Documentation
//! Group-scoped segment navigation trait.

use crate::segment::OwnedSegment;

/// Provides group-scoped segment access for condition evaluation.
///
/// Implementations translate hierarchical group paths (e.g., `["SG4", "SG8"]`)
/// into segment lookups scoped to a specific group instance.
pub trait GroupNavigator: Send + Sync {
    /// Find all segments with the given tag within a specific group instance.
    ///
    /// * `segment_id` - Segment tag to find (e.g., "SEQ", "CCI")
    /// * `group_path` - Path of group IDs from root (e.g., `&["SG4", "SG8"]`)
    /// * `instance_index` - Which repetition of the innermost group (0-based)
    fn find_segments_in_group(
        &self,
        segment_id: &str,
        group_path: &[&str],
        instance_index: usize,
    ) -> Vec<OwnedSegment>;

    /// Find segments matching a tag + qualifier within a group instance.
    ///
    /// * `segment_id` - Segment tag to find
    /// * `element_index` - Which element contains the qualifier
    /// * `qualifier` - Expected qualifier value
    /// * `group_path` - Path of group IDs from root
    /// * `instance_index` - Which repetition of the innermost group (0-based)
    fn find_segments_with_qualifier_in_group(
        &self,
        segment_id: &str,
        element_index: usize,
        qualifier: &str,
        group_path: &[&str],
        instance_index: usize,
    ) -> Vec<OwnedSegment>;

    /// Count repetitions of a group at the given path.
    fn group_instance_count(&self, group_path: &[&str]) -> usize;

    /// Find all segments with the given tag in one group instance, addressed
    /// by the repetition index at *every* level: `[("SG4", 1), ("SG8", 0)]` is
    /// the first SG8 of the second SG4.
    ///
    /// [`find_segments_in_group`](Self::find_segments_in_group) indexes only the
    /// innermost group, so it cannot reach an SG8 under any SG4 but the first.
    /// The default falls back to it; implementations that can address every
    /// level override this.
    fn find_segments_in_instance(
        &self,
        segment_id: &str,
        path: &[(&str, usize)],
    ) -> Vec<OwnedSegment> {
        let Some(&(_, instance_index)) = path.last() else {
            return Vec::new();
        };
        let group_path: Vec<&str> = path.iter().map(|(id, _)| *id).collect();
        self.find_segments_in_group(segment_id, &group_path, instance_index)
    }

    /// Count the repetitions of `child_group_id` in the group instance at
    /// `parent` (addressed at every level, as for
    /// [`find_segments_in_instance`](Self::find_segments_in_instance)); an
    /// empty `parent` counts the top-level repetitions.
    ///
    /// The default falls back to the innermost-index methods.
    fn child_instance_count(&self, parent: &[(&str, usize)], child_group_id: &str) -> usize {
        match parent.last() {
            None => self.group_instance_count(&[child_group_id]),
            Some(&(_, parent_instance)) => {
                let parent_path: Vec<&str> = parent.iter().map(|(id, _)| *id).collect();
                self.child_group_instance_count(&parent_path, parent_instance, child_group_id)
            }
        }
    }

    /// Like [`find_segments_in_instance`](Self::find_segments_in_instance), but
    /// including the segments of every group nested in that instance: "in
    /// dieser SG8 … SG10 CCI" reads the SG8's SG10s too.
    ///
    /// The default sees the instance's own segments only.
    fn find_segments_in_subtree(
        &self,
        segment_id: &str,
        path: &[(&str, usize)],
    ) -> Vec<OwnedSegment> {
        self.find_segments_in_instance(segment_id, path)
    }

    /// Check if a group instance has any segments at all.
    ///
    /// Returns `true` if the group instance at `instance_index` contains at least
    /// one segment. Used to distinguish genuinely populated group instances from
    /// navigator implementations that can't resolve per-instance segments.
    fn has_any_segment_in_group(&self, _group_path: &[&str], _instance_index: usize) -> bool {
        false // Default: unknown, treat as unpopulated
    }

    /// Check if a group instance belongs to the MIG variant identified by `mig_number`.
    ///
    /// Returns `true` when the instance's variant defines the given `mig_number`
    /// (directly or in a nested group). Used to scope per-instance rules — a rule
    /// tagged with `mig_number` only applies to instances whose variant includes
    /// that number. Example: PID 55218 has two SG8 variants (sg8_z01 with SEQ
    /// mig=00115, sg8_z45_z84 with SEQ mig=00171). A `[1P1..n]` package on SEQ
    /// mig=00171 must not be checked against sg8_z01 instances.
    ///
    /// Default: `true` (cannot determine — keep old behavior). Implementations
    /// backed by an assembled tree should consult `variant_mig_numbers`.
    fn instance_has_mig_number(
        &self,
        _group_path: &[&str],
        _instance_index: usize,
        _mig_number: &str,
    ) -> bool {
        true
    }

    /// Count repetitions of a child group within a specific parent group instance.
    ///
    /// * `parent_path` - Path to the parent group (e.g., `&["SG4", "SG8"]`)
    /// * `parent_instance` - Which repetition of the parent group (0-based)
    /// * `child_group_id` - ID of the child group to count (e.g., `"SG10"`)
    fn child_group_instance_count(
        &self,
        parent_path: &[&str],
        parent_instance: usize,
        child_group_id: &str,
    ) -> usize {
        let _ = (parent_path, parent_instance, child_group_id);
        0
    }

    /// Find all segments with the given tag within a child group instance.
    ///
    /// * `segment_id` - Segment tag to find (e.g., "CCI")
    /// * `parent_path` - Path to the parent group (e.g., `&["SG4", "SG8"]`)
    /// * `parent_instance` - Which repetition of the parent group (0-based)
    /// * `child_group_id` - ID of the child group (e.g., `"SG10"`)
    /// * `child_instance` - Which repetition of the child group (0-based)
    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> {
        let _ = (
            segment_id,
            parent_path,
            parent_instance,
            child_group_id,
            child_instance,
        );
        vec![]
    }

    /// Extract a single value from the first matching segment in a group instance.
    ///
    /// More efficient than `find_segments_in_group` when only one value is needed.
    ///
    /// * `segment_id` - Segment tag to find
    /// * `element_index` - Which element to extract from
    /// * `component_index` - Which component within the element
    /// * `group_path` - Path of group IDs from root
    /// * `instance_index` - Which repetition of the innermost group (0-based)
    fn extract_value_in_group(
        &self,
        segment_id: &str,
        element_index: usize,
        component_index: usize,
        group_path: &[&str],
        instance_index: usize,
    ) -> Option<String> {
        let _ = (
            segment_id,
            element_index,
            component_index,
            group_path,
            instance_index,
        );
        None
    }
}