use serde_json::Value;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum GpuFunctionAvailability {
Available,
Unavailable { reason: String },
}
pub(crate) const REQUIRED_FEATURE_DISABLED: &str = "required_feature_disabled";
impl GpuFunctionAvailability {
pub(crate) fn of_build_feature(enabled: bool) -> Self {
if enabled { Self::Available } else { Self::Unavailable { reason: REQUIRED_FEATURE_DISABLED.to_string() } }
}
pub(crate) const fn is_available(&self) -> bool {
matches!(self, Self::Available)
}
pub(crate) fn unavailable_reason(&self) -> Option<&str> {
match self {
Self::Available => None,
Self::Unavailable { reason } => Some(reason),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct GpuFunctionDescriptor {
pub(crate) function_name: String,
pub(crate) provider: String,
pub(crate) signature: String,
pub(crate) summary: String,
pub(crate) relation_roles: Value,
pub(crate) argument_descriptions: Value,
pub(crate) options_schema: Value,
pub(crate) result_schemas: Value,
pub(crate) validation_request_schema: Value,
pub(crate) examples: Value,
pub(crate) limitations: Value,
pub(crate) availability: GpuFunctionAvailability,
}
impl GpuFunctionDescriptor {
pub(crate) fn relation_role_names(&self) -> Result<Vec<&str>, &'static str> {
let Value::Array(roles) = &self.relation_roles else {
return Err("relation_roles must be a JSON array");
};
roles
.iter()
.map(|role| match role {
Value::String(name) => Ok(name.as_str()),
Value::Object(role) => {
role.get("name").and_then(Value::as_str).ok_or("relation role objects must contain a string name")
},
_ => Err("each relation role must be a string or an object with a string name"),
})
.collect()
}
pub(crate) fn required_relation_role_names(&self) -> Result<Vec<&str>, &'static str> {
let Value::Array(roles) = &self.relation_roles else {
return Err("relation_roles must be a JSON array");
};
roles
.iter()
.filter_map(|role| match role {
Value::String(name) => Some(Ok(name.as_str())),
Value::Object(role) => {
let required = role.get("required").and_then(Value::as_bool).unwrap_or(true);
required.then(|| {
role.get("name")
.and_then(Value::as_str)
.ok_or("relation role objects must contain a string name")
})
},
_ => Some(Err("each relation role must be a string or an object with a string name")),
})
.collect()
}
}