use std::sync::Mutex; use pyo3::{exceptions::PyRuntimeError, PyResult}; /// A wrapper around a rust builder /// /// Rust builders are often implemented so that the builder methods /// consume the builder and return a new one. This is not compatible /// with the pyo3, which, being garbage collected, cannot easily obtain /// ownership of an object. /// /// This wrapper converts the compile-time safety of rust into runtime /// errors if any attempt to use the builder happens after it is consumed. pub struct BuilderWrapper { name: String, inner: Mutex>, } impl BuilderWrapper { pub fn new(name: impl AsRef, inner: T) -> Self { Self { name: name.as_ref().to_string(), inner: Mutex::new(Some(inner)), } } pub fn consume(&self, mod_fn: impl FnOnce(T) -> O) -> PyResult { let mut inner = self.inner.lock().unwrap(); let inner_builder = inner.take().ok_or_else(|| { PyRuntimeError::new_err(format!("{} has already been consumed", self.name)) })?; let result = mod_fn(inner_builder); Ok(result) } }