зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1661583 - Update mp4parse-rust to fe90285. r=kinetik
- Enable fallible allocation in mp4parse_capi by default - Switch from local implementation of fallible allocation to using fallible_collections crate - Return error if any of the primary item data is missing Differential Revision: https://phabricator.services.mozilla.com/D89091
This commit is contained in:
Родитель
3c2aa8f90e
Коммит
5db1fd1dd5
|
@ -15,7 +15,7 @@ tag = "v0.4.10"
|
|||
[source."https://github.com/mozilla/mp4parse-rust"]
|
||||
git = "https://github.com/mozilla/mp4parse-rust"
|
||||
replace-with = "vendored-sources"
|
||||
rev = "d5a37fd0bd51e06a53274c68213b00136aba83a6"
|
||||
rev = "fe9028570e44f3a725dd78bbb58428909c4618bf"
|
||||
|
||||
[source."https://github.com/mozilla/application-services"]
|
||||
git = "https://github.com/mozilla/application-services"
|
||||
|
|
|
@ -1384,6 +1384,15 @@ version = "0.1.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "fallible_collections"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3301bcde54d3fc19c626ff4bf962630fe1f94cb6cdc3f18a26727a2d1f4a67"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ffi-support"
|
||||
version = "0.4.0"
|
||||
|
@ -3121,10 +3130,11 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "mp4parse"
|
||||
version = "0.11.4"
|
||||
source = "git+https://github.com/mozilla/mp4parse-rust?rev=d5a37fd0bd51e06a53274c68213b00136aba83a6#d5a37fd0bd51e06a53274c68213b00136aba83a6"
|
||||
source = "git+https://github.com/mozilla/mp4parse-rust?rev=fe9028570e44f3a725dd78bbb58428909c4618bf#fe9028570e44f3a725dd78bbb58428909c4618bf"
|
||||
dependencies = [
|
||||
"bitreader",
|
||||
"byteorder",
|
||||
"fallible_collections",
|
||||
"hashbrown",
|
||||
"log",
|
||||
"num-traits",
|
||||
|
@ -3138,9 +3148,10 @@ version = "0.1.0"
|
|||
[[package]]
|
||||
name = "mp4parse_capi"
|
||||
version = "0.11.4"
|
||||
source = "git+https://github.com/mozilla/mp4parse-rust?rev=d5a37fd0bd51e06a53274c68213b00136aba83a6#d5a37fd0bd51e06a53274c68213b00136aba83a6"
|
||||
source = "git+https://github.com/mozilla/mp4parse-rust?rev=fe9028570e44f3a725dd78bbb58428909c4618bf#fe9028570e44f3a725dd78bbb58428909c4618bf"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"fallible_collections",
|
||||
"log",
|
||||
"mp4parse",
|
||||
"num-traits",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"63f9088664a4a87c994e96e43e096a2a9b5746339a0689057ab669364536652b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"6d74a8ddac747e9fd6d8c2000c6d0ae05bc28bb9e47e629e86d4b8d05115f546","src/arc.rs":"60742619b7404d8c46237e9a3f98c49f75f88e4c24513ebca1d0ddad0274b6d6","src/boxed.rs":"8d9b1bc84e3bfb59f59f0c7df93ccd225ffc044166db6e2aa5976cc968203712","src/btree.rs":"b83820fc2a00e2e34127b3037abde8b945f0ca2785f3def725787e6813c3d3e0","src/btree/map.rs":"4d8710cf6f00bd889045a6144de692d9f752d51089db493e859d55e5ba12430a","src/btree/node.rs":"f6b4557d30ca0e30c7c7b6752c7a2c67432aab5c18c08392a28040326620a109","src/btree/search.rs":"ae78f73f3e56ea277b0a02cc39454447b75e12a6c817ecfee00065b3ddbfff67","src/btree/set.rs":"29cc3bff736007b21e14017d880edbcc7c76c30e0c256e811cae1fff0dad13fa","src/format.rs":"cee32d75cf260b19c8db74b50852bc50b8c47189d22b7424b647d084c4a76857","src/hashmap.rs":"cf02762085d9968fc235ef2c0626358661cb21aca2c8c19961b3969225c96dce","src/lib.rs":"deaf67958a1b8ae537a04a4eca3d424d20a6d9cf08cc9dfa2f6969a586976247","src/rc.rs":"102ad49f2201b9f69b50cf5a35af1e0039094936354b12572702551970c2f53c","src/try_clone.rs":"32c790435c71dec116756c284d2b953d382292b7727675740229a6b53d8c8b41","src/vec.rs":"95900e8d2f9a8902d5505e13c0d8ec17ac3ddc2ed8ae8f25b56962cdb4d8398c"},"package":"ba3301bcde54d3fc19c626ff4bf962630fe1f94cb6cdc3f18a26727a2d1f4a67"}
|
|
@ -0,0 +1,28 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "fallible_collections"
|
||||
version = "0.1.3"
|
||||
authors = ["vcombey <vcombey@student.42.fr>"]
|
||||
description = "a crate which adds fallible allocation api to std collections"
|
||||
readme = "README.md"
|
||||
keywords = ["fallible", "collections"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/vcombey/fallible_collections.git"
|
||||
[dependencies.hashbrown]
|
||||
version = "0.7.1"
|
||||
|
||||
[features]
|
||||
std_io = []
|
||||
unstable = []
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"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
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
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
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
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 stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2010 The Rust Project Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,73 @@
|
|||
Fallible Collections.rs
|
||||
==============
|
||||
|
||||
Implement api on rust collection wich returns a result when an allocation error occurs.
|
||||
This is inspired a lot by [RFC 2116](https://github.com/rust-lang/rfcs/blob/master/text/2116-alloc-me-maybe.md).
|
||||
|
||||
The api currently propose a fallible interface for Vec, Box, Arc, Btree and Rc,
|
||||
a TryClone trait wich is implemented for primitive rust traits and a fallible format macro.
|
||||
|
||||
You can use this with try_clone_derive crate wich derive TryClone for your own types.
|
||||
|
||||
# Getting Started
|
||||
|
||||
[fallible collections is available on crates.io](https://crates.io/crates/fallible_collections).
|
||||
It is recommended to look there for the newest released version, as well as links to the newest builds of the docs.
|
||||
|
||||
At the point of the last update of this README, the latest published version could be used like this:
|
||||
|
||||
Add the following dependency to your Cargo manifest...
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
fallible_collections = "0.1.3"
|
||||
```
|
||||
|
||||
...and see the [docs](https://docs.rs/fallible_collections) for how to use it.
|
||||
|
||||
# Example
|
||||
|
||||
Exemple of using the FallibleBox interface.
|
||||
```rust
|
||||
use fallible_collections::FallibleBox;
|
||||
|
||||
fn main() {
|
||||
// this crate an Ordinary box but return an error on allocation failure
|
||||
let mut a = Box::try_new(5).unwrap();
|
||||
let mut b = Box::new(5);
|
||||
|
||||
assert_eq!(a, b);
|
||||
*a = 3;
|
||||
assert_eq!(*a, 3);
|
||||
}
|
||||
```
|
||||
|
||||
Exemple of using the FallibleVec interface.
|
||||
```rust
|
||||
use fallible_collections::FallibleVec;
|
||||
|
||||
fn main() {
|
||||
// this crate an Ordinary Vec<Vec<u8>> but return an error on allocation failure
|
||||
let a: Vec<Vec<u8>> = try_vec![try_vec![42; 10].unwrap(); 100].unwrap();
|
||||
let b: Vec<Vec<u8>> = vec![vec![42; 10]; 100];
|
||||
assert_eq!(a, b);
|
||||
assert_eq!(a.try_clone().unwrap(), a);
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* 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)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
//! Implement a Fallible Arc
|
||||
use super::FallibleBox;
|
||||
use super::TryClone;
|
||||
|
||||
use crate::TryReserveError;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::sync::Arc;
|
||||
|
||||
/// trait to implement Fallible Arc
|
||||
pub trait FallibleArc<T> {
|
||||
/// try creating a new Arc, returning a Result<Box<T>,
|
||||
/// TryReserveError> if allocation failed
|
||||
fn try_new(t: T) -> Result<Self, TryReserveError>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<T> FallibleArc<T> for Arc<T> {
|
||||
fn try_new(t: T) -> Result<Self, TryReserveError> {
|
||||
// doesn't work as the inner variable of arc are also stocked in the box
|
||||
let b = Box::try_new(t)?;
|
||||
Ok(Arc::from(b))
|
||||
}
|
||||
}
|
||||
|
||||
/// Just a TryClone boilerplate for Arc
|
||||
impl<T: ?Sized> TryClone for Arc<T> {
|
||||
fn try_clone(&self) -> Result<Self, TryReserveError> {
|
||||
Ok(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
fn fallible_rc() {
|
||||
use std::sync::Arc;
|
||||
|
||||
let mut x = Arc::new(3);
|
||||
*Arc::get_mut(&mut x).unwrap() = 4;
|
||||
assert_eq!(*x, 4);
|
||||
|
||||
let _y = Arc::clone(&x);
|
||||
assert!(Arc::get_mut(&mut x).is_none());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
//! Implement Fallible Box
|
||||
use super::TryClone;
|
||||
use crate::TryReserveError;
|
||||
use alloc::alloc::Layout;
|
||||
use alloc::boxed::Box;
|
||||
use core::borrow::Borrow;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
/// trait to implement Fallible Box
|
||||
pub trait FallibleBox<T> {
|
||||
/// try creating a new box, returning a Result<Box<T>,
|
||||
/// TryReserveError> if allocation failed
|
||||
fn try_new(t: T) -> Result<Self, TryReserveError>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
/// TryBox is a thin wrapper around alloc::boxed::Box to provide support for
|
||||
/// fallible allocation.
|
||||
///
|
||||
/// See the crate documentation for more.
|
||||
pub struct TryBox<T> {
|
||||
inner: Box<T>,
|
||||
}
|
||||
|
||||
impl<T> TryBox<T> {
|
||||
pub fn try_new(t: T) -> Result<Self, TryReserveError> {
|
||||
Ok(Self {
|
||||
inner: Box::try_new(t)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_raw(b: TryBox<T>) -> *mut T {
|
||||
Box::into_raw(b.inner)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// See std::boxed::from_raw
|
||||
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
||||
Self {
|
||||
inner: Box::from_raw(raw),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TryClone> TryClone for TryBox<T> {
|
||||
fn try_clone(&self) -> Result<Self, TryReserveError> {
|
||||
let clone: T = (*self.inner).try_clone()?;
|
||||
Self::try_new(clone)
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc(layout: Layout) -> Result<NonNull<u8>, TryReserveError> {
|
||||
#[cfg(feature = "unstable")] // requires allocator_api
|
||||
{
|
||||
use core::alloc::AllocRef as _;
|
||||
let mut g = alloc::alloc::Global;
|
||||
g.alloc(layout, alloc::alloc::AllocInit::Uninitialized)
|
||||
.map_err(|_e| TryReserveError::AllocError {
|
||||
layout,
|
||||
non_exhaustive: (),
|
||||
})
|
||||
.map(|memory_block| memory_block.ptr)
|
||||
}
|
||||
#[cfg(not(feature = "unstable"))]
|
||||
{
|
||||
match layout.size() {
|
||||
0 => {
|
||||
// Required for alloc safety
|
||||
// See https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html#safety-1
|
||||
Ok(NonNull::dangling())
|
||||
}
|
||||
1..=core::usize::MAX => {
|
||||
let ptr = unsafe { alloc::alloc::alloc(layout) };
|
||||
core::ptr::NonNull::new(ptr).ok_or(TryReserveError::AllocErr { layout })
|
||||
}
|
||||
_ => unreachable!("size must be non-negative"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FallibleBox<T> for Box<T> {
|
||||
fn try_new(t: T) -> Result<Self, TryReserveError> {
|
||||
let layout = Layout::for_value(&t);
|
||||
let ptr = alloc(layout)?.as_ptr() as *mut T;
|
||||
unsafe {
|
||||
core::ptr::write(ptr, t);
|
||||
Ok(Box::from_raw(ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TryClone> TryClone for Box<T> {
|
||||
fn try_clone(&self) -> Result<Self, TryReserveError> {
|
||||
Self::try_new(Borrow::<T>::borrow(self).try_clone()?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn boxed() {
|
||||
let mut v = Box::try_new(5).unwrap();
|
||||
assert_eq!(*v, 5);
|
||||
*v = 3;
|
||||
assert_eq!(*v, 3);
|
||||
}
|
||||
// #[test]
|
||||
// fn big_alloc() {
|
||||
// let layout = Layout::from_size_align(1_000_000_000_000, 8).unwrap();
|
||||
// let ptr = unsafe { alloc::alloc::alloc(layout) };
|
||||
// assert!(ptr.is_null());
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn trybox_zst() {
|
||||
let b = Box::try_new(()).expect("ok");
|
||||
assert_eq!(b, Box::new(()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
//! Implement Fallible Btree, As there is no try_reserve methods on btree, I add no choice but to fork the std implementation and change return types.
|
||||
//! Currently this functionality is only available when building this crate with nightly and the `unstable` feature.
|
||||
pub mod map;
|
||||
pub use map::BTreeMap;
|
||||
|
||||
pub mod set;
|
||||
pub use set::BTreeSet;
|
||||
|
||||
mod node;
|
||||
mod search;
|
||||
use crate::TryReserveError;
|
||||
|
||||
#[doc(hidden)]
|
||||
trait Recover<Q: ?Sized> {
|
||||
type Key;
|
||||
|
||||
fn get(&self, key: &Q) -> Option<&Self::Key>;
|
||||
fn take(&mut self, key: &Q) -> Option<Self::Key>;
|
||||
fn replace(&mut self, key: Self::Key) -> Result<Option<Self::Key>, TryReserveError>;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,66 @@
|
|||
use core::borrow::Borrow;
|
||||
|
||||
use core::cmp::Ordering;
|
||||
|
||||
use super::node::{marker, ForceResult::*, Handle, NodeRef};
|
||||
|
||||
use SearchResult::*;
|
||||
|
||||
pub enum SearchResult<BorrowType, K, V, FoundType, GoDownType> {
|
||||
Found(Handle<NodeRef<BorrowType, K, V, FoundType>, marker::KV>),
|
||||
GoDown(Handle<NodeRef<BorrowType, K, V, GoDownType>, marker::Edge>),
|
||||
}
|
||||
|
||||
pub fn search_tree<BorrowType, K, V, Q: ?Sized>(
|
||||
mut node: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
|
||||
key: &Q,
|
||||
) -> SearchResult<BorrowType, K, V, marker::LeafOrInternal, marker::Leaf>
|
||||
where
|
||||
Q: Ord,
|
||||
K: Borrow<Q>,
|
||||
{
|
||||
loop {
|
||||
match search_node(node, key) {
|
||||
Found(handle) => return Found(handle),
|
||||
GoDown(handle) => match handle.force() {
|
||||
Leaf(leaf) => return GoDown(leaf),
|
||||
Internal(internal) => {
|
||||
node = internal.descend();
|
||||
continue;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn search_node<BorrowType, K, V, Type, Q: ?Sized>(
|
||||
node: NodeRef<BorrowType, K, V, Type>,
|
||||
key: &Q,
|
||||
) -> SearchResult<BorrowType, K, V, Type, Type>
|
||||
where
|
||||
Q: Ord,
|
||||
K: Borrow<Q>,
|
||||
{
|
||||
match search_linear(&node, key) {
|
||||
(idx, true) => Found(Handle::new_kv(node, idx)),
|
||||
(idx, false) => SearchResult::GoDown(Handle::new_edge(node, idx)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn search_linear<BorrowType, K, V, Type, Q: ?Sized>(
|
||||
node: &NodeRef<BorrowType, K, V, Type>,
|
||||
key: &Q,
|
||||
) -> (usize, bool)
|
||||
where
|
||||
Q: Ord,
|
||||
K: Borrow<Q>,
|
||||
{
|
||||
for (i, k) in node.keys().iter().enumerate() {
|
||||
match key.cmp(k.borrow()) {
|
||||
Ordering::Greater => {}
|
||||
Ordering::Equal => return (i, true),
|
||||
Ordering::Less => return (i, false),
|
||||
}
|
||||
}
|
||||
(node.keys().len(), false)
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,47 @@
|
|||
//! A try_format! macro replacing format!
|
||||
use super::FallibleVec;
|
||||
use crate::TryReserveError;
|
||||
use alloc::fmt::{Arguments, Write};
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
/// Take a max capacity a try allocating a string with it.
|
||||
///
|
||||
/// # Warning:
|
||||
///
|
||||
/// the max capacity must be > to the formating of the
|
||||
/// arguments. If writing the argument on the string exceed the
|
||||
/// capacity, no error is return and an allocation can occurs which
|
||||
/// can lead to a panic
|
||||
pub fn try_format(max_capacity: usize, args: Arguments<'_>) -> Result<String, TryReserveError> {
|
||||
let v = Vec::try_with_capacity(max_capacity)?;
|
||||
let mut s = String::from_utf8(v).expect("wtf an empty vec should be valid utf8");
|
||||
s.write_fmt(args)
|
||||
.expect("a formatting trait implementation returned an error");
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
/// Take a max capacity a try allocating a string with it.
|
||||
///
|
||||
/// # Warning:
|
||||
///
|
||||
/// the max capacity must be > to the formating of the
|
||||
/// arguments. If writing the argument on the string exceed the
|
||||
/// capacity, no error is return and an allocation can occurs which
|
||||
/// can lead to a panic
|
||||
macro_rules! tryformat {
|
||||
($max_capacity:tt, $($arg:tt)*) => (
|
||||
$crate::format::try_format($max_capacity, format_args!($($arg)*))
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn format() {
|
||||
assert_eq!(tryformat!(1, "1").unwrap(), format!("1"));
|
||||
assert_eq!(tryformat!(1, "{}", 1).unwrap(), format!("{}", 1));
|
||||
assert_eq!(tryformat!(3, "{}", 123).unwrap(), format!("{}", 123));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
//! Implement Fallible HashMap
|
||||
use super::TryClone;
|
||||
use crate::TryReserveError;
|
||||
use core::default::Default;
|
||||
use core::hash::Hash;
|
||||
|
||||
type HashMap<K, V> = hashbrown::hash_map::HashMap<K, V>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TryHashMap<K, V> {
|
||||
inner: HashMap<K, V>,
|
||||
}
|
||||
|
||||
impl<K, V> TryHashMap<K, V>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
{
|
||||
pub fn with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
|
||||
let mut map = Self {
|
||||
inner: HashMap::new(),
|
||||
};
|
||||
map.reserve(capacity)?;
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
|
||||
where
|
||||
K: core::borrow::Borrow<Q>,
|
||||
Q: Hash + Eq,
|
||||
{
|
||||
self.inner.get(k)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, k: K, v: V) -> Result<Option<V>, TryReserveError> {
|
||||
self.reserve(if self.inner.capacity() == 0 { 4 } else { 1 })?;
|
||||
Ok(self.inner.insert(k, v))
|
||||
}
|
||||
|
||||
fn reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
|
||||
self.inner.try_reserve(additional)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> TryClone for TryHashMap<K, V>
|
||||
where
|
||||
K: Eq + Hash + TryClone,
|
||||
V: TryClone,
|
||||
{
|
||||
fn try_clone(&self) -> Result<Self, TryReserveError> {
|
||||
let mut clone = Self::with_capacity(self.inner.len())?;
|
||||
|
||||
for (key, value) in self.inner.iter() {
|
||||
clone.insert(key.try_clone()?, value.try_clone()?)?;
|
||||
}
|
||||
|
||||
Ok(clone)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tryhashmap_oom() {
|
||||
match TryHashMap::<char, char>::default().reserve(core::usize::MAX) {
|
||||
Ok(_) => panic!("it should be OOM"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
//! impl Fallible collections on allocation errors, quite as describe
|
||||
//! in [RFC 2116](https://github.com/rust-lang/rfcs/blob/master/text/2116-alloc-me-maybe.md)
|
||||
//! This was used in the turbofish OS hobby project to mitigate the
|
||||
//! the lack of faillible allocation in rust.
|
||||
//!
|
||||
//! The `Try*` types in this module are thin wrappers around the stdlib types to add
|
||||
//! support for fallible allocation. The API differences from the stdlib types ensure
|
||||
//! that all operations which allocate return a `Result`. For the most part, this simply
|
||||
//! means adding a `Result` return value to functions which return nothing or a
|
||||
//! non-`Result` value. However, these types implement some traits whose API cannot
|
||||
//! communicate failure, but which do require allocation, so it is important that these
|
||||
//! wrapper types do not implement these traits.
|
||||
//!
|
||||
//! Specifically, these types must not implement any of the following traits:
|
||||
//! - Clone
|
||||
//! - Extend
|
||||
//! - From
|
||||
//! - FromIterator
|
||||
//!
|
||||
//! This list may not be exhaustive. Exercise caution when implementing
|
||||
//! any new traits to ensure they won't potentially allocate in a way that
|
||||
//! can't return a Result to indicate allocation failure.
|
||||
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
#![cfg_attr(feature = "unstable", feature(try_reserve))]
|
||||
#![cfg_attr(feature = "unstable", feature(specialization))]
|
||||
#![cfg_attr(feature = "unstable", feature(allocator_api))]
|
||||
#![cfg_attr(feature = "unstable", feature(dropck_eyepatch))]
|
||||
#![cfg_attr(feature = "unstable", feature(ptr_internals))]
|
||||
#![cfg_attr(feature = "unstable", feature(core_intrinsics))]
|
||||
#![cfg_attr(feature = "unstable", feature(maybe_uninit_ref))]
|
||||
#![cfg_attr(feature = "unstable", feature(maybe_uninit_slice))]
|
||||
#![cfg_attr(feature = "unstable", feature(maybe_uninit_extra))]
|
||||
#![cfg_attr(feature = "unstable", feature(internal_uninit_const))]
|
||||
extern crate alloc;
|
||||
#[cfg(feature = "std_io")]
|
||||
extern crate std;
|
||||
|
||||
pub mod boxed;
|
||||
pub use boxed::*;
|
||||
#[macro_use]
|
||||
pub mod vec;
|
||||
pub use vec::*;
|
||||
pub mod rc;
|
||||
pub use rc::*;
|
||||
pub mod arc;
|
||||
pub use arc::*;
|
||||
#[cfg(feature = "unstable")]
|
||||
pub mod btree;
|
||||
#[cfg(not(feature = "unstable"))]
|
||||
pub mod hashmap;
|
||||
#[cfg(not(feature = "unstable"))]
|
||||
pub use hashmap::*;
|
||||
#[macro_use]
|
||||
pub mod format;
|
||||
pub mod try_clone;
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
pub use alloc::collections::TryReserveError;
|
||||
#[cfg(not(feature = "unstable"))]
|
||||
pub use hashbrown::CollectionAllocErr as TryReserveError;
|
||||
|
||||
#[cfg(feature = "std_io")]
|
||||
pub use vec::std_io::*;
|
||||
|
||||
/// trait for trying to clone an elem, return an error instead of
|
||||
/// panic if allocation failed
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use fallible_collections::TryClone;
|
||||
/// let mut vec = vec![42, 100];
|
||||
/// assert_eq!(vec.try_clone().unwrap(), vec)
|
||||
/// ```
|
||||
pub trait TryClone {
|
||||
/// try clone method, (Self must be sized because of Result
|
||||
/// constraint)
|
||||
fn try_clone(&self) -> Result<Self, TryReserveError>
|
||||
where
|
||||
Self: core::marker::Sized;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
//! Implement a Fallible Rc
|
||||
use super::FallibleBox;
|
||||
use crate::TryReserveError;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
/// trait to implement Fallible Rc
|
||||
pub trait FallibleRc<T> {
|
||||
/// try creating a new Rc, returning a Result<Box<T>,
|
||||
/// TryReserveError> if allocation failed
|
||||
fn try_new(t: T) -> Result<Self, TryReserveError>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<T> FallibleRc<T> for Rc<T> {
|
||||
fn try_new(t: T) -> Result<Self, TryReserveError> {
|
||||
let b = Box::try_new(t)?;
|
||||
Ok(Rc::from(b))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
fn fallible_rc() {
|
||||
use std::rc::Rc;
|
||||
|
||||
let mut x = Rc::new(3);
|
||||
*Rc::get_mut(&mut x).unwrap() = 4;
|
||||
assert_eq!(*x, 4);
|
||||
|
||||
let _y = Rc::clone(&x);
|
||||
assert!(Rc::get_mut(&mut x).is_none());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
//! this module implements try clone for primitive rust types
|
||||
|
||||
use super::TryClone;
|
||||
use crate::TryReserveError;
|
||||
|
||||
macro_rules! impl_try_clone {
|
||||
($($e: ty),*) => {
|
||||
$(impl TryClone for $e {
|
||||
#[inline(always)]
|
||||
fn try_clone(&self) -> Result<Self, TryReserveError>
|
||||
where
|
||||
Self: core::marker::Sized,
|
||||
{
|
||||
Ok(*self)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_try_clone!(u8, u16, u32, u64, i8, i16, i32, i64, usize, isize, bool);
|
||||
|
||||
impl<T: TryClone> TryClone for Option<T> {
|
||||
fn try_clone(&self) -> Result<Self, TryReserveError> {
|
||||
Ok(match self {
|
||||
Some(t) => Some(t.try_clone()?),
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
// impl<T: Copy> TryClone for T {
|
||||
// fn try_clone(&self) -> Result<Self, TryReserveError>
|
||||
// where
|
||||
// Self: core::marker::Sized,
|
||||
// {
|
||||
// Ok(*self)
|
||||
// }
|
||||
// }
|
|
@ -0,0 +1,864 @@
|
|||
//! Implement Fallible Vec
|
||||
use super::TryClone;
|
||||
use crate::TryReserveError;
|
||||
#[allow(unused_imports)]
|
||||
use alloc::alloc::{alloc, realloc, Layout};
|
||||
use alloc::vec::Vec;
|
||||
use core::convert::TryInto as _;
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
#[macro_export]
|
||||
/// macro trying to create a vec, return a
|
||||
/// Result<Vec<T>,TryReserveError>
|
||||
macro_rules! try_vec {
|
||||
($elem:expr; $n:expr) => (
|
||||
$crate::vec::try_from_elem($elem, $n)
|
||||
);
|
||||
($($x:expr),*) => (
|
||||
match <alloc::boxed::Box<_> as $crate::boxed::FallibleBox<_>>::try_new([$($x),*]) {
|
||||
Err(e) => Err(e),
|
||||
Ok(b) => Ok(<[_]>::into_vec(b)),
|
||||
}
|
||||
);
|
||||
($($x:expr,)*) => ($crate::try_vec![$($x),*])
|
||||
}
|
||||
|
||||
/// trait implementing all fallible methods on vec
|
||||
pub trait FallibleVec<T> {
|
||||
/// see reserve
|
||||
fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>;
|
||||
/// see push
|
||||
fn try_push(&mut self, elem: T) -> Result<(), TryReserveError>;
|
||||
/// try push and give back ownership in case of error
|
||||
fn try_push_give_back(&mut self, elem: T) -> Result<(), (T, TryReserveError)>;
|
||||
/// see with capacity, (Self must be sized by the constraint of Result)
|
||||
fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError>
|
||||
where
|
||||
Self: core::marker::Sized;
|
||||
/// see insert
|
||||
fn try_insert(&mut self, index: usize, element: T) -> Result<(), (T, TryReserveError)>;
|
||||
/// see append
|
||||
fn try_append(&mut self, other: &mut Self) -> Result<(), TryReserveError>;
|
||||
/// see resize, only works when the `value` implements Copy, otherwise, look at try_resize_no_copy
|
||||
fn try_resize(&mut self, new_len: usize, value: T) -> Result<(), TryReserveError>
|
||||
where
|
||||
T: Copy + Clone;
|
||||
fn try_resize_with<F>(&mut self, new_len: usize, f: F) -> Result<(), TryReserveError>
|
||||
where
|
||||
F: FnMut() -> T;
|
||||
/// resize the vec by trying to clone the value repeatingly
|
||||
fn try_resize_no_copy(&mut self, new_len: usize, value: T) -> Result<(), TryReserveError>
|
||||
where
|
||||
T: TryClone;
|
||||
/// see resize, only works when the `value` implements Copy, otherwise, look at try_extend_from_slice_no_copy
|
||||
fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError>
|
||||
where
|
||||
T: Copy + Clone;
|
||||
/// extend the vec by trying to clone the value in `other`
|
||||
fn try_extend_from_slice_no_copy(&mut self, other: &[T]) -> Result<(), TryReserveError>
|
||||
where
|
||||
T: TryClone;
|
||||
}
|
||||
|
||||
/// TryVec is a thin wrapper around alloc::vec::Vec to provide support for
|
||||
/// fallible allocation.
|
||||
///
|
||||
/// See the crate documentation for more.
|
||||
#[derive(Default, PartialEq)]
|
||||
pub struct TryVec<T> {
|
||||
inner: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: core::fmt::Debug> core::fmt::Debug for TryVec<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{:?}", self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TryVec<T> {
|
||||
pub fn new() -> Self {
|
||||
Self { inner: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
|
||||
Ok(Self {
|
||||
inner: FallibleVec::try_with_capacity(capacity)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn append(&mut self, other: &mut Self) -> Result<(), TryReserveError> {
|
||||
FallibleVec::try_append(&mut self.inner, &mut other.inner)
|
||||
}
|
||||
|
||||
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.inner.clear()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn into_inner(self) -> Vec<T> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> IterMut<T> {
|
||||
IterMut {
|
||||
inner: self.inner.iter_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter {
|
||||
inner: self.inner.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
self.inner.pop()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: T) -> Result<(), TryReserveError> {
|
||||
FallibleVec::try_push(&mut self.inner, value)
|
||||
}
|
||||
|
||||
pub fn reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
|
||||
FallibleVec::try_reserve(&mut self.inner, additional)
|
||||
}
|
||||
|
||||
pub fn resize_with<F>(&mut self, new_len: usize, f: F) -> Result<(), TryReserveError>
|
||||
where
|
||||
F: FnMut() -> T,
|
||||
{
|
||||
FallibleVec::try_resize_with(&mut self.inner, new_len, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TryClone> TryClone for TryVec<T> {
|
||||
fn try_clone(&self) -> Result<Self, TryReserveError> {
|
||||
self.as_slice().try_into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TryClone> TryVec<TryVec<T>> {
|
||||
pub fn concat(&self) -> Result<TryVec<T>, TryReserveError> {
|
||||
let size = self.iter().map(|v| v.inner.len()).sum();
|
||||
let mut result = TryVec::with_capacity(size)?;
|
||||
for v in self.iter() {
|
||||
result.inner.try_extend_from_slice_no_copy(&v.inner)?;
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TryClone> TryVec<T> {
|
||||
pub fn extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> {
|
||||
self.inner.try_extend_from_slice_no_copy(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for TryVec<T> {
|
||||
type Item = T;
|
||||
type IntoIter = alloc::vec::IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.inner.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a TryVec<T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = alloc::slice::Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.inner.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std_io")]
|
||||
pub mod std_io {
|
||||
use super::*;
|
||||
use std::io::{self, Read, Take, Write};
|
||||
|
||||
pub trait TryRead {
|
||||
fn try_read_to_end(&mut self, buf: &mut TryVec<u8>) -> io::Result<usize>;
|
||||
|
||||
fn read_into_try_vec(&mut self) -> io::Result<TryVec<u8>> {
|
||||
let mut buf = TryVec::new();
|
||||
self.try_read_to_end(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Read> TryRead for Take<T> {
|
||||
/// This function reserves the upper limit of what `src` can generate before
|
||||
/// reading all bytes until EOF in this source, placing them into `buf`. If the
|
||||
/// allocation is unsuccessful, or reading from the source generates an error
|
||||
/// before reaching EOF, this will return an error. Otherwise, it will return
|
||||
/// the number of bytes read.
|
||||
///
|
||||
/// Since `Take::limit()` may return a value greater than the number of bytes
|
||||
/// which can be read from the source, it's possible this function may fail
|
||||
/// in the allocation phase even though allocating the number of bytes available
|
||||
/// to read would have succeeded. In general, it is assumed that the callers
|
||||
/// have accurate knowledge of the number of bytes of interest and have created
|
||||
/// `src` accordingly.
|
||||
fn try_read_to_end(&mut self, buf: &mut TryVec<u8>) -> io::Result<usize> {
|
||||
try_read_up_to(self, self.limit(), buf)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read up to `limit` bytes from `src`, placing them into `buf` and returning the
|
||||
/// number of bytes read. Space for `limit` additional bytes is reserved in `buf`, so
|
||||
/// this function will return an error if the allocation fails.
|
||||
pub fn try_read_up_to<R: Read>(
|
||||
src: &mut R,
|
||||
limit: u64,
|
||||
buf: &mut TryVec<u8>,
|
||||
) -> io::Result<usize> {
|
||||
let additional = limit
|
||||
.try_into()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||
buf.reserve(additional)
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::Other, "reserve allocation failed"))?;
|
||||
let bytes_read = src.take(limit).read_to_end(&mut buf.inner)?;
|
||||
Ok(bytes_read)
|
||||
}
|
||||
|
||||
impl Write for TryVec<u8> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.extend_from_slice(buf)
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::Other, "extend_from_slice failed"))?;
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn try_read_to_end() {
|
||||
let mut src = b"1234567890".take(5);
|
||||
let mut buf = TryVec::new();
|
||||
src.try_read_to_end(&mut buf).unwrap();
|
||||
assert_eq!(buf.len(), 5);
|
||||
assert_eq!(buf, b"12345".as_ref());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_into_try_vec() {
|
||||
let mut src = b"1234567890".take(5);
|
||||
let buf = src.read_into_try_vec().unwrap();
|
||||
assert_eq!(buf.len(), 5);
|
||||
assert_eq!(buf, b"12345".as_ref());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_into_try_vec_oom() {
|
||||
let mut src = b"1234567890".take(core::usize::MAX.try_into().expect("usize < u64"));
|
||||
assert!(src.read_into_try_vec().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_read_up_to() {
|
||||
let src = b"1234567890";
|
||||
let mut buf = TryVec::new();
|
||||
super::try_read_up_to(&mut src.as_ref(), 5, &mut buf).unwrap();
|
||||
assert_eq!(buf.len(), 5);
|
||||
assert_eq!(buf, b"12345".as_ref());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_read_up_to_oom() {
|
||||
let src = b"1234567890";
|
||||
let mut buf = TryVec::new();
|
||||
let limit = core::usize::MAX.try_into().expect("usize < u64");
|
||||
let res = super::try_read_up_to(&mut src.as_ref(), limit, &mut buf);
|
||||
assert!(res.is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq<Vec<T>> for TryVec<T> {
|
||||
fn eq(&self, other: &Vec<T>) -> bool {
|
||||
self.inner.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PartialEq> PartialEq<&'a [T]> for TryVec<T> {
|
||||
fn eq(&self, other: &&[T]) -> bool {
|
||||
self.inner.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for TryVec<u8> {
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
self.as_slice() == other.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::convert::AsRef<[u8]> for TryVec<u8> {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.inner.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> core::convert::From<Vec<T>> for TryVec<T> {
|
||||
fn from(value: Vec<T>) -> Self {
|
||||
Self { inner: value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TryClone> core::convert::TryFrom<&[T]> for TryVec<T> {
|
||||
type Error = TryReserveError;
|
||||
|
||||
fn try_from(value: &[T]) -> Result<Self, Self::Error> {
|
||||
let mut v = Self::new();
|
||||
v.inner.try_extend_from_slice_no_copy(value)?;
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::convert::TryFrom<&str> for TryVec<u8> {
|
||||
type Error = TryReserveError;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
let mut v = Self::new();
|
||||
v.extend_from_slice(value.as_bytes())?;
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> core::ops::Deref for TryVec<T> {
|
||||
type Target = [T];
|
||||
|
||||
fn deref(&self) -> &[T] {
|
||||
self.inner.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> core::ops::DerefMut for TryVec<T> {
|
||||
fn deref_mut(&mut self) -> &mut [T] {
|
||||
self.inner.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<'a, T> {
|
||||
inner: alloc::slice::Iter<'a, T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for Iter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.inner.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IterMut<'a, T> {
|
||||
inner: alloc::slice::IterMut<'a, T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for IterMut<'a, T> {
|
||||
type Item = &'a mut T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.inner.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unstable"))]
|
||||
fn vec_try_reserve<T>(v: &mut Vec<T>, additional: usize) -> Result<(), TryReserveError> {
|
||||
let available = v.capacity().checked_sub(v.len()).expect("capacity >= len");
|
||||
if additional > available {
|
||||
let increase = additional
|
||||
.checked_sub(available)
|
||||
.expect("additional > available");
|
||||
let new_cap = v
|
||||
.capacity()
|
||||
.checked_add(increase)
|
||||
.ok_or(TryReserveError::CapacityOverflow)?;
|
||||
vec_try_extend(v, new_cap)?;
|
||||
debug_assert!(v.capacity() == new_cap);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unstable"))]
|
||||
fn vec_try_extend<T>(v: &mut Vec<T>, new_cap: usize) -> Result<(), TryReserveError> {
|
||||
let old_len = v.len();
|
||||
let old_cap: usize = v.capacity();
|
||||
|
||||
if old_cap >= new_cap {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let elem_size = core::mem::size_of::<T>();
|
||||
let new_alloc_size = new_cap
|
||||
.checked_mul(elem_size)
|
||||
.ok_or(TryReserveError::CapacityOverflow)?;
|
||||
|
||||
// required for alloc safety
|
||||
// See https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html#safety-1
|
||||
// Should be unreachable given prior `old_cap >= new_cap` check.
|
||||
assert!(new_alloc_size > 0);
|
||||
|
||||
let align = core::mem::align_of::<T>();
|
||||
|
||||
let (new_ptr, layout) = {
|
||||
if old_cap == 0 {
|
||||
let layout = Layout::from_size_align(new_alloc_size, align).expect("Invalid layout");
|
||||
let new_ptr = unsafe { alloc(layout) };
|
||||
(new_ptr, layout)
|
||||
} else {
|
||||
let old_alloc_size = old_cap
|
||||
.checked_mul(elem_size)
|
||||
.ok_or(TryReserveError::CapacityOverflow)?;
|
||||
let layout = Layout::from_size_align(old_alloc_size, align).expect("Invalid layout");
|
||||
let new_ptr = unsafe { realloc(v.as_mut_ptr() as *mut u8, layout, new_alloc_size) };
|
||||
(new_ptr, layout)
|
||||
}
|
||||
};
|
||||
|
||||
if new_ptr.is_null() {
|
||||
return Err(TryReserveError::AllocErr { layout });
|
||||
}
|
||||
|
||||
let new_vec = unsafe { Vec::from_raw_parts(new_ptr.cast(), old_len, new_cap) };
|
||||
|
||||
core::mem::forget(core::mem::replace(v, new_vec));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<T> FallibleVec<T> for Vec<T> {
|
||||
fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
|
||||
#[cfg(feature = "unstable")]
|
||||
{
|
||||
self.try_reserve(additional)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unstable"))]
|
||||
{
|
||||
vec_try_reserve(self, additional)
|
||||
}
|
||||
}
|
||||
fn try_push(&mut self, elem: T) -> Result<(), TryReserveError> {
|
||||
FallibleVec::try_reserve(self, 1)?;
|
||||
Ok(self.push(elem))
|
||||
}
|
||||
fn try_push_give_back(&mut self, elem: T) -> Result<(), (T, TryReserveError)> {
|
||||
if let Err(e) = FallibleVec::try_reserve(self, 1) {
|
||||
return Err((elem, e));
|
||||
}
|
||||
Ok(self.push(elem))
|
||||
}
|
||||
fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError>
|
||||
where
|
||||
Self: core::marker::Sized,
|
||||
{
|
||||
let mut n = Self::new();
|
||||
FallibleVec::try_reserve(&mut n, capacity)?;
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
fn try_insert(&mut self, index: usize, element: T) -> Result<(), (T, TryReserveError)> {
|
||||
if let Err(e) = FallibleVec::try_reserve(self, 1) {
|
||||
return Err((element, e));
|
||||
}
|
||||
Ok(self.insert(index, element))
|
||||
}
|
||||
fn try_append(&mut self, other: &mut Self) -> Result<(), TryReserveError> {
|
||||
FallibleVec::try_reserve(self, other.len())?;
|
||||
Ok(self.append(other))
|
||||
}
|
||||
fn try_resize(&mut self, new_len: usize, value: T) -> Result<(), TryReserveError>
|
||||
where
|
||||
T: Copy + Clone,
|
||||
{
|
||||
let len = self.len();
|
||||
if new_len > len {
|
||||
FallibleVec::try_reserve(self, new_len - len)?;
|
||||
}
|
||||
Ok(self.resize(new_len, value))
|
||||
}
|
||||
fn try_resize_with<F>(&mut self, new_len: usize, f: F) -> Result<(), TryReserveError>
|
||||
where
|
||||
F: FnMut() -> T,
|
||||
{
|
||||
let len = self.len();
|
||||
if new_len > len {
|
||||
FallibleVec::try_reserve(self, new_len - len)?;
|
||||
}
|
||||
Ok(self.resize_with(new_len, f))
|
||||
}
|
||||
fn try_resize_no_copy(&mut self, new_len: usize, value: T) -> Result<(), TryReserveError>
|
||||
where
|
||||
T: TryClone,
|
||||
{
|
||||
let len = self.len();
|
||||
|
||||
if new_len > len {
|
||||
self.try_extend_with(new_len - len, TryExtendElement(value))
|
||||
} else {
|
||||
Ok(self.truncate(new_len))
|
||||
}
|
||||
}
|
||||
fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
FallibleVec::try_reserve(self, other.len())?;
|
||||
Ok(self.extend_from_slice(other))
|
||||
}
|
||||
fn try_extend_from_slice_no_copy(&mut self, other: &[T]) -> Result<(), TryReserveError>
|
||||
where
|
||||
T: TryClone,
|
||||
{
|
||||
let mut len = self.len();
|
||||
FallibleVec::try_reserve(self, other.len())?;
|
||||
let mut iterator = other.iter();
|
||||
while let Some(element) = iterator.next() {
|
||||
unsafe {
|
||||
core::ptr::write(self.get_unchecked_mut(len), element.try_clone()?);
|
||||
// NB can't overflow since we would have had to alloc the address space
|
||||
len += 1;
|
||||
self.set_len(len);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
trait ExtendWith<T> {
|
||||
fn next(&mut self) -> Result<T, TryReserveError>;
|
||||
fn last(self) -> T;
|
||||
}
|
||||
|
||||
struct TryExtendElement<T: TryClone>(T);
|
||||
impl<T: TryClone> ExtendWith<T> for TryExtendElement<T> {
|
||||
fn next(&mut self) -> Result<T, TryReserveError> {
|
||||
self.0.try_clone()
|
||||
}
|
||||
fn last(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
trait TryExtend<T> {
|
||||
fn try_extend_with<E: ExtendWith<T>>(
|
||||
&mut self,
|
||||
n: usize,
|
||||
value: E,
|
||||
) -> Result<(), TryReserveError>;
|
||||
}
|
||||
|
||||
impl<T> TryExtend<T> for Vec<T> {
|
||||
/// Extend the vector by `n` values, using the given generator.
|
||||
fn try_extend_with<E: ExtendWith<T>>(
|
||||
&mut self,
|
||||
n: usize,
|
||||
mut value: E,
|
||||
) -> Result<(), TryReserveError> {
|
||||
FallibleVec::try_reserve(self, n)?;
|
||||
|
||||
unsafe {
|
||||
let mut ptr = self.as_mut_ptr().add(self.len());
|
||||
|
||||
let mut local_len = self.len();
|
||||
// Write all elements except the last one
|
||||
for _ in 1..n {
|
||||
core::ptr::write(ptr, value.next()?);
|
||||
ptr = ptr.offset(1);
|
||||
// Increment the length in every step in case next() panics
|
||||
local_len += 1;
|
||||
self.set_len(local_len);
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
// We can write the last element directly without cloning needlessly
|
||||
core::ptr::write(ptr, value.last());
|
||||
local_len += 1;
|
||||
self.set_len(local_len);
|
||||
}
|
||||
|
||||
// len set by scope guard
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
trait Truncate {
|
||||
fn truncate(&mut self, len: usize);
|
||||
}
|
||||
|
||||
impl<T> Truncate for Vec<T> {
|
||||
fn truncate(&mut self, len: usize) {
|
||||
let current_len = self.len();
|
||||
unsafe {
|
||||
let mut ptr = self.as_mut_ptr().add(current_len);
|
||||
// Set the final length at the end, keeping in mind that
|
||||
// dropping an element might panic. Works around a missed
|
||||
// optimization, as seen in the following issue:
|
||||
// https://github.com/rust-lang/rust/issues/51802
|
||||
let mut local_len = self.len();
|
||||
|
||||
// drop any extra elements
|
||||
for _ in len..current_len {
|
||||
ptr = ptr.offset(-1);
|
||||
core::ptr::drop_in_place(ptr);
|
||||
local_len -= 1;
|
||||
self.set_len(local_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// try creating a vec from an `elem` cloned `n` times, see std::from_elem
|
||||
#[cfg(feature = "unstable")]
|
||||
pub fn try_from_elem<T: TryClone>(elem: T, n: usize) -> Result<Vec<T>, TryReserveError> {
|
||||
<T as SpecFromElem>::try_from_elem(elem, n)
|
||||
}
|
||||
|
||||
// Specialization trait used for Vec::from_elem
|
||||
#[cfg(feature = "unstable")]
|
||||
trait SpecFromElem: Sized {
|
||||
fn try_from_elem(elem: Self, n: usize) -> Result<Vec<Self>, TryReserveError>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
impl<T: TryClone> SpecFromElem for T {
|
||||
default fn try_from_elem(elem: Self, n: usize) -> Result<Vec<T>, TryReserveError> {
|
||||
let mut v = Vec::new();
|
||||
v.try_resize_no_copy(n, elem)?;
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
impl SpecFromElem for u8 {
|
||||
#[inline]
|
||||
fn try_from_elem(elem: u8, n: usize) -> Result<Vec<u8>, TryReserveError> {
|
||||
unsafe {
|
||||
let mut v = Vec::try_with_capacity(n)?;
|
||||
core::ptr::write_bytes(v.as_mut_ptr(), elem, n);
|
||||
v.set_len(n);
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TryClone> TryClone for Vec<T> {
|
||||
fn try_clone(&self) -> Result<Self, TryReserveError>
|
||||
where
|
||||
Self: core::marker::Sized,
|
||||
{
|
||||
let mut v = Vec::new();
|
||||
v.try_extend_from_slice_no_copy(self)?;
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TryFromIterator<I>: Sized {
|
||||
fn try_from_iterator<T: IntoIterator<Item = I>>(iterator: T) -> Result<Self, TryReserveError>;
|
||||
}
|
||||
|
||||
impl<I> TryFromIterator<I> for Vec<I> {
|
||||
fn try_from_iterator<T: IntoIterator<Item = I>>(iterator: T) -> Result<Self, TryReserveError>
|
||||
where
|
||||
T: IntoIterator<Item = I>,
|
||||
{
|
||||
let mut new = Self::new();
|
||||
for i in iterator {
|
||||
new.try_push(i)?;
|
||||
}
|
||||
Ok(new)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TryCollect<I> {
|
||||
fn try_collect<C: TryFromIterator<I>>(self) -> Result<C, TryReserveError>;
|
||||
}
|
||||
|
||||
impl<I, T> TryCollect<I> for T
|
||||
where
|
||||
T: IntoIterator<Item = I>,
|
||||
{
|
||||
fn try_collect<C: TryFromIterator<I>>(self) -> Result<C, TryReserveError> {
|
||||
C::try_from_iterator(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable")]
|
||||
fn vec() {
|
||||
// let v: Vec<u8> = from_elem(1, 10);
|
||||
let v: Vec<Vec<u8>> = try_vec![try_vec![42; 10].unwrap(); 100].unwrap();
|
||||
println!("{:?}", v);
|
||||
let v2 = try_vec![0, 1, 2];
|
||||
println!("{:?}", v2);
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_clone_vec() {
|
||||
// let v: Vec<u8> = from_elem(1, 10);
|
||||
let v = vec![42; 100];
|
||||
assert_eq!(v.try_clone().unwrap(), v);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_clone_oom() {
|
||||
let layout = Layout::new::<u8>();
|
||||
let v =
|
||||
unsafe { Vec::<u8>::from_raw_parts(alloc(layout), core::usize::MAX, core::usize::MAX) };
|
||||
assert!(v.try_clone().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tryvec_try_clone_oom() {
|
||||
let layout = Layout::new::<u8>();
|
||||
let inner =
|
||||
unsafe { Vec::<u8>::from_raw_parts(alloc(layout), core::usize::MAX, core::usize::MAX) };
|
||||
let tv = TryVec { inner };
|
||||
assert!(tv.try_clone().is_err());
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn try_out_of_mem() {
|
||||
// let v = try_vec![42_u8; 1000000000];
|
||||
// assert_eq!(v.try_clone().unwrap(), v);
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn oom() {
|
||||
let mut vec: Vec<char> = Vec::new();
|
||||
match FallibleVec::try_reserve(&mut vec, core::usize::MAX) {
|
||||
Ok(_) => panic!("it should be OOM"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tryvec_oom() {
|
||||
let mut vec: TryVec<char> = TryVec::new();
|
||||
match vec.reserve(core::usize::MAX) {
|
||||
Ok(_) => panic!("it should be OOM"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_reserve() {
|
||||
let mut vec: Vec<_> = vec![1];
|
||||
let additional_room = vec.capacity() - vec.len();
|
||||
let additional = additional_room + 1;
|
||||
let old_cap = vec.capacity();
|
||||
FallibleVec::try_reserve(&mut vec, additional).unwrap();
|
||||
assert!(vec.capacity() > old_cap);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tryvec_reserve() {
|
||||
let mut vec: TryVec<_> = vec![1].into();
|
||||
let old_cap = vec.inner.capacity();
|
||||
let new_cap = old_cap + 1;
|
||||
vec.reserve(new_cap).unwrap();
|
||||
assert!(vec.inner.capacity() >= new_cap);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_reserve_idempotent() {
|
||||
let mut vec: Vec<_> = vec![1];
|
||||
let additional_room = vec.capacity() - vec.len();
|
||||
let additional = additional_room + 1;
|
||||
FallibleVec::try_reserve(&mut vec, additional).unwrap();
|
||||
let cap_after_reserve = vec.capacity();
|
||||
FallibleVec::try_reserve(&mut vec, additional).unwrap();
|
||||
assert_eq!(vec.capacity(), cap_after_reserve);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tryvec_reserve_idempotent() {
|
||||
let mut vec: TryVec<_> = vec![1].into();
|
||||
let old_cap = vec.inner.capacity();
|
||||
let new_cap = old_cap + 1;
|
||||
vec.reserve(new_cap).unwrap();
|
||||
let cap_after_reserve = vec.inner.capacity();
|
||||
vec.reserve(new_cap).unwrap();
|
||||
assert_eq!(cap_after_reserve, vec.inner.capacity());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn capacity_overflow() {
|
||||
let mut vec: Vec<_> = vec![1];
|
||||
match FallibleVec::try_reserve(&mut vec, core::usize::MAX) {
|
||||
Ok(_) => panic!("capacity calculation should overflow"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tryvec_capacity_overflow() {
|
||||
let mut vec: TryVec<_> = vec![1].into();
|
||||
match vec.reserve(core::usize::MAX) {
|
||||
Ok(_) => panic!("capacity calculation should overflow"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extend_from_slice() {
|
||||
let mut vec: Vec<u8> = b"foo".as_ref().into();
|
||||
vec.try_extend_from_slice(b"bar").unwrap();
|
||||
assert_eq!(vec, b"foobar".as_ref());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tryvec_extend_from_slice() {
|
||||
let mut vec: TryVec<u8> = b"foo".as_ref().try_into().unwrap();
|
||||
vec.extend_from_slice(b"bar").unwrap();
|
||||
assert_eq!(vec, b"foobar".as_ref());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "unstable"))]
|
||||
fn try_extend_zst() {
|
||||
let mut vec: Vec<()> = Vec::new();
|
||||
assert_eq!(vec.capacity(), core::usize::MAX);
|
||||
assert!(vec_try_extend(&mut vec, 10).is_ok());
|
||||
assert!(vec_try_extend(&mut vec, core::usize::MAX).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_reserve_zst() {
|
||||
let mut vec: Vec<()> = Vec::new();
|
||||
assert!(FallibleVec::try_reserve(&mut vec, core::usize::MAX).is_ok());
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"f48619a9cfbcfcaf657d6b1e4894d2c68afd4b1c620d42d6923f814611bf6186","src/boxes.rs":"5f84805435af90034075709867e02c74a198e26dc628a9fc95df034928ee5bbc","src/fallible.rs":"7dc89699f1e75433ab5c6bbd23807383b3b918fe572d41e68e5a270591b0a4ab","src/lib.rs":"ff16461743a5e09c2dc8ade092206e4c84ddcae061766b38d53eff6f94916b2e","src/macros.rs":"76c840f9299797527fe71aa5b378ffb01312767372b45cc62deddb19775400ae","src/tests.rs":"f1a27e785d4006cd910ca3c48c8a972da1db9c9b4a67185f67a191ddc3c69328","tests/bug-1655846.avif":"e0a5a06225800fadf05f5352503a4cec11af73eef705c43b4acab5f4a99dea50","tests/overflow.rs":"16b591d8def1a155b3b997622f6ea255536870d99c3d8f97c51755b77a50de3c","tests/public.rs":"fd646ffd5fab8beed5949b87482048ba400438fa90860f86f357a7f6141dc649"},"package":null}
|
||||
{"files":{"Cargo.toml":"3707c837d19aeefff4bf899274055db9cd1fd8c7dcbbd5067622acb0f25ddd1f","src/boxes.rs":"7f989f8e91d173f323db22a8748ea911dd143c6304f66ccaf6ebc97d68ca5536","src/lib.rs":"4d4152c72ef49ced0a467879c51ff9e2430f704cd13a8eea4dc891b5f5843280","src/macros.rs":"76c840f9299797527fe71aa5b378ffb01312767372b45cc62deddb19775400ae","src/tests.rs":"6c1b8822410f5410d991f553925d3591f9c7ce41891191da8b3da62e783ebb02","tests/bug-1655846.avif":"e0a5a06225800fadf05f5352503a4cec11af73eef705c43b4acab5f4a99dea50","tests/bug-1661347.avif":"31c26561e1d9eafb60f7c5968b82a0859d203d73f17f26b29276256acee12966","tests/overflow.rs":"16b591d8def1a155b3b997622f6ea255536870d99c3d8f97c51755b77a50de3c","tests/public.rs":"5ff2282b0f84f55e25e18dcca9acc5bffde806d885c897354e5f65292f295557"},"package":null}
|
|
@ -27,6 +27,7 @@ travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
|
|||
[dependencies]
|
||||
byteorder = "1.2.1"
|
||||
bitreader = { version = "0.3.2" }
|
||||
fallible_collections = { version = "0.1.3", features = ["std_io"] }
|
||||
hashbrown = "0.7.1"
|
||||
num-traits = "=0.2.10"
|
||||
log = "0.4"
|
||||
|
@ -36,9 +37,3 @@ static_assertions = "1.1.0"
|
|||
test-assembler = "0.1.2"
|
||||
env_logger = "0.7.1"
|
||||
walkdir = "2.3.1"
|
||||
|
||||
[features]
|
||||
# Enable mp4parse_fallible to use fallible memory allocation rather than
|
||||
# panicking on OOM. Note that this is only safe within Gecko where the system
|
||||
# allocator has been globally overridden (see BMO 1457359).
|
||||
mp4parse_fallible = []
|
||||
|
|
|
@ -44,7 +44,7 @@ macro_rules! box_database {
|
|||
impl fmt::Debug for BoxType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let fourcc: FourCC = From::from(self.clone());
|
||||
write!(f, "{}", fourcc)
|
||||
fourcc.fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ impl From<[u8; 4]> for FourCC {
|
|||
impl fmt::Debug for FourCC {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match std::str::from_utf8(&self.value) {
|
||||
Ok(s) => write!(f, "{}", s),
|
||||
Ok(s) => f.write_str(s),
|
||||
Err(_) => self.value.fmt(f),
|
||||
}
|
||||
}
|
||||
|
@ -87,10 +87,7 @@ impl fmt::Debug for FourCC {
|
|||
|
||||
impl fmt::Display for FourCC {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match std::str::from_utf8(&self.value) {
|
||||
Ok(s) => write!(f, "{}", s),
|
||||
Err(_) => write!(f, "null"),
|
||||
}
|
||||
f.write_str(std::str::from_utf8(&self.value).unwrap_or("null"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,520 +0,0 @@
|
|||
//! The types in this module are thin wrappers around the stdlib types to add
|
||||
//! support for fallible allocation. Though the fallible allocator is only
|
||||
//! enabled with the mp4parse_fallible feature, the API differences from the
|
||||
//! stdlib types ensure that all operations which allocate return a Result.
|
||||
//! For the most part, this simply means adding a Result return value to
|
||||
//! functions which return nothing or a non-Result value. However, these types
|
||||
//! implement some traits whose API cannot communicate failure, but which do
|
||||
//! require allocation, so it is important that these wrapper types do not
|
||||
//! implement these traits.
|
||||
//!
|
||||
//! Specifically, do not implement any of the following traits:
|
||||
//! - Clone
|
||||
//! - Extend
|
||||
//! - From
|
||||
//! - FromIterator
|
||||
//!
|
||||
//! This list may not be exhaustive. Exercise caution when implementing
|
||||
//! any new traits to ensure they won't potentially allocate in a way that
|
||||
//! can't return a Result to indicate allocation failure.
|
||||
|
||||
#[cfg(feature = "mp4parse_fallible")]
|
||||
extern "C" {
|
||||
fn malloc(bytes: usize) -> *mut u8;
|
||||
fn realloc(ptr: *mut u8, bytes: usize) -> *mut u8;
|
||||
}
|
||||
|
||||
use std::convert::TryInto as _;
|
||||
use std::hash::Hash;
|
||||
use std::io::Read;
|
||||
use std::io::Take;
|
||||
use std::iter::IntoIterator;
|
||||
use BMFFBox;
|
||||
|
||||
type Result<T> = std::result::Result<T, super::Error>;
|
||||
|
||||
pub trait TryRead {
|
||||
fn try_read_to_end(&mut self, buf: &mut TryVec<u8>) -> Result<usize>;
|
||||
|
||||
fn read_into_try_vec(&mut self) -> Result<TryVec<u8>> {
|
||||
let mut buf = TryVec::new();
|
||||
let _ = self.try_read_to_end(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Read> TryRead for BMFFBox<'a, T> {
|
||||
fn try_read_to_end(&mut self, buf: &mut TryVec<u8>) -> Result<usize> {
|
||||
try_read_up_to(self, self.bytes_left(), buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Read> TryRead for Take<T> {
|
||||
/// With the `mp4parse_fallible` feature enabled, this function reserves the
|
||||
/// upper limit of what `src` can generate before reading all bytes until EOF
|
||||
/// in this source, placing them into buf. If the allocation is unsuccessful,
|
||||
/// or reading from the source generates an error before reaching EOF, this
|
||||
/// will return an error. Otherwise, it will return the number of bytes read.
|
||||
///
|
||||
/// Since `Take::limit()` may return a value greater than the number of bytes
|
||||
/// which can be read from the source, it's possible this function may fail
|
||||
/// in the allocation phase even though allocating the number of bytes available
|
||||
/// to read would have succeeded. In general, it is assumed that the callers
|
||||
/// have accurate knowledge of the number of bytes of interest and have created
|
||||
/// `src` accordingly.
|
||||
///
|
||||
/// With the `mp4parse_fallible` feature disabled, this is essentially a wrapper
|
||||
/// around `std::io::Read::read_to_end()`.
|
||||
fn try_read_to_end(&mut self, buf: &mut TryVec<u8>) -> Result<usize> {
|
||||
try_read_up_to(self, self.limit(), buf)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_read_up_to<R: Read>(src: &mut R, limit: u64, buf: &mut TryVec<u8>) -> Result<usize> {
|
||||
let additional = limit.try_into()?;
|
||||
buf.reserve(additional)?;
|
||||
let bytes_read = src.read_to_end(&mut buf.inner)?;
|
||||
Ok(bytes_read)
|
||||
}
|
||||
|
||||
/// TryBox is a thin wrapper around std::boxed::Box to provide support for
|
||||
/// fallible allocation.
|
||||
///
|
||||
/// See the `fallible` module documentation for more.
|
||||
pub struct TryBox<T> {
|
||||
inner: std::boxed::Box<T>,
|
||||
}
|
||||
|
||||
impl<T> TryBox<T> {
|
||||
pub fn try_new(x: T) -> Result<Self> {
|
||||
let inner;
|
||||
|
||||
#[cfg(feature = "mp4parse_fallible")]
|
||||
{
|
||||
let size = std::mem::size_of::<T>();
|
||||
let new_ptr = unsafe { malloc(size) as *mut T };
|
||||
|
||||
if new_ptr.is_null() {
|
||||
return Err(super::Error::OutOfMemory);
|
||||
}
|
||||
|
||||
// If we did a simple assignment: *new_ptr = x, then the value
|
||||
// pointed to by new_ptr would immediately be dropped, but
|
||||
// that would cause an invalid memory access. Instead, we use
|
||||
// replace() to avoid the immediate drop and forget() to
|
||||
// ensure that drop never happens.
|
||||
inner = unsafe {
|
||||
std::mem::forget(std::mem::replace(&mut *new_ptr, x));
|
||||
Box::from_raw(new_ptr)
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "mp4parse_fallible"))]
|
||||
{
|
||||
inner = Box::new(x);
|
||||
}
|
||||
|
||||
Ok(Self { inner })
|
||||
}
|
||||
|
||||
pub fn into_raw(b: TryBox<T>) -> *mut T {
|
||||
Box::into_raw(b.inner)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// See std::boxed::from_raw
|
||||
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
||||
Self {
|
||||
inner: Box::from_raw(raw),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TryHashMap is a thin wrapper around the hashbrown HashMap to provide
|
||||
/// support for fallible allocation. This is the same library that stdlib
|
||||
/// currently uses, but we use it directly since it provides try_reserve().
|
||||
///
|
||||
/// See the `fallible` module documentation for more.
|
||||
#[derive(Default)]
|
||||
pub struct TryHashMap<K, V> {
|
||||
inner: hashbrown::hash_map::HashMap<K, V>,
|
||||
}
|
||||
|
||||
impl<K, V> TryHashMap<K, V>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
{
|
||||
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
|
||||
where
|
||||
K: std::borrow::Borrow<Q>,
|
||||
Q: Hash + Eq,
|
||||
{
|
||||
self.inner.get(k)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, k: K, v: V) -> Result<Option<V>> {
|
||||
self.reserve(if self.inner.capacity() == 0 { 4 } else { 1 })?;
|
||||
Ok(self.inner.insert(k, v))
|
||||
}
|
||||
|
||||
fn reserve(&mut self, additional: usize) -> Result<()> {
|
||||
#[cfg(feature = "mp4parse_fallible")]
|
||||
{
|
||||
self.inner
|
||||
.try_reserve(additional)
|
||||
.map_err(|_| super::Error::OutOfMemory)
|
||||
}
|
||||
#[cfg(not(feature = "mp4parse_fallible"))]
|
||||
{
|
||||
self.inner.reserve(additional);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "mp4parse_fallible")]
|
||||
fn tryhashmap_oom() {
|
||||
match TryHashMap::<char, char>::default().reserve(std::usize::MAX) {
|
||||
Ok(_) => panic!("it should be OOM"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq)]
|
||||
pub struct TryVec<T> {
|
||||
inner: std::vec::Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: std::fmt::Debug> std::fmt::Debug for TryVec<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
/// TryVec is a thin wrapper around std::vec::Vec to provide support for
|
||||
/// fallible allocation.
|
||||
///
|
||||
/// See the `fallible` module documentation for more.
|
||||
impl<T> TryVec<T> {
|
||||
pub fn new() -> Self {
|
||||
Self { inner: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn with_capacity(capacity: usize) -> Result<Self> {
|
||||
let mut v = Self::new();
|
||||
v.reserve(capacity)?;
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
pub fn append(&mut self, other: &mut Self) -> Result<()> {
|
||||
self.reserve(other.inner.len())?;
|
||||
self.inner.append(&mut other.inner);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.inner.clear()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn into_inner(self) -> Vec<T> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> IterMut<T> {
|
||||
IterMut {
|
||||
inner: self.inner.iter_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter {
|
||||
inner: self.inner.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
self.inner.pop()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: T) -> Result<()> {
|
||||
self.reserve(if self.inner.capacity() == 0 { 4 } else { 1 })?;
|
||||
self.inner.push(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reserve(&mut self, additional: usize) -> Result<()> {
|
||||
#[cfg(feature = "mp4parse_fallible")]
|
||||
{
|
||||
let available = self
|
||||
.inner
|
||||
.capacity()
|
||||
.checked_sub(self.inner.len())
|
||||
.expect("capacity >= len");
|
||||
if additional > available {
|
||||
let increase = additional
|
||||
.checked_sub(available)
|
||||
.expect("additional > available");
|
||||
let new_cap = self
|
||||
.inner
|
||||
.capacity()
|
||||
.checked_add(increase)
|
||||
.ok_or(super::Error::OutOfMemory)?;
|
||||
self.try_extend(new_cap)?;
|
||||
debug_assert!(self.inner.capacity() == new_cap);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(not(feature = "mp4parse_fallible"))]
|
||||
{
|
||||
self.inner.reserve(additional);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resize_with<F>(&mut self, new_len: usize, f: F) -> Result<()>
|
||||
where
|
||||
F: FnMut() -> T,
|
||||
{
|
||||
self.reserve(new_len)?;
|
||||
self.inner.resize_with(new_len, f);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "mp4parse_fallible")]
|
||||
fn try_extend(&mut self, new_cap: usize) -> Result<()> {
|
||||
let old_ptr = self.as_mut_ptr();
|
||||
let old_len = self.inner.len();
|
||||
|
||||
let old_cap: usize = self.inner.capacity();
|
||||
|
||||
if old_cap >= new_cap {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let new_size_bytes = new_cap
|
||||
.checked_mul(std::mem::size_of::<T>())
|
||||
.ok_or(super::Error::OutOfMemory)?;
|
||||
|
||||
let new_ptr = unsafe {
|
||||
if old_cap == 0 {
|
||||
malloc(new_size_bytes)
|
||||
} else {
|
||||
realloc(old_ptr as *mut u8, new_size_bytes)
|
||||
}
|
||||
};
|
||||
|
||||
if new_ptr.is_null() {
|
||||
return Err(super::Error::OutOfMemory);
|
||||
}
|
||||
|
||||
let new_vec = unsafe { Vec::from_raw_parts(new_ptr as *mut T, old_len, new_cap) };
|
||||
|
||||
std::mem::forget(std::mem::replace(&mut self.inner, new_vec));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> TryVec<TryVec<T>> {
|
||||
pub fn concat(&self) -> Result<TryVec<T>> {
|
||||
let size = self.iter().map(|v| v.inner.len()).sum();
|
||||
let mut result = TryVec::with_capacity(size)?;
|
||||
for v in self.iter() {
|
||||
result.extend_from_slice(&v.inner)?;
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> TryVec<T> {
|
||||
pub fn extend_from_slice(&mut self, other: &[T]) -> Result<()> {
|
||||
self.reserve(other.len())?;
|
||||
self.inner.extend_from_slice(other);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "mp4parse_fallible")]
|
||||
fn oom() {
|
||||
let mut vec: TryVec<char> = TryVec::new();
|
||||
match vec.reserve(std::usize::MAX) {
|
||||
Ok(_) => panic!("it should be OOM"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_reserve() {
|
||||
let mut vec: TryVec<_> = vec![1].into();
|
||||
let old_cap = vec.inner.capacity();
|
||||
let new_cap = old_cap + 1;
|
||||
vec.reserve(new_cap).unwrap();
|
||||
assert!(vec.inner.capacity() >= new_cap);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_reserve_idempotent() {
|
||||
let mut vec: TryVec<_> = vec![1].into();
|
||||
let old_cap = vec.inner.capacity();
|
||||
let new_cap = old_cap + 1;
|
||||
vec.reserve(new_cap).unwrap();
|
||||
let cap_after_reserve = vec.inner.capacity();
|
||||
vec.reserve(new_cap).unwrap();
|
||||
assert_eq!(cap_after_reserve, vec.inner.capacity());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "mp4parse_fallible")]
|
||||
fn capacity_overflow() {
|
||||
let mut vec: TryVec<_> = vec![1].into();
|
||||
match vec.reserve(std::usize::MAX) {
|
||||
Ok(_) => panic!("capacity calculation should overflow"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extend_from_slice() {
|
||||
let mut vec: TryVec<u8> = b"foo".as_ref().try_into().unwrap();
|
||||
vec.extend_from_slice(b"bar").unwrap();
|
||||
assert_eq!(vec, b"foobar".as_ref());
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for TryVec<T> {
|
||||
type Item = T;
|
||||
type IntoIter = std::vec::IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.inner.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a TryVec<T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = std::slice::Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.inner.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::io::Write for TryVec<u8> {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.extend_from_slice(buf)?;
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq<Vec<T>> for TryVec<T> {
|
||||
fn eq(&self, other: &Vec<T>) -> bool {
|
||||
self.inner.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PartialEq> PartialEq<&'a [T]> for TryVec<T> {
|
||||
fn eq(&self, other: &&[T]) -> bool {
|
||||
self.inner.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for TryVec<u8> {
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
self.as_slice() == other.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::AsRef<[u8]> for TryVec<u8> {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.inner.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::convert::From<Vec<T>> for TryVec<T> {
|
||||
fn from(value: Vec<T>) -> Self {
|
||||
Self { inner: value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> std::convert::TryFrom<&[T]> for TryVec<T> {
|
||||
type Error = super::Error;
|
||||
|
||||
fn try_from(value: &[T]) -> Result<Self> {
|
||||
let mut v = Self::new();
|
||||
v.extend_from_slice(value)?;
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&str> for TryVec<u8> {
|
||||
type Error = super::Error;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self> {
|
||||
let mut v = Self::new();
|
||||
v.extend_from_slice(value.as_bytes())?;
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for TryVec<T> {
|
||||
type Target = [T];
|
||||
|
||||
fn deref(&self) -> &[T] {
|
||||
self.inner.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::DerefMut for TryVec<T> {
|
||||
fn deref_mut(&mut self) -> &mut [T] {
|
||||
self.inner.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<'a, T> {
|
||||
inner: std::slice::Iter<'a, T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for Iter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.inner.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IterMut<'a, T> {
|
||||
inner: std::slice::IterMut<'a, T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for IterMut<'a, T> {
|
||||
type Item = &'a mut T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.inner.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
}
|
|
@ -9,10 +9,11 @@ extern crate log;
|
|||
|
||||
extern crate bitreader;
|
||||
extern crate byteorder;
|
||||
extern crate fallible_collections;
|
||||
extern crate num_traits;
|
||||
use bitreader::{BitReader, ReadInto};
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||
use fallible::TryRead as _;
|
||||
use fallible_collections::TryRead;
|
||||
use num_traits::Num;
|
||||
use std::convert::{TryFrom, TryInto as _};
|
||||
use std::io::Cursor;
|
||||
|
@ -25,8 +26,6 @@ mod macros;
|
|||
mod boxes;
|
||||
use boxes::{BoxType, FourCC};
|
||||
|
||||
mod fallible;
|
||||
|
||||
// Unit tests.
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
@ -119,14 +118,10 @@ impl<'a, T: Read> Read for OffsetReader<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: all the functions that rely on the mp4parse_fallible feature need to
|
||||
// be updated when Rust supports fallible memory allocation in raw_vec.
|
||||
// See https://github.com/mozilla/mp4parse-rust/issues/146
|
||||
|
||||
pub type TryVec<T> = fallible::TryVec<T>;
|
||||
pub type TryString = TryVec<u8>;
|
||||
pub type TryHashMap<K, V> = fallible::TryHashMap<K, V>;
|
||||
pub type TryBox<T> = fallible::TryBox<T>;
|
||||
pub type TryVec<T> = fallible_collections::TryVec<T>;
|
||||
pub type TryString = fallible_collections::TryVec<u8>;
|
||||
pub type TryHashMap<K, V> = fallible_collections::TryHashMap<K, V>;
|
||||
pub type TryBox<T> = fallible_collections::TryBox<T>;
|
||||
|
||||
// To ensure we don't use stdlib allocating types by accident
|
||||
#[allow(dead_code)]
|
||||
|
@ -205,6 +200,12 @@ impl From<Error> for std::io::Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<fallible_collections::TryReserveError> for Error {
|
||||
fn from(_: fallible_collections::TryReserveError) -> Error {
|
||||
Error::OutOfMemory
|
||||
}
|
||||
}
|
||||
|
||||
/// Result shorthand using our Error enum.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
|
@ -1050,6 +1051,12 @@ impl<'a, T: Read> Read for BMFFBox<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Read> TryRead for BMFFBox<'a, T> {
|
||||
fn try_read_to_end(&mut self, buf: &mut TryVec<u8>) -> std::io::Result<usize> {
|
||||
fallible_collections::try_read_up_to(self, self.bytes_left(), buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Offset> Offset for BMFFBox<'a, T> {
|
||||
fn offset(&self) -> u64 {
|
||||
self.content.get_ref().offset()
|
||||
|
@ -1318,7 +1325,11 @@ pub fn read_avif<T: Read>(f: &mut T, context: &mut AvifContext) -> Result<()> {
|
|||
|
||||
context.primary_item = primary_item_extents_data.concat()?;
|
||||
|
||||
Ok(())
|
||||
if primary_item_extents_data.iter().any(TryVec::is_empty) {
|
||||
Err(Error::InvalidData("Primary item data incomplete"))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a metadata box in the context of an AVIF
|
||||
|
@ -1455,7 +1466,7 @@ struct U32BE(u32);
|
|||
impl std::fmt::Display for U32BE {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match std::str::from_utf8(&self.0.to_be_bytes()) {
|
||||
Ok(s) => write!(f, "{}", s),
|
||||
Ok(s) => f.write_str(s),
|
||||
Err(_) => write!(f, "{:x?}", self.0),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,11 @@
|
|||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
use super::fallible::TryRead as _;
|
||||
use super::read_mp4;
|
||||
use super::Error;
|
||||
use super::MediaContext;
|
||||
use fallible_collections::TryRead as _;
|
||||
|
||||
#[cfg(feature = "mp4parse_fallible")]
|
||||
use std::convert::TryInto as _;
|
||||
use std::io::Cursor;
|
||||
use std::io::Read as _;
|
||||
|
@ -1297,11 +1296,10 @@ fn read_to_end_() {
|
|||
let mut src = b"1234567890".take(5);
|
||||
let buf = src.read_into_try_vec().unwrap();
|
||||
assert_eq!(buf.len(), 5);
|
||||
assert_eq!(buf.into_inner(), b"12345");
|
||||
assert_eq!(buf, b"12345".as_ref());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "mp4parse_fallible")]
|
||||
fn read_to_end_oom() {
|
||||
let mut src = b"1234567890".take(std::usize::MAX.try_into().expect("usize < u64"));
|
||||
assert!(src.read_into_try_vec().is_err());
|
||||
|
|
Двоичный файл не отображается.
|
@ -29,6 +29,7 @@ static VIDEO_EME_CBCS_MP4: &str = "tests/bipbop_cbcs_video_init.mp4";
|
|||
static VIDEO_AV1_MP4: &str = "tests/tiny_av1.mp4";
|
||||
static IMAGE_AVIF: &str = "av1-avif/testFiles/Microsoft/Monochrome.avif";
|
||||
static IMAGE_AVIF_CORRUPT: &str = "tests/bug-1655846.avif";
|
||||
static IMAGE_AVIF_CORRUPT_2: &str = "tests/bug-1661347.avif";
|
||||
static IMAGE_AVIF_GRID: &str = "av1-avif/testFiles/Microsoft/Summer_in_Tomsk_720p_5x4_grid.avif";
|
||||
static AVIF_TEST_DIR: &str = "av1-avif/testFiles";
|
||||
|
||||
|
@ -635,6 +636,13 @@ fn public_avif_bug_1655846() {
|
|||
assert!(mp4::read_avif(input, context).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_avif_bug_1661347() {
|
||||
let context = &mut mp4::AvifContext::new();
|
||||
let input = &mut File::open(IMAGE_AVIF_CORRUPT_2).expect("Unknown file");
|
||||
assert!(mp4::read_avif(input, context).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // Remove when we add support; see https://github.com/mozilla/mp4parse-rust/issues/198
|
||||
fn public_avif_primary_item_is_grid() {
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"12f3f7561fa1d5facc70b63b68288997ca6fde3dd5d6fabcfe2e7d8ec5940ab2","cbindgen.toml":"5c9429f271d6e914d81b63e6509c04ffe84cab11ed3a53a2ed4715e5d5ace80e","examples/dump.rs":"83462422315c22e496960bae922edb23105c0aa272d2b106edd7574ff068513a","src/lib.rs":"e90c6bdfcf321115b19f0148b5f273c9516bc7dfdae16c7c01a76ba8be51dad3","tests/test_chunk_out_of_range.rs":"b5da583218d98027ed973a29c67434a91a1306f2d2fb39ec4d640d4824c308ce","tests/test_encryption.rs":"ca98516ff423c03b5fcc17b05f993f13b32485e4cf3ba86faf1bea72681d75ce","tests/test_fragment.rs":"e90eb5a4418d30002655466c0c4b3125c7fd70a74b6871471eaa172f1def9db8","tests/test_rotation.rs":"fb43c2f2dfa496d151c33bdd46c0fd3252387c23cc71e2cac9ed0234de715a81","tests/test_sample_table.rs":"185755909b2f4e0ea99604bb423a07623d614a180accdaebd1c98aef2c2e3ae6","tests/test_workaround_stsc.rs":"7dd419f3d55b9a3a039cac57e58a9240a9c8166bcd4356c24f69f731c3ced83b"},"package":null}
|
||||
{"files":{"Cargo.toml":"589072f91823f3ae58e4ccf0c2fc756c6512921497d8df648049ad620233059c","cbindgen.toml":"5c9429f271d6e914d81b63e6509c04ffe84cab11ed3a53a2ed4715e5d5ace80e","examples/dump.rs":"83462422315c22e496960bae922edb23105c0aa272d2b106edd7574ff068513a","src/lib.rs":"76fb7cd35bbe56463d43f452fd7ebaf5b4619bd661fb71fb45f69e980877b424","tests/test_chunk_out_of_range.rs":"b5da583218d98027ed973a29c67434a91a1306f2d2fb39ec4d640d4824c308ce","tests/test_encryption.rs":"ca98516ff423c03b5fcc17b05f993f13b32485e4cf3ba86faf1bea72681d75ce","tests/test_fragment.rs":"e90eb5a4418d30002655466c0c4b3125c7fd70a74b6871471eaa172f1def9db8","tests/test_rotation.rs":"fb43c2f2dfa496d151c33bdd46c0fd3252387c23cc71e2cac9ed0234de715a81","tests/test_sample_table.rs":"185755909b2f4e0ea99604bb423a07623d614a180accdaebd1c98aef2c2e3ae6","tests/test_workaround_stsc.rs":"7dd419f3d55b9a3a039cac57e58a9240a9c8166bcd4356c24f69f731c3ced83b"},"package":null}
|
|
@ -24,16 +24,10 @@ travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
|
|||
|
||||
[dependencies]
|
||||
byteorder = "1.2.1"
|
||||
fallible_collections = { version = "0.1.3", features = ["std_io"] }
|
||||
log = "0.4"
|
||||
mp4parse = {version = "0.11.2", path = "../mp4parse"}
|
||||
num-traits = "=0.2.10"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.7.1"
|
||||
|
||||
[features]
|
||||
# Enable mp4parse_fallible to use fallible memory allocation rather than
|
||||
# panicking on OOM. Note that this is only safe within Gecko where the system
|
||||
# allocator has been globally overridden (see BMO 1457359).
|
||||
mp4parse_fallible = ["mp4parse/mp4parse_fallible"]
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
extern crate byteorder;
|
||||
extern crate log;
|
||||
extern crate mp4parse;
|
||||
extern crate num_traits;
|
||||
|
||||
|
@ -600,7 +601,7 @@ fn mp4parse_new_common_safe<T: Read, P: ContextParser>(
|
|||
|
||||
P::read(io, &mut context)
|
||||
.map(|_| P::with_context(context))
|
||||
.and_then(TryBox::try_new)
|
||||
.and_then(|x| TryBox::try_new(x).map_err(mp4parse::Error::from))
|
||||
.map(TryBox::into_raw)
|
||||
.map_err(Mp4parseStatus::from)
|
||||
}
|
||||
|
@ -632,6 +633,12 @@ impl From<Result<(), Mp4parseStatus>> for Mp4parseStatus {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<fallible_collections::TryReserveError> for Mp4parseStatus {
|
||||
fn from(_: fallible_collections::TryReserveError) -> Self {
|
||||
Mp4parseStatus::Oom
|
||||
}
|
||||
}
|
||||
|
||||
/// Free an `Mp4parseParser*` allocated by `mp4parse_new()`.
|
||||
///
|
||||
/// # Safety
|
||||
|
|
|
@ -9,7 +9,7 @@ description = "Shared Rust code for libxul"
|
|||
geckoservo = { path = "../../../../servo/ports/geckolib" }
|
||||
kvstore = { path = "../../../components/kvstore" }
|
||||
lmdb-rkv-sys = { version = "0.11", features = ["mdb_idl_logn_9"] }
|
||||
mp4parse_capi = { git = "https://github.com/mozilla/mp4parse-rust", rev = "d5a37fd0bd51e06a53274c68213b00136aba83a6" }
|
||||
mp4parse_capi = { git = "https://github.com/mozilla/mp4parse-rust", rev = "fe9028570e44f3a725dd78bbb58428909c4618bf" }
|
||||
nserror = { path = "../../../../xpcom/rust/nserror" }
|
||||
nsstring = { path = "../../../../xpcom/rust/nsstring" }
|
||||
netwerk_helper = { path = "../../../../netwerk/base/rust-helper" }
|
||||
|
@ -83,7 +83,7 @@ cubeb_pulse_rust = ["cubeb-sys", "cubeb-pulse"]
|
|||
gecko_debug = ["geckoservo/gecko_debug", "nsstring/gecko_debug"]
|
||||
gecko_refcount_logging = ["geckoservo/gecko_refcount_logging"]
|
||||
simd-accel = ["encoding_glue/simd-accel", "jsrust_shared/simd-accel"]
|
||||
moz_memory = ["mp4parse_capi/mp4parse_fallible"]
|
||||
moz_memory = []
|
||||
moz_places = ["bookmark_sync"]
|
||||
spidermonkey_rust = ["jsrust_shared/baldrdash"]
|
||||
cranelift_x86 = ["jsrust_shared/cranelift_x86"]
|
||||
|
|
Загрузка…
Ссылка в новой задаче