Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

572
vendor/same-file/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,572 @@
/*!
This crate provides a safe and simple **cross platform** way to determine
whether two file paths refer to the same file or directory.
Most uses of this crate should be limited to the top-level [`is_same_file`]
function, which takes two file paths and returns true if they refer to the
same file or directory:
```rust,no_run
# use std::error::Error;
use same_file::is_same_file;
# fn try_main() -> Result<(), Box<Error>> {
assert!(is_same_file("/bin/sh", "/usr/bin/sh")?);
# Ok(())
# }
#
# fn main() {
# try_main().unwrap();
# }
```
Additionally, this crate provides a [`Handle`] type that permits a more efficient
equality check depending on your access pattern. For example, if one wanted to
check whether any path in a list of paths corresponded to the process' stdout
handle, then one could build a handle once for stdout. The equality check for
each file in the list then only requires one stat call instead of two. The code
might look like this:
```rust,no_run
# use std::error::Error;
use same_file::Handle;
# fn try_main() -> Result<(), Box<Error>> {
let candidates = &[
"examples/is_same_file.rs",
"examples/is_stderr.rs",
"examples/stderr",
];
let stdout_handle = Handle::stdout()?;
for candidate in candidates {
let handle = Handle::from_path(candidate)?;
if stdout_handle == handle {
println!("{:?} is stdout!", candidate);
} else {
println!("{:?} is NOT stdout!", candidate);
}
}
# Ok(())
# }
#
# fn main() {
# try_main().unwrap();
# }
```
See [`examples/is_stderr.rs`] for a runnable example and compare the output of:
- `cargo run --example is_stderr 2> examples/stderr` and
- `cargo run --example is_stderr`.
[`is_same_file`]: fn.is_same_file.html
[`Handle`]: struct.Handle.html
[`examples/is_stderr.rs`]: https://github.com/BurntSushi/same-file/blob/master/examples/is_same_file.rs
*/
#![allow(bare_trait_objects, unknown_lints)]
#![deny(missing_docs)]
#[cfg(test)]
doc_comment::doctest!("../README.md");
use std::fs::File;
use std::io;
use std::path::Path;
#[cfg(any(target_os = "redox", unix))]
use crate::unix as imp;
#[cfg(not(any(target_os = "redox", unix, windows)))]
use unknown as imp;
#[cfg(windows)]
use win as imp;
#[cfg(any(target_os = "redox", unix))]
mod unix;
#[cfg(not(any(target_os = "redox", unix, windows)))]
mod unknown;
#[cfg(windows)]
mod win;
/// A handle to a file that can be tested for equality with other handles.
///
/// If two files are the same, then any two handles of those files will compare
/// equal. If two files are not the same, then any two handles of those files
/// will compare not-equal.
///
/// A handle consumes an open file resource as long as it exists.
///
/// Equality is determined by comparing inode numbers on Unix and a combination
/// of identifier, volume serial, and file size on Windows. Note that it's
/// possible for comparing two handles to produce a false positive on some
/// platforms. Namely, two handles can compare equal even if the two handles
/// *don't* point to the same file. Check the [source] for specific
/// implementation details.
///
/// [source]: https://github.com/BurntSushi/same-file/tree/master/src
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct Handle(imp::Handle);
impl Handle {
/// Construct a handle from a path.
///
/// Note that the underlying [`File`] is opened in read-only mode on all
/// platforms.
///
/// [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html
///
/// # Errors
/// This method will return an [`io::Error`] if the path cannot
/// be opened, or the file's metadata cannot be obtained.
/// The most common reasons for this are: the path does not
/// exist, or there were not enough permissions.
///
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
///
/// # Examples
/// Check that two paths are not the same file:
///
/// ```rust,no_run
/// # use std::error::Error;
/// use same_file::Handle;
///
/// # fn try_main() -> Result<(), Box<Error>> {
/// let source = Handle::from_path("./source")?;
/// let target = Handle::from_path("./target")?;
/// assert_ne!(source, target, "The files are the same.");
/// # Ok(())
/// # }
/// #
/// # fn main() {
/// # try_main().unwrap();
/// # }
/// ```
pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> {
imp::Handle::from_path(p).map(Handle)
}
/// Construct a handle from a file.
///
/// # Errors
/// This method will return an [`io::Error`] if the metadata for
/// the given [`File`] cannot be obtained.
///
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
/// [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html
///
/// # Examples
/// Check that two files are not in fact the same file:
///
/// ```rust,no_run
/// # use std::error::Error;
/// # use std::fs::File;
/// use same_file::Handle;
///
/// # fn try_main() -> Result<(), Box<Error>> {
/// let source = File::open("./source")?;
/// let target = File::open("./target")?;
///
/// assert_ne!(
/// Handle::from_file(source)?,
/// Handle::from_file(target)?,
/// "The files are the same."
/// );
/// # Ok(())
/// # }
/// #
/// # fn main() {
/// # try_main().unwrap();
/// # }
/// ```
pub fn from_file(file: File) -> io::Result<Handle> {
imp::Handle::from_file(file).map(Handle)
}
/// Construct a handle from stdin.
///
/// # Errors
/// This method will return an [`io::Error`] if stdin cannot
/// be opened due to any I/O-related reason.
///
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
///
/// # Examples
///
/// ```rust
/// # use std::error::Error;
/// use same_file::Handle;
///
/// # fn try_main() -> Result<(), Box<Error>> {
/// let stdin = Handle::stdin()?;
/// let stdout = Handle::stdout()?;
/// let stderr = Handle::stderr()?;
///
/// if stdin == stdout {
/// println!("stdin == stdout");
/// }
/// if stdin == stderr {
/// println!("stdin == stderr");
/// }
/// if stdout == stderr {
/// println!("stdout == stderr");
/// }
/// #
/// # Ok(())
/// # }
/// #
/// # fn main() {
/// # try_main().unwrap();
/// # }
/// ```
///
/// The output differs depending on the platform.
///
/// On Linux:
///
/// ```text
/// $ ./example
/// stdin == stdout
/// stdin == stderr
/// stdout == stderr
/// $ ./example > result
/// $ cat result
/// stdin == stderr
/// $ ./example > result 2>&1
/// $ cat result
/// stdout == stderr
/// ```
///
/// Windows:
///
/// ```text
/// > example
/// > example > result 2>&1
/// > type result
/// stdout == stderr
/// ```
pub fn stdin() -> io::Result<Handle> {
imp::Handle::stdin().map(Handle)
}
/// Construct a handle from stdout.
///
/// # Errors
/// This method will return an [`io::Error`] if stdout cannot
/// be opened due to any I/O-related reason.
///
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
///
/// # Examples
/// See the example for [`stdin()`].
///
/// [`stdin()`]: #method.stdin
pub fn stdout() -> io::Result<Handle> {
imp::Handle::stdout().map(Handle)
}
/// Construct a handle from stderr.
///
/// # Errors
/// This method will return an [`io::Error`] if stderr cannot
/// be opened due to any I/O-related reason.
///
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
///
/// # Examples
/// See the example for [`stdin()`].
///
/// [`stdin()`]: #method.stdin
pub fn stderr() -> io::Result<Handle> {
imp::Handle::stderr().map(Handle)
}
/// Return a reference to the underlying file.
///
/// # Examples
/// Ensure that the target file is not the same as the source one,
/// and copy the data to it:
///
/// ```rust,no_run
/// # use std::error::Error;
/// use std::io::prelude::*;
/// use std::io::Write;
/// use std::fs::File;
/// use same_file::Handle;
///
/// # fn try_main() -> Result<(), Box<Error>> {
/// let source = File::open("source")?;
/// let target = File::create("target")?;
///
/// let source_handle = Handle::from_file(source)?;
/// let mut target_handle = Handle::from_file(target)?;
/// assert_ne!(source_handle, target_handle, "The files are the same.");
///
/// let mut source = source_handle.as_file();
/// let target = target_handle.as_file_mut();
///
/// let mut buffer = Vec::new();
/// // data copy is simplified for the purposes of the example
/// source.read_to_end(&mut buffer)?;
/// target.write_all(&buffer)?;
/// #
/// # Ok(())
/// # }
/// #
/// # fn main() {
/// # try_main().unwrap();
/// # }
/// ```
pub fn as_file(&self) -> &File {
self.0.as_file()
}
/// Return a mutable reference to the underlying file.
///
/// # Examples
/// See the example for [`as_file()`].
///
/// [`as_file()`]: #method.as_file
pub fn as_file_mut(&mut self) -> &mut File {
self.0.as_file_mut()
}
/// Return the underlying device number of this handle.
///
/// Note that this only works on unix platforms.
#[cfg(any(target_os = "redox", unix))]
pub fn dev(&self) -> u64 {
self.0.dev()
}
/// Return the underlying inode number of this handle.
///
/// Note that this only works on unix platforms.
#[cfg(any(target_os = "redox", unix))]
pub fn ino(&self) -> u64 {
self.0.ino()
}
}
/// Returns true if the two file paths may correspond to the same file.
///
/// Note that it's possible for this to produce a false positive on some
/// platforms. Namely, this can return true even if the two file paths *don't*
/// resolve to the same file.
/// # Errors
/// This function will return an [`io::Error`] if any of the two paths cannot
/// be opened. The most common reasons for this are: the path does not exist,
/// or there were not enough permissions.
///
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
///
/// # Example
///
/// ```rust,no_run
/// use same_file::is_same_file;
///
/// assert!(is_same_file("./foo", "././foo").unwrap_or(false));
/// ```
pub fn is_same_file<P, Q>(path1: P, path2: Q) -> io::Result<bool>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
Ok(Handle::from_path(path1)? == Handle::from_path(path2)?)
}
#[cfg(test)]
mod tests {
use std::env;
use std::error;
use std::fs::{self, File};
use std::io;
use std::path::{Path, PathBuf};
use std::result;
use super::is_same_file;
type Result<T> = result::Result<T, Box<error::Error + Send + Sync>>;
/// Create an error from a format!-like syntax.
macro_rules! err {
($($tt:tt)*) => {
Box::<error::Error + Send + Sync>::from(format!($($tt)*))
}
}
/// A simple wrapper for creating a temporary directory that is
/// automatically deleted when it's dropped.
///
/// We use this in lieu of tempfile because tempfile brings in too many
/// dependencies.
#[derive(Debug)]
struct TempDir(PathBuf);
impl Drop for TempDir {
fn drop(&mut self) {
fs::remove_dir_all(&self.0).unwrap();
}
}
impl TempDir {
/// Create a new empty temporary directory under the system's
/// configured temporary directory.
fn new() -> Result<TempDir> {
#![allow(deprecated)]
use std::sync::atomic::{
AtomicUsize, Ordering, ATOMIC_USIZE_INIT,
};
static TRIES: usize = 100;
static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
let tmpdir = env::temp_dir();
for _ in 0..TRIES {
let count = COUNTER.fetch_add(1, Ordering::SeqCst);
let path = tmpdir.join("rust-walkdir").join(count.to_string());
if path.is_dir() {
continue;
}
fs::create_dir_all(&path).map_err(|e| {
err!("failed to create {}: {}", path.display(), e)
})?;
return Ok(TempDir(path));
}
Err(err!("failed to create temp dir after {} tries", TRIES))
}
/// Return the underlying path to this temporary directory.
fn path(&self) -> &Path {
&self.0
}
}
fn tmpdir() -> TempDir {
TempDir::new().unwrap()
}
#[cfg(unix)]
pub fn soft_link_dir<P: AsRef<Path>, Q: AsRef<Path>>(
src: P,
dst: Q,
) -> io::Result<()> {
use std::os::unix::fs::symlink;
symlink(src, dst)
}
#[cfg(unix)]
pub fn soft_link_file<P: AsRef<Path>, Q: AsRef<Path>>(
src: P,
dst: Q,
) -> io::Result<()> {
soft_link_dir(src, dst)
}
#[cfg(windows)]
pub fn soft_link_dir<P: AsRef<Path>, Q: AsRef<Path>>(
src: P,
dst: Q,
) -> io::Result<()> {
use std::os::windows::fs::symlink_dir;
symlink_dir(src, dst)
}
#[cfg(windows)]
pub fn soft_link_file<P: AsRef<Path>, Q: AsRef<Path>>(
src: P,
dst: Q,
) -> io::Result<()> {
use std::os::windows::fs::symlink_file;
symlink_file(src, dst)
}
// These tests are rather uninteresting. The really interesting tests
// would stress the edge cases. On Unix, this might be comparing two files
// on different mount points with the same inode number. On Windows, this
// might be comparing two files whose file indices are the same on file
// systems where such things aren't guaranteed to be unique.
//
// Alas, I don't know how to create those environmental conditions. ---AG
#[test]
fn same_file_trivial() {
let tdir = tmpdir();
let dir = tdir.path();
File::create(dir.join("a")).unwrap();
assert!(is_same_file(dir.join("a"), dir.join("a")).unwrap());
}
#[test]
fn same_dir_trivial() {
let tdir = tmpdir();
let dir = tdir.path();
fs::create_dir(dir.join("a")).unwrap();
assert!(is_same_file(dir.join("a"), dir.join("a")).unwrap());
}
#[test]
fn not_same_file_trivial() {
let tdir = tmpdir();
let dir = tdir.path();
File::create(dir.join("a")).unwrap();
File::create(dir.join("b")).unwrap();
assert!(!is_same_file(dir.join("a"), dir.join("b")).unwrap());
}
#[test]
fn not_same_dir_trivial() {
let tdir = tmpdir();
let dir = tdir.path();
fs::create_dir(dir.join("a")).unwrap();
fs::create_dir(dir.join("b")).unwrap();
assert!(!is_same_file(dir.join("a"), dir.join("b")).unwrap());
}
#[test]
fn same_file_hard() {
let tdir = tmpdir();
let dir = tdir.path();
File::create(dir.join("a")).unwrap();
fs::hard_link(dir.join("a"), dir.join("alink")).unwrap();
assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap());
}
#[test]
fn same_file_soft() {
let tdir = tmpdir();
let dir = tdir.path();
File::create(dir.join("a")).unwrap();
soft_link_file(dir.join("a"), dir.join("alink")).unwrap();
assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap());
}
#[test]
fn same_dir_soft() {
let tdir = tmpdir();
let dir = tdir.path();
fs::create_dir(dir.join("a")).unwrap();
soft_link_dir(dir.join("a"), dir.join("alink")).unwrap();
assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap());
}
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<super::Handle>();
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<super::Handle>();
}
}

