use crate::codegen::builder::RustFileBuilder;
pub(super) fn add_generated_module_attributes(builder: &mut RustFileBuilder) {
// Suppress documentation and cast lints in generated code. Python stubs carry
// docs, and numeric casts are intentional FFI conversions.
builder.add_inner_attribute("allow(missing_docs)");
builder.add_inner_attribute("allow(deprecated, dead_code, unused_imports, unused_variables)");
builder.add_inner_attribute(
"allow(clippy::default_trait_access, clippy::cast_possible_wrap, clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::just_underscores_and_digits, clippy::unused_unit, clippy::let_unit_value, clippy::needless_borrow, clippy::too_many_arguments, clippy::map_identity, clippy::unnecessary_cast, clippy::unwrap_or_default, clippy::derivable_impls, clippy::needless_borrows_for_generic_args, clippy::unnecessary_fallible_conversions, clippy::useless_conversion, clippy::arc_with_non_send_sync, clippy::collapsible_if, clippy::clone_on_copy, clippy::should_implement_trait)",
);
// Pedantic/nursery lints that do not apply to autogenerated FFI bindings.
builder.add_inner_attribute(
"allow(clippy::unsafe_derive_deserialize, clippy::must_use_candidate, clippy::return_self_not_must_use, clippy::use_self, clippy::missing_const_for_fn, clippy::missing_errors_doc, clippy::needless_pass_by_value, clippy::doc_markdown, clippy::derive_partial_eq_without_eq, clippy::uninlined_format_args, clippy::redundant_clone, clippy::implicit_clone, clippy::redundant_closure_for_method_calls, clippy::wildcard_imports, clippy::option_if_let_else, clippy::too_many_lines)",
);
builder.add_inner_attribute("allow(clippy::multiple_unsafe_ops_per_block)");
builder.add_inner_attribute("allow(unsafe_code)");
}
pub(super) fn add_py_visitor_ref(builder: &mut RustFileBuilder) {
builder.add_item(
r#"
/// Wrapper for trait visitor types (`Py<PyAny>`) that implements Clone.
///
/// `Py<PyAny>` is not Clone. This wrapper uses `Arc<Py<PyAny>>` internally for cheap cloning.
/// The .inner field is public for compatibility with generated code that needs to access
/// the underlying `Py<PyAny>` for trait dispatch.
#[derive(Debug)]
pub struct PyVisitorRef {
pub inner: std::sync::Arc<pyo3::Py<pyo3::PyAny>>,
}
impl Clone for PyVisitorRef {
fn clone(&self) -> Self {
PyVisitorRef {
inner: std::sync::Arc::clone(&self.inner),
}
}
}
impl From<pyo3::Py<pyo3::PyAny>> for PyVisitorRef {
fn from(visitor: pyo3::Py<pyo3::PyAny>) -> Self {
PyVisitorRef {
inner: std::sync::Arc::new(visitor),
}
}
}
impl<'a, 'py> pyo3::FromPyObject<'a, 'py> for PyVisitorRef {
type Error = pyo3::PyErr;
fn extract(ob: pyo3::Borrowed<'a, 'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
Ok(PyVisitorRef {
inner: std::sync::Arc::new(ob.to_owned().unbind()),
})
}
}
impl<'py> pyo3::conversion::IntoPyObject<'py> for PyVisitorRef {
type Target = pyo3::PyAny;
type Output = pyo3::Bound<'py, pyo3::PyAny>;
type Error = std::convert::Infallible;
fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
Ok((*self.inner).bind(py).clone())
}
}
"#,
);
}
pub(super) fn add_json_helpers(builder: &mut RustFileBuilder) {
builder.add_item(
r#"
mod alef_json_str {
use serde::{Deserialize, Deserializer};
use serde_json::Value;
pub fn deserialize<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
let v = Value::deserialize(deserializer)?;
Ok(match v {
Value::String(s) => s,
other => other.to_string(),
})
}
}
mod alef_json_str_opt {
use serde::{Deserialize, Deserializer};
use serde_json::Value;
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
{
let v: Option<Value> = Option::deserialize(deserializer)?;
Ok(v.and_then(|val| match val {
Value::Null => None,
Value::String(s) => Some(s),
other => Some(other.to_string()),
}))
}
}
"#,
);
}