#![cfg(feature = "pyo3")]
use std::sync::Arc;
use parking_lot::Mutex;
use pyo3::prelude::*;
use smol_str::SmolStr;
use crate::error::PyPluginError;
#[derive(Debug)]
pub struct PyScalarEntry {
pub name: SmolStr,
pub args: Vec<SmolStr>,
pub returns: SmolStr,
pub vectorized: bool,
pub determinism: SmolStr,
pub callable: Py<PyAny>,
}
#[derive(Debug)]
pub struct PyAggregateEntry {
pub name: SmolStr,
pub args: Vec<SmolStr>,
pub returns: SmolStr,
pub determinism: SmolStr,
pub init: Py<PyAny>,
pub accumulate: Py<PyAny>,
pub merge: Py<PyAny>,
pub finalize: Py<PyAny>,
}
#[derive(Debug)]
pub struct PyProcedureEntry {
pub name: SmolStr,
pub args: Vec<SmolStr>,
pub yields: Vec<SmolStr>,
pub mode: SmolStr,
pub callable: Py<PyAny>,
}
#[derive(Debug, Default)]
pub struct PyManifest {
pub id: SmolStr,
pub version: SmolStr,
pub determinism: SmolStr,
pub scalar_fns: Vec<PyScalarEntry>,
pub aggregate_fns: Vec<PyAggregateEntry>,
pub procedures: Vec<PyProcedureEntry>,
}
impl PyManifest {
#[must_use]
pub fn empty() -> Self {
Self {
id: SmolStr::new("py.live"),
version: SmolStr::new("0.0.0"),
determinism: SmolStr::new("nondeterministic"),
scalar_fns: Vec::new(),
aggregate_fns: Vec::new(),
procedures: Vec::new(),
}
}
pub fn validate_non_empty(&self) -> Result<(), PyPluginError> {
if self.scalar_fns.is_empty() && self.aggregate_fns.is_empty() && self.procedures.is_empty()
{
return Err(PyPluginError::ManifestInvalid(
"no scalar / aggregate / procedure entries were declared by decorators".into(),
));
}
Ok(())
}
}
#[derive(Debug, Default)]
pub struct ManifestBuilder {
inner: Mutex<PyManifest>,
}
impl ManifestBuilder {
#[must_use]
pub fn new() -> Arc<Self> {
Arc::new(Self {
inner: Mutex::new(PyManifest::empty()),
})
}
pub fn set_id(&self, id: impl Into<SmolStr>) {
self.inner.lock().id = id.into();
}
pub fn set_version(&self, version: impl Into<SmolStr>) {
self.inner.lock().version = version.into();
}
pub fn set_determinism(&self, determinism: impl Into<SmolStr>) {
self.inner.lock().determinism = determinism.into();
}
pub fn push_scalar(&self, entry: PyScalarEntry) {
self.inner.lock().scalar_fns.push(entry);
}
pub fn push_aggregate(&self, entry: PyAggregateEntry) {
self.inner.lock().aggregate_fns.push(entry);
}
pub fn push_procedure(&self, entry: PyProcedureEntry) {
self.inner.lock().procedures.push(entry);
}
#[must_use]
pub fn into_manifest(&self) -> PyManifest {
std::mem::replace(&mut *self.inner.lock(), PyManifest::empty())
}
#[must_use]
pub fn entry_count(&self) -> usize {
let m = self.inner.lock();
m.scalar_fns.len() + m.aggregate_fns.len() + m.procedures.len()
}
}