Skip to main content

gldf_rs_python/
lib.rs

1//! Python bindings for GLDF (General Lighting Data Format) parser
2//!
3//! This module provides Python bindings for parsing, converting, and manipulating GLDF files.
4
5#![allow(clippy::useless_conversion)]
6
7use gldf_rs::convert::ldt_to_gldf;
8use gldf_rs::gldf::GldfProduct;
9use gldf_rs::EditableGldf;
10use pyo3::exceptions::PyValueError;
11use pyo3::prelude::*;
12
13/// Convert a GLDF file to XML string
14#[pyfunction]
15fn gldf_to_xml(path: &str) -> PyResult<String> {
16    let loaded = GldfProduct::load_gldf(path)
17        .map_err(|e| PyValueError::new_err(format!("Failed to load GLDF: {}", e)))?;
18    loaded
19        .to_xml()
20        .map_err(|e| PyValueError::new_err(format!("Failed to convert to XML: {}", e)))
21}
22
23/// Convert a GLDF file to JSON string
24#[pyfunction]
25fn gldf_to_json(path: &str) -> PyResult<String> {
26    let loaded = GldfProduct::load_gldf(path)
27        .map_err(|e| PyValueError::new_err(format!("Failed to load GLDF: {}", e)))?;
28    loaded
29        .to_json()
30        .map_err(|e| PyValueError::new_err(format!("Failed to convert to JSON: {}", e)))
31}
32
33/// Parse XML string to JSON
34#[pyfunction]
35fn json_from_xml_str(xml_str: &str) -> PyResult<String> {
36    let loaded = GldfProduct::from_xml(xml_str)
37        .map_err(|e| PyValueError::new_err(format!("Failed to parse XML: {}", e)))?;
38    loaded
39        .to_json()
40        .map_err(|e| PyValueError::new_err(format!("Failed to convert to JSON: {}", e)))
41}
42
43/// Parse JSON string to XML
44#[pyfunction]
45fn xml_from_json(json_str: &str) -> PyResult<String> {
46    let loaded = GldfProduct::from_json(json_str)
47        .map_err(|e| PyValueError::new_err(format!("Failed to parse JSON: {}", e)))?;
48    loaded
49        .to_xml()
50        .map_err(|e| PyValueError::new_err(format!("Failed to convert to XML: {}", e)))
51}
52
53/// Load GLDF from bytes and return JSON representation
54#[pyfunction]
55fn gldf_from_bytes(data: &[u8]) -> PyResult<String> {
56    let loaded = GldfProduct::load_gldf_from_buf(data.to_vec())
57        .map_err(|e| PyValueError::new_err(format!("Failed to load GLDF from bytes: {}", e)))?;
58    loaded
59        .to_json()
60        .map_err(|e| PyValueError::new_err(format!("Failed to convert to JSON: {}", e)))
61}
62
63/// Convert LDT/IES photometry file to GLDF and return JSON representation
64///
65/// Args:
66///     data: The LDT or IES file content as bytes
67///     filename: The original filename (used to determine format and product name)
68///
69/// Returns:
70///     JSON string representation of the GLDF product
71#[pyfunction]
72fn ldt_to_gldf_json(data: &[u8], filename: &str) -> PyResult<String> {
73    let gldf = ldt_to_gldf(data, filename)
74        .map_err(|e| PyValueError::new_err(format!("Failed to convert LDT/IES to GLDF: {}", e)))?;
75
76    gldf.gldf
77        .to_json()
78        .map_err(|e| PyValueError::new_err(format!("Failed to convert to JSON: {}", e)))
79}
80
81/// Convert LDT/IES photometry file to GLDF bytes (ZIP archive)
82///
83/// Args:
84///     data: The LDT or IES file content as bytes
85///     filename: The original filename (used to determine format and product name)
86///
87/// Returns:
88///     GLDF file content as bytes
89#[pyfunction]
90fn ldt_to_gldf_bytes<'py>(
91    py: Python<'py>,
92    data: &[u8],
93    filename: &str,
94) -> PyResult<Bound<'py, pyo3::types::PyBytes>> {
95    let file_buf_gldf = ldt_to_gldf(data, filename)
96        .map_err(|e| PyValueError::new_err(format!("Failed to convert LDT/IES to GLDF: {}", e)))?;
97
98    // Create EditableGldf from the result to use save_to_buf
99    let mut editable = EditableGldf::from_product(file_buf_gldf.gldf);
100
101    // Add embedded files
102    for buf_file in file_buf_gldf.files {
103        if let (Some(file_id), Some(content)) = (buf_file.file_id, buf_file.content) {
104            editable.embedded_files.insert(file_id, content);
105        }
106    }
107
108    let gldf_bytes = editable
109        .save_to_buf()
110        .map_err(|e| PyValueError::new_err(format!("Failed to create GLDF bytes: {}", e)))?;
111
112    Ok(pyo3::types::PyBytes::new(py, &gldf_bytes))
113}
114
115/// Export GLDF from JSON to bytes (ZIP archive)
116///
117/// Args:
118///     json_str: JSON string representation of the GLDF product
119///
120/// Returns:
121///     GLDF file content as bytes (ZIP archive)
122#[pyfunction]
123fn gldf_json_to_bytes<'py>(
124    py: Python<'py>,
125    json_str: &str,
126) -> PyResult<Bound<'py, pyo3::types::PyBytes>> {
127    let gldf = GldfProduct::from_json(json_str)
128        .map_err(|e| PyValueError::new_err(format!("Failed to parse JSON: {}", e)))?;
129
130    let editable = EditableGldf::from_product(gldf);
131
132    let gldf_bytes = editable
133        .save_to_buf()
134        .map_err(|e| PyValueError::new_err(format!("Failed to create GLDF bytes: {}", e)))?;
135
136    Ok(pyo3::types::PyBytes::new(py, &gldf_bytes))
137}
138
139/// A Python module for GLDF file handling implemented in Rust.
140///
141/// Functions:
142///     gldf_to_xml(path): Load GLDF file and convert to XML string
143///     gldf_to_json(path): Load GLDF file and convert to JSON string
144///     json_from_xml_str(xml_str): Parse XML string to JSON
145///     xml_from_json(json_str): Parse JSON string to XML
146///     gldf_from_bytes(data): Load GLDF from bytes and return JSON
147///     ldt_to_gldf_json(data, filename): Convert LDT/IES to GLDF JSON
148///     ldt_to_gldf_bytes(data, filename): Convert LDT/IES to GLDF bytes
149///     gldf_json_to_bytes(json_str): Export GLDF JSON to bytes
150#[pymodule]
151fn gldf_rs_python(m: &Bound<'_, PyModule>) -> PyResult<()> {
152    m.add_function(wrap_pyfunction!(gldf_to_xml, m)?)?;
153    m.add_function(wrap_pyfunction!(gldf_to_json, m)?)?;
154    m.add_function(wrap_pyfunction!(xml_from_json, m)?)?;
155    m.add_function(wrap_pyfunction!(json_from_xml_str, m)?)?;
156    m.add_function(wrap_pyfunction!(gldf_from_bytes, m)?)?;
157    m.add_function(wrap_pyfunction!(ldt_to_gldf_json, m)?)?;
158    m.add_function(wrap_pyfunction!(ldt_to_gldf_bytes, m)?)?;
159    m.add_function(wrap_pyfunction!(gldf_json_to_bytes, m)?)?;
160    Ok(())
161}