///|
/// An immutable in-memory feature/device catalog used by planning adapters.
pub(all) struct Catalog {
features : Array[Feature]
devices : Array[Device]
}
///|
/// Construct a catalog while preserving caller order.
pub fn catalog_from(
features~ : Array[Feature],
devices~ : Array[Device],
) -> Catalog {
{ features, devices }
}
///|
/// Find the first feature with the requested identifier.
pub fn find_feature(catalog : Catalog, id : String) -> Feature? {
let mut result = None
for feature in catalog.features {
if feature.id == id && result is None {
result = Some(feature)
}
}
result
}
///|
/// Find the first device with the requested identifier.
pub fn find_device(catalog : Catalog, id : String) -> Device? {
let mut result = None
for device in catalog.devices {
if device.id == id && result is None {
result = Some(device)
}
}
result
}
///|
/// Return features of one kind in source order.
pub fn features_of_kind(
catalog : Catalog,
kind : FeatureKind,
) -> Array[Feature] {
let result = []
for feature in catalog.features {
if feature.kind == kind {
result.push(feature)
}
}
result
}
///|
/// Return datum features in source order.
pub fn datum_features(catalog : Catalog) -> Array[Feature] {
let result = []
for feature in catalog.features {
if feature.datum {
result.push(feature)
}
}
result
}
///|
/// Count catalog features supported by a device.
pub fn supported_feature_count(
device : Device,
features : Array[Feature],
) -> Int {
let mut result = 0
for feature in features {
if device.can_measure(feature) {
result += 1
}
}
result
}
///|
/// Return features with no reachable supporting device.
pub fn unmeasurable_features(catalog : Catalog) -> Array[Feature] {
let result = []
for feature in catalog.features {
let mut supported = false
for device in catalog.devices {
if device.can_measure(feature) {
supported = true
}
}
if !supported {
result.push(feature)
}
}
result
}
///|
/// Return whether structural validation has no errors.
pub fn catalog_is_valid(catalog : Catalog) -> Bool {
!has_errors(validate_catalog(catalog.features, catalog.devices))
}
///|
/// Return feature identifiers in source order.
pub fn catalog_feature_ids(catalog : Catalog) -> Array[String] {
let result = []
for feature in catalog.features {
result.push(feature.id)
}
result
}
///|
/// Return device identifiers in source order.
pub fn catalog_device_ids(catalog : Catalog) -> Array[String] {
let result = []
for device in catalog.devices {
result.push(device.id)
}
result
}
///|
/// Return the first index of a feature identifier, or -1.
pub fn feature_index(catalog : Catalog, id : String) -> Int {
let mut result = -1
for i, feature in catalog.features {
if feature.id == id && result < 0 {
result = i
}
}
result
}
///|
/// Return the first index of a device identifier, or -1.
pub fn device_index(catalog : Catalog, id : String) -> Int {
let mut result = -1
for i, device in catalog.devices {
if device.id == id && result < 0 {
result = i
}
}
result
}
///|
/// Return all devices that can measure a feature.
pub fn supported_devices(catalog : Catalog, feature : Feature) -> Array[Device] {
let result = []
for device in catalog.devices {
if device.can_measure(feature) {
result.push(device)
}
}
result
}
///|
/// Return whether every catalog feature has a reachable device.
pub fn all_features_reachable(catalog : Catalog) -> Bool {
unmeasurable_features(catalog).length() == 0
}
///|
/// Count the number of unique feature kinds present in a catalog.
pub fn catalog_kind_count(catalog : Catalog) -> Int {
let kinds = []
for feature in catalog.features {
let mut seen = false
for kind in kinds {
if kind == feature.kind {
seen = true
}
}
if !seen {
kinds.push(feature.kind)
}
}
kinds.length()
}