scratchpad/scratchpad.rs
1// Copyright 2018-2021 Theodore Cipicchio
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! `Scratchpad` type implementation.
10
11use core::fmt;
12use core::ptr;
13
14use super::{
15 Buffer, Error, ErrorKind, MarkerBack, MarkerFront, StaticBuffer, Tracking,
16};
17use core::cell::{Cell, UnsafeCell};
18use core::mem::size_of;
19#[cfg(not(any(stable_maybe_uninit, feature = "unstable")))]
20use core::mem::uninitialized;
21#[cfg(any(stable_maybe_uninit, feature = "unstable"))]
22use core::mem::MaybeUninit;
23use core::ops::{Deref, DerefMut};
24
25/// Front and back stacks for `Marker` tracking (used internally).
26pub(crate) struct MarkerStacks<TrackingT>
27where
28 TrackingT: Tracking,
29{
30 /// Stack data.
31 pub(crate) data: TrackingT,
32 /// Front stack offset.
33 pub(crate) front: usize,
34 /// Back stack offset.
35 pub(crate) back: usize,
36}
37
38impl<TrackingT> fmt::Debug for MarkerStacks<TrackingT>
39where
40 TrackingT: Tracking,
41{
42 #[inline]
43 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44 write!(f, "MarkerStacks {{ ... }}")
45 }
46}
47
48/// `BorrowFlag` replacement for internal `RefCell` type.
49type BorrowFlag = usize;
50const UNUSED: BorrowFlag = 0usize;
51const WRITING: BorrowFlag = !0usize;
52
53/// `Ref` replacement for internal `RefCell` type.
54///
55/// This only implements the parts of `core::cell::Ref` used by this crate and
56/// is not intended as a full replacement.
57pub(crate) struct Ref<'a, T>
58where
59 T: 'a,
60{
61 cell: &'a RefCell<T>,
62}
63
64impl<'a, T> Drop for Ref<'a, T> {
65 #[inline]
66 fn drop(&mut self) {
67 let borrow = self.cell.borrow.get();
68 debug_assert_ne!(borrow, UNUSED);
69 debug_assert_ne!(borrow, WRITING);
70 self.cell.borrow.set(borrow - 1);
71 }
72}
73
74impl<'a, T> Deref for Ref<'a, T> {
75 type Target = T;
76
77 #[inline]
78 fn deref(&self) -> &T {
79 unsafe { &*self.cell.value.get() }
80 }
81}
82
83impl<'a, T> fmt::Debug for Ref<'a, T>
84where
85 T: fmt::Debug,
86{
87 #[inline]
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 fmt::Debug::fmt(&**self, f)
90 }
91}
92
93/// `RefMut` replacement for internal `RefCell` type.
94///
95/// This only implements the parts of `core::cell::RefMut` used by this crate
96/// and is not intended as a full replacement.
97pub(crate) struct RefMut<'a, T>
98where
99 T: 'a,
100{
101 cell: &'a RefCell<T>,
102}
103
104impl<'a, T> Drop for RefMut<'a, T> {
105 #[inline]
106 fn drop(&mut self) {
107 debug_assert_eq!(self.cell.borrow.get(), WRITING);
108 self.cell.borrow.set(UNUSED);
109 }
110}
111
112impl<'a, T> Deref for RefMut<'a, T> {
113 type Target = T;
114
115 #[inline]
116 fn deref(&self) -> &T {
117 unsafe { &*self.cell.value.get() }
118 }
119}
120
121impl<'a, T> DerefMut for RefMut<'a, T> {
122 #[inline]
123 fn deref_mut(&mut self) -> &mut T {
124 unsafe { &mut *self.cell.value.get() }
125 }
126}
127
128impl<'a, T> fmt::Debug for RefMut<'a, T>
129where
130 T: fmt::Debug,
131{
132 #[inline]
133 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134 fmt::Debug::fmt(&**self, f)
135 }
136}
137
138/// `RefCell` replacement for internal use.
139///
140/// In order to support initialization of a `RefCell<MarkerStacks<_>>` using
141/// `Scratchpad::static_new_in_place()`, we would need to be able to rely on
142/// the internals of `RefCell` to have a specific layout. It is likely
143/// dangerous to assume that its internals won't change over time, so we'll
144/// instead use a custom type whose layout we can depend on over future
145/// versions.
146pub(crate) struct RefCell<T> {
147 borrow: Cell<BorrowFlag>,
148 value: UnsafeCell<T>,
149}
150
151impl<T> RefCell<T> {
152 #[inline]
153 #[cfg(feature = "unstable")]
154 pub(crate) const fn new(value: T) -> Self {
155 RefCell {
156 borrow: Cell::new(UNUSED),
157 value: UnsafeCell::new(value),
158 }
159 }
160
161 #[inline]
162 #[cfg(not(feature = "unstable"))]
163 pub(crate) fn new(value: T) -> Self {
164 RefCell {
165 borrow: Cell::new(UNUSED),
166 value: UnsafeCell::new(value),
167 }
168 }
169
170 /// Creates a `RefCell` in uninitialized memory, leaving its value
171 /// uninitialized.
172 #[inline]
173 pub(crate) unsafe fn new_uninitialized_value_in_place(dst: *mut Self) {
174 // `UnsafeCell<T>` simply wraps a `T` value, so we don't need to do
175 // any special initialization for the `value` field.
176 ptr::write(&mut (*dst).borrow, Cell::new(UNUSED));
177 }
178
179 #[inline]
180 pub(crate) fn borrow(&self) -> Ref<T> {
181 let borrow = self.borrow.get();
182 assert_ne!(borrow, WRITING);
183 self.borrow.set(borrow + 1);
184 Ref { cell: self }
185 }
186
187 #[inline]
188 pub(crate) fn borrow_mut(&self) -> RefMut<T> {
189 assert_eq!(self.borrow.get(), UNUSED);
190 self.borrow.set(WRITING);
191 RefMut { cell: self }
192 }
193
194 #[inline]
195 pub(crate) fn get_mut(&mut self) -> &mut T {
196 unsafe { &mut *self.value.get() }
197 }
198}
199
200impl<T> fmt::Debug for RefCell<T>
201where
202 T: fmt::Debug,
203{
204 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205 // The `Debug` implementation for `core::cell::RefCell` won't show the
206 // cell's value if it is mutably borrowed, but that seems unnecessary
207 // since we won't be holding on to the immutably borrowed value
208 // outside the scope of this function (and since `RefCell` isn't
209 // `Sync`, we can expect it to not be modified while in this
210 // function).
211 f.debug_struct("RefCell")
212 .field("value", unsafe { &*self.value.get() })
213 .finish()
214 }
215}
216
217/// Stack-like dynamic memory pool with double-ended allocation support.
218///
219/// `Scratchpad` manages dynamic allocations from a fixed-size region of
220/// memory in a stack-like manner. Allocations can be made simultaneously from
221/// either the "front" or "back" of the scratchpad by setting a [`Marker`]
222/// using either [`mark_front()`][`mark_front()`] (returning a
223/// [`MarkerFront`]) or [`mark_back()`][`mark_back()`] (returning a
224/// [`MarkerBack`]). Multiple markers can be set, but only the most-recently
225/// set marker of a given type that is still active can be used to allocate
226/// objects.
227///
228/// Individual allocations can be made from the marker, but no memory is
229/// actually freed back into the pool until the marker is dropped, where all
230/// the memory allocated through the marker is released at once. If the marker
231/// is not the most-recently set active marker of its type, its memory will
232/// simply be flagged as unused until all markers of the same type that were
233/// created after it are also dropped, at which point the memory will be once
234/// again made available for allocations.
235///
236/// `Scratchpad`, [`Marker`] implementations, and [`Allocation`] all make use
237/// of static lifetimes to ensure that an object cannot be used after the
238/// object from which it was created is dropped (an allocation cannot outlive
239/// its marker, and a marker cannot outlive its scratchpad).
240///
241/// *See also the [crate-level documentation](index.html) for more detailed
242/// information about how `Scratchpad` works and can be used.*
243///
244/// [`Allocation`]: struct.Allocation.html
245/// [`mark_back()`]: #method.mark_back
246/// [`mark_front()`]: #method.mark_front
247/// [`Marker`]: trait.Marker.html
248/// [`MarkerBack`]: struct.MarkerBack.html
249/// [`MarkerFront`]: struct.MarkerFront.html
250pub struct Scratchpad<BufferT, TrackingT>
251where
252 BufferT: Buffer,
253 TrackingT: Tracking,
254{
255 /// Buffer from which allocations are made.
256 pub(crate) buffer: UnsafeCell<BufferT>,
257 /// Dual stack containing the offsets of each active marker. If a marker
258 /// not at the end of one of the stacks is freed, its offset is set to
259 /// `core::usize::MAX` to indicate it is no longer active until the
260 /// allocations that came after it (in the same stack) have also been
261 /// freed.
262 pub(crate) markers: RefCell<MarkerStacks<TrackingT>>,
263}
264
265impl<BufferT, TrackingT> Scratchpad<BufferT, TrackingT>
266where
267 BufferT: Buffer,
268 TrackingT: Tracking,
269{
270 /// Creates a new scratchpad instance.
271 ///
272 /// Note that using large static arrays for allocation storage or marker
273 /// tracking can cause the program to run out of stack space while calling
274 /// this function. It is recommended to either use borrowed slices or
275 /// boxed slices if this occurs, or alternatively use the unsafe
276 /// [`static_new_in_place()`] function to create the `Scratchpad`.
277 ///
278 /// # Examples
279 ///
280 /// ```
281 /// # #[macro_use]
282 /// # extern crate scratchpad;
283 /// use scratchpad::Scratchpad;
284 /// # #[cfg(not(any(stable_maybe_uninit, feature = "unstable")))]
285 /// # use std::mem::uninitialized;
286 /// # #[cfg(any(stable_maybe_uninit, feature = "unstable"))]
287 /// use std::mem::MaybeUninit;
288 ///
289 /// # fn main() {
290 /// // Creates a scratchpad that can hold up to 256 bytes of data and up
291 /// // to 4 allocation markers. The initial contents of each buffer are
292 /// // ignored, so we can provide uninitialized data in order to reduce
293 /// // the runtime overhead of creating a scratchpad.
294 /// # #[cfg(not(any(stable_maybe_uninit, feature = "unstable")))]
295 /// # let scratchpad = unsafe { Scratchpad::new(
296 /// # uninitialized::<array_type_for_bytes!(u64, 256)>(),
297 /// # uninitialized::<array_type_for_markers!(usize, 4)>(),
298 /// # ) };
299 /// # #[cfg(any(stable_maybe_uninit, feature = "unstable"))]
300 /// let scratchpad = unsafe { Scratchpad::new(
301 /// MaybeUninit::<array_type_for_bytes!(MaybeUninit<u64>, 256)>::uninit().assume_init(),
302 /// MaybeUninit::<array_type_for_markers!(MaybeUninit<usize>, 4)>::uninit().assume_init(),
303 /// ) };
304 /// # }
305 /// ```
306 ///
307 /// [`static_new_in_place()`]: #method.static_new_in_place
308 #[inline(always)]
309 #[cfg(feature = "unstable")]
310 pub const fn new(buffer: BufferT, tracking: TrackingT) -> Self {
311 Scratchpad {
312 buffer: UnsafeCell::new(buffer),
313 markers: RefCell::new(MarkerStacks {
314 data: tracking,
315 front: 0,
316 back: ::core::usize::MAX, // Lazy initialization.
317 }),
318 }
319 }
320
321 /// Creates a new scratchpad instance.
322 ///
323 /// Note that using large static arrays for allocation storage or marker
324 /// tracking can cause the program to run out of stack space while calling
325 /// this function. It is recommended to either use borrowed slices or
326 /// boxed slices if this occurs, or alternatively use the unsafe
327 /// [`static_new_in_place()`] function to create the `Scratchpad`.
328 ///
329 /// # Examples
330 ///
331 /// ```
332 /// # #[macro_use]
333 /// # extern crate scratchpad;
334 /// use scratchpad::Scratchpad;
335 /// # #[cfg(not(any(stable_maybe_uninit, feature = "unstable")))]
336 /// # use std::mem::uninitialized;
337 /// # #[cfg(any(stable_maybe_uninit, feature = "unstable"))]
338 /// use std::mem::MaybeUninit;
339 ///
340 /// # fn main() {
341 /// // Creates a scratchpad that can hold up to 256 bytes of data and up
342 /// // to 4 allocation markers. The initial contents of each buffer are
343 /// // ignored, so we can provide uninitialized data in order to reduce
344 /// // the runtime overhead of creating a scratchpad.
345 /// # #[cfg(not(any(stable_maybe_uninit, feature = "unstable")))]
346 /// # let scratchpad = unsafe { Scratchpad::new(
347 /// # uninitialized::<array_type_for_bytes!(u64, 256)>(),
348 /// # uninitialized::<array_type_for_markers!(usize, 4)>(),
349 /// # ) };
350 /// # #[cfg(any(stable_maybe_uninit, feature = "unstable"))]
351 /// let scratchpad = unsafe { Scratchpad::new(
352 /// MaybeUninit::<array_type_for_bytes!(MaybeUninit<u64>, 256)>::uninit().assume_init(),
353 /// MaybeUninit::<array_type_for_markers!(MaybeUninit<usize>, 4)>::uninit().assume_init(),
354 /// ) };
355 /// # }
356 /// ```
357 ///
358 /// [`static_new_in_place()`]: #method.static_new_in_place
359 #[inline(always)]
360 #[cfg(not(feature = "unstable"))]
361 pub fn new(buffer: BufferT, tracking: TrackingT) -> Self {
362 Scratchpad {
363 buffer: UnsafeCell::new(buffer),
364 markers: RefCell::new(MarkerStacks {
365 back: tracking.capacity(),
366 data: tracking,
367 front: 0,
368 }),
369 }
370 }
371}
372
373impl<BufferT, TrackingT> Scratchpad<BufferT, TrackingT>
374where
375 BufferT: StaticBuffer,
376 TrackingT: Tracking + StaticBuffer,
377{
378 /// Creates a new instance for scratchpad types backed entirely by static
379 /// arrays without initializing array memory.
380 ///
381 /// Since static array [`Buffer`] and [`Tracking`] types are owned by the
382 /// scratchpad, and their sizes are known ahead of time to the scratchpad
383 /// type, scratchpads using only static arrays for storage can be created
384 /// without having to provide any parameters.
385 ///
386 /// Note that using large static arrays for allocation storage or marker
387 /// tracking can cause the program to run out of stack space while calling
388 /// this function. It is recommended to either use borrowed slices or
389 /// boxed slices if this occurs, or alternatively use the unsafe
390 /// [`static_new_in_place()`] function to create the `Scratchpad`.
391 ///
392 /// It is strongly recommended to use arrays of [`MaybeUninit`] elements
393 /// for both allocation and tracking storage if possible when using this
394 /// function. Even though [`ByteData`] types can safely store any pattern
395 /// of bits without causing undefined behavior, the rules in Rust for
396 /// using integers whose memory is specifically uninitialized have not
397 /// been finalized.
398 ///
399 /// # Examples
400 ///
401 /// ```
402 /// # #[macro_use]
403 /// # extern crate scratchpad;
404 /// use scratchpad::Scratchpad;
405 /// # #[cfg(any(stable_maybe_uninit, feature = "unstable"))]
406 /// use std::mem::MaybeUninit;
407 ///
408 /// # fn main() {
409 /// // Creates a scratchpad that can hold up to 256 bytes of data and up
410 /// // to 4 allocation markers.
411 /// # #[cfg(not(any(stable_maybe_uninit, feature = "unstable")))]
412 /// # let scratchpad = Scratchpad::<
413 /// # array_type_for_bytes!(u64, 256),
414 /// # array_type_for_markers!(usize, 4),
415 /// # >::static_new();
416 /// # #[cfg(any(stable_maybe_uninit, feature = "unstable"))]
417 /// let scratchpad = Scratchpad::<
418 /// array_type_for_bytes!(MaybeUninit<u64>, 256),
419 /// array_type_for_markers!(MaybeUninit<usize>, 4),
420 /// >::static_new();
421 /// # }
422 /// ```
423 ///
424 /// [`Buffer`]: trait.Buffer.html
425 /// [`Tracking`]: trait.Tracking.html
426 /// [`static_new_in_place()`]: #method.static_new_in_place
427 /// [`MaybeUninit`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html
428 /// [`ByteData`]: trait.ByteData.html
429 #[inline(always)]
430 pub fn static_new() -> Self {
431 #[cfg(any(stable_maybe_uninit, feature = "unstable"))]
432 // LINT: In order to maintain backwards compatibility with
433 // `scratchpad` versions that predate `MaybeUninit`, we still
434 // have to allow uninitialized buffer setup for `ByteData` types
435 // not wrapped by `MaybeUninit`. The method documentation
436 // mentions the caveats of this and recommends using buffers of
437 // `MaybeUninit` types whenever possible.
438 #[cfg_attr(
439 feature = "cargo-clippy",
440 allow(clippy::uninit_assumed_init)
441 )]
442 return Scratchpad {
443 buffer: unsafe { MaybeUninit::uninit().assume_init() },
444 markers: RefCell::new(MarkerStacks {
445 data: unsafe { MaybeUninit::uninit().assume_init() },
446 front: 0,
447 back: size_of::<TrackingT>() / size_of::<usize>(),
448 }),
449 };
450
451 #[cfg(not(any(stable_maybe_uninit, feature = "unstable")))]
452 return Scratchpad {
453 buffer: unsafe { uninitialized() },
454 markers: RefCell::new(MarkerStacks {
455 data: unsafe { uninitialized() },
456 front: 0,
457 back: size_of::<TrackingT>() / size_of::<usize>(),
458 }),
459 };
460 }
461
462 /// Initializes a new instance in uninitialized memory for scratchpad
463 /// types backed entirely by static arrays.
464 ///
465 /// This is provided to allow for creation of scratchpads backed by large
466 /// static arrays while guaranteeing that both arrays and the created
467 /// `Scratchpad` are never accidentally stored on the stack, avoiding
468 /// possible stack overflow.
469 ///
470 /// It is strongly recommended to use arrays of [`MaybeUninit`] elements
471 /// for both allocation and tracking storage if possible when using this
472 /// function. Even though [`ByteData`] types can safely store any pattern
473 /// of bits without causing undefined behavior, the rules in Rust for
474 /// using integers whose memory is specifically uninitialized have not
475 /// been finalized.
476 ///
477 /// # Safety
478 ///
479 /// This function is unsafe because it operates on a raw pointer.
480 ///
481 /// It does not drop any existing contents of `dst` before writing, nor
482 /// does it check for whether `dst` is a valid pointer.
483 ///
484 /// `dst` must be properly aligned for storage of an instance of
485 /// `Scratchpad`.
486 ///
487 /// After returning, the contents of `dst` will need to be dropped when
488 /// the scratchpad is no longer in use before the memory pointed to by
489 /// `dst` is freed.
490 ///
491 /// # Examples
492 ///
493 /// ```
494 /// # #[macro_use]
495 /// # extern crate scratchpad;
496 /// use scratchpad::{CacheAligned, Scratchpad};
497 /// # #[cfg(any(stable_maybe_uninit, feature = "unstable"))]
498 /// use std::mem::MaybeUninit;
499 ///
500 /// // Scratchpad that can hold up to 1 MB of data and up to 16 allocation
501 /// // markers.
502 /// # #[cfg(not(any(stable_maybe_uninit, feature = "unstable")))]
503 /// # type LargeScratchpad = Scratchpad<
504 /// # array_type_for_bytes!(CacheAligned, 1024 * 1024),
505 /// # array_type_for_markers!(usize, 16),
506 /// # >;
507 /// # #[cfg(any(stable_maybe_uninit, feature = "unstable"))]
508 /// type LargeScratchpad = Scratchpad<
509 /// array_type_for_bytes!(MaybeUninit<CacheAligned>, 1024 * 1024),
510 /// array_type_for_markers!(MaybeUninit<usize>, 16),
511 /// >;
512 ///
513 /// # fn main() {
514 /// unsafe {
515 /// // The `Vec` here represents any region of memory in which a
516 /// // `Scratchpad` needs to be initialized at runtime, whether
517 /// // allocated from the heap or elsewhere.
518 /// let mut memory = Vec::with_capacity(1);
519 /// memory.set_len(1);
520 ///
521 /// LargeScratchpad::static_new_in_place(memory.as_mut_ptr());
522 ///
523 /// let scratchpad = &memory[0];
524 /// let marker = scratchpad.mark_front().unwrap();
525 /// let allocation = marker.allocate(12).unwrap();
526 /// assert_eq!(*allocation, 12);
527 /// }
528 /// # }
529 /// ```
530 ///
531 /// [`MaybeUninit`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html
532 /// [`ByteData`]: trait.ByteData.html
533 #[inline]
534 pub unsafe fn static_new_in_place(dst: *mut Self) {
535 // `UnsafeCell<T>` simply wraps a `T` value, so we don't need to do
536 // any special initialization for the `buffer` or `MarkerStacks::data`
537 // fields.
538 RefCell::new_uninitialized_value_in_place(&mut (*dst).markers);
539 let markers = (*dst).markers.get_mut();
540 ptr::write(&mut markers.front, 0);
541 ptr::write(&mut markers.back, markers.data.capacity());
542 }
543}
544
545impl<BufferT, TrackingT> Scratchpad<BufferT, TrackingT>
546where
547 BufferT: Buffer,
548 TrackingT: Tracking,
549{
550 /// Creates a marker at the front of the allocation buffer for subsequent
551 /// allocations.
552 ///
553 /// # Examples
554 ///
555 /// ```
556 /// use scratchpad::Scratchpad;
557 ///
558 /// let scratchpad = Scratchpad::<[u64; 1], [usize; 1]>::new([0], [0]);
559 ///
560 /// let marker = scratchpad.mark_front().unwrap();
561 /// // `marker` can now be used for allocations...
562 /// ```
563 pub fn mark_front(
564 &self,
565 ) -> Result<MarkerFront<BufferT, TrackingT>, Error<()>> {
566 let mut markers = self.markers.borrow_mut();
567
568 // `markers.back` is lazy-initialized when the "unstable" feature is
569 // enabled so that `Scratchpad::new()` can be a `const` function.
570 #[cfg(feature = "unstable")]
571 {
572 if markers.back == ::core::usize::MAX {
573 markers.back = markers.data.capacity();
574 }
575 }
576
577 let index = markers.front;
578 if index == markers.back {
579 return Err(Error::new(ErrorKind::MarkerLimit, ()));
580 }
581
582 let buffer_offset = if index == 0 {
583 0
584 } else {
585 markers.data.get(index - 1)
586 };
587 markers.data.set(index, buffer_offset);
588 markers.front = index + 1;
589
590 Ok(MarkerFront {
591 scratchpad: self,
592 index,
593 })
594 }
595
596 /// Creates a marker at the back of the allocation buffer for subsequent
597 /// allocations.
598 ///
599 /// # Examples
600 ///
601 /// ```
602 /// use scratchpad::Scratchpad;
603 ///
604 /// let scratchpad = Scratchpad::<[u64; 1], [usize; 1]>::new([0], [0]);
605 ///
606 /// let marker = scratchpad.mark_back().unwrap();
607 /// // `marker` can now be used for allocations...
608 /// ```
609 pub fn mark_back(
610 &self,
611 ) -> Result<MarkerBack<BufferT, TrackingT>, Error<()>> {
612 let mut markers = self.markers.borrow_mut();
613
614 // `markers.back` is lazy-initialized when the "unstable" feature is
615 // enabled so that `Scratchpad::new()` can be a `const` function.
616 #[cfg(feature = "unstable")]
617 {
618 if markers.back == ::core::usize::MAX {
619 markers.back = markers.data.capacity();
620 }
621 }
622
623 let mut index = markers.back;
624 if index == markers.front {
625 return Err(Error::new(ErrorKind::MarkerLimit, ()));
626 }
627
628 let buffer_offset = if index == markers.data.capacity() {
629 unsafe { (*self.buffer.get()).as_bytes().len() }
630 } else {
631 markers.data.get(index)
632 };
633 index -= 1;
634 markers.data.set(index, buffer_offset);
635 markers.back = index;
636
637 Ok(MarkerBack {
638 scratchpad: self,
639 index,
640 })
641 }
642}
643
644impl<BufferT, TrackingT> fmt::Debug for Scratchpad<BufferT, TrackingT>
645where
646 BufferT: Buffer,
647 TrackingT: Tracking,
648{
649 #[inline]
650 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
651 write!(
652 f,
653 "Scratchpad {{ buffer.len = {}, markers: {:?} }}",
654 unsafe { &*self.buffer.get() }.as_bytes().len(),
655 self.markers.borrow(),
656 )
657 }
658}