Bug 1982003 - Apply allocator-api2 upstream fix to build with rust 1.89. a=RyanVM

Original Revision: https://phabricator.services.mozilla.com/D264362

Differential Revision: https://phabricator.services.mozilla.com/D264537
This commit is contained in:
Mike Hommey
2025-09-25 19:54:59 +00:00
committed by rvandermeulen@mozilla.com
parent 40dc24686f
commit 94e68b81a7
28 changed files with 8351 additions and 8330 deletions

View File

@@ -45,6 +45,11 @@ git = "https://github.com/gfx-rs/wgpu"
rev = "88862f1fa3fd0f0c1010e9fc999dcfe47b5ae8fc" rev = "88862f1fa3fd0f0c1010e9fc999dcfe47b5ae8fc"
replace-with = "vendored-sources" replace-with = "vendored-sources"
[source."git+https://github.com/glandium/allocator-api2?rev=ad5f3d56a5a4519eff52af4ff85293431466ef5c"]
git = "https://github.com/glandium/allocator-api2"
rev = "ad5f3d56a5a4519eff52af4ff85293431466ef5c"
replace-with = "vendored-sources"
[source."git+https://github.com/glandium/rust-objc?rev=4de89f5aa9851ceca4d40e7ac1e2759410c04324"] [source."git+https://github.com/glandium/rust-objc?rev=4de89f5aa9851ceca4d40e7ac1e2759410c04324"]
git = "https://github.com/glandium/rust-objc" git = "https://github.com/glandium/rust-objc"
rev = "4de89f5aa9851ceca4d40e7ac1e2759410c04324" rev = "4de89f5aa9851ceca4d40e7ac1e2759410c04324"

3
Cargo.lock generated
View File

@@ -28,8 +28,7 @@ dependencies = [
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.2.21" version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/glandium/allocator-api2?rev=ad5f3d56a5a4519eff52af4ff85293431466ef5c#ad5f3d56a5a4519eff52af4ff85293431466ef5c"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
dependencies = [ dependencies = [
"serde", "serde",
] ]

View File

@@ -264,6 +264,9 @@ wr_malloc_size_of = { path = "gfx/wr/wr_malloc_size_of" }
# objc 0.2.7 + fa7ca43b862861dd1cd000d7ad01e6e0266cda13 # objc 0.2.7 + fa7ca43b862861dd1cd000d7ad01e6e0266cda13
objc = { git = "https://github.com/glandium/rust-objc", rev = "4de89f5aa9851ceca4d40e7ac1e2759410c04324" } objc = { git = "https://github.com/glandium/rust-objc", rev = "4de89f5aa9851ceca4d40e7ac1e2759410c04324" }
# allocator-api2 + f95e3419ce41883904fcb2279b52aa35b5f04d76 + fdd92751afa7ce34408b677004b429d597e72c90
allocator-api2 = { git = "https://github.com/glandium/allocator-api2", rev = "ad5f3d56a5a4519eff52af4ff85293431466ef5c" }
# application-services overrides to make updating them all simpler. # application-services overrides to make updating them all simpler.
context_id = { git = "https://github.com/mozilla/application-services", rev = "9b46be5beedb6a1d859014a71bac58e2d722f954" } context_id = { git = "https://github.com/mozilla/application-services", rev = "9b46be5beedb6a1d859014a71bac58e2d722f954" }
interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "9b46be5beedb6a1d859014a71bac58e2d722f954" } interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "9b46be5beedb6a1d859014a71bac58e2d722f954" }

View File

@@ -657,6 +657,12 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy" criteria = "safe-to-deploy"
delta = "0.2.20 -> 0.2.21" delta = "0.2.20 -> 0.2.21"
[[audits.allocator-api2]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "0.2.21 -> 0.2.21@git:ad5f3d56a5a4519eff52af4ff85293431466ef5c"
importable = false
[[audits.alsa]] [[audits.alsa]]
who = "Mike Hommey <mh+mozilla@glandium.org>" who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy" criteria = "safe-to-deploy"

View File

@@ -19,6 +19,10 @@ url = "https://raw.githubusercontent.com/divviup/libprio-rs/main/supply-chain/au
[imports.mozilla] [imports.mozilla]
url = "https://raw.githubusercontent.com/mozilla/supply-chain/main/audits.toml" url = "https://raw.githubusercontent.com/mozilla/supply-chain/main/audits.toml"
[policy.allocator-api2]
audit-as-crates-io = true
notes = "This is the upstream code with a fix for rust 1.89."
[policy.any_all_workaround] [policy.any_all_workaround]
audit-as-crates-io = true audit-as-crates-io = true
notes = "This is the upstream code plus the ARM intrinsics workaround from qcms, see bug 1882209." notes = "This is the upstream code plus the ARM intrinsics workaround from qcms, see bug 1882209."

View File

@@ -1 +1 @@
{"files":{"CHANGELOG.md":"886f8c688db0c22d24b650df0dc30a39d05d54d0e562c00d9574bf31cbf73251","Cargo.toml":"ddaa434cc54a30a33bbe0096e72479d71ba5deffa2ad9bee39419d4e50b75275","LICENSE-APACHE":"20fe7b00e904ed690e3b9fd6073784d3fc428141dbd10b81c01fd143d0797f58","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"8b8c45a89f9d61688fd32516ca24ea11cc6be4994757bd01bd9d02d96cd49337","src/lib.rs":"56a7344026bf5be503ca8b3fe208b74550956e82be7806a229951e80ebb3c249","src/nightly.rs":"c12152b6721216174c9a3cec90e612d5571a5d2c0a94ad54900cb814414519c3","src/stable/alloc/global.rs":"14836ad7d73a364474fc153b24a1f17ad0e60a69b90a8721dc1059eada8bf869","src/stable/alloc/mod.rs":"866dafd3984dd246e381d8ad1c2b3e02a60c3421b598ca493aa83f9b6422608d","src/stable/alloc/system.rs":"db5d5bf088eecac3fc5ff1281e1bf26ca36dd38f13cd52c49d95ff1bab064254","src/stable/boxed.rs":"fb664ab68a599b7fc5acbae1c634c2007ba2bda9a24fea2212b8202bb537f7a0","src/stable/macros.rs":"74490796a766338d0163f40a37612cd9ea2de58ae3d8e9abf6c7bcf81d9be4a6","src/stable/mod.rs":"474dce5f150456a98fa7c4debc24f03ec2db4ebf0d54011ae19c8b575feb5712","src/stable/raw_vec.rs":"9a56ce1bab4562000285e80837da7b7bd2bbbc63850c83ab5d8df9888b65f5db","src/stable/slice.rs":"089263b058e6c185467bad7ad14908479e5675408fc70a8291e5dddaef36035a","src/stable/unique.rs":"6ed3678beed7fa6bd18b694f7357e638d83e3f1f895f9988a465dc5afebfbac9","src/stable/vec/drain.rs":"740cd2e0f31eeb0146bbd0f645a14fe12bacd3912f003db433ddc6b3a178461f","src/stable/vec/into_iter.rs":"da72ce52344ea2e263ddf7776356cc012bbafc51f48499955c1771729448754d","src/stable/vec/mod.rs":"dd3ddca02747686ed2064397dd17068b64f28c6f42b55e9e2ce129cd573fe44c","src/stable/vec/partial_eq.rs":"9f1b18605164a62b58d9e17914d573698735de31c51ceb8bd3666e83d32df370","src/stable/vec/set_len_on_drop.rs":"561342e22a194e515cc25c9a1bcd827ca24c4db033e9e2c4266fbdd2fb16e5bc","src/stable/vec/splice.rs":"95a460b3a7b4af60fdc9ba04d3a719b61a0c11786cd2d8823d022e22c397f9c9"},"package":"683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"} {"files":{"CHANGELOG.md":"b4d01c4b8a790e435dc0ab67a1ef8b6d8e39f87bec233540e247ef313737d855","Cargo.toml":"97b99c5d9b742ecc3652dc4b77407c694cb67ca8bc75b12442cbec87c519ccce","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"8796f799e695228183db03715930631400df9b8527cfd7db200c53ab8a5d92e8","src/lib.rs":"6d0a4ce2987502a1f6ff40451ae00f819a3eb91ea14768f74744527342b4134a","src/nightly.rs":"3b9b055fea5e6df0a435706fe7b6967213dc60c5f39f2e6690b6e1a74b4af3c4","src/stable/alloc/global.rs":"e58d538406e80fe5e70f99f57452d9401ce8efa6a7fd4ccfb87b8d55430f01ab","src/stable/alloc/mod.rs":"63db909472169a70ad5332f33f67b88e9ea361c13725c65540d7003c83d8d226","src/stable/alloc/system.rs":"7c9145f594869c3cb934e97d3eda1b0b8ed6bd8ba89b1aea7435fc6680465b6b","src/stable/boxed.rs":"6903d42dd29cc945852a06a91d88da0d138651db954444e00ae2cf2484d597f1","src/stable/macros.rs":"c05b6bbc359a2e2ac1520922ed0c54d34ebea7da85a51902e1f840816ba4afc2","src/stable/mod.rs":"2df7ccfe227d62540c4ccc09538cef9aaa3780c7a1884914f364dbecd325d4b1","src/stable/raw_vec.rs":"e767edf03ef948e6d20dd09eb7f9534591e33f31be8a00a91c426c1b0500ca9d","src/stable/slice.rs":"14d6eb35e3557b5f78feb48fd4bea343f037e8f1f2d2707089db4dbed438b558","src/stable/unique.rs":"93a57a0270b8f5fc4d05afe251190f988bf5eabe4fb4eb286a31b3a6efb98649","src/stable/vec/drain.rs":"f8209cbd76a57823f6583a84fee285727b6c00189ec299acc9f97a0829f0742f","src/stable/vec/into_iter.rs":"6e8481635e2f9876a14636d4914f9b2bae7cccdefc4ca7c6b1e1f35ac420794f","src/stable/vec/mod.rs":"bdd605f7badb539d9f56ebcef05ea99fa1a3e90650c21cfa9edace7911b2eeac","src/stable/vec/partial_eq.rs":"cb88615747b4413f26dcab206e026bbd50150bf7d97d8df174384e86151d875e","src/stable/vec/set_len_on_drop.rs":"36f2e8fdc9b0a838eb443d74bec0291d389e52bfe4f617e391d977f15e6893b5","src/stable/vec/splice.rs":"7ce9fa74764c36ab9043f7339548e96b0b68f7d1a16769c9cb066b9a538dcb14"},"package":null}

View File

@@ -1,7 +1,7 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased]

View File

@@ -16,6 +16,7 @@ name = "allocator-api2"
version = "0.2.21" version = "0.2.21"
authors = ["Zakarum <zaq.dev@icloud.com>"] authors = ["Zakarum <zaq.dev@icloud.com>"]
build = false build = false
autolib = false
autobins = false autobins = false
autoexamples = false autoexamples = false
autotests = false autotests = false
@@ -27,6 +28,13 @@ readme = "README.md"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
repository = "https://github.com/zakarumych/allocator-api2" repository = "https://github.com/zakarumych/allocator-api2"
[features]
alloc = []
default = ["std"]
fresh-rust = []
nightly = []
std = ["alloc"]
[lib] [lib]
name = "allocator_api2" name = "allocator_api2"
path = "src/lib.rs" path = "src/lib.rs"
@@ -35,14 +43,10 @@ path = "src/lib.rs"
version = "1.0" version = "1.0"
optional = true optional = true
[features]
alloc = []
default = ["std"]
fresh-rust = []
nightly = []
std = ["alloc"]
[lints.rust.unexpected_cfgs] [lints.rust.unexpected_cfgs]
level = "warn" level = "warn"
priority = 0 priority = 0
check-cfg = ["cfg(no_global_oom_handling)"] check-cfg = ["cfg(no_global_oom_handling)"]
[workspace]
members = ["tests"]

View File

