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}