112
vendor/same-file/src/unix.rs vendored Normal file
View File

@@ -0,0 +1,112 @@
use std::fs::{File, OpenOptions};
use std::hash::{Hash, Hasher};
use std::io;
use std::os::unix::fs::MetadataExt;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::path::Path;
#[derive(Debug)]
pub struct Handle {
file: Option<File>,
// If is_std is true, then we don't drop the corresponding File since it
// will close the handle.
is_std: bool,
dev: u64,
ino: u64,
}
impl Drop for Handle {
fn drop(&mut self) {
if self.is_std {
// unwrap() will not panic. Since we were able to open an
// std stream successfully, then `file` is guaranteed to be Some()
self.file.take().unwrap().into_raw_fd();
}
}
}
impl Eq for Handle {}
impl PartialEq for Handle {
fn eq(&self, other: &Handle) -> bool {
(self.dev, self.ino) == (other.dev, other.ino)
}
}
impl AsRawFd for crate::Handle {
fn as_raw_fd(&self) -> RawFd {
// unwrap() will not panic. Since we were able to open the
// file successfully, then `file` is guaranteed to be Some()
self.0.file.as_ref().take().unwrap().as_raw_fd()
}
}
impl IntoRawFd for crate::Handle {
fn into_raw_fd(mut self) -> RawFd {
// unwrap() will not panic. Since we were able to open the
// file successfully, then `file` is guaranteed to be Some()
self.0.file.take().unwrap().into_raw_fd()
}
}
impl Hash for Handle {
fn hash<H: Hasher>(&self, state: &mut H) {
self.dev.hash(state);
self.ino.hash(state);
}
}
impl Handle {
pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> {
Handle::from_file(OpenOptions::new().read(true).open(p)?)
}
pub fn from_file(file: File) -> io::Result<Handle> {
let md = file.metadata()?;
Ok(Handle {
file: Some(file),
is_std: false,
dev: md.dev(),
ino: md.ino(),
})
}
pub fn from_std(file: File) -> io::Result<Handle> {
Handle::from_file(file).map(|mut h| {
h.is_std = true;
h
})
}
pub fn stdin() -> io::Result<Handle> {
Handle::from_std(unsafe { File::from_raw_fd(0) })
}
pub fn stdout() -> io::Result<Handle> {
Handle::from_std(unsafe { File::from_raw_fd(1) })
}
pub fn stderr() -> io::Result<Handle> {
Handle::from_std(unsafe { File::from_raw_fd(2) })
}
pub fn as_file(&self) -> &File {
// unwrap() will not panic. Since we were able to open the
// file successfully, then `file` is guaranteed to be Some()
self.file.as_ref().take().unwrap()
}
pub fn as_file_mut(&mut self) -> &mut File {
// unwrap() will not panic. Since we were able to open the
// file successfully, then `file` is guaranteed to be Some()
self.file.as_mut().take().unwrap()
}
pub fn dev(&self) -> u64 {
self.dev
}
pub fn ino(&self) -> u64 {
self.ino
}
}