@@ -1,176 +1,176 @@
Apache License Apache License
Version 2.0, January 2004 Version 2.0, January 2004
http://www.apache.org/licenses/ http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions. 1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, "License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document. and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by "Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License. the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all "Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition, control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the "control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity. outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity "You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License. exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, "Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation including but not limited to software source code, documentation
source, and configuration files. source, and configuration files.
"Object" form shall mean any form resulting from mechanical "Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation, not limited to compiled object code, generated documentation,
and conversions to other media types. and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or "Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work copyright notice that is included in or attached to the work
(an example is provided in the Appendix below). (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object "Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of, separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof. the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including "Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted" the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution." designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity "Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work. subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of 2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual, this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of, copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form. Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of 3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual, this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made, (except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work, use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s) Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate granted to You under this License for that Work shall terminate
as of the date such litigation is filed. as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the 4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You modifications, and in Source or Object form, provided that You
meet the following conditions: meet the following conditions:
(a) You must give any other recipients of the Work or (a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices (b) You must cause any modified files to carry prominent notices
stating that You changed the files; and stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works (c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work, attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of excluding those notices that do not pertain to any part of
the Derivative Works; and the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its (d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or, documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed that such additional attribution notices cannot be construed
as modifying the License. as modifying the License.
You may add Your own copyright statement to Your modifications and You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use, for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License. the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, 5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions. this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions. with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade 6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor, names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file. origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or 7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS, Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License. risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, 8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise, whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill, Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages. has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing 9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer, the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity, and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify, of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability. of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS

View File

@@ -1,23 +1,23 @@
Permission is hereby granted, free of charge, to any Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the documentation files (the "Software"), to deal in the
Software without restriction, including without Software without restriction, including without
limitation the rights to use, copy, modify, merge, limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following is furnished to do so, subject to the following
conditions: conditions:
The above copyright notice and this permission notice The above copyright notice and this permission notice
shall be included in all copies or substantial portions shall be included in all copies or substantial portions
of the Software. of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.

View File

@@ -1,61 +1,61 @@
# allocator-api2 # allocator-api2
[![crates](https://img.shields.io/crates/v/allocator-api2.svg?style=for-the-badge&label=allocator-api2)](https://crates.io/crates/allocator-api2) [![crates](https://img.shields.io/crates/v/allocator-api2.svg?style=for-the-badge&label=allocator-api2)](https://crates.io/crates/allocator-api2)
[![docs](https://img.shields.io/badge/docs.rs-allocator--api2-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white)](https://docs.rs/allocator-api2) [![docs](https://img.shields.io/badge/docs.rs-allocator--api2-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white)](https://docs.rs/allocator-api2)
[![actions](https://img.shields.io/github/actions/workflow/status/zakarumych/allocator-api2/badge.yml?branch=main&style=for-the-badge)](https://github.com/zakarumych/allocator-api2/actions/workflows/badge.yml) [![actions](https://img.shields.io/github/actions/workflow/status/zakarumych/allocator-api2/badge.yml?branch=main&style=for-the-badge)](https://github.com/zakarumych/allocator-api2/actions/workflows/badge.yml)
[![MIT/Apache](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?style=for-the-badge)](COPYING) [![MIT/Apache](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?style=for-the-badge)](COPYING)
![loc](https://img.shields.io/tokei/lines/github/zakarumych/allocator-api2?style=for-the-badge) ![loc](https://img.shields.io/tokei/lines/github/zakarumych/allocator-api2?style=for-the-badge)
This crate mirrors types and traits from Rust's unstable [`allocator_api`] This crate mirrors types and traits from Rust's unstable [`allocator_api`]
The intention of this crate is to serve as substitution for actual thing The intention of this crate is to serve as substitution for actual thing
for libs when build on stable and beta channels. for libs when build on stable and beta channels.
The target users are library authors who implement allocators or collection types The target users are library authors who implement allocators or collection types
that use allocators, or anyone else who wants using [`allocator_api`] that use allocators, or anyone else who wants using [`allocator_api`]
The crate should be frequently updated with minor version bump. The crate should be frequently updated with minor version bump.
When [`allocator_api`] is stable this crate will get version `1.0` and simply When [`allocator_api`] is stable this crate will get version `1.0` and simply
re-export from `core`, `alloc` and `std`. re-export from `core`, `alloc` and `std`.
The code is mostly verbatim copy from rust repository. The code is mostly verbatim copy from rust repository.
Mostly attributes are removed. Mostly attributes are removed.
## Usage ## Usage
This paragraph describes how to use this crate correctly to ensure This paragraph describes how to use this crate correctly to ensure
compatibility and interoperability on both stable and nightly channels. compatibility and interoperability on both stable and nightly channels.
If you are writing a library that interacts with allocators API, you can If you are writing a library that interacts with allocators API, you can
add this crate as a dependency and use the types and traits from this add this crate as a dependency and use the types and traits from this
crate instead of the ones in `core` or `alloc`. crate instead of the ones in `core` or `alloc`.
This will allow your library to compile on stable and beta channels. This will allow your library to compile on stable and beta channels.
Your library *MAY* provide a feature that will enable "allocator-api2/nightly". Your library *MAY* provide a feature that will enable "allocator-api2/nightly".
When this feature is enabled, your library *MUST* enable When this feature is enabled, your library *MUST* enable
unstable `#![feature(allocator_api)]` or it may not compile. unstable `#![feature(allocator_api)]` or it may not compile.
If feature is not provided, your library may not be compatible with the If feature is not provided, your library may not be compatible with the
rest of the users and cause compilation errors on nightly channel rest of the users and cause compilation errors on nightly channel
when some other crate enables "allocator-api2/nightly" feature. when some other crate enables "allocator-api2/nightly" feature.
# Minimal Supported Rust Version (MSRV) # Minimal Supported Rust Version (MSRV)
This crate is guaranteed to compile on stable Rust 1.63 and up. This crate is guaranteed to compile on stable Rust 1.64 and up.
A feature "fresh-rust" bumps the MSRV to unspecified higher version, but should be compatible with A feature "fresh-rust" bumps the MSRV to unspecified higher version, but should be compatible with
at least few latest stable releases. The feature enables some additional functionality: at least few latest stable releases. The feature enables some additional functionality:
* `CStr` without "std" feature * `CStr` without "std" feature
## License ## License
Licensed under either of Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option. at your option.
## Contributions ## Contributions
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
[`allocator_api`]: https://doc.rust-lang.org/unstable-book/library-features/allocator-api.html [`allocator_api`]: https://doc.rust-lang.org/unstable-book/library-features/allocator-api.html

View File

@@ -1,20 +1,20 @@
//! //!
//! allocator-api2 crate. //! allocator-api2 crate.
//! //!
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
extern crate alloc as alloc_crate; extern crate alloc as alloc_crate;
#[cfg(not(feature = "nightly"))] #[cfg(not(feature = "nightly"))]
#[macro_use] #[macro_use]
mod stable; mod stable;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
mod nightly; mod nightly;
#[cfg(not(feature = "nightly"))] #[cfg(not(feature = "nightly"))]
pub use self::stable::*; pub use self::stable::*;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
pub use self::nightly::*; pub use self::nightly::*;

View File

@@ -1,5 +1,5 @@
#[cfg(not(feature = "alloc"))] #[cfg(not(feature = "alloc"))]
pub use core::alloc; pub use core::alloc;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub use alloc_crate::{alloc, boxed, vec, collections}; pub use alloc_crate::{alloc, boxed, vec, collections};

View File

@@ -1,187 +1,187 @@
use core::ptr::NonNull; use core::ptr::NonNull;
use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc}; use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc};
use crate::stable::{assume, invalid_mut}; use crate::stable::{assume, invalid_mut};
use super::{AllocError, Allocator, Layout}; use super::{AllocError, Allocator, Layout};
/// The global memory allocator. /// The global memory allocator.
/// ///
/// This type implements the [`Allocator`] trait by forwarding calls /// This type implements the [`Allocator`] trait by forwarding calls
/// to the allocator registered with the `#[global_allocator]` attribute /// to the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crates default. /// if there is one, or the `std` crates default.
/// ///
/// Note: while this type is unstable, the functionality it provides can be /// Note: while this type is unstable, the functionality it provides can be
/// accessed through the [free functions in `alloc`](crate#functions). /// accessed through the [free functions in `alloc`](crate#functions).
#[derive(Copy, Clone, Default, Debug)] #[derive(Copy, Clone, Default, Debug)]
pub struct Global; pub struct Global;
impl Global { impl Global {
#[inline(always)] #[inline(always)]
fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> { fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() { match layout.size() {
0 => Ok(unsafe { 0 => Ok(unsafe {
NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
invalid_mut(layout.align()), invalid_mut(layout.align()),
0, 0,
)) ))
}), }),
// SAFETY: `layout` is non-zero in size, // SAFETY: `layout` is non-zero in size,
size => unsafe { size => unsafe {
let raw_ptr = if zeroed { let raw_ptr = if zeroed {
alloc_zeroed(layout) alloc_zeroed(layout)
} else { } else {
alloc(layout) alloc(layout)
}; };
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
ptr.as_ptr(), ptr.as_ptr(),
size, size,
))) )))
}, },
} }
} }
// SAFETY: Same as `Allocator::grow` // SAFETY: Same as `Allocator::grow`
#[inline(always)] #[inline(always)]
unsafe fn grow_impl( unsafe fn grow_impl(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
zeroed: bool, zeroed: bool,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() >= old_layout.size(), new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`" "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
); );
match old_layout.size() { match old_layout.size() {
0 => self.alloc_impl(new_layout, zeroed), 0 => self.alloc_impl(new_layout, zeroed),
// SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
// as required by safety conditions. Other conditions must be upheld by the caller // as required by safety conditions. Other conditions must be upheld by the caller
old_size if old_layout.align() == new_layout.align() => unsafe { old_size if old_layout.align() == new_layout.align() => unsafe {
let new_size = new_layout.size(); let new_size = new_layout.size();
// `realloc` probably checks for `new_size >= old_layout.size()` or something similar. // `realloc` probably checks for `new_size >= old_layout.size()` or something similar.
assume(new_size >= old_layout.size()); assume(new_size >= old_layout.size());
let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
if zeroed { if zeroed {
raw_ptr.add(old_size).write_bytes(0, new_size - old_size); raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
} }
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
ptr.as_ptr(), ptr.as_ptr(),
new_size, new_size,
))) )))
}, },
// SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`,
// both the old and new memory allocation are valid for reads and writes for `old_size` // both the old and new memory allocation are valid for reads and writes for `old_size`
// bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
// `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
// for `dealloc` must be upheld by the caller. // for `dealloc` must be upheld by the caller.
old_size => unsafe { old_size => unsafe {
let new_ptr = self.alloc_impl(new_layout, zeroed)?; let new_ptr = self.alloc_impl(new_layout, zeroed)?;
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_size); core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_size);
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
Ok(new_ptr) Ok(new_ptr)
}, },
} }
} }
} }
unsafe impl Allocator for Global { unsafe impl Allocator for Global {
#[inline(always)] #[inline(always)]
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.alloc_impl(layout, false) self.alloc_impl(layout, false)
} }
#[inline(always)] #[inline(always)]
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.alloc_impl(layout, true) self.alloc_impl(layout, true)
} }
#[inline(always)] #[inline(always)]
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
if layout.size() != 0 { if layout.size() != 0 {
// SAFETY: `layout` is non-zero in size, // SAFETY: `layout` is non-zero in size,
// other conditions must be upheld by the caller // other conditions must be upheld by the caller
unsafe { dealloc(ptr.as_ptr(), layout) } unsafe { dealloc(ptr.as_ptr(), layout) }
} }
} }
#[inline(always)] #[inline(always)]
unsafe fn grow( unsafe fn grow(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: all conditions must be upheld by the caller // SAFETY: all conditions must be upheld by the caller
unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } unsafe { self.grow_impl(ptr, old_layout, new_layout, false) }
} }
#[inline(always)] #[inline(always)]
unsafe fn grow_zeroed( unsafe fn grow_zeroed(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: all conditions must be upheld by the caller // SAFETY: all conditions must be upheld by the caller
unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } unsafe { self.grow_impl(ptr, old_layout, new_layout, true) }
} }
#[inline(always)] #[inline(always)]
unsafe fn shrink( unsafe fn shrink(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() <= old_layout.size(), new_layout.size() <= old_layout.size(),
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`" "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
); );
match new_layout.size() { match new_layout.size() {
// SAFETY: conditions must be upheld by the caller // SAFETY: conditions must be upheld by the caller
0 => unsafe { 0 => unsafe {
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
invalid_mut(new_layout.align()), invalid_mut(new_layout.align()),
0, 0,
))) )))
}, },
// SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
new_size if old_layout.align() == new_layout.align() => unsafe { new_size if old_layout.align() == new_layout.align() => unsafe {
// `realloc` probably checks for `new_size <= old_layout.size()` or something similar. // `realloc` probably checks for `new_size <= old_layout.size()` or something similar.
assume(new_size <= old_layout.size()); assume(new_size <= old_layout.size());
let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
ptr.as_ptr(), ptr.as_ptr(),
new_size, new_size,
))) )))
}, },
// SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`,
// both the old and new memory allocation are valid for reads and writes for `new_size` // both the old and new memory allocation are valid for reads and writes for `new_size`
// bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
// `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
// for `dealloc` must be upheld by the caller. // for `dealloc` must be upheld by the caller.
new_size => unsafe { new_size => unsafe {
let new_ptr = self.allocate(new_layout)?; let new_ptr = self.allocate(new_layout)?;
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_size); core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_size);
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
Ok(new_ptr) Ok(new_ptr)
}, },
} }
} }
} }

View File

