1use crate::helpers::symbol_to_atomic_number;
2use crate::iterators::ConFrameIterator;
3use crate::types::ConFrame;
4use crate::writer::ConFrameWriter;
5use std::ffi::{c_char, CStr, CString};
6use std::fs::{self, File};
7use std::ptr;
8
9#[repr(C)]
16pub struct RKRConFrame {
17 _private: [u8; 0],
18}
19
20#[repr(C)]
23pub struct RKRConFrameWriter {
24 _private: [u8; 0],
25}
26
27#[repr(C)]
31pub struct CFrame {
32 pub atoms: *mut CAtom,
33 pub num_atoms: usize,
34 pub cell: [f64; 3],
35 pub angles: [f64; 3],
36 pub has_velocities: bool,
37}
38
39#[repr(C)]
40pub struct CAtom {
41 pub atomic_number: u64,
42 pub x: f64,
43 pub y: f64,
44 pub z: f64,
45 pub atom_id: u64,
46 pub mass: f64,
47 pub is_fixed: bool,
48 pub vx: f64,
49 pub vy: f64,
50 pub vz: f64,
51 pub has_velocity: bool,
52}
53
54#[repr(C)]
55pub struct CConFrameIterator {
56 iterator: *mut ConFrameIterator<'static>,
57 file_contents: *mut String,
58}
59
60#[unsafe(no_mangle)]
68pub unsafe extern "C" fn read_con_file_iterator(
69 filename_c: *const c_char,
70) -> *mut CConFrameIterator {
71 if filename_c.is_null() {
72 return ptr::null_mut();
73 }
74 let filename = match unsafe { CStr::from_ptr(filename_c).to_str() } {
75 Ok(s) => s,
76 Err(_) => return ptr::null_mut(),
77 };
78 let file_contents_box = match fs::read_to_string(filename) {
79 Ok(contents) => Box::new(contents),
80 Err(_) => return ptr::null_mut(),
81 };
82 let file_contents_ptr = Box::into_raw(file_contents_box);
83 let static_file_contents: &'static str = unsafe { &*file_contents_ptr };
84 let iterator = Box::new(ConFrameIterator::new(static_file_contents));
85 let c_iterator = Box::new(CConFrameIterator {
86 iterator: Box::into_raw(iterator),
87 file_contents: file_contents_ptr,
88 });
89 Box::into_raw(c_iterator)
90}
91
92#[unsafe(no_mangle)]
95pub unsafe extern "C" fn con_frame_iterator_next(
96 iterator: *mut CConFrameIterator,
97) -> *mut RKRConFrame {
98 if iterator.is_null() {
99 return ptr::null_mut();
100 }
101 let iter = unsafe { &mut *(*iterator).iterator };
102 match iter.next() {
103 Some(Ok(frame)) => Box::into_raw(Box::new(frame)) as *mut RKRConFrame,
104 _ => ptr::null_mut(),
105 }
106}
107
108#[unsafe(no_mangle)]
110pub unsafe extern "C" fn free_rkr_frame(frame_handle: *mut RKRConFrame) {
111 if !frame_handle.is_null() {
112 let _ = unsafe { Box::from_raw(frame_handle as *mut ConFrame) };
113 }
114}
115
116#[unsafe(no_mangle)]
118pub unsafe extern "C" fn free_con_frame_iterator(iterator: *mut CConFrameIterator) {
119 if iterator.is_null() {
120 return;
121 }
122 unsafe {
123 let c_iterator_box = Box::from_raw(iterator);
124 let _ = Box::from_raw(c_iterator_box.iterator);
125 let _ = Box::from_raw(c_iterator_box.file_contents);
126 }
127}
128
129#[unsafe(no_mangle)]
136pub unsafe extern "C" fn rkr_frame_to_c_frame(frame_handle: *const RKRConFrame) -> *mut CFrame {
137 let frame = match unsafe { (frame_handle as *const ConFrame).as_ref() } {
138 Some(f) => f,
139 None => return ptr::null_mut(),
140 };
141
142 let masses_iter = frame
143 .header
144 .natms_per_type
145 .iter()
146 .zip(frame.header.masses_per_type.iter())
147 .flat_map(|(num_atoms, mass)| std::iter::repeat_n(*mass, *num_atoms));
148
149 let has_velocities = frame.has_velocities();
150
151 let mut c_atoms: Vec<CAtom> = frame
152 .atom_data
153 .iter()
154 .zip(masses_iter)
155 .map(|(atom_datum, mass)| CAtom {
156 atomic_number: symbol_to_atomic_number(&atom_datum.symbol),
157 x: atom_datum.x,
158 y: atom_datum.y,
159 z: atom_datum.z,
160 is_fixed: atom_datum.is_fixed,
161 atom_id: atom_datum.atom_id,
162 mass,
163 vx: atom_datum.vx.unwrap_or(0.0),
164 vy: atom_datum.vy.unwrap_or(0.0),
165 vz: atom_datum.vz.unwrap_or(0.0),
166 has_velocity: atom_datum.has_velocity(),
167 })
168 .collect();
169
170 let atoms_ptr = c_atoms.as_mut_ptr();
171 let num_atoms = c_atoms.len();
172 std::mem::forget(c_atoms);
173
174 let c_frame = Box::new(CFrame {
175 atoms: atoms_ptr,
176 num_atoms,
177 cell: frame.header.boxl,
178 angles: frame.header.angles,
179 has_velocities,
180 });
181
182 Box::into_raw(c_frame)
183}
184
185#[unsafe(no_mangle)]
187pub unsafe extern "C" fn free_c_frame(frame: *mut CFrame) {
188 if frame.is_null() {
189 return;
190 }
191 unsafe {
192 let frame_box = Box::from_raw(frame);
193 let _ = Vec::from_raw_parts(frame_box.atoms, frame_box.num_atoms, frame_box.num_atoms);
194 }
195}
196
197#[unsafe(no_mangle)]
201pub unsafe extern "C" fn rkr_frame_get_header_line(
202 frame_handle: *const RKRConFrame,
203 is_prebox: bool,
204 line_index: usize,
205 buffer: *mut c_char,
206 buffer_len: usize,
207) -> i32 {
208 let frame = match unsafe { (frame_handle as *const ConFrame).as_ref() } {
209 Some(f) => f,
210 None => return -1,
211 };
212 let line_to_copy = if is_prebox {
213 frame.header.prebox_header.get(line_index)
214 } else {
215 frame.header.postbox_header.get(line_index)
216 };
217 if let Some(line) = line_to_copy {
218 let bytes = line.as_bytes();
219 let len_to_copy = std::cmp::min(bytes.len(), buffer_len - 1);
220 unsafe {
221 ptr::copy_nonoverlapping(bytes.as_ptr(), buffer as *mut u8, len_to_copy);
222 *buffer.add(len_to_copy) = 0;
223 }
224 len_to_copy as i32
225 } else {
226 -1
227 }
228}
229
230#[unsafe(no_mangle)]
235pub unsafe extern "C" fn rkr_frame_get_header_line_cpp(
236 frame_handle: *const RKRConFrame,
237 is_prebox: bool,
238 line_index: usize,
239) -> *mut c_char {
240 let frame = match unsafe { (frame_handle as *const ConFrame).as_ref() } {
241 Some(f) => f,
242 None => return ptr::null_mut(),
243 };
244
245 let line_to_copy = if is_prebox {
246 frame.header.prebox_header.get(line_index)
247 } else {
248 frame.header.postbox_header.get(line_index)
249 };
250
251 if let Some(line) = line_to_copy {
252 match CString::new(line.as_str()) {
254 Ok(c_string) => c_string.into_raw(), Err(_) => ptr::null_mut(), }
257 } else {
258 ptr::null_mut() }
260}
261
262#[unsafe(no_mangle)]
264pub unsafe extern "C" fn rkr_free_string(s: *mut c_char) {
265 if !s.is_null() {
266 let _ = unsafe { CString::from_raw(s) };
268 }
269}
270
271#[unsafe(no_mangle)]
278pub unsafe extern "C" fn create_writer_from_path_c(
279 filename_c: *const c_char,
280) -> *mut RKRConFrameWriter {
281 if filename_c.is_null() {
282 return ptr::null_mut();
283 }
284 let filename = match unsafe { CStr::from_ptr(filename_c).to_str() } {
285 Ok(s) => s,
286 Err(_) => return ptr::null_mut(),
287 };
288 match crate::writer::ConFrameWriter::from_path(filename) {
289 Ok(writer) => Box::into_raw(Box::new(writer)) as *mut RKRConFrameWriter,
290 Err(_) => ptr::null_mut(),
291 }
292}
293
294#[unsafe(no_mangle)]
296pub unsafe extern "C" fn free_rkr_writer(writer_handle: *mut RKRConFrameWriter) {
297 if !writer_handle.is_null() {
298 let _ = unsafe { Box::from_raw(writer_handle as *mut ConFrameWriter<File>) };
299 }
300}
301
302#[unsafe(no_mangle)]
304pub unsafe extern "C" fn rkr_writer_extend(
305 writer_handle: *mut RKRConFrameWriter,
306 frame_handles: *const *const RKRConFrame,
307 num_frames: usize,
308) -> i32 {
309 let writer = match unsafe { (writer_handle as *mut ConFrameWriter<File>).as_mut() } {
310 Some(w) => w,
311 None => return -1,
312 };
313 if frame_handles.is_null() {
314 return -1;
315 }
316
317 let handles_slice = unsafe { std::slice::from_raw_parts(frame_handles, num_frames) };
318 let mut rust_frames: Vec<&ConFrame> = Vec::with_capacity(num_frames);
319 if handles_slice.iter().any(|&handle| handle.is_null()) {
320 return -1;
323 }
324 for &handle in handles_slice.iter() {
325 match unsafe { (handle as *const ConFrame).as_ref() } {
327 Some(frame) => rust_frames.push(frame),
328 None => return -1,
330 }
331 }
332
333 match writer.extend(rust_frames.into_iter()) {
334 Ok(_) => 0,
335 Err(_) => -1,
336 }
337}