Take &mut Arena in allocation methods
[hiphop-php.git] / hphp / hack / src / ocamlrep / lib.rs
blob37e12ebffae8a4784a83845ae58c6e73241607fe
1 // Copyright (c) Facebook, Inc. and its affiliates.
2 //
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
6 use std::borrow::Cow;
7 use std::fmt::{self, Debug};
8 use std::marker::PhantomData;
9 use std::mem;
10 use std::ops::{Index, IndexMut};
12 pub mod arena;
14 pub use arena::Arena;
16 const STRING_TAG: u8 = 252;
17 const DOUBLE_TAG: u8 = 253;
19 pub trait IntoOcamlRep {
20     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a>;
23 #[repr(transparent)]
24 pub struct BlockBuilder<'arena: 'builder, 'builder>(&'builder mut [Value<'arena>]);
26 impl<'a, 'b> BlockBuilder<'a, 'b> {
27     pub fn new(size: usize, tag: u8, block: &'b mut [Value<'a>]) -> Self {
28         if size == 0 {
29             panic!()
30         }
31         let header_bytes = size << 10 | (tag as usize);
32         let header = Value::bits(header_bytes);
33         block[0] = header;
34         BlockBuilder(block)
35     }
37     pub fn build(self) -> Value<'a> {
38         Value::bits(unsafe { mem::transmute(self.0.as_ptr().offset(1)) })
39     }
42 impl<'a, 'b> Index<usize> for BlockBuilder<'a, 'b> {
43     type Output = Value<'a>;
45     fn index(&self, index: usize) -> &Self::Output {
46         &self.0[index + 1]
47     }
50 impl IndexMut<usize> for BlockBuilder<'_, '_> {
51     fn index_mut(&mut self, index: usize) -> &mut Self::Output {
52         &mut self.0[index + 1]
53     }
56 #[repr(transparent)]
57 pub struct Block<'arena>(&'arena [Value<'arena>]);
59 impl<'a> Block<'a> {
60     fn header_bits(&self) -> usize {
61         self.0[0].0
62     }
64     fn size(&self) -> usize {
65         self.header_bits() >> 10
66     }
68     fn tag(&self) -> u8 {
69         self.header_bits() as u8
70     }
72     fn as_str(&self) -> Option<Cow<str>> {
73         if self.tag() != STRING_TAG {
74             return None;
75         }
76         let slice = unsafe {
77             let size = self.size() * mem::size_of::<usize>();
78             let ptr: *mut u8 = mem::transmute(self.0.as_ptr().offset(1));
79             let last_byte = ptr.offset(size as isize - 1);
80             let padding = *last_byte;
81             let size = size - padding as usize - 1;
82             std::slice::from_raw_parts(ptr, size)
83         };
84         Some(String::from_utf8_lossy(slice))
85     }
87     fn as_float(&self) -> Option<f64> {
88         if self.tag() != DOUBLE_TAG {
89             return None;
90         }
91         Some(f64::from_bits(self.0[1].0 as u64))
92     }
94     fn as_values(&self) -> Option<&[Value]> {
95         if self.tag() == STRING_TAG || self.tag() == DOUBLE_TAG {
96             return None;
97         }
98         Some(&self.0[1..])
99     }
102 impl<'a> Index<usize> for Block<'a> {
103     type Output = Value<'a>;
105     fn index(&self, index: usize) -> &Self::Output {
106         &self.0[index + 1]
107     }
110 impl Debug for Block<'_> {
111     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112         if self.tag() == STRING_TAG {
113             write!(f, "{:?}", self.as_str().unwrap())
114         } else if self.tag() == DOUBLE_TAG {
115             write!(f, "{:?}", self.as_float().unwrap())
116         } else {
117             write!(f, "{:?}", self.as_values().unwrap())
118         }
119     }
122 #[repr(transparent)]
123 #[derive(Clone, Copy)]
124 pub struct Value<'arena>(usize, PhantomData<&'arena ()>);
126 impl<'a> Value<'a> {
127     fn is_immediate(&self) -> bool {
128         self.0 & 1 == 1
129     }
131     pub fn int(value: isize) -> Value<'static> {
132         Value(((value as usize) << 1) | 1, PhantomData)
133     }
135     fn bits(value: usize) -> Value<'a> {
136         Value(value, PhantomData)
137     }
139     fn as_int(&self) -> isize {
140         if !self.is_immediate() {
141             panic!()
142         }
143         (self.0 as isize) >> 1
144     }
146     fn as_block(&self) -> Option<Block<'a>> {
147         if self.is_immediate() {
148             return None;
149         }
150         let block = unsafe {
151             let ptr: *const Value = mem::transmute(self.0);
152             let header = ptr.offset(-1);
153             let size = ((*header).0 >> 10) + 1;
154             std::slice::from_raw_parts(header, size)
155         };
156         Some(Block(block))
157     }
159     /// This method is unsafe because it decouples the value from the lifetime
160     /// of the arena. Take care that the returned value does not outlive the
161     /// arena.
162     pub unsafe fn as_usize(&self) -> usize {
163         self.0
164     }
167 impl Debug for Value<'_> {
168     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169         match self.as_block() {
170             None => write!(f, "{}", self.as_int()),
171             Some(block) => write!(f, "{:?}", block),
172         }
173     }
176 impl IntoOcamlRep for bool {
177     fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> {
178         Value::int(self as isize)
179     }
182 impl IntoOcamlRep for char {
183     fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> {
184         Value::int(self as isize)
185     }
188 impl IntoOcamlRep for isize {
189     fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> {
190         Value::int(self)
191     }
194 impl IntoOcamlRep for usize {
195     fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> {
196         Value::int(self as isize)
197     }
200 impl IntoOcamlRep for u64 {
201     fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> {
202         Value::int(self as isize)
203     }
206 impl IntoOcamlRep for i64 {
207     fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> {
208         Value::int(self as isize)
209     }
212 impl IntoOcamlRep for u32 {
213     fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> {
214         Value::int(self as isize)
215     }
218 impl IntoOcamlRep for i32 {
219     fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> {
220         Value::int(self as isize)
221     }
224 impl<T: IntoOcamlRep> IntoOcamlRep for Option<T> {
225     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
226         match self {
227             None => Value::int(0),
228             Some(val) => {
229                 let val = arena.add(val);
230                 let mut block = arena.block_with_size(1);
231                 block[0] = val;
232                 block.build()
233             }
234         }
235     }
238 impl<T: IntoOcamlRep> IntoOcamlRep for Vec<T> {
239     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
240         let mut hd = arena.add(());
241         for val in self.into_iter().rev() {
242             let val = arena.add(val);
243             let mut current_block = arena.block_with_size(2);
244             current_block[0] = val;
245             current_block[1] = hd;
246             hd = current_block.build();
247         }
248         hd
249     }
252 impl IntoOcamlRep for String {
253     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
254         self.as_str().into_ocamlrep(arena)
255     }
258 impl IntoOcamlRep for &str {
259     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
260         let bytes_in_word = mem::size_of::<usize>();
261         let blocks_length = 1 + (self.len() / bytes_in_word);
262         let padding: usize = bytes_in_word - 1 - (self.len() % bytes_in_word);
263         let mut block = arena.block_with_size_and_tag(blocks_length, STRING_TAG);
265         block[blocks_length - 1] = Value::bits(padding << ((bytes_in_word - 1) * 8));
267         let slice: &mut [u8] = unsafe {
268             let ptr: *mut u8 = mem::transmute(block.0.as_ptr().offset(1));
269             std::slice::from_raw_parts_mut(ptr, self.len())
270         };
271         slice.copy_from_slice(self.as_bytes());
273         block.build()
274     }
277 impl IntoOcamlRep for f64 {
278     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
279         let mut block = arena.block_with_size_and_tag(1, DOUBLE_TAG);
280         block[0] = Value::bits(self.to_bits() as usize);
281         block.build()
282     }
285 impl IntoOcamlRep for () {
286     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
287         0isize.into_ocamlrep(arena)
288     }
291 impl<T: IntoOcamlRep> IntoOcamlRep for Box<T> {
292     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
293         (*self).into_ocamlrep(arena)
294     }
297 impl<T0, T1> IntoOcamlRep for (T0, T1)
298 where
299     T0: IntoOcamlRep,
300     T1: IntoOcamlRep,
302     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
303         let v0 = arena.add(self.0);
304         let v1 = arena.add(self.1);
305         let mut block = arena.block_with_size(2);
306         block[0] = v0;
307         block[1] = v1;
308         block.build()
309     }
312 impl<T0, T1, T2> IntoOcamlRep for (T0, T1, T2)
313 where
314     T0: IntoOcamlRep,
315     T1: IntoOcamlRep,
316     T2: IntoOcamlRep,
318     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
319         let v0 = arena.add(self.0);
320         let v1 = arena.add(self.1);
321         let v2 = arena.add(self.2);
322         let mut block = arena.block_with_size(3);
323         block[0] = v0;
324         block[1] = v1;
325         block[2] = v2;
326         block.build()
327     }
330 impl<T0, T1, T2, T3> IntoOcamlRep for (T0, T1, T2, T3)
331 where
332     T0: IntoOcamlRep,
333     T1: IntoOcamlRep,
334     T2: IntoOcamlRep,
335     T3: IntoOcamlRep,
337     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
338         let v0 = arena.add(self.0);
339         let v1 = arena.add(self.1);
340         let v2 = arena.add(self.2);
341         let v3 = arena.add(self.3);
342         let mut block = arena.block_with_size(4);
343         block[0] = v0;
344         block[1] = v1;
345         block[2] = v2;
346         block[3] = v3;
347         block.build()
348     }
351 impl<T0, T1, T2, T3, T4> IntoOcamlRep for (T0, T1, T2, T3, T4)
352 where
353     T0: IntoOcamlRep,
354     T1: IntoOcamlRep,
355     T2: IntoOcamlRep,
356     T3: IntoOcamlRep,
357     T4: IntoOcamlRep,
359     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
360         let v0 = arena.add(self.0);
361         let v1 = arena.add(self.1);
362         let v2 = arena.add(self.2);
363         let v3 = arena.add(self.3);
364         let v4 = arena.add(self.4);
365         let mut block = arena.block_with_size(5);
366         block[0] = v0;
367         block[1] = v1;
368         block[2] = v2;
369         block[3] = v3;
370         block[4] = v4;
371         block.build()
372     }
375 impl<T0, T1, T2, T3, T4, T5> IntoOcamlRep for (T0, T1, T2, T3, T4, T5)
376 where
377     T0: IntoOcamlRep,
378     T1: IntoOcamlRep,
379     T2: IntoOcamlRep,
380     T3: IntoOcamlRep,
381     T4: IntoOcamlRep,
382     T5: IntoOcamlRep,
384     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
385         let v0 = arena.add(self.0);
386         let v1 = arena.add(self.1);
387         let v2 = arena.add(self.2);
388         let v3 = arena.add(self.3);
389         let v4 = arena.add(self.4);
390         let v5 = arena.add(self.5);
391         let mut block = arena.block_with_size(6);
392         block[0] = v0;
393         block[1] = v1;
394         block[2] = v2;
395         block[3] = v3;
396         block[4] = v4;
397         block[5] = v5;
398         block.build()
399     }
402 impl<T0, T1, T2, T3, T4, T5, T6> IntoOcamlRep for (T0, T1, T2, T3, T4, T5, T6)
403 where
404     T0: IntoOcamlRep,
405     T1: IntoOcamlRep,
406     T2: IntoOcamlRep,
407     T3: IntoOcamlRep,
408     T4: IntoOcamlRep,
409     T5: IntoOcamlRep,
410     T6: IntoOcamlRep,
412     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
413         let v0 = arena.add(self.0);
414         let v1 = arena.add(self.1);
415         let v2 = arena.add(self.2);
416         let v3 = arena.add(self.3);
417         let v4 = arena.add(self.4);
418         let v5 = arena.add(self.5);
419         let v6 = arena.add(self.6);
420         let mut block = arena.block_with_size(7);
421         block[0] = v0;
422         block[1] = v1;
423         block[2] = v2;
424         block[3] = v3;
425         block[4] = v4;
426         block[5] = v5;
427         block[6] = v6;
428         block.build()
429     }
432 impl<T0, T1, T2, T3, T4, T5, T6, T7> IntoOcamlRep for (T0, T1, T2, T3, T4, T5, T6, T7)
433 where
434     T0: IntoOcamlRep,
435     T1: IntoOcamlRep,
436     T2: IntoOcamlRep,
437     T3: IntoOcamlRep,
438     T4: IntoOcamlRep,
439     T5: IntoOcamlRep,
440     T6: IntoOcamlRep,
441     T7: IntoOcamlRep,
443     fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> {
444         let v0 = arena.add(self.0);
445         let v1 = arena.add(self.1);
446         let v2 = arena.add(self.2);
447         let v3 = arena.add(self.3);
448         let v4 = arena.add(self.4);
449         let v5 = arena.add(self.5);
450         let v6 = arena.add(self.6);
451         let v7 = arena.add(self.7);
452         let mut block = arena.block_with_size(8);
453         block[0] = v0;
454         block[1] = v1;
455         block[2] = v2;
456         block[3] = v3;
457         block[4] = v4;
458         block[5] = v5;
459         block[6] = v6;
460         block[7] = v7;
461         block.build()
462     }