pub(crate) mod builtins;
mod call;
mod config;
mod ctx;
mod erased;
mod layer;
pub mod layers;
mod outcome;
mod overlay;
mod registry;
mod spec;
mod sync;
mod templated;
pub mod testing;
pub use crate::expr::{ExprVisitor, FieldKind, FieldSpec, Rendered, ValueKind};
pub use call::{Function, Prepare};
pub use config::FunctionConfig;
pub(crate) use ctx::{Binding, CallStart, Primary};
pub use ctx::{CallInfo, Ctx};
pub use dataflow_rs_derive::FunctionConfig;
pub(crate) use erased::BoundCall;
pub use layer::{BoxFuture, CallLayer, Next};
pub use outcome::Outcome;
pub(crate) use overlay::Overlay;
pub(crate) use registry::Entry;
pub use registry::{FunctionInfo, Registry};
pub use spec::{FunctionSpec, Reference, RetrySafety};
pub(crate) use sync::{SyncCtx, eval, task_record, test};
pub use templated::Templated;
#[doc(hidden)]
pub mod __private {
pub use super::config::FunctionConfig;
pub use crate::base::{AuthoredPath, Result};
pub use crate::expr::{
CompileCx, ConfigField, ExprVisitor, FieldKind, FieldSpec, Output, Resolver, ValueKind,
Visit,
};
pub use datavalue::OwnedDataValue;
pub use serde_json::Value;
pub use std::sync::OnceLock;
use crate::base::{Error, ErrorKind, IssueCode};
use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_json::Map;
use std::borrow::Cow;
#[derive(Clone, Copy, Debug)]
pub struct Key {
key: &'static str,
default: Option<&'static str>,
output: bool,
}
impl Key {
pub const fn new(key: &'static str, default: Option<&'static str>, output: bool) -> Self {
Self {
key,
default,
output,
}
}
}
pub fn object<'v>(input: &'v Value, cx: &mut CompileCx<'_>) -> Option<&'v Map<String, Value>> {
let object = input.as_object();
if object.is_none() {
cx.issue(IssueCode::InputParse, "expected an object");
}
object
}
pub fn unknown_keys(object: &Map<String, Value>, known: &[&str], cx: &mut CompileCx<'_>) {
for key in object.keys().filter(|key| !known.contains(&key.as_str())) {
cx.at(key.as_str(), |cx| cx.unknown_key(key, known));
}
}
fn raw(object: &Map<String, Value>, key: Key) -> Option<Cow<'_, Value>> {
match object.get(key.key) {
Some(raw) if !(key.output && raw.is_null()) => Some(Cow::Borrowed(raw)),
_ => key.default.map(|text| Cow::Owned(default(text, key.key))),
}
}
fn default(text: &str, key: &str) -> Value {
serde_json::from_str(text).unwrap_or_else(|e| {
unreachable!("the default of `{key}` was validated by the derive ({e}): {text}")
})
}
pub(crate) fn missing(key: &str, cx: &mut CompileCx<'_>) {
cx.issue(IssueCode::InputParse, format!("missing field `{key}`"));
}
pub fn field<T: ConfigField>(
object: &Map<String, Value>,
key: Key,
cx: &mut CompileCx<'_>,
) -> Option<T> {
cx.at(key.key, |cx| match raw(object, key) {
Some(raw) => T::compile(&raw, cx),
None => T::absent().or_else(|| {
missing(key.key, cx);
None
}),
})
}
pub fn serde_field<T: DeserializeOwned>(
object: &Map<String, Value>,
key: Key,
cx: &mut CompileCx<'_>,
) -> Option<T> {
cx.at(key.key, |cx| {
let Some(raw) = raw(object, key) else {
return T::deserialize(&Value::Null).map_or_else(
|_| {
missing(key.key, cx);
None
},
Some,
);
};
T::deserialize(&*raw)
.map_err(|e| cx.issue(IssueCode::InputParse, e.to_string()))
.ok()
})
}
pub fn serde_required<T: DeserializeOwned>() -> bool {
T::deserialize(&Value::Null).is_err()
}
pub type Entries = Vec<(String, OwnedDataValue)>;
pub fn resolve_field<T: ConfigField>(
entries: &mut Entries,
key: &str,
field: &T,
r: &mut dyn Resolver,
) -> Result<()> {
if let Some(value) = field.resolve(r)? {
entries.push((key.to_owned(), value));
}
Ok(())
}
pub fn resolve_serde<T: Serialize>(entries: &mut Entries, key: &str, field: &T) -> Result<()> {
let refused = |e: serde_json::Error| {
Error::new(
ErrorKind::Config,
format!("the field `{key}` does not serialize: {e}"),
)
};
let text = serde_json::to_string(field).map_err(refused)?;
let value =
crate::base::exact(&mut serde_json::Deserializer::from_str(&text)).map_err(refused)?;
if !value.is_null() {
entries.push((key.to_owned(), value));
}
Ok(())
}
pub fn finish<T>(out: T, rejected_before: usize, cx: &CompileCx<'_>) -> Option<T> {
(cx.rejected() == rejected_before).then_some(out)
}
pub fn spec(
name: &'static str,
kind: FieldKind,
required: bool,
records: bool,
default: Option<&'static str>,
primary: bool,
description: Option<&'static str>,
) -> FieldSpec {
FieldSpec {
name: Cow::Borrowed(name),
kind,
required,
records: records || kind.contains_output(),
default: default.map(Cow::Borrowed),
primary,
description: description.map(Cow::Borrowed),
}
}
}