summaryrefslogtreecommitdiffstats
path: root/vendor/sized-chunks
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
commit2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch)
tree033cc839730fda84ff08db877037977be94e5e3a /vendor/sized-chunks
parentInitial commit. (diff)
downloadcargo-upstream.tar.xz
cargo-upstream.zip
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/sized-chunks')
-rw-r--r--vendor/sized-chunks/.cargo-checksum.json1
-rw-r--r--vendor/sized-chunks/CHANGELOG.md223
-rw-r--r--vendor/sized-chunks/CODE_OF_CONDUCT.md73
-rw-r--r--vendor/sized-chunks/Cargo.toml49
-rw-r--r--vendor/sized-chunks/LICENCE.md355
-rw-r--r--vendor/sized-chunks/README.md35
-rw-r--r--vendor/sized-chunks/debian/patches/disable-features.diff40
-rw-r--r--vendor/sized-chunks/debian/patches/series1
-rw-r--r--vendor/sized-chunks/src/arbitrary.rs98
-rw-r--r--vendor/sized-chunks/src/inline_array/iter.rs63
-rw-r--r--vendor/sized-chunks/src/inline_array/mod.rs736
-rw-r--r--vendor/sized-chunks/src/lib.rs126
-rw-r--r--vendor/sized-chunks/src/ring_buffer/index.rs178
-rw-r--r--vendor/sized-chunks/src/ring_buffer/iter.rs218
-rw-r--r--vendor/sized-chunks/src/ring_buffer/mod.rs1156
-rw-r--r--vendor/sized-chunks/src/ring_buffer/refpool.rs69
-rw-r--r--vendor/sized-chunks/src/ring_buffer/slice.rs556
-rw-r--r--vendor/sized-chunks/src/sized_chunk/iter.rs109
-rw-r--r--vendor/sized-chunks/src/sized_chunk/mod.rs1411
-rw-r--r--vendor/sized-chunks/src/sized_chunk/refpool.rs66
-rw-r--r--vendor/sized-chunks/src/sparse_chunk/iter.rs245
-rw-r--r--vendor/sized-chunks/src/sparse_chunk/mod.rs514
-rw-r--r--vendor/sized-chunks/src/sparse_chunk/refpool.rs57
-rw-r--r--vendor/sized-chunks/src/tests.rs18
-rw-r--r--vendor/sized-chunks/src/types.rs54
25 files changed, 6451 insertions, 0 deletions
diff --git a/vendor/sized-chunks/.cargo-checksum.json b/vendor/sized-chunks/.cargo-checksum.json
new file mode 100644
index 0000000..f80c01d
--- /dev/null
+++ b/vendor/sized-chunks/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{},"package":"16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e"} \ No newline at end of file
diff --git a/vendor/sized-chunks/CHANGELOG.md b/vendor/sized-chunks/CHANGELOG.md
new file mode 100644
index 0000000..8b1bbb8
--- /dev/null
+++ b/vendor/sized-chunks/CHANGELOG.md
@@ -0,0 +1,223 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project
+adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+## [0.6.5] - 2021-04-16
+
+- When `InlineArray` cannot hold any values because of misalignment, report it as capacity 0
+ instead of panicking at runtime. (#22)
+
+## [0.6.4] - 2021-02-17
+
+### FIXED
+
+- `InlineArray` can be used in recursive types again.
+
+### CHANGED
+
+- `InlineArray::new()` now panics when it can't store elements with large alignment (this was UB
+ prior to 0.6.3). Alignments of `usize` and smaller are always supported. Larger alignments are
+ supported if the capacity-providing type has sufficient alignment.
+
+## [0.6.3] - 2021-02-14
+
+### FIXED
+
+- Multilple soundness fixes: `InlineArray` handles large alignment, panic safety in `Chunk`'s
+ `clone` and `from_iter`, capacity checks in `unit()`, `pair()` and `from()`.
+- `InlineArray` can now handle zero sized values. This relies on conditionals in const functions,
+ a feature which was introduced in Rust 1.46.0, which means this is now the minimum Rust version
+ this crate will work on.
+
+## [0.6.2] - 2020-05-15
+
+### FIXED
+
+- This release exists for no other purpose than to bump the `refpool` optional dependency.
+
+## [0.6.1] - 2020-03-26
+
+### ADDED
+
+- The crate now has a `std` feature flag, which is on by default, and will make the crate `no_std`
+ if disabled.
+
+### FIXED
+
+- Fixed a compilation error if you had the `arbitrary` feature flag enabled without the
+ `ringbuffer` flag.
+
+## [0.6.0] - 2020-03-24
+
+### CHANGED
+
+- `RingBuffer` and its accompanying slice types `Slice` and `SliceMut` now implement `Array` and
+ `ArrayMut` from [`array-ops`](http://docs.rs/array-ops), giving them most of the methods that
+ would be available on primitive slice types and cutting down on code duplication in the
+ implementation, but at the price of having to pull `Array` et al into scope when you need them.
+ Because this means adding a dependency to `array-ops`, `RingBuffer` has now been moved behind
+ the `ringbuffer` feature flag. `Chunk` and `InlineArray` don't and won't implement `Array`,
+ because they are both able to implement `Deref<[A]>`, which provides the same functionality more
+ efficiently.
+
+### ADDED
+
+- The `insert_from` and `insert_ordered` methods recently added to `Chunk` have now also been
+ added to `RingBuffer`.
+- `RingBuffer`'s `Slice` and `SliceMut` now also have the three `binary_search` methods regular
+ slices have.
+- `SparseChunk`, `RingBuffer`, `Slice` and `SliceMut` now have unsafe `get_unchecked` and
+ `get_unchecked_mut` methods.
+- `PartialEq` implementations allowing you to compare `RingBuffer`s, `Slice`s and `SliceMut`s
+ interchangeably have been added.
+
+### FIXED
+
+- Fixed an aliasing issue in `RingBuffer`'s mutable iterator, as uncovered by Miri. Behind the
+ scenes, the full non-fuzzing unit test suite is now able to run on Miri without crashing it
+ (after migrating the last Proptest tests away from the test suite into the fuzz targets), and
+ this has been included in its CI build. (#6)
+
+## [0.5.3] - 2020-03-11
+
+### FIXED
+
+- Debug only assertions made it into the previous release by accident, and this change has been
+ reverted. (#7)
+
+## [0.5.2] - 2020-03-10
+
+### ADDED
+
+- `Chunk` now has an `insert_from` method for inserting multiple values at an index in one go.
+- `Chunk` now also has an `insert_ordered` method for inserting values into a sorted chunk.
+- `SparseChunk` now has the methods `option_iter()`, `option_iter_mut()` and `option_drain()` with
+ their corresponding iterators to iterate over a chunk as if it were an array of `Option`s.
+- [`Arbitrary`](https://docs.rs/arbitrary/latest/arbitrary/trait.Arbitrary.html) implementations
+ for all data types have been added behind the `arbitrary` feature flag.
+
+### FIXED
+
+- Internal consistency assertions are now only performed in debug mode (like with
+ `debug_assert!`). This means `sized_chunks` will no longer cause panics in release mode when you
+ do things like pushing to a full chunk, but do bad and undefined things instead. It also means a
+ very slight performance gain.
+
+## [0.5.1] - 2019-12-12
+
+### ADDED
+
+- `PoolDefault` and `PoolClone` implementations, from the
+ [`refpool`](https://crates.io/crates/refpool) crate, are available for `Chunk`, `SparseChunk`
+ and `RingBuffer`, behind the `refpool` feature flag.
+
+## [0.5.0] - 2019-09-09
+
+### CHANGED
+
+- The `Bitmap` type (and its helper type, `Bits`) has been split off into a separate crate, named
+ `bitmaps`. If you need it, it's in that crate now. `sized-chunks` does not re-export it. Of
+ course, this means `sized-chunks` has gained `bitmaps` as its second hard dependency.
+
+## [0.4.0] - 2019-09-02
+
+### CHANGED
+
+- The 0.3.2 release increased the minimum rustc version required, which should have been a major
+ version bump, so 0.3.2 is being yanked and re-tagged as 0.4.0.
+
+## [0.3.2] - 2019-08-29
+
+### ADDED
+
+- Chunk/bitmap sizes up to 1024 are now supported.
+
+### FIXED
+
+- Replaced `ManuallyDrop` in implementations with `MaybeUninit`, along with a general unsafe code
+ cleanup. (#3)
+
+## [0.3.1] - 2019-08-03
+
+### ADDED
+
+- Chunk sizes up to 256 are now supported.
+
+## [0.3.0] - 2019-05-18
+
+### ADDED
+
+- A new data structure, `InlineArray`, which is a stack allocated array matching the size of a
+ given type, intended for optimising for the case of very small vectors.
+- `Chunk` has an implementation of `From<InlineArray>` which is considerably faster than going via
+ iterators.
+
+## [0.2.2] - 2019-05-10
+
+### ADDED
+
+- `Slice::get` methods now return references with the lifetime of the underlying `RingBuffer`
+ rather than the lifetime of the slice.
+
+## [0.2.1] - 2019-04-15
+
+### ADDED
+
+- A lot of documentation.
+- `std::io::Read` implementations for `Chunk<u8>` and `RingBuffer<u8>` to match their `Write`
+ implementations.
+
+## [0.2.0] - 2019-04-14
+
+### CHANGED
+
+- The `capacity()` method has been replacied with a `CAPACITY` const on each type.
+
+### ADDED
+
+- There is now a `RingBuffer` implementation, which should be nearly a drop-in replacement for
+ `SizedChunk` but is always O(1) on push and cannot be dereferenced to slices (but it has a set
+ of custom slice-like implementations to make that less of a drawback).
+- The `Drain` iterator for `SizedChunk` now implements `DoubleEndedIterator`.
+
+### FIXED
+
+- `SizedChunk::drain_from_front/back` will now always panic if the iterator underflows, instead of
+ only doing it in debug mode.
+
+## [0.1.3] - 2019-04-12
+
+### ADDED
+
+- `SparseChunk` now has a default length of `U64`.
+- `Chunk` now has `PartialEq` defined for anything that can be borrowed as a slice.
+- `SparseChunk<A>` likewise has `PartialEq` defined for `BTreeMap<usize, A>` and
+ `HashMap<usize, A>`. These are intended for debugging and aren't optimally `efficient.
+- `Chunk` and `SparseChunk` now have a new method `capacity()` which returns its maximum capacity
+ (the number in the type) as a usize.
+- Added an `entries()` method to `SparseChunk`.
+- `SparseChunk` now has a `Debug` implementation.
+
+### FIXED
+
+- Extensive integration tests were added for `Chunk` and `SparseChunk`.
+- `Chunk::clear` is now very slightly faster.
+
+## [0.1.2] - 2019-03-11
+
+### FIXED
+
+- Fixed an alignment issue in `Chunk::drain_from_back`. (#1)
+
+## [0.1.1] - 2019-02-19
+
+### FIXED
+
+- Some 2018 edition issues.
+
+## [0.1.0] - 2019-02-19
+
+Initial release.
diff --git a/vendor/sized-chunks/CODE_OF_CONDUCT.md b/vendor/sized-chunks/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..02a0869
--- /dev/null
+++ b/vendor/sized-chunks/CODE_OF_CONDUCT.md
@@ -0,0 +1,73 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+education, socio-economic status, nationality, personal appearance, race,
+religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at admin@immutable.rs. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
diff --git a/vendor/sized-chunks/Cargo.toml b/vendor/sized-chunks/Cargo.toml
new file mode 100644
index 0000000..44712ce
--- /dev/null
+++ b/vendor/sized-chunks/Cargo.toml
@@ -0,0 +1,49 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "sized-chunks"
+version = "0.6.5"
+authors = ["Bodil Stokke <bodil@bodil.org>"]
+exclude = ["release.toml", "proptest-regressions/**"]
+description = "Efficient sized chunk datatypes"
+documentation = "http://docs.rs/sized-chunks"
+readme = "./README.md"
+keywords = ["sparse-array"]
+categories = ["data-structures"]
+license = "MPL-2.0+"
+repository = "https://github.com/bodil/sized-chunks"
+[package.metadata.docs.rs]
+all-features = true
+#[dependencies.arbitrary]
+#version = "1.0.0"
+#optional = true
+
+#[dependencies.array-ops]
+#version = "0.1.0"
+#optional = true
+
+[dependencies.bitmaps]
+version = "2.1.0"
+
+#[dependencies.refpool]
+#version = "0.4.3"
+#optional = true
+
+[dependencies.typenum]
+version = "1.12.0"
+
+[features]
+default = ["std"]
+#ringbuffer = ["array-ops"]
+std = []
diff --git a/vendor/sized-chunks/LICENCE.md b/vendor/sized-chunks/LICENCE.md
new file mode 100644
index 0000000..cd44203
--- /dev/null
+++ b/vendor/sized-chunks/LICENCE.md
@@ -0,0 +1,355 @@
+Mozilla Public License Version 2.0
+==================================
+
+### 1. Definitions
+
+**1.1. “Contributor”**
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+**1.2. “Contributor Version”**
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+**1.3. “Contribution”**
+ means Covered Software of a particular Contributor.
+
+**1.4. “Covered Software”**
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+**1.5. “Incompatible With Secondary Licenses”**
+ means
+
+* **(a)** that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+* **(b)** that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+**1.6. “Executable Form”**
+ means any form of the work other than Source Code Form.
+
+**1.7. “Larger Work”**
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+**1.8. “License”**
+ means this document.
+
+**1.9. “Licensable”**
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+**1.10. “Modifications”**
+ means any of the following:
+
+* **(a)** any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+* **(b)** any new file in Source Code Form that contains any Covered
+ Software.
+
+**1.11. “Patent Claims” of a Contributor**
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+**1.12. “Secondary License”**
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+**1.13. “Source Code Form”**
+ means the form of the work preferred for making modifications.
+
+**1.14. “You” (or “Your”)**
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, “You” includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, “control” means **(a)** the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or **(b)** ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+
+### 2. License Grants and Conditions
+
+#### 2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+* **(a)** under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+* **(b)** under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+#### 2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+#### 2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+* **(a)** for any code that a Contributor has removed from Covered Software;
+ or
+* **(b)** for infringements caused by: **(i)** Your and any other third party's
+ modifications of Covered Software, or **(ii)** the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+* **(c)** under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+#### 2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+#### 2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+#### 2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+#### 2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+
+### 3. Responsibilities
+
+#### 3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+#### 3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+* **(a)** such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+* **(b)** You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+#### 3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+#### 3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+#### 3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+
+### 4. Inability to Comply Due to Statute or Regulation
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: **(a)** comply with
+the terms of this License to the maximum extent possible; and **(b)**
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+
+### 5. Termination
+
+**5.1.** The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated **(a)** provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and **(b)** on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+**5.2.** If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+
+### 6. Disclaimer of Warranty
+
+> Covered Software is provided under this License on an “as is”
+> basis, without warranty of any kind, either expressed, implied, or
+> statutory, including, without limitation, warranties that the
+> Covered Software is free of defects, merchantable, fit for a
+> particular purpose or non-infringing. The entire risk as to the
+> quality and performance of the Covered Software is with You.
+> Should any Covered Software prove defective in any respect, You
+> (not any Contributor) assume the cost of any necessary servicing,
+> repair, or correction. This disclaimer of warranty constitutes an
+> essential part of this License. No use of any Covered Software is
+> authorized under this License except under this disclaimer.
+
+### 7. Limitation of Liability
+
+> Under no circumstances and under no legal theory, whether tort
+> (including negligence), contract, or otherwise, shall any
+> Contributor, or anyone who distributes Covered Software as
+> permitted above, be liable to You for any direct, indirect,
+> special, incidental, or consequential damages of any character
+> including, without limitation, damages for lost profits, loss of
+> goodwill, work stoppage, computer failure or malfunction, or any
+> and all other commercial damages or losses, even if such party
+> shall have been informed of the possibility of such damages. This
+> limitation of liability shall not apply to liability for death or
+> personal injury resulting from such party's negligence to the
+> extent applicable law prohibits such limitation. Some
+> jurisdictions do not allow the exclusion or limitation of
+> incidental or consequential damages, so this exclusion and
+> limitation may not apply to You.
+
+
+### 8. Litigation
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+
+### 9. Miscellaneous
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+
+### 10. Versions of the License
+
+#### 10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+#### 10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+#### 10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+## Exhibit A - Source Code Form License Notice
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+## Exhibit B - “Incompatible With Secondary Licenses” Notice
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/vendor/sized-chunks/README.md b/vendor/sized-chunks/README.md
new file mode 100644
index 0000000..0bb3c31
--- /dev/null
+++ b/vendor/sized-chunks/README.md
@@ -0,0 +1,35 @@
+# sized-chunks
+
+Various fixed length array data types, designed for [immutable.rs].
+
+## Overview
+
+This crate provides the core building blocks for the immutable data structures
+in [immutable.rs]: a sized array with O(1) amortised double ended push/pop and
+smarter insert/remove performance (used by `im::Vector` and `im::OrdMap`), and a
+fixed size sparse array (used by `im::HashMap`).
+
+In a nutshell, this crate contains the unsafe bits from [immutable.rs], which
+may or may not be useful to anyone else, and have been split out for ease of
+auditing.
+
+## Documentation
+
+* [API docs](https://docs.rs/sized-chunks)
+
+## Licence
+
+Copyright 2019 Bodil Stokke
+
+This software is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+## Code of Conduct
+
+Please note that this project is released with a [Contributor Code of
+Conduct][coc]. By participating in this project you agree to abide by its
+terms.
+
+[immutable.rs]: https://immutable.rs/
+[coc]: https://github.com/bodil/sized-chunks/blob/master/CODE_OF_CONDUCT.md
diff --git a/vendor/sized-chunks/debian/patches/disable-features.diff b/vendor/sized-chunks/debian/patches/disable-features.diff
new file mode 100644
index 0000000..7aed740
--- /dev/null
+++ b/vendor/sized-chunks/debian/patches/disable-features.diff
@@ -0,0 +1,40 @@
+Index: sized-chunks/Cargo.toml
+===================================================================
+--- sized-chunks.orig/Cargo.toml
++++ sized-chunks/Cargo.toml
+@@ -25,25 +25,25 @@ license = "MPL-2.0+"
+ repository = "https://github.com/bodil/sized-chunks"
+ [package.metadata.docs.rs]
+ all-features = true
+-[dependencies.arbitrary]
+-version = "1.0.0"
+-optional = true
++#[dependencies.arbitrary]
++#version = "1.0.0"
++#optional = true
+
+-[dependencies.array-ops]
+-version = "0.1.0"
+-optional = true
++#[dependencies.array-ops]
++#version = "0.1.0"
++#optional = true
+
+ [dependencies.bitmaps]
+ version = "2.1.0"
+
+-[dependencies.refpool]
+-version = "0.4.3"
+-optional = true
++#[dependencies.refpool]
++#version = "0.4.3"
++#optional = true
+
+ [dependencies.typenum]
+ version = "1.12.0"
+
+ [features]
+ default = ["std"]
+-ringbuffer = ["array-ops"]
++#ringbuffer = ["array-ops"]
+ std = []
diff --git a/vendor/sized-chunks/debian/patches/series b/vendor/sized-chunks/debian/patches/series
new file mode 100644
index 0000000..11136e0
--- /dev/null
+++ b/vendor/sized-chunks/debian/patches/series
@@ -0,0 +1 @@
+disable-features.diff
diff --git a/vendor/sized-chunks/src/arbitrary.rs b/vendor/sized-chunks/src/arbitrary.rs
new file mode 100644
index 0000000..718937e
--- /dev/null
+++ b/vendor/sized-chunks/src/arbitrary.rs
@@ -0,0 +1,98 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+use bitmaps::Bits;
+
+use ::arbitrary::{size_hint, Arbitrary, Result, Unstructured};
+
+use crate::{types::ChunkLength, Chunk, InlineArray, SparseChunk};
+
+#[cfg(feature = "ringbuffer")]
+use crate::RingBuffer;
+
+impl<'a, A, N> Arbitrary<'a> for Chunk<A, N>
+where
+ A: Arbitrary<'a>,
+ N: ChunkLength<A> + 'static,
+{
+ fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+ u.arbitrary_iter()?.take(Self::CAPACITY).collect()
+ }
+
+ fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+ u.arbitrary_take_rest_iter()?.take(Self::CAPACITY).collect()
+ }
+
+ fn size_hint(depth: usize) -> (usize, Option<usize>) {
+ size_hint::recursion_guard(depth, |depth| {
+ let (_, upper) = A::size_hint(depth);
+ (0, upper.map(|upper| upper * Self::CAPACITY))
+ })
+ }
+}
+
+#[cfg(feature = "ringbuffer")]
+impl<'a, A, N> Arbitrary<'a> for RingBuffer<A, N>
+where
+ A: Arbitrary<'a>,
+ N: ChunkLength<A> + 'static,
+{
+ fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+ u.arbitrary_iter()?.take(Self::CAPACITY).collect()
+ }
+
+ fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+ u.arbitrary_take_rest_iter()?.take(Self::CAPACITY).collect()
+ }
+
+ fn size_hint(depth: usize) -> (usize, Option<usize>) {
+ size_hint::recursion_guard(depth, |depth| {
+ let (_, upper) = A::size_hint(depth);
+ (0, upper.map(|upper| upper * Self::CAPACITY))
+ })
+ }
+}
+
+impl<'a, A, N> Arbitrary<'a> for SparseChunk<A, N>
+where
+ A: Clone,
+ Option<A>: Arbitrary<'a>,
+ N: ChunkLength<A> + Bits + 'static,
+{
+ fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+ u.arbitrary_iter()?.take(Self::CAPACITY).collect()
+ }
+
+ fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+ u.arbitrary_take_rest_iter()?.take(Self::CAPACITY).collect()
+ }
+
+ fn size_hint(depth: usize) -> (usize, Option<usize>) {
+ size_hint::recursion_guard(depth, |depth| {
+ let (_, upper) = Option::<A>::size_hint(depth);
+ (0, upper.map(|upper| upper * Self::CAPACITY))
+ })
+ }
+}
+
+impl<'a, A, T> Arbitrary<'a> for InlineArray<A, T>
+where
+ A: Arbitrary<'a>,
+ T: 'static,
+{
+ fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+ u.arbitrary_iter()?.take(Self::CAPACITY).collect()
+ }
+
+ fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+ u.arbitrary_take_rest_iter()?.take(Self::CAPACITY).collect()
+ }
+
+ fn size_hint(depth: usize) -> (usize, Option<usize>) {
+ size_hint::recursion_guard(depth, |depth| {
+ let (_, upper) = A::size_hint(depth);
+ (0, upper.map(|upper| upper * Self::CAPACITY))
+ })
+ }
+}
diff --git a/vendor/sized-chunks/src/inline_array/iter.rs b/vendor/sized-chunks/src/inline_array/iter.rs
new file mode 100644
index 0000000..eec6ad8
--- /dev/null
+++ b/vendor/sized-chunks/src/inline_array/iter.rs
@@ -0,0 +1,63 @@
+use core::iter::FusedIterator;
+
+use crate::InlineArray;
+
+/// A consuming iterator over the elements of an `InlineArray`.
+pub struct Iter<A, T> {
+ pub(crate) array: InlineArray<A, T>,
+}
+
+impl<A, T> Iterator for Iter<A, T> {
+ type Item = A;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.array.remove(0)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.array.len(), Some(self.array.len()))
+ }
+}
+
+impl<A, T> DoubleEndedIterator for Iter<A, T> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.array.pop()
+ }
+}
+
+impl<A, T> ExactSizeIterator for Iter<A, T> {}
+
+impl<A, T> FusedIterator for Iter<A, T> {}
+
+/// A draining iterator over the elements of an `InlineArray`.
+///
+/// "Draining" means that as the iterator yields each element, it's removed from
+/// the `InlineArray`. When the iterator terminates, the array will be empty.
+/// This is different from the consuming iterator `Iter` in that `Iter` will
+/// take ownership of the `InlineArray` and discard it when you're done
+/// iterating, while `Drain` leaves you still owning the drained `InlineArray`.
+pub struct Drain<'a, A, T> {
+ pub(crate) array: &'a mut InlineArray<A, T>,
+}
+
+impl<'a, A, T> Iterator for Drain<'a, A, T> {
+ type Item = A;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.array.remove(0)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.array.len(), Some(self.array.len()))
+ }
+}
+
+impl<'a, A, T> DoubleEndedIterator for Drain<'a, A, T> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.array.pop()
+ }
+}
+
+impl<'a, A, T> ExactSizeIterator for Drain<'a, A, T> {}
+
+impl<'a, A, T> FusedIterator for Drain<'a, A, T> {}
diff --git a/vendor/sized-chunks/src/inline_array/mod.rs b/vendor/sized-chunks/src/inline_array/mod.rs
new file mode 100644
index 0000000..4fea8f1
--- /dev/null
+++ b/vendor/sized-chunks/src/inline_array/mod.rs
@@ -0,0 +1,736 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+//! A fixed capacity array sized to match some other type `T`.
+//!
+//! See [`InlineArray`](struct.InlineArray.html)
+
+use core::borrow::{Borrow, BorrowMut};
+use core::cmp::Ordering;
+use core::fmt::{Debug, Error, Formatter};
+use core::hash::{Hash, Hasher};
+use core::iter::FromIterator;
+use core::marker::PhantomData;
+use core::mem::{self, MaybeUninit};
+use core::ops::{Deref, DerefMut};
+use core::ptr;
+use core::ptr::NonNull;
+use core::slice::{from_raw_parts, from_raw_parts_mut, Iter as SliceIter, IterMut as SliceIterMut};
+
+mod iter;
+pub use self::iter::{Drain, Iter};
+
+/// A fixed capacity array sized to match some other type `T`.
+///
+/// This works like a vector, but allocated on the stack (and thus marginally
+/// faster than `Vec`), with the allocated space exactly matching the size of
+/// the given type `T`. The vector consists of a `usize` tracking its current
+/// length and zero or more elements of type `A`. The capacity is thus
+/// `( size_of::<T>() - size_of::<usize>() ) / size_of::<A>()`. This could lead
+/// to situations where the capacity is zero, if `size_of::<A>()` is greater
+/// than `size_of::<T>() - size_of::<usize>()`, which is not an error and
+/// handled properly by the data structure.
+///
+/// If `size_of::<T>()` is less than `size_of::<usize>()`, meaning the vector
+/// has no space to store its length, `InlineArray::new()` will panic.
+///
+/// This is meant to facilitate optimisations where a list data structure
+/// allocates a fairly large struct for itself, allowing you to replace it with
+/// an `InlineArray` until it grows beyond its capacity. This not only gives you
+/// a performance boost at very small sizes, it also saves you from having to
+/// allocate anything on the heap until absolutely necessary.
+///
+/// For instance, `im::Vector<A>` in its final form currently looks like this
+/// (approximately):
+///
+/// ```rust, ignore
+/// struct RRB<A> {
+/// length: usize,
+/// tree_height: usize,
+/// outer_head: Rc<Chunk<A>>,
+/// inner_head: Rc<Chunk<A>>,
+/// tree: Rc<TreeNode<A>>,
+/// inner_tail: Rc<Chunk<A>>,
+/// outer_tail: Rc<Chunk<A>>,
+/// }
+/// ```
+///
+/// That's two `usize`s and five `Rc`s, which comes in at 56 bytes on x86_64
+/// architectures. With `InlineArray`, that leaves us with 56 -
+/// `size_of::<usize>()` = 48 bytes we can use before having to expand into the
+/// full data struture. If `A` is `u8`, that's 48 elements, and even if `A` is a
+/// pointer we can still keep 6 of them inline before we run out of capacity.
+///
+/// We can declare an enum like this:
+///
+/// ```rust, ignore
+/// enum VectorWrapper<A> {
+/// Inline(InlineArray<A, RRB<A>>),
+/// Full(RRB<A>),
+/// }
+/// ```
+///
+/// Both of these will have the same size, and we can swap the `Inline` case out
+/// with the `Full` case once the `InlineArray` runs out of capacity.
+#[repr(C)]
+pub struct InlineArray<A, T> {
+ // Alignment tricks
+ //
+ // We need both the `_header_align` and `data` to be properly aligned in memory. We do a few tricks
+ // to handle that.
+ //
+ // * An alignment is always power of 2. Therefore, with a pair of alignments, one is always
+ // a multiple of the other (one way or the other).
+ // * A struct is aligned to at least the max alignment of each of its fields.
+ // * A `repr(C)` struct follows the order of fields and pushes each as close to the previous one
+ // as allowed by alignment.
+ //
+ // By placing two "fake" fields that have 0 size, but an alignment first, we make sure that all
+ // 3 start at the beginning of the struct and that all of them are aligned to their maximum
+ // alignment.
+ //
+ // Unfortunately, we can't use `[A; 0]` to align to actual alignment of the type `A`, because
+ // it prevents use of `InlineArray` in recursive types.
+ // We rely on alignment of `u64`/`usize` or `T` to be sufficient, and panic otherwise. We use
+ // `u64` to handle all common types on 32-bit systems too.
+ //
+ // Furthermore, because we don't know if `u64` or `A` has bigger alignment, we decide on case by
+ // case basis if the header or the elements go first. By placing the one with higher alignment
+ // requirements first, we align that one and the other one will be aligned "automatically" when
+ // placed just after it.
+ //
+ // To the best of our knowledge, this is all guaranteed by the compiler. But just to make sure,
+ // we have bunch of asserts in the constructor to check; as these are invariants enforced by
+ // the compiler, it should be trivial for it to remove the checks so they are for free (if we
+ // are correct) or will save us (if we are not).
+ _header_align: [(u64, usize); 0],
+ _phantom: PhantomData<A>,
+ data: MaybeUninit<T>,
+}
+
+const fn capacity(
+ host_size: usize,
+ header_size: usize,
+ element_size: usize,
+ element_align: usize,
+ container_align: usize,
+) -> usize {
+ if element_size == 0 {
+ usize::MAX
+ } else if element_align <= container_align && host_size > header_size {
+ (host_size - header_size) / element_size
+ } else {
+ 0 // larger alignment can't be guaranteed, so it'd be unsafe to store any elements
+ }
+}
+
+impl<A, T> InlineArray<A, T> {
+ const HOST_SIZE: usize = mem::size_of::<T>();
+ const ELEMENT_SIZE: usize = mem::size_of::<A>();
+ const HEADER_SIZE: usize = mem::size_of::<usize>();
+ // Do we place the header before the elements or the other way around?
+ const HEADER_FIRST: bool = mem::align_of::<usize>() >= mem::align_of::<A>();
+ // Note: one of the following is always 0
+ // How many usizes to skip before the first element?
+ const ELEMENT_SKIP: usize = Self::HEADER_FIRST as usize;
+ // How many elements to skip before the header
+ const HEADER_SKIP: usize = Self::CAPACITY * (1 - Self::ELEMENT_SKIP);
+
+ /// The maximum number of elements the `InlineArray` can hold.
+ pub const CAPACITY: usize = capacity(
+ Self::HOST_SIZE,
+ Self::HEADER_SIZE,
+ Self::ELEMENT_SIZE,
+ mem::align_of::<A>(),
+ mem::align_of::<Self>(),
+ );
+
+ #[inline]
+ #[must_use]
+ unsafe fn len_const(&self) -> *const usize {
+ let ptr = self
+ .data
+ .as_ptr()
+ .cast::<A>()
+ .add(Self::HEADER_SKIP)
+ .cast::<usize>();
+ debug_assert!(ptr as usize % mem::align_of::<usize>() == 0);
+ ptr
+ }
+
+ #[inline]
+ #[must_use]
+ pub(crate) unsafe fn len_mut(&mut self) -> *mut usize {
+ let ptr = self
+ .data
+ .as_mut_ptr()
+ .cast::<A>()
+ .add(Self::HEADER_SKIP)
+ .cast::<usize>();
+ debug_assert!(ptr as usize % mem::align_of::<usize>() == 0);
+ ptr
+ }
+
+ #[inline]
+ #[must_use]
+ pub(crate) unsafe fn data(&self) -> *const A {
+ if Self::CAPACITY == 0 {
+ return NonNull::<A>::dangling().as_ptr();
+ }
+ let ptr = self
+ .data
+ .as_ptr()
+ .cast::<usize>()
+ .add(Self::ELEMENT_SKIP)
+ .cast::<A>();
+ debug_assert!(ptr as usize % mem::align_of::<A>() == 0);
+ ptr
+ }
+
+ #[inline]
+ #[must_use]
+ unsafe fn data_mut(&mut self) -> *mut A {
+ if Self::CAPACITY == 0 {
+ return NonNull::<A>::dangling().as_ptr();
+ }
+ let ptr = self
+ .data
+ .as_mut_ptr()
+ .cast::<usize>()
+ .add(Self::ELEMENT_SKIP)
+ .cast::<A>();
+ debug_assert!(ptr as usize % mem::align_of::<A>() == 0);
+ ptr
+ }
+
+ #[inline]
+ #[must_use]
+ unsafe fn ptr_at(&self, index: usize) -> *const A {
+ debug_assert!(index < Self::CAPACITY);
+ self.data().add(index)
+ }
+
+ #[inline]
+ #[must_use]
+ unsafe fn ptr_at_mut(&mut self, index: usize) -> *mut A {
+ debug_assert!(index < Self::CAPACITY);
+ self.data_mut().add(index)
+ }
+
+ #[inline]
+ unsafe fn read_at(&self, index: usize) -> A {
+ ptr::read(self.ptr_at(index))
+ }
+
+ #[inline]
+ unsafe fn write_at(&mut self, index: usize, value: A) {
+ ptr::write(self.ptr_at_mut(index), value);
+ }
+
+ /// Get the length of the array.
+ #[inline]
+ #[must_use]
+ pub fn len(&self) -> usize {
+ unsafe { *self.len_const() }
+ }
+
+ /// Test if the array is empty.
+ #[inline]
+ #[must_use]
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ /// Test if the array is at capacity.
+ #[inline]
+ #[must_use]
+ pub fn is_full(&self) -> bool {
+ self.len() >= Self::CAPACITY
+ }
+
+ /// Construct a new empty array.
+ ///
+ /// # Panics
+ ///
+ /// If the element type requires large alignment, which is larger than
+ /// both alignment of `usize` and alignment of the type that provides the capacity.
+ #[inline]
+ #[must_use]
+ pub fn new() -> Self {
+ assert!(Self::HOST_SIZE > Self::HEADER_SIZE);
+ assert!(
+ (Self::CAPACITY == 0) || (mem::align_of::<Self>() % mem::align_of::<A>() == 0),
+ "InlineArray can't satisfy alignment of {}",
+ core::any::type_name::<A>()
+ );
+
+ let mut self_ = Self {
+ _header_align: [],
+ _phantom: PhantomData,
+ data: MaybeUninit::uninit(),
+ };
+ // Sanity check our assumptions about what is guaranteed by the compiler. If we are right,
+ // these should completely optimize out of the resulting binary.
+ assert_eq!(
+ &self_ as *const _ as usize,
+ self_.data.as_ptr() as usize,
+ "Padding at the start of struct",
+ );
+ assert_eq!(
+ self_.data.as_ptr() as usize % mem::align_of::<usize>(),
+ 0,
+ "Unaligned header"
+ );
+ assert!(mem::size_of::<Self>() == mem::size_of::<T>() || mem::align_of::<T>() < mem::align_of::<Self>());
+ assert_eq!(0, unsafe { self_.data() } as usize % mem::align_of::<A>());
+ assert_eq!(0, unsafe { self_.data_mut() } as usize % mem::align_of::<A>());
+ assert!(Self::ELEMENT_SKIP == 0 || Self::HEADER_SKIP == 0);
+ unsafe { ptr::write(self_.len_mut(), 0usize) };
+ self_
+ }
+
+ /// Push an item to the back of the array.
+ ///
+ /// Panics if the capacity of the array is exceeded.
+ ///
+ /// Time: O(1)
+ pub fn push(&mut self, value: A) {
+ if self.is_full() {
+ panic!("InlineArray::push: chunk size overflow");
+ }
+ unsafe {
+ self.write_at(self.len(), value);
+ *self.len_mut() += 1;
+ }
+ }
+
+ /// Pop an item from the back of the array.
+ ///
+ /// Returns `None` if the array is empty.
+ ///
+ /// Time: O(1)
+ pub fn pop(&mut self) -> Option<A> {
+ if self.is_empty() {
+ None
+ } else {
+ unsafe {
+ *self.len_mut() -= 1;
+ }
+ Some(unsafe { self.read_at(self.len()) })
+ }
+ }
+
+ /// Insert a new value at index `index`, shifting all the following values
+ /// to the right.
+ ///
+ /// Panics if the index is out of bounds or the array is at capacity.
+ ///
+ /// Time: O(n) for the number of items shifted
+ pub fn insert(&mut self, index: usize, value: A) {
+ if self.is_full() {
+ panic!("InlineArray::push: chunk size overflow");
+ }
+ if index > self.len() {
+ panic!("InlineArray::insert: index out of bounds");
+ }
+ unsafe {
+ let src = self.ptr_at_mut(index);
+ ptr::copy(src, src.add(1), self.len() - index);
+ ptr::write(src, value);
+ *self.len_mut() += 1;
+ }
+ }
+
+ /// Remove the value at index `index`, shifting all the following values to
+ /// the left.
+ ///
+ /// Returns the removed value, or `None` if the array is empty or the index
+ /// is out of bounds.
+ ///
+ /// Time: O(n) for the number of items shifted
+ pub fn remove(&mut self, index: usize) -> Option<A> {
+ if index >= self.len() {
+ None
+ } else {
+ unsafe {
+ let src = self.ptr_at_mut(index);
+ let value = ptr::read(src);
+ *self.len_mut() -= 1;
+ ptr::copy(src.add(1), src, self.len() - index);
+ Some(value)
+ }
+ }
+ }
+
+ /// Split an array into two, the original array containing
+ /// everything up to `index` and the returned array containing
+ /// everything from `index` onwards.
+ ///
+ /// Panics if `index` is out of bounds.
+ ///
+ /// Time: O(n) for the number of items in the new chunk
+ pub fn split_off(&mut self, index: usize) -> Self {
+ if index > self.len() {
+ panic!("InlineArray::split_off: index out of bounds");
+ }
+ let mut out = Self::new();
+ if index < self.len() {
+ unsafe {
+ ptr::copy(self.ptr_at(index), out.data_mut(), self.len() - index);
+ *out.len_mut() = self.len() - index;
+ *self.len_mut() = index;
+ }
+ }
+ out
+ }
+
+ #[inline]
+ unsafe fn drop_contents(&mut self) {
+ ptr::drop_in_place::<[A]>(&mut **self) // uses DerefMut
+ }
+
+ /// Discard the contents of the array.
+ ///
+ /// Time: O(n)
+ pub fn clear(&mut self) {
+ unsafe {
+ self.drop_contents();
+ *self.len_mut() = 0;
+ }
+ }
+
+ /// Construct an iterator that drains values from the front of the array.
+ pub fn drain(&mut self) -> Drain<'_, A, T> {
+ Drain { array: self }
+ }
+}
+
+impl<A, T> Drop for InlineArray<A, T> {
+ fn drop(&mut self) {
+ unsafe { self.drop_contents() }
+ }
+}
+
+impl<A, T> Default for InlineArray<A, T> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+// WANT:
+// impl<A, T> Copy for InlineArray<A, T> where A: Copy {}
+
+impl<A, T> Clone for InlineArray<A, T>
+where
+ A: Clone,
+{
+ fn clone(&self) -> Self {
+ let mut copy = Self::new();
+ for i in 0..self.len() {
+ unsafe {
+ copy.write_at(i, self.get_unchecked(i).clone());
+ }
+ }
+ unsafe {
+ *copy.len_mut() = self.len();
+ }
+ copy
+ }
+}
+
+impl<A, T> Deref for InlineArray<A, T> {
+ type Target = [A];
+ fn deref(&self) -> &Self::Target {
+ unsafe { from_raw_parts(self.data(), self.len()) }
+ }
+}
+
+impl<A, T> DerefMut for InlineArray<A, T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ unsafe { from_raw_parts_mut(self.data_mut(), self.len()) }
+ }
+}
+
+impl<A, T> Borrow<[A]> for InlineArray<A, T> {
+ fn borrow(&self) -> &[A] {
+ self.deref()
+ }
+}
+
+impl<A, T> BorrowMut<[A]> for InlineArray<A, T> {
+ fn borrow_mut(&mut self) -> &mut [A] {
+ self.deref_mut()
+ }
+}
+
+impl<A, T> AsRef<[A]> for InlineArray<A, T> {
+ fn as_ref(&self) -> &[A] {
+ self.deref()
+ }
+}
+
+impl<A, T> AsMut<[A]> for InlineArray<A, T> {
+ fn as_mut(&mut self) -> &mut [A] {
+ self.deref_mut()
+ }
+}
+impl<A, T, Slice> PartialEq<Slice> for InlineArray<A, T>
+where
+ Slice: Borrow<[A]>,
+ A: PartialEq,
+{
+ fn eq(&self, other: &Slice) -> bool {
+ self.deref() == other.borrow()
+ }
+}
+
+impl<A, T> Eq for InlineArray<A, T> where A: Eq {}
+
+impl<A, T> PartialOrd for InlineArray<A, T>
+where
+ A: PartialOrd,
+{
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.iter().partial_cmp(other.iter())
+ }
+}
+
+impl<A, T> Ord for InlineArray<A, T>
+where
+ A: Ord,
+{
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.iter().cmp(other.iter())
+ }
+}
+
+impl<A, T> Debug for InlineArray<A, T>
+where
+ A: Debug,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
+ f.write_str("Chunk")?;
+ f.debug_list().entries(self.iter()).finish()
+ }
+}
+
+impl<A, T> Hash for InlineArray<A, T>
+where
+ A: Hash,
+{
+ fn hash<H>(&self, hasher: &mut H)
+ where
+ H: Hasher,
+ {
+ for item in self {
+ item.hash(hasher)
+ }
+ }
+}
+
+impl<A, T> IntoIterator for InlineArray<A, T> {
+ type Item = A;
+ type IntoIter = Iter<A, T>;
+ fn into_iter(self) -> Self::IntoIter {
+ Iter { array: self }
+ }
+}
+
+impl<A, T> FromIterator<A> for InlineArray<A, T> {
+ fn from_iter<I>(it: I) -> Self
+ where
+ I: IntoIterator<Item = A>,
+ {
+ let mut chunk = Self::new();
+ for item in it {
+ chunk.push(item);
+ }
+ chunk
+ }
+}
+
+impl<'a, A, T> IntoIterator for &'a InlineArray<A, T> {
+ type Item = &'a A;
+ type IntoIter = SliceIter<'a, A>;
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a, A, T> IntoIterator for &'a mut InlineArray<A, T> {
+ type Item = &'a mut A;
+ type IntoIter = SliceIterMut<'a, A>;
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+impl<A, T> Extend<A> for InlineArray<A, T> {
+ /// Append the contents of the iterator to the back of the array.
+ ///
+ /// Panics if the array exceeds its capacity.
+ ///
+ /// Time: O(n) for the length of the iterator
+ fn extend<I>(&mut self, it: I)
+ where
+ I: IntoIterator<Item = A>,
+ {
+ for item in it {
+ self.push(item);
+ }
+ }
+}
+
+impl<'a, A, T> Extend<&'a A> for InlineArray<A, T>
+where
+ A: 'a + Copy,
+{
+ /// Append the contents of the iterator to the back of the array.
+ ///
+ /// Panics if the array exceeds its capacity.
+ ///
+ /// Time: O(n) for the length of the iterator
+ fn extend<I>(&mut self, it: I)
+ where
+ I: IntoIterator<Item = &'a A>,
+ {
+ for item in it {
+ self.push(*item);
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::tests::DropTest;
+ use std::sync::atomic::{AtomicUsize, Ordering};
+
+ #[test]
+ fn dropping() {
+ let counter = AtomicUsize::new(0);
+ {
+ let mut chunk: InlineArray<DropTest<'_>, [usize; 32]> = InlineArray::new();
+ for _i in 0..16 {
+ chunk.push(DropTest::new(&counter));
+ }
+ assert_eq!(16, counter.load(Ordering::Relaxed));
+ for _i in 0..8 {
+ chunk.pop();
+ }
+ assert_eq!(8, counter.load(Ordering::Relaxed));
+ }
+ assert_eq!(0, counter.load(Ordering::Relaxed));
+ }
+
+ #[test]
+ fn zero_sized_values() {
+ let mut chunk: InlineArray<(), [usize; 32]> = InlineArray::new();
+ for _i in 0..65536 {
+ chunk.push(());
+ }
+ assert_eq!(65536, chunk.len());
+ assert_eq!(Some(()), chunk.pop());
+ }
+
+ #[test]
+ fn low_align_base() {
+ let mut chunk: InlineArray<String, [u8; 512]> = InlineArray::new();
+ chunk.push("Hello".to_owned());
+ assert_eq!(chunk[0], "Hello");
+
+ let mut chunk: InlineArray<String, [u16; 512]> = InlineArray::new();
+ chunk.push("Hello".to_owned());
+ assert_eq!(chunk[0], "Hello");
+ }
+
+ #[test]
+ fn float_align() {
+ let mut chunk: InlineArray<f64, [u8; 16]> = InlineArray::new();
+ chunk.push(1234.);
+ assert_eq!(chunk[0], 1234.);
+
+ let mut chunk: InlineArray<f64, [u8; 17]> = InlineArray::new();
+ chunk.push(1234.);
+ assert_eq!(chunk[0], 1234.);
+ }
+
+ #[test]
+ fn recursive_types_compile() {
+ #[allow(dead_code)]
+ enum Recursive {
+ A(InlineArray<Recursive, u64>),
+ B,
+ }
+ }
+
+ #[test]
+ fn insufficient_alignment1() {
+ #[repr(align(256))]
+ struct BigAlign(u8);
+ #[repr(align(32))]
+ struct MediumAlign(u8);
+
+ assert_eq!(0, InlineArray::<BigAlign, [usize; 256]>::CAPACITY);
+ assert_eq!(0, InlineArray::<BigAlign, [u64; 256]>::CAPACITY);
+ assert_eq!(0, InlineArray::<BigAlign, [f64; 256]>::CAPACITY);
+ assert_eq!(0, InlineArray::<BigAlign, [MediumAlign; 256]>::CAPACITY);
+ }
+
+ #[test]
+ fn insufficient_alignment2() {
+ #[repr(align(256))]
+ struct BigAlign(usize);
+
+ let mut bad: InlineArray<BigAlign, [usize; 256]> = InlineArray::new();
+ assert_eq!(0, InlineArray::<BigAlign, [usize; 256]>::CAPACITY);
+ assert_eq!(0, bad.len());
+ assert_eq!(0, bad[..].len());
+ assert_eq!(true, bad.is_full());
+ assert_eq!(0, bad.drain().count());
+ assert!(bad.pop().is_none());
+ assert!(bad.remove(0).is_none());
+ assert!(bad.split_off(0).is_full());
+ bad.clear();
+ }
+
+ #[test]
+ fn sufficient_alignment1() {
+ #[repr(align(256))]
+ struct BigAlign(u8);
+
+ assert_eq!(13, InlineArray::<BigAlign, [BigAlign; 14]>::CAPACITY);
+ assert_eq!(1, InlineArray::<BigAlign, [BigAlign; 2]>::CAPACITY);
+ assert_eq!(0, InlineArray::<BigAlign, [BigAlign; 1]>::CAPACITY);
+
+ let mut chunk: InlineArray<BigAlign, [BigAlign; 2]> = InlineArray::new();
+ chunk.push(BigAlign(42));
+ assert_eq!(
+ chunk.get(0).unwrap() as *const _ as usize % mem::align_of::<BigAlign>(),
+ 0
+ );
+ }
+
+ #[test]
+ fn sufficient_alignment2() {
+ #[repr(align(128))]
+ struct BigAlign([u8; 64]);
+ #[repr(align(256))]
+ struct BiggerAlign(u8);
+ assert_eq!(128, mem::align_of::<BigAlign>());
+ assert_eq!(256, mem::align_of::<BiggerAlign>());
+
+ assert_eq!(199, InlineArray::<BigAlign, [BiggerAlign; 100]>::CAPACITY);
+ assert_eq!(3, InlineArray::<BigAlign, [BiggerAlign; 2]>::CAPACITY);
+ assert_eq!(1, InlineArray::<BigAlign, [BiggerAlign; 1]>::CAPACITY);
+ assert_eq!(0, InlineArray::<BigAlign, [BiggerAlign; 0]>::CAPACITY);
+
+ let mut chunk: InlineArray<BigAlign, [BiggerAlign; 1]> = InlineArray::new();
+ chunk.push(BigAlign([0; 64]));
+ assert_eq!(
+ chunk.get(0).unwrap() as *const _ as usize % mem::align_of::<BigAlign>(),
+ 0
+ );
+ }
+}
diff --git a/vendor/sized-chunks/src/lib.rs b/vendor/sized-chunks/src/lib.rs
new file mode 100644
index 0000000..c011bea
--- /dev/null
+++ b/vendor/sized-chunks/src/lib.rs
@@ -0,0 +1,126 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+//! # Sized Chunks
+//!
+//! This crate contains three fixed size low level array like data structures,
+//! primarily intended for use in [immutable.rs], but fully supported as a
+//! standalone crate.
+//!
+//! Their sizing information is encoded in the type using the
+//! [`typenum`][typenum] crate, which you may want to take a look at before
+//! reading on, but usually all you need to know about it is that it provides
+//! types `U1` to `U128` to represent numbers, which the data types take as type
+//! parameters, eg. `SparseChunk<A, U32>` would give you a sparse array with
+//! room for 32 elements of type `A`. You can also omit the size, as they all
+//! default to a size of 64, so `SparseChunk<A>` would be a sparse array with a
+//! capacity of 64.
+//!
+//! All data structures always allocate the same amount of space, as determined
+//! by their capacity, regardless of how many elements they contain, and when
+//! they run out of space, they will panic.
+//!
+//! ## Data Structures
+//!
+//! | Type | Description | Push | Pop | Deref to `&[A]` |
+//! | ---- | ----------- | ---- | --- | --------------- |
+//! | [`Chunk`][Chunk] | Contiguous array | O(1)/O(n) | O(1) | Yes |
+//! | [`RingBuffer`][RingBuffer] | Non-contiguous array | O(1) | O(1) | No |
+//! | [`SparseChunk`][SparseChunk] | Sparse array | N/A | N/A | No |
+//!
+//! The [`Chunk`][Chunk] and [`RingBuffer`][RingBuffer] are very similar in
+//! practice, in that they both work like a plain array, except that you can
+//! push to either end with some expectation of performance. The difference is
+//! that [`RingBuffer`][RingBuffer] always allows you to do this in constant
+//! time, but in order to give that guarantee, it doesn't lay out its elements
+//! contiguously in memory, which means that you can't dereference it to a slice
+//! `&[A]`.
+//!
+//! [`Chunk`][Chunk], on the other hand, will shift its contents around when
+//! necessary to accommodate a push to a full side, but is able to guarantee a
+//! contiguous memory layout in this way, so it can always be dereferenced into
+//! a slice. Performance wise, repeated pushes to the same side will always run
+//! in constant time, but a push to one side followed by a push to the other
+//! side will cause the latter to run in linear time if there's no room (which
+//! there would only be if you've popped from that side).
+//!
+//! To choose between them, you can use the following rules:
+//! - I only ever want to push to the back: you don't need this crate, try
+//! [`ArrayVec`][ArrayVec].
+//! - I need to push to either side but probably not both on the same array: use
+//! [`Chunk`][Chunk].
+//! - I need to push to both sides and I don't need slices: use
+//! [`RingBuffer`][RingBuffer].
+//! - I need to push to both sides but I do need slices: use [`Chunk`][Chunk].
+//!
+//! Finally, [`SparseChunk`][SparseChunk] is a more efficient version of
+//! `Vec<Option<A>>`: each index is either inhabited or not, but instead of
+//! using the `Option` discriminant to decide which is which, it uses a compact
+//! bitmap. You can also think of `SparseChunk<A, N>` as a `BTreeMap<usize, A>`
+//! where the `usize` must be less than `N`, but without the performance
+//! overhead. Its API is also more consistent with a map than an array - there's
+//! no push, pop, append, etc, just insert, remove and lookup.
+//!
+//! # [`InlineArray`][InlineArray]
+//!
+//! Finally, there's [`InlineArray`][InlineArray], which is a simple vector that's
+//! sized to fit inside any `Sized` type that's big enough to hold a size counter
+//! and at least one instance of the array element type. This can be a useful
+//! optimisation when implementing a list like data structure with a nontrivial
+//! set of pointers in its full form, where you could plausibly fit several
+//! elements inside the space allocated for the pointers. `im::Vector` is a
+//! good example of that, and the use case for which [`InlineArray`][InlineArray]
+//! was implemented.
+//!
+//! # Feature Flags
+//!
+//! The following feature flags are available:
+//!
+//! | Feature | Description |
+//! | ------- | ----------- |
+//! | `arbitrary` | Provides [`Arbitrary`][Arbitrary] implementations from the [`arbitrary`][arbitrary_crate] crate. Requires the `std` flag. |
+//! | `refpool` | Provides [`PoolDefault`][PoolDefault] and [`PoolClone`][PoolClone] implemetations from the [`refpool`][refpool] crate. |
+//! | `ringbuffer` | Enables the [`RingBuffer`][RingBuffer] data structure. |
+//! | `std` | Without this flag (enabled by default), the crate will be `no_std`, and absent traits relating to `std::collections` and `std::io`. |
+//!
+//! [immutable.rs]: https://immutable.rs/
+//! [typenum]: https://docs.rs/typenum/
+//! [Chunk]: struct.Chunk.html
+//! [RingBuffer]: struct.RingBuffer.html
+//! [SparseChunk]: struct.SparseChunk.html
+//! [InlineArray]: struct.InlineArray.html
+//! [ArrayVec]: https://docs.rs/arrayvec/
+//! [Arbitrary]: https://docs.rs/arbitrary/latest/arbitrary/trait.Arbitrary.html
+//! [arbitrary_crate]: https://docs.rs/arbitrary
+//! [refpool]: https://docs.rs/refpool
+//! [PoolDefault]: https://docs.rs/refpool/latest/refpool/trait.PoolDefault.html
+//! [PoolClone]: https://docs.rs/refpool/latest/refpool/trait.PoolClone.html
+
+#![forbid(rust_2018_idioms)]
+#![deny(nonstandard_style)]
+#![warn(unreachable_pub, missing_docs)]
+#![cfg_attr(test, deny(warnings))]
+#![cfg_attr(not(any(feature = "std", test)), no_std)]
+// Jeremy Francis Corbyn, clippy devs need to calm down 🤦‍♀️
+#![allow(clippy::suspicious_op_assign_impl, clippy::suspicious_arithmetic_impl)]
+
+pub mod inline_array;
+pub mod sized_chunk;
+pub mod sparse_chunk;
+pub mod types;
+
+#[cfg(test)]
+mod tests;
+
+#[cfg(feature = "arbitrary")]
+mod arbitrary;
+
+pub use crate::inline_array::InlineArray;
+pub use crate::sized_chunk::Chunk;
+pub use crate::sparse_chunk::SparseChunk;
+
+#[cfg(feature = "ringbuffer")]
+pub mod ring_buffer;
+#[cfg(feature = "ringbuffer")]
+pub use crate::ring_buffer::RingBuffer;
diff --git a/vendor/sized-chunks/src/ring_buffer/index.rs b/vendor/sized-chunks/src/ring_buffer/index.rs
new file mode 100644
index 0000000..78009a2
--- /dev/null
+++ b/vendor/sized-chunks/src/ring_buffer/index.rs
@@ -0,0 +1,178 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+use core::iter::FusedIterator;
+use core::marker::PhantomData;
+use core::ops::{Add, AddAssign, Sub, SubAssign};
+
+use typenum::Unsigned;
+
+pub(crate) struct RawIndex<N: Unsigned>(usize, PhantomData<N>);
+
+impl<N: Unsigned> Clone for RawIndex<N> {
+ #[inline]
+ #[must_use]
+ fn clone(&self) -> Self {
+ self.0.into()
+ }
+}
+
+impl<N> Copy for RawIndex<N> where N: Unsigned {}
+
+impl<N: Unsigned> RawIndex<N> {
+ #[inline]
+ #[must_use]
+ pub(crate) fn to_usize(self) -> usize {
+ self.0
+ }
+
+ /// Increments the index and returns a copy of the index /before/ incrementing.
+ #[inline]
+ #[must_use]
+ pub(crate) fn inc(&mut self) -> Self {
+ let old = *self;
+ self.0 = if self.0 == N::USIZE - 1 {
+ 0
+ } else {
+ self.0 + 1
+ };
+ old
+ }
+
+ /// Decrements the index and returns a copy of the new value.
+ #[inline]
+ #[must_use]
+ pub(crate) fn dec(&mut self) -> Self {
+ self.0 = if self.0 == 0 {
+ N::USIZE - 1
+ } else {
+ self.0 - 1
+ };
+ *self
+ }
+}
+
+impl<N: Unsigned> From<usize> for RawIndex<N> {
+ #[inline]
+ #[must_use]
+ fn from(index: usize) -> Self {
+ debug_assert!(index < N::USIZE);
+ RawIndex(index, PhantomData)
+ }
+}
+
+impl<N: Unsigned> PartialEq for RawIndex<N> {
+ #[inline]
+ #[must_use]
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+}
+
+impl<N: Unsigned> Eq for RawIndex<N> {}
+
+impl<N: Unsigned> Add for RawIndex<N> {
+ type Output = RawIndex<N>;
+ #[inline]
+ #[must_use]
+ fn add(self, other: Self) -> Self::Output {
+ self + other.0
+ }
+}
+
+impl<N: Unsigned> Add<usize> for RawIndex<N> {
+ type Output = RawIndex<N>;
+ #[inline]
+ #[must_use]
+ fn add(self, other: usize) -> Self::Output {
+ let mut result = self.0 + other;
+ while result >= N::USIZE {
+ result -= N::USIZE;
+ }
+ result.into()
+ }
+}
+
+impl<N: Unsigned> AddAssign<usize> for RawIndex<N> {
+ #[inline]
+ fn add_assign(&mut self, other: usize) {
+ self.0 += other;
+ while self.0 >= N::USIZE {
+ self.0 -= N::USIZE;
+ }
+ }
+}
+
+impl<N: Unsigned> Sub for RawIndex<N> {
+ type Output = RawIndex<N>;
+ #[inline]
+ #[must_use]
+ fn sub(self, other: Self) -> Self::Output {
+ self - other.0
+ }
+}
+
+impl<N: Unsigned> Sub<usize> for RawIndex<N> {
+ type Output = RawIndex<N>;
+ #[inline]
+ #[must_use]
+ fn sub(self, other: usize) -> Self::Output {
+ let mut start = self.0;
+ while other > start {
+ start += N::USIZE;
+ }
+ (start - other).into()
+ }
+}
+
+impl<N: Unsigned> SubAssign<usize> for RawIndex<N> {
+ #[inline]
+ fn sub_assign(&mut self, other: usize) {
+ while other > self.0 {
+ self.0 += N::USIZE;
+ }
+ self.0 -= other;
+ }
+}
+
+pub(crate) struct IndexIter<N: Unsigned> {
+ pub(crate) remaining: usize,
+ pub(crate) left_index: RawIndex<N>,
+ pub(crate) right_index: RawIndex<N>,
+}
+
+impl<N: Unsigned> Iterator for IndexIter<N> {
+ type Item = RawIndex<N>;
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.remaining > 0 {
+ self.remaining -= 1;
+ Some(self.left_index.inc())
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ #[must_use]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.remaining, Some(self.remaining))
+ }
+}
+
+impl<N: Unsigned> DoubleEndedIterator for IndexIter<N> {
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.remaining > 0 {
+ self.remaining -= 1;
+ Some(self.right_index.dec())
+ } else {
+ None
+ }
+ }
+}
+
+impl<N: Unsigned> ExactSizeIterator for IndexIter<N> {}
+
+impl<N: Unsigned> FusedIterator for IndexIter<N> {}
diff --git a/vendor/sized-chunks/src/ring_buffer/iter.rs b/vendor/sized-chunks/src/ring_buffer/iter.rs
new file mode 100644
index 0000000..aa8d06b
--- /dev/null
+++ b/vendor/sized-chunks/src/ring_buffer/iter.rs
@@ -0,0 +1,218 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+use core::iter::FusedIterator;
+use core::marker::PhantomData;
+
+use crate::types::ChunkLength;
+
+use super::{index::RawIndex, RingBuffer};
+use array_ops::HasLength;
+
+/// A reference iterator over a `RingBuffer`.
+pub struct Iter<'a, A, N>
+where
+ N: ChunkLength<A>,
+{
+ pub(crate) buffer: &'a RingBuffer<A, N>,
+ pub(crate) left_index: RawIndex<N>,
+ pub(crate) right_index: RawIndex<N>,
+ pub(crate) remaining: usize,
+}
+
+impl<'a, A, N> Iterator for Iter<'a, A, N>
+where
+ N: ChunkLength<A>,
+{
+ type Item = &'a A;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.remaining == 0 {
+ None
+ } else {
+ self.remaining -= 1;
+ Some(unsafe { &*self.buffer.ptr(self.left_index.inc()) })
+ }
+ }
+
+ #[inline]
+ #[must_use]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.remaining, Some(self.remaining))
+ }
+}
+
+impl<'a, A, N> DoubleEndedIterator for Iter<'a, A, N>
+where
+ N: ChunkLength<A>,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.remaining == 0 {
+ None
+ } else {
+ self.remaining -= 1;
+ Some(unsafe { &*self.buffer.ptr(self.right_index.dec()) })
+ }
+ }
+}
+
+impl<'a, A, N> ExactSizeIterator for Iter<'a, A, N> where N: ChunkLength<A> {}
+
+impl<'a, A, N> FusedIterator for Iter<'a, A, N> where N: ChunkLength<A> {}
+
+/// A mutable reference iterator over a `RingBuffer`.
+pub struct IterMut<'a, A, N>
+where
+ N: ChunkLength<A>,
+{
+ data: *mut A,
+ left_index: RawIndex<N>,
+ right_index: RawIndex<N>,
+ remaining: usize,
+ phantom: PhantomData<&'a ()>,
+}
+
+impl<'a, A, N> IterMut<'a, A, N>
+where
+ N: ChunkLength<A>,
+ A: 'a,
+{
+ pub(crate) fn new(buffer: &mut RingBuffer<A, N>) -> Self {
+ Self::new_slice(buffer, buffer.origin, buffer.len())
+ }
+
+ pub(crate) fn new_slice(
+ buffer: &mut RingBuffer<A, N>,
+ origin: RawIndex<N>,
+ len: usize,
+ ) -> Self {
+ Self {
+ left_index: origin,
+ right_index: origin + len,
+ remaining: len,
+ phantom: PhantomData,
+ data: buffer.data.as_mut_ptr().cast(),
+ }
+ }
+
+ unsafe fn mut_ptr(&mut self, index: RawIndex<N>) -> *mut A {
+ self.data.add(index.to_usize())
+ }
+}
+
+impl<'a, A, N> Iterator for IterMut<'a, A, N>
+where
+ N: ChunkLength<A>,
+ A: 'a,
+{
+ type Item = &'a mut A;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.remaining == 0 {
+ None
+ } else {
+ self.remaining -= 1;
+ let index = self.left_index.inc();
+ Some(unsafe { &mut *self.mut_ptr(index) })
+ }
+ }
+
+ #[inline]
+ #[must_use]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.remaining, Some(self.remaining))
+ }
+}
+
+impl<'a, A, N> DoubleEndedIterator for IterMut<'a, A, N>
+where
+ N: ChunkLength<A>,
+ A: 'a,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.remaining == 0 {
+ None
+ } else {
+ self.remaining -= 1;
+ let index = self.right_index.dec();
+ Some(unsafe { &mut *self.mut_ptr(index) })
+ }
+ }
+}
+
+impl<'a, A, N> ExactSizeIterator for IterMut<'a, A, N>
+where
+ N: ChunkLength<A>,
+ A: 'a,
+{
+}
+
+impl<'a, A, N> FusedIterator for IterMut<'a, A, N>
+where
+ N: ChunkLength<A>,
+ A: 'a,
+{
+}
+
+/// A draining iterator over a `RingBuffer`.
+pub struct Drain<'a, A, N: ChunkLength<A>> {
+ pub(crate) buffer: &'a mut RingBuffer<A, N>,
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> Iterator for Drain<'a, A, N> {
+ type Item = A;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ self.buffer.pop_front()
+ }
+
+ #[inline]
+ #[must_use]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.buffer.len(), Some(self.buffer.len()))
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> DoubleEndedIterator for Drain<'a, A, N> {
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.buffer.pop_back()
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> ExactSizeIterator for Drain<'a, A, N> {}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> FusedIterator for Drain<'a, A, N> {}
+
+/// A consuming iterator over a `RingBuffer`.
+pub struct OwnedIter<A, N: ChunkLength<A>> {
+ pub(crate) buffer: RingBuffer<A, N>,
+}
+
+impl<A, N: ChunkLength<A>> Iterator for OwnedIter<A, N> {
+ type Item = A;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ self.buffer.pop_front()
+ }
+
+ #[inline]
+ #[must_use]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.buffer.len(), Some(self.buffer.len()))
+ }
+}
+
+impl<A, N: ChunkLength<A>> DoubleEndedIterator for OwnedIter<A, N> {
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.buffer.pop_back()
+ }
+}
+
+impl<A, N: ChunkLength<A>> ExactSizeIterator for OwnedIter<A, N> {}
+
+impl<A, N: ChunkLength<A>> FusedIterator for OwnedIter<A, N> {}
diff --git a/vendor/sized-chunks/src/ring_buffer/mod.rs b/vendor/sized-chunks/src/ring_buffer/mod.rs
new file mode 100644
index 0000000..76e0aaa
--- /dev/null
+++ b/vendor/sized-chunks/src/ring_buffer/mod.rs
@@ -0,0 +1,1156 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+//! A fixed capacity ring buffer.
+//!
+//! See [`RingBuffer`](struct.RingBuffer.html)
+
+use core::borrow::Borrow;
+use core::cmp::Ordering;
+use core::fmt::{Debug, Error, Formatter};
+use core::hash::{Hash, Hasher};
+use core::iter::FromIterator;
+use core::mem::{replace, MaybeUninit};
+use core::ops::{Bound, Range, RangeBounds};
+use core::ops::{Index, IndexMut};
+
+use typenum::U64;
+
+pub use array_ops::{Array, ArrayMut, HasLength};
+
+use crate::types::ChunkLength;
+
+mod index;
+use index::{IndexIter, RawIndex};
+
+mod iter;
+pub use iter::{Drain, Iter, IterMut, OwnedIter};
+
+mod slice;
+pub use slice::{Slice, SliceMut};
+
+#[cfg(feature = "refpool")]
+mod refpool;
+
+/// A fixed capacity ring buffer.
+///
+/// A ring buffer is an array where the first logical index is at some arbitrary
+/// location inside the array, and the indices wrap around to the start of the
+/// array once they overflow its bounds.
+///
+/// This gives us the ability to push to either the front or the end of the
+/// array in constant time, at the cost of losing the ability to get a single
+/// contiguous slice reference to the contents.
+///
+/// It differs from the [`Chunk`][Chunk] in that the latter will have mostly
+/// constant time pushes, but may occasionally need to shift its contents around
+/// to make room. They both have constant time pop, and they both have linear
+/// time insert and remove.
+///
+/// The `RingBuffer` offers its own [`Slice`][Slice] and [`SliceMut`][SliceMut]
+/// types to compensate for the loss of being able to take a slice, but they're
+/// somewhat less efficient, so the general rule should be that you shouldn't
+/// choose a `RingBuffer` if you rely heavily on slices - but if you don't,
+/// it's probably a marginally better choice overall than [`Chunk`][Chunk].
+///
+/// # Feature Flag
+///
+/// To use this data structure, you need to enable the `ringbuffer` feature.
+///
+/// [Chunk]: ../sized_chunk/struct.Chunk.html
+/// [Slice]: struct.Slice.html
+/// [SliceMut]: struct.SliceMut.html
+pub struct RingBuffer<A, N = U64>
+where
+ N: ChunkLength<A>,
+{
+ origin: RawIndex<N>,
+ length: usize,
+ data: MaybeUninit<N::SizedType>,
+}
+
+impl<A, N: ChunkLength<A>> Drop for RingBuffer<A, N> {
+ #[inline]
+ fn drop(&mut self) {
+ if core::mem::needs_drop::<A>() {
+ for i in self.range() {
+ unsafe { self.force_drop(i) }
+ }
+ }
+ }
+}
+
+impl<A, N> HasLength for RingBuffer<A, N>
+where
+ N: ChunkLength<A>,
+{
+ /// Get the length of the ring buffer.
+ #[inline]
+ #[must_use]
+ fn len(&self) -> usize {
+ self.length
+ }
+}
+
+impl<A, N> Array for RingBuffer<A, N>
+where
+ N: ChunkLength<A>,
+{
+ /// Get a reference to the value at a given index.
+ #[must_use]
+ fn get(&self, index: usize) -> Option<&A> {
+ if index >= self.len() {
+ None
+ } else {
+ Some(unsafe { self.get_unchecked(index) })
+ }
+ }
+}
+
+impl<A, N> ArrayMut for RingBuffer<A, N>
+where
+ N: ChunkLength<A>,
+{
+ /// Get a mutable reference to the value at a given index.
+ #[must_use]
+ fn get_mut(&mut self, index: usize) -> Option<&mut A> {
+ if index >= self.len() {
+ None
+ } else {
+ Some(unsafe { self.get_unchecked_mut(index) })
+ }
+ }
+}
+
+impl<A, N> RingBuffer<A, N>
+where
+ N: ChunkLength<A>,
+{
+ /// The capacity of this ring buffer, as a `usize`.
+ pub const CAPACITY: usize = N::USIZE;
+
+ /// Get the raw index for a logical index.
+ #[inline]
+ fn raw(&self, index: usize) -> RawIndex<N> {
+ self.origin + index
+ }
+
+ #[inline]
+ unsafe fn ptr(&self, index: RawIndex<N>) -> *const A {
+ debug_assert!(index.to_usize() < Self::CAPACITY);
+ (&self.data as *const _ as *const A).add(index.to_usize())
+ }
+
+ #[inline]
+ unsafe fn mut_ptr(&mut self, index: RawIndex<N>) -> *mut A {
+ debug_assert!(index.to_usize() < Self::CAPACITY);
+ (&mut self.data as *mut _ as *mut A).add(index.to_usize())
+ }
+
+ /// Drop the value at a raw index.
+ #[inline]
+ unsafe fn force_drop(&mut self, index: RawIndex<N>) {
+ core::ptr::drop_in_place(self.mut_ptr(index))
+ }
+
+ /// Copy the value at a raw index, discarding ownership of the copied value
+ #[inline]
+ unsafe fn force_read(&self, index: RawIndex<N>) -> A {
+ core::ptr::read(self.ptr(index))
+ }
+
+ /// Write a value at a raw index without trying to drop what's already there
+ #[inline]
+ unsafe fn force_write(&mut self, index: RawIndex<N>, value: A) {
+ core::ptr::write(self.mut_ptr(index), value)
+ }
+
+ /// Copy a range of raw indices from another buffer.
+ unsafe fn copy_from(
+ &mut self,
+ source: &mut Self,
+ from: RawIndex<N>,
+ to: RawIndex<N>,
+ count: usize,
+ ) {
+ #[inline]
+ unsafe fn force_copy_to<A, N: ChunkLength<A>>(
+ source: &mut RingBuffer<A, N>,
+ from: RawIndex<N>,
+ target: &mut RingBuffer<A, N>,
+ to: RawIndex<N>,
+ count: usize,
+ ) {
+ if count > 0 {
+ debug_assert!(from.to_usize() + count <= RingBuffer::<A, N>::CAPACITY);
+ debug_assert!(to.to_usize() + count <= RingBuffer::<A, N>::CAPACITY);
+ core::ptr::copy_nonoverlapping(source.mut_ptr(from), target.mut_ptr(to), count)
+ }
+ }
+
+ if from.to_usize() + count > Self::CAPACITY {
+ let first_length = Self::CAPACITY - from.to_usize();
+ let last_length = count - first_length;
+ self.copy_from(source, from, to, first_length);
+ self.copy_from(source, 0.into(), to + first_length, last_length);
+ } else if to.to_usize() + count > Self::CAPACITY {
+ let first_length = Self::CAPACITY - to.to_usize();
+ let last_length = count - first_length;
+ force_copy_to(source, from, self, to, first_length);
+ force_copy_to(source, from + first_length, self, 0.into(), last_length);
+ } else {
+ force_copy_to(source, from, self, to, count);
+ }
+ }
+
+ /// Copy values from a slice.
+ #[allow(dead_code)]
+ unsafe fn copy_from_slice(&mut self, source: &[A], to: RawIndex<N>) {
+ let count = source.len();
+ debug_assert!(to.to_usize() + count <= Self::CAPACITY);
+ if to.to_usize() + count > Self::CAPACITY {
+ let first_length = Self::CAPACITY - to.to_usize();
+ let first_slice = &source[..first_length];
+ let last_slice = &source[first_length..];
+ core::ptr::copy_nonoverlapping(
+ first_slice.as_ptr(),
+ self.mut_ptr(to),
+ first_slice.len(),
+ );
+ core::ptr::copy_nonoverlapping(
+ last_slice.as_ptr(),
+ self.mut_ptr(0.into()),
+ last_slice.len(),
+ );
+ } else {
+ core::ptr::copy_nonoverlapping(source.as_ptr(), self.mut_ptr(to), count)
+ }
+ }
+
+ /// Get an iterator over the raw indices of the buffer from left to right.
+ #[inline]
+ fn range(&self) -> IndexIter<N> {
+ IndexIter {
+ remaining: self.len(),
+ left_index: self.origin,
+ right_index: self.origin + self.len(),
+ }
+ }
+
+ /// Construct an empty ring buffer.
+ #[inline]
+ #[must_use]
+ pub fn new() -> Self {
+ Self {
+ origin: 0.into(),
+ length: 0,
+ data: MaybeUninit::uninit(),
+ }
+ }
+
+ /// Construct a ring buffer with a single item.
+ #[inline]
+ #[must_use]
+ pub fn unit(value: A) -> Self {
+ assert!(Self::CAPACITY >= 1);
+ let mut buffer = Self {
+ origin: 0.into(),
+ length: 1,
+ data: MaybeUninit::uninit(),
+ };
+ unsafe {
+ buffer.force_write(0.into(), value);
+ }
+ buffer
+ }
+
+ /// Construct a ring buffer with two items.
+ #[inline]
+ #[must_use]
+ pub fn pair(value1: A, value2: A) -> Self {
+ assert!(Self::CAPACITY >= 2);
+ let mut buffer = Self {
+ origin: 0.into(),
+ length: 2,
+ data: MaybeUninit::uninit(),
+ };
+ unsafe {
+ buffer.force_write(0.into(), value1);
+ buffer.force_write(1.into(), value2);
+ }
+ buffer
+ }
+
+ /// Construct a new ring buffer and move every item from `other` into the
+ /// new buffer.
+ ///
+ /// Time: O(n)
+ #[inline]
+ #[must_use]
+ pub fn drain_from(other: &mut Self) -> Self {
+ Self::from_front(other, other.len())
+ }
+
+ /// Construct a new ring buffer and populate it by taking `count` items from
+ /// the iterator `iter`.
+ ///
+ /// Panics if the iterator contains less than `count` items.
+ ///
+ /// Time: O(n)
+ #[must_use]
+ pub fn collect_from<I>(iter: &mut I, count: usize) -> Self
+ where
+ I: Iterator<Item = A>,
+ {
+ let buffer = Self::from_iter(iter.take(count));
+ if buffer.len() < count {
+ panic!("RingBuffer::collect_from: underfull iterator");
+ }
+ buffer
+ }
+
+ /// Construct a new ring buffer and populate it by taking `count` items from
+ /// the front of `other`.
+ ///
+ /// Time: O(n) for the number of items moved
+ #[must_use]
+ pub fn from_front(other: &mut Self, count: usize) -> Self {
+ let mut buffer = Self::new();
+ buffer.drain_from_front(other, count);
+ buffer
+ }
+
+ /// Construct a new ring buffer and populate it by taking `count` items from
+ /// the back of `other`.
+ ///
+ /// Time: O(n) for the number of items moved
+ #[must_use]
+ pub fn from_back(other: &mut Self, count: usize) -> Self {
+ let mut buffer = Self::new();
+ buffer.drain_from_back(other, count);
+ buffer
+ }
+
+ /// Test if the ring buffer is full.
+ #[inline]
+ #[must_use]
+ pub fn is_full(&self) -> bool {
+ self.len() == Self::CAPACITY
+ }
+
+ /// Get an iterator over references to the items in the ring buffer in
+ /// order.
+ #[inline]
+ #[must_use]
+ pub fn iter(&self) -> Iter<'_, A, N> {
+ Iter {
+ buffer: self,
+ left_index: self.origin,
+ right_index: self.origin + self.len(),
+ remaining: self.len(),
+ }
+ }
+
+ /// Get an iterator over mutable references to the items in the ring buffer
+ /// in order.
+ #[inline]
+ #[must_use]
+ pub fn iter_mut(&mut self) -> IterMut<'_, A, N> {
+ IterMut::new(self)
+ }
+
+ #[must_use]
+ fn parse_range<R: RangeBounds<usize>>(&self, range: R) -> Range<usize> {
+ let new_range = Range {
+ start: match range.start_bound() {
+ Bound::Unbounded => 0,
+ Bound::Included(index) => *index,
+ Bound::Excluded(_) => unimplemented!(),
+ },
+ end: match range.end_bound() {
+ Bound::Unbounded => self.len(),
+ Bound::Included(index) => *index + 1,
+ Bound::Excluded(index) => *index,
+ },
+ };
+ if new_range.end > self.len() || new_range.start > new_range.end {
+ panic!("Slice::parse_range: index out of bounds");
+ }
+ new_range
+ }
+
+ /// Get a `Slice` for a subset of the ring buffer.
+ #[must_use]
+ pub fn slice<R: RangeBounds<usize>>(&self, range: R) -> Slice<'_, A, N> {
+ Slice {
+ buffer: self,
+ range: self.parse_range(range),
+ }
+ }
+
+ /// Get a `SliceMut` for a subset of the ring buffer.
+ #[must_use]
+ pub fn slice_mut<R: RangeBounds<usize>>(&mut self, range: R) -> SliceMut<'_, A, N> {
+ SliceMut {
+ range: self.parse_range(range),
+ buffer: self,
+ }
+ }
+
+ /// Get an unchecked reference to the value at the given index.
+ ///
+ /// # Safety
+ ///
+ /// You must ensure the index is not out of bounds.
+ #[must_use]
+ pub unsafe fn get_unchecked(&self, index: usize) -> &A {
+ &*self.ptr(self.raw(index))
+ }
+
+ /// Get an unchecked mutable reference to the value at the given index.
+ ///
+ /// # Safety
+ ///
+ /// You must ensure the index is not out of bounds.
+ #[must_use]
+ pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut A {
+ &mut *self.mut_ptr(self.raw(index))
+ }
+
+ /// Push a value to the back of the buffer.
+ ///
+ /// Panics if the capacity of the buffer is exceeded.
+ ///
+ /// Time: O(1)
+ pub fn push_back(&mut self, value: A) {
+ if self.is_full() {
+ panic!("RingBuffer::push_back: can't push to a full buffer")
+ } else {
+ unsafe { self.force_write(self.raw(self.length), value) }
+ self.length += 1;
+ }
+ }
+
+ /// Push a value to the front of the buffer.
+ ///
+ /// Panics if the capacity of the buffer is exceeded.
+ ///
+ /// Time: O(1)
+ pub fn push_front(&mut self, value: A) {
+ if self.is_full() {
+ panic!("RingBuffer::push_front: can't push to a full buffer")
+ } else {
+ let origin = self.origin.dec();
+ self.length += 1;
+ unsafe { self.force_write(origin, value) }
+ }
+ }
+
+ /// Pop a value from the back of the buffer.
+ ///
+ /// Returns `None` if the buffer is empty.
+ ///
+ /// Time: O(1)
+ pub fn pop_back(&mut self) -> Option<A> {
+ if self.is_empty() {
+ None
+ } else {
+ self.length -= 1;
+ Some(unsafe { self.force_read(self.raw(self.length)) })
+ }
+ }
+
+ /// Pop a value from the front of the buffer.
+ ///
+ /// Returns `None` if the buffer is empty.
+ ///
+ /// Time: O(1)
+ pub fn pop_front(&mut self) -> Option<A> {
+ if self.is_empty() {
+ None
+ } else {
+ self.length -= 1;
+ let index = self.origin.inc();
+ Some(unsafe { self.force_read(index) })
+ }
+ }
+
+ /// Discard all items up to but not including `index`.
+ ///
+ /// Panics if `index` is out of bounds.
+ ///
+ /// Time: O(n) for the number of items dropped
+ pub fn drop_left(&mut self, index: usize) {
+ if index > 0 {
+ if index > self.len() {
+ panic!("RingBuffer::drop_left: index out of bounds");
+ }
+ for i in self.range().take(index) {
+ unsafe { self.force_drop(i) }
+ }
+ self.origin += index;
+ self.length -= index;
+ }
+ }
+
+ /// Discard all items from `index` onward.
+ ///
+ /// Panics if `index` is out of bounds.
+ ///
+ /// Time: O(n) for the number of items dropped
+ pub fn drop_right(&mut self, index: usize) {
+ if index > self.len() {
+ panic!("RingBuffer::drop_right: index out of bounds");
+ }
+ if index == self.len() {
+ return;
+ }
+ for i in self.range().skip(index) {
+ unsafe { self.force_drop(i) }
+ }
+ self.length = index;
+ }
+
+ /// Split a buffer into two, the original buffer containing
+ /// everything up to `index` and the returned buffer containing
+ /// everything from `index` onwards.
+ ///
+ /// Panics if `index` is out of bounds.
+ ///
+ /// Time: O(n) for the number of items in the new buffer
+ #[must_use]
+ pub fn split_off(&mut self, index: usize) -> Self {
+ if index > self.len() {
+ panic!("RingBuffer::split: index out of bounds");
+ }
+ if index == self.len() {
+ return Self::new();
+ }
+ let mut right = Self::new();
+ let length = self.length - index;
+ unsafe { right.copy_from(self, self.raw(index), 0.into(), length) };
+ self.length = index;
+ right.length = length;
+ right
+ }
+
+ /// Remove all items from `other` and append them to the back of `self`.
+ ///
+ /// Panics if the capacity of `self` is exceeded.
+ ///
+ /// `other` will be an empty buffer after this operation.
+ ///
+ /// Time: O(n) for the number of items moved
+ #[inline]
+ pub fn append(&mut self, other: &mut Self) {
+ self.drain_from_front(other, other.len());
+ }
+
+ /// Remove `count` items from the front of `other` and append them to the
+ /// back of `self`.
+ ///
+ /// Panics if `self` doesn't have `count` items left, or if `other` has
+ /// fewer than `count` items.
+ ///
+ /// Time: O(n) for the number of items moved
+ pub fn drain_from_front(&mut self, other: &mut Self, count: usize) {
+ let self_len = self.len();
+ let other_len = other.len();
+ if self_len + count > Self::CAPACITY {
+ panic!("RingBuffer::drain_from_front: chunk size overflow");
+ }
+ if other_len < count {
+ panic!("RingBuffer::drain_from_front: index out of bounds");
+ }
+ unsafe { self.copy_from(other, other.origin, self.raw(self.len()), count) };
+ other.origin += count;
+ other.length -= count;
+ self.length += count;
+ }
+
+ /// Remove `count` items from the back of `other` and append them to the
+ /// front of `self`.
+ ///
+ /// Panics if `self` doesn't have `count` items left, or if `other` has
+ /// fewer than `count` items.
+ ///
+ /// Time: O(n) for the number of items moved
+ pub fn drain_from_back(&mut self, other: &mut Self, count: usize) {
+ let self_len = self.len();
+ let other_len = other.len();
+ if self_len + count > Self::CAPACITY {
+ panic!("RingBuffer::drain_from_back: chunk size overflow");
+ }
+ if other_len < count {
+ panic!("RingBuffer::drain_from_back: index out of bounds");
+ }
+ self.origin -= count;
+ let source_index = other.origin + (other.len() - count);
+ unsafe { self.copy_from(other, source_index, self.origin, count) };
+ other.length -= count;
+ self.length += count;
+ }
+
+ /// Insert a new value at index `index`, shifting all the following values
+ /// to the right.
+ ///
+ /// Panics if the index is out of bounds.
+ ///
+ /// Time: O(n) for the number of items shifted
+ pub fn insert(&mut self, index: usize, value: A) {
+ if self.is_full() {
+ panic!("RingBuffer::insert: chunk size overflow");
+ }
+ if index > self.len() {
+ panic!("RingBuffer::insert: index out of bounds");
+ }
+ if index == 0 {
+ return self.push_front(value);
+ }
+ if index == self.len() {
+ return self.push_back(value);
+ }
+ let right_count = self.len() - index;
+ // Check which side has fewer elements to shift.
+ if right_count < index {
+ // Shift to the right.
+ let mut i = self.raw(self.len() - 1);
+ let target = self.raw(index);
+ while i != target {
+ unsafe { self.force_write(i + 1, self.force_read(i)) };
+ i -= 1;
+ }
+ unsafe { self.force_write(target + 1, self.force_read(target)) };
+ self.length += 1;
+ } else {
+ // Shift to the left.
+ self.origin -= 1;
+ self.length += 1;
+ for i in self.range().take(index) {
+ unsafe { self.force_write(i, self.force_read(i + 1)) };
+ }
+ }
+ unsafe { self.force_write(self.raw(index), value) };
+ }
+
+ /// Insert a new value into the buffer in sorted order.
+ ///
+ /// This assumes every element of the buffer is already in sorted order.
+ /// If not, the value will still be inserted but the ordering is not
+ /// guaranteed.
+ ///
+ /// Time: O(log n) to find the insert position, then O(n) for the number
+ /// of elements shifted.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use std::iter::FromIterator;
+ /// # use sized_chunks::Chunk;
+ /// # use typenum::U64;
+ /// let mut chunk = Chunk::<i32, U64>::from_iter(0..5);
+ /// chunk.insert_ordered(3);
+ /// assert_eq!(&[0, 1, 2, 3, 3, 4], chunk.as_slice());
+ /// ```
+ pub fn insert_ordered(&mut self, value: A)
+ where
+ A: Ord,
+ {
+ if self.is_full() {
+ panic!("Chunk::insert: chunk is full");
+ }
+ match self.slice(..).binary_search(&value) {
+ Ok(index) => self.insert(index, value),
+ Err(index) => self.insert(index, value),
+ }
+ }
+
+ /// Insert multiple values at index `index`, shifting all the following values
+ /// to the right.
+ ///
+ /// Panics if the index is out of bounds or the chunk doesn't have room for
+ /// all the values.
+ ///
+ /// Time: O(m+n) where m is the number of elements inserted and n is the number
+ /// of elements following the insertion index. Calling `insert`
+ /// repeatedly would be O(m*n).
+ pub fn insert_from<Iterable, I>(&mut self, index: usize, iter: Iterable)
+ where
+ Iterable: IntoIterator<Item = A, IntoIter = I>,
+ I: ExactSizeIterator<Item = A>,
+ {
+ let iter = iter.into_iter();
+ let insert_size = iter.len();
+ if self.len() + insert_size > Self::CAPACITY {
+ panic!(
+ "Chunk::insert_from: chunk cannot fit {} elements",
+ insert_size
+ );
+ }
+ if index > self.len() {
+ panic!("Chunk::insert_from: index out of bounds");
+ }
+ if index == self.len() {
+ self.extend(iter);
+ return;
+ }
+ let right_count = self.len() - index;
+ // Check which side has fewer elements to shift.
+ if right_count < index {
+ // Shift to the right.
+ let mut i = self.raw(self.len() - 1);
+ let target = self.raw(index);
+ while i != target {
+ unsafe { self.force_write(i + insert_size, self.force_read(i)) };
+ i -= 1;
+ }
+ unsafe { self.force_write(target + insert_size, self.force_read(target)) };
+ self.length += insert_size;
+ } else {
+ // Shift to the left.
+ self.origin -= insert_size;
+ self.length += insert_size;
+ for i in self.range().take(index) {
+ unsafe { self.force_write(i, self.force_read(i + insert_size)) };
+ }
+ }
+ let mut index = self.raw(index);
+ // Panic safety: unless and until we fill it fully, there's a hole somewhere in the middle
+ // and the destructor would drop non-existing elements. Therefore we pretend to be empty
+ // for a while (and leak the elements instead in case something bad happens).
+ let mut inserted = 0;
+ let length = replace(&mut self.length, 0);
+ for value in iter.take(insert_size) {
+ unsafe { self.force_write(index, value) };
+ index += 1;
+ inserted += 1;
+ }
+ // This would/could create a hole in the middle if it was less
+ assert_eq!(
+ inserted, insert_size,
+ "Iterator has fewer elements than advertised",
+ );
+ self.length = length;
+ }
+
+ /// Remove the value at index `index`, shifting all the following values to
+ /// the left.
+ ///
+ /// Returns the removed value.
+ ///
+ /// Panics if the index is out of bounds.
+ ///
+ /// Time: O(n) for the number of items shifted
+ pub fn remove(&mut self, index: usize) -> A {
+ if index >= self.len() {
+ panic!("RingBuffer::remove: index out of bounds");
+ }
+ let value = unsafe { self.force_read(self.raw(index)) };
+ let right_count = self.len() - index;
+ // Check which side has fewer elements to shift.
+ if right_count < index {
+ // Shift from the right.
+ self.length -= 1;
+ let mut i = self.raw(index);
+ let target = self.raw(self.len());
+ while i != target {
+ unsafe { self.force_write(i, self.force_read(i + 1)) };
+ i += 1;
+ }
+ } else {
+ // Shift from the left.
+ let mut i = self.raw(index);
+ while i != self.origin {
+ unsafe { self.force_write(i, self.force_read(i - 1)) };
+ i -= 1;
+ }
+ self.origin += 1;
+ self.length -= 1;
+ }
+ value
+ }
+
+ /// Construct an iterator that drains values from the front of the buffer.
+ pub fn drain(&mut self) -> Drain<'_, A, N> {
+ Drain { buffer: self }
+ }
+
+ /// Discard the contents of the buffer.
+ ///
+ /// Time: O(n)
+ pub fn clear(&mut self) {
+ for i in self.range() {
+ unsafe { self.force_drop(i) };
+ }
+ self.origin = 0.into();
+ self.length = 0;
+ }
+}
+
+impl<A, N: ChunkLength<A>> Default for RingBuffer<A, N> {
+ #[inline]
+ #[must_use]
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<A: Clone, N: ChunkLength<A>> Clone for RingBuffer<A, N> {
+ fn clone(&self) -> Self {
+ let mut out = Self::new();
+ out.origin = self.origin;
+ out.length = self.length;
+ let range = self.range();
+ // Panic safety. If we panic, we don't want to drop more than we have initialized.
+ out.length = 0;
+ for index in range {
+ unsafe { out.force_write(index, (&*self.ptr(index)).clone()) };
+ out.length += 1;
+ }
+ out
+ }
+}
+
+impl<A, N> Index<usize> for RingBuffer<A, N>
+where
+ N: ChunkLength<A>,
+{
+ type Output = A;
+
+ #[must_use]
+ fn index(&self, index: usize) -> &Self::Output {
+ if index >= self.len() {
+ panic!(
+ "RingBuffer::index: index out of bounds {} >= {}",
+ index,
+ self.len()
+ );
+ }
+ unsafe { &*self.ptr(self.raw(index)) }
+ }
+}
+
+impl<A, N> IndexMut<usize> for RingBuffer<A, N>
+where
+ N: ChunkLength<A>,
+{
+ #[must_use]
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ if index >= self.len() {
+ panic!(
+ "RingBuffer::index_mut: index out of bounds {} >= {}",
+ index,
+ self.len()
+ );
+ }
+ unsafe { &mut *self.mut_ptr(self.raw(index)) }
+ }
+}
+
+impl<A: PartialEq, N: ChunkLength<A>> PartialEq for RingBuffer<A, N> {
+ #[inline]
+ #[must_use]
+ fn eq(&self, other: &Self) -> bool {
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<A, N, PrimSlice> PartialEq<PrimSlice> for RingBuffer<A, N>
+where
+ PrimSlice: Borrow<[A]>,
+ A: PartialEq,
+ N: ChunkLength<A>,
+{
+ #[inline]
+ #[must_use]
+ fn eq(&self, other: &PrimSlice) -> bool {
+ let other = other.borrow();
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<A, N> PartialEq<Slice<'_, A, N>> for RingBuffer<A, N>
+where
+ A: PartialEq,
+ N: ChunkLength<A>,
+{
+ fn eq(&self, other: &Slice<'_, A, N>) -> bool {
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<A, N> PartialEq<SliceMut<'_, A, N>> for RingBuffer<A, N>
+where
+ A: PartialEq,
+ N: ChunkLength<A>,
+{
+ fn eq(&self, other: &SliceMut<'_, A, N>) -> bool {
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<A: Eq, N: ChunkLength<A>> Eq for RingBuffer<A, N> {}
+
+impl<A: PartialOrd, N: ChunkLength<A>> PartialOrd for RingBuffer<A, N> {
+ #[inline]
+ #[must_use]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.iter().partial_cmp(other.iter())
+ }
+}
+
+impl<A: Ord, N: ChunkLength<A>> Ord for RingBuffer<A, N> {
+ #[inline]
+ #[must_use]
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.iter().cmp(other.iter())
+ }
+}
+
+impl<A, N: ChunkLength<A>> Extend<A> for RingBuffer<A, N> {
+ #[inline]
+ fn extend<I: IntoIterator<Item = A>>(&mut self, iter: I) {
+ for item in iter {
+ self.push_back(item);
+ }
+ }
+}
+
+impl<'a, A: Clone + 'a, N: ChunkLength<A>> Extend<&'a A> for RingBuffer<A, N> {
+ #[inline]
+ fn extend<I: IntoIterator<Item = &'a A>>(&mut self, iter: I) {
+ for item in iter {
+ self.push_back(item.clone());
+ }
+ }
+}
+
+impl<A: Debug, N: ChunkLength<A>> Debug for RingBuffer<A, N> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
+ f.write_str("RingBuffer")?;
+ f.debug_list().entries(self.iter()).finish()
+ }
+}
+
+impl<A: Hash, N: ChunkLength<A>> Hash for RingBuffer<A, N> {
+ #[inline]
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ for item in self {
+ item.hash(hasher)
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl<N: ChunkLength<u8>> std::io::Write for RingBuffer<u8, N> {
+ fn write(&mut self, mut buf: &[u8]) -> std::io::Result<usize> {
+ let max_new = Self::CAPACITY - self.len();
+ if buf.len() > max_new {
+ buf = &buf[..max_new];
+ }
+ unsafe { self.copy_from_slice(buf, self.origin + self.len()) };
+ self.length += buf.len();
+ Ok(buf.len())
+ }
+
+ #[inline]
+ fn flush(&mut self) -> std::io::Result<()> {
+ Ok(())
+ }
+}
+
+#[cfg(feature = "std")]
+impl<N: ChunkLength<u8>> std::io::Read for RingBuffer<u8, N> {
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ let read_size = buf.len().min(self.len());
+ if read_size == 0 {
+ Ok(0)
+ } else {
+ for p in buf.iter_mut().take(read_size) {
+ *p = self.pop_front().unwrap();
+ }
+ Ok(read_size)
+ }
+ }
+}
+
+impl<A, N: ChunkLength<A>> FromIterator<A> for RingBuffer<A, N> {
+ #[must_use]
+ fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> Self {
+ let mut buffer = RingBuffer::new();
+ buffer.extend(iter);
+ buffer
+ }
+}
+
+impl<A, N: ChunkLength<A>> IntoIterator for RingBuffer<A, N> {
+ type Item = A;
+ type IntoIter = OwnedIter<A, N>;
+
+ #[inline]
+ #[must_use]
+ fn into_iter(self) -> Self::IntoIter {
+ OwnedIter { buffer: self }
+ }
+}
+
+impl<'a, A, N: ChunkLength<A>> IntoIterator for &'a RingBuffer<A, N> {
+ type Item = &'a A;
+ type IntoIter = Iter<'a, A, N>;
+
+ #[inline]
+ #[must_use]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a, A, N: ChunkLength<A>> IntoIterator for &'a mut RingBuffer<A, N> {
+ type Item = &'a mut A;
+ type IntoIter = IterMut<'a, A, N>;
+
+ #[inline]
+ #[must_use]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+// Tests
+
+#[cfg(test)]
+mod test {
+ use typenum::U0;
+
+ use super::*;
+
+ #[test]
+ fn validity_invariant() {
+ assert!(Some(RingBuffer::<Box<()>>::new()).is_some());
+ }
+
+ #[test]
+ fn is_full() {
+ let mut chunk = RingBuffer::<_, U64>::new();
+ for i in 0..64 {
+ assert_eq!(false, chunk.is_full());
+ chunk.push_back(i);
+ }
+ assert_eq!(true, chunk.is_full());
+ }
+
+ #[test]
+ fn ref_iter() {
+ let chunk: RingBuffer<i32> = (0..64).collect();
+ let out_vec: Vec<&i32> = chunk.iter().collect();
+ let should_vec_p: Vec<i32> = (0..64).collect();
+ let should_vec: Vec<&i32> = should_vec_p.iter().collect();
+ assert_eq!(should_vec, out_vec);
+ }
+
+ #[test]
+ fn mut_ref_iter() {
+ let mut chunk: RingBuffer<i32> = (0..64).collect();
+ let out_vec: Vec<&mut i32> = chunk.iter_mut().collect();
+ let mut should_vec_p: Vec<i32> = (0..64).collect();
+ let should_vec: Vec<&mut i32> = should_vec_p.iter_mut().collect();
+ assert_eq!(should_vec, out_vec);
+ }
+
+ #[test]
+ fn consuming_iter() {
+ let chunk: RingBuffer<i32> = (0..64).collect();
+ let out_vec: Vec<i32> = chunk.into_iter().collect();
+ let should_vec: Vec<i32> = (0..64).collect();
+ assert_eq!(should_vec, out_vec);
+ }
+
+ #[test]
+ fn draining_iter() {
+ let mut chunk: RingBuffer<i32> = (0..64).collect();
+ let mut half: RingBuffer<i32> = chunk.drain().take(16).collect();
+ half.extend(chunk.drain().rev().take(16));
+ let should: Vec<i32> = (16..48).collect();
+ assert_eq!(chunk, should);
+ let should: Vec<i32> = (0..16).chain((48..64).rev()).collect();
+ assert_eq!(half, should);
+ }
+
+ #[cfg(feature = "std")]
+ #[test]
+ fn io_write() {
+ use std::io::Write;
+ let mut buffer: RingBuffer<u8> = (0..32).collect();
+ let to_write: Vec<u8> = (32..128).collect();
+ assert_eq!(32, buffer.write(&to_write).unwrap());
+ assert_eq!(buffer, (0..64).collect::<Vec<u8>>());
+ }
+
+ #[cfg(feature = "std")]
+ #[test]
+ fn io_read() {
+ use std::io::Read;
+ let mut buffer: RingBuffer<u8> = (16..48).collect();
+ let mut read_buf: Vec<u8> = (0..16).collect();
+ assert_eq!(16, buffer.read(&mut read_buf).unwrap());
+ assert_eq!(read_buf, (16..32).collect::<Vec<u8>>());
+ assert_eq!(buffer, (32..48).collect::<Vec<u8>>());
+ assert_eq!(16, buffer.read(&mut read_buf).unwrap());
+ assert_eq!(read_buf, (32..48).collect::<Vec<u8>>());
+ assert_eq!(buffer, vec![]);
+ assert_eq!(0, buffer.read(&mut read_buf).unwrap());
+ }
+
+ #[test]
+ fn clone() {
+ let buffer: RingBuffer<u32> = (0..50).collect();
+ assert_eq!(buffer, buffer.clone());
+ }
+
+ #[test]
+ fn failing() {
+ let mut buffer: RingBuffer<u32> = RingBuffer::new();
+ buffer.push_front(0);
+ let mut add: RingBuffer<u32> = vec![1, 0, 0, 0, 0, 0].into_iter().collect();
+ buffer.append(&mut add);
+ assert_eq!(1, buffer.remove(1));
+ let expected = vec![0, 0, 0, 0, 0, 0];
+ assert_eq!(buffer, expected);
+ }
+
+ use crate::tests::DropTest;
+ use std::sync::atomic::{AtomicUsize, Ordering};
+
+ #[test]
+ fn dropping() {
+ let counter = AtomicUsize::new(0);
+ {
+ let mut chunk: RingBuffer<DropTest<'_>> = RingBuffer::new();
+ for _i in 0..20 {
+ chunk.push_back(DropTest::new(&counter))
+ }
+ for _i in 0..20 {
+ chunk.push_front(DropTest::new(&counter))
+ }
+ assert_eq!(40, counter.load(Ordering::Relaxed));
+ for _i in 0..10 {
+ chunk.pop_back();
+ }
+ assert_eq!(30, counter.load(Ordering::Relaxed));
+ }
+ assert_eq!(0, counter.load(Ordering::Relaxed));
+ }
+
+ #[test]
+ #[should_panic(expected = "assertion failed: Self::CAPACITY >= 1")]
+ fn unit_on_empty() {
+ let _ = RingBuffer::<usize, U0>::unit(1);
+ }
+
+ #[test]
+ #[should_panic(expected = "assertion failed: Self::CAPACITY >= 2")]
+ fn pair_on_empty() {
+ let _ = RingBuffer::<usize, U0>::pair(1, 2);
+ }
+}
diff --git a/vendor/sized-chunks/src/ring_buffer/refpool.rs b/vendor/sized-chunks/src/ring_buffer/refpool.rs
new file mode 100644
index 0000000..453eddf
--- /dev/null
+++ b/vendor/sized-chunks/src/ring_buffer/refpool.rs
@@ -0,0 +1,69 @@
+use core::mem::MaybeUninit;
+
+use ::refpool::{PoolClone, PoolDefault};
+
+use crate::ring_buffer::index::RawIndex;
+use crate::types::ChunkLength;
+use crate::RingBuffer;
+
+impl<A, N> PoolDefault for RingBuffer<A, N>
+where
+ N: ChunkLength<A>,
+{
+ unsafe fn default_uninit(target: &mut MaybeUninit<Self>) {
+ let ptr = target.as_mut_ptr();
+ let origin_ptr: *mut RawIndex<N> = &mut (*ptr).origin;
+ let length_ptr: *mut usize = &mut (*ptr).length;
+ origin_ptr.write(0.into());
+ length_ptr.write(0);
+ }
+}
+
+impl<A, N> PoolClone for RingBuffer<A, N>
+where
+ A: Clone,
+ N: ChunkLength<A>,
+{
+ unsafe fn clone_uninit(&self, target: &mut MaybeUninit<Self>) {
+ let ptr = target.as_mut_ptr();
+ let origin_ptr: *mut RawIndex<N> = &mut (*ptr).origin;
+ let length_ptr: *mut usize = &mut (*ptr).length;
+ let data_ptr: *mut _ = &mut (*ptr).data;
+ let data_ptr: *mut A = (*data_ptr).as_mut_ptr().cast();
+ origin_ptr.write(self.origin);
+ length_ptr.write(self.length);
+ for index in self.range() {
+ data_ptr
+ .add(index.to_usize())
+ .write((*self.ptr(index)).clone());
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use ::refpool::{Pool, PoolRef};
+ use std::iter::FromIterator;
+
+ #[test]
+ fn default_and_clone() {
+ let pool: Pool<RingBuffer<usize>> = Pool::new(16);
+ let mut ref1 = PoolRef::default(&pool);
+ {
+ let chunk = PoolRef::make_mut(&pool, &mut ref1);
+ chunk.push_back(1);
+ chunk.push_back(2);
+ chunk.push_back(3);
+ }
+ let ref2 = PoolRef::cloned(&pool, &ref1);
+ let ref3 = PoolRef::clone_from(&pool, &RingBuffer::from_iter(1..=3));
+ assert_eq!(RingBuffer::<usize>::from_iter(1..=3), *ref1);
+ assert_eq!(RingBuffer::<usize>::from_iter(1..=3), *ref2);
+ assert_eq!(RingBuffer::<usize>::from_iter(1..=3), *ref3);
+ assert_eq!(ref1, ref2);
+ assert_eq!(ref1, ref3);
+ assert_eq!(ref2, ref3);
+ assert!(!PoolRef::ptr_eq(&ref1, &ref2));
+ }
+}
diff --git a/vendor/sized-chunks/src/ring_buffer/slice.rs b/vendor/sized-chunks/src/ring_buffer/slice.rs
new file mode 100644
index 0000000..1a624ee
--- /dev/null
+++ b/vendor/sized-chunks/src/ring_buffer/slice.rs
@@ -0,0 +1,556 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+use core::borrow::Borrow;
+use core::cmp::Ordering;
+use core::fmt::Debug;
+use core::fmt::Error;
+use core::fmt::Formatter;
+use core::hash::Hash;
+use core::hash::Hasher;
+use core::ops::IndexMut;
+use core::ops::{Bound, Index, Range, RangeBounds};
+
+use super::{Iter, IterMut, RingBuffer};
+use crate::types::ChunkLength;
+
+use array_ops::{Array, ArrayMut, HasLength};
+
+/// An indexable representation of a subset of a `RingBuffer`.
+pub struct Slice<'a, A, N: ChunkLength<A>> {
+ pub(crate) buffer: &'a RingBuffer<A, N>,
+ pub(crate) range: Range<usize>,
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> HasLength for Slice<'a, A, N> {
+ /// Get the length of the slice.
+ #[inline]
+ #[must_use]
+ fn len(&self) -> usize {
+ self.range.end - self.range.start
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> Array for Slice<'a, A, N> {
+ /// Get a reference to the value at a given index.
+ #[inline]
+ #[must_use]
+ fn get(&self, index: usize) -> Option<&A> {
+ if index >= self.len() {
+ None
+ } else {
+ Some(unsafe { self.get_unchecked(index) })
+ }
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> Slice<'a, A, N> {
+ /// Get an unchecked reference to the value at the given index.
+ ///
+ /// # Safety
+ ///
+ /// You must ensure the index is not out of bounds.
+ #[must_use]
+ pub unsafe fn get_unchecked(&self, index: usize) -> &A {
+ self.buffer.get_unchecked(self.range.start + index)
+ }
+
+ /// Get an iterator over references to the items in the slice in order.
+ #[inline]
+ #[must_use]
+ pub fn iter(&self) -> Iter<'_, A, N> {
+ Iter {
+ buffer: self.buffer,
+ left_index: self.buffer.origin + self.range.start,
+ right_index: self.buffer.origin + self.range.start + self.len(),
+ remaining: self.len(),
+ }
+ }
+
+ /// Create a subslice of this slice.
+ ///
+ /// This consumes the slice. To create a subslice without consuming it,
+ /// clone it first: `my_slice.clone().slice(1..2)`.
+ #[must_use]
+ pub fn slice<R: RangeBounds<usize>>(self, range: R) -> Slice<'a, A, N> {
+ let new_range = Range {
+ start: match range.start_bound() {
+ Bound::Unbounded => self.range.start,
+ Bound::Included(index) => self.range.start + index,
+ Bound::Excluded(_) => unimplemented!(),
+ },
+ end: match range.end_bound() {
+ Bound::Unbounded => self.range.end,
+ Bound::Included(index) => self.range.start + index + 1,
+ Bound::Excluded(index) => self.range.start + index,
+ },
+ };
+ if new_range.start < self.range.start
+ || new_range.end > self.range.end
+ || new_range.start > new_range.end
+ {
+ panic!("Slice::slice: index out of bounds");
+ }
+ Slice {
+ buffer: self.buffer,
+ range: new_range,
+ }
+ }
+
+ /// Split the slice into two subslices at the given index.
+ #[must_use]
+ pub fn split_at(self, index: usize) -> (Slice<'a, A, N>, Slice<'a, A, N>) {
+ if index > self.len() {
+ panic!("Slice::split_at: index out of bounds");
+ }
+ let index = self.range.start + index;
+ (
+ Slice {
+ buffer: self.buffer,
+ range: Range {
+ start: self.range.start,
+ end: index,
+ },
+ },
+ Slice {
+ buffer: self.buffer,
+ range: Range {
+ start: index,
+ end: self.range.end,
+ },
+ },
+ )
+ }
+
+ /// Construct a new `RingBuffer` by copying the elements in this slice.
+ #[inline]
+ #[must_use]
+ pub fn to_owned(&self) -> RingBuffer<A, N>
+ where
+ A: Clone,
+ {
+ self.iter().cloned().collect()
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> From<&'a RingBuffer<A, N>> for Slice<'a, A, N> {
+ #[inline]
+ #[must_use]
+ fn from(buffer: &'a RingBuffer<A, N>) -> Self {
+ Slice {
+ range: Range {
+ start: 0,
+ end: buffer.len(),
+ },
+ buffer,
+ }
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> Clone for Slice<'a, A, N> {
+ #[inline]
+ #[must_use]
+ fn clone(&self) -> Self {
+ Slice {
+ buffer: self.buffer,
+ range: self.range.clone(),
+ }
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> Index<usize> for Slice<'a, A, N> {
+ type Output = A;
+
+ #[inline]
+ #[must_use]
+ fn index(&self, index: usize) -> &Self::Output {
+ self.buffer.index(self.range.start + index)
+ }
+}
+
+impl<'a, A: PartialEq + 'a, N: ChunkLength<A> + 'a> PartialEq for Slice<'a, A, N> {
+ #[inline]
+ #[must_use]
+ fn eq(&self, other: &Self) -> bool {
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<'a, A: PartialEq + 'a, N: ChunkLength<A> + 'a> PartialEq<SliceMut<'a, A, N>>
+ for Slice<'a, A, N>
+{
+ #[inline]
+ #[must_use]
+ fn eq(&self, other: &SliceMut<'a, A, N>) -> bool {
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<'a, A: PartialEq + 'a, N: ChunkLength<A> + 'a> PartialEq<RingBuffer<A, N>>
+ for Slice<'a, A, N>
+{
+ #[inline]
+ #[must_use]
+ fn eq(&self, other: &RingBuffer<A, N>) -> bool {
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<'a, A: PartialEq + 'a, N: ChunkLength<A> + 'a, S> PartialEq<S> for Slice<'a, A, N>
+where
+ S: Borrow<[A]>,
+{
+ #[inline]
+ #[must_use]
+ fn eq(&self, other: &S) -> bool {
+ let other = other.borrow();
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<'a, A: Eq + 'a, N: ChunkLength<A> + 'a> Eq for Slice<'a, A, N> {}
+
+impl<'a, A: PartialOrd + 'a, N: ChunkLength<A> + 'a> PartialOrd for Slice<'a, A, N> {
+ #[inline]
+ #[must_use]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.iter().partial_cmp(other.iter())
+ }
+}
+
+impl<'a, A: Ord + 'a, N: ChunkLength<A> + 'a> Ord for Slice<'a, A, N> {
+ #[inline]
+ #[must_use]
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.iter().cmp(other.iter())
+ }
+}
+
+impl<'a, A: Debug + 'a, N: ChunkLength<A> + 'a> Debug for Slice<'a, A, N> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
+ f.write_str("RingBuffer")?;
+ f.debug_list().entries(self.iter()).finish()
+ }
+}
+
+impl<'a, A: Hash + 'a, N: ChunkLength<A> + 'a> Hash for Slice<'a, A, N> {
+ #[inline]
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ for item in self {
+ item.hash(hasher)
+ }
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> IntoIterator for &'a Slice<'a, A, N> {
+ type Item = &'a A;
+ type IntoIter = Iter<'a, A, N>;
+
+ #[inline]
+ #[must_use]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+// Mutable slice
+
+/// An indexable representation of a mutable subset of a `RingBuffer`.
+pub struct SliceMut<'a, A, N: ChunkLength<A>> {
+ pub(crate) buffer: &'a mut RingBuffer<A, N>,
+ pub(crate) range: Range<usize>,
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> HasLength for SliceMut<'a, A, N> {
+ /// Get the length of the slice.
+ #[inline]
+ #[must_use]
+ fn len(&self) -> usize {
+ self.range.end - self.range.start
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> Array for SliceMut<'a, A, N> {
+ /// Get a reference to the value at a given index.
+ #[inline]
+ #[must_use]
+ fn get(&self, index: usize) -> Option<&A> {
+ if index >= self.len() {
+ None
+ } else {
+ Some(unsafe { self.get_unchecked(index) })
+ }
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> ArrayMut for SliceMut<'a, A, N> {
+ /// Get a mutable reference to the value at a given index.
+ #[inline]
+ #[must_use]
+ fn get_mut(&mut self, index: usize) -> Option<&mut A> {
+ if index >= self.len() {
+ None
+ } else {
+ Some(unsafe { self.get_unchecked_mut(index) })
+ }
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> SliceMut<'a, A, N> {
+ /// Downgrade this slice into a non-mutable slice.
+ #[inline]
+ #[must_use]
+ pub fn unmut(self) -> Slice<'a, A, N> {
+ Slice {
+ buffer: self.buffer,
+ range: self.range,
+ }
+ }
+
+ /// Get an unchecked reference to the value at the given index.
+ ///
+ /// # Safety
+ ///
+ /// You must ensure the index is not out of bounds.
+ #[must_use]
+ pub unsafe fn get_unchecked(&self, index: usize) -> &A {
+ self.buffer.get_unchecked(self.range.start + index)
+ }
+
+ /// Get an unchecked mutable reference to the value at the given index.
+ ///
+ /// # Safety
+ ///
+ /// You must ensure the index is not out of bounds.
+ #[must_use]
+ pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut A {
+ self.buffer.get_unchecked_mut(self.range.start + index)
+ }
+
+ /// Get an iterator over references to the items in the slice in order.
+ #[inline]
+ #[must_use]
+ pub fn iter(&self) -> Iter<'_, A, N> {
+ Iter {
+ buffer: self.buffer,
+ left_index: self.buffer.origin + self.range.start,
+ right_index: self.buffer.origin + self.range.start + self.len(),
+ remaining: self.len(),
+ }
+ }
+
+ /// Get an iterator over mutable references to the items in the slice in
+ /// order.
+ #[inline]
+ #[must_use]
+ pub fn iter_mut(&mut self) -> IterMut<'_, A, N> {
+ IterMut::new_slice(
+ self.buffer,
+ self.buffer.origin + self.range.start,
+ self.len(),
+ )
+ }
+
+ /// Create a subslice of this slice.
+ ///
+ /// This consumes the slice. Because the slice works like a mutable
+ /// reference, you can only have one slice over a given subset of a
+ /// `RingBuffer` at any one time, so that's just how it's got to be.
+ #[must_use]
+ pub fn slice<R: RangeBounds<usize>>(self, range: R) -> SliceMut<'a, A, N> {
+ let new_range = Range {
+ start: match range.start_bound() {
+ Bound::Unbounded => self.range.start,
+ Bound::Included(index) => self.range.start + index,
+ Bound::Excluded(_) => unimplemented!(),
+ },
+ end: match range.end_bound() {
+ Bound::Unbounded => self.range.end,
+ Bound::Included(index) => self.range.start + index + 1,
+ Bound::Excluded(index) => self.range.start + index,
+ },
+ };
+ if new_range.start < self.range.start
+ || new_range.end > self.range.end
+ || new_range.start > new_range.end
+ {
+ panic!("Slice::slice: index out of bounds");
+ }
+ SliceMut {
+ buffer: self.buffer,
+ range: new_range,
+ }
+ }
+
+ /// Split the slice into two subslices at the given index.
+ #[must_use]
+ pub fn split_at(self, index: usize) -> (SliceMut<'a, A, N>, SliceMut<'a, A, N>) {
+ if index > self.len() {
+ panic!("SliceMut::split_at: index out of bounds");
+ }
+ let index = self.range.start + index;
+ let ptr: *mut RingBuffer<A, N> = self.buffer;
+ (
+ SliceMut {
+ buffer: unsafe { &mut *ptr },
+ range: Range {
+ start: self.range.start,
+ end: index,
+ },
+ },
+ SliceMut {
+ buffer: unsafe { &mut *ptr },
+ range: Range {
+ start: index,
+ end: self.range.end,
+ },
+ },
+ )
+ }
+
+ /// Construct a new `RingBuffer` by copying the elements in this slice.
+ #[inline]
+ #[must_use]
+ pub fn to_owned(&self) -> RingBuffer<A, N>
+ where
+ A: Clone,
+ {
+ self.iter().cloned().collect()
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> From<&'a mut RingBuffer<A, N>> for SliceMut<'a, A, N> {
+ #[must_use]
+ fn from(buffer: &'a mut RingBuffer<A, N>) -> Self {
+ SliceMut {
+ range: Range {
+ start: 0,
+ end: buffer.len(),
+ },
+ buffer,
+ }
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> Into<Slice<'a, A, N>> for SliceMut<'a, A, N> {
+ #[inline]
+ #[must_use]
+ fn into(self) -> Slice<'a, A, N> {
+ self.unmut()
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> Index<usize> for SliceMut<'a, A, N> {
+ type Output = A;
+
+ #[inline]
+ #[must_use]
+ fn index(&self, index: usize) -> &Self::Output {
+ self.buffer.index(self.range.start + index)
+ }
+}
+
+impl<'a, A: 'a, N: ChunkLength<A> + 'a> IndexMut<usize> for SliceMut<'a, A, N> {
+ #[inline]
+ #[must_use]
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ self.buffer.index_mut(self.range.start + index)
+ }
+}
+
+impl<'a, A: PartialEq + 'a, N: ChunkLength<A> + 'a> PartialEq for SliceMut<'a, A, N> {
+ #[inline]
+ #[must_use]
+ fn eq(&self, other: &Self) -> bool {
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<'a, A: PartialEq + 'a, N: ChunkLength<A> + 'a> PartialEq<Slice<'a, A, N>>
+ for SliceMut<'a, A, N>
+{
+ #[inline]
+ #[must_use]
+ fn eq(&self, other: &Slice<'a, A, N>) -> bool {
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<'a, A: PartialEq + 'a, N: ChunkLength<A> + 'a> PartialEq<RingBuffer<A, N>>
+ for SliceMut<'a, A, N>
+{
+ #[inline]
+ #[must_use]
+ fn eq(&self, other: &RingBuffer<A, N>) -> bool {
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<'a, A: PartialEq + 'a, N: ChunkLength<A> + 'a, S> PartialEq<S> for SliceMut<'a, A, N>
+where
+ S: Borrow<[A]>,
+{
+ #[inline]
+ #[must_use]
+ fn eq(&self, other: &S) -> bool {
+ let other = other.borrow();
+ self.len() == other.len() && self.iter().eq(other.iter())
+ }
+}
+
+impl<'a, A: Eq + 'a, N: ChunkLength<A> + 'a> Eq for SliceMut<'a, A, N> {}
+
+impl<'a, A: PartialOrd + 'a, N: ChunkLength<A> + 'a> PartialOrd for SliceMut<'a, A, N> {
+ #[inline]
+ #[must_use]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.iter().partial_cmp(other.iter())
+ }
+}
+
+impl<'a, A: Ord + 'a, N: ChunkLength<A> + 'a> Ord for SliceMut<'a, A, N> {
+ #[inline]
+ #[must_use]
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.iter().cmp(other.iter())
+ }
+}
+
+impl<'a, A: Debug + 'a, N: ChunkLength<A> + 'a> Debug for SliceMut<'a, A, N> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
+ f.write_str("RingBuffer")?;
+ f.debug_list().entries(self.iter()).finish()
+ }
+}
+
+impl<'a, A: Hash + 'a, N: ChunkLength<A> + 'a> Hash for SliceMut<'a, A, N> {
+ #[inline]
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ for item in self {
+ item.hash(hasher)
+ }
+ }
+}
+
+impl<'a, 'b, A: 'a, N: ChunkLength<A> + 'a> IntoIterator for &'a SliceMut<'a, A, N> {
+ type Item = &'a A;
+ type IntoIter = Iter<'a, A, N>;
+
+ #[inline]
+ #[must_use]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a, 'b, A: 'a, N: ChunkLength<A> + 'a> IntoIterator for &'a mut SliceMut<'a, A, N> {
+ type Item = &'a mut A;
+ type IntoIter = IterMut<'a, A, N>;
+
+ #[inline]
+ #[must_use]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
diff --git a/vendor/sized-chunks/src/sized_chunk/iter.rs b/vendor/sized-chunks/src/sized_chunk/iter.rs
new file mode 100644
index 0000000..88c75fd
--- /dev/null
+++ b/vendor/sized-chunks/src/sized_chunk/iter.rs
@@ -0,0 +1,109 @@
+use core::iter::FusedIterator;
+
+use super::Chunk;
+use crate::types::ChunkLength;
+
+/// A consuming iterator over the elements of a `Chunk`.
+pub struct Iter<A, N>
+where
+ N: ChunkLength<A>,
+{
+ pub(crate) chunk: Chunk<A, N>,
+}
+
+impl<A, N> Iterator for Iter<A, N>
+where
+ N: ChunkLength<A>,
+{
+ type Item = A;
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.chunk.is_empty() {
+ None
+ } else {
+ Some(self.chunk.pop_front())
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.chunk.len(), Some(self.chunk.len()))
+ }
+}
+
+impl<A, N> DoubleEndedIterator for Iter<A, N>
+where
+ N: ChunkLength<A>,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.chunk.is_empty() {
+ None
+ } else {
+ Some(self.chunk.pop_back())
+ }
+ }
+}
+
+impl<A, N> ExactSizeIterator for Iter<A, N> where N: ChunkLength<A> {}
+
+impl<A, N> FusedIterator for Iter<A, N> where N: ChunkLength<A> {}
+
+/// A draining iterator over the elements of a `Chunk`.
+///
+/// "Draining" means that as the iterator yields each element, it's removed from
+/// the `Chunk`. When the iterator terminates, the chunk will be empty. This is
+/// different from the consuming iterator `Iter` in that `Iter` will take
+/// ownership of the `Chunk` and discard it when you're done iterating, while
+/// `Drain` leaves you still owning the drained `Chunk`.
+pub struct Drain<'a, A, N>
+where
+ N: ChunkLength<A>,
+{
+ pub(crate) chunk: &'a mut Chunk<A, N>,
+}
+
+impl<'a, A, N> Iterator for Drain<'a, A, N>
+where
+ A: 'a,
+ N: ChunkLength<A> + 'a,
+{
+ type Item = A;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.chunk.is_empty() {
+ None
+ } else {
+ Some(self.chunk.pop_front())
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.chunk.len(), Some(self.chunk.len()))
+ }
+}
+
+impl<'a, A, N> DoubleEndedIterator for Drain<'a, A, N>
+where
+ A: 'a,
+ N: ChunkLength<A> + 'a,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.chunk.is_empty() {
+ None
+ } else {
+ Some(self.chunk.pop_back())
+ }
+ }
+}
+
+impl<'a, A, N> ExactSizeIterator for Drain<'a, A, N>
+where
+ A: 'a,
+ N: ChunkLength<A> + 'a,
+{
+}
+
+impl<'a, A, N> FusedIterator for Drain<'a, A, N>
+where
+ A: 'a,
+ N: ChunkLength<A> + 'a,
+{
+}
diff --git a/vendor/sized-chunks/src/sized_chunk/mod.rs b/vendor/sized-chunks/src/sized_chunk/mod.rs
new file mode 100644
index 0000000..fc40643
--- /dev/null
+++ b/vendor/sized-chunks/src/sized_chunk/mod.rs
@@ -0,0 +1,1411 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+//! A fixed capacity smart array.
+//!
+//! See [`Chunk`](struct.Chunk.html)
+
+use crate::inline_array::InlineArray;
+use core::borrow::{Borrow, BorrowMut};
+use core::cmp::Ordering;
+use core::fmt::{Debug, Error, Formatter};
+use core::hash::{Hash, Hasher};
+use core::iter::FromIterator;
+use core::mem::{replace, MaybeUninit};
+use core::ops::{Deref, DerefMut, Index, IndexMut};
+use core::ptr;
+use core::slice::{
+ from_raw_parts, from_raw_parts_mut, Iter as SliceIter, IterMut as SliceIterMut, SliceIndex,
+};
+
+#[cfg(feature = "std")]
+use std::io;
+
+use typenum::U64;
+
+use crate::types::ChunkLength;
+
+mod iter;
+pub use self::iter::{Drain, Iter};
+
+#[cfg(feature = "refpool")]
+mod refpool;
+
+/// A fixed capacity smart array.
+///
+/// An inline array of items with a variable length but a fixed, preallocated
+/// capacity given by the `N` type, which must be an [`Unsigned`][Unsigned] type
+/// level numeral.
+///
+/// It's 'smart' because it's able to reorganise its contents based on expected
+/// behaviour. If you construct one using `push_back`, it will be laid out like
+/// a `Vec` with space at the end. If you `push_front` it will start filling in
+/// values from the back instead of the front, so that you still get linear time
+/// push as long as you don't reverse direction. If you do, and there's no room
+/// at the end you're pushing to, it'll shift its contents over to the other
+/// side, creating more space to push into. This technique is tuned for
+/// `Chunk`'s expected use case in [im::Vector]: usually, chunks always see
+/// either `push_front` or `push_back`, but not both unless they move around
+/// inside the tree, in which case they're able to reorganise themselves with
+/// reasonable efficiency to suit their new usage patterns.
+///
+/// It maintains a `left` index and a `right` index instead of a simple length
+/// counter in order to accomplish this, much like a ring buffer would, except
+/// that the `Chunk` keeps all its items sequentially in memory so that you can
+/// always get a `&[A]` slice for them, at the price of the occasional
+/// reordering operation. The allocated size of a `Chunk` is thus `usize` * 2 +
+/// `A` * `N`.
+///
+/// This technique also lets us choose to shift the shortest side to account for
+/// the inserted or removed element when performing insert and remove
+/// operations, unlike `Vec` where you always need to shift the right hand side.
+///
+/// Unlike a `Vec`, the `Chunk` has a fixed capacity and cannot grow beyond it.
+/// Being intended for low level use, it expects you to know or test whether
+/// you're pushing to a full array, and has an API more geared towards panics
+/// than returning `Option`s, on the assumption that you know what you're doing.
+/// Of course, if you don't, you can expect it to panic immediately rather than
+/// do something undefined and usually bad.
+///
+/// ## Isn't this just a less efficient ring buffer?
+///
+/// You might be wondering why you would want to use this data structure rather
+/// than a [`RingBuffer`][RingBuffer], which is similar but doesn't need to
+/// shift its content around when it hits the sides of the allocated buffer. The
+/// answer is that `Chunk` can be dereferenced into a slice, while a ring buffer
+/// can not. You'll also save a few cycles on index lookups, as a `Chunk`'s data
+/// is guaranteed to be contiguous in memory, so there's no need to remap logical
+/// indices to a ring buffer's physical layout.
+///
+/// # Examples
+///
+/// ```rust
+/// # #[macro_use] extern crate sized_chunks;
+/// # extern crate typenum;
+/// # use sized_chunks::Chunk;
+/// # use typenum::U64;
+/// // Construct a chunk with a 64 item capacity
+/// let mut chunk = Chunk::<i32, U64>::new();
+/// // Fill it with descending numbers
+/// chunk.extend((0..64).rev());
+/// // It derefs to a slice so we can use standard slice methods
+/// chunk.sort();
+/// // It's got all the amenities like `FromIterator` and `Eq`
+/// let expected: Chunk<i32, U64> = (0..64).collect();
+/// assert_eq!(expected, chunk);
+/// ```
+///
+/// [Unsigned]: https://docs.rs/typenum/1.10.0/typenum/marker_traits/trait.Unsigned.html
+/// [im::Vector]: https://docs.rs/im/latest/im/vector/enum.Vector.html
+/// [RingBuffer]: ../ring_buffer/struct.RingBuffer.html
+pub struct Chunk<A, N = U64>
+where
+ N: ChunkLength<A>,
+{
+ left: usize,
+ right: usize,
+ data: MaybeUninit<N::SizedType>,
+}
+
+impl<A, N> Drop for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ fn drop(&mut self) {
+ unsafe { ptr::drop_in_place(self.as_mut_slice()) }
+ }
+}
+
+impl<A, N> Clone for Chunk<A, N>
+where
+ A: Clone,
+ N: ChunkLength<A>,
+{
+ fn clone(&self) -> Self {
+ let mut out = Self::new();
+ out.left = self.left;
+ out.right = self.left;
+ for index in self.left..self.right {
+ unsafe { Chunk::force_write(index, (*self.ptr(index)).clone(), &mut out) }
+ // Panic safety, move the right index to cover only the really initialized things. This
+ // way we don't try to drop uninitialized, but also don't leak if we panic in the
+ // middle.
+ out.right = index + 1;
+ }
+ out
+ }
+}
+
+impl<A, N> Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ /// The maximum number of elements this `Chunk` can contain.
+ pub const CAPACITY: usize = N::USIZE;
+
+ /// Construct a new empty chunk.
+ pub fn new() -> Self {
+ Self {
+ left: 0,
+ right: 0,
+ data: MaybeUninit::uninit(),
+ }
+ }
+
+ /// Construct a new chunk with one item.
+ pub fn unit(value: A) -> Self {
+ assert!(Self::CAPACITY >= 1);
+ let mut chunk = Self {
+ left: 0,
+ right: 1,
+ data: MaybeUninit::uninit(),
+ };
+ unsafe {
+ Chunk::force_write(0, value, &mut chunk);
+ }
+ chunk
+ }
+
+ /// Construct a new chunk with two items.
+ pub fn pair(left: A, right: A) -> Self {
+ assert!(Self::CAPACITY >= 2);
+ let mut chunk = Self {
+ left: 0,
+ right: 2,
+ data: MaybeUninit::uninit(),
+ };
+ unsafe {
+ Chunk::force_write(0, left, &mut chunk);
+ Chunk::force_write(1, right, &mut chunk);
+ }
+ chunk
+ }
+
+ /// Construct a new chunk and move every item from `other` into the new
+ /// chunk.
+ ///
+ /// Time: O(n)
+ pub fn drain_from(other: &mut Self) -> Self {
+ let other_len = other.len();
+ Self::from_front(other, other_len)
+ }
+
+ /// Construct a new chunk and populate it by taking `count` items from the
+ /// iterator `iter`.
+ ///
+ /// Panics if the iterator contains less than `count` items.
+ ///
+ /// Time: O(n)
+ pub fn collect_from<I>(iter: &mut I, mut count: usize) -> Self
+ where
+ I: Iterator<Item = A>,
+ {
+ let mut chunk = Self::new();
+ while count > 0 {
+ count -= 1;
+ chunk.push_back(
+ iter.next()
+ .expect("Chunk::collect_from: underfull iterator"),
+ );
+ }
+ chunk
+ }
+
+ /// Construct a new chunk and populate it by taking `count` items from the
+ /// front of `other`.
+ ///
+ /// Time: O(n) for the number of items moved
+ pub fn from_front(other: &mut Self, count: usize) -> Self {
+ let other_len = other.len();
+ debug_assert!(count <= other_len);
+ let mut chunk = Self::new();
+ unsafe { Chunk::force_copy_to(other.left, 0, count, other, &mut chunk) };
+ chunk.right = count;
+ other.left += count;
+ chunk
+ }
+
+ /// Construct a new chunk and populate it by taking `count` items from the
+ /// back of `other`.
+ ///
+ /// Time: O(n) for the number of items moved
+ pub fn from_back(other: &mut Self, count: usize) -> Self {
+ let other_len = other.len();
+ debug_assert!(count <= other_len);
+ let mut chunk = Self::new();
+ unsafe { Chunk::force_copy_to(other.right - count, 0, count, other, &mut chunk) };
+ chunk.right = count;
+ other.right -= count;
+ chunk
+ }
+
+ /// Get the length of the chunk.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.right - self.left
+ }
+
+ /// Test if the chunk is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.left == self.right
+ }
+
+ /// Test if the chunk is at capacity.
+ #[inline]
+ pub fn is_full(&self) -> bool {
+ self.left == 0 && self.right == Self::CAPACITY
+ }
+
+ #[inline]
+ unsafe fn ptr(&self, index: usize) -> *const A {
+ (&self.data as *const _ as *const A).add(index)
+ }
+
+ /// It has no bounds checks
+ #[inline]
+ unsafe fn mut_ptr(&mut self, index: usize) -> *mut A {
+ (&mut self.data as *mut _ as *mut A).add(index)
+ }
+
+ /// Copy the value at an index, discarding ownership of the copied value
+ #[inline]
+ unsafe fn force_read(index: usize, chunk: &mut Self) -> A {
+ chunk.ptr(index).read()
+ }
+
+ /// Write a value at an index without trying to drop what's already there.
+ /// It has no bounds checks.
+ #[inline]
+ unsafe fn force_write(index: usize, value: A, chunk: &mut Self) {
+ chunk.mut_ptr(index).write(value)
+ }
+
+ /// Copy a range within a chunk
+ #[inline]
+ unsafe fn force_copy(from: usize, to: usize, count: usize, chunk: &mut Self) {
+ if count > 0 {
+ ptr::copy(chunk.ptr(from), chunk.mut_ptr(to), count)
+ }
+ }
+
+ /// Write values from iterator into range starting at write_index.
+ ///
+ /// Will overwrite values at the relevant range without dropping even in case the values were
+ /// already initialized (it is expected they are empty). Does not update the left or right
+ /// index.
+ ///
+ /// # Safety
+ ///
+ /// Range checks must already have been performed.
+ ///
+ /// # Panics
+ ///
+ /// If the iterator panics, the chunk becomes conceptually empty and will leak any previous
+ /// elements (even the ones outside the range).
+ #[inline]
+ unsafe fn write_from_iter<I>(mut write_index: usize, iter: I, chunk: &mut Self)
+ where
+ I: ExactSizeIterator<Item = A>,
+ {
+ // Panic safety. We make the array conceptually empty, so we never ever drop anything that
+ // is unitialized. We do so because we expect to be called when there's a potential "hole"
+ // in the array that makes the space for the new elements to be written. We return it back
+ // to original when everything goes fine, but leak any elements on panic. This is bad, but
+ // better than dropping non-existing stuff.
+ //
+ // Should we worry about some better panic recovery than this?
+ let left = replace(&mut chunk.left, 0);
+ let right = replace(&mut chunk.right, 0);
+ let len = iter.len();
+ let expected_end = write_index + len;
+ for value in iter.take(len) {
+ Chunk::force_write(write_index, value, chunk);
+ write_index += 1;
+ }
+ // Oops, we have a hole in here now. That would be bad, give up.
+ assert_eq!(
+ expected_end, write_index,
+ "ExactSizeIterator yielded fewer values than advertised",
+ );
+ chunk.left = left;
+ chunk.right = right;
+ }
+
+ /// Copy a range between chunks
+ #[inline]
+ unsafe fn force_copy_to(
+ from: usize,
+ to: usize,
+ count: usize,
+ chunk: &mut Self,
+ other: &mut Self,
+ ) {
+ if count > 0 {
+ ptr::copy_nonoverlapping(chunk.ptr(from), other.mut_ptr(to), count)
+ }
+ }
+
+ /// Push an item to the front of the chunk.
+ ///
+ /// Panics if the capacity of the chunk is exceeded.
+ ///
+ /// Time: O(1) if there's room at the front, O(n) otherwise
+ pub fn push_front(&mut self, value: A) {
+ if self.is_full() {
+ panic!("Chunk::push_front: can't push to full chunk");
+ }
+ if self.is_empty() {
+ self.left = N::USIZE;
+ self.right = N::USIZE;
+ } else if self.left == 0 {
+ self.left = N::USIZE - self.right;
+ unsafe { Chunk::force_copy(0, self.left, self.right, self) };
+ self.right = N::USIZE;
+ }
+ self.left -= 1;
+ unsafe { Chunk::force_write(self.left, value, self) }
+ }
+
+ /// Push an item to the back of the chunk.
+ ///
+ /// Panics if the capacity of the chunk is exceeded.
+ ///
+ /// Time: O(1) if there's room at the back, O(n) otherwise
+ pub fn push_back(&mut self, value: A) {
+ if self.is_full() {
+ panic!("Chunk::push_back: can't push to full chunk");
+ }
+ if self.is_empty() {
+ self.left = 0;
+ self.right = 0;
+ } else if self.right == N::USIZE {
+ unsafe { Chunk::force_copy(self.left, 0, self.len(), self) };
+ self.right = N::USIZE - self.left;
+ self.left = 0;
+ }
+ unsafe { Chunk::force_write(self.right, value, self) }
+ self.right += 1;
+ }
+
+ /// Pop an item off the front of the chunk.
+ ///
+ /// Panics if the chunk is empty.
+ ///
+ /// Time: O(1)
+ pub fn pop_front(&mut self) -> A {
+ if self.is_empty() {
+ panic!("Chunk::pop_front: can't pop from empty chunk");
+ } else {
+ let value = unsafe { Chunk::force_read(self.left, self) };
+ self.left += 1;
+ value
+ }
+ }
+
+ /// Pop an item off the back of the chunk.
+ ///
+ /// Panics if the chunk is empty.
+ ///
+ /// Time: O(1)
+ pub fn pop_back(&mut self) -> A {
+ if self.is_empty() {
+ panic!("Chunk::pop_back: can't pop from empty chunk");
+ } else {
+ self.right -= 1;
+ unsafe { Chunk::force_read(self.right, self) }
+ }
+ }
+
+ /// Discard all items up to but not including `index`.
+ ///
+ /// Panics if `index` is out of bounds.
+ ///
+ /// Time: O(n) for the number of items dropped
+ pub fn drop_left(&mut self, index: usize) {
+ if index > 0 {
+ unsafe { ptr::drop_in_place(&mut self[..index]) }
+ self.left += index;
+ }
+ }
+
+ /// Discard all items from `index` onward.
+ ///
+ /// Panics if `index` is out of bounds.
+ ///
+ /// Time: O(n) for the number of items dropped
+ pub fn drop_right(&mut self, index: usize) {
+ if index != self.len() {
+ unsafe { ptr::drop_in_place(&mut self[index..]) }
+ self.right = self.left + index;
+ }
+ }
+
+ /// Split a chunk into two, the original chunk containing
+ /// everything up to `index` and the returned chunk containing
+ /// everything from `index` onwards.
+ ///
+ /// Panics if `index` is out of bounds.
+ ///
+ /// Time: O(n) for the number of items in the new chunk
+ pub fn split_off(&mut self, index: usize) -> Self {
+ if index > self.len() {
+ panic!("Chunk::split_off: index out of bounds");
+ }
+ if index == self.len() {
+ return Self::new();
+ }
+ let mut right_chunk = Self::new();
+ let start = self.left + index;
+ let len = self.right - start;
+ unsafe { Chunk::force_copy_to(start, 0, len, self, &mut right_chunk) };
+ right_chunk.right = len;
+ self.right = start;
+ right_chunk
+ }
+
+ /// Remove all items from `other` and append them to the back of `self`.
+ ///
+ /// Panics if the capacity of the chunk is exceeded.
+ ///
+ /// Time: O(n) for the number of items moved
+ pub fn append(&mut self, other: &mut Self) {
+ let self_len = self.len();
+ let other_len = other.len();
+ if self_len + other_len > N::USIZE {
+ panic!("Chunk::append: chunk size overflow");
+ }
+ if self.right + other_len > N::USIZE {
+ unsafe { Chunk::force_copy(self.left, 0, self_len, self) };
+ self.right -= self.left;
+ self.left = 0;
+ }
+ unsafe { Chunk::force_copy_to(other.left, self.right, other_len, other, self) };
+ self.right += other_len;
+ other.left = 0;
+ other.right = 0;
+ }
+
+ /// Remove `count` items from the front of `other` and append them to the
+ /// back of `self`.
+ ///
+ /// Panics if `self` doesn't have `count` items left, or if `other` has
+ /// fewer than `count` items.
+ ///
+ /// Time: O(n) for the number of items moved
+ pub fn drain_from_front(&mut self, other: &mut Self, count: usize) {
+ let self_len = self.len();
+ let other_len = other.len();
+ assert!(self_len + count <= N::USIZE);
+ assert!(other_len >= count);
+ if self.right + count > N::USIZE {
+ unsafe { Chunk::force_copy(self.left, 0, self_len, self) };
+ self.right -= self.left;
+ self.left = 0;
+ }
+ unsafe { Chunk::force_copy_to(other.left, self.right, count, other, self) };
+ self.right += count;
+ other.left += count;
+ }
+
+ /// Remove `count` items from the back of `other` and append them to the
+ /// front of `self`.
+ ///
+ /// Panics if `self` doesn't have `count` items left, or if `other` has
+ /// fewer than `count` items.
+ ///
+ /// Time: O(n) for the number of items moved
+ pub fn drain_from_back(&mut self, other: &mut Self, count: usize) {
+ let self_len = self.len();
+ let other_len = other.len();
+ assert!(self_len + count <= N::USIZE);
+ assert!(other_len >= count);
+ if self.left < count {
+ unsafe { Chunk::force_copy(self.left, N::USIZE - self_len, self_len, self) };
+ self.left = N::USIZE - self_len;
+ self.right = N::USIZE;
+ }
+ unsafe { Chunk::force_copy_to(other.right - count, self.left - count, count, other, self) };
+ self.left -= count;
+ other.right -= count;
+ }
+
+ /// Update the value at index `index`, returning the old value.
+ ///
+ /// Panics if `index` is out of bounds.
+ ///
+ /// Time: O(1)
+ pub fn set(&mut self, index: usize, value: A) -> A {
+ replace(&mut self[index], value)
+ }
+
+ /// Insert a new value at index `index`, shifting all the following values
+ /// to the right.
+ ///
+ /// Panics if the index is out of bounds or the chunk is full.
+ ///
+ /// Time: O(n) for the number of elements shifted
+ pub fn insert(&mut self, index: usize, value: A) {
+ if self.is_full() {
+ panic!("Chunk::insert: chunk is full");
+ }
+ if index > self.len() {
+ panic!("Chunk::insert: index out of bounds");
+ }
+ let real_index = index + self.left;
+ let left_size = index;
+ let right_size = self.right - real_index;
+ if self.right == N::USIZE || (self.left > 0 && left_size < right_size) {
+ unsafe {
+ Chunk::force_copy(self.left, self.left - 1, left_size, self);
+ Chunk::force_write(real_index - 1, value, self);
+ }
+ self.left -= 1;
+ } else {
+ unsafe {
+ Chunk::force_copy(real_index, real_index + 1, right_size, self);
+ Chunk::force_write(real_index, value, self);
+ }
+ self.right += 1;
+ }
+ }
+
+ /// Insert a new value into the chunk in sorted order.
+ ///
+ /// This assumes every element of the chunk is already in sorted order.
+ /// If not, the value will still be inserted but the ordering is not
+ /// guaranteed.
+ ///
+ /// Time: O(log n) to find the insert position, then O(n) for the number
+ /// of elements shifted.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use std::iter::FromIterator;
+ /// # use sized_chunks::Chunk;
+ /// # use typenum::U64;
+ /// let mut chunk = Chunk::<i32, U64>::from_iter(0..5);
+ /// chunk.insert_ordered(3);
+ /// assert_eq!(&[0, 1, 2, 3, 3, 4], chunk.as_slice());
+ /// ```
+ pub fn insert_ordered(&mut self, value: A)
+ where
+ A: Ord,
+ {
+ if self.is_full() {
+ panic!("Chunk::insert: chunk is full");
+ }
+ match self.binary_search(&value) {
+ Ok(index) => self.insert(index, value),
+ Err(index) => self.insert(index, value),
+ }
+ }
+
+ /// Insert multiple values at index `index`, shifting all the following values
+ /// to the right.
+ ///
+ /// Panics if the index is out of bounds or the chunk doesn't have room for
+ /// all the values.
+ ///
+ /// Time: O(m+n) where m is the number of elements inserted and n is the number
+ /// of elements following the insertion index. Calling `insert`
+ /// repeatedly would be O(m*n).
+ pub fn insert_from<Iterable, I>(&mut self, index: usize, iter: Iterable)
+ where
+ Iterable: IntoIterator<Item = A, IntoIter = I>,
+ I: ExactSizeIterator<Item = A>,
+ {
+ let iter = iter.into_iter();
+ let insert_size = iter.len();
+ if self.len() + insert_size > Self::CAPACITY {
+ panic!(
+ "Chunk::insert_from: chunk cannot fit {} elements",
+ insert_size
+ );
+ }
+ if index > self.len() {
+ panic!("Chunk::insert_from: index out of bounds");
+ }
+ let real_index = index + self.left;
+ let left_size = index;
+ let right_size = self.right - real_index;
+ if self.right == N::USIZE || (self.left >= insert_size && left_size < right_size) {
+ unsafe {
+ Chunk::force_copy(self.left, self.left - insert_size, left_size, self);
+ let write_index = real_index - insert_size;
+ Chunk::write_from_iter(write_index, iter, self);
+ }
+ self.left -= insert_size;
+ } else if self.left == 0 || (self.right + insert_size <= Self::CAPACITY) {
+ unsafe {
+ Chunk::force_copy(real_index, real_index + insert_size, right_size, self);
+ let write_index = real_index;
+ Chunk::write_from_iter(write_index, iter, self);
+ }
+ self.right += insert_size;
+ } else {
+ unsafe {
+ Chunk::force_copy(self.left, 0, left_size, self);
+ Chunk::force_copy(real_index, left_size + insert_size, right_size, self);
+ let write_index = left_size;
+ Chunk::write_from_iter(write_index, iter, self);
+ }
+ self.right -= self.left;
+ self.right += insert_size;
+ self.left = 0;
+ }
+ }
+
+ /// Remove the value at index `index`, shifting all the following values to
+ /// the left.
+ ///
+ /// Returns the removed value.
+ ///
+ /// Panics if the index is out of bounds.
+ ///
+ /// Time: O(n) for the number of items shifted
+ pub fn remove(&mut self, index: usize) -> A {
+ if index >= self.len() {
+ panic!("Chunk::remove: index out of bounds");
+ }
+ let real_index = index + self.left;
+ let value = unsafe { Chunk::force_read(real_index, self) };
+ let left_size = index;
+ let right_size = self.right - real_index - 1;
+ if left_size < right_size {
+ unsafe { Chunk::force_copy(self.left, self.left + 1, left_size, self) };
+ self.left += 1;
+ } else {
+ unsafe { Chunk::force_copy(real_index + 1, real_index, right_size, self) };
+ self.right -= 1;
+ }
+ value
+ }
+
+ /// Construct an iterator that drains values from the front of the chunk.
+ pub fn drain(&mut self) -> Drain<'_, A, N> {
+ Drain { chunk: self }
+ }
+
+ /// Discard the contents of the chunk.
+ ///
+ /// Time: O(n)
+ pub fn clear(&mut self) {
+ unsafe { ptr::drop_in_place(self.as_mut_slice()) }
+ self.left = 0;
+ self.right = 0;
+ }
+
+ /// Get a reference to the contents of the chunk as a slice.
+ pub fn as_slice(&self) -> &[A] {
+ unsafe {
+ from_raw_parts(
+ (&self.data as *const MaybeUninit<N::SizedType> as *const A).add(self.left),
+ self.len(),
+ )
+ }
+ }
+
+ /// Get a reference to the contents of the chunk as a mutable slice.
+ pub fn as_mut_slice(&mut self) -> &mut [A] {
+ unsafe {
+ from_raw_parts_mut(
+ (&mut self.data as *mut MaybeUninit<N::SizedType> as *mut A).add(self.left),
+ self.len(),
+ )
+ }
+ }
+}
+
+impl<A, N> Default for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<A, N, I> Index<I> for Chunk<A, N>
+where
+ I: SliceIndex<[A]>,
+ N: ChunkLength<A>,
+{
+ type Output = I::Output;
+ fn index(&self, index: I) -> &Self::Output {
+ self.as_slice().index(index)
+ }
+}
+
+impl<A, N, I> IndexMut<I> for Chunk<A, N>
+where
+ I: SliceIndex<[A]>,
+ N: ChunkLength<A>,
+{
+ fn index_mut(&mut self, index: I) -> &mut Self::Output {
+ self.as_mut_slice().index_mut(index)
+ }
+}
+
+impl<A, N> Debug for Chunk<A, N>
+where
+ A: Debug,
+ N: ChunkLength<A>,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
+ f.write_str("Chunk")?;
+ f.debug_list().entries(self.iter()).finish()
+ }
+}
+
+impl<A, N> Hash for Chunk<A, N>
+where
+ A: Hash,
+ N: ChunkLength<A>,
+{
+ fn hash<H>(&self, hasher: &mut H)
+ where
+ H: Hasher,
+ {
+ for item in self {
+ item.hash(hasher)
+ }
+ }
+}
+
+impl<A, N, Slice> PartialEq<Slice> for Chunk<A, N>
+where
+ Slice: Borrow<[A]>,
+ A: PartialEq,
+ N: ChunkLength<A>,
+{
+ fn eq(&self, other: &Slice) -> bool {
+ self.as_slice() == other.borrow()
+ }
+}
+
+impl<A, N> Eq for Chunk<A, N>
+where
+ A: Eq,
+ N: ChunkLength<A>,
+{
+}
+
+impl<A, N> PartialOrd for Chunk<A, N>
+where
+ A: PartialOrd,
+ N: ChunkLength<A>,
+{
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.iter().partial_cmp(other.iter())
+ }
+}
+
+impl<A, N> Ord for Chunk<A, N>
+where
+ A: Ord,
+ N: ChunkLength<A>,
+{
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.iter().cmp(other.iter())
+ }
+}
+
+#[cfg(feature = "std")]
+impl<N> io::Write for Chunk<u8, N>
+where
+ N: ChunkLength<u8>,
+{
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let old_len = self.len();
+ self.extend(buf.iter().cloned().take(N::USIZE - old_len));
+ Ok(self.len() - old_len)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+#[cfg(feature = "std")]
+impl<N: ChunkLength<u8>> std::io::Read for Chunk<u8, N> {
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ let read_size = buf.len().min(self.len());
+ if read_size == 0 {
+ Ok(0)
+ } else {
+ for p in buf.iter_mut().take(read_size) {
+ *p = self.pop_front();
+ }
+ Ok(read_size)
+ }
+ }
+}
+
+impl<A, N, T> From<InlineArray<A, T>> for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ #[inline]
+ fn from(mut array: InlineArray<A, T>) -> Self {
+ Self::from(&mut array)
+ }
+}
+
+impl<'a, A, N, T> From<&'a mut InlineArray<A, T>> for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ fn from(array: &mut InlineArray<A, T>) -> Self {
+ // The first capacity comparison is to help optimize it out
+ assert!(
+ InlineArray::<A, T>::CAPACITY <= Self::CAPACITY || array.len() <= Self::CAPACITY,
+ "CAPACITY too small"
+ );
+ let mut out = Self::new();
+ out.left = 0;
+ out.right = array.len();
+ unsafe {
+ ptr::copy_nonoverlapping(array.data(), out.mut_ptr(0), out.right);
+ *array.len_mut() = 0;
+ }
+ out
+ }
+}
+
+impl<A, N> Borrow<[A]> for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ fn borrow(&self) -> &[A] {
+ self.as_slice()
+ }
+}
+
+impl<A, N> BorrowMut<[A]> for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ fn borrow_mut(&mut self) -> &mut [A] {
+ self.as_mut_slice()
+ }
+}
+
+impl<A, N> AsRef<[A]> for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ fn as_ref(&self) -> &[A] {
+ self.as_slice()
+ }
+}
+
+impl<A, N> AsMut<[A]> for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ fn as_mut(&mut self) -> &mut [A] {
+ self.as_mut_slice()
+ }
+}
+
+impl<A, N> Deref for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ type Target = [A];
+
+ fn deref(&self) -> &Self::Target {
+ self.as_slice()
+ }
+}
+
+impl<A, N> DerefMut for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.as_mut_slice()
+ }
+}
+
+impl<A, N> FromIterator<A> for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ fn from_iter<I>(it: I) -> Self
+ where
+ I: IntoIterator<Item = A>,
+ {
+ let mut chunk = Self::new();
+ for item in it {
+ chunk.push_back(item);
+ }
+ chunk
+ }
+}
+
+impl<'a, A, N> IntoIterator for &'a Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ type Item = &'a A;
+ type IntoIter = SliceIter<'a, A>;
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a, A, N> IntoIterator for &'a mut Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ type Item = &'a mut A;
+ type IntoIter = SliceIterMut<'a, A>;
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+impl<A, N> Extend<A> for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ /// Append the contents of the iterator to the back of the chunk.
+ ///
+ /// Panics if the chunk exceeds its capacity.
+ ///
+ /// Time: O(n) for the length of the iterator
+ fn extend<I>(&mut self, it: I)
+ where
+ I: IntoIterator<Item = A>,
+ {
+ for item in it {
+ self.push_back(item);
+ }
+ }
+}
+
+impl<'a, A, N> Extend<&'a A> for Chunk<A, N>
+where
+ A: 'a + Copy,
+ N: ChunkLength<A>,
+{
+ /// Append the contents of the iterator to the back of the chunk.
+ ///
+ /// Panics if the chunk exceeds its capacity.
+ ///
+ /// Time: O(n) for the length of the iterator
+ fn extend<I>(&mut self, it: I)
+ where
+ I: IntoIterator<Item = &'a A>,
+ {
+ for item in it {
+ self.push_back(*item);
+ }
+ }
+}
+
+impl<A, N> IntoIterator for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ type Item = A;
+ type IntoIter = Iter<A, N>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Iter { chunk: self }
+ }
+}
+
+#[cfg(test)]
+#[rustfmt::skip]
+mod test {
+ use super::*;
+ use typenum::{U0, U1, U2, U3, U5};
+
+ #[test]
+ #[should_panic(expected = "Chunk::push_back: can't push to full chunk")]
+ fn issue_11_testcase1d() {
+ let mut chunk = Chunk::<usize, U2>::pair(123, 456);
+ chunk.push_back(789);
+ }
+
+ #[test]
+ #[should_panic(expected = "CAPACITY too small")]
+ fn issue_11_testcase2a() {
+ let mut from = InlineArray::<u8, [u8; 256]>::new();
+ from.push(1);
+
+ let _ = Chunk::<u8, U0>::from(from);
+ }
+
+ #[test]
+ fn issue_11_testcase2b() {
+ let mut from = InlineArray::<u8, [u8; 256]>::new();
+ from.push(1);
+
+ let _ = Chunk::<u8, U1>::from(from);
+ }
+
+ struct DropDetector(u32);
+
+ impl DropDetector {
+ fn new(num: u32) -> Self {
+ DropDetector(num)
+ }
+ }
+
+ impl Drop for DropDetector {
+ fn drop(&mut self) {
+ assert!(self.0 == 42 || self.0 == 43);
+ }
+ }
+
+ impl Clone for DropDetector {
+ fn clone(&self) -> Self {
+ if self.0 == 42 {
+ panic!("panic on clone")
+ }
+ DropDetector::new(self.0)
+ }
+ }
+
+ /// This is for miri to catch
+ #[test]
+ fn issue_11_testcase3a() {
+ let mut chunk = Chunk::<DropDetector, U3>::new();
+ chunk.push_back(DropDetector::new(42));
+ chunk.push_back(DropDetector::new(42));
+ chunk.push_back(DropDetector::new(43));
+ let _ = chunk.pop_front();
+
+ let _ = std::panic::catch_unwind(|| {
+ let _ = chunk.clone();
+ });
+ }
+
+ struct PanickingIterator {
+ current: u32,
+ panic_at: u32,
+ len: usize,
+ }
+
+ impl Iterator for PanickingIterator {
+ type Item = DropDetector;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let num = self.current;
+
+ if num == self.panic_at {
+ panic!("panicking index")
+ }
+
+ self.current += 1;
+ Some(DropDetector::new(num))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len, Some(self.len))
+ }
+ }
+
+ impl ExactSizeIterator for PanickingIterator {}
+
+ #[test]
+ fn issue_11_testcase3b() {
+ let _ = std::panic::catch_unwind(|| {
+ let mut chunk = Chunk::<DropDetector, U5>::new();
+ chunk.push_back(DropDetector::new(1));
+ chunk.push_back(DropDetector::new(2));
+ chunk.push_back(DropDetector::new(3));
+
+ chunk.insert_from(
+ 1,
+ PanickingIterator {
+ current: 1,
+ panic_at: 1,
+ len: 1,
+ },
+ );
+ });
+ }
+
+ struct FakeSizeIterator { reported: usize, actual: usize }
+ impl Iterator for FakeSizeIterator {
+ type Item = u8;
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.actual == 0 {
+ None
+ } else {
+ self.actual -= 1;
+ Some(1)
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.reported, Some(self.reported))
+ }
+ }
+
+ impl ExactSizeIterator for FakeSizeIterator {
+ fn len(&self) -> usize {
+ self.reported
+ }
+ }
+
+ #[test]
+ fn iterator_too_long() {
+ let mut chunk = Chunk::<u8, U5>::new();
+ chunk.push_back(0);
+ chunk.push_back(1);
+ chunk.push_back(2);
+ chunk.insert_from(1, FakeSizeIterator { reported: 1, actual: 10 });
+
+ let mut chunk = Chunk::<u8, U5>::new();
+ chunk.push_back(1);
+ chunk.insert_from(0, FakeSizeIterator { reported: 1, actual: 10 });
+
+ let mut chunk = Chunk::<u8, U5>::new();
+ chunk.insert_from(0, FakeSizeIterator { reported: 1, actual: 10 });
+ }
+
+ #[test]
+ #[should_panic(expected = "ExactSizeIterator yielded fewer values than advertised")]
+ fn iterator_too_short1() {
+ let mut chunk = Chunk::<u8, U5>::new();
+ chunk.push_back(0);
+ chunk.push_back(1);
+ chunk.push_back(2);
+ chunk.insert_from(1, FakeSizeIterator { reported: 2, actual: 0 });
+ }
+
+ #[test]
+ #[should_panic(expected = "ExactSizeIterator yielded fewer values than advertised")]
+ fn iterator_too_short2() {
+ let mut chunk = Chunk::<u8, U5>::new();
+ chunk.push_back(1);
+ chunk.insert_from(1, FakeSizeIterator { reported: 4, actual: 2 });
+ }
+
+ #[test]
+ fn is_full() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 0..64 {
+ assert_eq!(false, chunk.is_full());
+ chunk.push_back(i);
+ }
+ assert_eq!(true, chunk.is_full());
+ }
+
+ #[test]
+ fn push_back_front() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 12..20 {
+ chunk.push_back(i);
+ }
+ assert_eq!(8, chunk.len());
+ for i in (0..12).rev() {
+ chunk.push_front(i);
+ }
+ assert_eq!(20, chunk.len());
+ for i in 20..32 {
+ chunk.push_back(i);
+ }
+ assert_eq!(32, chunk.len());
+ let right: Vec<i32> = chunk.into_iter().collect();
+ let left: Vec<i32> = (0..32).collect();
+ assert_eq!(left, right);
+ }
+
+ #[test]
+ fn push_and_pop() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 0..64 {
+ chunk.push_back(i);
+ }
+ for i in 0..64 {
+ assert_eq!(i, chunk.pop_front());
+ }
+ for i in 0..64 {
+ chunk.push_front(i);
+ }
+ for i in 0..64 {
+ assert_eq!(i, chunk.pop_back());
+ }
+ }
+
+ #[test]
+ fn drop_left() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 0..6 {
+ chunk.push_back(i);
+ }
+ chunk.drop_left(3);
+ let vec: Vec<i32> = chunk.into_iter().collect();
+ assert_eq!(vec![3, 4, 5], vec);
+ }
+
+ #[test]
+ fn drop_right() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 0..6 {
+ chunk.push_back(i);
+ }
+ chunk.drop_right(3);
+ let vec: Vec<i32> = chunk.into_iter().collect();
+ assert_eq!(vec![0, 1, 2], vec);
+ }
+
+ #[test]
+ fn split_off() {
+ let mut left = Chunk::<_, U64>::new();
+ for i in 0..6 {
+ left.push_back(i);
+ }
+ let right = left.split_off(3);
+ let left_vec: Vec<i32> = left.into_iter().collect();
+ let right_vec: Vec<i32> = right.into_iter().collect();
+ assert_eq!(vec![0, 1, 2], left_vec);
+ assert_eq!(vec![3, 4, 5], right_vec);
+ }
+
+ #[test]
+ fn append() {
+ let mut left = Chunk::<_, U64>::new();
+ for i in 0..32 {
+ left.push_back(i);
+ }
+ let mut right = Chunk::<_, U64>::new();
+ for i in (32..64).rev() {
+ right.push_front(i);
+ }
+ left.append(&mut right);
+ let out_vec: Vec<i32> = left.into_iter().collect();
+ let should_vec: Vec<i32> = (0..64).collect();
+ assert_eq!(should_vec, out_vec);
+ }
+
+ #[test]
+ fn ref_iter() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 0..64 {
+ chunk.push_back(i);
+ }
+ let out_vec: Vec<&i32> = chunk.iter().collect();
+ let should_vec_p: Vec<i32> = (0..64).collect();
+ let should_vec: Vec<&i32> = should_vec_p.iter().collect();
+ assert_eq!(should_vec, out_vec);
+ }
+
+ #[test]
+ fn mut_ref_iter() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 0..64 {
+ chunk.push_back(i);
+ }
+ let out_vec: Vec<&mut i32> = chunk.iter_mut().collect();
+ let mut should_vec_p: Vec<i32> = (0..64).collect();
+ let should_vec: Vec<&mut i32> = should_vec_p.iter_mut().collect();
+ assert_eq!(should_vec, out_vec);
+ }
+
+ #[test]
+ fn consuming_iter() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 0..64 {
+ chunk.push_back(i);
+ }
+ let out_vec: Vec<i32> = chunk.into_iter().collect();
+ let should_vec: Vec<i32> = (0..64).collect();
+ assert_eq!(should_vec, out_vec);
+ }
+
+ #[test]
+ fn insert_middle() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 0..32 {
+ chunk.push_back(i);
+ }
+ for i in 33..64 {
+ chunk.push_back(i);
+ }
+ chunk.insert(32, 32);
+ let out_vec: Vec<i32> = chunk.into_iter().collect();
+ let should_vec: Vec<i32> = (0..64).collect();
+ assert_eq!(should_vec, out_vec);
+ }
+
+ #[test]
+ fn insert_back() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 0..63 {
+ chunk.push_back(i);
+ }
+ chunk.insert(63, 63);
+ let out_vec: Vec<i32> = chunk.into_iter().collect();
+ let should_vec: Vec<i32> = (0..64).collect();
+ assert_eq!(should_vec, out_vec);
+ }
+
+ #[test]
+ fn insert_front() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 1..64 {
+ chunk.push_front(64 - i);
+ }
+ chunk.insert(0, 0);
+ let out_vec: Vec<i32> = chunk.into_iter().collect();
+ let should_vec: Vec<i32> = (0..64).collect();
+ assert_eq!(should_vec, out_vec);
+ }
+
+ #[test]
+ fn remove_value() {
+ let mut chunk = Chunk::<_, U64>::new();
+ for i in 0..64 {
+ chunk.push_back(i);
+ }
+ chunk.remove(32);
+ let out_vec: Vec<i32> = chunk.into_iter().collect();
+ let should_vec: Vec<i32> = (0..32).chain(33..64).collect();
+ assert_eq!(should_vec, out_vec);
+ }
+
+ use crate::tests::DropTest;
+ use std::sync::atomic::{AtomicUsize, Ordering};
+
+ #[test]
+ fn dropping() {
+ let counter = AtomicUsize::new(0);
+ {
+ let mut chunk: Chunk<DropTest<'_>> = Chunk::new();
+ for _i in 0..20 {
+ chunk.push_back(DropTest::new(&counter))
+ }
+ for _i in 0..20 {
+ chunk.push_front(DropTest::new(&counter))
+ }
+ assert_eq!(40, counter.load(Ordering::Relaxed));
+ for _i in 0..10 {
+ chunk.pop_back();
+ }
+ assert_eq!(30, counter.load(Ordering::Relaxed));
+ }
+ assert_eq!(0, counter.load(Ordering::Relaxed));
+ }
+
+ #[test]
+ #[should_panic(expected = "assertion failed: Self::CAPACITY >= 1")]
+ fn unit_on_empty() {
+ Chunk::<usize, U0>::unit(1);
+ }
+
+ #[test]
+ #[should_panic(expected = "assertion failed: Self::CAPACITY >= 2")]
+ fn pair_on_empty() {
+ Chunk::<usize, U0>::pair(1, 2);
+ }
+}
diff --git a/vendor/sized-chunks/src/sized_chunk/refpool.rs b/vendor/sized-chunks/src/sized_chunk/refpool.rs
new file mode 100644
index 0000000..9396ff6
--- /dev/null
+++ b/vendor/sized-chunks/src/sized_chunk/refpool.rs
@@ -0,0 +1,66 @@
+use core::mem::MaybeUninit;
+
+use ::refpool::{PoolClone, PoolDefault};
+
+use crate::types::ChunkLength;
+use crate::Chunk;
+
+impl<A, N> PoolDefault for Chunk<A, N>
+where
+ N: ChunkLength<A>,
+{
+ unsafe fn default_uninit(target: &mut MaybeUninit<Self>) {
+ let ptr = target.as_mut_ptr();
+ let left_ptr: *mut usize = &mut (*ptr).left;
+ let right_ptr: *mut usize = &mut (*ptr).right;
+ left_ptr.write(0);
+ right_ptr.write(0);
+ }
+}
+
+impl<A, N> PoolClone for Chunk<A, N>
+where
+ A: Clone,
+ N: ChunkLength<A>,
+{
+ unsafe fn clone_uninit(&self, target: &mut MaybeUninit<Self>) {
+ let ptr = target.as_mut_ptr();
+ let left_ptr: *mut usize = &mut (*ptr).left;
+ let right_ptr: *mut usize = &mut (*ptr).right;
+ let data_ptr: *mut _ = &mut (*ptr).data;
+ let data_ptr: *mut A = (*data_ptr).as_mut_ptr().cast();
+ left_ptr.write(self.left);
+ right_ptr.write(self.right);
+ for index in self.left..self.right {
+ data_ptr.add(index).write((*self.ptr(index)).clone());
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use ::refpool::{Pool, PoolRef};
+ use std::iter::FromIterator;
+
+ #[test]
+ fn default_and_clone() {
+ let pool: Pool<Chunk<usize>> = Pool::new(16);
+ let mut ref1 = PoolRef::default(&pool);
+ {
+ let chunk = PoolRef::make_mut(&pool, &mut ref1);
+ chunk.push_back(1);
+ chunk.push_back(2);
+ chunk.push_back(3);
+ }
+ let ref2 = PoolRef::cloned(&pool, &ref1);
+ let ref3 = PoolRef::clone_from(&pool, &Chunk::from_iter(1..=3));
+ assert_eq!(Chunk::<usize>::from_iter(1..=3), *ref1);
+ assert_eq!(Chunk::<usize>::from_iter(1..=3), *ref2);
+ assert_eq!(Chunk::<usize>::from_iter(1..=3), *ref3);
+ assert_eq!(ref1, ref2);
+ assert_eq!(ref1, ref3);
+ assert_eq!(ref2, ref3);
+ assert!(!PoolRef::ptr_eq(&ref1, &ref2));
+ }
+}
diff --git a/vendor/sized-chunks/src/sparse_chunk/iter.rs b/vendor/sized-chunks/src/sparse_chunk/iter.rs
new file mode 100644
index 0000000..460096c
--- /dev/null
+++ b/vendor/sized-chunks/src/sparse_chunk/iter.rs
@@ -0,0 +1,245 @@
+use bitmaps::{Bitmap, Bits, Iter as BitmapIter};
+
+use super::SparseChunk;
+use crate::types::ChunkLength;
+
+/// An iterator over references to the elements of a `SparseChunk`.
+pub struct Iter<'a, A, N: Bits + ChunkLength<A>> {
+ pub(crate) indices: BitmapIter<'a, N>,
+ pub(crate) chunk: &'a SparseChunk<A, N>,
+}
+
+impl<'a, A, N: Bits + ChunkLength<A>> Iterator for Iter<'a, A, N> {
+ type Item = &'a A;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.indices.next().map(|index| &self.chunk.values()[index])
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (0, Some(SparseChunk::<A, N>::CAPACITY))
+ }
+}
+
+/// An iterator over mutable references to the elements of a `SparseChunk`.
+pub struct IterMut<'a, A, N: Bits + ChunkLength<A>> {
+ pub(crate) bitmap: Bitmap<N>,
+ pub(crate) chunk: &'a mut SparseChunk<A, N>,
+}
+
+impl<'a, A, N: Bits + ChunkLength<A>> Iterator for IterMut<'a, A, N> {
+ type Item = &'a mut A;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if let Some(index) = self.bitmap.first_index() {
+ self.bitmap.set(index, false);
+ unsafe {
+ let p: *mut A = &mut self.chunk.values_mut()[index];
+ Some(&mut *p)
+ }
+ } else {
+ None
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (0, Some(SparseChunk::<A, N>::CAPACITY))
+ }
+}
+
+/// A draining iterator over the elements of a `SparseChunk`.
+///
+/// "Draining" means that as the iterator yields each element, it's removed from
+/// the `SparseChunk`. When the iterator terminates, the chunk will be empty.
+pub struct Drain<A, N: Bits + ChunkLength<A>> {
+ pub(crate) chunk: SparseChunk<A, N>,
+}
+
+impl<'a, A, N: Bits + ChunkLength<A>> Iterator for Drain<A, N> {
+ type Item = A;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.chunk.pop()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.chunk.len();
+ (len, Some(len))
+ }
+}
+
+/// An iterator over `Option`s of references to the elements of a `SparseChunk`.
+///
+/// Iterates over every index in the `SparseChunk`, from zero to its full capacity,
+/// returning an `Option<&A>` for each index.
+pub struct OptionIter<'a, A, N: Bits + ChunkLength<A>> {
+ pub(crate) index: usize,
+ pub(crate) chunk: &'a SparseChunk<A, N>,
+}
+
+impl<'a, A, N: Bits + ChunkLength<A>> Iterator for OptionIter<'a, A, N> {
+ type Item = Option<&'a A>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.index < N::USIZE {
+ let result = self.chunk.get(self.index);
+ self.index += 1;
+ Some(result)
+ } else {
+ None
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (
+ SparseChunk::<A, N>::CAPACITY - self.index,
+ Some(SparseChunk::<A, N>::CAPACITY - self.index),
+ )
+ }
+}
+
+/// An iterator over `Option`s of mutable references to the elements of a `SparseChunk`.
+///
+/// Iterates over every index in the `SparseChunk`, from zero to its full capacity,
+/// returning an `Option<&mut A>` for each index.
+pub struct OptionIterMut<'a, A, N: Bits + ChunkLength<A>> {
+ pub(crate) index: usize,
+ pub(crate) chunk: &'a mut SparseChunk<A, N>,
+}
+
+impl<'a, A, N: Bits + ChunkLength<A>> Iterator for OptionIterMut<'a, A, N> {
+ type Item = Option<&'a mut A>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.index < N::USIZE {
+ let result = if self.chunk.map.get(self.index) {
+ unsafe {
+ let p: *mut A = &mut self.chunk.values_mut()[self.index];
+ Some(Some(&mut *p))
+ }
+ } else {
+ Some(None)
+ };
+ self.index += 1;
+ result
+ } else {
+ None
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (
+ SparseChunk::<A, N>::CAPACITY - self.index,
+ Some(SparseChunk::<A, N>::CAPACITY - self.index),
+ )
+ }
+}
+
+/// A draining iterator over `Option`s of the elements of a `SparseChunk`.
+///
+/// Iterates over every index in the `SparseChunk`, from zero to its full capacity,
+/// returning an `Option<A>` for each index.
+pub struct OptionDrain<A, N: Bits + ChunkLength<A>> {
+ pub(crate) index: usize,
+ pub(crate) chunk: SparseChunk<A, N>,
+}
+
+impl<'a, A, N: Bits + ChunkLength<A>> Iterator for OptionDrain<A, N> {
+ type Item = Option<A>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.index < N::USIZE {
+ let result = self.chunk.remove(self.index);
+ self.index += 1;
+ Some(result)
+ } else {
+ None
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (
+ SparseChunk::<A, N>::CAPACITY - self.index,
+ Some(SparseChunk::<A, N>::CAPACITY - self.index),
+ )
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::iter::FromIterator;
+ use typenum::U64;
+
+ #[test]
+ fn iter() {
+ let vec: Vec<Option<usize>> =
+ Vec::from_iter((0..64).map(|i| if i % 2 == 0 { Some(i) } else { None }));
+ let chunk: SparseChunk<usize, U64> = vec.iter().cloned().collect();
+ let vec: Vec<usize> = vec
+ .iter()
+ .cloned()
+ .filter(|v| v.is_some())
+ .map(|v| v.unwrap())
+ .collect();
+ assert!(vec.iter().eq(chunk.iter()));
+ }
+
+ #[test]
+ fn iter_mut() {
+ let vec: Vec<Option<usize>> =
+ Vec::from_iter((0..64).map(|i| if i % 2 == 0 { Some(i) } else { None }));
+ let mut chunk: SparseChunk<_, U64> = vec.iter().cloned().collect();
+ let mut vec: Vec<usize> = vec
+ .iter()
+ .cloned()
+ .filter(|v| v.is_some())
+ .map(|v| v.unwrap())
+ .collect();
+ assert!(vec.iter_mut().eq(chunk.iter_mut()));
+ }
+
+ #[test]
+ fn drain() {
+ let vec: Vec<Option<usize>> =
+ Vec::from_iter((0..64).map(|i| if i % 2 == 0 { Some(i) } else { None }));
+ let chunk: SparseChunk<_, U64> = vec.iter().cloned().collect();
+ let vec: Vec<usize> = vec
+ .iter()
+ .cloned()
+ .filter(|v| v.is_some())
+ .map(|v| v.unwrap())
+ .collect();
+ assert!(vec.into_iter().eq(chunk.into_iter()));
+ }
+
+ #[test]
+ fn option_iter() {
+ let vec: Vec<Option<usize>> =
+ Vec::from_iter((0..64).map(|i| if i % 2 == 0 { Some(i) } else { None }));
+ let chunk: SparseChunk<_, U64> = vec.iter().cloned().collect();
+ assert!(vec
+ .iter()
+ .cloned()
+ .eq(chunk.option_iter().map(|v| v.cloned())));
+ }
+
+ #[test]
+ fn option_iter_mut() {
+ let vec: Vec<Option<usize>> =
+ Vec::from_iter((0..64).map(|i| if i % 2 == 0 { Some(i) } else { None }));
+ let mut chunk: SparseChunk<_, U64> = vec.iter().cloned().collect();
+ assert!(vec
+ .iter()
+ .cloned()
+ .eq(chunk.option_iter_mut().map(|v| v.cloned())));
+ }
+
+ #[test]
+ fn option_drain() {
+ let vec: Vec<Option<usize>> =
+ Vec::from_iter((0..64).map(|i| if i % 2 == 0 { Some(i) } else { None }));
+ let chunk: SparseChunk<_, U64> = vec.iter().cloned().collect();
+ assert!(vec.iter().cloned().eq(chunk.option_drain()));
+ }
+}
diff --git a/vendor/sized-chunks/src/sparse_chunk/mod.rs b/vendor/sized-chunks/src/sparse_chunk/mod.rs
new file mode 100644
index 0000000..455f167
--- /dev/null
+++ b/vendor/sized-chunks/src/sparse_chunk/mod.rs
@@ -0,0 +1,514 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+//! A fixed capacity sparse array.
+//!
+//! See [`SparseChunk`](struct.SparseChunk.html)
+
+use core::fmt::{Debug, Error, Formatter};
+use core::iter::FromIterator;
+use core::mem::{self, MaybeUninit};
+use core::ops::Index;
+use core::ops::IndexMut;
+use core::ptr;
+use core::slice::{from_raw_parts, from_raw_parts_mut};
+
+#[cfg(feature = "std")]
+use std::collections::{BTreeMap, HashMap};
+
+use typenum::U64;
+
+use bitmaps::{Bitmap, Bits, Iter as BitmapIter};
+
+use crate::types::ChunkLength;
+
+mod iter;
+pub use self::iter::{Drain, Iter, IterMut, OptionDrain, OptionIter, OptionIterMut};
+
+#[cfg(feature = "refpool")]
+mod refpool;
+
+/// A fixed capacity sparse array.
+///
+/// An inline sparse array of up to `N` items of type `A`, where `N` is an
+/// [`Unsigned`][Unsigned] type level numeral. You can think of it as an array
+/// of `Option<A>`, where the discriminant (whether the value is `Some<A>` or
+/// `None`) is kept in a bitmap instead of adjacent to the value.
+///
+/// Because the bitmap is kept in a primitive type, the maximum value of `N` is
+/// currently 128, corresponding to a type of `u128`. The type of the bitmap
+/// will be the minimum unsigned integer type required to fit the number of bits
+/// required. Thus, disregarding memory alignment rules, the allocated size of a
+/// `SparseChunk` will be `uX` + `A` * `N` where `uX` is the type of the
+/// discriminant bitmap, either `u8`, `u16`, `u32`, `u64` or `u128`.
+///
+/// # Examples
+///
+/// ```rust
+/// # #[macro_use] extern crate sized_chunks;
+/// # extern crate typenum;
+/// # use sized_chunks::SparseChunk;
+/// # use typenum::U20;
+/// // Construct a chunk with a 20 item capacity
+/// let mut chunk = SparseChunk::<i32, U20>::new();
+/// // Set the 18th index to the value 5.
+/// chunk.insert(18, 5);
+/// // Set the 5th index to the value 23.
+/// chunk.insert(5, 23);
+///
+/// assert_eq!(chunk.len(), 2);
+/// assert_eq!(chunk.get(5), Some(&23));
+/// assert_eq!(chunk.get(6), None);
+/// assert_eq!(chunk.get(18), Some(&5));
+/// ```
+///
+/// [Unsigned]: https://docs.rs/typenum/1.10.0/typenum/marker_traits/trait.Unsigned.html
+pub struct SparseChunk<A, N: Bits + ChunkLength<A> = U64> {
+ map: Bitmap<N>,
+ data: MaybeUninit<N::SizedType>,
+}
+
+impl<A, N: Bits + ChunkLength<A>> Drop for SparseChunk<A, N> {
+ fn drop(&mut self) {
+ if mem::needs_drop::<A>() {
+ let bits = self.map;
+ for index in &bits {
+ unsafe { ptr::drop_in_place(&mut self.values_mut()[index]) }
+ }
+ }
+ }
+}
+
+impl<A: Clone, N: Bits + ChunkLength<A>> Clone for SparseChunk<A, N> {
+ fn clone(&self) -> Self {
+ let mut out = Self::new();
+ for index in &self.map {
+ out.insert(index, self[index].clone());
+ }
+ out
+ }
+}
+
+impl<A, N> SparseChunk<A, N>
+where
+ N: Bits + ChunkLength<A>,
+{
+ /// The maximum number of elements a `SparseChunk` can contain.
+ pub const CAPACITY: usize = N::USIZE;
+
+ #[inline]
+ fn values(&self) -> &[A] {
+ unsafe { from_raw_parts(&self.data as *const _ as *const A, N::USIZE) }
+ }
+
+ #[inline]
+ fn values_mut(&mut self) -> &mut [A] {
+ unsafe { from_raw_parts_mut(&mut self.data as *mut _ as *mut A, N::USIZE) }
+ }
+
+ /// Copy the value at an index, discarding ownership of the copied value
+ #[inline]
+ unsafe fn force_read(index: usize, chunk: &Self) -> A {
+ ptr::read(&chunk.values()[index as usize])
+ }
+
+ /// Write a value at an index without trying to drop what's already there
+ #[inline]
+ unsafe fn force_write(index: usize, value: A, chunk: &mut Self) {
+ ptr::write(&mut chunk.values_mut()[index as usize], value)
+ }
+
+ /// Construct a new empty chunk.
+ pub fn new() -> Self {
+ Self {
+ map: Bitmap::default(),
+ data: MaybeUninit::uninit(),
+ }
+ }
+
+ /// Construct a new chunk with one item.
+ pub fn unit(index: usize, value: A) -> Self {
+ let mut chunk = Self::new();
+ chunk.insert(index, value);
+ chunk
+ }
+
+ /// Construct a new chunk with two items.
+ pub fn pair(index1: usize, value1: A, index2: usize, value2: A) -> Self {
+ let mut chunk = Self::new();
+ chunk.insert(index1, value1);
+ chunk.insert(index2, value2);
+ chunk
+ }
+
+ /// Get the length of the chunk.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.map.len()
+ }
+
+ /// Test if the chunk is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.map.len() == 0
+ }
+
+ /// Test if the chunk is at capacity.
+ #[inline]
+ pub fn is_full(&self) -> bool {
+ self.len() == N::USIZE
+ }
+
+ /// Insert a new value at a given index.
+ ///
+ /// Returns the previous value at that index, if any.
+ pub fn insert(&mut self, index: usize, value: A) -> Option<A> {
+ if index >= N::USIZE {
+ panic!("SparseChunk::insert: index out of bounds");
+ }
+ if self.map.set(index, true) {
+ Some(mem::replace(&mut self.values_mut()[index], value))
+ } else {
+ unsafe { SparseChunk::force_write(index, value, self) };
+ None
+ }
+ }
+
+ /// Remove the value at a given index.
+ ///
+ /// Returns the value, or `None` if the index had no value.
+ pub fn remove(&mut self, index: usize) -> Option<A> {
+ if index >= N::USIZE {
+ panic!("SparseChunk::remove: index out of bounds");
+ }
+ if self.map.set(index, false) {
+ Some(unsafe { SparseChunk::force_read(index, self) })
+ } else {
+ None
+ }
+ }
+
+ /// Remove the first value present in the array.
+ ///
+ /// Returns the value that was removed, or `None` if the array was empty.
+ pub fn pop(&mut self) -> Option<A> {
+ self.first_index().and_then(|index| self.remove(index))
+ }
+
+ /// Get the value at a given index.
+ pub fn get(&self, index: usize) -> Option<&A> {
+ if index >= N::USIZE {
+ return None;
+ }
+ if self.map.get(index) {
+ Some(unsafe { self.get_unchecked(index) })
+ } else {
+ None
+ }
+ }
+
+ /// Get a mutable reference to the value at a given index.
+ pub fn get_mut(&mut self, index: usize) -> Option<&mut A> {
+ if index >= N::USIZE {
+ return None;
+ }
+ if self.map.get(index) {
+ Some(unsafe { self.get_unchecked_mut(index) })
+ } else {
+ None
+ }
+ }
+
+ /// Get an unchecked reference to the value at a given index.
+ ///
+ /// # Safety
+ ///
+ /// Uninhabited indices contain uninitialised data, so make sure you validate
+ /// the index before using this method.
+ pub unsafe fn get_unchecked(&self, index: usize) -> &A {
+ self.values().get_unchecked(index)
+ }
+
+ /// Get an unchecked mutable reference to the value at a given index.
+ ///
+ /// # Safety
+ ///
+ /// Uninhabited indices contain uninitialised data, so make sure you validate
+ /// the index before using this method.
+ pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut A {
+ self.values_mut().get_unchecked_mut(index)
+ }
+
+ /// Make an iterator over the indices which contain values.
+ pub fn indices(&self) -> BitmapIter<'_, N> {
+ self.map.into_iter()
+ }
+
+ /// Find the first index which contains a value.
+ pub fn first_index(&self) -> Option<usize> {
+ self.map.first_index()
+ }
+
+ /// Make an iterator of references to the values contained in the array.
+ pub fn iter(&self) -> Iter<'_, A, N> {
+ Iter {
+ indices: self.indices(),
+ chunk: self,
+ }
+ }
+
+ /// Make an iterator of mutable references to the values contained in the
+ /// array.
+ pub fn iter_mut(&mut self) -> IterMut<'_, A, N> {
+ IterMut {
+ bitmap: self.map,
+ chunk: self,
+ }
+ }
+
+ /// Turn the chunk into an iterator over the values contained within it.
+ pub fn drain(self) -> Drain<A, N> {
+ Drain { chunk: self }
+ }
+
+ /// Make an iterator of pairs of indices and references to the values
+ /// contained in the array.
+ pub fn entries(&self) -> impl Iterator<Item = (usize, &A)> {
+ self.indices().zip(self.iter())
+ }
+
+ /// Make an iterator of `Option`s of references to the values contained in the array.
+ ///
+ /// Iterates over every index in the `SparseChunk`, from zero to its full capacity,
+ /// returning an `Option<&A>` for each index.
+ pub fn option_iter(&self) -> OptionIter<'_, A, N> {
+ OptionIter {
+ chunk: self,
+ index: 0,
+ }
+ }
+
+ /// Make an iterator of `Option`s of mutable references to the values contained in the array.
+ ///
+ /// Iterates over every index in the `SparseChunk`, from zero to its full capacity,
+ /// returning an `Option<&mut A>` for each index.
+ pub fn option_iter_mut(&mut self) -> OptionIterMut<'_, A, N> {
+ OptionIterMut {
+ chunk: self,
+ index: 0,
+ }
+ }
+
+ /// Make a draining iterator of `Option's of the values contained in the array.
+ ///
+ /// Iterates over every index in the `SparseChunk`, from zero to its full capacity,
+ /// returning an `Option<A>` for each index.
+ pub fn option_drain(self) -> OptionDrain<A, N> {
+ OptionDrain {
+ chunk: self,
+ index: 0,
+ }
+ }
+}
+
+impl<A, N: Bits + ChunkLength<A>> Default for SparseChunk<A, N> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<A, N: Bits + ChunkLength<A>> Index<usize> for SparseChunk<A, N> {
+ type Output = A;
+
+ #[inline]
+ fn index(&self, index: usize) -> &Self::Output {
+ self.get(index).unwrap()
+ }
+}
+
+impl<A, N: Bits + ChunkLength<A>> IndexMut<usize> for SparseChunk<A, N> {
+ #[inline]
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ self.get_mut(index).unwrap()
+ }
+}
+
+impl<A, N: Bits + ChunkLength<A>> IntoIterator for SparseChunk<A, N> {
+ type Item = A;
+ type IntoIter = Drain<A, N>;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.drain()
+ }
+}
+
+impl<A, N: Bits + ChunkLength<A>> FromIterator<Option<A>> for SparseChunk<A, N> {
+ fn from_iter<I>(iter: I) -> Self
+ where
+ I: IntoIterator<Item = Option<A>>,
+ {
+ let mut out = Self::new();
+ for (index, value) in iter.into_iter().enumerate() {
+ if let Some(value) = value {
+ out.insert(index, value);
+ }
+ }
+ out
+ }
+}
+
+impl<A, N> PartialEq for SparseChunk<A, N>
+where
+ A: PartialEq,
+ N: Bits + ChunkLength<A>,
+{
+ fn eq(&self, other: &Self) -> bool {
+ if self.map != other.map {
+ return false;
+ }
+ for index in self.indices() {
+ if self.get(index) != other.get(index) {
+ return false;
+ }
+ }
+ true
+ }
+}
+
+#[cfg(feature = "std")]
+impl<A, N> PartialEq<BTreeMap<usize, A>> for SparseChunk<A, N>
+where
+ A: PartialEq,
+ N: Bits + ChunkLength<A>,
+{
+ fn eq(&self, other: &BTreeMap<usize, A>) -> bool {
+ if self.len() != other.len() {
+ return false;
+ }
+ for index in self.indices() {
+ if self.get(index) != other.get(&index) {
+ return false;
+ }
+ }
+ true
+ }
+}
+
+#[cfg(feature = "std")]
+impl<A, N> PartialEq<HashMap<usize, A>> for SparseChunk<A, N>
+where
+ A: PartialEq,
+ N: Bits + ChunkLength<A>,
+{
+ fn eq(&self, other: &HashMap<usize, A>) -> bool {
+ if self.len() != other.len() {
+ return false;
+ }
+ for index in self.indices() {
+ if self.get(index) != other.get(&index) {
+ return false;
+ }
+ }
+ true
+ }
+}
+
+impl<A, N> Eq for SparseChunk<A, N>
+where
+ A: Eq,
+ N: Bits + ChunkLength<A>,
+{
+}
+
+impl<A, N> Debug for SparseChunk<A, N>
+where
+ A: Debug,
+ N: Bits + ChunkLength<A>,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
+ f.write_str("SparseChunk")?;
+ f.debug_map().entries(self.entries()).finish()
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use typenum::U32;
+
+ #[test]
+ fn insert_remove_iterate() {
+ let mut chunk: SparseChunk<_, U32> = SparseChunk::new();
+ assert_eq!(None, chunk.insert(5, 5));
+ assert_eq!(None, chunk.insert(1, 1));
+ assert_eq!(None, chunk.insert(24, 42));
+ assert_eq!(None, chunk.insert(22, 22));
+ assert_eq!(Some(42), chunk.insert(24, 24));
+ assert_eq!(None, chunk.insert(31, 31));
+ assert_eq!(Some(24), chunk.remove(24));
+ assert_eq!(4, chunk.len());
+ let indices: Vec<_> = chunk.indices().collect();
+ assert_eq!(vec![1, 5, 22, 31], indices);
+ let values: Vec<_> = chunk.into_iter().collect();
+ assert_eq!(vec![1, 5, 22, 31], values);
+ }
+
+ #[test]
+ fn clone_chunk() {
+ let mut chunk: SparseChunk<_, U32> = SparseChunk::new();
+ assert_eq!(None, chunk.insert(5, 5));
+ assert_eq!(None, chunk.insert(1, 1));
+ assert_eq!(None, chunk.insert(24, 42));
+ assert_eq!(None, chunk.insert(22, 22));
+ let cloned = chunk.clone();
+ let right_indices: Vec<_> = chunk.indices().collect();
+ let left_indices: Vec<_> = cloned.indices().collect();
+ let right: Vec<_> = chunk.into_iter().collect();
+ let left: Vec<_> = cloned.into_iter().collect();
+ assert_eq!(left, right);
+ assert_eq!(left_indices, right_indices);
+ assert_eq!(vec![1, 5, 22, 24], left_indices);
+ assert_eq!(vec![1, 5, 22, 24], right_indices);
+ }
+
+ use crate::tests::DropTest;
+ use std::sync::atomic::{AtomicUsize, Ordering};
+
+ #[test]
+ fn dropping() {
+ let counter = AtomicUsize::new(0);
+ {
+ let mut chunk: SparseChunk<DropTest<'_>> = SparseChunk::new();
+ for i in 0..40 {
+ chunk.insert(i, DropTest::new(&counter));
+ }
+ assert_eq!(40, counter.load(Ordering::Relaxed));
+ for i in 0..20 {
+ chunk.remove(i);
+ }
+ assert_eq!(20, counter.load(Ordering::Relaxed));
+ }
+ assert_eq!(0, counter.load(Ordering::Relaxed));
+ }
+
+ #[test]
+ fn equality() {
+ let mut c1 = SparseChunk::<usize>::new();
+ for i in 0..32 {
+ c1.insert(i, i);
+ }
+ let mut c2 = c1.clone();
+ assert_eq!(c1, c2);
+ for i in 4..8 {
+ c2.insert(i, 0);
+ }
+ assert_ne!(c1, c2);
+ c2 = c1.clone();
+ for i in 0..16 {
+ c2.remove(i);
+ }
+ assert_ne!(c1, c2);
+ }
+}
diff --git a/vendor/sized-chunks/src/sparse_chunk/refpool.rs b/vendor/sized-chunks/src/sparse_chunk/refpool.rs
new file mode 100644
index 0000000..ca6379e
--- /dev/null
+++ b/vendor/sized-chunks/src/sparse_chunk/refpool.rs
@@ -0,0 +1,57 @@
+use core::mem::MaybeUninit;
+
+use bitmaps::{Bitmap, Bits};
+
+use ::refpool::{PoolClone, PoolDefault};
+
+use crate::types::ChunkLength;
+use crate::SparseChunk;
+
+impl<A, N> PoolDefault for SparseChunk<A, N>
+where
+ N: Bits + ChunkLength<A>,
+{
+ unsafe fn default_uninit(target: &mut MaybeUninit<Self>) {
+ let ptr = target.as_mut_ptr();
+ let map_ptr: *mut Bitmap<N> = &mut (*ptr).map;
+ map_ptr.write(Bitmap::new());
+ }
+}
+
+impl<A, N> PoolClone for SparseChunk<A, N>
+where
+ A: Clone,
+ N: Bits + ChunkLength<A>,
+{
+ unsafe fn clone_uninit(&self, target: &mut MaybeUninit<Self>) {
+ let ptr = target.as_mut_ptr();
+ let map_ptr: *mut Bitmap<N> = &mut (*ptr).map;
+ let data_ptr: *mut _ = &mut (*ptr).data;
+ let data_ptr: *mut A = (*data_ptr).as_mut_ptr().cast();
+ map_ptr.write(self.map);
+ for index in &self.map {
+ data_ptr.add(index).write(self[index].clone());
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use ::refpool::{Pool, PoolRef};
+
+ #[test]
+ fn default_and_clone() {
+ let pool: Pool<SparseChunk<usize>> = Pool::new(16);
+ let mut ref1 = PoolRef::default(&pool);
+ {
+ let chunk = PoolRef::make_mut(&pool, &mut ref1);
+ chunk.insert(5, 13);
+ chunk.insert(10, 37);
+ chunk.insert(31, 337);
+ }
+ let ref2 = PoolRef::cloned(&pool, &ref1);
+ assert_eq!(ref1, ref2);
+ assert!(!PoolRef::ptr_eq(&ref1, &ref2));
+ }
+}
diff --git a/vendor/sized-chunks/src/tests.rs b/vendor/sized-chunks/src/tests.rs
new file mode 100644
index 0000000..e97900f
--- /dev/null
+++ b/vendor/sized-chunks/src/tests.rs
@@ -0,0 +1,18 @@
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+pub(crate) struct DropTest<'a> {
+ counter: &'a AtomicUsize,
+}
+
+impl<'a> DropTest<'a> {
+ pub(crate) fn new(counter: &'a AtomicUsize) -> Self {
+ counter.fetch_add(1, Ordering::Relaxed);
+ DropTest { counter }
+ }
+}
+
+impl<'a> Drop for DropTest<'a> {
+ fn drop(&mut self) {
+ self.counter.fetch_sub(1, Ordering::Relaxed);
+ }
+}
diff --git a/vendor/sized-chunks/src/types.rs b/vendor/sized-chunks/src/types.rs
new file mode 100644
index 0000000..0abd464
--- /dev/null
+++ b/vendor/sized-chunks/src/types.rs
@@ -0,0 +1,54 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+//! Helper types for chunks.
+
+use core::marker::PhantomData;
+
+use typenum::*;
+
+// Chunk sizes
+
+/// A trait used to decide the size of an array.
+///
+/// `<N as ChunkLength<A>>::SizedType` for a type level integer N will have the
+/// same size as `[A; N]`.
+pub trait ChunkLength<A>: Unsigned {
+ /// A `Sized` type matching the size of an array of `Self` elements of `A`.
+ type SizedType;
+}
+
+impl<A> ChunkLength<A> for UTerm {
+ type SizedType = ();
+}
+
+#[doc(hidden)]
+#[allow(dead_code)]
+pub struct SizeEven<A, B> {
+ parent1: B,
+ parent2: B,
+ _marker: PhantomData<A>,
+}
+
+#[doc(hidden)]
+#[allow(dead_code)]
+pub struct SizeOdd<A, B> {
+ parent1: B,
+ parent2: B,
+ data: A,
+}
+
+impl<A, N> ChunkLength<A> for UInt<N, B0>
+where
+ N: ChunkLength<A>,
+{
+ type SizedType = SizeEven<A, N::SizedType>;
+}
+
+impl<A, N> ChunkLength<A> for UInt<N, B1>
+where
+ N: ChunkLength<A>,
+{
+ type SizedType = SizeOdd<A, N::SizedType>;
+}