52
vendor/same-file/src/unknown.rs vendored Normal file
View File

@@ -0,0 +1,52 @@
use std::fs::File;
use std::io;
use std::path::Path;
static ERROR_MESSAGE: &str = "same-file is not supported on this platform.";
// This implementation is to allow same-file to be compiled on
// unsupported platforms in case it was incidentally included
// as a transitive, unused dependency
#[derive(Debug, Hash)]
pub struct Handle;
impl Eq for Handle {}
impl PartialEq for Handle {
fn eq(&self, _other: &Handle) -> bool {
unreachable!(ERROR_MESSAGE);
}
}
impl Handle {
pub fn from_path<P: AsRef<Path>>(_p: P) -> io::Result<Handle> {
error()
}
pub fn from_file(_file: File) -> io::Result<Handle> {
error()
}
pub fn stdin() -> io::Result<Handle> {
error()
}
pub fn stdout() -> io::Result<Handle> {
error()
}
pub fn stderr() -> io::Result<Handle> {
error()
}
pub fn as_file(&self) -> &File {
unreachable!(ERROR_MESSAGE);
}
pub fn as_file_mut(&self) -> &mut File {
unreachable!(ERROR_MESSAGE);
}
}
fn error<T>() -> io::Result<T> {
Err(io::Error::new(io::ErrorKind::Other, ERROR_MESSAGE))
}

