Bug 1854025 - Update tempfile to 3.8.0. r=emilio,supply-chain-reviewers,sylvestre

Differential Revision: https://phabricator.services.mozilla.com/D188654
This commit is contained in:
Mike Hommey 2023-09-25 20:47:25 +00:00
Родитель 390281e651
Коммит 1e09918ec1
43 изменённых файлов: 1578 добавлений и 1396 удалений

37
Cargo.lock сгенерированный
Просмотреть файл

@ -1626,12 +1626,9 @@ dependencies = [
[[package]]
name = "fastrand"
version = "1.9.0"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
dependencies = [
"instant",
]
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
[[package]]
name = "ffi-support"
@ -2201,7 +2198,6 @@ dependencies = [
"rure",
"rusqlite",
"rust_minidump_writer_linux",
"rustix",
"static_prefs",
"storage",
"suggest",
@ -2771,15 +2767,6 @@ dependencies = [
"syn",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "interrupt-support"
version = "0.1.0"
@ -4151,7 +4138,7 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall 0.3.999",
"redox_syscall",
"smallvec",
"windows-targets",
]
@ -4553,13 +4540,6 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "redox_syscall"
version = "0.2.999"
dependencies = [
"redox_syscall 0.3.999",
]
[[package]]
name = "redox_syscall"
version = "0.3.999"
@ -5409,16 +5389,15 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.3.0"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
dependencies = [
"cfg-if 1.0.0",
"fastrand",
"libc",
"redox_syscall 0.2.999",
"remove_dir_all",
"winapi",
"redox_syscall",
"rustix",
"windows-sys",
]
[[package]]

Просмотреть файл

@ -121,7 +121,6 @@ serde_with = { path = "build/rust/serde_with" }
redox_users = { path = "build/rust/redox_users" }
# Patch redox_syscall to an empty crate
redox_syscall_0_2 = { package = "redox_syscall", path = "build/rust/redox_syscall_0_2" }
redox_syscall = { path = "build/rust/redox_syscall" }
# Override tinyvec with smallvec

Просмотреть файл

@ -1,11 +0,0 @@
[package]
name = "redox_syscall"
version = "0.2.999"
edition = "2018"
license = "MPL-2.0"
[lib]
path = "lib.rs"
[dependencies]
redox_syscall = "0.3"

Просмотреть файл

@ -1,3 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

Просмотреть файл

@ -1396,6 +1396,11 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "1.8.0 -> 1.9.0"
[[audits.fastrand]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "1.9.0 -> 2.0.0"
[[audits.filetime_win]]
who = "Nick Alexander <nalexander@mozilla.com>"
criteria = "safe-to-deploy"
@ -3271,6 +3276,11 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "0.12.6 -> 0.13.0"
[[audits.tempfile]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "3.6.0 -> 3.8.0"
[[audits.termcolor]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"

Просмотреть файл

@ -1034,6 +1034,17 @@ criteria = "safe-to-deploy"
version = "0.4.6"
notes = "provides a datastructure implemented using std's Vec. all uses of unsafe are just delegating to the underlying unsafe Vec methods."
[[audits.bytecode-alliance.audits.tempfile]]
who = "Pat Hickey <phickey@fastly.com>"
criteria = "safe-to-deploy"
delta = "3.3.0 -> 3.5.0"
[[audits.bytecode-alliance.audits.tempfile]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"
delta = "3.5.0 -> 3.6.0"
notes = "Dependency updates and new optimized trait implementations, but otherwise everything looks normal."
[[audits.bytecode-alliance.audits.unicase]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"

Просмотреть файл

@ -1 +1 @@
{"files":{"CHANGELOG.md":"64192695962b6d2ec5f1f57f3b7909c216611a5de5cd5d0d28d863477eef0a12","Cargo.toml":"9d3bf85fff7d7228a8aae6e0c20a43f19a846412e598ee0b7d1f6f2a30bac880","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"dec6b96d3549746937d7e0e62e35e206e6f5b7e2d1886451281905f4edf096d4","benches/bench.rs":"234b2e5f725102ed0ff7686def089de23e433eeecaf03542af31fc60725e85e3","src/lib.rs":"88bf8a952c723b28b989c7b998b2ec0de6a1351f6891088d6237300c8982f36d","tests/char.rs":"a530b41837f5bf43701d983ef0267d9b44779d455f24cbf30b881cd348de9ee1","tests/smoke.rs":"aac00322cce06f15378aacbf247a37e9602c46cfd2bd588a0887b266cbc4770a"},"package":"e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"}
{"files":{"CHANGELOG.md":"a88b4ec120e965c0219c8d4a95e0868ed9396acb47d171ca864608eacda7efb8","Cargo.toml":"f0bc7071d293be9565d4a960fa914317f00f319901e9578e7a49a3a86959d90a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"ba09e4125cf5450a26d1bd2236bd079d668b118df639d9055e61eaa4d3c23336","benches/bench.rs":"95df618eeb6f3432e11295d75267c0ececcda35a6d230e9ca504e5d772fa2b62","src/global_rng.rs":"43a74ba2c3c15ebdbbacff65d6da5a90b4c062dedc43c6bf3fcf05499beaeece","src/lib.rs":"67568c53a27b34c5e2eb5e613a9656bcc9da1688a85070c4c36b60c216e3da8b","tests/char.rs":"a530b41837f5bf43701d983ef0267d9b44779d455f24cbf30b881cd348de9ee1","tests/smoke.rs":"8eac48144705364d142882538be43b8d69018959579404c3b1e638827888e62e"},"package":"6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"}

9
third_party/rust/fastrand/CHANGELOG.md поставляемый
Просмотреть файл

@ -1,3 +1,12 @@
# Version 2.0.0
- **Breaking:** Remove interior mutability from `Rng`. (#47)
- Add a `fork()` method. (#49)
- Add a `no_std` mode. (#50)
- Add an iterator selection function. (#51)
- Add a `choose_multiple()` function for sampling several elements from an iterator. (#55)
- Use the `getrandom` crate for seeding on WebAssembly targets if the `js` feature is enabled. (#60)
# Version 1.9.0
- Add `Rng::fill()` (#35, #43)

34
third_party/rust/fastrand/Cargo.toml поставляемый
Просмотреть файл

@ -11,9 +11,9 @@
[package]
edition = "2018"
rust-version = "1.34"
rust-version = "1.36"
name = "fastrand"
version = "1.9.0"
version = "2.0.0"
authors = ["Stjepan Glavina <stjepang@gmail.com>"]
exclude = ["/.*"]
description = "A simple and fast random number generator"
@ -29,6 +29,13 @@ categories = ["algorithms"]
license = "Apache-2.0 OR MIT"
repository = "https://github.com/smol-rs/fastrand"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = [
"--cfg",
"docsrs",
]
[dev-dependencies.getrandom]
version = "0.2"
@ -38,16 +45,23 @@ version = "0.8"
[dev-dependencies.wyhash]
version = "0.5"
[target."cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))".dependencies.instant]
version = "0.1"
[features]
alloc = []
default = ["std"]
js = [
"std",
"getrandom",
]
std = ["alloc"]
[target."cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))".dev-dependencies.getrandom]
[target."cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))".dependencies.getrandom]
version = "0.2"
features = ["js"]
optional = true
[target."cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))".dev-dependencies.getrandom]
version = "0.2"
features = ["js"]
[target."cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))".dev-dependencies.instant]
version = "0.1"
features = ["wasm-bindgen"]
[target."cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))".dev-dependencies.wasm-bindgen-test]
[target."cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))".dev-dependencies.wasm-bindgen-test]
version = "0.3"

13
third_party/rust/fastrand/README.md поставляемый
Просмотреть файл

@ -40,6 +40,13 @@ let i = fastrand::usize(..v.len());
let elem = v[i];
```
Sample values from an array with `O(n)` complexity (`n` is the length of array):
```rust
fastrand::choose_multiple(vec![1, 4, 5].iter(), 2);
fastrand::choose_multiple(0..20, 12);
```
Shuffle an array:
```rust
@ -76,6 +83,12 @@ let rng = fastrand::Rng::new();
let mut bytes: Vec<u8> = repeat_with(|| rng.u8(..)).take(10_000).collect();
```
# Features
- `std` (enabled by default): Enables the `std` library. This is required for the global
generator and global entropy. Without this feature, [`Rng`] can only be instantiated using
the [`with_seed`](Rng::with_seed) method.
## License
Licensed under either of

10
third_party/rust/fastrand/benches/bench.rs поставляемый
Просмотреть файл

@ -18,7 +18,7 @@ fn shuffle_wyhash(b: &mut Bencher) {
#[bench]
fn shuffle_fastrand(b: &mut Bencher) {
let rng = fastrand::Rng::new();
let mut rng = fastrand::Rng::new();
let mut x = (0..100).collect::<Vec<usize>>();
b.iter(|| {
rng.shuffle(&mut x);
@ -40,7 +40,7 @@ fn u8_wyhash(b: &mut Bencher) {
#[bench]
fn u8_fastrand(b: &mut Bencher) {
let rng = fastrand::Rng::new();
let mut rng = fastrand::Rng::new();
b.iter(|| {
let mut sum = 0u8;
for _ in 0..10_000 {
@ -64,7 +64,7 @@ fn u32_wyhash(b: &mut Bencher) {
#[bench]
fn u32_fastrand(b: &mut Bencher) {
let rng = fastrand::Rng::new();
let mut rng = fastrand::Rng::new();
b.iter(|| {
let mut sum = 0u32;
for _ in 0..10_000 {
@ -76,7 +76,7 @@ fn u32_fastrand(b: &mut Bencher) {
#[bench]
fn fill(b: &mut Bencher) {
let rng = fastrand::Rng::new();
let mut rng = fastrand::Rng::new();
b.iter(|| {
// Pick a size that isn't divisble by 8.
let mut bytes = [0u8; 367];
@ -87,7 +87,7 @@ fn fill(b: &mut Bencher) {
#[bench]
fn fill_naive(b: &mut Bencher) {
let rng = fastrand::Rng::new();
let mut rng = fastrand::Rng::new();
b.iter(|| {
let mut bytes = [0u8; 367];
for item in &mut bytes {

218
third_party/rust/fastrand/src/global_rng.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,218 @@
//! A global, thread-local random number generator.
use crate::Rng;
use std::cell::Cell;
use std::ops::RangeBounds;
// Chosen by fair roll of the dice.
const DEFAULT_RNG_SEED: u64 = 0xef6f79ed30ba75a;
impl Default for Rng {
/// Initialize the `Rng` from the system's random number generator.
///
/// This is equivalent to [`Rng::new()`].
#[inline]
fn default() -> Rng {
Rng::new()
}
}
impl Rng {
/// Creates a new random number generator.
#[inline]
pub fn new() -> Rng {
try_with_rng(Rng::fork).unwrap_or_else(|_| Rng::with_seed(0x4d595df4d0f33173))
}
}
thread_local! {
static RNG: Cell<Rng> = Cell::new(Rng(random_seed().unwrap_or(DEFAULT_RNG_SEED)));
}
/// Run an operation with the current thread-local generator.
#[inline]
fn with_rng<R>(f: impl FnOnce(&mut Rng) -> R) -> R {
RNG.with(|rng| {
let current = rng.replace(Rng(0));
let mut restore = RestoreOnDrop { rng, current };
f(&mut restore.current)
})
}
/// Try to run an operation with the current thread-local generator.
#[inline]
fn try_with_rng<R>(f: impl FnOnce(&mut Rng) -> R) -> Result<R, std::thread::AccessError> {
RNG.try_with(|rng| {
let current = rng.replace(Rng(0));
let mut restore = RestoreOnDrop { rng, current };
f(&mut restore.current)
})
}
/// Make sure the original RNG is restored even on panic.
struct RestoreOnDrop<'a> {
rng: &'a Cell<Rng>,
current: Rng,
}
impl Drop for RestoreOnDrop<'_> {
fn drop(&mut self) {
self.rng.set(Rng(self.current.0));
}
}
/// Initializes the thread-local generator with the given seed.
#[inline]
pub fn seed(seed: u64) {
with_rng(|r| r.seed(seed));
}
/// Gives back **current** seed that is being held by the thread-local generator.
#[inline]
pub fn get_seed() -> u64 {
with_rng(|r| r.get_seed())
}
/// Generates a random `bool`.
#[inline]
pub fn bool() -> bool {
with_rng(|r| r.bool())
}
/// Generates a random `char` in ranges a-z and A-Z.
#[inline]
pub fn alphabetic() -> char {
with_rng(|r| r.alphabetic())
}
/// Generates a random `char` in ranges a-z, A-Z and 0-9.
#[inline]
pub fn alphanumeric() -> char {
with_rng(|r| r.alphanumeric())
}
/// Generates a random `char` in range a-z.
#[inline]
pub fn lowercase() -> char {
with_rng(|r| r.lowercase())
}
/// Generates a random `char` in range A-Z.
#[inline]
pub fn uppercase() -> char {
with_rng(|r| r.uppercase())
}
/// Choose an item from an iterator at random.
///
/// This function may have an unexpected result if the `len()` property of the
/// iterator does not match the actual number of items in the iterator. If
/// the iterator is empty, this returns `None`.
#[inline]
pub fn choice<I>(iter: I) -> Option<I::Item>
where
I: IntoIterator,
I::IntoIter: ExactSizeIterator,
{
with_rng(|r| r.choice(iter))
}
/// Generates a random digit in the given `base`.
///
/// Digits are represented by `char`s in ranges 0-9 and a-z.
///
/// Panics if the base is zero or greater than 36.
#[inline]
pub fn digit(base: u32) -> char {
with_rng(|r| r.digit(base))
}
/// Shuffles a slice randomly.
#[inline]
pub fn shuffle<T>(slice: &mut [T]) {
with_rng(|r| r.shuffle(slice))
}
macro_rules! integer {
($t:tt, $doc:tt) => {
#[doc = $doc]
///
/// Panics if the range is empty.
#[inline]
pub fn $t(range: impl RangeBounds<$t>) -> $t {
with_rng(|r| r.$t(range))
}
};
}
integer!(u8, "Generates a random `u8` in the given range.");
integer!(i8, "Generates a random `i8` in the given range.");
integer!(u16, "Generates a random `u16` in the given range.");
integer!(i16, "Generates a random `i16` in the given range.");
integer!(u32, "Generates a random `u32` in the given range.");
integer!(i32, "Generates a random `i32` in the given range.");
integer!(u64, "Generates a random `u64` in the given range.");
integer!(i64, "Generates a random `i64` in the given range.");
integer!(u128, "Generates a random `u128` in the given range.");
integer!(i128, "Generates a random `i128` in the given range.");
integer!(usize, "Generates a random `usize` in the given range.");
integer!(isize, "Generates a random `isize` in the given range.");
integer!(char, "Generates a random `char` in the given range.");
/// Generates a random `f32` in range `0..1`.
pub fn f32() -> f32 {
with_rng(|r| r.f32())
}
/// Generates a random `f64` in range `0..1`.
pub fn f64() -> f64 {
with_rng(|r| r.f64())
}
/// Collects `amount` values at random from the iterator into a vector.
pub fn choose_multiple<T: Iterator>(source: T, amount: usize) -> Vec<T::Item> {
with_rng(|rng| rng.choose_multiple(source, amount))
}
#[cfg(not(all(
any(target_arch = "wasm32", target_arch = "wasm64"),
target_os = "unknown"
)))]
fn random_seed() -> Option<u64> {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::thread;
use std::time::Instant;
let mut hasher = DefaultHasher::new();
Instant::now().hash(&mut hasher);
thread::current().id().hash(&mut hasher);
let hash = hasher.finish();
Some((hash << 1) | 1)
}
#[cfg(all(
any(target_arch = "wasm32", target_arch = "wasm64"),
target_os = "unknown",
feature = "js"
))]
fn random_seed() -> Option<u64> {
// TODO(notgull): Failures should be logged somewhere.
let mut seed = [0u8; 8];
getrandom::getrandom(&mut seed).ok()?;
Some(u64::from_ne_bytes(seed))
}
#[cfg(all(
any(target_arch = "wasm32", target_arch = "wasm64"),
target_os = "unknown",
not(feature = "js")
))]
fn random_seed() -> Option<u64> {
None
}

367
third_party/rust/fastrand/src/lib.rs поставляемый
Просмотреть файл

@ -29,6 +29,14 @@
//! let elem = v[i];
//! ```
//!
//! Sample values from an array with `O(n)` complexity (`n` is the length of array):
//!
//! ```
//! fastrand::choose_multiple(vec![1, 4, 5].iter(), 2);
//! fastrand::choose_multiple(0..20, 12);
//! ```
//!
//!
//! Shuffle an array:
//!
//! ```
@ -61,87 +69,88 @@
//! ```
//! use std::iter::repeat_with;
//!
//! let rng = fastrand::Rng::new();
//! let mut rng = fastrand::Rng::new();
//! let mut bytes: Vec<u8> = repeat_with(|| rng.u8(..)).take(10_000).collect();
//! ```
//!
//! # Features
//!
//! - `std` (enabled by default): Enables the `std` library. This is required for the global
//! generator and global entropy. Without this feature, [`Rng`] can only be instantiated using
//! the [`with_seed`](Rng::with_seed) method.
//! - `js`: Assumes that WebAssembly targets are being run in a JavaScript environment. See the
//! [WebAssembly Notes](#webassembly-notes) section for more information.
//!
//! # WebAssembly Notes
//!
//! For non-WASI WASM targets, there is additional sublety to consider when utilizing the global RNG.
//! By default, `std` targets will use entropy sources in the standard library to seed the global RNG.
//! However, these sources are not available by default on WASM targets outside of WASI.
//!
//! If the `js` feature is enabled, this crate will assume that it is running in a JavaScript
//! environment. At this point, the [`getrandom`] crate will be used in order to access the available
//! entropy sources and seed the global RNG. If the `js` feature is not enabled, the global RNG will
//! use a predefined seed.
//!
//! [`getrandom`]: https://crates.io/crates/getrandom
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(unsafe_code)]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
use std::cell::Cell;
use std::collections::hash_map::DefaultHasher;
use std::convert::TryInto;
use std::hash::{Hash, Hasher};
use std::ops::{Bound, RangeBounds};
use std::thread;
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
use instant::Instant;
#[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"))))]
use std::time::Instant;
use core::convert::{TryFrom, TryInto};
use core::ops::{Bound, RangeBounds};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
mod global_rng;
#[cfg(feature = "std")]
pub use global_rng::*;
/// A random number generator.
#[derive(Debug, PartialEq, Eq)]
pub struct Rng(Cell<u64>);
impl Default for Rng {
#[inline]
fn default() -> Rng {
Rng::new()
}
}
pub struct Rng(u64);
impl Clone for Rng {
/// Clones the generator by deterministically deriving a new generator based on the initial
/// seed.
///
/// # Example
///
/// ```
/// // Seed two generators equally, and clone both of them.
/// let base1 = fastrand::Rng::new();
/// base1.seed(0x4d595df4d0f33173);
/// base1.bool(); // Use the generator once.
///
/// let base2 = fastrand::Rng::new();
/// base2.seed(0x4d595df4d0f33173);
/// base2.bool(); // Use the generator once.
///
/// let rng1 = base1.clone();
/// let rng2 = base2.clone();
///
/// assert_eq!(rng1.u64(..), rng2.u64(..), "the cloned generators are identical");
/// ```
/// Clones the generator by creating a new generator with the same seed.
fn clone(&self) -> Rng {
Rng::with_seed(self.gen_u64())
Rng::with_seed(self.0)
}
}
impl Rng {
/// Generates a random `u32`.
#[inline]
fn gen_u32(&self) -> u32 {
fn gen_u32(&mut self) -> u32 {
self.gen_u64() as u32
}
/// Generates a random `u64`.
#[inline]
fn gen_u64(&self) -> u64 {
let s = self.0.get().wrapping_add(0xA0761D6478BD642F);
self.0.set(s);
fn gen_u64(&mut self) -> u64 {
let s = self.0.wrapping_add(0xA0761D6478BD642F);
self.0 = s;
let t = u128::from(s) * u128::from(s ^ 0xE7037ED1A0B428DB);
(t as u64) ^ (t >> 64) as u64
}
/// Generates a random `u128`.
#[inline]
fn gen_u128(&self) -> u128 {
fn gen_u128(&mut self) -> u128 {
(u128::from(self.gen_u64()) << 64) | u128::from(self.gen_u64())
}
/// Generates a random `u32` in `0..n`.
#[inline]
fn gen_mod_u32(&self, n: u32) -> u32 {
fn gen_mod_u32(&mut self, n: u32) -> u32 {
// Adapted from: https://lemire.me/blog/2016/06/30/fast-random-shuffling/
let mut r = self.gen_u32();
let mut hi = mul_high_u32(r, n);
@ -159,7 +168,7 @@ impl Rng {
/// Generates a random `u64` in `0..n`.
#[inline]
fn gen_mod_u64(&self, n: u64) -> u64 {
fn gen_mod_u64(&mut self, n: u64) -> u64 {
// Adapted from: https://lemire.me/blog/2016/06/30/fast-random-shuffling/
let mut r = self.gen_u64();
let mut hi = mul_high_u64(r, n);
@ -177,7 +186,7 @@ impl Rng {
/// Generates a random `u128` in `0..n`.
#[inline]
fn gen_mod_u128(&self, n: u128) -> u128 {
fn gen_mod_u128(&mut self, n: u128) -> u128 {
// Adapted from: https://lemire.me/blog/2016/06/30/fast-random-shuffling/
let mut r = self.gen_u128();
let mut hi = mul_high_u128(r, n);
@ -194,16 +203,6 @@ impl Rng {
}
}
thread_local! {
static RNG: Rng = Rng(Cell::new({
let mut hasher = DefaultHasher::new();
Instant::now().hash(&mut hasher);
thread::current().id().hash(&mut hasher);
let hash = hasher.finish();
(hash << 1) | 1
}));
}
/// Computes `(a * b) >> 32`.
#[inline]
fn mul_high_u32(a: u32, b: u32) -> u32 {
@ -235,7 +234,7 @@ macro_rules! rng_integer {
///
/// Panics if the range is empty.
#[inline]
pub fn $t(&self, range: impl RangeBounds<$t>) -> $t {
pub fn $t(&mut self, range: impl RangeBounds<$t>) -> $t {
let panic_empty_range = || {
panic!(
"empty range: {:?}..{:?}",
@ -245,13 +244,13 @@ macro_rules! rng_integer {
};
let low = match range.start_bound() {
Bound::Unbounded => std::$t::MIN,
Bound::Unbounded => core::$t::MIN,
Bound::Included(&x) => x,
Bound::Excluded(&x) => x.checked_add(1).unwrap_or_else(panic_empty_range),
};
let high = match range.end_bound() {
Bound::Unbounded => std::$t::MAX,
Bound::Unbounded => core::$t::MAX,
Bound::Included(&x) => x,
Bound::Excluded(&x) => x.checked_sub(1).unwrap_or_else(panic_empty_range),
};
@ -260,7 +259,7 @@ macro_rules! rng_integer {
panic_empty_range();
}
if low == std::$t::MIN && high == std::$t::MAX {
if low == core::$t::MIN && high == core::$t::MAX {
self.$gen() as $t
} else {
let len = high.wrapping_sub(low).wrapping_add(1);
@ -271,46 +270,59 @@ macro_rules! rng_integer {
}
impl Rng {
/// Creates a new random number generator.
#[inline]
pub fn new() -> Rng {
Rng::with_seed(
RNG.try_with(|rng| rng.u64(..))
.unwrap_or(0x4d595df4d0f33173),
)
}
/// Creates a new random number generator with the initial seed.
#[inline]
#[must_use = "this creates a new instance of `Rng`; if you want to initialize the thread-local generator, use `fastrand::seed()` instead"]
pub fn with_seed(seed: u64) -> Self {
let rng = Rng(Cell::new(0));
let mut rng = Rng(0);
rng.seed(seed);
rng
}
/// Clones the generator by deterministically deriving a new generator based on the initial
/// seed.
///
/// # Example
///
/// ```
/// // Seed two generators equally, and clone both of them.
/// let mut base1 = fastrand::Rng::new();
/// base1.seed(0x4d595df4d0f33173);
/// base1.bool(); // Use the generator once.
///
/// let mut base2 = fastrand::Rng::new();
/// base2.seed(0x4d595df4d0f33173);
/// base2.bool(); // Use the generator once.
///
/// let mut rng1 = base1.clone();
/// let mut rng2 = base2.clone();
///
/// assert_eq!(rng1.u64(..), rng2.u64(..), "the cloned generators are identical");
/// ```
#[inline]
#[must_use = "this creates a new instance of `Rng`"]
pub fn fork(&mut self) -> Self {
Rng::with_seed(self.gen_u64())
}
/// Generates a random `char` in ranges a-z and A-Z.
#[inline]
pub fn alphabetic(&self) -> char {
pub fn alphabetic(&mut self) -> char {
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
let len = CHARS.len() as u8;
let i = self.u8(..len);
CHARS[i as usize] as char
*self.choice(CHARS).unwrap() as char
}
/// Generates a random `char` in ranges a-z, A-Z and 0-9.
#[inline]
pub fn alphanumeric(&self) -> char {
pub fn alphanumeric(&mut self) -> char {
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let len = CHARS.len() as u8;
let i = self.u8(..len);
CHARS[i as usize] as char
*self.choice(CHARS).unwrap() as char
}
/// Generates a random `bool`.
#[inline]
pub fn bool(&self) -> bool {
pub fn bool(&mut self) -> bool {
self.u8(..) % 2 == 0
}
@ -320,7 +332,7 @@ impl Rng {
///
/// Panics if the base is zero or greater than 36.
#[inline]
pub fn digit(&self, base: u32) -> char {
pub fn digit(&mut self, base: u32) -> char {
if base == 0 {
panic!("base cannot be zero");
}
@ -336,19 +348,57 @@ impl Rng {
}
/// Generates a random `f32` in range `0..1`.
pub fn f32(&self) -> f32 {
pub fn f32(&mut self) -> f32 {
let b = 32;
let f = std::f32::MANTISSA_DIGITS - 1;
let f = core::f32::MANTISSA_DIGITS - 1;
f32::from_bits((1 << (b - 2)) - (1 << f) + (self.u32(..) >> (b - f))) - 1.0
}
/// Generates a random `f64` in range `0..1`.
pub fn f64(&self) -> f64 {
pub fn f64(&mut self) -> f64 {
let b = 64;
let f = std::f64::MANTISSA_DIGITS - 1;
let f = core::f64::MANTISSA_DIGITS - 1;
f64::from_bits((1 << (b - 2)) - (1 << f) + (self.u64(..) >> (b - f))) - 1.0
}
/// Collects `amount` values at random from the iterator into a vector.
///
/// The length of the returned vector equals `amount` unless the iterator
/// contains insufficient elements, in which case it equals the number of
/// elements available.
///
/// Complexity is `O(n)` where `n` is the length of the iterator.
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn choose_multiple<T: Iterator>(&mut self, mut source: T, amount: usize) -> Vec<T::Item> {
// Adapted from: https://docs.rs/rand/latest/rand/seq/trait.IteratorRandom.html#method.choose_multiple
let mut reservoir = Vec::with_capacity(amount);
reservoir.extend(source.by_ref().take(amount));
// Continue unless the iterator was exhausted
//
// note: this prevents iterators that "restart" from causing problems.
// If the iterator stops once, then so do we.
if reservoir.len() == amount {
for (i, elem) in source.enumerate() {
let end = i + 1 + amount;
let k = self.usize(0..end);
if let Some(slot) = reservoir.get_mut(k) {
*slot = elem;
}
}
} else {
// If less than one third of the `Vec` was used, reallocate
// so that the unused space is not wasted. There is a corner
// case where `amount` was much less than `self.len()`.
if reservoir.capacity() > 3 * reservoir.len() {
reservoir.shrink_to_fit();
}
}
reservoir
}
rng_integer!(
i8,
u8,
@ -416,28 +466,49 @@ impl Rng {
/// Generates a random `char` in range a-z.
#[inline]
pub fn lowercase(&self) -> char {
pub fn lowercase(&mut self) -> char {
const CHARS: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
let len = CHARS.len() as u8;
let i = self.u8(..len);
CHARS[i as usize] as char
*self.choice(CHARS).unwrap() as char
}
/// Initializes this generator with the given seed.
#[inline]
pub fn seed(&self, seed: u64) {
self.0.set(seed);
pub fn seed(&mut self, seed: u64) {
self.0 = seed;
}
/// Gives back **current** seed that is being held by this generator.
#[inline]
pub fn get_seed(&self) -> u64 {
self.0.get()
self.0
}
/// Choose an item from an iterator at random.
///
/// This function may have an unexpected result if the `len()` property of the
/// iterator does not match the actual number of items in the iterator. If
/// the iterator is empty, this returns `None`.
#[inline]
pub fn choice<I>(&mut self, iter: I) -> Option<I::Item>
where
I: IntoIterator,
I::IntoIter: ExactSizeIterator,
{
let mut iter = iter.into_iter();
// Get the item at a random index.
let len = iter.len();
if len == 0 {
return None;
}
let index = self.usize(0..len);
iter.nth(index)
}
/// Shuffles a slice randomly.
#[inline]
pub fn shuffle<T>(&self, slice: &mut [T]) {
pub fn shuffle<T>(&mut self, slice: &mut [T]) {
for i in 1..slice.len() {
slice.swap(i, self.usize(..=i));
}
@ -445,7 +516,7 @@ impl Rng {
/// Fill a byte slice with random data.
#[inline]
pub fn fill(&self, slice: &mut [u8]) {
pub fn fill(&mut self, slice: &mut [u8]) {
// We fill the slice by chunks of 8 bytes, or one block of
// WyRand output per new state.
let mut chunks = slice.chunks_exact_mut(core::mem::size_of::<u64>());
@ -542,20 +613,16 @@ impl Rng {
/// Generates a random `char` in range A-Z.
#[inline]
pub fn uppercase(&self) -> char {
pub fn uppercase(&mut self) -> char {
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
let len = CHARS.len() as u8;
let i = self.u8(..len);
CHARS[i as usize] as char
*self.choice(CHARS).unwrap() as char
}
/// Generates a random `char` in the given range.
///
/// Panics if the range is empty.
#[inline]
pub fn char(&self, range: impl RangeBounds<char>) -> char {
use std::convert::TryFrom;
pub fn char(&mut self, range: impl RangeBounds<char>) -> char {
let panic_empty_range = || {
panic!(
"empty range: {:?}..{:?}",
@ -581,7 +648,7 @@ impl Rng {
};
let high = match range.end_bound() {
Bound::Unbounded => std::char::MAX,
Bound::Unbounded => core::char::MAX,
Bound::Included(&x) => x,
Bound::Excluded(&x) => {
let scalar = if x as u32 == surrogate_start + surrogate_len {
@ -610,97 +677,3 @@ impl Rng {
val.try_into().unwrap()
}
}
/// Initializes the thread-local generator with the given seed.
#[inline]
pub fn seed(seed: u64) {
RNG.with(|rng| rng.seed(seed))
}
/// Gives back **current** seed that is being held by the thread-local generator.
#[inline]
pub fn get_seed() -> u64 {
RNG.with(|rng| rng.get_seed())
}
/// Generates a random `bool`.
#[inline]
pub fn bool() -> bool {
RNG.with(|rng| rng.bool())
}
/// Generates a random `char` in ranges a-z and A-Z.
#[inline]
pub fn alphabetic() -> char {
RNG.with(|rng| rng.alphabetic())
}
/// Generates a random `char` in ranges a-z, A-Z and 0-9.
#[inline]
pub fn alphanumeric() -> char {
RNG.with(|rng| rng.alphanumeric())
}
/// Generates a random `char` in range a-z.
#[inline]
pub fn lowercase() -> char {
RNG.with(|rng| rng.lowercase())
}
/// Generates a random `char` in range A-Z.
#[inline]
pub fn uppercase() -> char {
RNG.with(|rng| rng.uppercase())
}
/// Generates a random digit in the given `base`.
///
/// Digits are represented by `char`s in ranges 0-9 and a-z.
///
/// Panics if the base is zero or greater than 36.
#[inline]
pub fn digit(base: u32) -> char {
RNG.with(|rng| rng.digit(base))
}
/// Shuffles a slice randomly.
#[inline]
pub fn shuffle<T>(slice: &mut [T]) {
RNG.with(|rng| rng.shuffle(slice))
}
macro_rules! integer {
($t:tt, $doc:tt) => {
#[doc = $doc]
///
/// Panics if the range is empty.
#[inline]
pub fn $t(range: impl RangeBounds<$t>) -> $t {
RNG.with(|rng| rng.$t(range))
}
};
}
integer!(u8, "Generates a random `u8` in the given range.");
integer!(i8, "Generates a random `i8` in the given range.");
integer!(u16, "Generates a random `u16` in the given range.");
integer!(i16, "Generates a random `i16` in the given range.");
integer!(u32, "Generates a random `u32` in the given range.");
integer!(i32, "Generates a random `i32` in the given range.");
integer!(u64, "Generates a random `u64` in the given range.");
integer!(i64, "Generates a random `i64` in the given range.");
integer!(u128, "Generates a random `u128` in the given range.");
integer!(i128, "Generates a random `i128` in the given range.");
integer!(usize, "Generates a random `usize` in the given range.");
integer!(isize, "Generates a random `isize` in the given range.");
integer!(char, "Generates a random `char` in the given range.");
/// Generates a random `f32` in range `0..1`.
pub fn f32() -> f32 {
RNG.with(|rng| rng.f32())
}
/// Generates a random `f64` in range `0..1`.
pub fn f64() -> f64 {
RNG.with(|rng| rng.f64())
}

35
third_party/rust/fastrand/tests/smoke.rs поставляемый
Просмотреть файл

@ -77,7 +77,7 @@ fn u128() {
#[test]
fn fill() {
let r = fastrand::Rng::new();
let mut r = fastrand::Rng::new();
let mut a = [0u8; 64];
let mut b = [0u8; 64];
@ -89,7 +89,7 @@ fn fill() {
#[test]
fn rng() {
let r = fastrand::Rng::new();
let mut r = fastrand::Rng::new();
assert_ne!(r.u64(..), r.u64(..));
@ -102,8 +102,8 @@ fn rng() {
#[test]
fn rng_init() {
let a = fastrand::Rng::new();
let b = fastrand::Rng::new();
let mut a = fastrand::Rng::new();
let mut b = fastrand::Rng::new();
assert_ne!(a.u64(..), b.u64(..));
a.seed(7);
@ -113,8 +113,31 @@ fn rng_init() {
#[test]
fn with_seed() {
let a = fastrand::Rng::with_seed(7);
let b = fastrand::Rng::new();
let mut a = fastrand::Rng::with_seed(7);
let mut b = fastrand::Rng::new();
b.seed(7);
assert_eq!(a.u64(..), b.u64(..));
}
#[test]
fn choose_multiple() {
let mut a = fastrand::Rng::new();
let mut elements = (0..20).collect::<Vec<_>>();
while !elements.is_empty() {
let chosen = a.choose_multiple(0..20, 5);
for &x in &chosen {
elements.retain(|&y| y != x);
}
}
}
#[test]
fn choice() {
let items = [1, 4, 9, 5, 2, 3, 6, 7, 8, 0];
let mut r = fastrand::Rng::new();
for item in &items {
while r.choice(&items).unwrap() != item {}
}
}

Просмотреть файл

@ -1 +0,0 @@
{"files":{"AUTHORS":"451a1be16acafff0cb0eaedc49b46063cc6ce087d0c36f6d64d67aa93d20e485","CHANGELOGS.md":"bb587c08dd9b1f04cba934a241a99655f9d7e38bc70e4d45feca95efa09bd799","Cargo.toml":"a64c7ab3a5906d2e7360fb30cc23e5042bd7c22aa640e8e47bb3dad1a3dbf8eb","LICENSE":"2510d4cde8c4e13d8c54b9fe2a9d144daf567ec8d02832f1454e7ca2d58cdda6","README.md":"22b54b9f16ad18144f29e50d1b1f16791c5e8f1afee81265bad9b72f6efb8e62","src/lib.rs":"cc4822f1c4ac7926859045608d91e3f855914468039bffb75bc9b455c0950ab3","src/native.rs":"bd4cd1f888b83a9eaf07f640bef51c4f16138ceb427a685d3ab07152eec53d1c","src/wasm.rs":"c17c7bf8a28fee134444201212d1cf62bff49650f297e42367ec1b7aeaddc7c9","tests/wasm.rs":"1b81ff541bec36bac824a7ec41cd15f68d9919c3c7522290aa003fa4c253e840"},"package":"7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"}

2
third_party/rust/instant/AUTHORS поставляемый
Просмотреть файл

@ -1,2 +0,0 @@
Main developer:
* Sébastien Crozet <developer@crozet.re>

7
third_party/rust/instant/CHANGELOGS.md поставляемый
Просмотреть файл

@ -1,7 +0,0 @@
# v0.1.12
## Added
- Add `SystemTime` which works in both native and WASM environments.
## Modified
- The `now` function is always available now: there is no need to enable the `now` feature any more. The `now` feature
still exists (but doesnt do anything) for backwards compatibility.

81
third_party/rust/instant/Cargo.toml поставляемый
Просмотреть файл

@ -1,81 +0,0 @@
# 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 are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "instant"
version = "0.1.12"
authors = ["sebcrozet <developer@crozet.re>"]
description = "A partial replacement for std::time::Instant that works on WASM too."
readme = "README.md"
keywords = ["time", "wasm"]
license = "BSD-3-Clause"
repository = "https://github.com/sebcrozet/instant"
[dependencies.cfg-if]
version = "1.0"
[dev-dependencies.wasm-bindgen-test]
version = "0.3"
[features]
inaccurate = []
now = []
wasm-bindgen = ["js-sys", "wasm-bindgen_rs", "web-sys"]
[target.asmjs-unknown-emscripten.dependencies.js-sys]
version = "0.3"
optional = true
[target.asmjs-unknown-emscripten.dependencies.stdweb]
version = "0.4"
optional = true
[target.asmjs-unknown-emscripten.dependencies.wasm-bindgen_rs]
version = "0.2"
optional = true
package = "wasm-bindgen"
[target.asmjs-unknown-emscripten.dependencies.web-sys]
version = "0.3"
features = ["Window", "Performance", "PerformanceTiming"]
optional = true
[target.wasm32-unknown-emscripten.dependencies.js-sys]
version = "0.3"
optional = true
[target.wasm32-unknown-emscripten.dependencies.stdweb]
version = "0.4"
optional = true
[target.wasm32-unknown-emscripten.dependencies.wasm-bindgen_rs]
version = "0.2"
optional = true
package = "wasm-bindgen"
[target.wasm32-unknown-emscripten.dependencies.web-sys]
version = "0.3"
features = ["Window", "Performance", "PerformanceTiming"]
optional = true
[target.wasm32-unknown-unknown.dependencies.js-sys]
version = "0.3"
optional = true
[target.wasm32-unknown-unknown.dependencies.stdweb]
version = "0.4"
optional = true
[target.wasm32-unknown-unknown.dependencies.wasm-bindgen_rs]
version = "0.2"
optional = true
package = "wasm-bindgen"
[target.wasm32-unknown-unknown.dependencies.web-sys]
version = "0.3"
features = ["Window", "Performance", "PerformanceTiming"]
optional = true

27
third_party/rust/instant/LICENSE поставляемый
Просмотреть файл

@ -1,27 +0,0 @@
Copyright (c) 2019, Sébastien Crozet
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the author nor the names of its contributors may be used
to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

143
third_party/rust/instant/README.md поставляемый
Просмотреть файл

@ -1,143 +0,0 @@
# Instant
If you call `std::time::Instant::now()` on a WASM platform, it will panic. This crate provides a partial
replacement for `std::time::Instant` that works on WASM too. This defines the type `instant::Instant` which is:
* A struct emulating the behavior of **std::time::Instant** if you are targeting `wasm32-unknown-unknown` or `wasm32-unknown-asmjs`
**and** you enabled either the `stdweb` or the `wasm-bindgen` feature. This emulation is based on the javascript `performance.now()` function.
* A type alias for `std::time::Instant` otherwise.
Note that even if the **stdweb** or **wasm-bindgen** feature is enabled, this crate will continue to rely on `std::time::Instant`
as long as you are not targeting wasm32. This allows for portable code that will work on both native and WASM platforms.
This crate also exports the function `instant::now()` which returns a representation of the current time as an `f64`, expressed in milliseconds, in a platform-agnostic way. `instant::now()` will either:
* Call `performance.now()` when compiling for a WASM platform with the features **stdweb** or **wasm-bindgen** enabled, or using a custom javascript function.
* Return the time elapsed since the *Unix Epoch* on *native*, *non-WASM* platforms.
*Note*: The old feature, `now`, has been deprecated. `instant::now()` is always exported and the `now` feature flag no longer has any effect. It remains listed in `Cargo.toml` to avoid introducing breaking changes and may be removed in future versions.
## Examples
### Using `instant` for a native platform.
_Cargo.toml_:
```toml
[dependencies]
instant = "0.1"
```
_main.rs_:
```rust
fn main() {
// Will be the same as `std::time::Instant`.
let now = instant::Instant::now();
}
```
-----
### Using `instant` for a WASM platform.
This example shows the use of the `stdweb` feature. It would be similar with `wasm-bindgen`.
_Cargo.toml_:
```toml
[dependencies]
instant = { version = "0.1", features = [ "stdweb" ] }
```
_main.rs_:
```rust
fn main() {
// Will emulate `std::time::Instant` based on `performance.now()`.
let now = instant::Instant::now();
}
```
-----
### Using `instant` for a WASM platform where `performance.now()` is not available.
This example shows the use of the `inaccurate` feature.
_Cargo.toml_:
```toml
[dependencies]
instant = { version = "0.1", features = [ "wasm-bindgen", "inaccurate" ] }
```
_main.rs_:
```rust
fn main() {
// Will emulate `std::time::Instant` based on `Date.now()`.
let now = instant::Instant::now();
}
```
-----
### Using `instant` for any platform enabling a feature transitively.
_Cargo.toml_:
```toml
[features]
stdweb = [ "instant/stdweb" ]
wasm-bindgen = [ "instant/wasm-bindgen" ]
[dependencies]
instant = "0.1"
```
_lib.rs_:
```rust
fn my_function() {
// Will select the proper implementation depending on the
// feature selected by the user.
let now = instant::Instant::now();
}
```
-----
### Using `instant::now()`
_Cargo.toml_:
```toml
[features]
stdweb = [ "instant/stdweb" ]
wasm-bindgen = [ "instant/wasm-bindgen" ]
[dependencies]
instant = "0.1"
```
_lib.rs_:
```rust
fn my_function() {
// Will select the proper implementation depending on the
// feature selected by the user.
let now_instant = instant::Instant::now();
let now_milliseconds = instant::now(); // In milliseconds.
}
```
### Using the feature `now` without `stdweb` or `wasm-bindgen`.
_Cargo.toml_:
```toml
[dependencies]
instant = "0.1"
```
_lib.rs_:
```rust
fn my_function() {
// Will use the 'now' javascript implementation.
let now_instant = instant::Instant::now();
let now_milliseconds = instant::now(); // In milliseconds.
}
```
_javascript WASM bindings file_:
```js
function now() {
return Date.now() / 1000.0;
}
```

22
third_party/rust/instant/src/lib.rs поставляемый
Просмотреть файл

@ -1,22 +0,0 @@
cfg_if::cfg_if! {
if #[cfg(any(
all(target_arch = "wasm32", not(target_os = "wasi")),
target_arch = "asmjs"
))] {
#[cfg(all(feature = "stdweb", not(feature = "wasm-bindgen")))]
#[macro_use]
extern crate stdweb;
mod wasm;
pub use wasm::Instant;
pub use crate::wasm::now;
pub use wasm::SystemTime;
} else {
mod native;
pub use native::Instant;
pub use native::now;
pub use native::SystemTime;
}
}
pub use std::time::Duration;

9
third_party/rust/instant/src/native.rs поставляемый
Просмотреть файл

@ -1,9 +0,0 @@
pub type Instant = std::time::Instant;
pub type SystemTime = std::time::SystemTime;
/// The current time, expressed in milliseconds since the Unix Epoch.
pub fn now() -> f64 {
std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH)
.expect("System clock was before 1970.")
.as_secs_f64() * 1000.0
}

240
third_party/rust/instant/src/wasm.rs поставляемый
Просмотреть файл

@ -1,240 +0,0 @@
use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::time::Duration;
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
pub struct Instant(Duration);
impl Ord for Instant {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other)
.expect("an instant should never be NaN or Inf.")
}
}
impl Eq for Instant {}
impl Instant {
#[inline]
pub fn now() -> Self {
Instant(duration_from_f64(now()))
}
#[inline]
pub fn duration_since(&self, earlier: Instant) -> Duration {
assert!(
earlier.0 <= self.0,
"`earlier` cannot be later than `self`."
);
self.0 - earlier.0
}
#[inline]
pub fn elapsed(&self) -> Duration {
Self::now().duration_since(*self)
}
/// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
/// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
/// otherwise.
#[inline]
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
self.0.checked_add(duration).map(Instant)
}
/// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
/// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
/// otherwise.
#[inline]
pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
self.0.checked_sub(duration).map(Instant)
}
/// Returns the amount of time elapsed from another instant to this one, or None if that
/// instant is later than this one.
#[inline]
pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
if earlier.0 > self.0 {
None
} else {
Some(self.0 - earlier.0)
}
}
/// Returns the amount of time elapsed from another instant to this one, or zero duration if
/// that instant is later than this one.
#[inline]
pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
self.checked_duration_since(earlier).unwrap_or_default()
}
}
impl Add<Duration> for Instant {
type Output = Self;
#[inline]
fn add(self, rhs: Duration) -> Self {
Instant(self.0 + rhs)
}
}
impl AddAssign<Duration> for Instant {
#[inline]
fn add_assign(&mut self, rhs: Duration) {
self.0 += rhs
}
}
impl Sub<Duration> for Instant {
type Output = Self;
#[inline]
fn sub(self, rhs: Duration) -> Self {
Instant(self.0 - rhs)
}
}
impl Sub<Instant> for Instant {
type Output = Duration;
#[inline]
fn sub(self, rhs: Instant) -> Duration {
self.duration_since(rhs)
}
}
impl SubAssign<Duration> for Instant {
#[inline]
fn sub_assign(&mut self, rhs: Duration) {
self.0 -= rhs
}
}
fn duration_from_f64(millis: f64) -> Duration {
Duration::from_millis(millis.trunc() as u64)
+ Duration::from_nanos((millis.fract() * 1.0e6) as u64)
}
#[cfg(all(feature = "stdweb", not(feature = "wasm-bindgen")))]
#[allow(unused_results)] // Needed because the js macro triggers it.
pub fn now() -> f64 {
use stdweb::unstable::TryInto;
// https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
#[cfg(not(feature = "inaccurate"))]
let v = js! { return performance.now(); };
#[cfg(feature = "inaccurate")]
let v = js! { return Date.now(); };
v.try_into().unwrap()
}
#[cfg(feature = "wasm-bindgen")]
pub fn now() -> f64 {
#[cfg(not(feature = "inaccurate"))]
let now = {
use wasm_bindgen_rs::prelude::*;
use wasm_bindgen_rs::JsCast;
js_sys::Reflect::get(&js_sys::global(), &JsValue::from_str("performance"))
.expect("failed to get performance from global object")
.unchecked_into::<web_sys::Performance>()
.now()
};
#[cfg(feature = "inaccurate")]
let now = js_sys::Date::now();
now
}
// The JS now function is in a module so it won't have to be renamed
#[cfg(not(any(feature = "wasm-bindgen", feature = "stdweb")))]
mod js {
extern "C" {
#[cfg(not(target_os = "emscripten"))]
pub fn now() -> f64;
#[cfg(target_os = "emscripten")]
pub fn _emscripten_get_now() -> f64;
}
}
// Make the unsafe extern function "safe" so it can be called like the other 'now' functions
#[cfg(not(any(feature = "wasm-bindgen", feature = "stdweb")))]
pub fn now() -> f64 {
#[cfg(not(target_os = "emscripten"))]
return unsafe { js::now() };
#[cfg(target_os = "emscripten")]
return unsafe { js::_emscripten_get_now() };
}
/// Returns the number of millisecods elapsed since January 1, 1970 00:00:00 UTC.
#[cfg(any(feature = "wasm-bindgen", feature = "stdweb"))]
fn get_time() -> f64 {
#[cfg(feature = "wasm-bindgen")]
return js_sys::Date::now();
#[cfg(all(feature = "stdweb", not(feature = "wasm-bindgen")))]
{
let v = js! { return Date.now(); };
return v.try_into().unwrap();
}
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct SystemTime(f64);
impl SystemTime {
pub const UNIX_EPOCH: SystemTime = SystemTime(0.0);
pub fn now() -> SystemTime {
cfg_if::cfg_if! {
if #[cfg(any(feature = "wasm-bindgen", feature = "stdweb"))] {
SystemTime(get_time())
} else {
SystemTime(now())
}
}
}
pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, ()> {
let dur_ms = self.0 - earlier.0;
if dur_ms < 0.0 {
return Err(());
}
Ok(Duration::from_millis(dur_ms as u64))
}
pub fn elapsed(&self) -> Result<Duration, ()> {
self.duration_since(SystemTime::now())
}
pub fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
Some(*self + duration)
}
pub fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
Some(*self - duration)
}
}
impl Add<Duration> for SystemTime {
type Output = SystemTime;
fn add(self, other: Duration) -> SystemTime {
SystemTime(self.0 + other.as_millis() as f64)
}
}
impl Sub<Duration> for SystemTime {
type Output = SystemTime;
fn sub(self, other: Duration) -> SystemTime {
SystemTime(self.0 - other.as_millis() as f64)
}
}
impl AddAssign<Duration> for SystemTime {
fn add_assign(&mut self, rhs: Duration) {
*self = *self + rhs;
}
}
impl SubAssign<Duration> for SystemTime {
fn sub_assign(&mut self, rhs: Duration) {
*self = *self - rhs;
}
}

57
third_party/rust/instant/tests/wasm.rs поставляемый
Просмотреть файл

@ -1,57 +0,0 @@
extern crate wasm_bindgen_test;
use instant::{Instant, SystemTime};
use std::time::Duration;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
// run these tests using: wasm-pack test --chrome --headless -- --features wasm-bindgen
#[wasm_bindgen_test]
fn test_instant_now() {
let now = Instant::now();
#[cfg(feature = "inaccurate")]
while now.elapsed().as_millis() == 0 {}
#[cfg(not(feature = "inaccurate"))]
assert!(now.elapsed().as_nanos() > 0);
}
#[wasm_bindgen_test]
fn test_duration() {
let now = Instant::now();
let one_sec = Duration::from_secs(1);
assert!(now.elapsed() < one_sec);
}
// Duration::new will overflow when you have u64::MAX seconds and one billion nanoseconds.
// <https://doc.rust-lang.org/std/time/struct.Duration.html#method.new>
const ONE_BILLION: u32 = 1_000_000_000;
#[wasm_bindgen_test]
fn test_checked_add() {
let now = Instant::now();
assert!(now.checked_add(Duration::from_millis(1)).is_some());
assert_eq!(
None,
now.checked_add(Duration::new(u64::MAX, ONE_BILLION - 1))
);
}
#[wasm_bindgen_test]
fn test_checked_sub() {
let now = Instant::now();
assert!(now.checked_sub(Duration::from_millis(1)).is_some());
assert!(now
.checked_sub(Duration::new(u64::MAX, ONE_BILLION - 1))
.is_none());
}
#[wasm_bindgen_test]
fn test_system_time() {
assert!(SystemTime::UNIX_EPOCH
.duration_since(SystemTime::now())
.is_err());
}

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"685243e302f6e014de9c8e9b95596e5f63c7bf7fde42e8e66a41a6bc7fd5e803","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36","NEWS":"4255c86ac140a4d08423cd05cbd0aa42ff796bb4b38579dd19cde289ee3baecd","README.md":"db6717cbd0b3cbbce5f3cdb8a80d8f2d90b1be251b4c1c647557ae0f78ec9748","src/dir.rs":"4499ff439b740f8d2f01458664e2bf72bbfdd1206226780c6a91fb309ef15707","src/error.rs":"cc7d8eace0fff11cb342158d2885d5637bfb14b24ef30755e808554772039c5f","src/file/imp/mod.rs":"f6da9fcd93f11889670a251fdd8231b5f4614e5a971b7b183f52b44af68568d5","src/file/imp/other.rs":"99c8f9f3251199fc31e7b88810134712e5725fb6fa14648696ed5cbea980fc5b","src/file/imp/unix.rs":"cf8eeceecfddc37c9eaf95a1ebe088314dc468f07fe357961d80817eef619ca4","src/file/imp/windows.rs":"03d81d71c404f0d448e1162825d6fbd57a78b4af8d4dc5287ec2e7c5a873d7cc","src/file/mod.rs":"bda4ee3998106089a4c0ccbc8e46dc22b7d3aec427487fd4e414fb132b378736","src/lib.rs":"e2b0df7e17cc6680a5bb0829d0433f069c6bf9eede2007d21e3b01a595df41a8","src/spooled.rs":"51fa1d7639027234e257d343a5d3c95f2e47899ba6a24f0abec8d4d729eba6d6","src/util.rs":"2bd80ee69009e7e36b596d0105bb00184cff04e899e9fcce2e4cc21f23dda073","tests/namedtempfile.rs":"0031cb33ae6faf45be103869b4d98af63bef4040dc489b323212eb7a7ef72a9a","tests/spooled.rs":"29e797d486d867cb6ac46d4cf126eb5868a069a4070c3f50ffa02fbb0b887934","tests/tempdir.rs":"771d555d4eaa410207d212eb3744e016e0b5a22f1f1b7199636a4fac5daaf952","tests/tempfile.rs":"92078a1e20a39af77c1daa9a422345d20c41584dd2010b4829911c8741d1c628"},"package":"5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"}
{"files":{"CHANGELOG.md":"14cb935001b72d1da431865d0e618b58ca962cc17c8be6bcd9cf4e1699f58b7d","Cargo.toml":"285d4565218bd4a8e5d36cb9b12ece4b8bb9c91d3357e75708acb0ca2f414b49","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36","README.md":"972f1c35ec653943e067fd2c3d09e78f593b2e9e1eafd5b9668bf3653513de3e","src/dir.rs":"3b515f42feb934ba83ba56d506116e5e932c6b863b764fd61d26994eff28700a","src/error.rs":"cc7d8eace0fff11cb342158d2885d5637bfb14b24ef30755e808554772039c5f","src/file/imp/mod.rs":"f6da9fcd93f11889670a251fdd8231b5f4614e5a971b7b183f52b44af68568d5","src/file/imp/other.rs":"501cd1b444a5821127ea831fc8018706148f2d9f47c478f502b069963a42a2c7","src/file/imp/unix.rs":"0fa63a8b831947fdc7307e889d129adef6f47b19965b963a5e25d70cb3106e62","src/file/imp/windows.rs":"fa4211087c36290064de9a41b5e533e4e8c24a10fb8f8908835a67e00555c06e","src/file/mod.rs":"f417e0e8637116e50de201581b1dfe8feb8dee30f71c5bb9dbcd95603094cb49","src/lib.rs":"6303e7470c680ad785f32eb717de2e512b88c2c5da0e1684e3704471fabd7398","src/spooled.rs":"de848218bb7c0733d9c46e337564137673c95f5a6cf9f6bb28baf218b2503247","src/util.rs":"63737b9180cb769c1fcac56f1fa928221ae41a8917872d3e878d0a915e877710","tests/namedtempfile.rs":"87dd6a8bba2fdd77418ec2b50b8aec5e26d05a2f780182b4e9ff464b3404d47c","tests/spooled.rs":"a97e96404dc5136421ac027b965070c0d5b44c93d06d456e12dc85f81755d064","tests/tempdir.rs":"f5a86f56df6bb60aa5dfa136ce75f8d0f29c2e87546dccfe1fb680d209be525e","tests/tempfile.rs":"9a2f8142151a6aa2fd047aa3749f9982ece4b080a3ace0d3c58d6bdb3f883c81"},"package":"cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"}

256
third_party/rust/tempfile/CHANGELOG.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,256 @@
# Changelog
## 3.8.0
- Added `with_prefix` and `with_prefix_in` to `TempDir` and `NamedTempFile` to make it easier to create temporary files/directories with nice prefixes.
- Misc cleanups.
## 3.7.1
- Tempfile builds on haiku again.
- Under the hood, we've switched from the unlinkat/linkat syscalls to the regular unlink/link syscalls where possible.
## 3.7.0
BREAKING: This release updates the MSRV to 1.63. This isn't an API-breaking change (so no major
release) but it's still a breaking change for some users.
- Update fastrand from 1.6 to 2.0
- Update rustix to 0.38
- Updates the MSRV to 1.63.
- Provide AsFd/AsRawFd on wasi.
## 3.6.0
- Update windows-sys to 0.48.
- Update rustix min version to 0.37.11
- Forward some `NamedTempFile` and `SpooledTempFile` methods to the underlying `File` object for
better performance (especially vectorized writes, etc.).
- Implement `AsFd` and `AsHandle`.
- Misc documentation fixes and code cleanups.
## 3.5.0
- Update rustix from 0.36 to 0.37.1. This makes wasi work on rust stable
- Update `windows-sys`, `redox_syscall`
- BREAKING: Remove the implementation of `Write for &NamedTempFile<F> where &F: Write`. Unfortunately, this can cause compile issues in unrelated code (https://github.com/Stebalien/tempfile/issues/224).
## 3.4.0
SECURITY: Prior `tempfile` releases depended on `remove_dir_all` version 0.5.0 which was vulnerable to a [TOCTOU race](https://github.com/XAMPPRocky/remove_dir_all/security/advisories/GHSA-mc8h-8q98-g5hr). This same race is present in rust versions prior to 1.58.1.
Features:
- Generalized temporary files: `NamedTempFile` can now abstract over different kinds of files (e.g.,
unix domain sockets, pipes, etc.):
- Add `Builder::make` and `Builder::make_in` for generalized temp file
creation.
- Add `NamedTempFile::from_parts` to complement `NamedTempFile::into_parts`.
- Add generic parameter to `NamedTempFile` to support wrapping non-File types.
Bug Fixes/Improvements:
- Don't try to create a temporary file multiple times if the file path has been fully specified by
the user (no random characters).
- `NamedTempFile::persist_noclobber` is now always atomic on linux when `renameat_with` is
supported. Previously, it would first link the new path, then unlink the previous path.
- Fix compiler warnings on windows.
Trivia:
- Switch from `libc` to `rustix` on wasi/unix. This now makes direct syscalls instead of calling
through libc.
- Remove `remove_dir_all` dependency. The rust standard library has optimized their internal version
significantly.
- Switch to official windows-sys windows bindings.
Breaking:
- The minimum rust version is now `1.48.0`.
- Mark most functions as `must_use`.
- Uses direct syscalls on linux by default, instead of libc.
- The new type parameter in `NamedTempFile` may lead to type inference issues in some cases.
## 3.3.0
Features:
- Replace rand with fastrand for a significantly smaller dependency tree. Cryptographic randomness
isn't necessary for temporary file names, and isn't all that helpful either.
- Add limited WASI support.
- Add a function to extract the inner data from a `SpooledTempFile`.
Bug Fixes:
- Make it possible to persist unnamed temporary files on linux by removing the `O_EXCL` flag.
- Fix redox minimum crate version.
## 3.2.0
Features:
- Bump rand dependency to `0.8`.
- Bump cfg-if dependency to `1.0`
Other than that, this release mostly includes small cleanups and simplifications.
Breaking: The minimum rust version is now `1.40.0`.
## 3.1.0
Features:
- Bump rand dependency to `0.7`.
Breaking: The minimum rust version is now `1.32.0`.
## 3.0.9
Documentation:
- Add an example for reopening a named temporary file.
- Flesh out the security documentation.
Features:
- Introduce an `append` option to the builder.
- Errors:
- No longer implement the soft-deprecated `description`.
- Implement `source` instead of `cause`.
Breaking: The minimum rust version is now 1.30.
## 3.0.8
This is a bugfix release.
Fixes:
- Export `PathPersistError`.
- Fix a bug where flushing a `SpooledTempFile` to disk could fail to write part
of the file in some rare, yet-to-reproduced cases.
## 3.0.7
Breaking:
- `Builder::prefix` and `Builder::suffix` now accept a generic `&AsRef<OsStr>`.
This could affect type inference.
- Temporary files (except unnamed temporary files on Windows and Linux >= 3.11)
now use absolute path names. This will break programs that create temporary
files relative to their current working directory when they don't have the
search permission (x) on some ancestor directory. This is only likely to
affect programs with strange chroot-less filesystem sandboxes. If you believe
you're affected by this issue, please comment on #40.
Features:
- Accept anything implementing `&AsRef<OsStr>` in the builder: &OsStr, &OsString, &Path, etc.
Fixes:
- Fix LFS support.
- Use absolute paths for named temporary files to guard against changes in the
current directory.
- Use absolute paths when creating unnamed temporary files on platforms that
can't create unlinked or auto-deleted temporary files. This fixes a very
unlikely race where the current directory could change while the temporary
file is being created.
Misc:
- Use modern stdlib features to avoid custom unsafe code. This reduces the
number of unsafe blocks from 12 to 4.
## 3.0.6
- Don't hide temporary files on windows, fixing #66 and #69.
## 3.0.5
Features:
- Added a spooled temporary file implementation. This temporary file variant
starts out as an in-memory temporary file but "rolls-over" onto disk when it
grows over a specified size (#68).
- Errors are now annotated with paths to make debugging easier (#73).
Misc:
- The rand version has been bumped to 0.6 (#74).
Bugs:
- Tempfile compiles again on Redox (#75).
## 3.0.4
- Now compiles on unsupported platforms.
## 3.0.3
- update rand to 0.5
## 3.0.2
- Actually *delete* temporary files on non-Linux unix systems (thanks to
@oliverhenshaw for the fix and a test case).
## 3.0.1
- Restore NamedTempFile::new_in
## 3.0.0
- Adds temporary directory support (@KodrAus)
- Allow closing named temporary files without deleting them (@jasonwhite)
## 2.2.0
- Redox Support
## 2.1.6
- Remove build script and bump minimum rustc version to 1.9.0
## 2.1.5
- Don't build platform-specific dependencies on all platforms.
- Cleanup some documentation.
## 2.1.4
- Fix crates.io tags. No interesting changes.
## 2.1.3
Export `PersistError`.
## 2.1.2
Add `Read`/`Write`/`Seek` impls on `&NamedTempFile`. This mirrors the
implementations on `&File`. One can currently just deref to a `&File` but these
implementations are more discoverable.
## 2.1.1
Add LFS Support.
## 2.1.0
- Implement `AsRef<File>` for `NamedTempFile` allowing named temporary files to
be borrowed as `File`s.
- Add a method to convert a `NamedTempFile` to an unnamed temporary `File`.
## 2.0.1
- Arm bugfix
## 2.0.0
This release replaces `TempFile` with a `tempfile()` function that returns
`std::fs::File` objects. These are significantly more useful because most rust
libraries expect normal `File` objects.
To continue supporting shared temporary files, this new version adds a
`reopen()` method to `NamedTempFile`.

42
third_party/rust/tempfile/Cargo.toml поставляемый
Просмотреть файл

@ -11,33 +11,49 @@
[package]
edition = "2018"
rust-version = "1.63"
name = "tempfile"
version = "3.3.0"
authors = ["Steven Allen <steven@stebalien.com>", "The Rust Project Developers", "Ashley Mannix <ashleymannix@live.com.au>", "Jason White <jasonaw0@gmail.com>"]
exclude = ["/.travis.yml", "/appveyor.yml"]
version = "3.8.0"
authors = [
"Steven Allen <steven@stebalien.com>",
"The Rust Project Developers",
"Ashley Mannix <ashleymannix@live.com.au>",
"Jason White <me@jasonwhite.io>",
]
description = "A library for managing temporary files and directories."
homepage = "http://stebalien.com/projects/tempfile-rs"
homepage = "https://stebalien.com/projects/tempfile-rs/"
documentation = "https://docs.rs/tempfile"
keywords = ["tempfile", "tmpfile", "filesystem"]
readme = "README.md"
keywords = [
"tempfile",
"tmpfile",
"filesystem",
]
license = "MIT OR Apache-2.0"
repository = "https://github.com/Stebalien/tempfile"
[dependencies.cfg-if]
version = "1"
[dependencies.fastrand]
version = "1.6.0"
version = "2.0.0"
[dependencies.remove_dir_all]
version = "0.5"
[dev-dependencies.doc-comment]
version = "0.3"
[features]
nightly = []
[target."cfg(any(unix, target_os = \"wasi\"))".dependencies.libc]
version = "0.2.27"
[target."cfg(any(unix, target_os = \"wasi\"))".dependencies.rustix]
version = "0.38"
features = ["fs"]
[target."cfg(target_os = \"redox\")".dependencies.redox_syscall]
version = "0.2.9"
[target."cfg(windows)".dependencies.winapi]
version = "0.3"
features = ["fileapi", "handleapi", "winbase"]
[target."cfg(windows)".dependencies.windows-sys]
version = "0.48"
features = [
"Win32_Storage_FileSystem",
"Win32_Foundation",
]

206
third_party/rust/tempfile/NEWS поставляемый
Просмотреть файл

@ -1,206 +0,0 @@
3.3.0
=====
Features:
* Replace rand with fastrand for a significantly smaller dependency tree. Cryptographic randomness
isn't necessary for temporary file names, and isn't all that helpful either.
* Add limited WASI support.
* Add a function to extract the inner data from a `SpooledTempFile`.
Bug Fixes:
* Make it possible to persist unnamed temporary files on linux by removing the `O_EXCL` flag.
* Fix redox minimum crate version.
3.2.0
=====
Features:
* Bump rand dependency to `0.8`.
* Bump cfg-if dependency to `1.0`
Other than that, this release mostly includes small cleanups and simplifications.
Breaking: The minimum rust version is now `1.40.0`.
3.1.0
=====
Features:
* Bump rand dependency to `0.7`.
Breaking: The minimum rust version is now `1.32.0`.
3.0.9
=====
Documentation:
* Add an example for reopening a named temporary file.
* Flesh out the security documentation.
Features:
* Introduce an `append` option to the builder.
* Errors:
* No longer implement the soft-deprecated `description`.
* Implement `source` instead of `cause`.
Breaking: The minimum rust version is now 1.30.
3.0.8
=====
This is a bugfix release.
Fixes:
* Export `PathPersistError`.
* Fix a bug where flushing a `SpooledTempFile` to disk could fail to write part
of the file in some rare, yet-to-reproduced cases.
3.0.7
=====
Breaking:
* `Builder::prefix` and `Builder::suffix` now accept a generic `&AsRef<OsStr>`.
This could affect type inference.
* Temporary files (except unnamed temporary files on Windows and Linux >= 3.11)
now use absolute path names. This will break programs that create temporary
files relative to their current working directory when they don't have the
search permission (x) on some ancestor directory. This is only likely to
affect programs with strange chroot-less filesystem sandboxes. If you believe
you're affected by this issue, please comment on #40.
Features:
* Accept anything implementing `&AsRef<OsStr>` in the builder: &OsStr, &OsString, &Path, etc.
Fixes:
* Fix LFS support.
* Use absolute paths for named temporary files to guard against changes in the
current directory.
* Use absolute paths when creating unnamed temporary files on platforms that
can't create unlinked or auto-deleted temporary files. This fixes a very
unlikely race where the current directory could change while the temporary
file is being created.
Misc:
* Use modern stdlib features to avoid custom unsafe code. This reduces the
number of unsafe blocks from 12 to 4.
3.0.6
=====
* Don't hide temporary files on windows, fixing #66 and #69.
3.0.5
=====
Features:
* Added a spooled temporary file implementation. This temporary file variant
starts out as an in-memory temporary file but "rolls-over" onto disk when it
grows over a specified size (#68).
* Errors are now annotated with paths to make debugging easier (#73).
Misc:
* The rand version has been bumped to 0.6 (#74).
Bugs:
* Tempfile compiles again on Redox (#75).
3.0.4
=====
* Now compiles on unsupported platforms.
3.0.3
=====
* update rand to 0.5
3.0.2
=====
* Actually *delete* temporary files on non-Linux unix systems (thanks to
@oliverhenshaw for the fix and a test case).
3.0.1
=====
* Restore NamedTempFile::new_in
3.0.0
=====
* Adds temporary directory support (@KodrAus)
* Allow closing named temporary files without deleting them (@jasonwhite)
2.2.0
=====
* Redox Support
2.1.6
=====
* Remove build script and bump minimum rustc version to 1.9.0
2.1.5
=====
* Don't build platform-specific dependencies on all platforms.
* Cleanup some documentation.
2.1.4
=====
* Fix crates.io tags. No interesting changes.
2.1.3
=====
Export `PersistError`.
2.1.2
=====
Add `Read`/`Write`/`Seek` impls on `&NamedTempFile`. This mirrors the
implementations on `&File`. One can currently just deref to a `&File` but these
implementations are more discoverable.
2.1.1
=====
Add LFS Support.
2.1.0
=====
* Implement `AsRef<File>` for `NamedTempFile` allowing named temporary files to
be borrowed as `File`s.
* Add a method to convert a `NamedTempFile` to an unnamed temporary `File`.
2.0.1
=====
* Arm bugfix
2.0.0
=====
This release replaces `TempFile` with a `tempfile()` function that returnes
`std::fs::File` objects. These are significantly more useful because most rust
libraries expect normal `File` objects.
To continue supporting shared temporary files, this new version adds a
`reopen()` method to `NamedTempFile`.

3
third_party/rust/tempfile/README.md поставляемый
Просмотреть файл

@ -14,9 +14,10 @@ patterns and surprisingly difficult to implement securely).
Usage
-----
Minimum required Rust version: 1.40.0
Minimum required Rust version: 1.63.0
Add this to your `Cargo.toml`:
```toml
[dependencies]
tempfile = "3"

96
third_party/rust/tempfile/src/dir.rs поставляемый
Просмотреть файл

@ -8,7 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use remove_dir_all::remove_dir_all;
use std::ffi::OsStr;
use std::fs::remove_dir_all;
use std::mem;
use std::path::{self, Path, PathBuf};
use std::{fmt, fs, io};
@ -45,16 +46,16 @@ use crate::Builder;
/// # }
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of `std::env::temp_dir()`
/// let dir = tempdir()?;
/// let tmp_dir = tempdir()?;
///
/// let file_path = dir.path().join("my-temporary-note.txt");
/// let mut file = File::create(file_path)?;
/// writeln!(file, "Brian was here. Briefly.")?;
/// let file_path = tmp_dir.path().join("my-temporary-note.txt");
/// let mut tmp_file = File::create(file_path)?;
/// writeln!(tmp_file, "Brian was here. Briefly.")?;
///
/// // `tmp_dir` goes out of scope, the directory as well as
/// // `tmp_file` will be deleted here.
/// drop(file);
/// dir.close()?;
/// drop(tmp_file);
/// tmp_dir.close()?;
/// # Ok(())
/// # }
/// ```
@ -65,9 +66,9 @@ pub fn tempdir() -> io::Result<TempDir> {
TempDir::new()
}
/// Create a new temporary directory.
/// Create a new temporary directory in a specific directory.
///
/// The `tempdir` function creates a directory in the file system
/// The `tempdir_in` function creates a directory in the specified directory
/// and returns a [`TempDir`].
/// The directory will be automatically deleted when the `TempDir`s
/// destructor is run.
@ -83,7 +84,7 @@ pub fn tempdir() -> io::Result<TempDir> {
/// # Examples
///
/// ```
/// use tempfile::tempdir;
/// use tempfile::tempdir_in;
/// use std::fs::File;
/// use std::io::{self, Write};
///
@ -93,17 +94,17 @@ pub fn tempdir() -> io::Result<TempDir> {
/// # }
/// # }
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of `std::env::temp_dir()`,
/// let dir = tempdir()?;
/// // Create a directory inside of the current directory.
/// let tmp_dir = tempdir_in(".")?;
///
/// let file_path = dir.path().join("my-temporary-note.txt");
/// let mut file = File::create(file_path)?;
/// writeln!(file, "Brian was here. Briefly.")?;
/// let file_path = tmp_dir.path().join("my-temporary-note.txt");
/// let mut tmp_file = File::create(file_path)?;
/// writeln!(tmp_file, "Brian was here. Briefly.")?;
///
/// // `tmp_dir` goes out of scope, the directory as well as
/// // `tmp_file` will be deleted here.
/// drop(file);
/// dir.close()?;
/// drop(tmp_file);
/// tmp_dir.close()?;
/// # Ok(())
/// # }
/// ```
@ -264,6 +265,65 @@ impl TempDir {
Builder::new().tempdir_in(dir)
}
/// Attempts to make a temporary directory with the specified prefix inside of
/// `env::temp_dir()`. The directory and everything inside it will be automatically
/// deleted once the returned `TempDir` is destroyed.
///
/// # Errors
///
/// If the directory can not be created, `Err` is returned.
///
/// # Examples
///
/// ```
/// use std::fs::{self, File};
/// use std::io::Write;
/// use tempfile::TempDir;
///
/// # use std::io;
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of the current directory
/// let tmp_dir = TempDir::with_prefix("foo-")?;
/// let tmp_name = tmp_dir.path().file_name().unwrap().to_str().unwrap();
/// assert!(tmp_name.starts_with("foo-"));
/// # Ok(())
/// # }
/// ```
pub fn with_prefix<S: AsRef<OsStr>>(prefix: S) -> io::Result<TempDir> {
Builder::new().prefix(&prefix).tempdir()
}
/// Attempts to make a temporary directory with the specified prefix inside
/// the specified directory. The directory and everything inside it will be
/// automatically deleted once the returned `TempDir` is destroyed.
///
/// # Errors
///
/// If the directory can not be created, `Err` is returned.
///
/// # Examples
///
/// ```
/// use std::fs::{self, File};
/// use std::io::Write;
/// use tempfile::TempDir;
///
/// # use std::io;
/// # fn run() -> Result<(), io::Error> {
/// // Create a directory inside of the current directory
/// let tmp_dir = TempDir::with_prefix_in("foo-", ".")?;
/// let tmp_name = tmp_dir.path().file_name().unwrap().to_str().unwrap();
/// assert!(tmp_name.starts_with("foo-"));
/// # Ok(())
/// # }
/// ```
pub fn with_prefix_in<S: AsRef<OsStr>, P: AsRef<Path>>(
prefix: S,
dir: P,
) -> io::Result<TempDir> {
Builder::new().prefix(&prefix).tempdir_in(dir)
}
/// Accesses the [`Path`] to the temporary directory.
///
/// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html
@ -292,6 +352,7 @@ impl TempDir {
/// # Ok(())
/// # }
/// ```
#[must_use]
pub fn path(&self) -> &path::Path {
self.path.as_ref()
}
@ -323,6 +384,7 @@ impl TempDir {
/// # Ok(())
/// # }
/// ```
#[must_use]
pub fn into_path(self) -> PathBuf {
// Prevent the Drop impl from being called.
let mut this = mem::ManuallyDrop::new(self);

Просмотреть файл

@ -9,7 +9,7 @@ fn not_supported<T>() -> io::Result<T> {
))
}
pub fn create_named(_path: &Path, open_options: &mut OpenOptions) -> io::Result<File> {
pub fn create_named(_path: &Path, _open_options: &mut OpenOptions) -> io::Result<File> {
not_supported()
}
@ -25,6 +25,6 @@ pub fn persist(_old_path: &Path, _new_path: &Path, _overwrite: bool) -> io::Resu
not_supported()
}
pub fn keep(path: &Path) -> io::Result<()> {
pub fn keep(_path: &Path) -> io::Result<()> {
not_supported()
}

Просмотреть файл

@ -1,13 +1,11 @@
use std::env;
use std::ffi::{CString, OsStr};
use std::ffi::OsStr;
use std::fs::{self, File, OpenOptions};
use std::io;
cfg_if::cfg_if! {
if #[cfg(not(target_os = "wasi"))] {
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
} else {
use std::os::wasi::ffi::OsStrExt;
#[cfg(feature = "nightly")]
use std::os::wasi::fs::MetadataExt;
}
@ -16,29 +14,10 @@ use crate::util;
use std::path::Path;
#[cfg(not(target_os = "redox"))]
use libc::{c_char, c_int, link, rename, unlink};
#[cfg(not(target_os = "redox"))]
#[inline(always)]
pub fn cvt_err(result: c_int) -> io::Result<c_int> {
if result == -1 {
Err(io::Error::last_os_error())
} else {
Ok(result)
}
}
#[cfg(target_os = "redox")]
#[inline(always)]
pub fn cvt_err(result: Result<usize, syscall::Error>) -> io::Result<usize> {
result.map_err(|err| io::Error::from_raw_os_error(err.errno))
}
// Stolen from std.
pub fn cstr(path: &Path) -> io::Result<CString> {
CString::new(path.as_os_str().as_bytes())
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
}
use {
rustix::fs::{rename, unlink},
std::fs::hard_link,
};
pub fn create_named(path: &Path, open_options: &mut OpenOptions) -> io::Result<File> {
open_options.read(true).write(true).create_new(true);
@ -70,16 +49,18 @@ fn create_unlinked(path: &Path) -> io::Result<File> {
#[cfg(target_os = "linux")]
pub fn create(dir: &Path) -> io::Result<File> {
use libc::{EISDIR, ENOENT, EOPNOTSUPP, O_TMPFILE};
use rustix::{fs::OFlags, io::Errno};
OpenOptions::new()
.read(true)
.write(true)
.custom_flags(O_TMPFILE) // do not mix with `create_new(true)`
.custom_flags(OFlags::TMPFILE.bits() as i32) // do not mix with `create_new(true)`
.open(dir)
.or_else(|e| {
match e.raw_os_error() {
match Errno::from_io_error(&e) {
// These are the three "not supported" error codes for O_TMPFILE.
Some(EOPNOTSUPP) | Some(EISDIR) | Some(ENOENT) => create_unix(dir),
Some(Errno::OPNOTSUPP) | Some(Errno::ISDIR) | Some(Errno::NOENT) => {
create_unix(dir)
}
_ => Err(e),
}
})
@ -124,29 +105,41 @@ pub fn reopen(_file: &File, _path: &Path) -> io::Result<File> {
#[cfg(not(target_os = "redox"))]
pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
unsafe {
let old_path = cstr(old_path)?;
let new_path = cstr(new_path)?;
if overwrite {
cvt_err(rename(
old_path.as_ptr() as *const c_char,
new_path.as_ptr() as *const c_char,
))?;
} else {
cvt_err(link(
old_path.as_ptr() as *const c_char,
new_path.as_ptr() as *const c_char,
))?;
// Ignore unlink errors. Can we do better?
// On recent linux, we can use renameat2 to do this atomically.
let _ = unlink(old_path.as_ptr() as *const c_char);
if overwrite {
rename(old_path, new_path)?;
} else {
// On Linux, use `renameat_with` to avoid overwriting an existing name,
// if the kernel and the filesystem support it.
#[cfg(any(target_os = "android", target_os = "linux"))]
{
use rustix::fs::{renameat_with, RenameFlags, CWD};
use rustix::io::Errno;
use std::sync::atomic::{AtomicBool, Ordering::Relaxed};
static NOSYS: AtomicBool = AtomicBool::new(false);
if !NOSYS.load(Relaxed) {
match renameat_with(CWD, old_path, CWD, new_path, RenameFlags::NOREPLACE) {
Ok(()) => return Ok(()),
Err(Errno::NOSYS) => NOSYS.store(true, Relaxed),
Err(Errno::INVAL) => {}
Err(e) => return Err(e.into()),
}
}
}
Ok(())
// Otherwise use `hard_link` to create the new filesystem name, which
// will fail if the name already exists, and then `unlink` to remove
// the old name.
hard_link(old_path, new_path)?;
// Ignore unlink errors. Can we do better?
let _ = unlink(old_path);
}
Ok(())
}
#[cfg(target_os = "redox")]
pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
pub fn persist(_old_path: &Path, _new_path: &Path, _overwrite: bool) -> io::Result<()> {
// XXX implement when possible
Err(io::Error::from_raw_os_error(syscall::ENOSYS))
}

Просмотреть файл

@ -6,13 +6,12 @@ use std::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle};
use std::path::Path;
use std::{io, iter};
use winapi::um::fileapi::SetFileAttributesW;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::winbase::{MoveFileExW, ReOpenFile};
use winapi::um::winbase::{FILE_FLAG_DELETE_ON_CLOSE, MOVEFILE_REPLACE_EXISTING};
use winapi::um::winnt::{FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_TEMPORARY};
use winapi::um::winnt::{FILE_GENERIC_READ, FILE_GENERIC_WRITE, HANDLE};
use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
use windows_sys::Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE};
use windows_sys::Win32::Storage::FileSystem::{
MoveFileExW, ReOpenFile, SetFileAttributesW, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_TEMPORARY,
FILE_FLAG_DELETE_ON_CLOSE, FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_SHARE_DELETE,
FILE_SHARE_READ, FILE_SHARE_WRITE, MOVEFILE_REPLACE_EXISTING,
};
use crate::util;
@ -76,9 +75,6 @@ pub fn keep(path: &Path) -> io::Result<()> {
}
pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
// TODO: We should probably do this in one-shot using SetFileInformationByHandle but the API is
// really painful.
unsafe {
let old_path_w = to_utf16(old_path);
let new_path_w = to_utf16(new_path);

289
third_party/rust/tempfile/src/file/mod.rs поставляемый
Просмотреть файл

@ -6,6 +6,12 @@ use std::fs::{self, File, OpenOptions};
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::mem;
use std::ops::Deref;
#[cfg(unix)]
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
#[cfg(target_os = "wasi")]
use std::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, RawHandle};
use std::path::{Path, PathBuf};
use crate::error::IoResultExt;
@ -52,7 +58,7 @@ mod imp;
///
/// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
pub fn tempfile() -> io::Result<File> {
tempfile_in(&env::temp_dir())
tempfile_in(env::temp_dir())
}
/// Create a new temporary file in the specified directory.
@ -467,29 +473,31 @@ impl AsRef<OsStr> for TempPath {
/// # Resource Leaking
///
/// If the program exits before the `NamedTempFile` destructor is
/// run, such as via [`std::process::exit()`], by segfaulting, or by
/// receiving a signal like `SIGINT`, then the temporary file
/// will not be deleted.
/// run, the temporary file will not be deleted. This can happen
/// if the process exits using [`std::process::exit()`], a segfault occurs,
/// receiving an interrupt signal like `SIGINT` that is not handled, or by using
/// a statically declared `NamedTempFile` instance (like with [`lazy_static`]).
///
/// Use the [`tempfile()`] function unless you absolutely need a named file.
/// Use the [`tempfile()`] function unless you need a named file path.
///
/// [`tempfile()`]: fn.tempfile.html
/// [`NamedTempFile::new()`]: #method.new
/// [`NamedTempFile::new_in()`]: #method.new_in
/// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
/// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html
pub struct NamedTempFile {
/// [`lazy_static`]: https://github.com/rust-lang-nursery/lazy-static.rs/issues/62
pub struct NamedTempFile<F = File> {
path: TempPath,
file: File,
file: F,
}
impl fmt::Debug for NamedTempFile {
impl<F> fmt::Debug for NamedTempFile<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "NamedTempFile({:?})", self.path)
}
}
impl AsRef<Path> for NamedTempFile {
impl<F> AsRef<Path> for NamedTempFile<F> {
#[inline]
fn as_ref(&self) -> &Path {
self.path()
@ -497,41 +505,46 @@ impl AsRef<Path> for NamedTempFile {
}
/// Error returned when persisting a temporary file fails.
#[derive(Debug)]
pub struct PersistError {
pub struct PersistError<F = File> {
/// The underlying IO error.
pub error: io::Error,
/// The temporary file that couldn't be persisted.
pub file: NamedTempFile,
pub file: NamedTempFile<F>,
}
impl From<PersistError> for io::Error {
impl<F> fmt::Debug for PersistError<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "PersistError({:?})", self.error)
}
}
impl<F> From<PersistError<F>> for io::Error {
#[inline]
fn from(error: PersistError) -> io::Error {
fn from(error: PersistError<F>) -> io::Error {
error.error
}
}
impl From<PersistError> for NamedTempFile {
impl<F> From<PersistError<F>> for NamedTempFile<F> {
#[inline]
fn from(error: PersistError) -> NamedTempFile {
fn from(error: PersistError<F>) -> NamedTempFile<F> {
error.file
}
}
impl fmt::Display for PersistError {
impl<F> fmt::Display for PersistError<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "failed to persist temporary file: {}", self.error)
}
}
impl error::Error for PersistError {
impl<F> error::Error for PersistError<F> {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
Some(&self.error)
}
}
impl NamedTempFile {
impl NamedTempFile<File> {
/// Create a new named temporary file.
///
/// See [`Builder`] for more configuration.
@ -595,6 +608,12 @@ impl NamedTempFile {
/// Create a new named temporary file in the specified directory.
///
/// This is equivalent to:
///
/// ```ignore
/// Builder::new().prefix(&prefix).tempfile()
/// ```
///
/// See [`NamedTempFile::new()`] for details.
///
/// [`NamedTempFile::new()`]: #method.new
@ -602,6 +621,35 @@ impl NamedTempFile {
Builder::new().tempfile_in(dir)
}
/// Create a new named temporary file with the specified filename prefix.
///
/// See [`NamedTempFile::new()`] for details.
///
/// [`NamedTempFile::new()`]: #method.new
pub fn with_prefix<S: AsRef<OsStr>>(prefix: S) -> io::Result<NamedTempFile> {
Builder::new().prefix(&prefix).tempfile()
}
/// Create a new named temporary file with the specified filename prefix,
/// in the specified directory.
///
/// This is equivalent to:
///
/// ```ignore
/// Builder::new().prefix(&prefix).tempfile_in(directory)
/// ```
///
/// See [`NamedTempFile::new()`] for details.
///
/// [`NamedTempFile::new()`]: #method.new
pub fn with_prefix_in<S: AsRef<OsStr>, P: AsRef<Path>>(
prefix: S,
dir: P,
) -> io::Result<NamedTempFile> {
Builder::new().prefix(&prefix).tempfile_in(dir)
}
}
impl<F> NamedTempFile<F> {
/// Get the temporary file's path.
///
/// # Security
@ -711,7 +759,7 @@ impl NamedTempFile {
/// ```
///
/// [`PersistError`]: struct.PersistError.html
pub fn persist<P: AsRef<Path>>(self, new_path: P) -> Result<File, PersistError> {
pub fn persist<P: AsRef<Path>>(self, new_path: P) -> Result<F, PersistError<F>> {
let NamedTempFile { path, file } = self;
match path.persist(new_path) {
Ok(_) => Ok(file),
@ -764,7 +812,7 @@ impl NamedTempFile {
/// # Ok(())
/// # }
/// ```
pub fn persist_noclobber<P: AsRef<Path>>(self, new_path: P) -> Result<File, PersistError> {
pub fn persist_noclobber<P: AsRef<Path>>(self, new_path: P) -> Result<F, PersistError<F>> {
let NamedTempFile { path, file } = self;
match path.persist_noclobber(new_path) {
Ok(_) => Ok(file),
@ -808,7 +856,7 @@ impl NamedTempFile {
/// ```
///
/// [`PathPersistError`]: struct.PathPersistError.html
pub fn keep(self) -> Result<(File, PathBuf), PersistError> {
pub fn keep(self) -> Result<(F, PathBuf), PersistError<F>> {
let (file, path) = (self.file, self.path);
match path.keep() {
Ok(path) => Ok((file, path)),
@ -819,6 +867,49 @@ impl NamedTempFile {
}
}
/// Get a reference to the underlying file.
pub fn as_file(&self) -> &F {
&self.file
}
/// Get a mutable reference to the underlying file.
pub fn as_file_mut(&mut self) -> &mut F {
&mut self.file
}
/// Convert the temporary file into a `std::fs::File`.
///
/// The inner file will be deleted.
pub fn into_file(self) -> F {
self.file
}
/// Closes the file, leaving only the temporary file path.
///
/// This is useful when another process must be able to open the temporary
/// file.
pub fn into_temp_path(self) -> TempPath {
self.path
}
/// Converts the named temporary file into its constituent parts.
///
/// Note: When the path is dropped, the file is deleted but the file handle
/// is still usable.
pub fn into_parts(self) -> (F, TempPath) {
(self.file, self.path)
}
/// Creates a `NamedTempFile` from its constituent parts.
///
/// This can be used with [`NamedTempFile::into_parts`] to reconstruct the
/// `NamedTempFile`.
pub fn from_parts(file: F, path: TempPath) -> Self {
Self { file, path }
}
}
impl NamedTempFile<File> {
/// Securely reopen the temporary file.
///
/// This function is useful when you need multiple independent handles to
@ -858,54 +949,67 @@ impl NamedTempFile {
imp::reopen(self.as_file(), NamedTempFile::path(self))
.with_err_path(|| NamedTempFile::path(self))
}
/// Get a reference to the underlying file.
pub fn as_file(&self) -> &File {
&self.file
}
/// Get a mutable reference to the underlying file.
pub fn as_file_mut(&mut self) -> &mut File {
&mut self.file
}
/// Convert the temporary file into a `std::fs::File`.
///
/// The inner file will be deleted.
pub fn into_file(self) -> File {
self.file
}
/// Closes the file, leaving only the temporary file path.
///
/// This is useful when another process must be able to open the temporary
/// file.
pub fn into_temp_path(self) -> TempPath {
self.path
}
/// Converts the named temporary file into its constituent parts.
///
/// Note: When the path is dropped, the file is deleted but the file handle
/// is still usable.
pub fn into_parts(self) -> (File, TempPath) {
(self.file, self.path)
}
}
impl Read for NamedTempFile {
impl<F: Read> Read for NamedTempFile<F> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.as_file_mut().read(buf).with_err_path(|| self.path())
}
}
impl<'a> Read for &'a NamedTempFile {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.as_file().read(buf).with_err_path(|| self.path())
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.as_file_mut()
.read_vectored(bufs)
.with_err_path(|| self.path())
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.as_file_mut()
.read_to_end(buf)
.with_err_path(|| self.path())
}
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
self.as_file_mut()
.read_to_string(buf)
.with_err_path(|| self.path())
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.as_file_mut()
.read_exact(buf)
.with_err_path(|| self.path())
}
}
impl Write for NamedTempFile {
impl Read for &NamedTempFile<File> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.as_file().read(buf).with_err_path(|| self.path())
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.as_file()
.read_vectored(bufs)
.with_err_path(|| self.path())
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.as_file()
.read_to_end(buf)
.with_err_path(|| self.path())
}
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
self.as_file()
.read_to_string(buf)
.with_err_path(|| self.path())
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.as_file().read_exact(buf).with_err_path(|| self.path())
}
}
impl<F: Write> Write for NamedTempFile<F> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.as_file_mut().write(buf).with_err_path(|| self.path())
}
@ -913,9 +1017,27 @@ impl Write for NamedTempFile {
fn flush(&mut self) -> io::Result<()> {
self.as_file_mut().flush().with_err_path(|| self.path())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.as_file_mut()
.write_vectored(bufs)
.with_err_path(|| self.path())
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.as_file_mut()
.write_all(buf)
.with_err_path(|| self.path())
}
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
self.as_file_mut()
.write_fmt(fmt)
.with_err_path(|| self.path())
}
}
impl<'a> Write for &'a NamedTempFile {
impl Write for &NamedTempFile<File> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.as_file().write(buf).with_err_path(|| self.path())
}
@ -923,32 +1045,61 @@ impl<'a> Write for &'a NamedTempFile {
fn flush(&mut self) -> io::Result<()> {
self.as_file().flush().with_err_path(|| self.path())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.as_file()
.write_vectored(bufs)
.with_err_path(|| self.path())
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.as_file().write_all(buf).with_err_path(|| self.path())
}
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
self.as_file().write_fmt(fmt).with_err_path(|| self.path())
}
}
impl Seek for NamedTempFile {
impl<F: Seek> Seek for NamedTempFile<F> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
self.as_file_mut().seek(pos).with_err_path(|| self.path())
}
}
impl<'a> Seek for &'a NamedTempFile {
impl Seek for &NamedTempFile<File> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
self.as_file().seek(pos).with_err_path(|| self.path())
}
}
#[cfg(unix)]
impl std::os::unix::io::AsRawFd for NamedTempFile {
#[cfg(any(unix, target_os = "wasi"))]
impl<F: AsFd> AsFd for NamedTempFile<F> {
fn as_fd(&self) -> BorrowedFd<'_> {
self.as_file().as_fd()
}
}
#[cfg(any(unix, target_os = "wasi"))]
impl<F: AsRawFd> AsRawFd for NamedTempFile<F> {
#[inline]
fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
fn as_raw_fd(&self) -> RawFd {
self.as_file().as_raw_fd()
}
}
#[cfg(windows)]
impl std::os::windows::io::AsRawHandle for NamedTempFile {
impl<F: AsHandle> AsHandle for NamedTempFile<F> {
#[inline]
fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.as_file().as_handle()
}
}
#[cfg(windows)]
impl<F: AsRawHandle> AsRawHandle for NamedTempFile<F> {
#[inline]
fn as_raw_handle(&self) -> RawHandle {
self.as_file().as_raw_handle()
}
}

176
third_party/rust/tempfile/src/lib.rs поставляемый
Просмотреть файл

@ -14,9 +14,12 @@
//!
//! ## Resource Leaking
//!
//! `tempfile` will (almost) never fail to cleanup temporary resources, but `TempDir` and `NamedTempFile` will if
//! their destructors don't run. This is because `tempfile` relies on the OS to cleanup the
//! underlying file, while `TempDir` and `NamedTempFile` rely on their destructors to do so.
//! `tempfile` will (almost) never fail to cleanup temporary resources. However `TempDir` and `NamedTempFile` will
//! fail if their destructors don't run. This is because `tempfile` relies on the OS to cleanup the
//! underlying file, while `TempDir` and `NamedTempFile` rely on rust destructors to do so.
//! Destructors may fail to run if the process exits through an unhandled signal interrupt (like `SIGINT`),
//! or if the instance is declared statically (like with [`lazy_static`]), among other possible
//! reasons.
//!
//! ## Security
//!
@ -152,6 +155,7 @@
//! [`TempDir`]: struct.TempDir.html
//! [`NamedTempFile`]: struct.NamedTempFile.html
//! [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
//! [`lazy_static`]: https://github.com/rust-lang-nursery/lazy-static.rs/issues/62
#![doc(
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
@ -161,7 +165,7 @@
#![cfg_attr(test, deny(warnings))]
#![deny(rust_2018_idioms)]
#![allow(clippy::redundant_field_names)]
#![cfg_attr(feature = "nightly", feature(wasi_ext))]
#![cfg_attr(all(feature = "nightly", target_os = "wasi"), feature(wasi_ext))]
#[cfg(doctest)]
doc_comment::doctest!("../README.md");
@ -276,6 +280,15 @@ impl<'a, 'b> Builder<'a, 'b> {
/// # Ok(())
/// # }
/// ```
///
/// Create a temporary directory with a chosen prefix under a chosen folder:
///
/// ```ignore
/// let dir = Builder::new()
/// .prefix("my-temporary-dir")
/// .tempdir_in("folder-with-tempdirs")?;
/// ```
#[must_use]
pub fn new() -> Self {
Self::default()
}
@ -419,7 +432,7 @@ impl<'a, 'b> Builder<'a, 'b> {
/// [security]: struct.NamedTempFile.html#security
/// [resource-leaking]: struct.NamedTempFile.html#resource-leaking
pub fn tempfile(&self) -> io::Result<NamedTempFile> {
self.tempfile_in(&env::temp_dir())
self.tempfile_in(env::temp_dir())
}
/// Create the named temporary file in the specified directory.
@ -493,7 +506,7 @@ impl<'a, 'b> Builder<'a, 'b> {
///
/// [resource-leaking]: struct.TempDir.html#resource-leaking
pub fn tempdir(&self) -> io::Result<TempDir> {
self.tempdir_in(&env::temp_dir())
self.tempdir_in(env::temp_dir())
}
/// Attempts to make a temporary directory inside of `dir`.
@ -534,4 +547,155 @@ impl<'a, 'b> Builder<'a, 'b> {
util::create_helper(dir, self.prefix, self.suffix, self.random_len, dir::create)
}
/// Attempts to create a temporary file (or file-like object) using the
/// provided closure. The closure is passed a temporary file path and
/// returns an [`std::io::Result`]. The path provided to the closure will be
/// inside of [`std::env::temp_dir()`]. Use [`Builder::make_in`] to provide
/// a custom temporary directory. If the closure returns one of the
/// following errors, then another randomized file path is tried:
/// - [`std::io::ErrorKind::AlreadyExists`]
/// - [`std::io::ErrorKind::AddrInUse`]
///
/// This can be helpful for taking full control over the file creation, but
/// leaving the temporary file path construction up to the library. This
/// also enables creating a temporary UNIX domain socket, since it is not
/// possible to bind to a socket that already exists.
///
/// Note that [`Builder::append`] is ignored when using [`Builder::make`].
///
/// # Security
///
/// This has the same [security implications][security] as
/// [`NamedTempFile`], but with additional caveats. Specifically, it is up
/// to the closure to ensure that the file does not exist and that such a
/// check is *atomic*. Otherwise, a [time-of-check to time-of-use
/// bug][TOCTOU] could be introduced.
///
/// For example, the following is **not** secure:
///
/// ```
/// # use std::io;
/// # use std::fs::File;
/// # fn main() {
/// # if let Err(_) = run() {
/// # ::std::process::exit(1);
/// # }
/// # }
/// # fn run() -> Result<(), io::Error> {
/// # use tempfile::Builder;
/// // This is NOT secure!
/// let tempfile = Builder::new().make(|path| {
/// if path.is_file() {
/// return Err(io::ErrorKind::AlreadyExists.into());
/// }
///
/// // Between the check above and the usage below, an attacker could
/// // have replaced `path` with another file, which would get truncated
/// // by `File::create`.
///
/// File::create(path)
/// })?;
/// # Ok(())
/// # }
/// ```
/// Note that simply using [`std::fs::File::create`] alone is not correct
/// because it does not fail if the file already exists:
/// ```
/// # use std::io;
/// # use std::fs::File;
/// # fn main() {
/// # if let Err(_) = run() {
/// # ::std::process::exit(1);
/// # }
/// # }
/// # fn run() -> Result<(), io::Error> {
/// # use tempfile::Builder;
/// // This could overwrite an existing file!
/// let tempfile = Builder::new().make(|path| File::create(path))?;
/// # Ok(())
/// # }
/// ```
/// For creating regular temporary files, use [`Builder::tempfile`] instead
/// to avoid these problems. This function is meant to enable more exotic
/// use-cases.
///
/// # Resource leaking
///
/// See [the resource leaking][resource-leaking] docs on `NamedTempFile`.
///
/// # Errors
///
/// If the closure returns any error besides
/// [`std::io::ErrorKind::AlreadyExists`] or
/// [`std::io::ErrorKind::AddrInUse`], then `Err` is returned.
///
/// # Examples
/// ```
/// # use std::io;
/// # fn main() {
/// # if let Err(_) = run() {
/// # ::std::process::exit(1);
/// # }
/// # }
/// # fn run() -> Result<(), io::Error> {
/// # use tempfile::Builder;
/// # #[cfg(unix)]
/// use std::os::unix::net::UnixListener;
/// # #[cfg(unix)]
/// let tempsock = Builder::new().make(|path| UnixListener::bind(path))?;
/// # Ok(())
/// # }
/// ```
///
/// [TOCTOU]: https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use
/// [security]: struct.NamedTempFile.html#security
/// [resource-leaking]: struct.NamedTempFile.html#resource-leaking
pub fn make<F, R>(&self, f: F) -> io::Result<NamedTempFile<R>>
where
F: FnMut(&Path) -> io::Result<R>,
{
self.make_in(env::temp_dir(), f)
}
/// This is the same as [`Builder::make`], except `dir` is used as the base
/// directory for the temporary file path.
///
/// See [`Builder::make`] for more details and security implications.
///
/// # Examples
/// ```
/// # use std::io;
/// # fn main() {
/// # if let Err(_) = run() {
/// # ::std::process::exit(1);
/// # }
/// # }
/// # fn run() -> Result<(), io::Error> {
/// # use tempfile::Builder;
/// # #[cfg(unix)]
/// use std::os::unix::net::UnixListener;
/// # #[cfg(unix)]
/// let tempsock = Builder::new().make_in("./", |path| UnixListener::bind(path))?;
/// # Ok(())
/// # }
/// ```
pub fn make_in<F, R, P>(&self, dir: P, mut f: F) -> io::Result<NamedTempFile<R>>
where
F: FnMut(&Path) -> io::Result<R>,
P: AsRef<Path>,
{
util::create_helper(
dir.as_ref(),
self.prefix,
self.suffix,
self.random_len,
move |path| {
Ok(NamedTempFile::from_parts(
f(&path)?,
TempPath::from_path(path),
))
},
)
}
}

89
third_party/rust/tempfile/src/spooled.rs поставляемый
Просмотреть файл

@ -64,14 +64,16 @@ pub fn spooled_tempfile(max_size: usize) -> SpooledTempFile {
}
impl SpooledTempFile {
#[must_use]
pub fn new(max_size: usize) -> SpooledTempFile {
SpooledTempFile {
max_size: max_size,
max_size,
inner: SpooledData::InMemory(Cursor::new(Vec::new())),
}
}
/// Returns true if the file has been rolled over to disk.
#[must_use]
pub fn is_rolled(&self) -> bool {
match self.inner {
SpooledData::InMemory(_) => false,
@ -84,7 +86,7 @@ impl SpooledTempFile {
pub fn roll(&mut self) -> io::Result<()> {
if !self.is_rolled() {
let mut file = tempfile()?;
if let SpooledData::InMemory(ref mut cursor) = self.inner {
if let SpooledData::InMemory(cursor) = &mut self.inner {
file.write_all(cursor.get_ref())?;
file.seek(SeekFrom::Start(cursor.position()))?;
}
@ -97,16 +99,17 @@ impl SpooledTempFile {
if size as usize > self.max_size {
self.roll()?; // does nothing if already rolled over
}
match self.inner {
SpooledData::InMemory(ref mut cursor) => {
match &mut self.inner {
SpooledData::InMemory(cursor) => {
cursor.get_mut().resize(size as usize, 0);
Ok(())
}
SpooledData::OnDisk(ref mut file) => file.set_len(size),
SpooledData::OnDisk(file) => file.set_len(size),
}
}
/// Consumes and returns the inner `SpooledData` type.
#[must_use]
pub fn into_inner(self) -> SpooledData {
self.inner
}
@ -114,9 +117,37 @@ impl SpooledTempFile {
impl Read for SpooledTempFile {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.inner {
SpooledData::InMemory(ref mut cursor) => cursor.read(buf),
SpooledData::OnDisk(ref mut file) => file.read(buf),
match &mut self.inner {
SpooledData::InMemory(cursor) => cursor.read(buf),
SpooledData::OnDisk(file) => file.read(buf),
}
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
match &mut self.inner {
SpooledData::InMemory(cursor) => cursor.read_vectored(bufs),
SpooledData::OnDisk(file) => file.read_vectored(bufs),
}
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
match &mut self.inner {
SpooledData::InMemory(cursor) => cursor.read_to_end(buf),
SpooledData::OnDisk(file) => file.read_to_end(buf),
}
}
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
match &mut self.inner {
SpooledData::InMemory(cursor) => cursor.read_to_string(buf),
SpooledData::OnDisk(file) => file.read_to_string(buf),
}
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
match &mut self.inner {
SpooledData::InMemory(cursor) => cursor.read_exact(buf),
SpooledData::OnDisk(file) => file.read_exact(buf),
}
}
}
@ -124,35 +155,49 @@ impl Read for SpooledTempFile {
impl Write for SpooledTempFile {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// roll over to file if necessary
let mut rolling = false;
if let SpooledData::InMemory(ref mut cursor) = self.inner {
rolling = cursor.position() as usize + buf.len() > self.max_size;
}
if rolling {
if matches! {
&self.inner, SpooledData::InMemory(cursor)
if cursor.position() as usize + buf.len() > self.max_size
} {
self.roll()?;
}
// write the bytes
match self.inner {
SpooledData::InMemory(ref mut cursor) => cursor.write(buf),
SpooledData::OnDisk(ref mut file) => file.write(buf),
match &mut self.inner {
SpooledData::InMemory(cursor) => cursor.write(buf),
SpooledData::OnDisk(file) => file.write(buf),
}
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
if matches! {
&self.inner, SpooledData::InMemory(cursor)
// Borrowed from the rust standard library.
if cursor.position() as usize + bufs.iter()
.fold(0usize, |a, b| a.saturating_add(b.len())) > self.max_size
} {
self.roll()?;
}
match &mut self.inner {
SpooledData::InMemory(cursor) => cursor.write_vectored(bufs),
SpooledData::OnDisk(file) => file.write_vectored(bufs),
}
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
match self.inner {
SpooledData::InMemory(ref mut cursor) => cursor.flush(),
SpooledData::OnDisk(ref mut file) => file.flush(),
match &mut self.inner {
SpooledData::InMemory(cursor) => cursor.flush(),
SpooledData::OnDisk(file) => file.flush(),
}
}
}
impl Seek for SpooledTempFile {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match self.inner {
SpooledData::InMemory(ref mut cursor) => cursor.seek(pos),
SpooledData::OnDisk(ref mut file) => file.seek(pos),
match &mut self.inner {
SpooledData::InMemory(cursor) => cursor.seek(pos),
SpooledData::OnDisk(file) => file.seek(pos),
}
}
}

15
third_party/rust/tempfile/src/util.rs поставляемый
Просмотреть файл

@ -1,4 +1,3 @@
use fastrand;
use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf};
use std::{io, iter::repeat_with};
@ -16,16 +15,13 @@ fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> OsString {
buf
}
pub fn create_helper<F, R>(
pub fn create_helper<R>(
base: &Path,
prefix: &OsStr,
suffix: &OsStr,
random_len: usize,
f: F,
) -> io::Result<R>
where
F: Fn(PathBuf) -> io::Result<R>,
{
mut f: impl FnMut(PathBuf) -> io::Result<R>,
) -> io::Result<R> {
let num_retries = if random_len != 0 {
crate::NUM_RETRIES
} else {
@ -35,7 +31,10 @@ where
for _ in 0..num_retries {
let path = base.join(tmpname(prefix, suffix, random_len));
return match f(path) {
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists && num_retries > 1 => continue,
// AddrInUse can happen if we're creating a UNIX domain socket and
// the path already exists.
Err(ref e) if e.kind() == io::ErrorKind::AddrInUse && num_retries > 1 => continue,
res => res,
};
}

Просмотреть файл

@ -11,6 +11,13 @@ fn exists<P: AsRef<Path>>(path: P) -> bool {
std::fs::metadata(path.as_ref()).is_ok()
}
#[test]
fn test_prefix() {
let tmpfile = NamedTempFile::with_prefix("prefix").unwrap();
let name = tmpfile.path().file_name().unwrap().to_str().unwrap();
assert!(name.starts_with("prefix"));
}
#[test]
fn test_basic() {
let mut tmpfile = NamedTempFile::new().unwrap();
@ -87,7 +94,7 @@ fn test_persist_noclobber() {
fn test_customnamed() {
let tmpfile = Builder::new()
.prefix("tmp")
.suffix(&".rs".to_string())
.suffix(&".rs")
.rand_bytes(12)
.tempfile()
.unwrap();
@ -100,9 +107,9 @@ fn test_customnamed() {
#[test]
fn test_append() {
let mut tmpfile = Builder::new().append(true).tempfile().unwrap();
tmpfile.write(b"a").unwrap();
tmpfile.write_all(b"a").unwrap();
tmpfile.seek(SeekFrom::Start(0)).unwrap();
tmpfile.write(b"b").unwrap();
tmpfile.write_all(b"b").unwrap();
tmpfile.seek(SeekFrom::Start(0)).unwrap();
let mut buf = vec![0u8; 1];
@ -298,6 +305,18 @@ fn test_into_parts() {
assert_eq!("abcdefgh", buf);
}
#[test]
fn test_from_parts() {
let mut file = NamedTempFile::new().unwrap();
write!(file, "abcd").expect("write failed");
let (file, temp_path) = file.into_parts();
let file = NamedTempFile::from_parts(file, temp_path);
assert!(file.path().exists());
}
#[test]
fn test_keep() {
let mut tmpfile = NamedTempFile::new().unwrap();
@ -326,3 +345,129 @@ fn test_keep() {
}
std::fs::remove_file(&path).unwrap();
}
#[test]
fn test_make() {
let tmpfile = Builder::new().make(|path| File::create(path)).unwrap();
assert!(tmpfile.path().is_file());
}
#[test]
fn test_make_in() {
let tmp_dir = tempdir().unwrap();
let tmpfile = Builder::new()
.make_in(tmp_dir.path(), |path| File::create(path))
.unwrap();
assert!(tmpfile.path().is_file());
assert_eq!(tmpfile.path().parent(), Some(tmp_dir.path()));
}
#[test]
fn test_make_fnmut() {
let mut count = 0;
// Show that an FnMut can be used.
let tmpfile = Builder::new()
.make(|path| {
count += 1;
File::create(path)
})
.unwrap();
assert!(tmpfile.path().is_file());
}
#[cfg(unix)]
#[test]
fn test_make_uds() {
use std::os::unix::net::UnixListener;
let temp_sock = Builder::new()
.prefix("tmp")
.suffix(".sock")
.rand_bytes(12)
.make(|path| UnixListener::bind(path))
.unwrap();
assert!(temp_sock.path().exists());
}
#[cfg(unix)]
#[test]
fn test_make_uds_conflict() {
use std::os::unix::net::UnixListener;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
// Check that retries happen correctly by racing N different threads.
const NTHREADS: usize = 20;
// The number of times our callback was called.
let tries = Arc::new(AtomicUsize::new(0));
let mut threads = Vec::with_capacity(NTHREADS);
for _ in 0..NTHREADS {
let tries = tries.clone();
threads.push(std::thread::spawn(move || {
// Ensure that every thread uses the same seed so we are guaranteed
// to retry. Note that fastrand seeds are thread-local.
fastrand::seed(42);
Builder::new()
.prefix("tmp")
.suffix(".sock")
.rand_bytes(12)
.make(|path| {
tries.fetch_add(1, Ordering::Relaxed);
UnixListener::bind(path)
})
}));
}
// Join all threads, but don't drop the temp file yet. Otherwise, we won't
// get a deterministic number of `tries`.
let sockets: Vec<_> = threads
.into_iter()
.map(|thread| thread.join().unwrap().unwrap())
.collect();
// Number of tries is exactly equal to (n*(n+1))/2.
assert_eq!(
tries.load(Ordering::Relaxed),
(NTHREADS * (NTHREADS + 1)) / 2
);
for socket in sockets {
assert!(socket.path().exists());
}
}
// Issue #224.
#[test]
fn test_overly_generic_bounds() {
pub struct Foo<T>(T);
impl<T> Foo<T>
where
T: Sync + Send + 'static,
for<'a> &'a T: Write + Read,
{
pub fn new(foo: T) -> Self {
Self(foo)
}
}
// Don't really need to run this. Only care if it compiles.
if let Ok(file) = File::open("i_do_not_exist") {
let mut f;
let _x = {
f = Foo::new(file);
&mut f
};
}
}

32
third_party/rust/tempfile/tests/spooled.rs поставляемый
Просмотреть файл

@ -10,7 +10,7 @@ fn test_automatic_rollover() {
let mut buf = Vec::new();
assert!(!t.is_rolled());
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 0);
assert_eq!(t.stream_position().unwrap(), 0);
assert_eq!(t.read_to_end(&mut buf).unwrap(), 0);
assert_eq!(buf.as_slice(), b"");
buf.clear();
@ -24,7 +24,7 @@ fn test_automatic_rollover() {
assert_eq!(t.write(b"fghijklmno").unwrap(), 10);
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 15);
assert_eq!(t.stream_position().unwrap(), 15);
assert!(t.is_rolled());
}
@ -32,13 +32,13 @@ fn test_automatic_rollover() {
fn test_explicit_rollover() {
let mut t = SpooledTempFile::new(100);
assert_eq!(t.write(b"abcdefghijklmnopqrstuvwxyz").unwrap(), 26);
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26);
assert_eq!(t.stream_position().unwrap(), 26);
assert!(!t.is_rolled());
// roll over explicitly
assert!(t.roll().is_ok());
assert!(t.is_rolled());
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26);
assert_eq!(t.stream_position().unwrap(), 26);
let mut buf = Vec::new();
assert_eq!(t.read_to_end(&mut buf).unwrap(), 0);
@ -48,7 +48,7 @@ fn test_explicit_rollover() {
assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(t.read_to_end(&mut buf).unwrap(), 26);
assert_eq!(buf.as_slice(), b"abcdefghijklmnopqrstuvwxyz");
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26);
assert_eq!(t.stream_position().unwrap(), 26);
}
// called by test_seek_{buffer, file}
@ -56,7 +56,7 @@ fn test_explicit_rollover() {
fn test_seek(t: &mut SpooledTempFile) {
assert_eq!(t.write(b"abcdefghijklmnopqrstuvwxyz").unwrap(), 26);
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26); // tell()
assert_eq!(t.stream_position().unwrap(), 26); // tell()
assert_eq!(t.seek(SeekFrom::Current(-1)).unwrap(), 25);
assert_eq!(t.seek(SeekFrom::Current(1)).unwrap(), 26);
assert_eq!(t.seek(SeekFrom::Current(1)).unwrap(), 27);
@ -110,7 +110,7 @@ fn test_seek_read(t: &mut SpooledTempFile) {
buf.clear();
// now we're at the end again
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26); // tell()
assert_eq!(t.stream_position().unwrap(), 26); // tell()
assert_eq!(t.read_to_end(&mut buf).unwrap(), 0);
assert_eq!(buf.as_slice(), b"");
buf.clear();
@ -122,7 +122,7 @@ fn test_seek_read(t: &mut SpooledTempFile) {
assert_eq!(buf, *b"fghij");
// read again from current spot
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 10); // tell()
assert_eq!(t.stream_position().unwrap(), 10); // tell()
assert!(t.read_exact(&mut buf).is_ok());
assert_eq!(buf, *b"klmno");
@ -190,11 +190,11 @@ fn test_overwrite_and_extend_rollover() {
assert_eq!(t.write(b"abcdefghijklmno").unwrap(), 15);
assert!(!t.is_rolled());
assert_eq!(t.seek(SeekFrom::End(-5)).unwrap(), 10);
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 10); // tell()
assert_eq!(t.stream_position().unwrap(), 10); // tell()
assert!(!t.is_rolled());
assert_eq!(t.write(b"0123456789)!@#$%^&*(").unwrap(), 20);
assert!(t.is_rolled());
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 30); // tell()
assert_eq!(t.stream_position().unwrap(), 30); // tell()
let mut buf = Vec::new();
assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(t.read_to_end(&mut buf).unwrap(), 30);
@ -247,11 +247,11 @@ fn test_set_len(t: &mut SpooledTempFile) {
assert!(t.set_len(10).is_ok());
// position should not have moved
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26); // tell()
assert_eq!(t.stream_position().unwrap(), 26); // tell()
assert_eq!(t.read_to_end(&mut buf).unwrap(), 0);
assert_eq!(buf.as_slice(), b"");
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26); // tell()
assert_eq!(t.stream_position().unwrap(), 26); // tell()
buf.clear();
// read whole thing
@ -262,7 +262,7 @@ fn test_set_len(t: &mut SpooledTempFile) {
// set_len to expand beyond the end
assert!(t.set_len(40).is_ok());
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 10); // tell()
assert_eq!(t.stream_position().unwrap(), 10); // tell()
assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(t.read_to_end(&mut buf).unwrap(), 40);
assert_eq!(
@ -290,17 +290,17 @@ fn test_set_len_rollover() {
let mut t = spooled_tempfile(10);
assert_eq!(t.write(b"abcde").unwrap(), 5);
assert!(!t.is_rolled());
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 5); // tell()
assert_eq!(t.stream_position().unwrap(), 5); // tell()
assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(t.read_to_end(&mut buf).unwrap(), 5);
assert_eq!(buf.as_slice(), b"abcde");
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 5); // tell()
assert_eq!(t.stream_position().unwrap(), 5); // tell()
buf.clear();
assert!(t.set_len(20).is_ok());
assert!(t.is_rolled());
assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 5); // tell()
assert_eq!(t.stream_position().unwrap(), 5); // tell()
assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(t.read_to_end(&mut buf).unwrap(), 20);
assert_eq!(buf.as_slice(), b"abcde\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");

147
third_party/rust/tempfile/tests/tempdir.rs поставляемый
Просмотреть файл

@ -18,32 +18,9 @@ use std::thread;
use tempfile::{Builder, TempDir};
macro_rules! t {
($e:expr) => {
match $e {
Ok(n) => n,
Err(e) => panic!("error: {}", e),
}
};
}
trait PathExt {
fn exists(&self) -> bool;
fn is_dir(&self) -> bool;
}
impl PathExt for Path {
fn exists(&self) -> bool {
fs::metadata(self).is_ok()
}
fn is_dir(&self) -> bool {
fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
}
}
fn test_tempdir() {
let path = {
let p = t!(Builder::new().prefix("foobar").tempdir_in(&Path::new(".")));
let p = Builder::new().prefix("foobar").tempdir_in(".").unwrap();
let p = p.path();
assert!(p.to_str().unwrap().contains("foobar"));
p.to_path_buf()
@ -51,7 +28,12 @@ fn test_tempdir() {
assert!(!path.exists());
}
#[test]
fn test_prefix() {
let tmpfile = TempDir::with_prefix_in("prefix", ".").unwrap();
let name = tmpfile.path().file_name().unwrap().to_str().unwrap();
assert!(name.starts_with("prefix"));
}
fn test_customnamed() {
let tmpfile = Builder::new()
.prefix("prefix")
@ -67,8 +49,8 @@ fn test_customnamed() {
fn test_rm_tempdir() {
let (tx, rx) = channel();
let f = move || -> () {
let tmp = t!(TempDir::new());
let f = move || {
let tmp = TempDir::new().unwrap();
tx.send(tmp.path().to_path_buf()).unwrap();
panic!("panic to unwind past `tmp`");
};
@ -76,9 +58,9 @@ fn test_rm_tempdir() {
let path = rx.recv().unwrap();
assert!(!path.exists());
let tmp = t!(TempDir::new());
let tmp = TempDir::new().unwrap();
let path = tmp.path().to_path_buf();
let f = move || -> () {
let f = move || {
let _tmp = tmp;
panic!("panic to unwind past `tmp`");
};
@ -87,7 +69,7 @@ fn test_rm_tempdir() {
let path;
{
let f = move || t!(TempDir::new());
let f = move || TempDir::new().unwrap();
let tmp = thread::spawn(f).join().unwrap();
path = tmp.path().to_path_buf();
@ -97,31 +79,31 @@ fn test_rm_tempdir() {
let path;
{
let tmp = t!(TempDir::new());
let tmp = TempDir::new().unwrap();
path = tmp.into_path();
}
assert!(path.exists());
t!(fs::remove_dir_all(&path));
fs::remove_dir_all(&path).unwrap();
assert!(!path.exists());
}
fn test_rm_tempdir_close() {
let (tx, rx) = channel();
let f = move || -> () {
let tmp = t!(TempDir::new());
let f = move || {
let tmp = TempDir::new().unwrap();
tx.send(tmp.path().to_path_buf()).unwrap();
t!(tmp.close());
tmp.close().unwrap();
panic!("panic when unwinding past `tmp`");
};
let _ = thread::spawn(f).join();
let path = rx.recv().unwrap();
assert!(!path.exists());
let tmp = t!(TempDir::new());
let tmp = TempDir::new().unwrap();
let path = tmp.path().to_path_buf();
let f = move || -> () {
let f = move || {
let tmp = tmp;
t!(tmp.close());
tmp.close().unwrap();
panic!("panic when unwinding past `tmp`");
};
let _ = thread::spawn(f).join();
@ -129,96 +111,31 @@ fn test_rm_tempdir_close() {
let path;
{
let f = move || t!(TempDir::new());
let f = move || TempDir::new().unwrap();
let tmp = thread::spawn(f).join().unwrap();
path = tmp.path().to_path_buf();
assert!(path.exists());
t!(tmp.close());
tmp.close().unwrap();
}
assert!(!path.exists());
let path;
{
let tmp = t!(TempDir::new());
let tmp = TempDir::new().unwrap();
path = tmp.into_path();
}
assert!(path.exists());
t!(fs::remove_dir_all(&path));
fs::remove_dir_all(&path).unwrap();
assert!(!path.exists());
}
// Ideally these would be in std::os but then core would need
// to depend on std
fn recursive_mkdir_rel() {
let path = Path::new("frob");
let cwd = env::current_dir().unwrap();
println!(
"recursive_mkdir_rel: Making: {} in cwd {} [{}]",
path.display(),
cwd.display(),
path.exists()
);
t!(fs::create_dir(&path));
assert!(path.is_dir());
t!(fs::create_dir_all(&path));
assert!(path.is_dir());
}
fn recursive_mkdir_dot() {
let dot = Path::new(".");
t!(fs::create_dir_all(&dot));
let dotdot = Path::new("..");
t!(fs::create_dir_all(&dotdot));
}
fn recursive_mkdir_rel_2() {
let path = Path::new("./frob/baz");
let cwd = env::current_dir().unwrap();
println!(
"recursive_mkdir_rel_2: Making: {} in cwd {} [{}]",
path.display(),
cwd.display(),
path.exists()
);
t!(fs::create_dir_all(&path));
assert!(path.is_dir());
assert!(path.parent().unwrap().is_dir());
let path2 = Path::new("quux/blat");
println!(
"recursive_mkdir_rel_2: Making: {} in cwd {}",
path2.display(),
cwd.display()
);
t!(fs::create_dir("quux"));
t!(fs::create_dir_all(&path2));
assert!(path2.is_dir());
assert!(path2.parent().unwrap().is_dir());
}
// Ideally this would be in core, but needs TempFile
pub fn test_remove_dir_all_ok() {
let tmpdir = t!(TempDir::new());
let tmpdir = tmpdir.path();
let root = tmpdir.join("foo");
println!("making {}", root.display());
t!(fs::create_dir(&root));
t!(fs::create_dir(&root.join("foo")));
t!(fs::create_dir(&root.join("foo").join("bar")));
t!(fs::create_dir(&root.join("foo").join("bar").join("blat")));
t!(fs::remove_dir_all(&root));
assert!(!root.exists());
assert!(!root.join("bar").exists());
assert!(!root.join("bar").join("blat").exists());
}
pub fn dont_double_panic() {
fn dont_double_panic() {
let r: Result<(), _> = thread::spawn(move || {
let tmpdir = TempDir::new().unwrap();
// Remove the temporary directory so that TempDir sees
// an error on drop
t!(fs::remove_dir(tmpdir.path()));
fs::remove_dir(tmpdir.path()).unwrap();
// Panic. If TempDir panics *again* due to the rmdir
// error then the process will abort.
panic!();
@ -231,14 +148,14 @@ fn in_tmpdir<F>(f: F)
where
F: FnOnce(),
{
let tmpdir = t!(TempDir::new());
let tmpdir = TempDir::new().unwrap();
assert!(env::set_current_dir(tmpdir.path()).is_ok());
f();
}
pub fn pass_as_asref_path() {
let tempdir = t!(TempDir::new());
fn pass_as_asref_path() {
let tempdir = TempDir::new().unwrap();
takes_asref_path(&tempdir);
fn takes_asref_path<T: AsRef<Path>>(path: T) {
@ -250,12 +167,10 @@ pub fn pass_as_asref_path() {
#[test]
fn main() {
in_tmpdir(test_tempdir);
in_tmpdir(test_prefix);
in_tmpdir(test_customnamed);
in_tmpdir(test_rm_tempdir);
in_tmpdir(test_rm_tempdir_close);
in_tmpdir(recursive_mkdir_rel);
in_tmpdir(recursive_mkdir_dot);
in_tmpdir(recursive_mkdir_rel_2);
in_tmpdir(test_remove_dir_all_ok);
in_tmpdir(dont_double_panic);
in_tmpdir(pass_as_asref_path);
}

7
third_party/rust/tempfile/tests/tempfile.rs поставляемый
Просмотреть файл

@ -2,8 +2,11 @@
use std::fs;
use std::io::{Read, Seek, SeekFrom, Write};
use std::sync::mpsc::{sync_channel, TryRecvError};
use std::thread;
#[cfg(target_os = "linux")]
use std::{
sync::mpsc::{sync_channel, TryRecvError},
thread,
};
#[test]
fn test_basic() {

Просмотреть файл

@ -1895,7 +1895,6 @@ into source code and to files in the following directories:
<ul>
<li><code>browser/components/newtab/vendor/react-transition-group.js</code></li>
<li><code>third_party/rust/bindgen/</code></li>
<li><code>third_party/rust/instant/</code></li>
<li><code>third_party/rust/subtle/</code></li>
#ifdef MOZ_JXL
<li><code>third_party/jpeg-xl/</code></li>

Просмотреть файл

@ -104,9 +104,6 @@ url = "=2.1.0"
# Since we're building with at least rustc 1.63, enable rust 1.57 features (use of try_reserve methods).
fallible_collections = { version = "0.4", features = ["rust_1_57"] }
# Temporarily add an explicit dependency on rustix to vendor it.
rustix = "0.38"
[target.'cfg(not(target_os = "android"))'.dependencies]
viaduct = "0.1"
webext_storage_bridge = { path = "../../../components/extensions/storage/webext_storage_bridge" }