66 * LICENSE file in the root directory of this source tree.
77 */
88
9- //! Temporary byte arena backed by a file.
9+ //! Temporary byte area backed by a file.
1010//!
11- //! The arena allows staged writing through [`ByteArena::write `]. Each
12- //! call returns a mutable [`Buffer `] bound to the arena so only one
13- //! writer can exist at a time. Finalizing the buffer via
14- //! [`Buffer::finish `] remaps the written range as immutable and
11+ //! The area offers staged writing through a [`SectionWriter `]. Each call to
12+ //! [`SectionWriter::reserve`] returns a mutable [`Section `] tied to the area's
13+ //! lifetime. Multiple sections may coexist; their byte ranges do not overlap.
14+ //! Freezing a section via [`Section::freeze `] remaps its range as immutable and
1515//! returns [`Bytes`].
1616
1717use std:: io:: { self , Seek , SeekFrom } ;
@@ -31,93 +31,98 @@ fn align_up(val: usize, align: usize) -> usize {
3131 ( val + align - 1 ) & !( align - 1 )
3232}
3333
34- /// Arena managing a temporary file.
34+ /// Area managing a temporary file.
3535#[ derive( Debug ) ]
36- pub struct ByteArena {
37- /// Temporary file backing the arena .
36+ pub struct ByteArea {
37+ /// Temporary file backing the area .
3838 file : NamedTempFile ,
3939 /// Current length of initialized data in bytes.
4040 len : usize ,
4141}
4242
43- impl ByteArena {
44- /// Create a new empty arena .
43+ impl ByteArea {
44+ /// Create a new empty area .
4545 pub fn new ( ) -> io:: Result < Self > {
4646 let file = NamedTempFile :: new ( ) ?;
4747 Ok ( Self { file, len : 0 } )
4848 }
4949
50- /// Start a new write of `elems` elements of type `T`.
51- pub fn write < ' a , T > ( & ' a mut self , elems : usize ) -> io:: Result < Buffer < ' a , T > >
50+ /// Obtain a handle for reserving sections.
51+ pub fn sections ( & mut self ) -> SectionWriter < ' _ > {
52+ SectionWriter { area : self }
53+ }
54+
55+ /// Freeze the area and return immutable bytes for the entire file.
56+ pub fn freeze ( self ) -> io:: Result < Bytes > {
57+ let file = self . file . into_file ( ) ;
58+ let mmap = unsafe { memmap2:: MmapOptions :: new ( ) . map ( & file) ? } ;
59+ Ok ( Bytes :: from_source ( mmap) )
60+ }
61+
62+ /// Persist the temporary area file to `path` and return the underlying [`File`].
63+ pub fn persist < P : AsRef < std:: path:: Path > > ( self , path : P ) -> io:: Result < std:: fs:: File > {
64+ self . file . persist ( path) . map_err ( Into :: into)
65+ }
66+ }
67+
68+ /// RAII guard giving temporary exclusive write access.
69+ #[ derive( Debug ) ]
70+ pub struct SectionWriter < ' area > {
71+ area : & ' area mut ByteArea ,
72+ }
73+
74+ impl < ' area > SectionWriter < ' area > {
75+ /// Reserve a new section inside the area.
76+ pub fn reserve < T > ( & mut self , elems : usize ) -> io:: Result < Section < ' area , T > >
5277 where
5378 T : FromBytes + Immutable ,
5479 {
5580 let page = page_size:: get ( ) ;
5681 let align = core:: mem:: align_of :: < T > ( ) ;
5782 let len_bytes = core:: mem:: size_of :: < T > ( ) * elems;
58- let start = align_up ( self . len , align) ;
83+ let start = align_up ( self . area . len , align) ;
5984 let end = start + len_bytes;
60- self . file . as_file_mut ( ) . set_len ( end as u64 ) ?;
61- // Ensure subsequent mappings see the extended size.
62- self . file . as_file_mut ( ) . seek ( SeekFrom :: Start ( end as u64 ) ) ?;
6385
64- // Map must start on a page boundary; round `start` down while
65- // keeping track of how far into the mapping the buffer begins.
6686 let aligned_offset = start & !( page - 1 ) ;
6787 let offset = start - aligned_offset;
6888 let map_len = end - aligned_offset;
6989
90+ let file = & mut self . area . file ;
91+ file. as_file_mut ( ) . set_len ( end as u64 ) ?;
92+ // Ensure subsequent mappings see the extended size.
93+ file. as_file_mut ( ) . seek ( SeekFrom :: Start ( end as u64 ) ) ?;
7094 let mmap = unsafe {
7195 memmap2:: MmapOptions :: new ( )
7296 . offset ( aligned_offset as u64 )
7397 . len ( map_len)
74- . map_mut ( self . file . as_file ( ) ) ?
98+ . map_mut ( file. as_file ( ) ) ?
7599 } ;
76- Ok ( Buffer {
77- arena : self ,
100+
101+ self . area . len = end;
102+
103+ Ok ( Section {
78104 mmap,
79- start,
80105 offset,
81106 elems,
82107 _marker : PhantomData ,
83108 } )
84109 }
85-
86- fn update_len ( & mut self , end : usize ) {
87- self . len = end;
88- }
89-
90- /// Finalize the arena and return immutable bytes for the entire file.
91- pub fn finish ( self ) -> io:: Result < Bytes > {
92- let file = self . file . into_file ( ) ;
93- let mmap = unsafe { memmap2:: MmapOptions :: new ( ) . map ( & file) ? } ;
94- Ok ( Bytes :: from_source ( mmap) )
95- }
96-
97- /// Persist the temporary arena file to `path` and return the underlying [`File`].
98- pub fn persist < P : AsRef < std:: path:: Path > > ( self , path : P ) -> io:: Result < std:: fs:: File > {
99- self . file . persist ( path) . map_err ( Into :: into)
100- }
101110}
102111
103- /// Mutable buffer for writing into a [`ByteArena `].
112+ /// Mutable section reserved from a [`ByteArea `].
104113#[ derive( Debug ) ]
105- pub struct Buffer < ' a , T > {
106- /// Arena that owns the underlying file.
107- arena : & ' a mut ByteArena ,
114+ pub struct Section < ' arena , T > {
108115 /// Writable mapping for the current allocation.
109116 mmap : memmap2:: MmapMut ,
110- /// Start position of this buffer within the arena file in bytes.
111- start : usize ,
112117 /// Offset from the beginning of `mmap` to the start of the buffer.
113118 offset : usize ,
114119 /// Number of elements in the buffer.
115120 elems : usize ,
116- /// Marker to tie the buffer to element type `T` .
117- _marker : PhantomData < T > ,
121+ /// Marker tying the section to the area and element type.
122+ _marker : PhantomData < ( & ' arena ByteArea , * mut T ) > ,
118123}
119124
120- impl < ' a , T > Buffer < ' a , T >
125+ impl < ' arena , T > Section < ' arena , T >
121126where
122127 T : FromBytes + Immutable ,
123128{
@@ -129,21 +134,19 @@ where
129134 }
130135 }
131136
132- /// Finalize the buffer and return immutable [`Bytes`].
133- pub fn finish ( self ) -> io:: Result < Bytes > {
137+ /// Freeze the section and return immutable [`Bytes`].
138+ pub fn freeze ( self ) -> io:: Result < Bytes > {
134139 self . mmap . flush ( ) ?;
135140 let len_bytes = self . elems * core:: mem:: size_of :: < T > ( ) ;
136141 let offset = self . offset ;
137- let arena = self . arena ;
138142 // Convert the writable mapping into a read-only view instead of
139143 // unmapping and remapping the region.
140144 let map = self . mmap . make_read_only ( ) ?;
141- arena. update_len ( self . start + len_bytes) ;
142145 Ok ( Bytes :: from_source ( map) . slice ( offset..offset + len_bytes) )
143146 }
144147}
145148
146- impl < ' a , T > core:: ops:: Deref for Buffer < ' a , T >
149+ impl < ' arena , T > core:: ops:: Deref for Section < ' arena , T >
147150where
148151 T : FromBytes + Immutable ,
149152{
@@ -157,7 +160,7 @@ where
157160 }
158161}
159162
160- impl < ' a , T > core:: ops:: DerefMut for Buffer < ' a , T >
163+ impl < ' arena , T > core:: ops:: DerefMut for Section < ' arena , T >
161164where
162165 T : FromBytes + Immutable ,
163166{
@@ -169,7 +172,7 @@ where
169172 }
170173}
171174
172- impl < ' a , T > AsRef < [ T ] > for Buffer < ' a , T >
175+ impl < ' arena , T > AsRef < [ T ] > for Section < ' arena , T >
173176where
174177 T : FromBytes + Immutable ,
175178{
@@ -178,7 +181,7 @@ where
178181 }
179182}
180183
181- impl < ' a , T > AsMut < [ T ] > for Buffer < ' a , T >
184+ impl < ' arena , T > AsMut < [ T ] > for Section < ' arena , T >
182185where
183186 T : FromBytes + Immutable ,
184187{
0 commit comments