@@ -1,416 +1,416 @@
//! Memory allocation APIs //! Memory allocation APIs
use core::{ use core::{
fmt, fmt,
ptr::{self, NonNull}, ptr::{self, NonNull},
}; };
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
mod global; mod global;
#[cfg(feature = "std")] #[cfg(feature = "std")]
mod system; mod system;
pub use core::alloc::{GlobalAlloc, Layout, LayoutError}; pub use core::alloc::{GlobalAlloc, Layout, LayoutError};
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub use self::global::Global; pub use self::global::Global;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use self::system::System; pub use self::system::System;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc}; pub use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc};
#[cfg(all(feature = "alloc", not(no_global_oom_handling)))] #[cfg(all(feature = "alloc", not(no_global_oom_handling)))]
pub use alloc_crate::alloc::handle_alloc_error; pub use alloc_crate::alloc::handle_alloc_error;
/// The `AllocError` error indicates an allocation failure /// The `AllocError` error indicates an allocation failure
/// that may be due to resource exhaustion or to /// that may be due to resource exhaustion or to
/// something wrong when combining the given input arguments with this /// something wrong when combining the given input arguments with this
/// allocator. /// allocator.
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct AllocError; pub struct AllocError;
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for AllocError {} impl std::error::Error for AllocError {}
// (we need this for downstream impl of trait Error) // (we need this for downstream impl of trait Error)
impl fmt::Display for AllocError { impl fmt::Display for AllocError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("memory allocation failed") f.write_str("memory allocation failed")
} }
} }
/// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of /// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of
/// data described via [`Layout`][]. /// data described via [`Layout`][].
/// ///
/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers because having /// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers because having
/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the /// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
/// allocated memory. /// allocated memory.
/// ///
/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `Allocator`. If an underlying /// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `Allocator`. If an underlying
/// allocator does not support this (like jemalloc) or return a null pointer (such as /// allocator does not support this (like jemalloc) or return a null pointer (such as
/// `libc::malloc`), this must be caught by the implementation. /// `libc::malloc`), this must be caught by the implementation.
/// ///
/// ### Currently allocated memory /// ### Currently allocated memory
/// ///
/// Some of the methods require that a memory block be *currently allocated* via an allocator. This /// Some of the methods require that a memory block be *currently allocated* via an allocator. This
/// means that: /// means that:
/// ///
/// * the starting address for that memory block was previously returned by [`allocate`], [`grow`], or /// * the starting address for that memory block was previously returned by [`allocate`], [`grow`], or
/// [`shrink`], and /// [`shrink`], and
/// ///
/// * the memory block has not been subsequently deallocated, where blocks are either deallocated /// * the memory block has not been subsequently deallocated, where blocks are either deallocated
/// directly by being passed to [`deallocate`] or were changed by being passed to [`grow`] or /// directly by being passed to [`deallocate`] or were changed by being passed to [`grow`] or
/// [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer /// [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
/// remains valid. /// remains valid.
/// ///
/// [`allocate`]: Allocator::allocate /// [`allocate`]: Allocator::allocate
/// [`grow`]: Allocator::grow /// [`grow`]: Allocator::grow
/// [`shrink`]: Allocator::shrink /// [`shrink`]: Allocator::shrink
/// [`deallocate`]: Allocator::deallocate /// [`deallocate`]: Allocator::deallocate
/// ///
/// ### Memory fitting /// ### Memory fitting
/// ///
/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to /// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the /// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
/// following conditions must hold: /// following conditions must hold:
/// ///
/// * The block must be allocated with the same alignment as [`layout.align()`], and /// * The block must be allocated with the same alignment as [`layout.align()`], and
/// ///
/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where: /// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
/// - `min` is the size of the layout most recently used to allocate the block, and /// - `min` is the size of the layout most recently used to allocate the block, and
/// - `max` is the latest actual size returned from [`allocate`], [`grow`], or [`shrink`]. /// - `max` is the latest actual size returned from [`allocate`], [`grow`], or [`shrink`].
/// ///
/// [`layout.align()`]: Layout::align /// [`layout.align()`]: Layout::align
/// [`layout.size()`]: Layout::size /// [`layout.size()`]: Layout::size
/// ///
/// # Safety /// # Safety
/// ///
/// * Memory blocks returned from an allocator must point to valid memory and retain their validity /// * Memory blocks returned from an allocator must point to valid memory and retain their validity
/// until the instance and all of its clones are dropped, /// until the instance and all of its clones are dropped,
/// ///
/// * cloning or moving the allocator must not invalidate memory blocks returned from this /// * cloning or moving the allocator must not invalidate memory blocks returned from this
/// allocator. A cloned allocator must behave like the same allocator, and /// allocator. A cloned allocator must behave like the same allocator, and
/// ///
/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other /// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
/// method of the allocator. /// method of the allocator.
/// ///
/// [*currently allocated*]: #currently-allocated-memory /// [*currently allocated*]: #currently-allocated-memory
pub unsafe trait Allocator { pub unsafe trait Allocator {
/// Attempts to allocate a block of memory. /// Attempts to allocate a block of memory.
/// ///
/// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`.
/// ///
/// The returned block may have a larger size than specified by `layout.size()`, and may or may /// The returned block may have a larger size than specified by `layout.size()`, and may or may
/// not have its contents initialized. /// not have its contents initialized.
/// ///
/// # Errors /// # Errors
/// ///
/// Returning `Err` indicates that either memory is exhausted or `layout` does not meet /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
/// allocator's size or alignment constraints. /// allocator's size or alignment constraints.
/// ///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an allocation error are encouraged to /// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
/// ///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>; fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
/// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized. /// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized.
/// ///
/// # Errors /// # Errors
/// ///
/// Returning `Err` indicates that either memory is exhausted or `layout` does not meet /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
/// allocator's size or alignment constraints. /// allocator's size or alignment constraints.
/// ///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an allocation error are encouraged to /// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
/// ///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
#[inline(always)] #[inline(always)]
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
let ptr = self.allocate(layout)?; let ptr = self.allocate(layout)?;
// SAFETY: `alloc` returns a valid memory block // SAFETY: `alloc` returns a valid memory block
unsafe { ptr.cast::<u8>().as_ptr().write_bytes(0, ptr.len()) } unsafe { ptr.cast::<u8>().as_ptr().write_bytes(0, ptr.len()) }
Ok(ptr) Ok(ptr)
} }
/// Deallocates the memory referenced by `ptr`. /// Deallocates the memory referenced by `ptr`.
/// ///
/// # Safety /// # Safety
/// ///
/// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and
/// * `layout` must [*fit*] that block of memory. /// * `layout` must [*fit*] that block of memory.
/// ///
/// [*currently allocated*]: #currently-allocated-memory /// [*currently allocated*]: #currently-allocated-memory
/// [*fit*]: #memory-fitting /// [*fit*]: #memory-fitting
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout); unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
/// Attempts to extend the memory block. /// Attempts to extend the memory block.
/// ///
/// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
/// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
/// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout.
/// ///
/// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
/// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the
/// allocation was grown in-place. The newly returned pointer is the only valid pointer /// allocation was grown in-place. The newly returned pointer is the only valid pointer
/// for accessing this memory now. /// for accessing this memory now.
/// ///
/// If this method returns `Err`, then ownership of the memory block has not been transferred to /// If this method returns `Err`, then ownership of the memory block has not been transferred to
/// this allocator, and the contents of the memory block are unaltered. /// this allocator, and the contents of the memory block are unaltered.
/// ///
/// # Safety /// # Safety
/// ///
/// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
/// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
/// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
/// ///
/// Note that `new_layout.align()` need not be the same as `old_layout.align()`. /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
/// ///
/// [*currently allocated*]: #currently-allocated-memory /// [*currently allocated*]: #currently-allocated-memory
/// [*fit*]: #memory-fitting /// [*fit*]: #memory-fitting
/// ///
/// # Errors /// # Errors
/// ///
/// Returns `Err` if the new layout does not meet the allocator's size and alignment /// Returns `Err` if the new layout does not meet the allocator's size and alignment
/// constraints of the allocator, or if growing otherwise fails. /// constraints of the allocator, or if growing otherwise fails.
/// ///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an allocation error are encouraged to /// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
/// ///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
#[inline(always)] #[inline(always)]
unsafe fn grow( unsafe fn grow(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() >= old_layout.size(), new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`" "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
); );
let new_ptr = self.allocate(new_layout)?; let new_ptr = self.allocate(new_layout)?;
// SAFETY: because `new_layout.size()` must be greater than or equal to // SAFETY: because `new_layout.size()` must be greater than or equal to
// `old_layout.size()`, both the old and new memory allocation are valid for reads and // `old_layout.size()`, both the old and new memory allocation are valid for reads and
// writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
// deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
// safe. The safety contract for `dealloc` must be upheld by the caller. // safe. The safety contract for `dealloc` must be upheld by the caller.
unsafe { unsafe {
ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_layout.size()); ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_layout.size());
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
} }
Ok(new_ptr) Ok(new_ptr)
} }
/// Behaves like `grow`, but also ensures that the new contents are set to zero before being /// Behaves like `grow`, but also ensures that the new contents are set to zero before being
/// returned. /// returned.
/// ///
/// The memory block will contain the following contents after a successful call to /// The memory block will contain the following contents after a successful call to
/// `grow_zeroed`: /// `grow_zeroed`:
/// * Bytes `0..old_layout.size()` are preserved from the original allocation. /// * Bytes `0..old_layout.size()` are preserved from the original allocation.
/// * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on /// * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on
/// the allocator implementation. `old_size` refers to the size of the memory block prior /// the allocator implementation. `old_size` refers to the size of the memory block prior
/// to the `grow_zeroed` call, which may be larger than the size that was originally /// to the `grow_zeroed` call, which may be larger than the size that was originally
/// requested when it was allocated. /// requested when it was allocated.
/// * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory /// * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory
/// block returned by the `grow_zeroed` call. /// block returned by the `grow_zeroed` call.
/// ///
/// # Safety /// # Safety
/// ///
/// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
/// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
/// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
/// ///
/// Note that `new_layout.align()` need not be the same as `old_layout.align()`. /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
/// ///
/// [*currently allocated*]: #currently-allocated-memory /// [*currently allocated*]: #currently-allocated-memory
/// [*fit*]: #memory-fitting /// [*fit*]: #memory-fitting
/// ///
/// # Errors /// # Errors
/// ///
/// Returns `Err` if the new layout does not meet the allocator's size and alignment /// Returns `Err` if the new layout does not meet the allocator's size and alignment
/// constraints of the allocator, or if growing otherwise fails. /// constraints of the allocator, or if growing otherwise fails.
/// ///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an allocation error are encouraged to /// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
/// ///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
#[inline(always)] #[inline(always)]
unsafe fn grow_zeroed( unsafe fn grow_zeroed(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() >= old_layout.size(), new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`" "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
); );
let new_ptr = self.allocate_zeroed(new_layout)?; let new_ptr = self.allocate_zeroed(new_layout)?;
// SAFETY: because `new_layout.size()` must be greater than or equal to // SAFETY: because `new_layout.size()` must be greater than or equal to
// `old_layout.size()`, both the old and new memory allocation are valid for reads and // `old_layout.size()`, both the old and new memory allocation are valid for reads and
// writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
// deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
// safe. The safety contract for `dealloc` must be upheld by the caller. // safe. The safety contract for `dealloc` must be upheld by the caller.
unsafe { unsafe {
ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_layout.size()); ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_layout.size());
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
} }
Ok(new_ptr) Ok(new_ptr)
} }
/// Attempts to shrink the memory block. /// Attempts to shrink the memory block.
/// ///
/// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
/// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
/// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout. /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout.
/// ///
/// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
/// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the
/// allocation was shrunk in-place. The newly returned pointer is the only valid pointer /// allocation was shrunk in-place. The newly returned pointer is the only valid pointer
/// for accessing this memory now. /// for accessing this memory now.
/// ///
/// If this method returns `Err`, then ownership of the memory block has not been transferred to /// If this method returns `Err`, then ownership of the memory block has not been transferred to
/// this allocator, and the contents of the memory block are unaltered. /// this allocator, and the contents of the memory block are unaltered.
/// ///
/// # Safety /// # Safety
/// ///
/// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
/// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
/// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`. /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`.
/// ///
/// Note that `new_layout.align()` need not be the same as `old_layout.align()`. /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
/// ///
/// [*currently allocated*]: #currently-allocated-memory /// [*currently allocated*]: #currently-allocated-memory
/// [*fit*]: #memory-fitting /// [*fit*]: #memory-fitting
/// ///
/// # Errors /// # Errors
/// ///
/// Returns `Err` if the new layout does not meet the allocator's size and alignment /// Returns `Err` if the new layout does not meet the allocator's size and alignment
/// constraints of the allocator, or if shrinking otherwise fails. /// constraints of the allocator, or if shrinking otherwise fails.
/// ///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an allocation error are encouraged to /// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
/// ///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
#[inline(always)] #[inline(always)]
unsafe fn shrink( unsafe fn shrink(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() <= old_layout.size(), new_layout.size() <= old_layout.size(),
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`" "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
); );
let new_ptr = self.allocate(new_layout)?; let new_ptr = self.allocate(new_layout)?;
// SAFETY: because `new_layout.size()` must be lower than or equal to // SAFETY: because `new_layout.size()` must be lower than or equal to
// `old_layout.size()`, both the old and new memory allocation are valid for reads and // `old_layout.size()`, both the old and new memory allocation are valid for reads and
// writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet // writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet
// deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
// safe. The safety contract for `dealloc` must be upheld by the caller. // safe. The safety contract for `dealloc` must be upheld by the caller.
unsafe { unsafe {
ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_layout.size()); ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_layout.size());
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
} }
Ok(new_ptr) Ok(new_ptr)
} }
/// Creates a "by reference" adapter for this instance of `Allocator`. /// Creates a "by reference" adapter for this instance of `Allocator`.
/// ///
/// The returned adapter also implements `Allocator` and will simply borrow this. /// The returned adapter also implements `Allocator` and will simply borrow this.
#[inline(always)] #[inline(always)]
fn by_ref(&self) -> &Self fn by_ref(&self) -> &Self
where where
Self: Sized, Self: Sized,
{ {
self self
} }
} }
unsafe impl<A> Allocator for &A unsafe impl<A> Allocator for &A
where where
A: Allocator + ?Sized, A: Allocator + ?Sized,
{ {
#[inline(always)] #[inline(always)]
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
(**self).allocate(layout) (**self).allocate(layout)
} }
#[inline(always)] #[inline(always)]
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
(**self).allocate_zeroed(layout) (**self).allocate_zeroed(layout)
} }
#[inline(always)] #[inline(always)]
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
// SAFETY: the safety contract must be upheld by the caller // SAFETY: the safety contract must be upheld by the caller
unsafe { (**self).deallocate(ptr, layout) } unsafe { (**self).deallocate(ptr, layout) }
} }
#[inline(always)] #[inline(always)]
unsafe fn grow( unsafe fn grow(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller // SAFETY: the safety contract must be upheld by the caller
unsafe { (**self).grow(ptr, old_layout, new_layout) } unsafe { (**self).grow(ptr, old_layout, new_layout) }
} }
#[inline(always)] #[inline(always)]
unsafe fn grow_zeroed( unsafe fn grow_zeroed(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller // SAFETY: the safety contract must be upheld by the caller
unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) }
} }
#[inline(always)] #[inline(always)]
unsafe fn shrink( unsafe fn shrink(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller // SAFETY: the safety contract must be upheld by the caller
unsafe { (**self).shrink(ptr, old_layout, new_layout) } unsafe { (**self).shrink(ptr, old_layout, new_layout) }
} }
} }

View File

@@ -1,172 +1,172 @@
use core::ptr::NonNull; use core::ptr::NonNull;
pub use std::alloc::System; pub use std::alloc::System;
use crate::stable::{assume, invalid_mut}; use crate::stable::{assume, invalid_mut};
use super::{AllocError, Allocator, GlobalAlloc as _, Layout}; use super::{AllocError, Allocator, GlobalAlloc as _, Layout};
unsafe impl Allocator for System { unsafe impl Allocator for System {
#[inline(always)] #[inline(always)]
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
alloc_impl(layout, false) alloc_impl(layout, false)
} }
#[inline(always)] #[inline(always)]
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
alloc_impl(layout, true) alloc_impl(layout, true)
} }
#[inline(always)] #[inline(always)]
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
if layout.size() != 0 { if layout.size() != 0 {
// SAFETY: `layout` is non-zero in size, // SAFETY: `layout` is non-zero in size,
// other conditions must be upheld by the caller // other conditions must be upheld by the caller
unsafe { System.dealloc(ptr.as_ptr(), layout) } unsafe { System.dealloc(ptr.as_ptr(), layout) }
} }
} }
#[inline(always)] #[inline(always)]
unsafe fn grow( unsafe fn grow(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: all conditions must be upheld by the caller // SAFETY: all conditions must be upheld by the caller
unsafe { grow_impl(ptr, old_layout, new_layout, false) } unsafe { grow_impl(ptr, old_layout, new_layout, false) }
} }
#[inline(always)] #[inline(always)]
unsafe fn grow_zeroed( unsafe fn grow_zeroed(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: all conditions must be upheld by the caller // SAFETY: all conditions must be upheld by the caller
unsafe { grow_impl(ptr, old_layout, new_layout, true) } unsafe { grow_impl(ptr, old_layout, new_layout, true) }
} }
#[inline(always)] #[inline(always)]
unsafe fn shrink( unsafe fn shrink(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() <= old_layout.size(), new_layout.size() <= old_layout.size(),
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`" "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
); );
match new_layout.size() { match new_layout.size() {
// SAFETY: conditions must be upheld by the caller // SAFETY: conditions must be upheld by the caller
0 => unsafe { 0 => unsafe {
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
invalid_mut(new_layout.align()), invalid_mut(new_layout.align()),
0, 0,
))) )))
}, },
// SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
new_size if old_layout.align() == new_layout.align() => unsafe { new_size if old_layout.align() == new_layout.align() => unsafe {
// `realloc` probably checks for `new_size <= old_layout.size()` or something similar. // `realloc` probably checks for `new_size <= old_layout.size()` or something similar.
assume(new_size <= old_layout.size()); assume(new_size <= old_layout.size());
let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size); let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size);
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
ptr.as_ptr(), ptr.as_ptr(),
new_size, new_size,
))) )))
}, },
// SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`,
// both the old and new memory allocation are valid for reads and writes for `new_size` // both the old and new memory allocation are valid for reads and writes for `new_size`
// bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
// `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
// for `dealloc` must be upheld by the caller. // for `dealloc` must be upheld by the caller.
new_size => unsafe { new_size => unsafe {
let new_ptr = self.allocate(new_layout)?; let new_ptr = self.allocate(new_layout)?;
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_size); core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_size);
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
Ok(new_ptr) Ok(new_ptr)
}, },
} }
} }
} }
#[inline(always)] #[inline(always)]
fn alloc_impl(layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> { fn alloc_impl(layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() { match layout.size() {
0 => Ok(unsafe { 0 => Ok(unsafe {
NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
invalid_mut(layout.align()), invalid_mut(layout.align()),
0, 0,
)) ))
}), }),
// SAFETY: `layout` is non-zero in size, // SAFETY: `layout` is non-zero in size,
size => unsafe { size => unsafe {
let raw_ptr = if zeroed { let raw_ptr = if zeroed {
System.alloc_zeroed(layout) System.alloc_zeroed(layout)
} else { } else {
System.alloc(layout) System.alloc(layout)
}; };
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
ptr.as_ptr(), ptr.as_ptr(),
size, size,
))) )))
}, },
} }
} }
// SAFETY: Same as `Allocator::grow` // SAFETY: Same as `Allocator::grow`
#[inline(always)] #[inline(always)]
unsafe fn grow_impl( unsafe fn grow_impl(
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
zeroed: bool, zeroed: bool,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() >= old_layout.size(), new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`" "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
); );
match old_layout.size() { match old_layout.size() {
0 => alloc_impl(new_layout, zeroed), 0 => alloc_impl(new_layout, zeroed),
// SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
// as required by safety conditions. Other conditions must be upheld by the caller // as required by safety conditions. Other conditions must be upheld by the caller
old_size if old_layout.align() == new_layout.align() => unsafe { old_size if old_layout.align() == new_layout.align() => unsafe {
let new_size = new_layout.size(); let new_size = new_layout.size();
// `realloc` probably checks for `new_size >= old_layout.size()` or something similar. // `realloc` probably checks for `new_size >= old_layout.size()` or something similar.
assume(new_size >= old_layout.size()); assume(new_size >= old_layout.size());
let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size); let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size);
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
if zeroed { if zeroed {
raw_ptr.add(old_size).write_bytes(0, new_size - old_size); raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
} }
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
ptr.as_ptr(), ptr.as_ptr(),
new_size, new_size,
))) )))
}, },
// SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`,
// both the old and new memory allocation are valid for reads and writes for `old_size` // both the old and new memory allocation are valid for reads and writes for `old_size`
// bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
// `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
// for `dealloc` must be upheld by the caller. // for `dealloc` must be upheld by the caller.
old_size => unsafe { old_size => unsafe {
let new_ptr = alloc_impl(new_layout, zeroed)?; let new_ptr = alloc_impl(new_layout, zeroed)?;
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_size); core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_size);
System.deallocate(ptr, old_layout); System.deallocate(ptr, old_layout);
Ok(new_ptr) Ok(new_ptr)
}, },
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,83 +1,83 @@
/// Creates a [`Vec`] containing the arguments. /// Creates a [`Vec`] containing the arguments.
/// ///
/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions. /// `vec!` allows `Vec`s to be defined with the same syntax as array expressions.
/// There are two forms of this macro: /// There are two forms of this macro:
/// ///
/// - Create a [`Vec`] containing a given list of elements: /// - Create a [`Vec`] containing a given list of elements:
/// ///
/// ``` /// ```
/// use allocator_api2::vec; /// use allocator_api2::vec;
/// let v = vec![1, 2, 3]; /// let v = vec![1, 2, 3];
/// assert_eq!(v[0], 1); /// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2); /// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3); /// assert_eq!(v[2], 3);
/// ``` /// ```
/// ///
/// ///
/// ``` /// ```
/// use allocator_api2::{vec, alloc::Global}; /// use allocator_api2::{vec, alloc::Global};
/// let v = vec![in Global; 1, 2, 3]; /// let v = vec![in Global; 1, 2, 3];
/// assert_eq!(v[0], 1); /// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2); /// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3); /// assert_eq!(v[2], 3);
/// ``` /// ```
/// ///
/// - Create a [`Vec`] from a given element and size: /// - Create a [`Vec`] from a given element and size:
/// ///
/// ``` /// ```
/// use allocator_api2::vec; /// use allocator_api2::vec;
/// let v = vec![1; 3]; /// let v = vec![1; 3];
/// assert_eq!(v, [1, 1, 1]); /// assert_eq!(v, [1, 1, 1]);
/// ``` /// ```
/// ///
/// ``` /// ```
/// use allocator_api2::{vec, alloc::Global}; /// use allocator_api2::{vec, alloc::Global};
/// let v = vec![in Global; 1; 3]; /// let v = vec![in Global; 1; 3];
/// assert_eq!(v, [1, 1, 1]); /// assert_eq!(v, [1, 1, 1]);
/// ``` /// ```
/// ///
/// Note that unlike array expressions this syntax supports all elements /// Note that unlike array expressions this syntax supports all elements
/// which implement [`Clone`] and the number of elements doesn't have to be /// which implement [`Clone`] and the number of elements doesn't have to be
/// a constant. /// a constant.
/// ///
/// This will use `clone` to duplicate an expression, so one should be careful /// This will use `clone` to duplicate an expression, so one should be careful
/// using this with types having a nonstandard `Clone` implementation. For /// using this with types having a nonstandard `Clone` implementation. For
/// example, `vec![Rc::new(1); 5]` will create a vector of five references /// example, `vec![Rc::new(1); 5]` will create a vector of five references
/// to the same boxed integer value, not five references pointing to independently /// to the same boxed integer value, not five references pointing to independently
/// boxed integers. /// boxed integers.
/// ///
/// Also, note that `vec![expr; 0]` is allowed, and produces an empty vector. /// Also, note that `vec![expr; 0]` is allowed, and produces an empty vector.
/// This will still evaluate `expr`, however, and immediately drop the resulting value, so /// This will still evaluate `expr`, however, and immediately drop the resulting value, so
/// be mindful of side effects. /// be mindful of side effects.
/// ///
/// [`Vec`]: crate::vec::Vec /// [`Vec`]: crate::vec::Vec
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[macro_export] #[macro_export]
macro_rules! vec { macro_rules! vec {
(in $alloc:expr $(;)?) => ( (in $alloc:expr $(;)?) => (
$crate::vec::Vec::new_in($alloc) $crate::vec::Vec::new_in($alloc)
); );
(in $alloc:expr; $elem:expr; $n:expr) => ( (in $alloc:expr; $elem:expr; $n:expr) => (
$crate::vec::from_elem_in($elem, $n, $alloc) $crate::vec::from_elem_in($elem, $n, $alloc)
); );
(in $alloc:expr; $($x:expr),+ $(,)?) => ( (in $alloc:expr; $($x:expr),+ $(,)?) => (
$crate::boxed::Box::<[_]>::into_vec( $crate::boxed::Box::<[_]>::into_vec(
$crate::boxed::Box::slice( $crate::boxed::Box::slice(
$crate::boxed::Box::new_in([$($x),+], $alloc) $crate::boxed::Box::new_in([$($x),+], $alloc)
) )
) )
); );
() => ( () => (
$crate::vec::Vec::new() $crate::vec::Vec::new()
); );
($elem:expr; $n:expr) => ( ($elem:expr; $n:expr) => (
$crate::vec::from_elem($elem, $n) $crate::vec::from_elem($elem, $n)
); );
($($x:expr),+ $(,)?) => ( ($($x:expr),+ $(,)?) => (
$crate::boxed::Box::<[_]>::into_vec( $crate::boxed::Box::<[_]>::into_vec(
$crate::boxed::Box::slice( $crate::boxed::Box::slice(
$crate::boxed::Box::new([$($x),+]) $crate::boxed::Box::new([$($x),+])
) )
) )
); );
} }

