use std::sync::OnceLock;
use harn_builtin_meta::{BuiltinContract, BuiltinSignature};
use harn_builtin_registry::BuiltinManifestEntry;
#[derive(Debug, Clone, Copy)]
pub struct CapabilityMethodDef {
pub signature: BuiltinSignature,
pub contract: BuiltinContract,
pub doc: &'static str,
pub signature_text: Option<&'static str>,
}
pub static ALL_CAPABILITY_METHOD_DEFS: &[&CapabilityMethodDef] =
include!(concat!(env!("OUT_DIR"), "/capability_method_defs.rs"));
#[doc(hidden)]
pub mod support {
pub use crate::{CapabilityMethodDef, ALL_CAPABILITY_METHOD_DEFS};
pub use harn_builtin_meta::{
shapes, BuiltinContract, BuiltinExposure, BuiltinSignature, CapabilityId, EffectAccess,
EffectKind, EffectSpec, Param, ResourceSelector, ShapeFieldDescriptor, Ty, TY_ANY, TY_BOOL,
TY_BYTES, TY_BYTES_OR_NIL, TY_CLOSURE, TY_DICT, TY_DICT_OR_NIL, TY_DURATION, TY_FLOAT,
TY_INT, TY_INT_OR_NIL, TY_LIST, TY_NEVER, TY_NIL, TY_NUMBER, TY_RESOURCE, TY_STRING,
TY_STRING_OR_NIL,
};
}
use harn_builtin_macros::harn_capability_contract as capability_method;
mod vm_declared;
include!("ai.rs");
include!("data.rs");
include!("host.rs");
include!("io.rs");
pub fn manifest() -> &'static [&'static BuiltinManifestEntry] {
static MANIFEST: OnceLock<Vec<&'static BuiltinManifestEntry>> = OnceLock::new();
MANIFEST
.get_or_init(|| {
let mut defs = ALL_CAPABILITY_METHOD_DEFS.to_vec();
defs.sort_by_key(|def| def.signature.name);
defs.into_iter()
.map(|def| {
Box::leak(Box::new(BuiltinManifestEntry {
name: def.signature.name,
canonical_name: def.signature.name,
signature: &def.signature,
contract: def.contract,
})) as &'static BuiltinManifestEntry
})
.collect()
})
.as_slice()
}
pub fn capability_method_entry(field: &str, method: &str) -> Option<&'static BuiltinManifestEntry> {
let capability = harn_builtin_meta::CapabilityId::from_field_name(field)?;
manifest().iter().copied().find(|entry| {
matches!(
entry.contract.exposure,
harn_builtin_meta::BuiltinExposure::HarnessMethod {
capability: candidate,
method: candidate_method,
} if candidate == capability && candidate_method == method
)
})
}
#[must_use]
pub fn is_declared_capability_method(field: &str, method: &str) -> bool {
if capability_method_entry(field, method).is_some() {
return true;
}
if vm_declared::VM_DECLARED_CAPABILITY_METHODS
.binary_search(&(field, method))
.is_ok()
{
return true;
}
harn_builtin_meta::CapabilityId::from_field_name(field).is_some_and(|capability| {
harn_builtin_meta::host_capabilities::is_host_capability_method(capability, method)
})
}
#[must_use]
pub fn declared_capability_method_names(field: &str) -> Vec<&'static str> {
let mut names: Vec<&'static str> = vm_declared::VM_DECLARED_CAPABILITY_METHODS
.iter()
.filter(|(capability, _)| *capability == field)
.map(|(_, method)| *method)
.collect();
if let Some(capability) = harn_builtin_meta::CapabilityId::from_field_name(field) {
names.extend(
manifest()
.iter()
.filter_map(|entry| match entry.contract.exposure {
harn_builtin_meta::BuiltinExposure::HarnessMethod {
capability: candidate,
method,
} if candidate == capability => Some(method),
_ => None,
}),
);
names.extend(
harn_builtin_meta::host_capabilities::all_host_capability_groups()
.filter(|group| group.capability == capability)
.flat_map(|group| group.methods.iter().copied()),
);
}
names.sort_unstable();
names.dedup();
names
}
#[cfg(test)]
mod tests {
#[test]
fn vm_declared_methods_are_sorted_and_unique() {
let table = super::vm_declared::VM_DECLARED_CAPABILITY_METHODS;
assert!(!table.is_empty());
assert!(
table.windows(2).all(|pair| pair[0] < pair[1]),
"the generated table must be sorted and free of duplicates"
);
}
#[test]
fn a_vm_only_method_is_declared_without_the_vm() {
assert!(super::capability_method_entry("runtime", "shared_cell").is_none());
assert!(super::is_declared_capability_method(
"runtime",
"shared_cell"
));
}
#[test]
fn a_contract_owned_method_is_declared() {
assert!(super::is_declared_capability_method("fs", "read_text"));
}
#[test]
fn a_host_bridged_method_is_declared() {
assert!(super::capability_method_entry("workspace", "search").is_none());
assert!(super::is_declared_capability_method("workspace", "search"));
assert!(super::declared_capability_method_names("workspace").contains(&"search"));
}
#[test]
fn a_typo_is_not_declared() {
assert!(!super::is_declared_capability_method("fs", "bogus_method"));
assert!(!super::is_declared_capability_method(
"runtime",
"shared_cel"
));
assert!(!super::is_declared_capability_method(
"workspace",
"searchh"
));
}
}