graphrecords-query 0.5.0

High-performance graph-based data records
Documentation
use super::{
    ArityDescriptor, Bindings, CapabilityRegistry, EmissionSpec, IndexDescriptor,
    LaneShapeDescriptor, OperandDescriptor, OrderDescriptor, OutArityTable, ValueDescriptor,
    VariableIdentifier,
};

#[derive(Clone, Debug)]
pub enum IndexDescriptorTemplate {
    Concrete(IndexDescriptor),
    Variable(VariableIdentifier),
    Expanded { parent: Box<Self>, child: Box<Self> },
    GroupKeyOf(VariableIdentifier),
}

impl IndexDescriptorTemplate {
    pub(super) fn fill(
        &self,
        bindings: &Bindings,
        capabilities: &CapabilityRegistry,
    ) -> IndexDescriptor {
        match self {
            Self::Concrete(index) => index.clone(),
            Self::Variable(variable) => bindings
                .index(*variable)
                .unwrap_or_else(|| {
                    panic!("registry output has no binding for index variable {variable}")
                })
                .clone(),
            Self::Expanded { parent, child } => IndexDescriptor::expanded(
                parent.fill(bindings, capabilities),
                child.fill(bindings, capabilities),
            ),
            Self::GroupKeyOf(variable) => {
                let value = bindings.value(*variable).unwrap_or_else(|| {
                    panic!("registry output has no binding for value variable {variable}")
                });

                capabilities.group_key(value).unwrap_or_else(|| {
                    panic!("registry admitted a grouping value without a group key domain")
                })
            }
        }
    }
}

#[derive(Clone, Debug)]
pub enum ValueDescriptorTemplate {
    Concrete(ValueDescriptor),
    Variable(VariableIdentifier),
    Index(IndexDescriptorTemplate),
    EntityReference(IndexDescriptorTemplate),
}

impl ValueDescriptorTemplate {
    pub(super) fn fill(
        &self,
        bindings: &Bindings,
        capabilities: &CapabilityRegistry,
    ) -> ValueDescriptor {
        match self {
            Self::Concrete(value) => value.clone(),
            Self::Variable(variable) => bindings
                .value(*variable)
                .unwrap_or_else(|| {
                    panic!("registry output has no binding for value variable {variable}")
                })
                .clone(),
            Self::Index(index) => ValueDescriptor::index(index.fill(bindings, capabilities)),
            Self::EntityReference(index) => {
                ValueDescriptor::entity_reference_index(index.fill(bindings, capabilities))
            }
        }
    }
}

#[derive(Clone, Debug)]
pub enum LaneShapeDescriptorTemplate {
    Indexed {
        index: IndexDescriptorTemplate,
        value: ValueDescriptorTemplate,
    },
    Bare {
        value: ValueDescriptorTemplate,
    },
    Variable(VariableIdentifier),
}

impl LaneShapeDescriptorTemplate {
    pub(super) fn fill(
        &self,
        bindings: &Bindings,
        capabilities: &CapabilityRegistry,
    ) -> LaneShapeDescriptor {
        match self {
            Self::Indexed { index, value } => LaneShapeDescriptor::Indexed {
                index: index.fill(bindings, capabilities),
                value: value.fill(bindings, capabilities),
            },
            Self::Bare { value } => LaneShapeDescriptor::Bare {
                value: value.fill(bindings, capabilities),
            },
            Self::Variable(variable) => bindings
                .shape(*variable)
                .unwrap_or_else(|| {
                    panic!("registry output has no binding for shape variable {variable}")
                })
                .clone(),
        }
    }
}

#[derive(Clone, Debug)]
pub enum OrderDescriptorTemplate {
    Concrete(OrderDescriptor),
    Variable(VariableIdentifier),
}

impl OrderDescriptorTemplate {
    pub(super) fn fill(&self, bindings: &Bindings) -> OrderDescriptor {
        match self {
            Self::Concrete(order) => *order,
            Self::Variable(variable) => bindings.order(*variable).unwrap_or_else(|| {
                panic!("registry output has no binding for order variable {variable}")
            }),
        }
    }
}

#[derive(Clone, Debug)]
pub enum ArityDescriptorTemplate {
    Multiple(OrderDescriptorTemplate),
    Single,
    Definite,
    Variable(VariableIdentifier),
    EmissionOf {
        input: VariableIdentifier,
        emission: EmissionSpec,
    },
}

impl ArityDescriptorTemplate {
    pub(super) fn fill(&self, bindings: &Bindings, arities: &OutArityTable) -> ArityDescriptor {
        match self {
            Self::Multiple(order) => ArityDescriptor::Multiple {
                order: order.fill(bindings),
            },
            Self::Single => ArityDescriptor::Single,
            Self::Definite => ArityDescriptor::Definite,
            Self::Variable(variable) => Self::bound_arity(bindings, *variable),
            Self::EmissionOf { input, emission } => arities.resolve(
                *emission,
                Self::bound_arity(bindings, *input),
                bindings.argument_retention(),
            ),
        }
    }

    fn bound_arity(bindings: &Bindings, variable: VariableIdentifier) -> ArityDescriptor {
        bindings.arity(variable).unwrap_or_else(|| {
            panic!("registry output has no binding for arity variable {variable}")
        })
    }
}

#[derive(Clone, Debug)]
pub enum OperandDescriptorTemplate {
    Lane {
        shape: LaneShapeDescriptorTemplate,
        arity: ArityDescriptorTemplate,
    },
    Group {
        member: IndexDescriptorTemplate,
        key: IndexDescriptorTemplate,
        payload: Box<Self>,
    },
    Variable(VariableIdentifier),
}

impl OperandDescriptorTemplate {
    pub(super) fn fill(
        &self,
        bindings: &Bindings,
        capabilities: &CapabilityRegistry,
        arities: &OutArityTable,
    ) -> OperandDescriptor {
        match self {
            Self::Lane { shape, arity } => OperandDescriptor::Lane {
                shape: shape.fill(bindings, capabilities),
                arity: arity.fill(bindings, arities),
            },
            Self::Group {
                member,
                key,
                payload,
            } => OperandDescriptor::Group {
                member: member.fill(bindings, capabilities),
                key: key.fill(bindings, capabilities),
                payload: Box::new(payload.fill(bindings, capabilities, arities)),
            },
            Self::Variable(variable) => bindings
                .operand(*variable)
                .unwrap_or_else(|| {
                    panic!("registry output has no binding for operand variable {variable}")
                })
                .clone(),
        }
    }
}