172
vendor/same-file/src/win.rs vendored Normal file
View File

@@ -0,0 +1,172 @@
use std::fs::File;
use std::hash::{Hash, Hasher};
use std::io;
use std::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle};
use std::path::Path;
use winapi_util as winutil;
// For correctness, it is critical that both file handles remain open while
// their attributes are checked for equality. In particular, the file index
// numbers on a Windows stat object are not guaranteed to remain stable over
// time.
//
// See the docs and remarks on MSDN:
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788(v=vs.85).aspx
//
// It gets worse. It appears that the index numbers are not always
// guaranteed to be unique. Namely, ReFS uses 128 bit numbers for unique
// identifiers. This requires a distinct syscall to get `FILE_ID_INFO`
// documented here:
// https://msdn.microsoft.com/en-us/library/windows/desktop/hh802691(v=vs.85).aspx
//
// It seems straight-forward enough to modify this code to use
// `FILE_ID_INFO` when available (minimum Windows Server 2012), but I don't
// have access to such Windows machines.
//
// Two notes.
//
// 1. Java's NIO uses the approach implemented here and appears to ignore
// `FILE_ID_INFO` altogether. So Java's NIO and this code are
// susceptible to bugs when running on a file system where
// `nFileIndex{Low,High}` are not unique.
//
// 2. LLVM has a bug where they fetch the id of a file and continue to use
// it even after the handle has been closed, so that uniqueness is no
// longer guaranteed (when `nFileIndex{Low,High}` are unique).
// bug report: http://lists.llvm.org/pipermail/llvm-bugs/2014-December/037218.html
//
// All said and done, checking whether two files are the same on Windows
// seems quite tricky. Moreover, even if the code is technically incorrect,
// it seems like the chances of actually observing incorrect behavior are
// extremely small. Nevertheless, we mitigate this by checking size too.
//
// In the case where this code is erroneous, two files will be reported
// as equivalent when they are in fact distinct. This will cause the loop
// detection code to report a false positive, which will prevent descending
// into the offending directory. As far as failure modes goes, this isn't
// that bad.
#[derive(Debug)]
pub struct Handle {
kind: HandleKind,
key: Option<Key>,
}
#[derive(Debug)]
enum HandleKind {
/// Used when opening a file or acquiring ownership of a file.
Owned(winutil::Handle),
/// Used for stdio.
Borrowed(winutil::HandleRef),
}
#[derive(Debug, Eq, PartialEq, Hash)]
struct Key {
volume: u64,
index: u64,
}
impl Eq for Handle {}
impl PartialEq for Handle {
fn eq(&self, other: &Handle) -> bool {
// Need this branch to satisfy `Eq` since `Handle`s with
// `key.is_none()` wouldn't otherwise.
if self as *const Handle == other as *const Handle {
return true;
} else if self.key.is_none() || other.key.is_none() {
return false;
}
self.key == other.key
}
}
impl AsRawHandle for crate::Handle {
fn as_raw_handle(&self) -> RawHandle {
match self.0.kind {
HandleKind::Owned(ref h) => h.as_raw_handle(),
HandleKind::Borrowed(ref h) => h.as_raw_handle(),
}
}
}
impl IntoRawHandle for crate::Handle {
fn into_raw_handle(self) -> RawHandle {
match self.0.kind {
HandleKind::Owned(h) => h.into_raw_handle(),
HandleKind::Borrowed(h) => h.as_raw_handle(),
}
}
}
impl Hash for Handle {
fn hash<H: Hasher>(&self, state: &mut H) {
self.key.hash(state);
}
}
impl Handle {
pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> {
let h = winutil::Handle::from_path_any(p)?;
let info = winutil::file::information(&h)?;
Ok(Handle::from_info(HandleKind::Owned(h), info))
}
pub fn from_file(file: File) -> io::Result<Handle> {
let h = winutil::Handle::from_file(file);
let info = winutil::file::information(&h)?;
Ok(Handle::from_info(HandleKind::Owned(h), info))
}
fn from_std_handle(h: winutil::HandleRef) -> io::Result<Handle> {
match winutil::file::information(&h) {
Ok(info) => Ok(Handle::from_info(HandleKind::Borrowed(h), info)),
// In a Windows console, if there is no pipe attached to a STD
// handle, then GetFileInformationByHandle will return an error.
// We don't really care. The only thing we care about is that
// this handle is never equivalent to any other handle, which is
// accomplished by setting key to None.
Err(_) => Ok(Handle { kind: HandleKind::Borrowed(h), key: None }),
}
}
fn from_info(
kind: HandleKind,
info: winutil::file::Information,
) -> Handle {
Handle {
kind: kind,
key: Some(Key {
volume: info.volume_serial_number(),
index: info.file_index(),
}),
}
}
pub fn stdin() -> io::Result<Handle> {
Handle::from_std_handle(winutil::HandleRef::stdin())
}
pub fn stdout() -> io::Result<Handle> {
Handle::from_std_handle(winutil::HandleRef::stdout())
}
pub fn stderr() -> io::Result<Handle> {
Handle::from_std_handle(winutil::HandleRef::stderr())
}
pub fn as_file(&self) -> &File {
match self.kind {
HandleKind::Owned(ref h) => h.as_file(),
HandleKind::Borrowed(ref h) => h.as_file(),
}
}
pub fn as_file_mut(&mut self) -> &mut File {
match self.kind {
HandleKind::Owned(ref mut h) => h.as_file_mut(),
HandleKind::Borrowed(ref mut h) => h.as_file_mut(),
}
}
}