io-extras-0.18.3/.cargo_vcs_info.json0000644000000001360000000000100130400ustar { "git": { "sha1": "c2e9e2f51b464ee9789d1c7f40210ff81ce99090" }, "path_in_vcs": "" }io-extras-0.18.3/CODE_OF_CONDUCT.md000064400000000000000000000066471046102023000144440ustar 00000000000000# Contributor Covenant Code of Conduct *Note*: this Code of Conduct pertains to individuals' behavior. Please also see the [Organizational Code of Conduct][OCoC]. ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Bytecode Alliance CoC team at [report@bytecodealliance.org](mailto:report@bytecodealliance.org). The CoC team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The CoC team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the Bytecode Alliance's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [OCoC]: https://github.com/sunfishcode/io-extras/blob/main/ORG_CODE_OF_CONDUCT.md [homepage]: https://www.contributor-covenant.org [version]: https://www.contributor-covenant.org/version/1/4/ io-extras-0.18.3/COPYRIGHT000064400000000000000000000015411046102023000131240ustar 00000000000000Short version for non-lawyers: `io-extras` is triple-licensed under Apache 2.0 with the LLVM Exception, Apache 2.0, and MIT terms. Longer version: Copyrights in the `io-extras` project are retained by their contributors. No copyright assignment is required to contribute to the `io-extras` project. Some files include code derived from Rust's `libstd`; see the comments in the code for details. Except as otherwise noted (below and/or in individual files), `io-extras` is licensed under: - the Apache License, Version 2.0, with the LLVM Exception or - the Apache License, Version 2.0 or , - or the MIT license or , at your option. io-extras-0.18.3/Cargo.lock0000644000000465740000000000100110330ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "addr2line" version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "async-channel" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", "event-listener 2.5.3", "futures-core", ] [[package]] name = "async-channel" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-executor" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", "slab", ] [[package]] name = "async-global-executor" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", "async-io", "async-lock", "blocking", "futures-lite", "once_cell", ] [[package]] name = "async-io" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ "async-lock", "cfg-if", "concurrent-queue", "futures-io", "futures-lite", "parking", "polling", "rustix", "slab", "tracing", "windows-sys 0.59.0", ] [[package]] name = "async-lock" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener 5.3.1", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-std" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" dependencies = [ "async-channel 1.9.0", "async-global-executor", "async-io", "async-lock", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", "futures-lite", "gloo-timers", "kv-log-macro", "log", "memchr", "once_cell", "pin-project-lite", "pin-utils", "slab", "wasm-bindgen-futures", ] [[package]] name = "async-task" version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", "windows-targets", ] [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blocking" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", "futures-lite", "piper", ] [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytes" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "concurrent-queue" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "errno" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "event-listener" version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] [[package]] name = "event-listener-strategy" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener 5.3.1", "pin-project-lite", ] [[package]] name = "fastrand" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "futures-channel" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", ] [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-io" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f1fa2f9765705486b33fd2acf1577f8ec449c2ba1f318ae5447697b7c08d210" dependencies = [ "fastrand", "futures-core", "futures-io", "parking", "pin-project-lite", ] [[package]] name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "gloo-timers" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", "js-sys", "wasm-bindgen", ] [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hermit-abi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "io-extras" version = "0.18.3" dependencies = [ "async-std", "io-lifetimes", "mio", "os_pipe", "socket2", "tokio", "windows-sys 0.52.0", ] [[package]] name = "io-lifetimes" version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a611371471e98973dbcab4e0ec66c31a10bc356eeb4d54a0e05eac8158fe38c" [[package]] name = "js-sys" version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] [[package]] name = "kv-log-macro" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" dependencies = [ "log", ] [[package]] name = "libc" version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" dependencies = [ "value-bag", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ "adler2", ] [[package]] name = "mio" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi 0.3.9", "libc", "log", "wasi", "windows-sys 0.52.0", ] [[package]] name = "object" version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "os_pipe" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" dependencies = [ "libc", "windows-sys 0.59.0", ] [[package]] name = "parking" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "pin-project-lite" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", "fastrand", "futures-io", ] [[package]] name = "polling" version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", "rustix", "tracing", "windows-sys 0.59.0", ] [[package]] name = "proc-macro2" version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" version = "0.38.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "signal-hook-registry" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "socket2" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "syn" version = "2.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tokio" version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" dependencies = [ "backtrace", "bytes", "libc", "mio", "pin-project-lite", "signal-hook-registry", "socket2", "windows-sys 0.52.0", ] [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" [[package]] name = "unicode-ident" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "value-bag" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" io-extras-0.18.3/Cargo.toml0000644000000041260000000000100110410ustar # 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 = "2021" rust-version = "1.63" name = "io-extras" version = "0.18.3" authors = ["Dan Gohman "] build = "build.rs" include = [ "src", "build.rs", "Cargo.toml", "COPYRIGHT", "LICENSE*", "/*.md", ] autobins = false autoexamples = false autotests = false autobenches = false description = "File/socket handle/descriptor utilities" readme = "README.md" keywords = [ "api", "io", "stream", ] categories = [ "os", "rust-patterns", ] license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" repository = "https://github.com/sunfishcode/io-extras" [lib] name = "io_extras" path = "src/lib.rs" [dependencies.async-std] version = "1.13.0" features = ["io_safety"] optional = true [dependencies.io-lifetimes] version = "2.0.0" [dependencies.mio] version = "1.0.2" optional = true [dependencies.os_pipe] version = "1.2.1" optional = true [dependencies.socket2] version = "0.5.7" optional = true [dependencies.tokio] version = "1.6.0" features = [ "io-std", "fs", "net", "process", ] optional = true [dev-dependencies.os_pipe] version = "1.0.0" [features] default = [] use_async_std = ["async-std"] use_mio_net = [ "mio", "mio/net", ] use_mio_os_ext = [ "mio", "mio/os-ext", ] use_os_pipe = ["os_pipe"] use_socket2 = ["socket2"] use_tokio = ["tokio"] [target."cfg(windows)".dependencies.windows-sys] version = "0.52.0" features = [ "Win32_Foundation", "Win32_Networking_WinSock", "Win32_System_Console", ] [lints.rust.unexpected_cfgs] level = "warn" priority = 0 check-cfg = [ "cfg(can_vector)", "cfg(write_all_vectored)", ] io-extras-0.18.3/Cargo.toml.orig000064400000000000000000000032011046102023000145130ustar 00000000000000[package] name = "io-extras" version = "0.18.3" description = "File/socket handle/descriptor utilities" authors = ["Dan Gohman "] edition = "2021" license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" keywords = ["api", "io", "stream"] categories = ["os", "rust-patterns"] repository = "https://github.com/sunfishcode/io-extras" include = ["src", "build.rs", "Cargo.toml", "COPYRIGHT", "LICENSE*", "/*.md"] rust-version = "1.63" [dependencies] io-lifetimes = "2.0.0" # Optionally depend on async-std to implement traits for its types. async-std = { version = "1.13.0", features = ["io_safety"], optional = true } # Optionally depend on tokio to implement traits for its types. tokio = { version = "1.6.0", features = ["io-std", "fs", "net", "process"], optional = true } # Optionally depend on os_pipe to implement traits for its types. os_pipe = { version = "1.2.1", optional = true } # Optionally depend on socket2 to implement traits for its types. socket2 = { version = "0.5.7", optional = true } # Optionally depend on mio to implement traits for its types. mio = { version = "1.0.2", optional = true } [target.'cfg(windows)'.dependencies.windows-sys] version = "0.52.0" features = [ "Win32_Foundation", "Win32_Networking_WinSock", "Win32_System_Console", ] [dev-dependencies] os_pipe = "1.0.0" [features] default = [] use_mio_net = ["mio", "mio/net"] use_mio_os_ext = ["mio", "mio/os-ext"] use_async_std = ["async-std"] use_tokio = ["tokio"] use_socket2 = ["socket2"] use_os_pipe = ["os_pipe"] [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ 'cfg(can_vector)', 'cfg(write_all_vectored)' ] io-extras-0.18.3/LICENSE-APACHE000064400000000000000000000251371046102023000135640ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. io-extras-0.18.3/LICENSE-Apache-2.0_WITH_LLVM-exception000064400000000000000000000277231046102023000200050ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. io-extras-0.18.3/LICENSE-MIT000064400000000000000000000017771046102023000133000ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. io-extras-0.18.3/ORG_CODE_OF_CONDUCT.md000064400000000000000000000160721046102023000151440ustar 00000000000000# Bytecode Alliance Organizational Code of Conduct (OCoC) *Note*: this Code of Conduct pertains to organizations' behavior. Please also see the [Individual Code of Conduct](CODE_OF_CONDUCT.md). ## Preamble The Bytecode Alliance (BA) welcomes involvement from organizations, including commercial organizations. This document is an *organizational* code of conduct, intended particularly to provide guidance to commercial organizations. It is distinct from the [Individual Code of Conduct (ICoC)](CODE_OF_CONDUCT.md), and does not replace the ICoC. This OCoC applies to any group of people acting in concert as a BA member or as a participant in BA activities, whether or not that group is formally incorporated in some jurisdiction. The code of conduct described below is not a set of rigid rules, and we did not write it to encompass every conceivable scenario that might arise. For example, it is theoretically possible there would be times when asserting patents is in the best interest of the BA community as a whole. In such instances, consult with the BA, strive for consensus, and interpret these rules with an intent that is generous to the community the BA serves. While we may revise these guidelines from time to time based on real-world experience, overall they are based on a simple principle: *Bytecode Alliance members should observe the distinction between public community functions and private functions — especially commercial ones — and should ensure that the latter support, or at least do not harm, the former.* ## Guidelines * **Do not cause confusion about Wasm standards or interoperability.** Having an interoperable WebAssembly core is a high priority for the BA, and members should strive to preserve that core. It is fine to develop additional non-standard features or APIs, but they should always be clearly distinguished from the core interoperable Wasm. Treat the WebAssembly name and any BA-associated names with respect, and follow BA trademark and branding guidelines. If you distribute a customized version of software originally produced by the BA, or if you build a product or service using BA-derived software, use names that clearly distinguish your work from the original. (You should still provide proper attribution to the original, of course, wherever such attribution would normally be given.) Further, do not use the WebAssembly name or BA-associated names in other public namespaces in ways that could cause confusion, e.g., in company names, names of commercial service offerings, domain names, publicly-visible social media accounts or online service accounts, etc. It may sometimes be reasonable, however, to register such a name in a new namespace and then immediately donate control of that account to the BA, because that would help the project maintain its identity. For further guidance, see the BA Trademark and Branding Policy [TODO: create policy, then insert link]. * **Do not restrict contributors.** If your company requires employees or contractors to sign non-compete agreements, those agreements must not prevent people from participating in the BA or contributing to related projects. This does not mean that all non-compete agreements are incompatible with this code of conduct. For example, a company may restrict an employee's ability to solicit the company's customers. However, an agreement must not block any form of technical or social participation in BA activities, including but not limited to the implementation of particular features. The accumulation of experience and expertise in individual persons, who are ultimately free to direct their energy and attention as they decide, is one of the most important drivers of progress in open source projects. A company that limits this freedom may hinder the success of the BA's efforts. * **Do not use patents as offensive weapons.** If any BA participant prevents the adoption or development of BA technologies by asserting its patents, that undermines the purpose of the coalition. The collaboration fostered by the BA cannot include members who act to undermine its work. * **Practice responsible disclosure** for security vulnerabilities. Use designated, non-public reporting channels to disclose technical vulnerabilities, and give the project a reasonable period to respond, remediate, and patch. [TODO: optionally include the security vulnerability reporting URL here.] Vulnerability reporters may patch their company's own offerings, as long as that patching does not significantly delay the reporting of the vulnerability. Vulnerability information should never be used for unilateral commercial advantage. Vendors may legitimately compete on the speed and reliability with which they deploy security fixes, but withholding vulnerability information damages everyone in the long run by risking harm to the BA project's reputation and to the security of all users. * **Respect the letter and spirit of open source practice.** While there is not space to list here all possible aspects of standard open source practice, some examples will help show what we mean: * Abide by all applicable open source license terms. Do not engage in copyright violation or misattribution of any kind. * Do not claim others' ideas or designs as your own. * When others engage in publicly visible work (e.g., an upcoming demo that is coordinated in a public issue tracker), do not unilaterally announce early releases or early demonstrations of that work ahead of their schedule in order to secure private advantage (such as marketplace advantage) for yourself. The BA reserves the right to determine what constitutes good open source practices and to take action as it deems appropriate to encourage, and if necessary enforce, such practices. ## Enforcement Instances of organizational behavior in violation of the OCoC may be reported by contacting the Bytecode Alliance CoC team at [report@bytecodealliance.org](mailto:report@bytecodealliance.org). The CoC team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The CoC team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. When the BA deems an organization in violation of this OCoC, the BA will, at its sole discretion, determine what action to take. The BA will decide what type, degree, and duration of corrective action is needed, if any, before a violating organization can be considered for membership (if it was not already a member) or can have its membership reinstated (if it was a member and the BA canceled its membership due to the violation). In practice, the BA's first approach will be to start a conversation, with punitive enforcement used only as a last resort. Violations often turn out to be unintentional and swiftly correctable with all parties acting in good faith. io-extras-0.18.3/README.md000064400000000000000000000026441046102023000131150ustar 00000000000000

io-extras

File/socket handle/descriptor utilities

Github Actions CI Status crates.io page docs.rs docs

