feat(recycling): add customizable recycling policies #33
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Motivation
Currently, all queues and channels in
thingbuf
require that items inthe queue/channel implement
Default
, becauseDefault
is used to fillslots when they are initially allocated. Furthermore, when slots are
checked out for writing to, they are not cleared prior to being written
to --- the user code is responsible for clearing them if needed.
The
StringBuf
type currently implements special behaviorspecifically for
String
s, where theString
is cleared in placeprior to writing to, but this only works for
String
s.StringBuf
alsoprovides an API for limiting the maximum capacity of "empty" strings, so
that they can be shrunk down to that capacity when returning them to the
pool. This allows introducing an upper bound on the capacity allocated
by unused strings. However, again, this only works with
String
s and isonly provided by the
StringBuf
type.This isn't ideal --- users shouldn't have to be responsible for
clearing non-
String
types when reusing allocations.Solution
This branch introduces a new
Recycle<T>
trait that defines a policyfor how
T
-typed pooled objects should be reused.Recycle<T>
definestwo methods:
fn new_element(&self) -> T
creates a new elementfn recycle(&self, element: &mut T)
clears a pooled element for reuseThis allows a
Recycle
implementation to define the lifecycle of apooled item.
In addition, we define a couple of pre-made
Recycle
implementations:DefaultRecycle
, which implementsRecycle
for all typesT
whereT: Default + Clone
. This is used by allthingbuf
types by default.It creates new elements using
Default::default
, and recycles themusing
element.clone_from(T::default())
.Clone::clone_from
is not guaranteed to re-use existing capacity,but it's overridden by most array-based collections (such as the ones
in the standard library) to do so --- it should be equivalent to
.clear()
when cloning from an empty collection. However, this policywill still work with types that don't have a clear-in-place
function.
WithCapacity
implementsRecycle
only for types that definewith_capacity
,shrink_to
, andclear
methods, like allarray-based collections in the Rust standard library. Unlike
DefaultRecycle
, it is guaranteed to clear elements in place andretain any previously allocated capacity.
It can also be configured to add both upper and lower bounds on
capacity. When there is a lower bound, new elements are allocated with
that value as their initial capacity, rather than being allocated with
0 capacity. When an upper bound is set, it will call
shrink_to
priorto clearing elements, to limit the total allocated capacity retained
by the pool.
WithCapacity
currently implementsRecycle
for allalloc
andstd
types that define the requisite methods:Vec
,String
,VecDeque
, andBinaryHeap
when thealloc
feature is enabled, andHashMap
andHashSet
as well, when thestd
feature is enabled.Finally, I've modified the existing queue and channel types to allow
configuring them to use a
Recycle
implementation. TheStringBuf
typeis removed, as it's now obviated by the new APIs.
Future Work
We may wish to factor out the
recycling
module into its own crate, sothat it can be used in other libraries.
Closes #30