Skip to main content

neopdf/
lib.rs

1//! Generate `PyO3` interface for `neopdf`
2
3#![allow(unsafe_op_in_unsafe_fn)]
4
5use pyo3::prelude::*;
6use std::sync::atomic::{AtomicI32, Ordering};
7
8use crate::pdf::{PyLoaderMethod, PyPDF, PyPDFSet};
9use ::neopdf::manage::ManageData;
10
11/// Python bindings for the `converter` module.
12pub mod converter;
13/// Python bindings for the `gridpdf` module.
14pub mod gridpdf;
15/// Python bindings for the `manage` module.
16pub mod manage;
17/// Python bindings for the `metadata` module.
18pub mod metadata;
19/// Python bindings for the `parser` module.
20pub mod parser;
21/// Python bindings for the `PDF` module.
22pub mod pdf;
23/// Python bindings for the `uncertainty` module.
24pub mod uncertainty;
25/// Python bindings for the `writer` module.
26pub mod writer;
27
28static VERBOSITY: AtomicI32 = AtomicI32::new(0);
29
30/// Set the `NeoPDF` verbosity level (no-op, exists for LHAPDF API compatibility).
31#[pyfunction]
32#[pyo3(name = "setVerbosity")]
33fn set_verbosity(level: i32) {
34    VERBOSITY.store(level, Ordering::Relaxed);
35}
36
37/// Return the current verbosity level.
38#[pyfunction]
39fn verbosity() -> i32 {
40    VERBOSITY.load(Ordering::Relaxed)
41}
42
43/// Return a `PDFSet` object for the named set (LHAPDF-compatible).
44#[pyfunction]
45#[pyo3(name = "getPDFSet")]
46fn get_pdf_set(setname: &str) -> PyPDFSet {
47    PyPDFSet::new(setname)
48}
49
50/// Load a single PDF member by set name and member index (LHAPDF-compatible).
51#[pyfunction]
52#[pyo3(name = "mkPDF")]
53#[pyo3(signature = (pdf_name, member = 0))]
54fn mk_pdf(pdf_name: &str, member: usize) -> PyPDF {
55    PyPDF::new(pdf_name, member)
56}
57
58/// Load all members of a PDF set (LHAPDF-compatible).
59#[pyfunction]
60#[pyo3(name = "mkPDFs")]
61fn mk_pdfs(pdf_name: &str) -> Vec<PyPDF> {
62    PyPDF::mkpdfs(pdf_name, &PyLoaderMethod::Parallel)
63}
64
65/// Return a list of PDF set names available in the current data path.
66#[pyfunction]
67#[pyo3(name = "availablePDFSets")]
68fn available_pdf_sets() -> Vec<String> {
69    let data_path = ManageData::get_data_path();
70    let mut sets = Vec::new();
71    if let Ok(entries) = std::fs::read_dir(&data_path) {
72        for entry in entries.flatten() {
73            let path = entry.path();
74            if path.is_dir() {
75                let name = path
76                    .file_name()
77                    .unwrap_or_default()
78                    .to_string_lossy()
79                    .into_owned();
80                if path.join(format!("{name}.info")).exists() {
81                    sets.push(name);
82                }
83            }
84        }
85    }
86    sets.sort();
87    sets
88}
89
90/// Return the list of data paths searched for PDF sets.
91#[pyfunction]
92fn paths() -> Vec<String> {
93    vec![ManageData::get_data_path().to_string_lossy().into_owned()]
94}
95
96/// No-op: path management is controlled via the `NEOPDF_DATA_PATH` env var.
97#[pyfunction]
98#[pyo3(name = "setPaths")]
99fn set_paths(_paths: Vec<String>) {}
100
101/// No-op: path management is controlled via the `NEOPDF_DATA_PATH` env var.
102#[pyfunction]
103#[pyo3(name = "pathsAppend")]
104fn paths_append(_path: String) {}
105
106/// No-op: path management is controlled via the `NEOPDF_DATA_PATH` env var.
107#[pyfunction]
108#[pyo3(name = "pathsPrepend")]
109fn paths_prepend(_path: String) {}
110
111/// Return the NeoPDF version string (LHAPDF-compatible callable).
112#[pyfunction]
113fn version() -> &'static str {
114    env!("CARGO_PKG_VERSION")
115}
116
117/// `PyO3` Python module that contains all exposed classes from Rust.
118#[pymodule]
119fn neopdf(m: &Bound<'_, PyModule>) -> PyResult<()> {
120    m.add("__version__", env!("CARGO_PKG_VERSION"))?;
121    pdf::register(m)?;
122    metadata::register(m)?;
123    converter::register(m)?;
124    gridpdf::register(m)?;
125    manage::register(m)?;
126    parser::register(m)?;
127    writer::register(m)?;
128    uncertainty::register(m)?;
129    m.add_function(wrap_pyfunction!(set_verbosity, m)?)?;
130    m.add_function(wrap_pyfunction!(verbosity, m)?)?;
131    m.add_function(wrap_pyfunction!(get_pdf_set, m)?)?;
132    m.add_function(wrap_pyfunction!(mk_pdf, m)?)?;
133    m.add_function(wrap_pyfunction!(mk_pdfs, m)?)?;
134    m.add_function(wrap_pyfunction!(available_pdf_sets, m)?)?;
135    m.add_function(wrap_pyfunction!(paths, m)?)?;
136    m.add_function(wrap_pyfunction!(set_paths, m)?)?;
137    m.add_function(wrap_pyfunction!(paths_append, m)?)?;
138    m.add_function(wrap_pyfunction!(paths_prepend, m)?)?;
139    m.add_function(wrap_pyfunction!(version, m)?)?;
140    Ok(())
141}