View File

@@ -1,105 +1,105 @@
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
#![allow(clippy::needless_doctest_main, clippy::partialeq_ne_impl)] #![allow(clippy::needless_doctest_main, clippy::partialeq_ne_impl)]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub use self::slice::SliceExt; pub use self::slice::SliceExt;
pub mod alloc; pub mod alloc;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub mod boxed; pub mod boxed;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
mod raw_vec; mod raw_vec;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub mod vec; pub mod vec;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
mod macros; mod macros;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
mod slice; mod slice;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
mod unique; mod unique;
/// Allows turning a [`Box<T: Sized, A>`][boxed::Box] into a [`Box<U: ?Sized, A>`][boxed::Box] where `T` can be unsizing-coerced into a `U`. /// Allows turning a [`Box<T: Sized, A>`][boxed::Box] into a [`Box<U: ?Sized, A>`][boxed::Box] where `T` can be unsizing-coerced into a `U`.
/// ///
/// This is the only way to create an `allocator_api2::boxed::Box` of an unsized type on stable. /// This is the only way to create an `allocator_api2::boxed::Box` of an unsized type on stable.
/// ///
/// With the standard library's `alloc::boxed::Box`, this is done automatically using the unstable unsize traits, but this crate's Box /// With the standard library's `alloc::boxed::Box`, this is done automatically using the unstable unsize traits, but this crate's Box
/// can't take advantage of that machinery on stable. So, we need to use type inference and the fact that you *can* /// can't take advantage of that machinery on stable. So, we need to use type inference and the fact that you *can*
/// still coerce the inner pointer of a box to get the compiler to help us unsize it using this macro. /// still coerce the inner pointer of a box to get the compiler to help us unsize it using this macro.
/// ///
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use allocator_api2::unsize_box; /// use allocator_api2::unsize_box;
/// use allocator_api2::boxed::Box; /// use allocator_api2::boxed::Box;
/// use core::any::Any; /// use core::any::Any;
/// ///
/// let sized_box: Box<u64> = Box::new(0); /// let sized_box: Box<u64> = Box::new(0);
/// let unsized_box: Box<dyn Any> = unsize_box!(sized_box); /// let unsized_box: Box<dyn Any> = unsize_box!(sized_box);
/// ``` /// ```
#[macro_export] #[macro_export]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
macro_rules! unsize_box {( $boxed:expr $(,)? ) => ({ macro_rules! unsize_box {( $boxed:expr $(,)? ) => ({
let (ptr, allocator) = ::allocator_api2::boxed::Box::into_raw_with_allocator($boxed); let (ptr, allocator) = ::allocator_api2::boxed::Box::into_raw_with_allocator($boxed);
// we don't want to allow casting to arbitrary type U, but we do want to allow unsize coercion to happen. // we don't want to allow casting to arbitrary type U, but we do want to allow unsize coercion to happen.
// that's exactly what's happening here -- this is *not* a pointer cast ptr as *mut _, but the compiler // that's exactly what's happening here -- this is *not* a pointer cast ptr as *mut _, but the compiler
// *will* allow an unsizing coercion to happen into the `ptr` place, if one is available. And we use _ so that the user can // *will* allow an unsizing coercion to happen into the `ptr` place, if one is available. And we use _ so that the user can
// fill in what they want the unsized type to be by annotating the type of the variable this macro will // fill in what they want the unsized type to be by annotating the type of the variable this macro will
// assign its result to. // assign its result to.
let ptr: *mut _ = ptr; let ptr: *mut _ = ptr;
// SAFETY: see above for why ptr's type can only be something that can be safely coerced. // SAFETY: see above for why ptr's type can only be something that can be safely coerced.
// also, ptr just came from a properly allocated box in the same allocator. // also, ptr just came from a properly allocated box in the same allocator.
unsafe { unsafe {
::allocator_api2::boxed::Box::from_raw_in(ptr, allocator) ::allocator_api2::boxed::Box::from_raw_in(ptr, allocator)
} }
})} })}
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub mod collections { pub mod collections {
pub use super::raw_vec::{TryReserveError, TryReserveErrorKind}; pub use super::raw_vec::{TryReserveError, TryReserveErrorKind};
} }
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[track_caller] #[track_caller]
#[inline(always)] #[inline(always)]
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
unsafe fn assume(v: bool) { unsafe fn assume(v: bool) {
if !v { if !v {
core::unreachable!() core::unreachable!()
} }
} }
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[track_caller] #[track_caller]
#[inline(always)] #[inline(always)]
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
unsafe fn assume(v: bool) { unsafe fn assume(v: bool) {
if !v { if !v {
unsafe { unsafe {
core::hint::unreachable_unchecked(); core::hint::unreachable_unchecked();
} }
} }
} }
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[inline(always)] #[inline(always)]
fn addr<T>(x: *const T) -> usize { fn addr<T>(x: *const T) -> usize {
#[allow(clippy::useless_transmute, clippy::transmutes_expressible_as_ptr_casts)] #[allow(clippy::useless_transmute, clippy::transmutes_expressible_as_ptr_casts)]
unsafe { unsafe {
core::mem::transmute(x) core::mem::transmute(x)
} }
} }
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[inline(always)] #[inline(always)]
fn invalid_mut<T>(addr: usize) -> *mut T { fn invalid_mut<T>(addr: usize) -> *mut T {
#[allow(clippy::useless_transmute, clippy::transmutes_expressible_as_ptr_casts)] #[allow(clippy::useless_transmute, clippy::transmutes_expressible_as_ptr_casts)]
unsafe { unsafe {
core::mem::transmute(addr) core::mem::transmute(addr)
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,171 +1,171 @@
use crate::{ use crate::{
alloc::{Allocator, Global}, alloc::{Allocator, Global},
vec::Vec, vec::Vec,
}; };
/// Slice methods that use `Box` and `Vec` from this crate. /// Slice methods that use `Box` and `Vec` from this crate.
pub trait SliceExt<T> { pub trait SliceExt<T> {
/// Copies `self` into a new `Vec`. /// Copies `self` into a new `Vec`.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// let s = [10, 40, 30]; /// let s = [10, 40, 30];
/// let x = s.to_vec(); /// let x = s.to_vec();
/// // Here, `s` and `x` can be modified independently. /// // Here, `s` and `x` can be modified independently.
/// ``` /// ```
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[inline(always)] #[inline(always)]
fn to_vec(&self) -> Vec<T, Global> fn to_vec(&self) -> Vec<T, Global>
where where
T: Clone, T: Clone,
{ {
self.to_vec_in(Global) self.to_vec_in(Global)
} }
/// Copies `self` into a new `Vec` with an allocator. /// Copies `self` into a new `Vec` with an allocator.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(allocator_api)] /// #![feature(allocator_api)]
/// ///
/// use std::alloc::System; /// use std::alloc::System;
/// ///
/// let s = [10, 40, 30]; /// let s = [10, 40, 30];
/// let x = s.to_vec_in(System); /// let x = s.to_vec_in(System);
/// // Here, `s` and `x` can be modified independently. /// // Here, `s` and `x` can be modified independently.
/// ``` /// ```
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A> fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A>
where where
T: Clone; T: Clone;
/// Creates a vector by copying a slice `n` times. /// Creates a vector by copying a slice `n` times.
/// ///
/// # Panics /// # Panics
/// ///
/// This function will panic if the capacity would overflow. /// This function will panic if the capacity would overflow.
/// ///
/// # Examples /// # Examples
/// ///
/// Basic usage: /// Basic usage:
/// ///
/// ``` /// ```
/// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
/// ``` /// ```
/// ///
/// A panic upon overflow: /// A panic upon overflow:
/// ///
/// ```should_panic /// ```should_panic
/// // this will panic at runtime /// // this will panic at runtime
/// b"0123456789abcdef".repeat(usize::MAX); /// b"0123456789abcdef".repeat(usize::MAX);
/// ``` /// ```
fn repeat(&self, n: usize) -> Vec<T, Global> fn repeat(&self, n: usize) -> Vec<T, Global>
where where
T: Copy; T: Copy;
} }
impl<T> SliceExt<T> for [T] { impl<T> SliceExt<T> for [T] {
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[inline] #[inline]
fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A> fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A>
where where
T: Clone, T: Clone,
{ {
struct DropGuard<'a, T, A: Allocator> { struct DropGuard<'a, T, A: Allocator> {
vec: &'a mut Vec<T, A>, vec: &'a mut Vec<T, A>,
num_init: usize, num_init: usize,
} }
impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
// SAFETY: // SAFETY:
// items were marked initialized in the loop below // items were marked initialized in the loop below
unsafe { unsafe {
self.vec.set_len(self.num_init); self.vec.set_len(self.num_init);
} }
} }
} }
let mut vec = Vec::with_capacity_in(self.len(), alloc); let mut vec = Vec::with_capacity_in(self.len(), alloc);
let mut guard = DropGuard { let mut guard = DropGuard {
vec: &mut vec, vec: &mut vec,
num_init: 0, num_init: 0,
}; };
let slots = guard.vec.spare_capacity_mut(); let slots = guard.vec.spare_capacity_mut();
// .take(slots.len()) is necessary for LLVM to remove bounds checks // .take(slots.len()) is necessary for LLVM to remove bounds checks
// and has better codegen than zip. // and has better codegen than zip.
for (i, b) in self.iter().enumerate().take(slots.len()) { for (i, b) in self.iter().enumerate().take(slots.len()) {
guard.num_init = i; guard.num_init = i;
slots[i].write(b.clone()); slots[i].write(b.clone());
} }
core::mem::forget(guard); core::mem::forget(guard);
// SAFETY: // SAFETY:
// the vec was allocated and initialized above to at least this length. // the vec was allocated and initialized above to at least this length.
unsafe { unsafe {
vec.set_len(self.len()); vec.set_len(self.len());
} }
vec vec
} }
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[inline] #[inline]
fn repeat(&self, n: usize) -> Vec<T, Global> fn repeat(&self, n: usize) -> Vec<T, Global>
where where
T: Copy, T: Copy,
{ {
if n == 0 { if n == 0 {
return Vec::new(); return Vec::new();
} }
// If `n` is larger than zero, it can be split as // If `n` is larger than zero, it can be split as
// `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`. // `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`.
// `2^expn` is the number represented by the leftmost '1' bit of `n`, // `2^expn` is the number represented by the leftmost '1' bit of `n`,
// and `rem` is the remaining part of `n`. // and `rem` is the remaining part of `n`.
// Using `Vec` to access `set_len()`. // Using `Vec` to access `set_len()`.
let capacity = self.len().checked_mul(n).expect("capacity overflow"); let capacity = self.len().checked_mul(n).expect("capacity overflow");
let mut buf = Vec::with_capacity(capacity); let mut buf = Vec::with_capacity(capacity);
// `2^expn` repetition is done by doubling `buf` `expn`-times. // `2^expn` repetition is done by doubling `buf` `expn`-times.
buf.extend(self); buf.extend(self);
{ {
let mut m = n >> 1; let mut m = n >> 1;
// If `m > 0`, there are remaining bits up to the leftmost '1'. // If `m > 0`, there are remaining bits up to the leftmost '1'.
while m > 0 { while m > 0 {
// `buf.extend(buf)`: // `buf.extend(buf)`:
unsafe { unsafe {
core::ptr::copy_nonoverlapping( core::ptr::copy_nonoverlapping(
buf.as_ptr(), buf.as_ptr(),
(buf.as_mut_ptr() as *mut T).add(buf.len()), (buf.as_mut_ptr() as *mut T).add(buf.len()),
buf.len(), buf.len(),
); );
// `buf` has capacity of `self.len() * n`. // `buf` has capacity of `self.len() * n`.
let buf_len = buf.len(); let buf_len = buf.len();
buf.set_len(buf_len * 2); buf.set_len(buf_len * 2);
} }
m >>= 1; m >>= 1;
} }
} }
// `rem` (`= n - 2^expn`) repetition is done by copying // `rem` (`= n - 2^expn`) repetition is done by copying
// first `rem` repetitions from `buf` itself. // first `rem` repetitions from `buf` itself.
let rem_len = capacity - buf.len(); // `self.len() * rem` let rem_len = capacity - buf.len(); // `self.len() * rem`
if rem_len > 0 { if rem_len > 0 {
// `buf.extend(buf[0 .. rem_len])`: // `buf.extend(buf[0 .. rem_len])`:
unsafe { unsafe {
// This is non-overlapping since `2^expn > rem`. // This is non-overlapping since `2^expn > rem`.
core::ptr::copy_nonoverlapping( core::ptr::copy_nonoverlapping(
buf.as_ptr(), buf.as_ptr(),
(buf.as_mut_ptr() as *mut T).add(buf.len()), (buf.as_mut_ptr() as *mut T).add(buf.len()),
rem_len, rem_len,
); );
// `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`). // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`).
buf.set_len(capacity); buf.set_len(capacity);
} }
} }
buf buf
} }
} }

