1use pyo3::prelude::*;
4
5use eulumdat::batch::{
6 self, BatchInput as CoreBatchInput, ConversionFormat as CoreConversionFormat,
7};
8
9#[pyclass(eq, eq_int)]
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum InputFormat {
13 Ldt = 0,
15 Ies = 1,
17}
18
19#[pymethods]
20impl InputFormat {
21 fn __repr__(&self) -> String {
22 match self {
23 Self::Ldt => "InputFormat.Ldt".to_string(),
24 Self::Ies => "InputFormat.Ies".to_string(),
25 }
26 }
27}
28
29#[pyclass(eq, eq_int)]
31#[derive(Clone, Copy, PartialEq, Eq)]
32pub enum ConversionFormat {
33 Ldt = 0,
35 Ies = 1,
37}
38
39#[pymethods]
40impl ConversionFormat {
41 fn __repr__(&self) -> String {
42 match self {
43 Self::Ldt => "ConversionFormat.Ldt".to_string(),
44 Self::Ies => "ConversionFormat.Ies".to_string(),
45 }
46 }
47}
48
49#[pyclass]
51#[derive(Clone)]
52pub struct BatchInput {
53 #[pyo3(get, set)]
55 pub name: String,
56 #[pyo3(get, set)]
58 pub content: String,
59 #[pyo3(get, set)]
61 pub format: Option<InputFormat>,
62}
63
64#[pymethods]
65impl BatchInput {
66 #[new]
67 #[pyo3(signature = (name, content, format=None))]
68 fn new(name: String, content: String, format: Option<InputFormat>) -> Self {
69 Self {
70 name,
71 content,
72 format,
73 }
74 }
75
76 fn __repr__(&self) -> String {
77 format!(
78 "BatchInput(name='{}', content_len={}, format={:?})",
79 self.name,
80 self.content.len(),
81 self.format
82 )
83 }
84}
85
86#[pyclass]
88#[derive(Clone)]
89pub struct BatchOutput {
90 #[pyo3(get)]
92 pub input_name: String,
93 #[pyo3(get)]
95 pub output_name: String,
96 #[pyo3(get)]
98 pub content: Option<String>,
99 #[pyo3(get)]
101 pub error: Option<String>,
102}
103
104#[pymethods]
105impl BatchOutput {
106 fn __repr__(&self) -> String {
107 if let Some(err) = &self.error {
108 format!("BatchOutput(input='{}', error='{}')", self.input_name, err)
109 } else {
110 format!(
111 "BatchOutput(input='{}', output='{}', content_len={})",
112 self.input_name,
113 self.output_name,
114 self.content.as_ref().map(|c| c.len()).unwrap_or(0)
115 )
116 }
117 }
118
119 #[getter]
121 fn success(&self) -> bool {
122 self.error.is_none()
123 }
124}
125
126#[pyclass]
128#[derive(Clone)]
129pub struct BatchStats {
130 #[pyo3(get)]
132 pub total: usize,
133 #[pyo3(get)]
135 pub successful: usize,
136 #[pyo3(get)]
138 pub failed: usize,
139}
140
141#[pymethods]
142impl BatchStats {
143 fn __repr__(&self) -> String {
144 format!(
145 "BatchStats(total={}, successful={}, failed={})",
146 self.total, self.successful, self.failed
147 )
148 }
149
150 #[getter]
152 fn success_rate(&self) -> f64 {
153 if self.total == 0 {
154 0.0
155 } else {
156 (self.successful as f64 / self.total as f64) * 100.0
157 }
158 }
159}
160
161#[pyfunction]
181#[pyo3(signature = (inputs, format))]
182pub fn batch_convert(
183 inputs: Vec<BatchInput>,
184 format: ConversionFormat,
185) -> (Vec<BatchOutput>, BatchStats) {
186 let core_inputs: Vec<CoreBatchInput> = inputs
188 .into_iter()
189 .map(|input| CoreBatchInput {
190 name: input.name,
191 content: input.content,
192 format: input.format.map(|f| match f {
193 InputFormat::Ldt => eulumdat::InputFormat::Ldt,
194 InputFormat::Ies => eulumdat::InputFormat::Ies,
195 }),
196 })
197 .collect();
198
199 let core_format = match format {
200 ConversionFormat::Ldt => CoreConversionFormat::Ldt,
201 ConversionFormat::Ies => CoreConversionFormat::Ies,
202 };
203
204 let (core_outputs, core_stats) = batch::batch_convert_with_stats(&core_inputs, core_format);
206
207 let outputs: Vec<BatchOutput> = core_outputs
209 .into_iter()
210 .map(|output| BatchOutput {
211 input_name: output.input_name,
212 output_name: output.output_name,
213 content: output.content,
214 error: output.error,
215 })
216 .collect();
217
218 let stats = BatchStats {
219 total: core_stats.total,
220 successful: core_stats.successful,
221 failed: core_stats.failed,
222 };
223
224 (outputs, stats)
225}