Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/commands/inspect/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ pub fn execute(args: &Args, sink: LogSink, global: &GlobalOptions) -> anyhow::Re

async fn execute_async(_args: Args, _sink: LogSink, _global: GlobalOptions) -> anyhow::Result<()> {
let (engine, _shutdown) = bootstrap::new_engine()?;
for (provider, func) in engine.provider_functions() {
println!("heph.{provider}.{func}");
for (provider, _func, rendered) in engine.provider_functions() {
println!("heph.{provider}.{rendered}");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove heph. prefix

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
Ok(())
}
17 changes: 9 additions & 8 deletions src/engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,17 +359,18 @@ impl Engine {
&self.result_lock
}

/// Every `(provider name, function name)` pair exposed across all registered
/// providers, sorted. Surfaced via `heph inspect functions`.
pub fn provider_functions(&self) -> Vec<(String, String)> {
let mut out: Vec<(String, String)> = self
/// Every `(provider name, function name, rendered signature)` exposed across
/// all registered providers, sorted. The rendered signature looks like
/// `glob(pattern: string) -> list[string]`. Surfaced via `heph inspect functions`.
pub fn provider_functions(&self) -> Vec<(String, String, String)> {
let mut out: Vec<(String, String, String)> = self
.providers
.iter()
.flat_map(|p| {
p.provider
.functions()
.into_iter()
.map(move |def| (p.name.clone(), def.name))
p.provider.functions().into_iter().map(move |def| {
let rendered = def.signature.render(&def.name);
(p.name.clone(), def.name, rendered)
})
})
.collect();
out.sort();
Expand Down
37 changes: 28 additions & 9 deletions src/engine/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::htaddr::Addr;
use crate::htmatcher::Matcher;
use crate::htpkg::PkgBuf;
use crate::htvalue::Value;
use crate::htvalue::signature::FnSignature;
use async_trait::async_trait;
use futures::future::BoxFuture;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -112,9 +113,21 @@ pub trait ProviderFn: Send + Sync {
async fn call(&self, ctx: &FnCallContext<'_>, args: FnArgs) -> anyhow::Result<Value>;
}

/// One exposed function: its bare name (no `heph.<provider>.` prefix) and handler.
/// One exposed function: its bare name (no `heph.<provider>.` prefix), its
/// declarative signature, and its handler. The engine enforces `signature`
/// against every call (see [`crate::htvalue::signature::FnSignature`]).
pub struct ProviderFunctionDef {
pub name: String,
pub signature: FnSignature,
pub func: Arc<dyn ProviderFn>,
}

/// A function as held in the [`ProviderFunctionRegistry`]: its signature
/// (shared, so the Starlark bridge can both enforce it and derive a native
/// param spec from it) plus the handler.
#[derive(Clone)]
pub struct RegisteredFn {
pub signature: Arc<FnSignature>,
pub func: Arc<dyn ProviderFn>,
}

Expand Down Expand Up @@ -144,7 +157,7 @@ pub struct FnArgs {
/// (the buildfile provider) via [`Provider::set_function_registry`].
#[derive(Default)]
pub struct ProviderFunctionRegistry {
map: HashMap<String, HashMap<String, Arc<dyn ProviderFn>>>,
map: HashMap<String, HashMap<String, RegisteredFn>>,
}

impl ProviderFunctionRegistry {
Expand All @@ -155,25 +168,31 @@ impl ProviderFunctionRegistry {
}
let entry = self.map.entry(provider.to_string()).or_default();
for def in defs {
entry.insert(def.name, def.func);
entry.insert(
def.name,
RegisteredFn {
signature: Arc::new(def.signature),
func: def.func,
},
);
}
}

/// Look up a single handler by provider + function name.
pub fn get(&self, provider: &str, func: &str) -> Option<&Arc<dyn ProviderFn>> {
/// Look up a single function by provider + function name.
pub fn get(&self, provider: &str, func: &str) -> Option<&RegisteredFn> {
self.map.get(provider).and_then(|m| m.get(func))
}

/// Iterate `(provider, function name, handler)` over every registered function.
pub fn iter(&self) -> impl Iterator<Item = (&str, &str, &Arc<dyn ProviderFn>)> {
/// Iterate `(provider, function name, function)` over every registered function.
pub fn iter(&self) -> impl Iterator<Item = (&str, &str, &RegisteredFn)> {
self.map.iter().flat_map(|(p, fns)| {
fns.iter()
.map(move |(name, func)| (p.as_str(), name.as_str(), func))
.map(move |(name, rf)| (p.as_str(), name.as_str(), rf))
})
}

/// Iterate `(provider name, its functions)` — one entry per provider.
pub fn providers(&self) -> impl Iterator<Item = (&str, &HashMap<String, Arc<dyn ProviderFn>>)> {
pub fn providers(&self) -> impl Iterator<Item = (&str, &HashMap<String, RegisteredFn>)> {
self.map.iter().map(|(p, fns)| (p.as_str(), fns))
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/engine/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2083,7 +2083,9 @@ mod tests {
.unwrap();
let fns = engine.provider_functions();
assert!(
fns.contains(&("fs".to_string(), "glob".to_string())),
fns.iter().any(|(p, n, sig)| p == "fs"
&& n == "glob"
&& sig == "glob(pattern: string) -> list[string]"),
"{fns:?}"
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/htvalue/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

pub mod signature;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Value {
String(String),
Expand Down
Loading