1use core::{borrow::Borrow, str};
5
6use ocaml_sys::{caml_alloc_float_array, caml_sys_store_double_field};
7
8use crate::{
9 internal::{caml_alloc, store_field},
10 memory::{
11 alloc_bigarray1, alloc_bytes, alloc_cons, alloc_double, alloc_error, alloc_int32,
12 alloc_int64, alloc_ok, alloc_some, alloc_string, alloc_tuple, store_raw_field_at, OCamlRef,
13 },
14 mlvalues::{
15 bigarray::{Array1, BigarrayElt},
16 OCamlBytes, OCamlFloat, OCamlInt, OCamlInt32, OCamlInt64, OCamlList, RawOCaml, FALSE, NONE,
17 TRUE,
18 },
19 runtime::OCamlRuntime,
20 value::OCaml,
21 BoxRoot, OCamlFloatArray, OCamlUniformArray,
22};
23
24pub unsafe trait ToOCaml<T> {
42 fn to_boxroot(&self, cr: &mut OCamlRuntime) -> BoxRoot<T> {
44 BoxRoot::new(self.to_ocaml(cr))
45 }
46
47 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, T>;
49}
50
51unsafe impl<T> ToOCaml<T> for OCamlRef<'_, T> {
52 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, T> {
53 unsafe { OCaml::new(cr, self.get_raw()) }
54 }
55}
56
57unsafe impl<T> ToOCaml<T> for BoxRoot<T> {
58 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, T> {
59 self.get(cr)
60 }
61}
62
63unsafe impl ToOCaml<()> for () {
64 fn to_ocaml(&self, _cr: &mut OCamlRuntime) -> OCaml<'static, ()> {
65 OCaml::unit()
66 }
67}
68
69unsafe impl ToOCaml<OCamlInt> for i64 {
70 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt> {
71 unsafe { OCaml::new(cr, ((self << 1) | 1i64) as RawOCaml) }
72 }
73}
74
75unsafe impl ToOCaml<OCamlInt> for i32 {
76 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt> {
77 (*self as i64).to_ocaml(cr)
78 }
79}
80
81unsafe impl ToOCaml<OCamlInt32> for i32 {
82 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt32> {
83 alloc_int32(cr, *self)
84 }
85}
86
87unsafe impl ToOCaml<OCamlInt64> for i64 {
88 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt64> {
89 alloc_int64(cr, *self)
90 }
91}
92
93unsafe impl ToOCaml<OCamlFloat> for f64 {
94 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlFloat> {
95 alloc_double(cr, *self)
96 }
97}
98
99unsafe impl ToOCaml<bool> for bool {
100 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, bool> {
101 unsafe { OCaml::new(cr, if *self { TRUE } else { FALSE }) }
102 }
103}
104
105unsafe impl ToOCaml<String> for &str {
111 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> {
112 alloc_string(cr, self)
113 }
114}
115
116unsafe impl ToOCaml<OCamlBytes> for &str {
117 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> {
118 alloc_bytes(cr, self.as_bytes())
119 }
120}
121
122unsafe impl ToOCaml<OCamlBytes> for &[u8] {
123 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> {
124 alloc_bytes(cr, self)
125 }
126}
127
128unsafe impl ToOCaml<String> for &[u8] {
129 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> {
130 alloc_string(cr, unsafe { str::from_utf8_unchecked(self) })
131 }
132}
133
134unsafe impl ToOCaml<String> for String {
135 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> {
136 self.as_str().to_ocaml(cr)
137 }
138}
139
140unsafe impl ToOCaml<OCamlBytes> for String {
141 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> {
142 self.as_str().to_ocaml(cr)
143 }
144}
145
146unsafe impl ToOCaml<String> for Vec<u8> {
147 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> {
148 self.as_slice().to_ocaml(cr)
149 }
150}
151
152unsafe impl ToOCaml<OCamlBytes> for Vec<u8> {
153 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> {
154 self.as_slice().to_ocaml(cr)
155 }
156}
157
158unsafe impl ToOCaml<OCamlBytes> for Box<[u8]> {
159 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> {
160 let slice: &[u8] = self;
161 slice.to_ocaml(cr)
162 }
163}
164
165unsafe impl ToOCaml<Array1<u8>> for Box<[u8]> {
166 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Array1<u8>> {
167 let slice: &[u8] = self;
168 slice.to_ocaml(cr)
169 }
170}
171
172unsafe impl<A, OCamlA> ToOCaml<OCamlA> for Box<A>
173where
174 A: ToOCaml<OCamlA>,
175{
176 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlA> {
177 self.as_ref().to_ocaml(cr)
178 }
179}
180
181unsafe impl<A, OCamlA: 'static> ToOCaml<Option<OCamlA>> for Option<A>
182where
183 A: ToOCaml<OCamlA>,
184{
185 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Option<OCamlA>> {
186 if let Some(value) = self {
187 let ocaml_value = value.to_boxroot(cr);
188 alloc_some(cr, &ocaml_value)
189 } else {
190 unsafe { OCaml::new(cr, NONE) }
191 }
192 }
193}
194
195unsafe impl<A, OCamlA: 'static, Err, OCamlErr: 'static> ToOCaml<Result<OCamlA, OCamlErr>>
196 for Result<A, Err>
197where
198 A: ToOCaml<OCamlA>,
199 Err: ToOCaml<OCamlErr>,
200{
201 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Result<OCamlA, OCamlErr>> {
202 match self {
203 Ok(value) => {
204 let ocaml_value = value.to_boxroot(cr);
205 alloc_ok(cr, &ocaml_value)
206 }
207 Err(error) => {
208 let ocaml_error = error.to_boxroot(cr);
209 alloc_error(cr, &ocaml_error)
210 }
211 }
212 }
213}
214
215unsafe impl<A, OCamlA: 'static> ToOCaml<OCamlList<OCamlA>> for Vec<A>
216where
217 A: ToOCaml<OCamlA>,
218{
219 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlList<OCamlA>> {
220 let mut result = BoxRoot::new(OCaml::nil(cr));
221 for elt in self.iter().rev() {
222 let ov = elt.to_boxroot(cr);
223 let cons = alloc_cons(cr, &ov, &result);
224 result.keep(cons);
225 }
226 cr.get(&result)
227 }
228}
229
230unsafe impl<A, OCamlA: 'static> ToOCaml<OCamlUniformArray<OCamlA>> for Vec<A>
231where
232 A: ToOCaml<OCamlA>,
233{
234 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlUniformArray<OCamlA>> {
235 let result = BoxRoot::new(unsafe { OCaml::new(cr, caml_alloc(self.len(), 0)) });
236
237 for (i, elt) in self.iter().enumerate() {
238 let ov = elt.to_ocaml(cr);
239 unsafe { store_field(result.get_raw(), i, ov.raw()) };
240 }
241
242 result.get(cr)
243 }
244}
245
246unsafe impl ToOCaml<OCamlFloatArray> for Vec<f64> {
247 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlFloatArray> {
248 let result = unsafe { OCaml::new(cr, caml_alloc_float_array(self.len())) };
249
250 for (i, elt) in self.iter().enumerate() {
251 unsafe { caml_sys_store_double_field(result.raw(), i, *elt) };
252 }
253
254 result
255 }
256}
257
258macro_rules! tuple_to_ocaml {
261 ($($n:tt: $t:ident => $ot:ident),+) => {
262 unsafe impl<$($t),+, $($ot: 'static),+> ToOCaml<($($ot),+)> for ($($t),+)
263 where
264 $($t: ToOCaml<$ot>),+
265 {
266 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, ($($ot),+)> {
267 let len = $crate::count_fields!($($t)*);
268
269 let ocaml_tuple: BoxRoot<($($ot),+)> = BoxRoot::new(unsafe { alloc_tuple(cr, len) });
270 $(
271 unsafe {
272 let field_val = self.$n.to_ocaml(cr).get_raw();
273 store_raw_field_at(cr, &ocaml_tuple, $n, field_val);
274 }
275 )+
276
277 cr.get(&ocaml_tuple)
278 }
279 }
280 };
281}
282
283tuple_to_ocaml!(
284 0: A => OCamlA,
285 1: B => OCamlB);
286tuple_to_ocaml!(
287 0: A => OCamlA,
288 1: B => OCamlB,
289 2: C => OCamlC);
290tuple_to_ocaml!(
291 0: A => OCamlA,
292 1: B => OCamlB,
293 2: C => OCamlC,
294 3: D => OCamlD);
295tuple_to_ocaml!(
296 0: A => OCamlA,
297 1: B => OCamlB,
298 2: C => OCamlC,
299 3: D => OCamlD,
300 4: E => OCamlE);
301tuple_to_ocaml!(
302 0: A => OCamlA,
303 1: B => OCamlB,
304 2: C => OCamlC,
305 3: D => OCamlD,
306 4: E => OCamlE,
307 5: F => OCamlF);
308tuple_to_ocaml!(
309 0: A => OCamlA,
310 1: B => OCamlB,
311 2: C => OCamlC,
312 3: D => OCamlD,
313 4: E => OCamlE,
314 5: F => OCamlF,
315 6: G => OCamlG);
316tuple_to_ocaml!(
317 0: A => OCamlA,
318 1: B => OCamlB,
319 2: C => OCamlC,
320 3: D => OCamlD,
321 4: E => OCamlE,
322 5: F => OCamlF,
323 6: G => OCamlG,
324 7: H => OCamlH);
325tuple_to_ocaml!(
326 0: A => OCamlA,
327 1: B => OCamlB,
328 2: C => OCamlC,
329 3: D => OCamlD,
330 4: E => OCamlE,
331 5: F => OCamlF,
332 6: G => OCamlG,
333 7: H => OCamlH,
334 8: I => OCamlI);
335tuple_to_ocaml!(
336 0: A => OCamlA,
337 1: B => OCamlB,
338 2: C => OCamlC,
339 3: D => OCamlD,
340 4: E => OCamlE,
341 5: F => OCamlF,
342 6: G => OCamlG,
343 7: H => OCamlH,
344 8: I => OCamlI,
345 9: J => OCamlJ);
346
347unsafe impl<A: BigarrayElt> ToOCaml<Array1<A>> for &[A] {
349 fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Array1<A>> {
350 alloc_bigarray1(cr, self)
351 }
352}
353
354impl<A: BigarrayElt> Borrow<[A]> for OCaml<'_, Array1<A>> {
358 fn borrow(&self) -> &[A] {
359 unsafe {
360 let ba = self.custom_ptr_val::<ocaml_sys::bigarray::Bigarray>();
361 core::slice::from_raw_parts((*ba).data as *const A, self.len())
362 }
363 }
364}