use std::{fmt, time::Duration};
use super::CapabilityOperationKind;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PlanResolutionError {
UnsupportedSchemaVersion { expected: u32, actual: u32 },
DuplicateModuleInstance { instance_key: String },
MissingExecutionLane,
InvalidExecutionLane { execution_lane: String },
DuplicateExecutionLane { execution_lane: String },
UndeclaredExecutionLane {
instance_key: String,
execution_lane: String,
},
InvalidModuleEntrypoint { instance_key: String },
DuplicateProvidedCapability {
provider_instance: String,
capability_id: String,
},
DuplicateOperation {
provider_instance: String,
capability_id: String,
operation: String,
},
DuplicateRequiredCapability {
consumer_instance: String,
capability_id: String,
},
InvalidConsumerReference {
consumer_instance: String,
capability_id: String,
},
InvalidProviderReference {
consumer_instance: String,
capability_id: String,
provider_instance: String,
},
UndeclaredCapabilityRequirement {
consumer_instance: String,
capability_id: String,
},
IncompatibleCapabilityVersion {
consumer_instance: String,
capability_id: String,
required: String,
provided: String,
provider_instance: String,
},
CrossLaneTransferUnsupported {
consumer_instance: String,
provider_instance: String,
capability_id: String,
},
CrossLaneInteractionUnsupported {
capability_id: String,
operation: String,
interaction: CapabilityOperationKind,
},
MissingOneBinding {
consumer_instance: String,
capability_id: String,
},
AmbiguousOneBinding {
consumer_instance: String,
capability_id: String,
providers: usize,
},
AmbiguousOptionalBinding {
consumer_instance: String,
capability_id: String,
providers: usize,
},
DuplicateBinding {
consumer_instance: String,
capability_id: String,
provider_instance: String,
},
InvalidRequestAdmission {
capability_id: String,
operation: String,
queue_capacity: usize,
max_concurrency: usize,
},
UnknownAdmissionOperation {
capability_id: String,
operation: String,
},
UnknownOperationInteraction {
capability_id: String,
operation: String,
},
InvalidRestartPolicy {
instance_key: String,
max_attempts: usize,
window: Duration,
},
ActivationCycle { instances: Vec<String> },
}
impl fmt::Display for PlanResolutionError {
#[allow(clippy::too_many_lines)]
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnsupportedSchemaVersion { expected, actual } => write!(
formatter,
"unsupported Plan schema version {actual}; expected {expected}"
),
Self::DuplicateModuleInstance { instance_key } => {
write!(formatter, "duplicate Module Instance `{instance_key}`")
}
Self::MissingExecutionLane => {
formatter.write_str("Resolved App Plan declares no Execution Lanes")
}
Self::InvalidExecutionLane { execution_lane } => {
write!(formatter, "invalid Execution Lane `{execution_lane}`")
}
Self::DuplicateExecutionLane { execution_lane } => {
write!(formatter, "duplicate Execution Lane `{execution_lane}`")
}
Self::UndeclaredExecutionLane {
instance_key,
execution_lane,
} => write!(
formatter,
"Module Instance `{instance_key}` is placed on undeclared Execution Lane `{execution_lane}`"
),
Self::InvalidModuleEntrypoint { instance_key } => write!(
formatter,
"Module Instance `{instance_key}` has an empty entrypoint"
),
Self::DuplicateProvidedCapability {
provider_instance,
capability_id,
} => write!(
formatter,
"Module Instance `{provider_instance}` provides Capability `{capability_id}` more than once"
),
Self::DuplicateOperation {
provider_instance,
capability_id,
operation,
} => write!(
formatter,
"Module Instance `{provider_instance}` Capability `{capability_id}` declares Operation `{operation}` more than once"
),
Self::DuplicateRequiredCapability {
consumer_instance,
capability_id,
} => write!(
formatter,
"Module Instance `{consumer_instance}` requires Capability `{capability_id}` more than once"
),
Self::InvalidConsumerReference {
consumer_instance,
capability_id,
} => write!(
formatter,
"Capability `{capability_id}` names missing consumer `{consumer_instance}`"
),
Self::InvalidProviderReference {
consumer_instance,
capability_id,
provider_instance,
} => write!(
formatter,
"consumer `{consumer_instance}` names invalid provider `{provider_instance}` for Capability `{capability_id}`"
),
Self::UndeclaredCapabilityRequirement {
consumer_instance,
capability_id,
} => write!(
formatter,
"consumer `{consumer_instance}` has no declared requirement for Capability `{capability_id}`"
),
Self::IncompatibleCapabilityVersion {
consumer_instance,
capability_id,
required,
provided,
provider_instance,
} => write!(
formatter,
"consumer `{consumer_instance}` requires Capability `{capability_id}` version `{required}`, but provider `{provider_instance}` provides `{provided}`"
),
Self::CrossLaneTransferUnsupported {
consumer_instance,
provider_instance,
capability_id,
} => write!(
formatter,
"consumer `{consumer_instance}` binds Capability `{capability_id}` across Execution Lanes to provider `{provider_instance}`, but its contract types do not support cross-lane transfer"
),
Self::CrossLaneInteractionUnsupported {
capability_id,
operation,
interaction,
} => write!(
formatter,
"Capability `{capability_id}` Operation `{operation}` uses {interaction:?}, which this Plan version cannot transfer across Execution Lanes"
),
Self::MissingOneBinding {
consumer_instance,
capability_id,
} => write!(
formatter,
"consumer `{consumer_instance}` is missing one binding for Capability `{capability_id}`"
),
Self::AmbiguousOneBinding {
consumer_instance,
capability_id,
providers,
} => write!(
formatter,
"consumer `{consumer_instance}` has {providers} bindings for one Capability `{capability_id}`"
),
Self::AmbiguousOptionalBinding {
consumer_instance,
capability_id,
providers,
} => write!(
formatter,
"consumer `{consumer_instance}` has {providers} bindings for optional Capability `{capability_id}`"
),
Self::DuplicateBinding {
consumer_instance,
capability_id,
provider_instance,
} => write!(
formatter,
"consumer `{consumer_instance}` binds Capability `{capability_id}` to provider `{provider_instance}` more than once"
),
Self::InvalidRequestAdmission {
capability_id,
operation,
queue_capacity,
max_concurrency,
} => write!(
formatter,
"Capability `{capability_id}` Operation `{operation}` has invalid request admission (queue capacity {queue_capacity}, concurrency {max_concurrency})"
),
Self::UnknownAdmissionOperation {
capability_id,
operation,
} => write!(
formatter,
"Capability `{capability_id}` configures request admission for unknown Operation `{operation}`"
),
Self::UnknownOperationInteraction {
capability_id,
operation,
} => write!(
formatter,
"Capability `{capability_id}` configures interaction metadata for unknown Operation `{operation}`"
),
Self::InvalidRestartPolicy {
instance_key,
max_attempts,
window,
} => write!(
formatter,
"Module Instance `{instance_key}` has invalid restart policy (attempts {max_attempts}, window {window:?})"
),
Self::ActivationCycle { instances } => write!(
formatter,
"required Capability activation cycle: {}",
instances.join(" -> ")
),
}
}
}
impl std::error::Error for PlanResolutionError {}