summaryrefslogtreecommitdiffstats
path: root/vendor/io-lifetimes/examples/owning-wrapper.rs
blob: 74a05b2f429eea7d1eaa086028f7f2d48debfd72 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! A simple example implementing the main traits for a type.

#![cfg_attr(io_lifetimes_use_std, feature(io_safety))]

use io_lifetimes::OwnedFilelike;
#[cfg(not(windows))]
use io_lifetimes::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd};
#[cfg(windows)]
use io_lifetimes::{AsHandle, BorrowedHandle, FromHandle, IntoHandle, OwnedHandle};

/// A wrapper around a file descriptor.
///
/// Implementing `AsFd`, `IntoFd`, and `FromFd` for a type that wraps an
/// `Owned*` is straightforward. `Owned*` types also automatically close the
/// handle in its `Drop`.
///
/// Should owning wrappers implement `AsRawFd`, `IntoRawFd`, and `FromRawFd`
/// too? They can, and there's no need to remove them from a type that already
/// implements them. But for new code, they can be omitted. Users that really
/// need the raw value can always do `as_fd().as_raw_fd()`,
/// `.into_fd().into_raw_fd()`, or `T::from_fd(OwnedFd::from_raw_fd(raw_fd))`.
/// But if possible, users should use just `as_fd`, `into_fd`, and `from_fd`
/// and avoid working with raw values altogether.
struct Thing {
    filelike: OwnedFilelike,
}

#[cfg(not(windows))]
impl AsFd for Thing {
    #[inline]
    fn as_fd(&self) -> BorrowedFd<'_> {
        self.filelike.as_fd()
    }
}

#[cfg(not(windows))]
impl IntoFd for Thing {
    #[inline]
    fn into_fd(self) -> OwnedFd {
        self.filelike
    }
}

#[cfg(not(io_lifetimes_use_std))]
#[cfg(not(windows))]
impl From<Thing> for OwnedFd {
    #[inline]
    fn from(owned: Thing) -> Self {
        owned.filelike
    }
}

#[cfg(not(windows))]
impl FromFd for Thing {
    #[inline]
    fn from_fd(filelike: OwnedFd) -> Self {
        Self { filelike }
    }
}

#[cfg(not(io_lifetimes_use_std))]
#[cfg(not(windows))]
impl From<OwnedFd> for Thing {
    #[inline]
    fn from(filelike: OwnedFd) -> Self {
        Self { filelike }
    }
}

#[cfg(windows)]
impl AsHandle for Thing {
    #[inline]
    fn as_handle(&self) -> BorrowedHandle<'_> {
        self.filelike.as_handle()
    }
}

#[cfg(windows)]
impl IntoHandle for Thing {
    #[inline]
    fn into_handle(self) -> OwnedHandle {
        self.filelike
    }
}

#[cfg(not(io_lifetimes_use_std))]
#[cfg(windows)]
impl From<Thing> for OwnedHandle {
    #[inline]
    fn from(owned: Thing) -> Self {
        owned.filelike
    }
}

#[cfg(windows)]
impl FromHandle for Thing {
    #[inline]
    fn from_handle(filelike: OwnedHandle) -> Self {
        Self { filelike }
    }
}

#[cfg(not(io_lifetimes_use_std))]
#[cfg(windows)]
impl From<OwnedHandle> for Thing {
    #[inline]
    fn from(filelike: OwnedHandle) -> Self {
        Self { filelike }
    }
}

#[cfg(feature = "close")]
fn main() {
    use io_lifetimes::{AsFilelike, FromFilelike, IntoFilelike};

    // Minimally exercise `Thing`'s Posix-ish API.
    #[cfg(not(windows))]
    {
        let file = std::fs::File::open("Cargo.toml").unwrap();
        let thing = Thing::from_into_fd(file);
        let _ = thing.as_fd();
        let _ = thing.into_fd();
    }

    // Minimally exercise `Thing`'s Windows API.
    #[cfg(windows)]
    {
        let file = std::fs::File::open("Cargo.toml").unwrap();
        let thing = Thing::from_into_handle(file);
        let _ = thing.as_handle();
        let _ = thing.into_handle();
    }

    // Implementing the above traits makes the blanket impls for the portable
    // `Filelike` traits available too.
    {
        let file = std::fs::File::open("Cargo.toml").unwrap();
        let thing = Thing::from_into_filelike(file);
        let _ = thing.as_filelike();
        let _ = thing.into_filelike();
    }
}

#[cfg(not(feature = "close"))]
fn main() {
    println!("This example requires the \"close\" feature.");
}