///|
/// Integration boundary supported by the planning library.
pub(all) enum AdapterKind {
Cmm
Vision
Laser
OpcUa
} derive(Eq, Debug)
///|
/// Capability contract for a future measurement adapter.
pub(all) struct AdapterContract {
kind : AdapterKind
supported_kinds : Array[FeatureKind]
required_fields : Array[String]
}
///|
/// Construct an adapter contract.
pub fn adapter_contract(
kind : AdapterKind,
supported_kinds : Array[FeatureKind],
) -> AdapterContract {
let required_fields = match kind {
Cmm => ["device_id", "probe_id", "coordinate_system"]
Vision => ["camera_id", "calibration_id", "image_reference"]
Laser => ["scanner_id", "calibration_id", "point_cloud_reference"]
OpcUa => ["endpoint", "node_id", "timestamp"]
}
{ kind, supported_kinds, required_fields }
}
///|
/// Choose a conservative default adapter for a feature kind.
pub fn adapter_for_kind(kind : FeatureKind) -> AdapterContract {
let adapter = match kind {
Hole | Shaft | Slot | Circle => AdapterKind::Vision
Plane | Cylinder | Datum => AdapterKind::Cmm
}
let kinds = []
for candidate in all_feature_kinds() {
if candidate == kind {
kinds.push(candidate)
}
}
adapter_contract(adapter, kinds)
}
///|
/// Return a stable adapter name.
pub fn adapter_name(kind : AdapterKind) -> String {
match kind {
Cmm => "cmm"
Vision => "vision"
Laser => "laser"
OpcUa => "opcua"
}
}
///|
/// Parse an adapter name.
pub fn adapter_kind_from_name(name : String) -> AdapterKind? {
match name.trim().to_lower() {
"cmm" => Some(AdapterKind::Cmm)
"vision" => Some(AdapterKind::Vision)
"laser" => Some(AdapterKind::Laser)
"opcua" => Some(AdapterKind::OpcUa)
_ => None
}
}
///|
/// Return all adapter kinds in stable order.
pub fn all_adapter_kinds() -> Array[AdapterKind] {
[
AdapterKind::Cmm,
AdapterKind::Vision,
AdapterKind::Laser,
AdapterKind::OpcUa,
]
}
///|
/// Return whether an adapter supports a feature kind.
pub fn adapter_can_measure(
contract : AdapterContract,
kind : FeatureKind,
) -> Bool {
let mut result = false
for supported in contract.supported_kinds {
if supported == kind {
result = true
}
}
result
}
///|
/// Return whether a contract has a non-empty integration boundary.
pub fn adapter_contract_is_valid(contract : AdapterContract) -> Bool {
contract.supported_kinds.length() > 0 && contract.required_fields.length() > 0
}
///|
/// Explain an adapter/feature mismatch.
pub fn adapter_selection_reason(
contract : AdapterContract,
kind : FeatureKind,
) -> String {
if adapter_can_measure(contract, kind) {
"supported"
} else {
"unsupported-kind"
}
}
///|
/// Return the number of required integration fields.
pub fn adapter_required_field_count(contract : AdapterContract) -> Int {
contract.required_fields.length()
}
///|
/// Return whether an adapter normally connects to a live system.
pub fn adapter_is_online(kind : AdapterKind) -> Bool {
match kind {
OpcUa => true
_ => false
}
}
///|
/// Return whether an adapter requires calibration metadata.
pub fn adapter_requires_calibration(kind : AdapterKind) -> Bool {
match kind {
Cmm | Vision | Laser => true
OpcUa => false
}
}
///|
/// Return whether an adapter can process batches offline.
pub fn adapter_supports_batch(kind : AdapterKind) -> Bool {
match kind {
Cmm | Vision | Laser => true
OpcUa => false
}
}
///|
/// Return a stable adapter priority for selection UI.
pub fn adapter_priority(kind : AdapterKind) -> Int {
match kind {
Cmm => 0
Vision => 1
Laser => 2
OpcUa => 3
}
}
///|
/// Return the number of feature kinds supported by a contract.
pub fn adapter_supported_kind_count(contract : AdapterContract) -> Int {
contract.supported_kinds.length()
}
///|
/// Render an adapter contract summary.
pub fn adapter_contract_summary(contract : AdapterContract) -> String {
adapter_name(contract.kind) +
" kinds=" +
contract.supported_kinds.length().to_string() +
" fields=" +
contract.required_fields.length().to_string()
}
///|
/// Return the intersection of two adapter feature-kind lists.
pub fn adapter_kind_intersection(
left : AdapterContract,
right : AdapterContract,
) -> Array[FeatureKind] {
let result = []
for kind in left.supported_kinds {
if adapter_can_measure(right, kind) {
result.push(kind)
}
}
result
}
///|
/// Return whether two contracts can serve a common feature kind.
pub fn adapters_overlap(
left : AdapterContract,
right : AdapterContract,
) -> Bool {
adapter_kind_intersection(left, right).length() > 0
}