View File

@@ -1,106 +1,106 @@
/// A wrapper around a raw non-null `*mut T` that indicates that the possessor /// A wrapper around a raw non-null `*mut T` that indicates that the possessor
/// of this wrapper owns the referent. Useful for building abstractions like /// of this wrapper owns the referent. Useful for building abstractions like
/// `Box<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`. /// `Box<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`.
/// ///
/// Unlike `*mut T`, `Unique<T>` behaves "as if" it were an instance of `T`. /// Unlike `*mut T`, `Unique<T>` behaves "as if" it were an instance of `T`.
/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies /// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies
/// the kind of strong aliasing guarantees an instance of `T` can expect: /// the kind of strong aliasing guarantees an instance of `T` can expect:
/// the referent of the pointer should not be modified without a unique path to /// the referent of the pointer should not be modified without a unique path to
/// its owning Unique. /// its owning Unique.
/// ///
/// If you're uncertain of whether it's correct to use `Unique` for your purposes, /// If you're uncertain of whether it's correct to use `Unique` for your purposes,
/// consider using `NonNull`, which has weaker semantics. /// consider using `NonNull`, which has weaker semantics.
/// ///
/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer /// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
/// is never dereferenced. This is so that enums may use this forbidden value /// is never dereferenced. This is so that enums may use this forbidden value
/// as a discriminant -- `Option<Unique<T>>` has the same size as `Unique<T>`. /// as a discriminant -- `Option<Unique<T>>` has the same size as `Unique<T>`.
/// However the pointer may still dangle if it isn't dereferenced. /// However the pointer may still dangle if it isn't dereferenced.
/// ///
/// Unlike `*mut T`, `Unique<T>` is covariant over `T`. This should always be correct /// Unlike `*mut T`, `Unique<T>` is covariant over `T`. This should always be correct
/// for any type which upholds Unique's aliasing requirements. /// for any type which upholds Unique's aliasing requirements.
#[repr(transparent)] #[repr(transparent)]
pub(crate) struct Unique<T: ?Sized> { pub(crate) struct Unique<T: ?Sized> {
pointer: NonNull<T>, pointer: NonNull<T>,
_marker: PhantomData<T>, _marker: PhantomData<T>,
} }
/// `Unique` pointers are `Send` if `T` is `Send` because the data they /// `Unique` pointers are `Send` if `T` is `Send` because the data they
/// reference is unaliased. Note that this aliasing invariant is /// reference is unaliased. Note that this aliasing invariant is
/// unenforced by the type system; the abstraction using the /// unenforced by the type system; the abstraction using the
/// `Unique` must enforce it. /// `Unique` must enforce it.
unsafe impl<T: Send + ?Sized> Send for Unique<T> {} unsafe impl<T: Send + ?Sized> Send for Unique<T> {}
/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they /// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
/// reference is unaliased. Note that this aliasing invariant is /// reference is unaliased. Note that this aliasing invariant is
/// unenforced by the type system; the abstraction using the /// unenforced by the type system; the abstraction using the
/// `Unique` must enforce it. /// `Unique` must enforce it.
unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {} unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {}
impl<T: ?Sized> Unique<T> { impl<T: ?Sized> Unique<T> {
/// Creates a new `Unique`. /// Creates a new `Unique`.
/// ///
/// # Safety /// # Safety
/// ///
/// `ptr` must be non-null. /// `ptr` must be non-null.
#[inline] #[inline]
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
// SAFETY: the caller must guarantee that `ptr` is non-null. // SAFETY: the caller must guarantee that `ptr` is non-null.
unsafe { unsafe {
Unique { Unique {
pointer: NonNull::new_unchecked(ptr), pointer: NonNull::new_unchecked(ptr),
_marker: PhantomData, _marker: PhantomData,
} }
} }
} }
/// Acquires the underlying `*mut` pointer. /// Acquires the underlying `*mut` pointer.
#[must_use = "`self` will be dropped if the result is not used"] #[must_use = "`self` will be dropped if the result is not used"]
#[inline] #[inline]
pub const fn as_ptr(self) -> *mut T { pub const fn as_ptr(self) -> *mut T {
self.pointer.as_ptr() self.pointer.as_ptr()
} }
/// Acquires the underlying `*mut` pointer. /// Acquires the underlying `*mut` pointer.
#[must_use = "`self` will be dropped if the result is not used"] #[must_use = "`self` will be dropped if the result is not used"]
#[inline] #[inline]
pub const fn as_non_null_ptr(self) -> NonNull<T> { pub const fn as_non_null_ptr(self) -> NonNull<T> {
self.pointer self.pointer
} }
/// Dereferences the content. /// Dereferences the content.
/// ///
/// The resulting lifetime is bound to self so this behaves "as if" /// The resulting lifetime is bound to self so this behaves "as if"
/// it were actually an instance of T that is getting borrowed. If a longer /// it were actually an instance of T that is getting borrowed. If a longer
/// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
#[must_use] #[must_use]
#[inline] #[inline]
pub const unsafe fn as_ref(&self) -> &T { pub const unsafe fn as_ref(&self) -> &T {
// SAFETY: the caller must guarantee that `self` meets all the // SAFETY: the caller must guarantee that `self` meets all the
// requirements for a reference. // requirements for a reference.
unsafe { &*(self.as_ptr() as *const T) } unsafe { &*(self.as_ptr() as *const T) }
} }
/// Mutably dereferences the content. /// Mutably dereferences the content.
/// ///
/// The resulting lifetime is bound to self so this behaves "as if" /// The resulting lifetime is bound to self so this behaves "as if"
/// it were actually an instance of T that is getting borrowed. If a longer /// it were actually an instance of T that is getting borrowed. If a longer
/// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
#[must_use] #[must_use]
#[inline] #[inline]
pub unsafe fn as_mut(&mut self) -> &mut T { pub unsafe fn as_mut(&mut self) -> &mut T {
// SAFETY: the caller must guarantee that `self` meets all the // SAFETY: the caller must guarantee that `self` meets all the
// requirements for a mutable reference. // requirements for a mutable reference.
unsafe { self.pointer.as_mut() } unsafe { self.pointer.as_mut() }
} }
} }
impl<T: ?Sized> Clone for Unique<T> { impl<T: ?Sized> Clone for Unique<T> {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
*self *self
} }
} }
impl<T: ?Sized> Copy for Unique<T> {} impl<T: ?Sized> Copy for Unique<T> {}
use core::{marker::PhantomData, ptr::NonNull}; use core::{marker::PhantomData, ptr::NonNull};

