ocaml_interop/conv/
from_ocaml.rs1use crate::{
5 mlvalues::{
6 field_val, tag, OCamlBytes, OCamlFloat, OCamlFloatArray, OCamlInt, OCamlInt32, OCamlInt64,
7 OCamlList, OCamlUniformArray,
8 },
9 value::OCaml,
10};
11use ocaml_sys::caml_sys_double_field;
12
13pub unsafe trait FromOCaml<T> {
32 fn from_ocaml(v: OCaml<T>) -> Self;
34}
35
36unsafe impl FromOCaml<()> for () {
37 fn from_ocaml(_v: OCaml<()>) -> Self {
38 }
40}
41
42unsafe impl FromOCaml<OCamlInt> for i64 {
43 fn from_ocaml(v: OCaml<OCamlInt>) -> Self {
44 v.to_i64()
45 }
46}
47
48unsafe impl FromOCaml<OCamlInt> for i32 {
49 fn from_ocaml(v: OCaml<OCamlInt>) -> Self {
50 v.to_i64() as i32
51 }
52}
53
54unsafe impl FromOCaml<OCamlInt32> for i32 {
55 fn from_ocaml(v: OCaml<OCamlInt32>) -> Self {
56 let val = unsafe { field_val(v.raw(), 1) };
57 unsafe { *(val as *const i32) }
58 }
59}
60
61unsafe impl FromOCaml<OCamlInt64> for i64 {
62 fn from_ocaml(v: OCaml<OCamlInt64>) -> Self {
63 let val = unsafe { field_val(v.raw(), 1) };
64 unsafe { *(val as *const i64) }
65 }
66}
67
68unsafe impl FromOCaml<bool> for bool {
69 fn from_ocaml(v: OCaml<bool>) -> Self {
70 v.to_bool()
71 }
72}
73
74unsafe impl FromOCaml<OCamlFloat> for f64 {
75 fn from_ocaml(v: OCaml<OCamlFloat>) -> Self {
76 unsafe { *(v.raw() as *const f64) }
77 }
78}
79
80unsafe impl FromOCaml<String> for Vec<u8> {
81 fn from_ocaml(v: OCaml<String>) -> Self {
82 let raw_bytes = v.as_bytes();
83 let mut vec: Vec<u8> = Vec::with_capacity(raw_bytes.len());
84 vec.extend_from_slice(raw_bytes);
85 vec
86 }
87}
88
89unsafe impl FromOCaml<String> for String {
90 fn from_ocaml(v: OCaml<String>) -> Self {
91 String::from_utf8_lossy(v.as_bytes()).into_owned()
92 }
93}
94
95unsafe impl FromOCaml<OCamlBytes> for Vec<u8> {
96 fn from_ocaml(v: OCaml<OCamlBytes>) -> Self {
97 let raw_bytes = v.as_bytes();
98 let mut vec: Vec<u8> = Vec::with_capacity(raw_bytes.len());
99 vec.extend_from_slice(raw_bytes);
100 vec
101 }
102}
103
104unsafe impl FromOCaml<OCamlBytes> for Box<[u8]> {
105 fn from_ocaml(v: OCaml<OCamlBytes>) -> Self {
106 let raw_bytes = v.as_bytes();
107 Box::from(raw_bytes)
108 }
109}
110
111unsafe impl FromOCaml<OCamlBytes> for String {
112 fn from_ocaml(v: OCaml<OCamlBytes>) -> Self {
113 unsafe { v.as_str_unchecked() }.to_owned()
114 }
115}
116
117unsafe impl<OCamlT, T: FromOCaml<OCamlT>> FromOCaml<OCamlT> for Box<T> {
118 fn from_ocaml(v: OCaml<OCamlT>) -> Self {
119 Box::new(T::from_ocaml(v))
120 }
121}
122
123unsafe impl<A, OCamlA, Err, OCamlErr> FromOCaml<Result<OCamlA, OCamlErr>> for Result<A, Err>
124where
125 A: FromOCaml<OCamlA>,
126 Err: FromOCaml<OCamlErr>,
127{
128 fn from_ocaml(v: OCaml<Result<OCamlA, OCamlErr>>) -> Self {
129 match v.to_result() {
130 Ok(ocaml_ok) => Ok(A::from_ocaml(ocaml_ok)),
131 Err(ocaml_err) => Err(Err::from_ocaml(ocaml_err)),
132 }
133 }
134}
135
136unsafe impl<A, OCamlA> FromOCaml<Option<OCamlA>> for Option<A>
137where
138 A: FromOCaml<OCamlA>,
139{
140 fn from_ocaml(v: OCaml<Option<OCamlA>>) -> Self {
141 v.to_option().map(A::from_ocaml)
142 }
143}
144
145unsafe impl<A, OCamlA> FromOCaml<OCamlList<OCamlA>> for Vec<A>
146where
147 A: FromOCaml<OCamlA>,
148{
149 fn from_ocaml(v: OCaml<OCamlList<OCamlA>>) -> Self {
150 let mut vec = Vec::new();
152 let mut current = v;
153 while let Some((hd, tl)) = current.uncons() {
154 current = tl;
155 vec.push(A::from_ocaml(hd));
156 }
157 vec
158 }
159}
160
161unsafe impl<A, OCamlA> FromOCaml<OCamlUniformArray<OCamlA>> for Vec<A>
162where
163 A: FromOCaml<OCamlA>,
164{
165 fn from_ocaml(v: OCaml<OCamlUniformArray<OCamlA>>) -> Self {
166 assert!(
167 v.tag_value() != tag::DOUBLE_ARRAY,
168 "unboxed float arrays are not supported"
169 );
170
171 let size = unsafe { v.size() };
172 let mut vec = Vec::with_capacity(size);
173 for i in 0..size {
174 vec.push(A::from_ocaml(unsafe { v.field(i) }));
175 }
176 vec
177 }
178}
179
180unsafe impl FromOCaml<OCamlFloatArray> for Vec<f64> {
181 fn from_ocaml(v: OCaml<OCamlFloatArray>) -> Self {
182 let size = unsafe { v.size() };
183
184 if size > 0 {
187 assert_eq!(v.tag_value(), tag::DOUBLE_ARRAY)
188 };
189
190 let mut vec = Vec::with_capacity(size);
191 for i in 0..size {
192 vec.push(unsafe { caml_sys_double_field(v.raw(), i) });
193 }
194 vec
195 }
196}
197
198macro_rules! tuple_from_ocaml {
201 ($($accessor:ident: $t:ident => $ot:ident),+) => {
202 unsafe impl<$($t),+, $($ot: 'static),+> FromOCaml<($($ot),+)> for ($($t),+)
203 where
204 $($t: FromOCaml<$ot>),+
205 {
206 fn from_ocaml(v: OCaml<($($ot),+)>) -> Self {
207 ($($t::from_ocaml(v.$accessor())),+)
208
209 }
210 }
211 };
212}
213
214tuple_from_ocaml!(
215 fst: OCamlA => A,
216 snd: OCamlB => B);
217tuple_from_ocaml!(
218 fst: OCamlA => A,
219 snd: OCamlB => B,
220 tuple_3: OCamlC => C);
221tuple_from_ocaml!(
222 fst: OCamlA => A,
223 snd: OCamlB => B,
224 tuple_3: OCamlC => C,
225 tuple_4: OCamlD => D);
226tuple_from_ocaml!(
227 fst: OCamlA => A,
228 snd: OCamlB => B,
229 tuple_3: OCamlC => C,
230 tuple_4: OCamlD => D,
231 tuple_5: OCamlE => E);
232tuple_from_ocaml!(
233 fst: OCamlA => A,
234 snd: OCamlB => B,
235 tuple_3: OCamlC => C,
236 tuple_4: OCamlD => D,
237 tuple_5: OCamlE => E,
238 tuple_6: OCamlF => F);
239tuple_from_ocaml!(
240 fst: OCamlA => A,
241 snd: OCamlB => B,
242 tuple_3: OCamlC => C,
243 tuple_4: OCamlD => D,
244 tuple_5: OCamlE => E,
245 tuple_6: OCamlF => F,
246 tuple_7: OCamlG => G);
247tuple_from_ocaml!(
248 fst: OCamlA => A,
249 snd: OCamlB => B,
250 tuple_3: OCamlC => C,
251 tuple_4: OCamlD => D,
252 tuple_5: OCamlE => E,
253 tuple_6: OCamlF => F,
254 tuple_7: OCamlG => G,
255 tuple_8: OCamlH => H);
256tuple_from_ocaml!(
257 fst: OCamlA => A,
258 snd: OCamlB => B,
259 tuple_3: OCamlC => C,
260 tuple_4: OCamlD => D,
261 tuple_5: OCamlE => E,
262 tuple_6: OCamlF => F,
263 tuple_7: OCamlG => G,
264 tuple_8: OCamlH => H,
265 tuple_9: OCamlI => I);