1- use crate :: erts:: { AllocInProcess , Term } ;
1+ use core:: alloc:: { AllocErr , Layout } ;
2+ use core:: mem;
3+ use core:: ptr:: NonNull ;
4+
5+ use crate :: erts:: { self , HeapAlloc , HeapFragment , ProcessControlBlock , Term } ;
26
37/// This trait represents cloning, like `Clone`, but specifically
48/// in the context of terms which need to be cloned into the heap
@@ -15,7 +19,44 @@ use crate::erts::{AllocInProcess, Term};
1519/// just be aware that any uses of `Clone` will allocate on the global heap
1620pub trait CloneToProcess {
1721 /// Returns boxed copy of this value, performing any heap allocations
18- /// using the process heap of `process`, or using heap fragments if
22+ /// using the process heap of `process`, possibly using heap fragments if
1923 /// there is not enough space for the cloned value
20- fn clone_to_process < A : AllocInProcess > ( & self , process : & mut A ) -> Term ;
24+ fn clone_to_process ( & self , process : & ProcessControlBlock ) -> Term {
25+ let mut heap = process. acquire_heap ( ) ;
26+ match self . clone_to_heap ( & mut heap) {
27+ Ok ( term) => term,
28+ Err ( _) => {
29+ drop ( heap) ;
30+ let ( term, mut frag) = self . clone_to_fragment ( ) . unwrap ( ) ;
31+ process. attach_fragment ( unsafe { frag. as_mut ( ) } ) ;
32+ term
33+ }
34+ }
35+ }
36+
37+ /// Returns boxed copy of this value, performing any heap allocations
38+ /// using the given heap. If cloning requires allocation that exceeds
39+ /// the amount of memory available, this returns `Err(AllocErr)`, otherwise
40+ /// it returns `Ok(Term)`
41+ fn clone_to_heap < A : HeapAlloc > ( & self , heap : & mut A ) -> Result < Term , AllocErr > ;
42+
43+ /// Returns boxed copy of this value and the heap fragment it was allocated into
44+ ///
45+ /// If unable to allocate a heap fragment that fits this value, `Err(AllocErr)` is returned
46+ fn clone_to_fragment ( & self ) -> Result < ( Term , NonNull < HeapFragment > ) , AllocErr > {
47+ let need = self . size_in_words ( ) ;
48+ let layout = unsafe {
49+ let size = need * mem:: size_of :: < usize > ( ) ;
50+ Layout :: from_size_align_unchecked ( size, mem:: align_of :: < Term > ( ) )
51+ } ;
52+ let mut frag = unsafe { HeapFragment :: new ( layout) ? } ;
53+ let frag_ref = unsafe { frag. as_mut ( ) } ;
54+ let term = self . clone_to_heap ( frag_ref) ?;
55+ Ok ( ( term, frag) )
56+ }
57+
58+ /// Returns the size in words needed to allocate this value
59+ fn size_in_words ( & self ) -> usize {
60+ erts:: to_word_size ( mem:: size_of_val ( self ) )
61+ }
2162}
0 commit comments