View File

@@ -1,242 +1,242 @@
use core::fmt; use core::fmt;
use core::iter::FusedIterator; use core::iter::FusedIterator;
use core::mem::{self, size_of, ManuallyDrop}; use core::mem::{self, size_of, ManuallyDrop};
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
use core::slice::{self}; use core::slice::{self};
use crate::stable::alloc::{Allocator, Global}; use crate::stable::alloc::{Allocator, Global};
use super::Vec; use super::Vec;
/// A draining iterator for `Vec<T>`. /// A draining iterator for `Vec<T>`.
/// ///
/// This `struct` is created by [`Vec::drain`]. /// This `struct` is created by [`Vec::drain`].
/// See its documentation for more. /// See its documentation for more.
/// ///
/// # Example /// # Example
/// ///
/// ``` /// ```
/// let mut v = vec![0, 1, 2]; /// let mut v = vec![0, 1, 2];
/// let iter: std::vec::Drain<_> = v.drain(..); /// let iter: std::vec::Drain<_> = v.drain(..);
/// ``` /// ```
pub struct Drain<'a, T: 'a, A: Allocator + 'a = Global> { pub struct Drain<'a, T: 'a, A: Allocator + 'a = Global> {
/// Index of tail to preserve /// Index of tail to preserve
pub(super) tail_start: usize, pub(super) tail_start: usize,
/// Length of tail /// Length of tail
pub(super) tail_len: usize, pub(super) tail_len: usize,
/// Current remaining range to remove /// Current remaining range to remove
pub(super) iter: slice::Iter<'a, T>, pub(super) iter: slice::Iter<'a, T>,
pub(super) vec: NonNull<Vec<T, A>>, pub(super) vec: NonNull<Vec<T, A>>,
} }
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> { impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
} }
} }
impl<'a, T, A: Allocator> Drain<'a, T, A> { impl<'a, T, A: Allocator> Drain<'a, T, A> {
/// Returns the remaining items of this iterator as a slice. /// Returns the remaining items of this iterator as a slice.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// let mut vec = vec!['a', 'b', 'c']; /// let mut vec = vec!['a', 'b', 'c'];
/// let mut drain = vec.drain(..); /// let mut drain = vec.drain(..);
/// assert_eq!(drain.as_slice(), &['a', 'b', 'c']); /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
/// let _ = drain.next().unwrap(); /// let _ = drain.next().unwrap();
/// assert_eq!(drain.as_slice(), &['b', 'c']); /// assert_eq!(drain.as_slice(), &['b', 'c']);
/// ``` /// ```
#[must_use] #[must_use]
#[inline(always)] #[inline(always)]
pub fn as_slice(&self) -> &[T] { pub fn as_slice(&self) -> &[T] {
self.iter.as_slice() self.iter.as_slice()
} }
/// Returns a reference to the underlying allocator. /// Returns a reference to the underlying allocator.
#[must_use] #[must_use]
#[inline(always)] #[inline(always)]
pub fn allocator(&self) -> &A { pub fn allocator(&self) -> &A {
unsafe { self.vec.as_ref().allocator() } unsafe { self.vec.as_ref().allocator() }
} }
/// Keep unyielded elements in the source `Vec`. /// Keep unyielded elements in the source `Vec`.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(drain_keep_rest)] /// #![feature(drain_keep_rest)]
/// ///
/// let mut vec = vec!['a', 'b', 'c']; /// let mut vec = vec!['a', 'b', 'c'];
/// let mut drain = vec.drain(..); /// let mut drain = vec.drain(..);
/// ///
/// assert_eq!(drain.next().unwrap(), 'a'); /// assert_eq!(drain.next().unwrap(), 'a');
/// ///
/// // This call keeps 'b' and 'c' in the vec. /// // This call keeps 'b' and 'c' in the vec.
/// drain.keep_rest(); /// drain.keep_rest();
/// ///
/// // If we wouldn't call `keep_rest()`, /// // If we wouldn't call `keep_rest()`,
/// // `vec` would be empty. /// // `vec` would be empty.
/// assert_eq!(vec, ['b', 'c']); /// assert_eq!(vec, ['b', 'c']);
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn keep_rest(self) { pub fn keep_rest(self) {
// At this moment layout looks like this: // At this moment layout looks like this:
// //
// [head] [yielded by next] [unyielded] [yielded by next_back] [tail] // [head] [yielded by next] [unyielded] [yielded by next_back] [tail]
// ^-- start \_________/-- unyielded_len \____/-- self.tail_len // ^-- start \_________/-- unyielded_len \____/-- self.tail_len
// ^-- unyielded_ptr ^-- tail // ^-- unyielded_ptr ^-- tail
// //
// Normally `Drop` impl would drop [unyielded] and then move [tail] to the `start`. // Normally `Drop` impl would drop [unyielded] and then move [tail] to the `start`.
// Here we want to // Here we want to
// 1. Move [unyielded] to `start` // 1. Move [unyielded] to `start`
// 2. Move [tail] to a new start at `start + len(unyielded)` // 2. Move [tail] to a new start at `start + len(unyielded)`
// 3. Update length of the original vec to `len(head) + len(unyielded) + len(tail)` // 3. Update length of the original vec to `len(head) + len(unyielded) + len(tail)`
// a. In case of ZST, this is the only thing we want to do // a. In case of ZST, this is the only thing we want to do
// 4. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do // 4. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
let mut this = ManuallyDrop::new(self); let mut this = ManuallyDrop::new(self);
unsafe { unsafe {
let source_vec = this.vec.as_mut(); let source_vec = this.vec.as_mut();
let start = source_vec.len(); let start = source_vec.len();
let tail = this.tail_start; let tail = this.tail_start;
let unyielded_len = this.iter.len(); let unyielded_len = this.iter.len();
let unyielded_ptr = this.iter.as_slice().as_ptr(); let unyielded_ptr = this.iter.as_slice().as_ptr();
// ZSTs have no identity, so we don't need to move them around. // ZSTs have no identity, so we don't need to move them around.
let needs_move = mem::size_of::<T>() != 0; let needs_move = mem::size_of::<T>() != 0;
if needs_move { if needs_move {
let start_ptr = source_vec.as_mut_ptr().add(start); let start_ptr = source_vec.as_mut_ptr().add(start);
// memmove back unyielded elements // memmove back unyielded elements
if unyielded_ptr != start_ptr { if unyielded_ptr != start_ptr {
let src = unyielded_ptr; let src = unyielded_ptr;
let dst = start_ptr; let dst = start_ptr;
ptr::copy(src, dst, unyielded_len); ptr::copy(src, dst, unyielded_len);
} }
// memmove back untouched tail // memmove back untouched tail
if tail != (start + unyielded_len) { if tail != (start + unyielded_len) {
let src = source_vec.as_ptr().add(tail); let src = source_vec.as_ptr().add(tail);
let dst = start_ptr.add(unyielded_len); let dst = start_ptr.add(unyielded_len);
ptr::copy(src, dst, this.tail_len); ptr::copy(src, dst, this.tail_len);
} }
} }
source_vec.set_len(start + unyielded_len + this.tail_len); source_vec.set_len(start + unyielded_len + this.tail_len);
} }
} }
} }
impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> { impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> {
#[inline(always)] #[inline(always)]
fn as_ref(&self) -> &[T] { fn as_ref(&self) -> &[T] {
self.as_slice() self.as_slice()
} }
} }
unsafe impl<T: Sync, A: Sync + Allocator> Sync for Drain<'_, T, A> {} unsafe impl<T: Sync, A: Sync + Allocator> Sync for Drain<'_, T, A> {}
unsafe impl<T: Send, A: Send + Allocator> Send for Drain<'_, T, A> {} unsafe impl<T: Send, A: Send + Allocator> Send for Drain<'_, T, A> {}
impl<T, A: Allocator> Iterator for Drain<'_, T, A> { impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
type Item = T; type Item = T;
#[inline(always)] #[inline(always)]
fn next(&mut self) -> Option<T> { fn next(&mut self) -> Option<T> {
self.iter self.iter
.next() .next()
.map(|elt| unsafe { ptr::read(elt as *const _) }) .map(|elt| unsafe { ptr::read(elt as *const _) })
} }
#[inline(always)] #[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint() self.iter.size_hint()
} }
} }
impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> { impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
#[inline(always)] #[inline(always)]
fn next_back(&mut self) -> Option<T> { fn next_back(&mut self) -> Option<T> {
self.iter self.iter
.next_back() .next_back()
.map(|elt| unsafe { ptr::read(elt as *const _) }) .map(|elt| unsafe { ptr::read(elt as *const _) })
} }
} }
impl<T, A: Allocator> Drop for Drain<'_, T, A> { impl<T, A: Allocator> Drop for Drain<'_, T, A> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
/// Moves back the un-`Drain`ed elements to restore the original `Vec`. /// Moves back the un-`Drain`ed elements to restore the original `Vec`.
struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>); struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> { impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
fn drop(&mut self) { fn drop(&mut self) {
if self.0.tail_len > 0 { if self.0.tail_len > 0 {
unsafe { unsafe {
let source_vec = self.0.vec.as_mut(); let source_vec = self.0.vec.as_mut();
// memmove back untouched tail, update to new length // memmove back untouched tail, update to new length
let start = source_vec.len(); let start = source_vec.len();
let tail = self.0.tail_start; let tail = self.0.tail_start;
if tail != start { if tail != start {
let src = source_vec.as_ptr().add(tail); let src = source_vec.as_ptr().add(tail);
let dst = source_vec.as_mut_ptr().add(start); let dst = source_vec.as_mut_ptr().add(start);
ptr::copy(src, dst, self.0.tail_len); ptr::copy(src, dst, self.0.tail_len);
} }
source_vec.set_len(start + self.0.tail_len); source_vec.set_len(start + self.0.tail_len);
} }
} }
} }
} }
let iter = mem::replace(&mut self.iter, [].iter()); let iter = mem::replace(&mut self.iter, [].iter());
let drop_len = iter.len(); let drop_len = iter.len();
let mut vec = self.vec; let mut vec = self.vec;
if size_of::<T>() == 0 { if size_of::<T>() == 0 {
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount. // ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
// this can be achieved by manipulating the Vec length instead of moving values out from `iter`. // this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
unsafe { unsafe {
let vec = vec.as_mut(); let vec = vec.as_mut();
let old_len = vec.len(); let old_len = vec.len();
vec.set_len(old_len + drop_len + self.tail_len); vec.set_len(old_len + drop_len + self.tail_len);
vec.truncate(old_len + self.tail_len); vec.truncate(old_len + self.tail_len);
} }
return; return;
} }
// ensure elements are moved back into their appropriate places, even when drop_in_place panics // ensure elements are moved back into their appropriate places, even when drop_in_place panics
let _guard = DropGuard(self); let _guard = DropGuard(self);
if drop_len == 0 { if drop_len == 0 {
return; return;
} }
// as_slice() must only be called when iter.len() is > 0 because // as_slice() must only be called when iter.len() is > 0 because
// vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate // vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate
// the iterator's internal pointers. Creating a reference to deallocated memory // the iterator's internal pointers. Creating a reference to deallocated memory
// is invalid even when it is zero-length // is invalid even when it is zero-length
let drop_ptr = iter.as_slice().as_ptr(); let drop_ptr = iter.as_slice().as_ptr();
unsafe { unsafe {
// drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place // drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place
// a pointer with mutable provenance is necessary. Therefore we must reconstruct // a pointer with mutable provenance is necessary. Therefore we must reconstruct
// it from the original vec but also avoid creating a &mut to the front since that could // it from the original vec but also avoid creating a &mut to the front since that could
// invalidate raw pointers to it which some unsafe code might rely on. // invalidate raw pointers to it which some unsafe code might rely on.
let vec_ptr = vec.as_mut().as_mut_ptr(); let vec_ptr = vec.as_mut().as_mut_ptr();
let drop_offset = drop_ptr.offset_from(vec_ptr) as usize; let drop_offset = drop_ptr.offset_from(vec_ptr) as usize;
let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len); let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len);
ptr::drop_in_place(to_drop); ptr::drop_in_place(to_drop);
} }
} }
} }
impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {} impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {}
impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {} impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}