This crate provides a few miscellaneous utilities related to I/O: - `HandleOrSocket` types and traits for Windows, which abstract over Windows `*Handle*` and their corresponding Windows `*Socket*` types and traits. - `Grip` types and traits, which abstract over the aforementioned Windows `HandleOrSocket` types and traits and their corresponding non-Windows `Fd` types and traits. - `RawReadable` and `RawWritable`, which adapt a raw `Fd`/`Handle` to implement the `Read` and `Write` traits, respectively. - `ReadWrite` traits, and supporting types, which provide abstractions over types with one or two I/O resources, for reading and for writing. ## Minimum Supported Rust Version (MSRV) This crate currently works on Rust 1.63, when default features are enabled. Some of the optional features have stricter requirements. io-extras-0.18.3/SECURITY.md000064400000000000000000000034571046102023000134320ustar 00000000000000# Security Policy Building secure foundations for software development is at the core of what we do in the Bytecode Alliance. Contributions of external security researchers are a vital part of that. ## Scope If you believe you've found a security issue in any website, service, or software owned or operated by the Bytecode Alliance, we encourage you to notify us. ## How to Submit a Report To submit a vulnerability report to the Bytecode Alliance, please contact us at [security@bytecodealliance.org](mailto:security@bytecodealliance.org). Your submission will be reviewed and validated by a member of our security team. ## Safe Harbor The Bytecode Alliance supports safe harbor for security researchers who: * Make a good faith effort to avoid privacy violations, destruction of data, and interruption or degradation of our services. * Only interact with accounts you own or with explicit permission of the account holder. If you do encounter Personally Identifiable Information (PII) contact us immediately, do not proceed with access, and immediately purge any local information. * Provide us with a reasonable amount of time to resolve vulnerabilities prior to any disclosure to the public or a third-party. We will consider activities conducted consistent with this policy to constitute "authorized" conduct and will not pursue civil action or initiate a complaint to law enforcement. We will help to the extent we can if legal action is initiated by a third party against you. Please submit a report to us before engaging in conduct that may be inconsistent with or unaddressed by this policy. ## Preferences * Please provide detailed reports with reproducible steps and a clearly defined impact. * Submit one vulnerability per report. * Social engineering (e.g. phishing, vishing, smishing) is prohibited. io-extras-0.18.3/build.rs000064400000000000000000000051401046102023000132750ustar 00000000000000use std::env::var; use std::io::Write; fn main() { use_feature_or_nothing("can_vector"); // https://github.com/rust-lang/rust/issues/69941 use_feature_or_nothing("write_all_vectored"); // https://github.com/rust-lang/rust/issues/70436 use_feature("io_lifetimes_use_std"); // Don't rerun this on changes other than build.rs, as we only depend on // the rustc version. println!("cargo:rerun-if-changed=build.rs"); } fn use_feature_or_nothing(feature: &str) { if has_feature(feature) { use_feature(feature); } } fn use_feature(feature: &str) { println!("cargo:rustc-cfg={}", feature); } /// Test whether the rustc at `var("RUSTC")` supports the given feature. fn has_feature(feature: &str) -> bool { can_compile(format!( "#![allow(stable_features)]\n#![feature({})]", feature )) } /// Test whether the rustc at `var("RUSTC")` can compile the given code. fn can_compile>(test: T) -> bool { use std::process::Stdio; let out_dir = var("OUT_DIR").unwrap(); let rustc = var("RUSTC").unwrap(); let target = var("TARGET").unwrap(); // Use `RUSTC_WRAPPER` if it's set, unless it's set to an empty string, as // documented [here]. // [here]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-reads let wrapper = var("RUSTC_WRAPPER") .ok() .and_then(|w| if w.is_empty() { None } else { Some(w) }); let mut cmd = if let Some(wrapper) = wrapper { let mut cmd = std::process::Command::new(wrapper); // The wrapper's first argument is supposed to be the path to rustc. cmd.arg(rustc); cmd } else { std::process::Command::new(rustc) }; cmd.arg("--crate-type=rlib") // Don't require `main`. .arg("--emit=metadata") // Do as little as possible but still parse. .arg("--target") .arg(target) .arg("--out-dir") .arg(out_dir); // Put the output somewhere inconsequential. // If Cargo wants to set RUSTFLAGS, use that. if let Ok(rustflags) = var("CARGO_ENCODED_RUSTFLAGS") { if !rustflags.is_empty() { for arg in rustflags.split('\x1f') { cmd.arg(arg); } } } let mut child = cmd .arg("-") // Read from stdin. .stdin(Stdio::piped()) // Stdin is a pipe. .stderr(Stdio::null()) // Errors from feature detection aren't interesting and can be confusing. .spawn() .unwrap(); writeln!(child.stdin.take().unwrap(), "{}", test.as_ref()).unwrap(); child.wait().unwrap().success() } io-extras-0.18.3/src/borrowed.rs000064400000000000000000000177511046102023000146230ustar 00000000000000//! `BorrowedReadable` and `BorrowedWriteable`. use crate::grip::{AsRawGrip, BorrowedGrip, FromRawGrip}; #[cfg(windows)] use crate::os::windows::{AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket}; use crate::raw::{RawReadable, RawWriteable}; #[cfg(not(windows))] use io_lifetimes::{AsFd, BorrowedFd}; use std::fmt; use std::io::{self, IoSlice, IoSliceMut, Read, Write}; use std::marker::PhantomData; #[cfg(all(doc, not(windows)))] use std::net::TcpStream; #[cfg(unix)] use std::os::unix::io::AsRawFd; #[cfg(target_os = "wasi")] use std::os::wasi::io::AsRawFd; /// An owning I/O handle that implements [`Read`]. /// /// This doesn't implement `Into*` or `From*` traits. /// /// # Platform-specific behavior /// /// On Posix-ish platforms, this reads from the handle as if it were a /// [`File`]. On Windows, this reads from a file-like handle as if it were a /// [`File`], and from a socket-like handle as if it were a [`TcpStream`]. #[repr(transparent)] pub struct BorrowedReadable<'a> { raw: RawReadable, _phantom: PhantomData<&'a ()>, } /// An owning I/O handle that implements [`Write`]. /// /// This doesn't implement `Into*` or `From*` traits. /// /// # Platform-specific behavior /// /// On Posix-ish platforms, this writes to the handle as if it were a /// [`File`]. On Windows, this writes to a file-like handle as if it were a /// [`File`], and to a socket-like handle as if it were a [`TcpStream`]. #[repr(transparent)] pub struct BorrowedWriteable<'a> { raw: RawWriteable, _phantom: PhantomData<&'a ()>, } impl<'a> BorrowedReadable<'a> { /// Create a `BorrowedReadable` that can read from a `BorrowedGrip`. #[must_use] #[inline] pub fn borrow(grip: BorrowedGrip<'a>) -> Self { Self { raw: unsafe { RawReadable::from_raw_grip(grip.as_raw_grip()) }, _phantom: PhantomData, } } } impl<'a> BorrowedWriteable<'a> { /// Create a `BorrowedReadable` that can write to a `BorrowedGrip`. #[must_use] #[inline] pub fn borrow(grip: BorrowedGrip<'a>) -> Self { Self { raw: unsafe { RawWriteable::from_raw_grip(grip.as_raw_grip()) }, _phantom: PhantomData, } } } /// `BorrowedReadable` borrows its handle. #[cfg(not(windows))] impl<'a> AsFd for BorrowedReadable<'a> { #[inline] fn as_fd(&self) -> BorrowedFd<'a> { unsafe { BorrowedFd::borrow_raw(self.raw.as_raw_fd()) } } } /// `BorrowedWriteable` borrows its handle. #[cfg(not(windows))] impl<'a> AsFd for BorrowedWriteable<'a> { #[inline] fn as_fd(&self) -> BorrowedFd<'a> { unsafe { BorrowedFd::borrow_raw(self.raw.as_raw_fd()) } } } // Windows implementations. /// `BorrowedReadable` borrows its handle. #[cfg(windows)] impl<'a> AsHandleOrSocket for BorrowedReadable<'a> { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'a> { unsafe { BorrowedHandleOrSocket::borrow_raw(self.raw.as_raw_handle_or_socket()) } } } /// `BorrowedWriteable` borrows its handle. #[cfg(windows)] impl<'a> AsHandleOrSocket for BorrowedWriteable<'a> { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'a> { unsafe { BorrowedHandleOrSocket::borrow_raw(self.raw.as_raw_handle_or_socket()) } } } #[cfg(not(windows))] impl<'a> Read for BorrowedReadable<'a> { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.raw.read(buf) } #[inline] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.raw.read_vectored(bufs) } #[cfg(can_vector)] #[inline] fn is_read_vectored(&self) -> bool { self.raw.is_read_vectored() } #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.raw.read_to_end(buf) } #[inline] fn read_to_string(&mut self, buf: &mut String) -> io::Result { self.raw.read_to_string(buf) } #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { self.raw.read_exact(buf) } } #[cfg(windows)] impl<'a> Read for BorrowedReadable<'a> { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.raw.read(buf) } #[inline] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.raw.read_vectored(bufs) } #[cfg(can_vector)] #[inline] fn is_read_vectored(&self) -> bool { self.raw.is_read_vectored() } #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.raw.read_to_end(buf) } #[inline] fn read_to_string(&mut self, buf: &mut String) -> io::Result { self.raw.read_to_string(buf) } #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { self.raw.read_exact(buf) } } #[cfg(not(windows))] impl<'a> Write for BorrowedWriteable<'a> { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.raw.write(buf) } #[inline] fn flush(&mut self) -> io::Result<()> { self.raw.flush() } #[inline] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.raw.write_vectored(bufs) } #[cfg(can_vector)] #[inline] fn is_write_vectored(&self) -> bool { self.raw.is_write_vectored() } #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.raw.write_all(buf) } #[cfg(write_all_vectored)] #[inline] fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { self.raw.write_all_vectored(bufs) } #[inline] fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { self.raw.write_fmt(fmt) } } #[cfg(windows)] impl<'a> Write for BorrowedWriteable<'a> { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.raw.write(buf) } #[inline] fn flush(&mut self) -> io::Result<()> { self.raw.flush() } #[inline] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.raw.write_vectored(bufs) } #[cfg(can_vector)] #[inline] fn is_write_vectored(&self) -> bool { self.raw.is_write_vectored() } #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.raw.write_all(buf) } #[cfg(write_all_vectored)] #[inline] fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { self.raw.write_all_vectored(bufs) } #[inline] fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { self.raw.write_fmt(fmt) } } #[cfg(not(windows))] impl<'a> fmt::Debug for BorrowedReadable<'a> { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw fd number. f.debug_struct("BorrowedReadable") .field("fd", &self.raw) .finish() } } #[cfg(windows)] impl<'a> fmt::Debug for BorrowedReadable<'a> { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw handle or socket. f.debug_struct("BorrowedReadable") .field("handle_or_socket", &self.raw) .finish() } } #[cfg(not(windows))] impl<'a> fmt::Debug for BorrowedWriteable<'a> { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw fd number. f.debug_struct("BorrowedWriteable") .field("fd", &self.raw) .finish() } } #[cfg(windows)] impl<'a> fmt::Debug for BorrowedWriteable<'a> { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw handle or socket. f.debug_struct("BorrowedWriteable") .field("handle_or_socket", &self.raw) .finish() } } io-extras-0.18.3/src/grip.rs000064400000000000000000000243721046102023000137360ustar 00000000000000//! "Grip" is an abstraction over "Fd" and "HandleOrSocket". "Handle" //! would be the obvious term, but that has a more specific meaning on //! Windows. #[cfg(windows)] use crate::os::windows::{ AsHandleOrSocket, AsRawHandleOrSocket, AsRawReadWriteHandleOrSocket, AsReadWriteHandleOrSocket, BorrowedHandleOrSocket, FromRawHandleOrSocket, IntoRawHandleOrSocket, OwnedHandleOrSocket, RawHandleOrSocket, }; #[cfg(not(windows))] use { crate::os::rustix::{AsRawFd, AsRawReadWriteFd, AsReadWriteFd, FromRawFd, IntoRawFd, RawFd}, io_lifetimes::{AsFd, BorrowedFd, OwnedFd}, }; /// Portability abstraction over `BorrowedFd` and `BorrowedHandleOrSocket`. #[cfg(not(windows))] pub type BorrowedGrip<'a> = BorrowedFd<'a>; /// Portability abstraction over `OwnedFd` and `OwnedHandleOrSocket`. #[cfg(not(windows))] pub type OwnedGrip = OwnedFd; /// Portability abstraction over `BorrowedFd` and `BorrowedHandleOrSocket`. #[cfg(windows)] pub type BorrowedGrip<'a> = BorrowedHandleOrSocket<'a>; /// Portability abstraction over `OwnedFd` and `OwnedHandleOrSocket`. #[cfg(windows)] pub type OwnedGrip = OwnedHandleOrSocket; /// Portability abstraction over `AsFd` and `AsHandleOrSocket`. #[cfg(not(windows))] pub trait AsGrip: AsFd { /// Extracts the grip. fn as_grip(&self) -> BorrowedGrip<'_>; } /// Portability abstraction over `AsFd` and `AsHandleOrSocket`. #[cfg(windows)] pub trait AsGrip: AsHandleOrSocket { /// Extracts the grip. fn as_grip(&self) -> BorrowedGrip<'_>; } /// Portability abstraction over `AsReadWriteFd` and /// `AsReadWriteHandleOrSocket`. #[cfg(not(windows))] pub trait AsReadWriteGrip: AsReadWriteFd { /// Extracts the grip for reading. /// /// Like [`AsGrip::as_grip`], but returns the /// reading grip. fn as_read_grip(&self) -> BorrowedGrip<'_>; /// Extracts the grip for writing. /// /// Like [`AsGrip::as_grip`], but returns the /// writing grip. fn as_write_grip(&self) -> BorrowedGrip<'_>; } /// Portability abstraction over `AsReadWriteFd` and /// `AsReadWriteHandleOrSocket`. #[cfg(windows)] pub trait AsReadWriteGrip: AsReadWriteHandleOrSocket { /// Extracts the grip for reading. /// /// Like [`AsGrip::as_grip`], but returns the /// reading grip. fn as_read_grip(&self) -> BorrowedGrip<'_>; /// Extracts the grip for writing. /// /// Like [`AsGrip::as_grip`], but returns the /// writing grip. fn as_write_grip(&self) -> BorrowedGrip<'_>; } /// Portability abstraction over `Into` and /// `Into`. #[cfg(not(windows))] pub trait IntoGrip: Into { /// Consume `self` and convert into an `OwnedGrip`. fn into_grip(self) -> OwnedGrip; } /// Portability abstraction over `Into` and /// `Into`. #[cfg(windows)] pub trait IntoGrip: Into { /// Consume `self` and convert into an `OwnedGrip`. fn into_grip(self) -> OwnedGrip; } /// Portability abstraction over `From` and /// `From`. #[cfg(not(windows))] pub trait FromGrip: From { /// Consume an `OwnedGrip` and convert into a `Self`. fn from_grip(owned_grip: OwnedGrip) -> Self; } /// Portability abstraction over `From` and /// `From`. #[cfg(windows)] pub trait FromGrip: From { /// Consume an `OwnedGrip` and convert into a `Self`. fn from_grip(owned_grip: OwnedGrip) -> Self; } #[cfg(not(windows))] impl AsGrip for T { #[inline] fn as_grip(&self) -> BorrowedGrip<'_> { self.as_fd() } } #[cfg(windows)] impl AsGrip for T { #[inline] fn as_grip(&self) -> BorrowedGrip<'_> { self.as_handle_or_socket() } } #[cfg(not(windows))] impl AsReadWriteGrip for T { #[inline] fn as_read_grip(&self) -> BorrowedGrip<'_> { self.as_read_fd() } #[inline] fn as_write_grip(&self) -> BorrowedGrip<'_> { self.as_write_fd() } } #[cfg(windows)] impl AsReadWriteGrip for T { #[inline] fn as_read_grip(&self) -> BorrowedGrip<'_> { self.as_read_handle_or_socket() } #[inline] fn as_write_grip(&self) -> BorrowedGrip<'_> { self.as_write_handle_or_socket() } } #[cfg(not(windows))] impl> IntoGrip for T { #[inline] fn into_grip(self) -> OwnedGrip { self.into() } } #[cfg(windows)] impl> IntoGrip for T { #[inline] fn into_grip(self) -> OwnedGrip { self.into() } } #[cfg(not(windows))] impl> FromGrip for T { #[inline] fn from_grip(owned_grip: OwnedGrip) -> Self { Self::from(owned_grip) } } #[cfg(windows)] impl> FromGrip for T { #[inline] fn from_grip(owned_grip: OwnedGrip) -> Self { Self::from(owned_grip) } } /// Portability abstraction over `RawFd` and `RawHandleOrSocket`. #[cfg(not(windows))] pub type RawGrip = RawFd; /// Portability abstraction over `RawFd` and `RawHandleOrSocket`. #[cfg(windows)] pub type RawGrip = RawHandleOrSocket; /// Portability abstraction over `AsFd` and `AsHandleOrSocket`. #[cfg(not(windows))] pub trait AsRawGrip: AsRawFd { /// Extracts the raw grip. fn as_raw_grip(&self) -> RawGrip; } /// Portability abstraction over `AsFd` and `AsHandleOrSocket`. #[cfg(windows)] pub trait AsRawGrip: AsRawHandleOrSocket { /// Extracts the raw grip. fn as_raw_grip(&self) -> RawGrip; } /// Portability abstraction over `AsReadWriteFd` and /// `AsReadWriteHandleOrSocket`. #[cfg(not(windows))] pub trait AsRawReadWriteGrip: AsRawReadWriteFd { /// Extracts the grip for reading. /// /// Like [`AsRawGrip::as_raw_grip`], but returns the /// raw reading grip. fn as_raw_read_grip(&self) -> RawGrip; /// Extracts the grip for writing. /// /// Like [`AsRawGrip::as_raw_grip`], but returns the /// raw writing grip. fn as_raw_write_grip(&self) -> RawGrip; } /// Portability abstraction over `AsReadWriteFd` and /// `AsReadWriteHandleOrSocket`. #[cfg(windows)] pub trait AsRawReadWriteGrip: AsRawReadWriteHandleOrSocket { /// Extracts the grip for reading. /// /// Like [`AsRawGrip::as_raw_grip`], but returns the /// raw reading grip. fn as_raw_read_grip(&self) -> RawGrip; /// Extracts the grip for writing. /// /// Like [`AsRawGrip::as_raw_grip`], but returns the /// raw writing grip. fn as_raw_write_grip(&self) -> RawGrip; } /// Portability abstraction over `IntoRawFd` and /// `IntoRawHandleOrSocket`. #[cfg(not(windows))] pub trait IntoRawGrip: IntoRawFd { /// Consume `self` and convert into an `RawGrip`. fn into_raw_grip(self) -> RawGrip; } /// Portability abstraction over `IntoRawFd` and /// `IntoRawHandleOrSocket`. #[cfg(windows)] pub trait IntoRawGrip: IntoRawHandleOrSocket { /// Consume `self` and convert into an `RawGrip`. fn into_raw_grip(self) -> RawGrip; } /// Portability abstraction over `From` and /// `From`. #[cfg(not(windows))] pub trait FromRawGrip: FromRawFd { /// Consume an `RawGrip` and convert into a `Self`. /// /// # Safety /// /// `raw_grip` must be a suitable grip for assuming ownership. unsafe fn from_raw_grip(raw_grip: RawGrip) -> Self; } /// Portability abstraction over `From` and /// `From`. #[cfg(windows)] pub trait FromRawGrip: FromRawHandleOrSocket { /// Consume an `RawGrip` and convert into a `Self`. /// /// # Safety /// /// `raw_grip` must be a suitable grip for assuming ownership. unsafe fn from_raw_grip(raw_grip: RawGrip) -> Self; } #[cfg(not(windows))] impl AsRawGrip for T { #[inline] fn as_raw_grip(&self) -> RawGrip { self.as_raw_fd() } } #[cfg(windows)] impl AsRawGrip for T { #[inline] fn as_raw_grip(&self) -> RawGrip { self.as_raw_handle_or_socket() } } #[cfg(not(windows))] impl AsRawReadWriteGrip for T { #[inline] fn as_raw_read_grip(&self) -> RawGrip { self.as_raw_read_fd() } #[inline] fn as_raw_write_grip(&self) -> RawGrip { self.as_raw_write_fd() } } #[cfg(windows)] impl AsRawReadWriteGrip for T { #[inline] fn as_raw_read_grip(&self) -> RawGrip { self.as_raw_read_handle_or_socket() } #[inline] fn as_raw_write_grip(&self) -> RawGrip { self.as_raw_write_handle_or_socket() } } #[cfg(not(windows))] impl IntoRawGrip for T { #[inline] fn into_raw_grip(self) -> RawGrip { self.into_raw_fd() } } #[cfg(windows)] impl IntoRawGrip for T { #[inline] fn into_raw_grip(self) -> RawGrip { self.into_raw_handle_or_socket() } } #[cfg(not(windows))] impl FromRawGrip for T { #[inline] unsafe fn from_raw_grip(raw_grip: RawGrip) -> Self { Self::from_raw_fd(raw_grip) } } #[cfg(windows)] impl FromRawGrip for T { #[inline] unsafe fn from_raw_grip(raw_grip: RawGrip) -> Self { Self::from_raw_handle_or_socket(raw_grip) } } /// Portability abstraction over `BorrowedFd::from_raw_fd` and /// `BorrowedHandleOrSocket::from_raw_handle_or_socket`. /// /// # Safety /// /// See the safety conditions for [`borrow_raw`]. /// /// [`borrow_raw`]: https://doc.rust-lang.org/stable/std/os/unix/io/struct.BorrowedFd.html#method.borrow_raw #[cfg(not(windows))] #[must_use] #[inline] pub unsafe fn borrow_raw<'a>(grip: RawGrip) -> BorrowedGrip<'a> { BorrowedFd::borrow_raw(grip) } /// Portability abstraction over `BorrowedFd::from_raw_fd` and /// `BorrowedHandleOrSocket::from_raw_handle_or_socket`. /// /// # Safety /// /// See the safety conditions for [`BorrowedHandle::borrow_raw`], and /// [`BorrowedSocket::borrow_raw`]. /// /// [`BorrowedHandle::borrow_raw`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.BorrowedHandle.html#method.borrow_raw /// [`BorrowedSocket::borrow_raw`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.BorrowedSocket.html#method.borrow_raw #[cfg(windows)] #[must_use] #[inline] pub unsafe fn borrow_raw<'a>(grip: RawGrip) -> BorrowedGrip<'a> { BorrowedHandleOrSocket::borrow_raw(grip) } io-extras-0.18.3/src/lib.rs000064400000000000000000000020711046102023000135330ustar 00000000000000//! This crate provides a few miscellaneous utilities related to I/O: //! //! - `HandleOrSocket` types and traits for Windows, which abstract over //! Windows `*Handle*` and their corresponding Windows `*Socket*` types and //! traits. //! //! - `Grip` types and traits, which abstract over the aforementioned Windows //! `HandleOrSocket` types and traits and their corresponding non-Windows //! `Fd` types and traits. //! //! - `OwnedReadable`, `OwnedWriteable`, `BorrowedReadable`, //! `BorrowedWriteable`, `RawReadable` and `RawWriteable`, which adapt a raw //! `Fd`/`Handle` to implement the `Read` and `Write` traits, respectively. //! //! - `ReadWrite` traits, and supporting types, which provide abstractions over //! types with one or two I/O resources, for reading and for writing. #![deny(missing_docs)] #![cfg_attr(can_vector, feature(can_vector))] #![cfg_attr(write_all_vectored, feature(write_all_vectored))] #![cfg_attr(target_os = "wasi", feature(wasi_ext))] pub mod borrowed; pub mod grip; pub mod os; pub mod owned; pub mod raw; pub mod read_write; io-extras-0.18.3/src/os/mod.rs000064400000000000000000000001461046102023000141660ustar 00000000000000//! OS-specific functionality. #[cfg(not(windows))] pub mod rustix; #[cfg(windows)] pub mod windows; io-extras-0.18.3/src/os/rustix.rs000064400000000000000000000011561046102023000147470ustar 00000000000000//! All Posix-ish platforms have `RawFd` and related traits. Re-export them //! so that users don't need target-specific code to import them. #[cfg(unix)] pub use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; #[cfg(target_os = "wasi")] pub use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; pub use crate::read_write::{AsRawReadWriteFd, AsReadWriteFd}; // In theory we could do something similar for // `std::os::fortanix_sgx::io::{AsRawFd, FromRawFd, RawFd}`, however it lacks // `IntoRawFd`, and `std::fs::File` doesn't implement its `AsRawFd`, so it // doesn't seem to qualify as Posix-ish. io-extras-0.18.3/src/os/windows/mod.rs000064400000000000000000000475201046102023000156670ustar 00000000000000//! The [`RawHandleOrSocket`] type and accompanying [`AsRawHandleOrSocket`], //! [`IntoRawHandleOrSocket`], and [`FromRawHandleOrSocket`] traits. These //! provide minimal Windows analogs for the Posix-ish `RawFd` type and //! accompanying `AsRawFd`, `IntoRawFd`, and `FromRawFd` traits. //! //! These types are only defined on Windows and do not require implementors to //! assert that they own their resources. #[cfg(any(test, feature = "os_pipe"))] use os_pipe::{PipeReader, PipeWriter}; use std::fs::File; use std::io::{Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock}; use std::net::{TcpListener, TcpStream, UdpSocket}; use std::os::windows::io::{ AsRawHandle, AsRawSocket, IntoRawHandle, IntoRawSocket, RawHandle, RawSocket, }; use std::process::{ChildStderr, ChildStdin, ChildStdout}; use stdio::Stdio; mod stdio; mod traits; mod types; pub use crate::read_write::{AsRawReadWriteHandleOrSocket, AsReadWriteHandleOrSocket}; pub use traits::AsHandleOrSocket; pub use types::{BorrowedHandleOrSocket, OwnedHandleOrSocket}; /// A Windows analog for the Posix-ish `AsRawFd` type. Unlike Posix-ish /// platforms which have a single type for files and sockets, Windows has /// distinct types, `RawHandle` and `RawSocket`. And unlike Posix-ish /// platforms where text streams are generally UTF-8, the Windows Console /// is UTF-16. This type behaves like an enum which can hold either a /// handle or a socket, and to which UTF-8 text can be written. /// /// It's reasonable to worry that this might be trying too hard to make Windows /// work like Posix-ish platforms, however in this case, the number of types is /// small, so the enum is simple and the overhead is relatively low, and the /// benefit is that we can abstract over major [`Read`] and [`Write`] /// resources. /// /// [`Read`]: std::io::Read /// [`Write`]: std::io::Write #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)] #[repr(transparent)] pub struct RawHandleOrSocket(pub(crate) RawEnum); /// The enum itself is a private type so that we have the flexibility to change /// the representation in the future. /// /// It's possible that Windows could add other handle-like types in the future. /// And it's possible that we'll want to optimize the representation, possibly /// by finding an unused bit in the `RawHandle` and `RawSocket` representations /// which we can repurpose as a discriminant. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)] pub(crate) enum RawEnum { /// A `RawHandle`. Handle(RawHandle), /// A `RawSocket`. Socket(RawSocket), /// `Stdin`, `Stdout`, or `Stderr` that might be on a console and might /// need translation from UTF-8 to UTF-16. Stdio(Stdio), } impl RawHandleOrSocket { /// Like [`FromRawHandle::from_raw_handle`], but isn't unsafe because it /// doesn't imply a dereference. /// /// [`FromRawHandle::from_raw_handle`]: std::os::windows::io::FromRawHandle::from_raw_handle #[inline] #[must_use] pub const fn unowned_from_raw_handle(raw_handle: RawHandle) -> Self { Self(RawEnum::Handle(raw_handle)) } /// Like [`FromRawSocket::from_raw_socket`], but isn't unsafe because it /// doesn't imply a dereference. /// /// [`FromRawSocket::from_raw_socket`]: std::os::windows::io::FromRawSocket::from_raw_socket #[inline] #[must_use] pub const fn unowned_from_raw_socket(raw_socket: RawSocket) -> Self { Self(RawEnum::Socket(raw_socket)) } /// Like [`AsRawHandle::as_raw_handle`], but returns an `Option` so that /// it can return `None` if `self` doesn't contain a `RawHandle`. #[inline] #[must_use] pub fn as_raw_handle(&self) -> Option { match self.0 { RawEnum::Handle(raw_handle) => Some(raw_handle), RawEnum::Socket(_) => None, RawEnum::Stdio(ref stdio) => Some(stdio.as_raw_handle()), } } /// Like [`AsRawSocket::as_raw_socket`], but returns an `Option` so that /// it can return `None` if `self` doesn't contain a `RawSocket`. #[inline] #[must_use] pub const fn as_raw_socket(&self) -> Option { match self.0 { RawEnum::Handle(_) | RawEnum::Stdio(_) => None, RawEnum::Socket(raw_socket) => Some(raw_socket), } } /// Return a `RawHandleOrSocket` representing stdin. /// /// This differs from `unowned_from_raw_handle` on the stdin handle in two /// ways: /// - It tracks the stdin handle, which may change dynamically via /// `SetStdHandle`. /// - When stdin is attached to a console, reads from this handle via /// `RawReadable` are decoded into UTF-8. #[inline] #[must_use] pub const fn stdin() -> Self { Self(RawEnum::Stdio(Stdio::stdin())) } /// Return a `RawHandleOrSocket` representing stdout. /// /// This differs from `unowned_from_raw_handle` on the stdout handle in two /// ways: /// - It tracks the stdout handle, which may change dynamically via /// `SetStdHandle`. /// - When stdout is attached to a console, writes to this handle via /// `RawWriteable` are encoded from UTF-8. #[inline] #[must_use] pub const fn stdout() -> Self { Self(RawEnum::Stdio(Stdio::stdout())) } /// Return a `RawHandleOrSocket` representing stderr. /// /// This differs from `unowned_from_raw_handle` on the stderr handle in two /// ways: /// - It tracks the stderr handle, which may change dynamically via /// `SetStdHandle`. /// - When stderr is attached to a console, writes to this handle via /// `RawWriteable` are encoded from UTF-8. #[inline] #[must_use] pub const fn stderr() -> Self { Self(RawEnum::Stdio(Stdio::stderr())) } } /// Like [`AsRawHandle`] and [`AsRawSocket`], but implementable by types which /// can implement either one. pub trait AsRawHandleOrSocket { /// Like [`AsRawHandle::as_raw_handle`] and [`AsRawSocket::as_raw_socket`] /// but can return either type. fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket; } /// Like [`IntoRawHandle`] and [`IntoRawSocket`], but implementable by types /// which can implement either one. pub trait IntoRawHandleOrSocket { /// Like [`IntoRawHandle::into_raw_handle`] and /// [`IntoRawSocket::into_raw_socket`] but can return either type. fn into_raw_handle_or_socket(self) -> RawHandleOrSocket; } /// Like [`FromRawHandle`] and [`FromRawSocket`], but implementable by types /// which can implement both. /// /// Note: Don't implement this trait for types which can only implement one /// or the other, such that it would need to panic if passed the wrong form. /// /// [`FromRawHandle`]: std::os::windows::io::FromRawHandle /// [`FromRawSocket`]: std::os::windows::io::FromRawSocket pub trait FromRawHandleOrSocket { /// Like [`FromRawHandle::from_raw_handle`] and /// [`FromRawSocket::from_raw_socket`] but can be passed either type. /// /// # Safety /// /// `raw_handle_or_socket` must be valid and otherwise unowned. /// /// [`FromRawHandle::from_raw_handle`]: std::os::windows::io::FromRawHandle::from_raw_handle /// [`FromRawSocket::from_raw_socket`]: std::os::windows::io::FromRawSocket::from_raw_socket unsafe fn from_raw_handle_or_socket(raw_handle_or_socket: RawHandleOrSocket) -> Self; } /// The Windows [`HANDLE`] and [`SOCKET`] types may be sent between threads. /// /// [`HANDLE`]: std::os::windows::raw::HANDLE /// [`SOCKET`]: std::os::windows::raw::SOCKET unsafe impl Send for RawHandleOrSocket {} /// The Windows [`HANDLE`] and [`SOCKET`] types may be shared between threads. /// /// [`HANDLE`]: std::os::windows::raw::HANDLE /// [`SOCKET`]: std::os::windows::raw::SOCKET unsafe impl Sync for RawHandleOrSocket {} impl AsRawHandleOrSocket for RawHandleOrSocket { #[inline] fn as_raw_handle_or_socket(&self) -> Self { *self } } impl AsRawHandleOrSocket for Stdin { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } impl AsRawHandleOrSocket for StdinLock<'_> { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } impl AsRawHandleOrSocket for Stdout { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } impl AsRawHandleOrSocket for StdoutLock<'_> { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } impl AsRawHandleOrSocket for Stderr { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } impl AsRawHandleOrSocket for StderrLock<'_> { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } impl AsRawHandleOrSocket for File { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } impl AsRawHandleOrSocket for ChildStdin { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } impl AsRawHandleOrSocket for ChildStdout { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } impl AsRawHandleOrSocket for ChildStderr { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } impl AsRawHandleOrSocket for TcpStream { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } impl AsRawHandleOrSocket for TcpListener { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } impl AsRawHandleOrSocket for UdpSocket { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } #[cfg(feature = "async-std")] impl AsRawHandleOrSocket for async_std::io::Stdin { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(feature = "async-std")] impl AsRawHandleOrSocket for async_std::io::Stdout { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(feature = "async-std")] impl AsRawHandleOrSocket for async_std::io::Stderr { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(feature = "async-std")] impl AsRawHandleOrSocket for async_std::fs::File { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } // async_std's `ChildStdin`, `ChildStdout`, and `ChildStderr` don't implement // `AsRawFd` or `AsRawHandle`. #[cfg(feature = "async-std")] impl AsRawHandleOrSocket for async_std::net::TcpStream { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } #[cfg(feature = "async-std")] impl AsRawHandleOrSocket for async_std::net::TcpListener { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } #[cfg(feature = "async-std")] impl AsRawHandleOrSocket for async_std::net::UdpSocket { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } #[cfg(feature = "tokio")] impl AsRawHandleOrSocket for tokio::io::Stdin { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(feature = "tokio")] impl AsRawHandleOrSocket for tokio::io::Stdout { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(feature = "tokio")] impl AsRawHandleOrSocket for tokio::io::Stderr { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(feature = "tokio")] impl AsRawHandleOrSocket for tokio::fs::File { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(feature = "tokio")] impl AsRawHandleOrSocket for tokio::net::TcpStream { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } #[cfg(feature = "tokio")] impl AsRawHandleOrSocket for tokio::net::TcpListener { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } #[cfg(feature = "tokio")] impl AsRawHandleOrSocket for tokio::net::UdpSocket { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } #[cfg(feature = "tokio")] impl AsRawHandleOrSocket for tokio::process::ChildStdin { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(feature = "tokio")] impl AsRawHandleOrSocket for tokio::process::ChildStdout { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(feature = "tokio")] impl AsRawHandleOrSocket for tokio::process::ChildStderr { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(any(test, feature = "os_pipe"))] impl AsRawHandleOrSocket for PipeReader { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(any(test, feature = "os_pipe"))] impl AsRawHandleOrSocket for PipeWriter { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::as_raw_handle(self)) } } #[cfg(feature = "socket2")] impl AsRawHandleOrSocket for socket2::Socket { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } #[cfg(feature = "use_mio_net")] impl AsRawHandleOrSocket for mio::net::TcpStream { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } #[cfg(feature = "use_mio_net")] impl AsRawHandleOrSocket for mio::net::TcpListener { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } #[cfg(feature = "use_mio_net")] impl AsRawHandleOrSocket for mio::net::UdpSocket { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::as_raw_socket(self)) } } impl IntoRawHandleOrSocket for File { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::into_raw_handle(self)) } } impl IntoRawHandleOrSocket for ChildStdin { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::into_raw_handle(self)) } } impl IntoRawHandleOrSocket for ChildStdout { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::into_raw_handle(self)) } } impl IntoRawHandleOrSocket for ChildStderr { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::into_raw_handle(self)) } } impl IntoRawHandleOrSocket for TcpStream { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::into_raw_socket(self)) } } impl IntoRawHandleOrSocket for TcpListener { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::into_raw_socket(self)) } } impl IntoRawHandleOrSocket for UdpSocket { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::into_raw_socket(self)) } } #[cfg(feature = "os_pipe")] impl IntoRawHandleOrSocket for PipeReader { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::into_raw_handle(self)) } } #[cfg(feature = "os_pipe")] impl IntoRawHandleOrSocket for PipeWriter { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::into_raw_handle(self)) } } #[cfg(feature = "socket2")] impl IntoRawHandleOrSocket for socket2::Socket { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::into_raw_socket(self)) } } #[cfg(feature = "use_mio_net")] impl IntoRawHandleOrSocket for mio::net::TcpStream { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::into_raw_socket(self)) } } #[cfg(feature = "use_mio_net")] impl IntoRawHandleOrSocket for mio::net::TcpListener { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::into_raw_socket(self)) } } #[cfg(feature = "use_mio_net")] impl IntoRawHandleOrSocket for mio::net::UdpSocket { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::into_raw_socket(self)) } } #[cfg(feature = "async-std")] impl IntoRawHandleOrSocket for async_std::fs::File { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_handle(Self::into_raw_handle(self)) } } #[cfg(feature = "async-std")] impl IntoRawHandleOrSocket for async_std::net::TcpStream { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::into_raw_socket(self)) } } #[cfg(feature = "async-std")] impl IntoRawHandleOrSocket for async_std::net::TcpListener { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::into_raw_socket(self)) } } #[cfg(feature = "async-std")] impl IntoRawHandleOrSocket for async_std::net::UdpSocket { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { RawHandleOrSocket::unowned_from_raw_socket(Self::into_raw_socket(self)) } } io-extras-0.18.3/src/os/windows/stdio.rs000064400000000000000000000253161046102023000162310ustar 00000000000000//! This file is derived from Rust's library/std/src/sys/windows/stdio.rs at //! revision 8e863eb59a10fb0900d7377524a0dc7bf44b9ae3. #![allow( clippy::missing_docs_in_private_items, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::shadow_reuse, clippy::panic_in_result_fn, clippy::integer_division, clippy::integer_arithmetic, clippy::indexing_slicing, clippy::unwrap_used, clippy::needless_borrow, clippy::let_underscore_drop, clippy::match_same_arms )] use crate::raw::{RawReadable, RawWriteable}; use std::char::decode_utf16; use std::io::{self, Read, Write}; use std::os::raw::c_void; use std::os::windows::io::{FromRawHandle, RawHandle}; use std::sync::atomic::AtomicU16; use std::sync::atomic::Ordering::SeqCst; use std::{cmp, ptr, str}; use windows_sys::Win32::Foundation::{ERROR_INVALID_HANDLE, HANDLE, INVALID_HANDLE_VALUE}; use windows_sys::Win32::System::Console::{ GetConsoleMode, GetStdHandle, ReadConsoleW, WriteConsoleW, CONSOLE_READCONSOLE_CONTROL, STD_ERROR_HANDLE, STD_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, }; static SURROGATE: AtomicU16 = AtomicU16::new(0); // Don't cache handles but get them fresh for every read/write. This allows us // to track changes to the value over time (such as if a process calls // `SetStdHandle` while it's running). See #40490. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)] pub(crate) struct Stdio { id: STD_HANDLE, } impl Stdio { #[inline] pub(crate) const fn stdin() -> Self { Self { id: STD_INPUT_HANDLE, } } #[inline] pub(crate) const fn stdout() -> Self { Self { id: STD_OUTPUT_HANDLE, } } #[inline] pub(crate) const fn stderr() -> Self { Self { id: STD_ERROR_HANDLE, } } #[inline] pub(crate) fn as_raw_handle(self) -> RawHandle { get_handle(self.id).unwrap() } } // Apparently Windows doesn't handle large reads on stdin or writes to // stdout/stderr well (see #13304 for details). // // From MSDN (2011): "The storage for this buffer is allocated from a shared // heap for the process that is 64 KB in size. The maximum size of the buffer // will depend on heap usage." // // We choose the cap at 8 KiB because libuv does the same, and it seems to be // acceptable so far. const MAX_BUFFER_SIZE: usize = 8192; #[allow(clippy::as_conversions)] fn get_handle(handle_id: STD_HANDLE) -> io::Result { let handle = unsafe { GetStdHandle(handle_id) }; if handle == INVALID_HANDLE_VALUE { Err(io::Error::last_os_error()) } else if (handle as RawHandle).is_null() { Err(io::Error::from_raw_os_error(ERROR_INVALID_HANDLE as i32)) } else { Ok(handle as RawHandle) } } fn is_console(handle: RawHandle) -> bool { // `GetConsoleMode` will return false (0) if this is a pipe (we don't care // about the reported mode). This will only detect Windows Console, not // other terminals connected to a pipe like MSYS. Which is exactly what we // need, as only Windows Console needs a conversion to UTF-16. let mut mode = 0; unsafe { GetConsoleMode(handle as HANDLE, &mut mode) != 0_i32 } } fn write(handle_id: STD_HANDLE, data: &[u8]) -> io::Result { let handle = get_handle(handle_id)?; if !is_console(handle) { return unsafe { RawWriteable::from_raw_handle(handle) }.write(data); } // As the console is meant for presenting text, we assume bytes of `data` come // from a string and are encoded as UTF-8, which needs to be encoded as // UTF-16. // // If the data is not valid UTF-8 we write out as many bytes as are valid. // Only when there are no valid bytes (which will happen on the next call), // return an error. let len = cmp::min(data.len(), MAX_BUFFER_SIZE / 2); let utf8 = match str::from_utf8(&data[..len]) { Ok(s) => s, Err(ref e) if e.valid_up_to() == 0 => { return Err(io::Error::new( io::ErrorKind::InvalidData, "Windows stdio in console mode does not support writing non-UTF-8 byte sequences", )); } Err(e) => str::from_utf8(&data[..e.valid_up_to()]).unwrap(), }; let mut utf16 = [0_u16; MAX_BUFFER_SIZE / 2]; let mut len_utf16 = 0; for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) { *dest = chr; len_utf16 += 1; } let utf16 = &utf16[..len_utf16]; let mut written = write_u16s(handle, &utf16)?; // Figure out how many bytes of as UTF-8 were written away as UTF-16. if written == utf16.len() { Ok(utf8.len()) } else { // Make sure we didn't end up writing only half of a surrogate pair (even // though the chance is tiny). Because it is not possible for user code // to re-slice `data` in such a way that a missing surrogate can be // produced (and also because of the UTF-8 validation above), write the // missing surrogate out now. Buffering it would mean we have to lie // about the number of bytes written. let first_char_remaining = utf16[written]; if (0xDCEE..=0xDFFF).contains(&first_char_remaining) { // low surrogate // We just hope this works, and give up otherwise let _ = write_u16s(handle, &utf16[written..=written]); written += 1; } // Calculate the number of bytes of `utf8` that were actually written. let mut count = 0; for ch in utf16[..written].iter() { count += match ch { 0x0000..=0x007F => 1, 0x0080..=0x07FF => 2, 0xDCEE..=0xDFFF => 1, // Low surrogate. We already counted 3 bytes for the other. _ => 3, }; } debug_assert!(String::from_utf16(&utf16[..written]).unwrap() == utf8[..count]); Ok(count) } } #[allow(clippy::as_conversions)] fn write_u16s(handle: RawHandle, data: &[u16]) -> io::Result { let mut written = 0; let len: u32 = if let Ok(len) = data.len().try_into() { len } else { u32::MAX }; if unsafe { WriteConsoleW( handle as HANDLE, data.as_ptr().cast::(), len, &mut written, ptr::null_mut(), ) } == 0_i32 { return Err(io::Error::last_os_error()); } Ok(written as usize) } impl Read for Stdio { fn read(&mut self, buf: &mut [u8]) -> io::Result { let handle = get_handle(self.id)?; if !is_console(handle) { return unsafe { RawReadable::from_raw_handle(handle) }.read(buf); } if buf.is_empty() { return Ok(0); } if buf.len() < 4 { return Err(io::Error::new( io::ErrorKind::InvalidInput, "Windows stdin in console mode does not support a buffer too small to \ guarantee holding one arbitrary UTF-8 character (4 bytes)", )); } let mut utf16_buf = [0_u16; MAX_BUFFER_SIZE / 2]; // In the worst case, an UTF-8 string can take 3 bytes for every `u16` of an // UTF-16. So we can read at most a third of `buf.len()` chars and // uphold the guarantee no data gets lost. let amount = cmp::min(buf.len() / 3, utf16_buf.len()); let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount)?; utf16_to_utf8(&utf16_buf[..read], buf) } } // We assume that if the last `u16` is an unpaired surrogate they got sliced // apart by our buffer size, and keep it around for the next read hoping to put // them together. This is a best effort, and may not work if we are not the // only reader on Stdio. fn read_u16s_fixup_surrogates( handle: RawHandle, buf: &mut [u16], mut amount: usize, ) -> io::Result { // Insert possibly remaining unpaired surrogate from last read. let mut start = 0; let s = SURROGATE.swap(0, SeqCst); if s != 0 { buf[0] = s; start = 1; if amount == 1 { // Special case: `Stdio::read` guarantees we can always read at least one new // `u16` and combine it with an unpaired surrogate, because the // UTF-8 buffer is at least 4 bytes. amount = 2; } } let mut amount = read_u16s(handle, &mut buf[start..amount])? + start; if amount > 0 { let last_char = buf[amount - 1]; if (0xD800..=0xDBFF).contains(&last_char) { // high surrogate SURROGATE.store(last_char, SeqCst); amount -= 1; } } Ok(amount) } #[allow(clippy::as_conversions)] fn read_u16s(handle: RawHandle, buf: &mut [u16]) -> io::Result { // Configure the `pInputControl` parameter to not only return on `\r\n` but // also Ctrl-Z, the traditional DOS method to indicate end of character // stream / user input (SUB). See #38274 and https://stackoverflow.com/questions/43836040/win-api-readconsole. const CTRL_Z: u16 = 0x1A; const CTRL_Z_MASK: u32 = 1 << CTRL_Z; let input_control = CONSOLE_READCONSOLE_CONTROL { nLength: std::mem::size_of::() as u32, nInitialChars: 0, dwCtrlWakeupMask: CTRL_Z_MASK, dwControlKeyState: 0, }; let mut amount = 0; let len: u32 = if let Ok(len) = buf.len().try_into() { len } else { u32::MAX }; if unsafe { ReadConsoleW( handle as HANDLE, buf.as_mut_ptr().cast::(), len, &mut amount, &input_control, ) } == 0_i32 { return Err(io::Error::last_os_error()); } if amount > 0 && buf[amount as usize - 1] == CTRL_Z { amount -= 1; } Ok(amount as usize) } #[allow(unused)] fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result { let mut written = 0; for chr in decode_utf16(utf16.iter().copied()) { match chr { Ok(chr) => { let _ = chr.encode_utf8(&mut utf8[written..]); written += chr.len_utf8(); } Err(_) => { // We can't really do any better than forget all data and return an error. return Err(io::Error::new( io::ErrorKind::InvalidData, "Windows stdin in console mode does not support non-UTF-16 input; \ encountered unpaired surrogate", )); } } } Ok(written) } impl Write for Stdio { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { write(self.id, buf) } #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } io-extras-0.18.3/src/os/windows/traits.rs000064400000000000000000000316011046102023000164070ustar 00000000000000//! `AsHandleOrSocket` and related `From` impls. use super::types::{BorrowedHandleOrSocket, OwnedHandleOrSocket}; use super::AsRawHandleOrSocket; use io_lifetimes::{AsHandle, AsSocket}; use std::fs::File; use std::io::{Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock}; use std::net::{TcpListener, TcpStream, UdpSocket}; use std::process::{ChildStderr, ChildStdin, ChildStdout}; /// Like [`AsHandle`] and [`AsSocket`], but implementable by types which /// can implement either one. pub trait AsHandleOrSocket { /// Like [`AsHandle::as_handle`] and [`AsSocket::as_socket`] /// but can return either type. fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_>; } impl AsHandleOrSocket for OwnedHandleOrSocket { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { unsafe { BorrowedHandleOrSocket::borrow_raw(self.as_raw_handle_or_socket()) } } } impl AsHandleOrSocket for BorrowedHandleOrSocket<'_> { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { *self } } impl AsHandleOrSocket for Stdin { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } impl AsHandleOrSocket for StdinLock<'_> { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } impl AsHandleOrSocket for Stdout { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } impl AsHandleOrSocket for StdoutLock<'_> { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } impl AsHandleOrSocket for Stderr { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } impl AsHandleOrSocket for StderrLock<'_> { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } impl AsHandleOrSocket for File { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } impl AsHandleOrSocket for ChildStdin { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } impl AsHandleOrSocket for ChildStdout { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } impl AsHandleOrSocket for ChildStderr { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } impl AsHandleOrSocket for TcpStream { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } impl AsHandleOrSocket for TcpListener { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } impl AsHandleOrSocket for UdpSocket { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } #[cfg(feature = "async-std")] impl AsHandleOrSocket for async_std::io::Stdin { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "async-std")] impl AsHandleOrSocket for async_std::io::Stdout { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "async-std")] impl AsHandleOrSocket for async_std::io::Stderr { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "async-std")] impl AsHandleOrSocket for async_std::fs::File { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } // async_std's `ChildStdin`, `ChildStdout`, and `ChildStderr` don't implement // `AsFd` or `AsHandle`. #[cfg(feature = "async-std")] impl AsHandleOrSocket for async_std::net::TcpStream { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } #[cfg(feature = "async-std")] impl AsHandleOrSocket for async_std::net::TcpListener { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } #[cfg(feature = "async-std")] impl AsHandleOrSocket for async_std::net::UdpSocket { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } #[cfg(feature = "tokio")] impl AsHandleOrSocket for tokio::io::Stdin { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "tokio")] impl AsHandleOrSocket for tokio::io::Stdout { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "tokio")] impl AsHandleOrSocket for tokio::io::Stderr { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "tokio")] impl AsHandleOrSocket for tokio::fs::File { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "tokio")] impl AsHandleOrSocket for tokio::net::TcpStream { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } #[cfg(feature = "tokio")] impl AsHandleOrSocket for tokio::net::TcpListener { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } #[cfg(feature = "tokio")] impl AsHandleOrSocket for tokio::net::UdpSocket { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } #[cfg(feature = "tokio")] impl AsHandleOrSocket for tokio::process::ChildStdin { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "tokio")] impl AsHandleOrSocket for tokio::process::ChildStdout { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "tokio")] impl AsHandleOrSocket for tokio::process::ChildStderr { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "os_pipe")] impl AsHandleOrSocket for os_pipe::PipeReader { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "os_pipe")] impl AsHandleOrSocket for os_pipe::PipeWriter { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_handle(Self::as_handle(self)) } } #[cfg(feature = "socket2")] impl AsHandleOrSocket for socket2::Socket { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } #[cfg(feature = "use_mio_net")] #[cfg(not(io_lifetimes_use_std))] // TODO: Enable when we have impls for mio impl AsHandleOrSocket for mio::net::TcpStream { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } #[cfg(feature = "use_mio_net")] #[cfg(not(io_lifetimes_use_std))] // TODO: Enable when we have impls for mio impl AsHandleOrSocket for mio::net::TcpListener { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } #[cfg(feature = "use_mio_net")] #[cfg(not(io_lifetimes_use_std))] // TODO: Enable when we have impls for mio impl AsHandleOrSocket for mio::net::UdpSocket { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { BorrowedHandleOrSocket::from_socket(Self::as_socket(self)) } } impl From for OwnedHandleOrSocket { #[inline] fn from(file: File) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_handle(file.into()) } } impl From for OwnedHandleOrSocket { #[inline] fn from(stdin: ChildStdin) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_handle(stdin.into()) } } impl From for OwnedHandleOrSocket { #[inline] fn from(stdout: ChildStdout) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_handle(stdout.into()) } } impl From for OwnedHandleOrSocket { #[inline] fn from(stderr: ChildStderr) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_handle(stderr.into()) } } impl From for OwnedHandleOrSocket { #[inline] fn from(stream: TcpStream) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_socket(stream.into()) } } impl From for OwnedHandleOrSocket { #[inline] fn from(listener: TcpListener) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_socket(listener.into()) } } impl From for OwnedHandleOrSocket { #[inline] fn from(socket: UdpSocket) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_socket(socket.into()) } } #[cfg(feature = "os_pipe")] impl From for OwnedHandleOrSocket { #[inline] fn from(reader: os_pipe::PipeReader) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_handle(reader.into()) } } #[cfg(feature = "os_pipe")] impl From for OwnedHandleOrSocket { #[inline] fn from(writer: os_pipe::PipeWriter) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_handle(writer.into()) } } #[cfg(feature = "socket2")] impl From for OwnedHandleOrSocket { #[inline] fn from(socket: socket2::Socket) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_socket(socket.into()) } } #[cfg(feature = "use_mio_net")] #[cfg(not(io_lifetimes_use_std))] // TODO: Enable when we have impls for mio impl From for OwnedHandleOrSocket { #[inline] fn from(stream: mio::net::TcpStream) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_socket(stream.into()) } } #[cfg(feature = "use_mio_net")] #[cfg(not(io_lifetimes_use_std))] // TODO: Enable when we have impls for mio impl From for OwnedHandleOrSocket { #[inline] fn from(listener: mio::net::TcpListener) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_socket(listener.into()) } } #[cfg(feature = "use_mio_net")] #[cfg(not(io_lifetimes_use_std))] // TODO: Enable when we have impls for mio impl From for OwnedHandleOrSocket { #[inline] fn from(socket: mio::net::UdpSocket) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_socket(socket.into()) } } #[cfg(feature = "async-std")] impl From for OwnedHandleOrSocket { #[inline] fn from(file: async_std::fs::File) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_handle(file.into()) } } #[cfg(feature = "async-std")] impl From for OwnedHandleOrSocket { #[inline] fn from(stream: async_std::net::TcpStream) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_socket(stream.into()) } } #[cfg(feature = "async-std")] impl From for OwnedHandleOrSocket { #[inline] fn from(listener: async_std::net::TcpListener) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_socket(listener.into()) } } #[cfg(feature = "async-std")] impl From for OwnedHandleOrSocket { #[inline] fn from(socket: async_std::net::UdpSocket) -> OwnedHandleOrSocket { OwnedHandleOrSocket::from_socket(socket.into()) } } io-extras-0.18.3/src/os/windows/types.rs000064400000000000000000000166571046102023000162630ustar 00000000000000//! `HandleOrSocket` variants of io-lifetimes' //! `BorrowedHandle`/`BorrowedSocket` and `OwnedHandle`/`OwnedSocket`. use super::{ AsRawHandleOrSocket, FromRawHandleOrSocket, IntoRawHandleOrSocket, RawEnum, RawHandleOrSocket, }; use io_lifetimes::{BorrowedHandle, BorrowedSocket, OwnedHandle, OwnedSocket}; use std::fmt; use std::marker::PhantomData; use std::mem::forget; use std::os::windows::io::{ AsRawHandle, AsRawSocket, FromRawHandle, FromRawSocket, IntoRawHandle, IntoRawSocket, RawSocket, }; use windows_sys::Win32::Networking::WinSock::INVALID_SOCKET; /// `HandleOrSocket` variant of io-lifetimes' /// `BorrowedHandle`/`BorrowedSocket`. #[derive(Copy, Clone)] pub struct BorrowedHandleOrSocket<'a> { raw: RawHandleOrSocket, _phantom: PhantomData<&'a OwnedHandleOrSocket>, } /// `HandleOrSocket` variant of io-lifetimes' /// `OwnedHandle`/`OwnedSocket`. #[allow(missing_copy_implementations)] pub struct OwnedHandleOrSocket { raw: RawHandleOrSocket, } impl<'a> BorrowedHandleOrSocket<'a> { /// Return a `BorrowedHandleOrSocket` holding the given raw handle or /// socket. /// /// # Safety /// /// The resource pointed to by `raw` must remain open for the duration of /// the returned `BorrowedHandleOrSocket`, and it must not be a null handle /// or an invalid socket. #[inline] pub unsafe fn borrow_raw(raw: RawHandleOrSocket) -> Self { match raw.0 { RawEnum::Handle(raw_handle) => assert!(!raw_handle.is_null()), RawEnum::Socket(raw_socket) => assert_ne!(raw_socket, INVALID_SOCKET as RawSocket), RawEnum::Stdio(_) => (), } Self { raw, _phantom: PhantomData, } } /// Construct a `BorrowedHandleOrSocket` from a `BorrowedHandle`. #[inline] pub fn from_handle(handle: BorrowedHandle<'a>) -> Self { Self { raw: RawHandleOrSocket(RawEnum::Handle(handle.as_raw_handle())), _phantom: PhantomData, } } /// Construct a `BorrowedHandleOrSocket` from a `BorrowedSocket`. #[inline] pub fn from_socket(socket: BorrowedSocket<'a>) -> Self { Self { raw: RawHandleOrSocket(RawEnum::Socket(socket.as_raw_socket())), _phantom: PhantomData, } } /// Like [`AsHandle::as_handle`], but returns an `Option` so that /// it can return `None` if `self` doesn't contain a `BorrowedHandle`. /// /// [`AsHandle::as_handle`]: std::os::windows::io::AsHandle::as_handle #[inline] #[must_use] pub fn as_handle(&self) -> Option> { unsafe { match self.raw.0 { RawEnum::Handle(handle) => Some(BorrowedHandle::borrow_raw(handle)), RawEnum::Socket(_) => None, RawEnum::Stdio(ref stdio) => { Some(BorrowedHandle::borrow_raw(stdio.as_raw_handle())) } } } } /// Like [`AsSocket::as_socket`], but returns an `Option` so that /// it can return `None` if `self` doesn't contain a `BorrowedSocket`. /// /// [`AsSocket::as_socket`]: std::os::windows::io::AsSocket::as_socket #[inline] #[must_use] pub fn as_socket(&self) -> Option> { unsafe { match self.raw.0 { RawEnum::Handle(_) => None, RawEnum::Socket(socket) => Some(BorrowedSocket::borrow_raw(socket)), RawEnum::Stdio(_) => None, } } } } impl OwnedHandleOrSocket { /// Construct a new `OwnedHandleOrSocket` from an `OwnedHandle`. #[inline] pub fn from_handle(handle: OwnedHandle) -> Self { Self { raw: RawHandleOrSocket(RawEnum::Handle(handle.into_raw_handle())), } } /// Construct a new `OwnedHandleOrSocket` from an `OwnedSocket`. #[inline] pub fn from_socket(socket: OwnedSocket) -> Self { Self { raw: RawHandleOrSocket(RawEnum::Socket(socket.into_raw_socket())), } } /// Like [`AsHandle::as_handle`], but returns an `Option` so that /// it can return `None` if `self` doesn't contain a `BorrowedHandle`. /// /// [`AsHandle::as_handle`]: std::os::windows::io::AsHandle::as_handle #[inline] #[must_use] pub fn as_handle(&self) -> Option { unsafe { match self.raw.0 { RawEnum::Handle(handle) => Some(BorrowedHandle::borrow_raw(handle)), RawEnum::Socket(_) => None, RawEnum::Stdio(ref stdio) => { Some(BorrowedHandle::borrow_raw(stdio.as_raw_handle())) } } } } /// Like [`AsSocket::as_socket`], but returns an `Option` so that /// it can return `None` if `self` doesn't contain a `BorrowedSocket`. /// /// [`AsSocket::as_socket`]: std::os::windows::io::AsSocket::as_socket #[inline] #[must_use] pub fn as_socket(&self) -> Option { unsafe { match self.raw.0 { RawEnum::Handle(_) => None, RawEnum::Socket(socket) => Some(BorrowedSocket::borrow_raw(socket)), RawEnum::Stdio(_) => None, } } } } impl AsRawHandleOrSocket for OwnedHandleOrSocket { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { self.raw } } impl AsRawHandleOrSocket for BorrowedHandleOrSocket<'_> { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { self.raw } } impl IntoRawHandleOrSocket for OwnedHandleOrSocket { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { let raw = self.raw; forget(self); raw } } impl FromRawHandleOrSocket for OwnedHandleOrSocket { #[inline] unsafe fn from_raw_handle_or_socket(raw: RawHandleOrSocket) -> Self { match raw.0 { RawEnum::Handle(raw_handle) => assert!(!raw_handle.is_null()), RawEnum::Socket(raw_socket) => assert_ne!(raw_socket, INVALID_SOCKET as RawSocket), RawEnum::Stdio(_) => (), } Self { raw } } } impl Drop for OwnedHandleOrSocket { fn drop(&mut self) { match self.raw.0 { RawEnum::Handle(raw_handle) => unsafe { let _ = OwnedHandle::from_raw_handle(raw_handle); }, RawEnum::Socket(raw_socket) => unsafe { let _ = OwnedSocket::from_raw_socket(raw_socket); }, RawEnum::Stdio(_) => (), } } } impl fmt::Debug for BorrowedHandleOrSocket<'_> { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw handle or socket; don't try to print the path or // any information about it, because this information is otherwise // unavailable to safe portable Rust code. f.debug_struct("BorrowedHandleOrSocket") .field("raw", &self.raw) .finish() } } impl fmt::Debug for OwnedHandleOrSocket { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw handle or socket; don't try to print the path or // any information about it, because this information is otherwise // unavailable to safe portable Rust code. f.debug_struct("OwnedHandleOrSocket") .field("raw", &self.raw) .finish() } } io-extras-0.18.3/src/owned.rs000064400000000000000000000242561046102023000141120ustar 00000000000000//! `OwnedReadable` and `OwnedWriteable`. use crate::grip::{AsRawGrip, FromRawGrip, OwnedGrip}; use crate::raw::{RawReadable, RawWriteable}; #[cfg(not(windows))] use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; use std::fmt; use std::io::{self, IoSlice, IoSliceMut, Read, Write}; #[cfg(all(doc, not(windows)))] use std::net::TcpStream; #[cfg(unix)] use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; #[cfg(target_os = "wasi")] use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd}; #[cfg(windows)] use { crate::os::windows::{ AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, FromRawHandleOrSocket, IntoRawHandleOrSocket, OwnedHandleOrSocket, }, io_lifetimes::OwnedHandle, std::os::windows::io::{FromRawHandle, IntoRawHandle}, }; /// An owning I/O handle that implements [`Read`]. /// /// This doesn't implement `Into*` or `From*` traits. /// /// # Platform-specific behavior /// /// On Posix-ish platforms, this reads from the handle as if it were a /// [`File`]. On Windows, this reads from a file-like handle as if it were a /// [`File`], and from a socket-like handle as if it were a [`TcpStream`]. #[repr(transparent)] pub struct OwnedReadable(RawReadable); /// An owning I/O handle that implements [`Write`]. /// /// This doesn't implement `Into*` or `From*` traits. /// /// # Platform-specific behavior /// /// On Posix-ish platforms, this writes to the handle as if it were a /// [`File`]. On Windows, this writes to a file-like handle as if it were a /// [`File`], and to a socket-like handle as if it were a [`TcpStream`]. #[repr(transparent)] pub struct OwnedWriteable(RawWriteable); /// `OwnedReadable` owns its handle. #[cfg(not(windows))] impl AsFd for OwnedReadable { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { unsafe { BorrowedFd::borrow_raw(self.0.as_raw_fd()) } } } /// `OwnedReadable` owns its handle. #[cfg(not(windows))] impl From for OwnedFd { #[inline] fn from(owned: OwnedReadable) -> Self { unsafe { Self::from_raw_fd(owned.0.into_raw_fd()) } } } /// `OwnedReadable` owns its handle. #[cfg(not(windows))] impl From for OwnedReadable { #[inline] fn from(fd: OwnedFd) -> Self { unsafe { Self(RawReadable::from_raw_fd(fd.into_raw_fd())) } } } /// `OwnedWriteable` owns its handle. #[cfg(not(windows))] impl AsFd for OwnedWriteable { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { unsafe { BorrowedFd::borrow_raw(self.0.as_raw_fd()) } } } /// `OwnedWriteable` owns its handle. #[cfg(not(windows))] impl From for OwnedFd { #[inline] fn from(owned: OwnedWriteable) -> Self { unsafe { Self::from_raw_fd(owned.0.as_raw_fd()) } } } /// `OwnedWriteable` owns its handle. #[cfg(not(windows))] impl From for OwnedWriteable { #[inline] fn from(fd: OwnedFd) -> Self { unsafe { Self(RawWriteable::from_raw_fd(fd.into_raw_fd())) } } } // Windows implementations. /// `OwnedReadable` owns its handle. #[cfg(windows)] impl AsHandleOrSocket for OwnedReadable { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { unsafe { BorrowedHandleOrSocket::borrow_raw(self.0.as_raw_handle_or_socket()) } } } /// `OwnedReadable` owns its handle. #[cfg(windows)] impl From for OwnedHandleOrSocket { #[inline] fn from(readable: OwnedReadable) -> Self { unsafe { OwnedHandleOrSocket::from_raw_handle_or_socket(readable.0.into_raw_handle_or_socket()) } } } /// `OwnedReadable` owns its handle. #[cfg(windows)] impl From for OwnedReadable { #[inline] fn from(handle_or_socket: OwnedHandleOrSocket) -> Self { unsafe { Self(RawReadable::from_raw_handle_or_socket( handle_or_socket.into_raw_handle_or_socket(), )) } } } /// `OwnedReadable` owns its handle. #[cfg(windows)] impl From for OwnedReadable { #[inline] fn from(handle: OwnedHandle) -> Self { unsafe { Self(RawReadable::from_raw_handle(handle.into_raw_handle())) } } } /// `OwnedWriteable` owns its handle. #[cfg(windows)] impl AsHandleOrSocket for OwnedWriteable { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { unsafe { BorrowedHandleOrSocket::borrow_raw(self.0.as_raw_handle_or_socket()) } } } /// `OwnedWriteable` owns its handle. #[cfg(windows)] impl From for OwnedHandleOrSocket { #[inline] fn from(writeable: OwnedWriteable) -> Self { unsafe { OwnedHandleOrSocket::from_raw_handle_or_socket(writeable.0.into_raw_handle_or_socket()) } } } /// `OwnedWriteable` owns its handle. #[cfg(windows)] impl From for OwnedWriteable { #[inline] fn from(handle_or_socket: OwnedHandleOrSocket) -> Self { unsafe { Self(RawWriteable::from_raw_handle_or_socket( handle_or_socket.into_raw_handle_or_socket(), )) } } } /// `OwnedWriteable` owns its handle. #[cfg(windows)] impl From for OwnedWriteable { #[inline] fn from(handle: OwnedHandle) -> Self { unsafe { Self(RawWriteable::from_raw_handle(handle.into_raw_handle())) } } } #[cfg(not(windows))] impl Read for OwnedReadable { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } #[inline] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } #[cfg(can_vector)] #[inline] fn is_read_vectored(&self) -> bool { self.0.is_read_vectored() } #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.0.read_to_end(buf) } #[inline] fn read_to_string(&mut self, buf: &mut String) -> io::Result { self.0.read_to_string(buf) } #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { self.0.read_exact(buf) } } #[cfg(windows)] impl Read for OwnedReadable { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } #[inline] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } #[cfg(can_vector)] #[inline] fn is_read_vectored(&self) -> bool { self.0.is_read_vectored() } #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.0.read_to_end(buf) } #[inline] fn read_to_string(&mut self, buf: &mut String) -> io::Result { self.0.read_to_string(buf) } #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { self.0.read_exact(buf) } } #[cfg(not(windows))] impl Write for OwnedWriteable { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } #[inline] fn flush(&mut self) -> io::Result<()> { self.0.flush() } #[inline] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.0.write_vectored(bufs) } #[cfg(can_vector)] #[inline] fn is_write_vectored(&self) -> bool { self.0.is_write_vectored() } #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.0.write_all(buf) } #[cfg(write_all_vectored)] #[inline] fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { self.0.write_all_vectored(bufs) } #[inline] fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { self.0.write_fmt(fmt) } } #[cfg(windows)] impl Write for OwnedWriteable { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } #[inline] fn flush(&mut self) -> io::Result<()> { self.0.flush() } #[inline] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.0.write_vectored(bufs) } #[cfg(can_vector)] #[inline] fn is_write_vectored(&self) -> bool { self.0.is_write_vectored() } #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.0.write_all(buf) } #[cfg(write_all_vectored)] #[inline] fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { self.0.write_all_vectored(bufs) } #[inline] fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { self.0.write_fmt(fmt) } } impl Drop for OwnedReadable { #[inline] fn drop(&mut self) { unsafe { let _owned = OwnedGrip::from_raw_grip(self.0.as_raw_grip()); } } } impl Drop for OwnedWriteable { #[inline] fn drop(&mut self) { unsafe { let _owned = OwnedGrip::from_raw_grip(self.0.as_raw_grip()); } } } #[cfg(not(windows))] impl fmt::Debug for OwnedReadable { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw fd number. f.debug_struct("OwnedReadable") .field("fd", &self.0) .finish() } } #[cfg(windows)] impl fmt::Debug for OwnedReadable { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw handle or socket. f.debug_struct("OwnedReadable") .field("handle_or_socket", &self.0) .finish() } } #[cfg(not(windows))] impl fmt::Debug for OwnedWriteable { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw fd number. f.debug_struct("OwnedWriteable") .field("fd", &self.0) .finish() } } #[cfg(windows)] impl fmt::Debug for OwnedWriteable { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw handle or socket. f.debug_struct("OwnedWriteable") .field("handle_or_socket", &self.0) .finish() } } io-extras-0.18.3/src/raw.rs000064400000000000000000000336601046102023000135660ustar 00000000000000//! `RawReadable` and `RawWriteable`. use crate::grip::RawGrip; #[cfg(not(windows))] use crate::os::rustix::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use io_lifetimes::raw::RawFilelike; use io_lifetimes::views::FilelikeView; use std::fmt; use std::fs::File; use std::io::{self, IoSlice, IoSliceMut, Read, Write}; #[cfg(all(doc, not(windows)))] use std::net::TcpStream; #[cfg(windows)] use { crate::os::windows::{ AsRawHandleOrSocket, FromRawHandleOrSocket, IntoRawHandleOrSocket, RawEnum, RawHandleOrSocket, }, io_lifetimes::raw::RawSocketlike, io_lifetimes::views::SocketlikeView, std::net::TcpStream, std::os::windows::io::{FromRawHandle, RawHandle}, }; /// A non-owning unsafe I/O handle that implements [`Read`]. `Read` functions /// are considered safe, so this type requires `unsafe` to construct. /// /// This doesn't implement `Into*` or `From*` traits. /// /// # Platform-specific behavior /// /// On Posix-ish platforms, this reads from the handle as if it were a /// [`File`]. On Windows, this reads from a file-like handle as if it were a /// [`File`], and from a socket-like handle as if it were a [`TcpStream`]. #[derive(Copy, Clone)] #[repr(transparent)] pub struct RawReadable(RawGrip); /// A non-owning unsafe I/O handle that implements [`Write`]. `Write` functions /// considered are safe, so this type requires `unsafe` to construct. /// /// This doesn't implement `Into*` or `From*` traits. /// /// # Platform-specific behavior /// /// On Posix-ish platforms, this writes to the handle as if it were a /// [`File`]. On Windows, this writes to a file-like handle as if it were a /// [`File`], and to a socket-like handle as if it were a [`TcpStream`]. #[derive(Copy, Clone)] #[repr(transparent)] pub struct RawWriteable(RawGrip); /// `RawReadable` doesn't own its handle. #[cfg(not(windows))] impl AsRawFd for RawReadable { #[inline] fn as_raw_fd(&self) -> RawFd { self.0 } } /// `RawReadable` doesn't own its handle. #[cfg(not(windows))] impl IntoRawFd for RawReadable { #[inline] fn into_raw_fd(self) -> RawFd { self.0 } } /// `RawReadable` doesn't own its handle. #[cfg(not(windows))] impl FromRawFd for RawReadable { #[inline] unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { Self(raw_fd) } } /// `RawWriteable` doesn't own its handle. #[cfg(not(windows))] impl AsRawFd for RawWriteable { #[inline] fn as_raw_fd(&self) -> RawFd { self.0 } } /// `RawWriteable` doesn't own its handle. #[cfg(not(windows))] impl IntoRawFd for RawWriteable { #[inline] fn into_raw_fd(self) -> RawFd { self.0 } } /// `RawWriteable` doesn't own its handle. #[cfg(not(windows))] impl FromRawFd for RawWriteable { #[inline] unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { Self(raw_fd) } } // Windows implementations. /// `RawReadable` doesn't own its handle. #[cfg(windows)] impl AsRawHandleOrSocket for RawReadable { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { self.0 } } /// `RawReadable` doesn't own its handle. #[cfg(windows)] impl IntoRawHandleOrSocket for RawReadable { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { self.0 } } /// `RawReadable` doesn't own its handle. #[cfg(windows)] impl FromRawHandleOrSocket for RawReadable { #[inline] unsafe fn from_raw_handle_or_socket(raw_handle_or_socket: RawHandleOrSocket) -> Self { Self(raw_handle_or_socket) } } /// `RawReadable` doesn't own its handle. #[cfg(windows)] impl FromRawHandle for RawReadable { #[inline] unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { Self(RawHandleOrSocket::unowned_from_raw_handle(raw_handle)) } } /// `RawWriteable` doesn't own its handle. #[cfg(windows)] impl AsRawHandleOrSocket for RawWriteable { #[inline] fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket { self.0 } } /// `RawWriteable` doesn't own its handle. #[cfg(windows)] impl IntoRawHandleOrSocket for RawWriteable { #[inline] fn into_raw_handle_or_socket(self) -> RawHandleOrSocket { self.0 } } /// `RawWriteable` doesn't own its handle. #[cfg(windows)] impl FromRawHandleOrSocket for RawWriteable { #[inline] unsafe fn from_raw_handle_or_socket(raw_handle_or_socket: RawHandleOrSocket) -> Self { Self(raw_handle_or_socket) } } /// `RawWriteable` doesn't own its handle. #[cfg(windows)] impl FromRawHandle for RawWriteable { #[inline] unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { Self(RawHandleOrSocket::unowned_from_raw_handle(raw_handle)) } } #[inline] unsafe fn as_file_view<'a>(file: RawFilelike) -> FilelikeView<'a, File> { FilelikeView::<'a>::view_raw(file) } #[cfg(windows)] #[inline] unsafe fn as_socket_view<'a>(socket: RawSocketlike) -> SocketlikeView<'a, TcpStream> { SocketlikeView::<'a>::view_raw(socket) } #[cfg(not(windows))] impl Read for RawReadable { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { // Safety: The caller of `as_readable()`, which is unsafe, is expected // to ensure that the underlying resource outlives this // `RawReadable`. unsafe { &*as_file_view(self.0) }.read(buf) } #[inline] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { unsafe { &*as_file_view(self.0) }.read_vectored(bufs) } #[cfg(can_vector)] #[inline] fn is_read_vectored(&self) -> bool { unsafe { &*as_file_view(self.0) }.is_read_vectored() } #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { unsafe { &*as_file_view(self.0) }.read_to_end(buf) } #[inline] fn read_to_string(&mut self, buf: &mut String) -> io::Result { unsafe { &*as_file_view(self.0) }.read_to_string(buf) } #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { unsafe { &*as_file_view(self.0) }.read_exact(buf) } } #[cfg(windows)] impl Read for RawReadable { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { match self.0 .0 { RawEnum::Handle(raw_handle) => unsafe { &*as_file_view(raw_handle) }.read(buf), RawEnum::Socket(raw_socket) => unsafe { &*as_socket_view(raw_socket) }.read(buf), RawEnum::Stdio(ref mut stdio) => stdio.read(buf), } } #[inline] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { match self.0 .0 { RawEnum::Handle(raw_handle) => { unsafe { &*as_file_view(raw_handle) }.read_vectored(bufs) } RawEnum::Socket(raw_socket) => { unsafe { &*as_socket_view(raw_socket) }.read_vectored(bufs) } RawEnum::Stdio(ref mut stdio) => stdio.read_vectored(bufs), } } #[cfg(can_vector)] #[inline] fn is_read_vectored(&self) -> bool { match self.0 .0 { RawEnum::Handle(raw_handle) => unsafe { &*as_file_view(raw_handle) }.is_read_vectored(), RawEnum::Socket(raw_socket) => { unsafe { &*as_socket_view(raw_socket) }.is_read_vectored() } RawEnum::Stdio(ref stdio) => stdio.is_read_vectored(), } } #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { match self.0 .0 { RawEnum::Handle(raw_handle) => unsafe { &*as_file_view(raw_handle) }.read_to_end(buf), RawEnum::Socket(raw_socket) => unsafe { &*as_socket_view(raw_socket) }.read_to_end(buf), RawEnum::Stdio(ref mut stdio) => stdio.read_to_end(buf), } } #[inline] fn read_to_string(&mut self, buf: &mut String) -> io::Result { match self.0 .0 { RawEnum::Handle(raw_handle) => { unsafe { &*as_file_view(raw_handle) }.read_to_string(buf) } RawEnum::Socket(raw_socket) => { unsafe { &*as_socket_view(raw_socket) }.read_to_string(buf) } RawEnum::Stdio(ref mut stdio) => stdio.read_to_string(buf), } } #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { match self.0 .0 { RawEnum::Handle(raw_handle) => unsafe { &*as_file_view(raw_handle) }.read_exact(buf), RawEnum::Socket(raw_socket) => unsafe { &*as_socket_view(raw_socket) }.read_exact(buf), RawEnum::Stdio(ref mut stdio) => stdio.read_exact(buf), } } } #[cfg(not(windows))] impl Write for RawWriteable { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { // Safety: The caller of `as_writeable()`, which is unsafe, is expected // to ensure that the underlying resource outlives this // `RawReadable`. unsafe { &*as_file_view(self.0) }.write(buf) } #[inline] fn flush(&mut self) -> io::Result<()> { unsafe { &*as_file_view(self.0) }.flush() } #[inline] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { unsafe { &*as_file_view(self.0) }.write_vectored(bufs) } #[cfg(can_vector)] #[inline] fn is_write_vectored(&self) -> bool { unsafe { &*as_file_view(self.0) }.is_write_vectored() } #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { unsafe { &*as_file_view(self.0) }.write_all(buf) } #[cfg(write_all_vectored)] #[inline] fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { unsafe { &*as_file_view(self.0) }.write_all_vectored(bufs) } #[inline] fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { unsafe { &*as_file_view(self.0) }.write_fmt(fmt) } } #[cfg(windows)] impl Write for RawWriteable { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { match self.0 .0 { RawEnum::Handle(raw_handle) => unsafe { &*as_file_view(raw_handle) }.write(buf), RawEnum::Socket(raw_socket) => unsafe { &*as_socket_view(raw_socket) }.write(buf), RawEnum::Stdio(ref mut stdio) => stdio.write(buf), } } #[inline] fn flush(&mut self) -> io::Result<()> { match self.0 .0 { RawEnum::Handle(raw_handle) => unsafe { &*as_file_view(raw_handle) }.flush(), RawEnum::Socket(raw_socket) => unsafe { &*as_socket_view(raw_socket) }.flush(), RawEnum::Stdio(ref mut stdio) => stdio.flush(), } } #[inline] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { match self.0 .0 { RawEnum::Handle(raw_handle) => { unsafe { &*as_file_view(raw_handle) }.write_vectored(bufs) } RawEnum::Socket(raw_socket) => { unsafe { &*as_socket_view(raw_socket) }.write_vectored(bufs) } RawEnum::Stdio(ref mut stdio) => stdio.write_vectored(bufs), } } #[cfg(can_vector)] #[inline] fn is_write_vectored(&self) -> bool { match self.0 .0 { RawEnum::Handle(raw_handle) => { unsafe { &*as_file_view(raw_handle) }.is_write_vectored() } RawEnum::Socket(raw_socket) => { unsafe { &*as_socket_view(raw_socket) }.is_write_vectored() } RawEnum::Stdio(ref stdio) => stdio.is_write_vectored(), } } #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { match self.0 .0 { RawEnum::Handle(raw_handle) => unsafe { &*as_file_view(raw_handle) }.write_all(buf), RawEnum::Socket(raw_socket) => unsafe { &*as_socket_view(raw_socket) }.write_all(buf), RawEnum::Stdio(ref mut stdio) => stdio.write_all(buf), } } #[cfg(write_all_vectored)] #[inline] fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { match self.0 .0 { RawEnum::Handle(raw_handle) => { unsafe { &*as_file_view(raw_handle) }.write_all_vectored(bufs) } RawEnum::Socket(raw_socket) => { unsafe { &*as_socket_view(raw_socket) }.write_all_vectored(bufs) } RawEnum::Stdio(ref mut stdio) => stdio.write_all_vectored(bufs), } } #[inline] fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { match self.0 .0 { RawEnum::Handle(raw_handle) => unsafe { &*as_file_view(raw_handle) }.write_fmt(fmt), RawEnum::Socket(raw_socket) => unsafe { &*as_socket_view(raw_socket) }.write_fmt(fmt), RawEnum::Stdio(ref mut stdio) => stdio.write_fmt(fmt), } } } #[cfg(not(windows))] impl fmt::Debug for RawReadable { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw fd number. f.debug_struct("RawReadable") .field("raw_fd", &self.0) .finish() } } #[cfg(windows)] impl fmt::Debug for RawReadable { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw handle or socket. f.debug_struct("RawReadable") .field("raw_handle_or_socket", &self.0) .finish() } } #[cfg(not(windows))] impl fmt::Debug for RawWriteable { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw fd number. f.debug_struct("RawWriteable") .field("raw_fd", &self.0) .finish() } } #[cfg(windows)] impl fmt::Debug for RawWriteable { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just print the raw handle or socket. f.debug_struct("RawWriteable") .field("raw_handle_or_socket", &self.0) .finish() } } io-extras-0.18.3/src/read_write.rs000064400000000000000000000460071046102023000151210ustar 00000000000000//! Traits for working with types that may have up to two I/O objects. #[cfg(windows)] use crate::os::windows::{ AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, RawHandleOrSocket, }; use std::fs::File; use std::net::TcpStream; #[cfg(unix)] use std::os::unix::net::UnixStream; #[cfg(not(windows))] use { crate::os::rustix::{AsRawFd, RawFd}, io_lifetimes::{AsFd, BorrowedFd}, }; /// Like [`AsRawFd`], but for types which may have one or two file descriptors, /// for reading and writing. /// /// For types that only have one, both functions return the same value. #[cfg(not(windows))] pub trait AsRawReadWriteFd { /// Extracts the raw file descriptor for reading. /// /// Like [`AsRawFd::as_raw_fd`], but returns the reading file descriptor. fn as_raw_read_fd(&self) -> RawFd; /// Extracts the raw file descriptor for writing. /// /// Like [`AsRawFd::as_raw_fd`], but returns the writing file descriptor. fn as_raw_write_fd(&self) -> RawFd; } /// Like [`AsFd`], but for types which may have one or two file descriptors, /// for reading and writing. /// /// For types that only have one, both functions return the same value. #[cfg(not(windows))] pub trait AsReadWriteFd { /// Extracts the file descriptor for reading. /// /// Like [`AsFd::as_fd`], but returns the reading file descriptor. fn as_read_fd(&self) -> BorrowedFd<'_>; /// Extracts the file descriptor for writing. /// /// Like [`AsFd::as_fd`], but returns the writing file descriptor. fn as_write_fd(&self) -> BorrowedFd<'_>; } /// Like [`AsRawHandleOrSocket`], but for types which may have one or two /// handles or sockets, for reading and writing. /// /// For types that only have one, both functions return the same value. #[cfg(windows)] pub trait AsRawReadWriteHandleOrSocket { /// Extracts the raw handle or socket for reading. /// /// Like [`AsRawHandleOrSocket::as_raw_handle_or_socket`], but returns the /// reading handle. fn as_raw_read_handle_or_socket(&self) -> RawHandleOrSocket; /// Extracts the raw handle or socket for writing. /// /// Like [`AsRawHandleOrSocket::as_raw_handle_or_socket`], but returns the /// writing handle. fn as_raw_write_handle_or_socket(&self) -> RawHandleOrSocket; } /// Like [`AsHandleOrSocket`], but for types which may have one or two /// handles or sockets, for reading and writing. /// /// For types that only have one, both functions return the same value. #[cfg(windows)] pub trait AsReadWriteHandleOrSocket { /// Extracts the handle or socket for reading. /// /// Like [`AsHandleOrSocket::as_handle_or_socket`], but returns the /// reading handle. fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_>; /// Extracts the handle or socket for writing. /// /// Like [`AsHandleOrSocket::as_handle_or_socket`], but returns the /// writing handle. fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_>; } #[cfg(not(windows))] impl AsRawReadWriteFd for File { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(not(windows))] impl AsReadWriteFd for File { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(windows)] impl AsRawReadWriteHandleOrSocket for File { #[inline] fn as_raw_read_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } #[inline] fn as_raw_write_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } } #[cfg(windows)] impl AsReadWriteHandleOrSocket for File { #[inline] fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } #[inline] fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } } #[cfg(not(windows))] impl AsRawReadWriteFd for TcpStream { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(not(windows))] impl AsReadWriteFd for TcpStream { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(windows)] impl AsRawReadWriteHandleOrSocket for TcpStream { #[inline] fn as_raw_read_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } #[inline] fn as_raw_write_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } } #[cfg(windows)] impl AsReadWriteHandleOrSocket for TcpStream { #[inline] fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } #[inline] fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } } #[cfg(unix)] impl AsRawReadWriteFd for UnixStream { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(unix)] impl AsReadWriteFd for UnixStream { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(all(feature = "async-std", not(windows)))] impl AsRawReadWriteFd for async_std::fs::File { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(all(feature = "async-std", not(windows)))] impl AsReadWriteFd for async_std::fs::File { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(all(feature = "async-std", windows))] impl AsRawReadWriteHandleOrSocket for async_std::fs::File { #[inline] fn as_raw_read_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } #[inline] fn as_raw_write_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } } #[cfg(all(feature = "async-std", windows))] impl AsReadWriteHandleOrSocket for async_std::fs::File { #[inline] fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } #[inline] fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } } #[cfg(all(feature = "async-std", not(windows)))] impl AsRawReadWriteFd for async_std::net::TcpStream { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(all(feature = "async-std", not(windows)))] impl AsReadWriteFd for async_std::net::TcpStream { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(all(feature = "async-std", windows))] impl AsRawReadWriteHandleOrSocket for async_std::net::TcpStream { #[inline] fn as_raw_read_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } #[inline] fn as_raw_write_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } } #[cfg(all(feature = "async-std", windows))] impl AsReadWriteHandleOrSocket for async_std::net::TcpStream { #[inline] fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } #[inline] fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } } #[cfg(all(feature = "async-std", unix))] impl AsRawReadWriteFd for async_std::os::unix::net::UnixStream { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(all(feature = "async-std", unix))] impl AsReadWriteFd for async_std::os::unix::net::UnixStream { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(all(feature = "tokio", not(windows)))] impl AsRawReadWriteFd for tokio::fs::File { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(all(feature = "tokio", not(windows)))] impl AsReadWriteFd for tokio::fs::File { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(all(feature = "tokio", windows))] impl AsRawReadWriteHandleOrSocket for tokio::fs::File { #[inline] fn as_raw_read_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } #[inline] fn as_raw_write_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } } #[cfg(all(feature = "tokio", windows))] impl AsReadWriteHandleOrSocket for tokio::fs::File { #[inline] fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } #[inline] fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } } #[cfg(all(feature = "tokio", not(windows)))] impl AsRawReadWriteFd for tokio::net::TcpStream { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(all(feature = "tokio", not(windows)))] impl AsReadWriteFd for tokio::net::TcpStream { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(all(feature = "tokio", windows))] impl AsReadWriteHandleOrSocket for tokio::net::TcpStream { #[inline] fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } #[inline] fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } } #[cfg(all(feature = "tokio", unix))] impl AsRawReadWriteFd for tokio::net::UnixStream { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(all(feature = "tokio", unix))] impl AsReadWriteFd for tokio::net::UnixStream { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(not(windows))] impl AsRawReadWriteFd for Box { #[inline] fn as_raw_read_fd(&self) -> RawFd { (**self).as_raw_read_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { (**self).as_raw_write_fd() } } #[cfg(not(windows))] impl AsReadWriteFd for Box { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { (**self).as_read_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { (**self).as_write_fd() } } #[cfg(windows)] impl AsRawReadWriteHandleOrSocket for Box { #[inline] fn as_raw_read_handle_or_socket(&self) -> RawHandleOrSocket { (**self).as_raw_read_handle_or_socket() } #[inline] fn as_raw_write_handle_or_socket(&self) -> RawHandleOrSocket { (**self).as_raw_write_handle_or_socket() } } #[cfg(windows)] impl AsReadWriteHandleOrSocket for Box { #[inline] fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { (**self).as_read_handle_or_socket() } #[inline] fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { (**self).as_write_handle_or_socket() } } #[cfg(all(not(windows), feature = "socket2"))] impl AsRawReadWriteFd for socket2::Socket { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(all(not(windows), feature = "socket2"))] impl AsReadWriteFd for socket2::Socket { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(all(windows, feature = "socket2"))] impl AsRawReadWriteHandleOrSocket for socket2::Socket { #[inline] fn as_raw_read_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } #[inline] fn as_raw_write_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } } #[cfg(all(windows, feature = "socket2"))] impl AsReadWriteHandleOrSocket for socket2::Socket { #[inline] fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } #[inline] fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } } #[cfg(all(not(windows), feature = "use_mio_net"))] impl AsRawReadWriteFd for mio::net::TcpListener { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(all(not(windows), feature = "use_mio_net"))] impl AsReadWriteFd for mio::net::TcpListener { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(all(windows, feature = "use_mio_net"))] impl AsRawReadWriteHandleOrSocket for mio::net::TcpListener { #[inline] fn as_raw_read_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } #[inline] fn as_raw_write_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } } #[cfg(all(windows, feature = "use_mio_net"))] #[cfg(not(io_lifetimes_use_std))] // TODO: Enable once we have mio impls impl AsReadWriteHandleOrSocket for mio::net::TcpListener { #[inline] fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } #[inline] fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } } #[cfg(all(not(windows), feature = "use_mio_net"))] impl AsRawReadWriteFd for mio::net::TcpStream { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(all(not(windows), feature = "use_mio_net"))] impl AsReadWriteFd for mio::net::TcpStream { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(all(windows, feature = "use_mio_net"))] impl AsRawReadWriteHandleOrSocket for mio::net::TcpStream { #[inline] fn as_raw_read_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } #[inline] fn as_raw_write_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } } #[cfg(all(windows, feature = "use_mio_net"))] #[cfg(not(io_lifetimes_use_std))] // TODO: Enable once we have mio impls impl AsReadWriteHandleOrSocket for mio::net::TcpStream { #[inline] fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } #[inline] fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } } #[cfg(all(not(windows), feature = "use_mio_net"))] impl AsRawReadWriteFd for mio::net::UdpSocket { #[inline] fn as_raw_read_fd(&self) -> RawFd { self.as_raw_fd() } #[inline] fn as_raw_write_fd(&self) -> RawFd { self.as_raw_fd() } } #[cfg(all(not(windows), feature = "use_mio_net"))] impl AsReadWriteFd for mio::net::UdpSocket { #[inline] fn as_read_fd(&self) -> BorrowedFd<'_> { self.as_fd() } #[inline] fn as_write_fd(&self) -> BorrowedFd<'_> { self.as_fd() } } #[cfg(all(windows, feature = "use_mio_net"))] impl AsRawReadWriteHandleOrSocket for mio::net::UdpSocket { #[inline] fn as_raw_read_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } #[inline] fn as_raw_write_handle_or_socket(&self) -> RawHandleOrSocket { self.as_raw_handle_or_socket() } } #[cfg(all(windows, feature = "use_mio_net"))] #[cfg(not(io_lifetimes_use_std))] // TODO: Enable once we have mio impls impl AsReadWriteHandleOrSocket for mio::net::UdpSocket { #[inline] fn as_read_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } #[inline] fn as_write_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> { self.as_handle_or_socket() } } /// Adapt an `AsReadWriteGrip` implementation to implement /// `AsGrip` with the read handle. #[allow(clippy::exhaustive_structs)] #[derive(Debug, Copy, Clone)] pub struct ReadHalf<'a, RW>(&'a RW); impl<'a, RW> ReadHalf<'a, RW> { /// Returns a new instance of `Self`. #[inline] pub const fn new(rw: &'a RW) -> Self { Self(rw) } } #[cfg(not(windows))] impl<'a, RW: AsReadWriteFd> AsFd for ReadHalf<'a, RW> { #[inline] fn as_fd(&self) -> BorrowedFd<'a> { self.0.as_read_fd() } } #[cfg(windows)] impl<'a, RW: AsReadWriteHandleOrSocket> AsHandleOrSocket for ReadHalf<'a, RW> { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'a> { self.0.as_read_handle_or_socket() } } /// Adapt an `AsReadWriteGrip` implementation to implement /// `AsGrip` with the write handle. #[allow(clippy::exhaustive_structs)] #[derive(Debug, Copy, Clone)] pub struct WriteHalf<'a, RW>(&'a RW); impl<'a, RW> WriteHalf<'a, RW> { /// Returns a new instance of `Self`. #[inline] pub const fn new(rw: &'a RW) -> Self { Self(rw) } } #[cfg(not(windows))] impl<'a, RW: AsReadWriteFd> AsFd for WriteHalf<'a, RW> { #[inline] fn as_fd(&self) -> BorrowedFd<'a> { self.0.as_write_fd() } } #[cfg(windows)] impl<'a, RW: AsReadWriteHandleOrSocket> AsHandleOrSocket for WriteHalf<'a, RW> { #[inline] fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'a> { self.0.as_write_handle_or_socket() } }