View File

@@ -1,191 +1,191 @@
use core::fmt; use core::fmt;
use core::iter::FusedIterator; use core::iter::FusedIterator;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::{self, size_of, ManuallyDrop}; use core::mem::{self, size_of, ManuallyDrop};
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
use core::slice::{self}; use core::slice::{self};
use crate::stable::addr; use crate::stable::addr;
use super::{Allocator, Global, RawVec}; use super::{Allocator, Global, RawVec};
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
use super::Vec; use super::Vec;
/// An iterator that moves out of a vector. /// An iterator that moves out of a vector.
/// ///
/// This `struct` is created by the `into_iter` method on [`Vec`](super::Vec) /// This `struct` is created by the `into_iter` method on [`Vec`](super::Vec)
/// (provided by the [`IntoIterator`] trait). /// (provided by the [`IntoIterator`] trait).
/// ///
/// # Example /// # Example
/// ///
/// ``` /// ```
/// let v = vec![0, 1, 2]; /// let v = vec![0, 1, 2];
/// let iter: std::vec::IntoIter<_> = v.into_iter(); /// let iter: std::vec::IntoIter<_> = v.into_iter();
/// ``` /// ```
pub struct IntoIter<T, A: Allocator = Global> { pub struct IntoIter<T, A: Allocator = Global> {
pub(super) buf: NonNull<T>, pub(super) buf: NonNull<T>,
pub(super) phantom: PhantomData<T>, pub(super) phantom: PhantomData<T>,
pub(super) cap: usize, pub(super) cap: usize,
// the drop impl reconstructs a RawVec from buf, cap and alloc // the drop impl reconstructs a RawVec from buf, cap and alloc
// to avoid dropping the allocator twice we need to wrap it into ManuallyDrop // to avoid dropping the allocator twice we need to wrap it into ManuallyDrop
pub(super) alloc: ManuallyDrop<A>, pub(super) alloc: ManuallyDrop<A>,
pub(super) ptr: *const T, pub(super) ptr: *const T,
pub(super) end: *const T, pub(super) end: *const T,
} }
impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> { impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoIter").field(&self.as_slice()).finish() f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
} }
} }
impl<T, A: Allocator> IntoIter<T, A> { impl<T, A: Allocator> IntoIter<T, A> {
/// Returns the remaining items of this iterator as a slice. /// Returns the remaining items of this iterator as a slice.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// let vec = vec!['a', 'b', 'c']; /// let vec = vec!['a', 'b', 'c'];
/// let mut into_iter = vec.into_iter(); /// let mut into_iter = vec.into_iter();
/// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
/// let _ = into_iter.next().unwrap(); /// let _ = into_iter.next().unwrap();
/// assert_eq!(into_iter.as_slice(), &['b', 'c']); /// assert_eq!(into_iter.as_slice(), &['b', 'c']);
/// ``` /// ```
pub fn as_slice(&self) -> &[T] { pub fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.ptr, self.len()) } unsafe { slice::from_raw_parts(self.ptr, self.len()) }
} }
/// Returns the remaining items of this iterator as a mutable slice. /// Returns the remaining items of this iterator as a mutable slice.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// let vec = vec!['a', 'b', 'c']; /// let vec = vec!['a', 'b', 'c'];
/// let mut into_iter = vec.into_iter(); /// let mut into_iter = vec.into_iter();
/// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
/// into_iter.as_mut_slice()[2] = 'z'; /// into_iter.as_mut_slice()[2] = 'z';
/// assert_eq!(into_iter.next().unwrap(), 'a'); /// assert_eq!(into_iter.next().unwrap(), 'a');
/// assert_eq!(into_iter.next().unwrap(), 'b'); /// assert_eq!(into_iter.next().unwrap(), 'b');
/// assert_eq!(into_iter.next().unwrap(), 'z'); /// assert_eq!(into_iter.next().unwrap(), 'z');
/// ``` /// ```
pub fn as_mut_slice(&mut self) -> &mut [T] { pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { &mut *self.as_raw_mut_slice() } unsafe { &mut *self.as_raw_mut_slice() }
} }
/// Returns a reference to the underlying allocator. /// Returns a reference to the underlying allocator.
#[inline(always)] #[inline(always)]
pub fn allocator(&self) -> &A { pub fn allocator(&self) -> &A {
&self.alloc &self.alloc
} }
fn as_raw_mut_slice(&mut self) -> *mut [T] { fn as_raw_mut_slice(&mut self) -> *mut [T] {
ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len()) ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len())
} }
} }
impl<T, A: Allocator> AsRef<[T]> for IntoIter<T, A> { impl<T, A: Allocator> AsRef<[T]> for IntoIter<T, A> {
fn as_ref(&self) -> &[T] { fn as_ref(&self) -> &[T] {
self.as_slice() self.as_slice()
} }
} }
unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {} unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {}
unsafe impl<T: Sync, A: Allocator + Sync> Sync for IntoIter<T, A> {} unsafe impl<T: Sync, A: Allocator + Sync> Sync for IntoIter<T, A> {}
impl<T, A: Allocator> Iterator for IntoIter<T, A> { impl<T, A: Allocator> Iterator for IntoIter<T, A> {
type Item = T; type Item = T;
#[inline(always)] #[inline(always)]
fn next(&mut self) -> Option<T> { fn next(&mut self) -> Option<T> {
if self.ptr == self.end { if self.ptr == self.end {
None None
} else if size_of::<T>() == 0 { } else if size_of::<T>() == 0 {
// purposefully don't use 'ptr.offset' because for // purposefully don't use 'ptr.offset' because for
// vectors with 0-size elements this would return the // vectors with 0-size elements this would return the
// same pointer. // same pointer.
self.ptr = self.ptr.cast::<u8>().wrapping_add(1).cast(); self.ptr = self.ptr.cast::<u8>().wrapping_add(1).cast();
// Make up a value of this ZST. // Make up a value of this ZST.
Some(unsafe { mem::zeroed() }) Some(unsafe { mem::zeroed() })
} else { } else {
let old = self.ptr; let old = self.ptr;
self.ptr = unsafe { self.ptr.add(1) }; self.ptr = unsafe { self.ptr.add(1) };
Some(unsafe { ptr::read(old) }) Some(unsafe { ptr::read(old) })
} }
} }
#[inline(always)] #[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
let exact = if size_of::<T>() == 0 { let exact = if size_of::<T>() == 0 {
addr(self.end).wrapping_sub(addr(self.ptr)) addr(self.end).wrapping_sub(addr(self.ptr))
} else { } else {
unsafe { self.end.offset_from(self.ptr) as usize } unsafe { self.end.offset_from(self.ptr) as usize }
}; };
(exact, Some(exact)) (exact, Some(exact))
} }
#[inline(always)] #[inline(always)]
fn count(self) -> usize { fn count(self) -> usize {
self.len() self.len()
} }
} }
impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> { impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
#[inline(always)] #[inline(always)]
fn next_back(&mut self) -> Option<T> { fn next_back(&mut self) -> Option<T> {
if self.end == self.ptr { if self.end == self.ptr {
None None
} else if size_of::<T>() == 0 { } else if size_of::<T>() == 0 {
// See above for why 'ptr.offset' isn't used // See above for why 'ptr.offset' isn't used
self.end = self.end.cast::<u8>().wrapping_add(1).cast(); self.end = self.end.cast::<u8>().wrapping_add(1).cast();
// Make up a value of this ZST. // Make up a value of this ZST.
Some(unsafe { mem::zeroed() }) Some(unsafe { mem::zeroed() })
} else { } else {
self.end = unsafe { self.end.sub(1) }; self.end = unsafe { self.end.sub(1) };
Some(unsafe { ptr::read(self.end) }) Some(unsafe { ptr::read(self.end) })
} }
} }
} }
impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {} impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {}
impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {} impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> { impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
let mut vec = Vec::<T, A>::with_capacity_in(self.len(), (*self.alloc).clone()); let mut vec = Vec::<T, A>::with_capacity_in(self.len(), (*self.alloc).clone());
vec.extend(self.as_slice().iter().cloned()); vec.extend(self.as_slice().iter().cloned());
vec.into_iter() vec.into_iter()
} }
} }
impl<T, A: Allocator> Drop for IntoIter<T, A> { impl<T, A: Allocator> Drop for IntoIter<T, A> {
fn drop(&mut self) { fn drop(&mut self) {
struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter<T, A>); struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter<T, A>);
impl<T, A: Allocator> Drop for DropGuard<'_, T, A> { impl<T, A: Allocator> Drop for DropGuard<'_, T, A> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
// `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec // `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec
let alloc = ManuallyDrop::take(&mut self.0.alloc); let alloc = ManuallyDrop::take(&mut self.0.alloc);
// RawVec handles deallocation // RawVec handles deallocation
let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc); let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc);
} }
} }
} }
let guard = DropGuard(self); let guard = DropGuard(self);
// destroy the remaining elements // destroy the remaining elements
unsafe { unsafe {
ptr::drop_in_place(guard.0.as_raw_mut_slice()); ptr::drop_in_place(guard.0.as_raw_mut_slice());
} }
// now `guard` will be dropped and do the rest // now `guard` will be dropped and do the rest
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,43 +1,43 @@
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
use alloc_crate::borrow::Cow; use alloc_crate::borrow::Cow;
use crate::stable::alloc::Allocator; use crate::stable::alloc::Allocator;
use super::Vec; use super::Vec;
macro_rules! __impl_slice_eq1 { macro_rules! __impl_slice_eq1 {
([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => { ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => {
impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
where where
T: PartialEq<U>, T: PartialEq<U>,
$($ty: $bound)? $($ty: $bound)?
{ {
#[inline(always)] #[inline(always)]
fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] } fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
#[inline(always)] #[inline(always)]
fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] } fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] }
} }
} }
} }
__impl_slice_eq1! { [A1: Allocator, A2: Allocator] Vec<T, A1>, Vec<U, A2> } __impl_slice_eq1! { [A1: Allocator, A2: Allocator] Vec<T, A1>, Vec<U, A2> }
__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &[U] } __impl_slice_eq1! { [A: Allocator] Vec<T, A>, &[U] }
__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &mut [U] } __impl_slice_eq1! { [A: Allocator] Vec<T, A>, &mut [U] }
__impl_slice_eq1! { [A: Allocator] &[T], Vec<U, A> } __impl_slice_eq1! { [A: Allocator] &[T], Vec<U, A> }
__impl_slice_eq1! { [A: Allocator] &mut [T], Vec<U, A> } __impl_slice_eq1! { [A: Allocator] &mut [T], Vec<U, A> }
__impl_slice_eq1! { [A: Allocator] Vec<T, A>, [U] } __impl_slice_eq1! { [A: Allocator] Vec<T, A>, [U] }
__impl_slice_eq1! { [A: Allocator] [T], Vec<U, A> } __impl_slice_eq1! { [A: Allocator] [T], Vec<U, A> }
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec<U, A> where T: Clone } __impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec<U, A> where T: Clone }
__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] } __impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] } __impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
// NOTE: some less important impls are omitted to reduce code bloat // NOTE: some less important impls are omitted to reduce code bloat
// FIXME(Centril): Reconsider this? // FIXME(Centril): Reconsider this?
//__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], } //__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], }
//__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, } //__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, }
//__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, } //__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, }
//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, } //__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, }
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], } //__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], }
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], } //__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], }
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], } //__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], }

View File

@@ -1,31 +1,31 @@
// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. // Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
// //
// The idea is: The length field in SetLenOnDrop is a local variable // The idea is: The length field in SetLenOnDrop is a local variable
// that the optimizer will see does not alias with any stores through the Vec's data // that the optimizer will see does not alias with any stores through the Vec's data
// pointer. This is a workaround for alias analysis issue #32155 // pointer. This is a workaround for alias analysis issue #32155
pub(super) struct SetLenOnDrop<'a> { pub(super) struct SetLenOnDrop<'a> {
len: &'a mut usize, len: &'a mut usize,
local_len: usize, local_len: usize,
} }
impl<'a> SetLenOnDrop<'a> { impl<'a> SetLenOnDrop<'a> {
#[inline(always)] #[inline(always)]
pub(super) fn new(len: &'a mut usize) -> Self { pub(super) fn new(len: &'a mut usize) -> Self {
SetLenOnDrop { SetLenOnDrop {
local_len: *len, local_len: *len,
len, len,
} }
} }
#[inline(always)] #[inline(always)]
pub(super) fn increment_len(&mut self, increment: usize) { pub(super) fn increment_len(&mut self, increment: usize) {
self.local_len += increment; self.local_len += increment;
} }
} }
impl Drop for SetLenOnDrop<'_> { impl Drop for SetLenOnDrop<'_> {
#[inline(always)] #[inline(always)]
fn drop(&mut self) { fn drop(&mut self) {
*self.len = self.local_len; *self.len = self.local_len;
} }
} }

View File

@@ -1,135 +1,135 @@
use core::ptr::{self}; use core::ptr::{self};
use core::slice::{self}; use core::slice::{self};
use crate::stable::alloc::{Allocator, Global}; use crate::stable::alloc::{Allocator, Global};
use super::{Drain, Vec}; use super::{Drain, Vec};
/// A splicing iterator for `Vec`. /// A splicing iterator for `Vec`.
/// ///
/// This struct is created by [`Vec::splice()`]. /// This struct is created by [`Vec::splice()`].
/// See its documentation for more. /// See its documentation for more.
/// ///
/// # Example /// # Example
/// ///
/// ``` /// ```
/// let mut v = vec![0, 1, 2]; /// let mut v = vec![0, 1, 2];
/// let new = [7, 8]; /// let new = [7, 8];
/// let iter: std::vec::Splice<_> = v.splice(1.., new); /// let iter: std::vec::Splice<_> = v.splice(1.., new);
/// ``` /// ```
#[derive(Debug)] #[derive(Debug)]
pub struct Splice<'a, I: Iterator + 'a, A: Allocator + 'a = Global> { pub struct Splice<'a, I: Iterator + 'a, A: Allocator + 'a = Global> {
pub(super) drain: Drain<'a, I::Item, A>, pub(super) drain: Drain<'a, I::Item, A>,
pub(super) replace_with: I, pub(super) replace_with: I,
} }
impl<I: Iterator, A: Allocator> Iterator for Splice<'_, I, A> { impl<I: Iterator, A: Allocator> Iterator for Splice<'_, I, A> {
type Item = I::Item; type Item = I::Item;
#[inline(always)] #[inline(always)]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.drain.next() self.drain.next()
} }
#[inline(always)] #[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
self.drain.size_hint() self.drain.size_hint()
} }
} }
impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> { impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> {
#[inline(always)] #[inline(always)]
fn next_back(&mut self) -> Option<Self::Item> { fn next_back(&mut self) -> Option<Self::Item> {
self.drain.next_back() self.drain.next_back()
} }
} }
impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {} impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> { impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
self.drain.by_ref().for_each(drop); self.drain.by_ref().for_each(drop);
unsafe { unsafe {
if self.drain.tail_len == 0 { if self.drain.tail_len == 0 {
self.drain.vec.as_mut().extend(self.replace_with.by_ref()); self.drain.vec.as_mut().extend(self.replace_with.by_ref());
return; return;
} }
// First fill the range left by drain(). // First fill the range left by drain().
if !self.drain.fill(&mut self.replace_with) { if !self.drain.fill(&mut self.replace_with) {
return; return;
} }
// There may be more elements. Use the lower bound as an estimate. // There may be more elements. Use the lower bound as an estimate.
// FIXME: Is the upper bound a better guess? Or something else? // FIXME: Is the upper bound a better guess? Or something else?
let (lower_bound, _upper_bound) = self.replace_with.size_hint(); let (lower_bound, _upper_bound) = self.replace_with.size_hint();
if lower_bound > 0 { if lower_bound > 0 {
self.drain.move_tail(lower_bound); self.drain.move_tail(lower_bound);
if !self.drain.fill(&mut self.replace_with) { if !self.drain.fill(&mut self.replace_with) {
return; return;
} }
} }
// Collect any remaining elements. // Collect any remaining elements.
// This is a zero-length vector which does not allocate if `lower_bound` was exact. // This is a zero-length vector which does not allocate if `lower_bound` was exact.
let mut collected = self let mut collected = self
.replace_with .replace_with
.by_ref() .by_ref()
.collect::<Vec<I::Item>>() .collect::<Vec<I::Item>>()
.into_iter(); .into_iter();
// Now we have an exact count. // Now we have an exact count.
if collected.len() > 0 { if collected.len() > 0 {
self.drain.move_tail(collected.len()); self.drain.move_tail(collected.len());
let filled = self.drain.fill(&mut collected); let filled = self.drain.fill(&mut collected);
debug_assert!(filled); debug_assert!(filled);
debug_assert_eq!(collected.len(), 0); debug_assert_eq!(collected.len(), 0);
} }
} }
// Let `Drain::drop` move the tail back if necessary and restore `vec.len`. // Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
} }
} }
/// Private helper methods for `Splice::drop` /// Private helper methods for `Splice::drop`
impl<T, A: Allocator> Drain<'_, T, A> { impl<T, A: Allocator> Drain<'_, T, A> {
/// The range from `self.vec.len` to `self.tail_start` contains elements /// The range from `self.vec.len` to `self.tail_start` contains elements
/// that have been moved out. /// that have been moved out.
/// Fill that range as much as possible with new elements from the `replace_with` iterator. /// Fill that range as much as possible with new elements from the `replace_with` iterator.
/// Returns `true` if we filled the entire range. (`replace_with.next()` didnt return `None`.) /// Returns `true` if we filled the entire range. (`replace_with.next()` didnt return `None`.)
#[inline(always)] #[inline(always)]
unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool { unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
let vec = unsafe { self.vec.as_mut() }; let vec = unsafe { self.vec.as_mut() };
let range_start = vec.len; let range_start = vec.len;
let range_end = self.tail_start; let range_end = self.tail_start;
let range_slice = unsafe { let range_slice = unsafe {
slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start) slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
}; };
for place in range_slice { for place in range_slice {
if let Some(new_item) = replace_with.next() { if let Some(new_item) = replace_with.next() {
unsafe { ptr::write(place, new_item) }; unsafe { ptr::write(place, new_item) };
vec.len += 1; vec.len += 1;
} else { } else {
return false; return false;
} }
} }
true true
} }
/// Makes room for inserting more elements before the tail. /// Makes room for inserting more elements before the tail.
#[inline(always)] #[inline(always)]
unsafe fn move_tail(&mut self, additional: usize) { unsafe fn move_tail(&mut self, additional: usize) {
let vec = unsafe { self.vec.as_mut() }; let vec = unsafe { self.vec.as_mut() };
let len = self.tail_start + self.tail_len; let len = self.tail_start + self.tail_len;
vec.buf.reserve(len, additional); vec.buf.reserve(len, additional);
let new_tail_start = self.tail_start + additional; let new_tail_start = self.tail_start + additional;
unsafe { unsafe {
let src = vec.as_ptr().add(self.tail_start); let src = vec.as_ptr().add(self.tail_start);
let dst = vec.as_mut_ptr().add(new_tail_start); let dst = vec.as_mut_ptr().add(new_tail_start);
ptr::copy(src, dst, self.tail_len); ptr::copy(src, dst, self.tail_len);
} }
self.tail_start = new_tail_start; self.tail_start = new_tail_start;
} }
} }