Bug 1512445 - Re-vendor Rust dependencies for AudioIPC. r=chunmin

Differential Revision: https://phabricator.services.mozilla.com/D22154

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Matthew Gregan 2019-03-07 02:04:54 +00:00
parent 1ecd53f466
commit 3bc23059fe
21 changed files with 1429 additions and 34 deletions

49
Cargo.lock generated
View File

@ -90,19 +90,22 @@ version = "0.2.4"
dependencies = [
"bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.23 (git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64)",
"cubeb 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-named-pipes 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)",
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
]
[[package]]
@ -110,7 +113,7 @@ name = "audioipc-client"
version = "0.4.0"
dependencies = [
"audioipc 0.2.4",
"cubeb-backend 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-backend 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -126,7 +129,7 @@ version = "0.2.3"
dependencies = [
"audioipc 0.2.4",
"bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-core 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -671,34 +674,34 @@ dependencies = [
[[package]]
name = "cubeb"
version = "0.5.2"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cubeb-core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-core 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cubeb-backend"
version = "0.5.1"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cubeb-core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-core 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cubeb-core"
version = "0.5.1"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cubeb-pulse"
version = "0.2.0"
dependencies = [
"cubeb-backend 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-backend 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"pulse 0.2.0",
"pulse-ffi 0.1.0",
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -706,11 +709,10 @@ dependencies = [
[[package]]
name = "cubeb-sys"
version = "0.5.1"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1118,7 +1120,7 @@ dependencies = [
"audioipc-server 0.2.3",
"cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-pulse 0.2.0",
"cubeb-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_c 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_glue 0.1.0",
"env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1626,6 +1628,18 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio-named-pipes"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio-uds"
version = "0.6.4"
@ -3354,10 +3368,10 @@ dependencies = [
"checksum cssparser-macros 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f3a5383ae18dbfdeb569ed62019f5bddb2a95cd2d3833313c475a0d014777805"
"checksum cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b6557bdb1dc9647eae1cf7f5601b14cd45fc3c7ccf2df618387416fe542da6ea"
"checksum cstr-macros 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0472c17c83d3ec1af32fb6ee2b3ad56ae0b6e69355d63d1d30602055c34324a8"
"checksum cubeb 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a3502aafa1bf95c524f65d2ba46d8741700c6a8a9543ea52c6da3d8b69a2896"
"checksum cubeb-backend 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0432a0d08c3f9a778a2b0b6214c87ec2eb17e8639eb68baf0686bdafc4fd11f1"
"checksum cubeb-core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37f7b20f757a4e4b6aa28863236551bff77682dc6db192eba15af615492b5445"
"checksum cubeb-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "653b9e245d35dbe2a2da7c4586275cee75ff656ddeb02d4a73b4afdfa6d67502"
"checksum cubeb 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "db3f0df2ad5cb453126364a77921466ba6c1034e8bd9247f326cdb31430dbc2a"
"checksum cubeb-backend 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "442cd5cfb980ff62730525278ce320d9b2ff635b725857ad3176832664262fec"
"checksum cubeb-core 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0161f9327864922ba7a172c90bd86bc9094938433eca415e2c75629954045022"
"checksum cubeb-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba7540c17b90159cf7d7854da370998ff0560d9b90e2c9290bb588afa0edf95"
"checksum darling 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f593353cad5af2df6d54810de2b61aa8acba5b5fbc70b0d75e7cc5bdd80aca73"
"checksum darling_core 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "168c246e87e727d58575d9b4595491010627f0cdc910e3e6ea3b36db2b9a9d9a"
"checksum darling_macro 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "99c4eff4bcbeaf6a22578012ff79c95910338668278d1901e528bd34a22f575d"
@ -3439,6 +3453,7 @@ dependencies = [
"checksum miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aaa2d3ad070f428fffbd7d3ca2ea20bb0d8cffe9024405c44e1840bc1418b398"
"checksum miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "92d98fdbd6145645828069b37ea92ca3de225e000d80702da25c20d3584b38a5"
"checksum mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4fcfcb32d63961fb6f367bfd5d21e4600b92cd310f71f9dca25acae196eb1560"
"checksum mio-named-pipes 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "82f43a815b57d2d652550f3d20cec88a495bb2d0956aa873dc43040278455677"
"checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum moz_cbor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20c82a57087fd5990d7122dbff1607c3b20c3d2958e9d9ad9765aab415e2c91c"

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"5009330f8a03fc0cf4b10540514496db0281bb92541f9850217c5de7d12dc8b7","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/capi.rs":"300e76bd3901de540b21a2cfc8d15dbcd1b2940d5fbb517fc5fe568af2ec2775","src/lib.rs":"94b80747ae1037423a2281f2572fc6d15cd7702417974ae3730adccd71c7a300","src/log.rs":"704faeb31934dad6bc6d02e01caa85118754209bd559d30d03fcfa5cb8c1603c","src/ops.rs":"55cbf9bdccdd854834eba72e8bde3e59a9a4193e65209769a1a6e0d8a320b8f6","src/traits.rs":"1a6e3401bb25088d355041704bd89099d62b51eda94da177e7e860646c52b955","tests/test_capi.rs":"9d949cbdb1c19e229ce4f652999a058c283cf7d5a882a669dbca08b71ac2fb62"},"package":"0432a0d08c3f9a778a2b0b6214c87ec2eb17e8639eb68baf0686bdafc4fd11f1"}
{"files":{"Cargo.toml":"1933f3fab97c50556ade6cc02e82b911aa7d7787be13501e9ea8dc09b85b2739","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/capi.rs":"300e76bd3901de540b21a2cfc8d15dbcd1b2940d5fbb517fc5fe568af2ec2775","src/lib.rs":"94b80747ae1037423a2281f2572fc6d15cd7702417974ae3730adccd71c7a300","src/log.rs":"704faeb31934dad6bc6d02e01caa85118754209bd559d30d03fcfa5cb8c1603c","src/ops.rs":"55cbf9bdccdd854834eba72e8bde3e59a9a4193e65209769a1a6e0d8a320b8f6","src/traits.rs":"1a6e3401bb25088d355041704bd89099d62b51eda94da177e7e860646c52b955","tests/test_capi.rs":"9d949cbdb1c19e229ce4f652999a058c283cf7d5a882a669dbca08b71ac2fb62"},"package":"442cd5cfb980ff62730525278ce320d9b2ff635b725857ad3176832664262fec"}

View File

@ -12,7 +12,7 @@
[package]
name = "cubeb-backend"
version = "0.5.1"
version = "0.5.4"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
description = "Bindings to libcubeb internals to facilitate implementing cubeb backends in rust.\n"
homepage = "https://github.com/djg/cubeb-rs"
@ -21,7 +21,7 @@ categories = ["api-bindings"]
license = "ISC"
repository = "https://github.com/djg/cubeb-rs"
[dependencies.cubeb-core]
version = "0.5.0"
version = "0.5.4"
[features]
gecko-in-tree = ["cubeb-core/gecko-in-tree"]

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"c379f4deb07a056d5d1679f4641c3a29dec6c74a82b2304cbf5ec65488e5a9bc","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/builders.rs":"ca97e3a3d1f3fc451c17851c8538964ec67f3964dfe29e902d904ee7445becca","src/channel.rs":"c8d5a76ef3ecdd96cd4de516e3d4d139bbb83c4690d1c3f5fd07fffc47be51f1","src/context.rs":"09625b75070ec88d566a907ab2e574e2d85df4c6df295f798b3372df2cdc8f7a","src/device.rs":"490d2e94ecae1e149476c2e8d9aa03c4163987c3efccc962b2d3123e4c09dedf","src/device_collection.rs":"f6d0c1628cc34b524f86b84a1e1c79971c3f64ebc4ac64eeb10a1330bbe8c238","src/error.rs":"855ff3d3597753f832ecea00e403c71129afd80db3d39456cf3e23cb9aeb91e7","src/ffi_types.rs":"d815d7a80895b5e86907e708dc0219fca4ac4668cde114afee434e7d702a145d","src/format.rs":"5513c537a72af1c222ee7c30b26d4de9d368a69772688b95d88b1a99f6892d5c","src/lib.rs":"6010a5e20b836b8e5c9fba382fde819e6f3c18c0ec2016e6e7e118eabedbcd51","src/log.rs":"c46bae3472043fd076df3229c3421d948a87fae8495c1524b41ab2d8608f612a","src/stream.rs":"775b9af0e3d8c1a7a38f96b8365a632a9d52a43541d96ede9a4ed9688c2dc914","src/try_call.rs":"231bfa3f3448f7531427bb228beb2bcd4fd711f0b13d2d8f412af013470f40c7","src/util.rs":"308cfbaacd615ff600e74415c52daeef007fff34a4a0648a73c0042f6067f84f"},"package":"37f7b20f757a4e4b6aa28863236551bff77682dc6db192eba15af615492b5445"}
{"files":{"Cargo.toml":"5606a2dfca9a44892ebfbc7caa0a96a50e8bb96676f7a9aaf584b3d459843d86","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/builders.rs":"ca97e3a3d1f3fc451c17851c8538964ec67f3964dfe29e902d904ee7445becca","src/channel.rs":"c8d5a76ef3ecdd96cd4de516e3d4d139bbb83c4690d1c3f5fd07fffc47be51f1","src/context.rs":"09625b75070ec88d566a907ab2e574e2d85df4c6df295f798b3372df2cdc8f7a","src/device.rs":"490d2e94ecae1e149476c2e8d9aa03c4163987c3efccc962b2d3123e4c09dedf","src/device_collection.rs":"f6d0c1628cc34b524f86b84a1e1c79971c3f64ebc4ac64eeb10a1330bbe8c238","src/error.rs":"855ff3d3597753f832ecea00e403c71129afd80db3d39456cf3e23cb9aeb91e7","src/ffi_types.rs":"d815d7a80895b5e86907e708dc0219fca4ac4668cde114afee434e7d702a145d","src/format.rs":"5513c537a72af1c222ee7c30b26d4de9d368a69772688b95d88b1a99f6892d5c","src/lib.rs":"6010a5e20b836b8e5c9fba382fde819e6f3c18c0ec2016e6e7e118eabedbcd51","src/log.rs":"c46bae3472043fd076df3229c3421d948a87fae8495c1524b41ab2d8608f612a","src/stream.rs":"775b9af0e3d8c1a7a38f96b8365a632a9d52a43541d96ede9a4ed9688c2dc914","src/try_call.rs":"231bfa3f3448f7531427bb228beb2bcd4fd711f0b13d2d8f412af013470f40c7","src/util.rs":"308cfbaacd615ff600e74415c52daeef007fff34a4a0648a73c0042f6067f84f"},"package":"0161f9327864922ba7a172c90bd86bc9094938433eca415e2c75629954045022"}

View File

@ -12,7 +12,7 @@
[package]
name = "cubeb-core"
version = "0.5.1"
version = "0.5.4"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
description = "Common types and definitions for cubeb rust and C bindings. Not intended for direct use.\n"
homepage = "https://github.com/djg/cubeb-rs"
@ -24,7 +24,7 @@ repository = "https://github.com/djg/cubeb-rs"
version = "1.0"
[dependencies.cubeb-sys]
version = "0.5.0"
version = "0.5.4"
[features]
gecko-in-tree = ["cubeb-sys/gecko-in-tree"]

File diff suppressed because one or more lines are too long

View File

@ -12,7 +12,7 @@
[package]
name = "cubeb-sys"
version = "0.5.1"
version = "0.5.4"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
build = "build.rs"
links = "cubeb"
@ -22,9 +22,6 @@ repository = "https://github.com/djg/cubeb-rs"
[build-dependencies.cmake]
version = "0.1.2"
[build-dependencies.gcc]
version = "0.3"
[build-dependencies.pkg-config]
version = "0.3"

View File

@ -4,7 +4,6 @@
// accompanying file LICENSE for details.
extern crate cmake;
extern crate gcc;
extern crate pkg_config;
use std::env;

View File

@ -4,6 +4,7 @@
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
#define MINGW_HAS_SECURE_API 1
#define _WIN32_WINNT 0x0600
#define NOMINMAX

View File

@ -3,10 +3,13 @@
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
use std::os::raw::c_uint;
#[cfg(all(windows, not(target_env = "gnu")))]
use std::os::raw::c_int as c_enum;
#[cfg(any(not(windows), all(windows, target_env = "gnu")))]
use std::os::raw::c_uint as c_enum;
cubeb_enum! {
pub enum cubeb_channel : c_uint {
pub enum cubeb_channel : c_enum {
CHANNEL_UNKNOWN = 0,
CHANNEL_FRONT_LEFT = 1 << 0,
CHANNEL_FRONT_RIGHT = 1 << 1,

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"7c56fd36743a0c83f3977d8b24e67abff5ecd34e4e6043742ff331746165c60a","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","README.md":"408c573ec240927cf5b9c036098e94e374ec41f71991415422586f450586b214","examples/common/mod.rs":"a5e1b79fc2b4addff1e442879ba3dbcb1cf5973e76b9a62d97dd0042597480db","examples/devices.rs":"89e13542853995d1ae4a49d6829156efb29dd25c6caffdf22496c28c8263ffeb","examples/tone.rs":"8f5f9851b6d99f6f16c597fcb9312e3ef81769cbfb89341d2ea2522ca2e2214e","src/context.rs":"03511fa960a411728163e700edc2fd6cfbfcf09766ffe62ee82a2cbd08fdf243","src/frame.rs":"ed1e8f4576022d0c23106bb115125e5a2967b0375a10d0c54bbe99f04a70cc3f","src/lib.rs":"98e9280890551ac9305f2f808e315b6aa6bcd5781b8e96a078787ded0ef91e2a","src/log.rs":"704faeb31934dad6bc6d02e01caa85118754209bd559d30d03fcfa5cb8c1603c","src/sample.rs":"e23be3b691052001916f920ce9c1a0051bd097e39c9d34cbcb80ab8120265f45","src/stream.rs":"3ee0432f655cd42959cd5d8e75cb4fe2322e1f88fa5d9cc83e615ae229cdeb8a"},"package":"8a3502aafa1bf95c524f65d2ba46d8741700c6a8a9543ea52c6da3d8b69a2896"}
{"files":{"Cargo.toml":"fbfad79bbb62cf1ff067b5c73d239d7d9acf84be48492af1af55b55acc52904a","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","README.md":"408c573ec240927cf5b9c036098e94e374ec41f71991415422586f450586b214","examples/common/mod.rs":"a5e1b79fc2b4addff1e442879ba3dbcb1cf5973e76b9a62d97dd0042597480db","examples/devices.rs":"89e13542853995d1ae4a49d6829156efb29dd25c6caffdf22496c28c8263ffeb","examples/tone.rs":"8f5f9851b6d99f6f16c597fcb9312e3ef81769cbfb89341d2ea2522ca2e2214e","src/context.rs":"03511fa960a411728163e700edc2fd6cfbfcf09766ffe62ee82a2cbd08fdf243","src/frame.rs":"ed1e8f4576022d0c23106bb115125e5a2967b0375a10d0c54bbe99f04a70cc3f","src/lib.rs":"98e9280890551ac9305f2f808e315b6aa6bcd5781b8e96a078787ded0ef91e2a","src/log.rs":"704faeb31934dad6bc6d02e01caa85118754209bd559d30d03fcfa5cb8c1603c","src/sample.rs":"e23be3b691052001916f920ce9c1a0051bd097e39c9d34cbcb80ab8120265f45","src/stream.rs":"3ee0432f655cd42959cd5d8e75cb4fe2322e1f88fa5d9cc83e615ae229cdeb8a"},"package":"db3f0df2ad5cb453126364a77921466ba6c1034e8bd9247f326cdb31430dbc2a"}

View File

@ -12,7 +12,7 @@
[package]
name = "cubeb"
version = "0.5.2"
version = "0.5.4"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
description = "Bindings to libcubeb for interacting with system audio from rust.\n"
homepage = "https://github.com/djg/cubeb-rs"
@ -22,7 +22,7 @@ categories = ["api-bindings"]
license = "ISC"
repository = "https://github.com/djg/cubeb-rs"
[dependencies.cubeb-core]
version = "0.5.1"
version = "0.5.4"
[features]
gecko-in-tree = ["cubeb-core/gecko-in-tree"]

View File

@ -0,0 +1 @@
{"files":{"Cargo.toml":"d0a5c57e548259b2ef7d6e443f72a91775cfd20b926ccd88d7505ce24400faa1","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"76068a8cb49c12b1f45599fe8ed1ed53554485afe1cc5302360cc73687458a1a","appveyor.yml":"0bd9b8e5a94a36972b37227cc59984fc6ec01b4ee4b617ef20d0e3acd19f44b1","src/from_raw_arc.rs":"c2cee14a0355256beb55a1feb54ccdcc50c8ab2d9abb3b7f114be00ed8a5583f","src/lib.rs":"1eaafb6635a525abfea3eefdeba831e3bae2f80dda847f8a7102f26f32cbddad","tests/smoke.rs":"b1bd2ecbaae2a6458fdc2c50b8b1607277108196b607c12f47f4c5c78b9a250e"},"package":"82f43a815b57d2d652550f3d20cec88a495bb2d0956aa873dc43040278455677"}

View File

@ -0,0 +1,23 @@
[package]
name = "mio-named-pipes"
version = "0.1.5"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
license = "MIT/Apache-2.0"
readme = "README.md"
repository = "https://github.com/alexcrichton/mio-named-pipes"
homepage = "https://github.com/alexcrichton/mio-named-pipes"
documentation = "https://docs.rs/mio-named-pipes/0.1/x86_64-pc-windows-msvc/mio_named_pipes/"
description = """
Windows named pipe bindings for mio.
"""
[target.'cfg(windows)'.dependencies]
kernel32-sys = "0.2"
log = "0.3"
mio = "0.6.5"
miow = "0.2"
winapi = "0.2"
[dev-dependencies]
env_logger = { version = "0.3", default-features = false }
rand = "0.3"

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,25 @@
Copyright (c) 2014 Alex Crichton
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,42 @@
# mio-named-pipes
[![Build status](https://ci.appveyor.com/api/projects/status/y0ct01srewnhhesn?svg=true)](https://ci.appveyor.com/project/alexcrichton/mio-named-pipes)
[Documentation](https://docs.rs/mio-named-pipes/0.1/x86_64-pc-windows-msvc/mio_named_pipes/)
A library for integrating Windows [Named Pipes] with [mio].
[Named Pipes]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365590(v=vs.85).aspx
[mio]: https://github.com/carllerche/mio
```toml
# Cargo.toml
[dependencies]
mio-named-pipes = "0.6"
mio = "0.6"
```
## Usage
The primary type, `NamedPipe`, can be constructed with `NamedPipe::new` or
through the `IntoRawHandle` type. All operations on `NamedPipe` are nonblocking
and will return an I/O error if they'd block (with the error indicating so).
Typically you can use a `NamedPipe` in the same way you would a TCP socket on
Windows with mio.
> **Note**: Named pipes on Windows do not have a zero-cost abstraction when
> working with the mio interface (readiness, not completion). As a result, this
> library internally has some buffer management that hasn't been optimized yet.
> It's recommended you benchmark this library for your application, and feel
> free to contact me if anything looks awry.
# License
`mio-named-pipes` is primarily distributed under the terms of both the MIT
license and the Apache License (Version 2.0), with portions covered by various
BSD-like licenses.
See LICENSE-APACHE, and LICENSE-MIT for details.

View File

@ -0,0 +1,18 @@
environment:
matrix:
- TARGET: x86_64-pc-windows-msvc
GH_TOKEN:
secure: nHB4fVo+y/Aak+L0nYfrT8Rcs8OfUNm0F2xcIVFVYJ9ehf0CzvCmSMUvWguM0kKp
install:
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
- rustup-init.exe -y --default-host %TARGET%
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin;C:\MinGW\bin
- rustc -vV
- cargo -vV
build: false
test_script:
- cargo test

View File

@ -0,0 +1,116 @@
//! A "Manual Arc" which allows manually frobbing the reference count
//!
//! This module contains a copy of the `Arc` found in the standard library,
//! stripped down to the bare bones of what we actually need. The reason this is
//! done is for the ability to concretely know the memory layout of the `Inner`
//! structure of the arc pointer itself (e.g. `ArcInner` in the standard
//! library).
//!
//! We do some unsafe casting from `*mut OVERLAPPED` to a `FromRawArc<T>` to
//! ensure that data lives for the length of an I/O operation, but this means
//! that we have to know the layouts of the structures involved. This
//! representation primarily guarantees that the data, `T` is at the front of
//! the inner pointer always.
//!
//! Note that we're missing out on some various optimizations implemented in the
//! standard library:
//!
//! * The size of `FromRawArc` is actually two words because of the drop flag
//! * The compiler doesn't understand that the pointer in `FromRawArc` is never
//! null, so Option<FromRawArc<T>> is not a nullable pointer.
use std::ops::Deref;
use std::mem;
use std::sync::atomic::{self, AtomicUsize, Ordering};
pub struct FromRawArc<T> {
_inner: *mut Inner<T>,
}
unsafe impl<T: Sync + Send> Send for FromRawArc<T> { }
unsafe impl<T: Sync + Send> Sync for FromRawArc<T> { }
#[repr(C)]
struct Inner<T> {
data: T,
cnt: AtomicUsize,
}
impl<T> FromRawArc<T> {
pub fn new(data: T) -> FromRawArc<T> {
let x = Box::new(Inner {
data: data,
cnt: AtomicUsize::new(1),
});
FromRawArc { _inner: unsafe { mem::transmute(x) } }
}
pub unsafe fn from_raw(ptr: *mut T) -> FromRawArc<T> {
// Note that if we could use `mem::transmute` here to get a libstd Arc
// (guaranteed) then we could just use std::sync::Arc, but this is the
// crucial reason this currently exists.
FromRawArc { _inner: ptr as *mut Inner<T> }
}
}
impl<T> Clone for FromRawArc<T> {
fn clone(&self) -> FromRawArc<T> {
// Atomic ordering of Relaxed lifted from libstd, but the general idea
// is that you need synchronization to communicate this increment to
// another thread, so this itself doesn't need to be synchronized.
unsafe {
(*self._inner).cnt.fetch_add(1, Ordering::Relaxed);
}
FromRawArc { _inner: self._inner }
}
}
impl<T> Deref for FromRawArc<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &(*self._inner).data }
}
}
impl<T> Drop for FromRawArc<T> {
fn drop(&mut self) {
unsafe {
// Atomic orderings lifted from the standard library
if (*self._inner).cnt.fetch_sub(1, Ordering::Release) != 1 {
return
}
atomic::fence(Ordering::Acquire);
drop(mem::transmute::<_, Box<T>>(self._inner));
}
}
}
#[cfg(test)]
mod tests {
use super::FromRawArc;
#[test]
fn smoke() {
let a = FromRawArc::new(1);
assert_eq!(*a, 1);
assert_eq!(*a.clone(), 1);
}
#[test]
fn drops() {
struct A<'a>(&'a mut bool);
impl<'a> Drop for A<'a> {
fn drop(&mut self) {
*self.0 = true;
}
}
let mut a = false;
{
let a = FromRawArc::new(A(&mut a));
a.clone();
assert!(!*a.0);
}
assert!(a);
}
}

View File

@ -0,0 +1,681 @@
//! Windows named pipes bindings for mio.
//!
//! This crate implements bindings for named pipes for the mio crate. This
//! crate compiles on all platforms but only contains anything on Windows.
//! Currently this crate requires mio 0.6.2.
//!
//! On Windows, mio is implemented with an IOCP object at the heart of its
//! `Poll` implementation. For named pipes, this means that all I/O is done in
//! an overlapped fashion and the named pipes themselves are registered with
//! mio's internal IOCP object. Essentially, this crate is using IOCP for
//! bindings with named pipes.
//!
//! Note, though, that IOCP is a *completion* based model whereas mio expects a
//! *readiness* based model. As a result this crate, like with TCP objects in
//! mio, has internal buffering to translate the completion model to a readiness
//! model. This means that this crate is not a zero-cost binding over named
//! pipes on Windows, but rather approximates the performance of mio's TCP
//! implementation on Windows.
//!
//! # Trait implementations
//!
//! The `Read` and `Write` traits are implemented for `NamedPipe` and for
//! `&NamedPipe`. This represents that a named pipe can be concurrently read and
//! written to and also can be read and written to at all. Typically a named
//! pipe needs to be connected to a client before it can be read or written,
//! however.
//!
//! Note that for I/O operations on a named pipe to succeed then the named pipe
//! needs to be associated with an event loop. Until this happens all I/O
//! operations will return a "would block" error.
//!
//! # Managing connections
//!
//! The `NamedPipe` type supports a `connect` method to connect to a client and
//! a `disconnect` method to disconnect from that client. These two methods only
//! work once a named pipe is associated with an event loop.
//!
//! The `connect` method will succeed asynchronously and a completion can be
//! detected once the object receives a writable notification.
//!
//! # Named pipe clients
//!
//! Currently to create a client of a named pipe server then you can use the
//! `OpenOptions` type in the standard library to create a `File` that connects
//! to a named pipe. Afterwards you can use the `into_raw_handle` method coupled
//! with the `NamedPipe::from_raw_handle` method to convert that to a named pipe
//! that can operate asynchronously. Don't forget to pass the
//! `FILE_FLAG_OVERLAPPED` flag when opening the `File`.
#![cfg(windows)]
#![deny(missing_docs)]
extern crate kernel32;
#[macro_use]
extern crate log;
extern crate mio;
extern crate miow;
extern crate winapi;
use std::ffi::OsStr;
use std::fmt;
use std::io::prelude::*;
use std::io;
use std::mem;
use std::os::windows::io::*;
use std::slice;
use std::sync::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;
use mio::windows;
use mio::{Registration, Poll, Token, PollOpt, Ready, Evented, SetReadiness};
use miow::iocp::CompletionStatus;
use miow::pipe;
use winapi::{ERROR_PIPE_LISTENING, OVERLAPPED_ENTRY, ERROR_BROKEN_PIPE};
mod from_raw_arc;
use from_raw_arc::FromRawArc;
macro_rules! offset_of {
($t:ty, $($field:ident).+) => (
&(*(0 as *const $t)).$($field).+ as *const _ as usize
)
}
macro_rules! overlapped2arc {
($e:expr, $t:ty, $($field:ident).+) => ({
let offset = offset_of!($t, $($field).+);
debug_assert!(offset < mem::size_of::<$t>());
FromRawArc::from_raw(($e as usize - offset) as *mut $t)
})
}
fn would_block() -> io::Error {
io::Error::new(io::ErrorKind::WouldBlock, "would block")
}
/// Representation of a named pipe on Windows.
///
/// This structure internally contains a `HANDLE` which represents the named
/// pipe, and also maintains state associated with the mio event loop and active
/// I/O operations that have been scheduled to translate IOCP to a readiness
/// model.
pub struct NamedPipe {
registered: AtomicBool,
ready_registration: Registration,
poll_registration: windows::Binding,
inner: FromRawArc<Inner>,
}
struct Inner {
handle: pipe::NamedPipe,
readiness: SetReadiness,
connect: windows::Overlapped,
connecting: AtomicBool,
read: windows::Overlapped,
write: windows::Overlapped,
io: Mutex<Io>,
}
struct Io {
read: State,
write: State,
connect_error: Option<io::Error>,
}
enum State {
None,
Pending(Vec<u8>, usize),
Ok(Vec<u8>, usize),
Err(io::Error),
}
fn _assert_kinds() {
fn _assert_send<T: Send>() {}
fn _assert_sync<T: Sync>() {}
_assert_send::<NamedPipe>();
_assert_sync::<NamedPipe>();
}
impl NamedPipe {
/// Creates a new named pipe at the specified `addr` given a "reasonable
/// set" of initial configuration options.
///
/// Currently the configuration options are the [same as miow]. To change
/// these options, you can create a custom named pipe yourself and then use
/// the `FromRawHandle` constructor to convert that type to an instance of a
/// `NamedPipe` in this crate.
///
/// [same as miow]: https://docs.rs/miow/0.1.4/x86_64-pc-windows-msvc/miow/pipe/struct.NamedPipe.html#method.new
pub fn new<A: AsRef<OsStr>>(addr: A) -> io::Result<NamedPipe> {
NamedPipe::_new(addr.as_ref())
}
fn _new(addr: &OsStr) -> io::Result<NamedPipe> {
let pipe = try!(pipe::NamedPipe::new(addr));
unsafe {
Ok(NamedPipe::from_raw_handle(pipe.into_raw_handle()))
}
}
/// Attempts to call `ConnectNamedPipe`, if possible.
///
/// This function will attempt to connect this pipe to a client in an
/// asynchronous fashion. If the function immediately establishes a
/// connection to a client then `Ok(())` is returned. Otherwise if a
/// connection attempt was issued and is now in progress then a "would
/// block" error is returned.
///
/// When the connection is finished then this object will be flagged as
/// being ready for a write, or otherwise in the writable state.
///
/// # Errors
///
/// This function will return a "would block" error if the pipe has not yet
/// been registered with an event loop, if the connection operation has
/// previously been issued but has not yet completed, or if the connect
/// itself was issued and didn't finish immediately.
///
/// Normal I/O errors from the call to `ConnectNamedPipe` are returned
/// immediately.
pub fn connect(&self) -> io::Result<()> {
// Make sure we're associated with an IOCP object
if !self.registered() {
return Err(would_block())
}
// "Acquire the connecting lock" or otherwise just make sure we're the
// only operation that's using the `connect` overlapped instance.
if self.inner.connecting.swap(true, SeqCst) {
return Err(would_block())
}
// Now that we've flagged ourselves in the connecting state, issue the
// connection attempt. Afterwards interpret the return value and set
// internal state accordingly.
let res = unsafe {
let overlapped = self.inner.connect.as_mut_ptr();
self.inner.handle.connect_overlapped(overlapped)
};
match res {
// The connection operation finished immediately, so let's schedule
// reads/writes and such.
Ok(true) => {
trace!("connect done immediately");
self.inner.connecting.store(false, SeqCst);
Inner::post_register(&self.inner);
Ok(())
}
// If the overlapped operation was successful and didn't finish
// immediately then we forget a copy of the arc we hold
// internally. This ensures that when the completion status comes
// in for the I/O operation finishing it'll have a reference
// associated with it and our data will still be valid. The
// `connect_done` function will "reify" this forgotten pointer to
// drop the refcount on the other side.
Ok(false) => {
trace!("connect in progress");
mem::forget(self.inner.clone());
Err(would_block())
}
// TODO: are we sure no IOCP notification comes in here?
Err(e) => {
trace!("connect error: {}", e);
self.inner.connecting.store(false, SeqCst);
Err(e)
}
}
}
/// Takes any internal error that has happened after the last I/O operation
/// which hasn't been retrieved yet.
///
/// This is particularly useful when detecting failed attempts to `connect`.
/// After a completed `connect` flags this pipe as writable then callers
/// must invoke this method to determine whether the connection actually
/// succeeded. If this function returns `None` then a client is connected,
/// otherwise it returns an error of what happened and a client shouldn't be
/// connected.
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
Ok(self.inner.io.lock().unwrap().connect_error.take())
}
/// Disconnects this named pipe from a connected client.
///
/// This function will disconnect the pipe from a connected client, if any,
/// transitively calling the `DisconnectNamedPipe` function. If the
/// disconnection is successful then this object will no longer be readable
/// or writable.
///
/// After a `disconnect` is issued, then a `connect` may be called again to
/// connect to another client.
pub fn disconnect(&self) -> io::Result<()> {
try!(self.inner.handle.disconnect());
self.inner.readiness.set_readiness(Ready::empty())
.expect("event loop seems gone");
Ok(())
}
fn registered(&self) -> bool {
self.registered.load(SeqCst)
}
}
impl Read for NamedPipe {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
<&NamedPipe as Read>::read(&mut &*self, buf)
}
}
impl Write for NamedPipe {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
<&NamedPipe as Write>::write(&mut &*self, buf)
}
fn flush(&mut self) -> io::Result<()> {
<&NamedPipe as Write>::flush(&mut &*self)
}
}
impl<'a> Read for &'a NamedPipe {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// Make sure we're registered
if !self.registered() {
return Err(would_block())
}
let mut state = self.inner.io.lock().unwrap();
match mem::replace(&mut state.read, State::None) {
// In theory not possible with `ready_registration` checked above,
// but return would block for now.
State::None => Err(would_block()),
// A read is in flight, still waiting for it to finish
State::Pending(buf, amt) => {
state.read = State::Pending(buf, amt);
Err(would_block())
}
// We previously read something into `data`, try to copy out some
// data. If we copy out all the data schedule a new read and
// otherwise store the buffer to get read later.
State::Ok(data, cur) => {
let n = {
let mut remaining = &data[cur..];
try!(remaining.read(buf))
};
let next = cur + n;
if next != data.len() {
state.read = State::Ok(data, next);
} else {
Inner::schedule_read(&self.inner, &mut state);
}
Ok(n)
}
// Looks like an in-flight read hit an error, return that here while
// we schedule a new one.
State::Err(e) => {
Inner::schedule_read(&self.inner, &mut state);
if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) {
Ok(0)
} else {
Err(e)
}
}
}
}
}
impl<'a> Write for &'a NamedPipe {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// Make sure we're registered
if !self.registered() {
return Err(would_block())
}
// Make sure there's no writes pending
let mut io = self.inner.io.lock().unwrap();
match io.write {
State::None => {}
_ => return Err(would_block())
}
// Move `buf` onto the heap and fire off the write
//
// TODO: need to be smarter about buffer management here
Inner::schedule_write(&self.inner, buf.to_vec(), 0, &mut io);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
// TODO: `FlushFileBuffers` somehow?
Ok(())
}
}
impl Evented for NamedPipe {
fn register(&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt) -> io::Result<()> {
// First, register the handle with the event loop
unsafe {
try!(self.poll_registration.register_handle(&self.inner.handle,
token,
poll));
}
try!(poll.register(&self.ready_registration, token, interest, opts));
self.registered.store(true, SeqCst);
Inner::post_register(&self.inner);
Ok(())
}
fn reregister(&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt) -> io::Result<()> {
// Validate `Poll` and that we were previously registered
unsafe {
try!(self.poll_registration.reregister_handle(&self.inner.handle,
token,
poll));
}
// At this point we should for sure have `ready_registration` unless
// we're racing with `register` above, so just return a bland error if
// the borrow fails.
try!(poll.reregister(&self.ready_registration, token, interest, opts));
Inner::post_register(&self.inner);
Ok(())
}
fn deregister(&self, poll: &Poll) -> io::Result<()> {
// Validate `Poll` and deregister ourselves
unsafe {
try!(self.poll_registration.deregister_handle(&self.inner.handle, poll));
}
poll.deregister(&self.ready_registration)
}
}
impl AsRawHandle for NamedPipe {
fn as_raw_handle(&self) -> RawHandle {
self.inner.handle.as_raw_handle()
}
}
impl FromRawHandle for NamedPipe {
unsafe fn from_raw_handle(handle: RawHandle) -> NamedPipe {
let (r, s) = Registration::new2();
NamedPipe {
registered: AtomicBool::new(false),
ready_registration: r,
poll_registration: windows::Binding::new(),
inner: FromRawArc::new(Inner {
handle: pipe::NamedPipe::from_raw_handle(handle),
readiness: s,
connect: windows::Overlapped::new(connect_done),
connecting: AtomicBool::new(false),
read: windows::Overlapped::new(read_done),
write: windows::Overlapped::new(write_done),
io: Mutex::new(Io {
read: State::None,
write: State::None,
connect_error: None,
}),
}),
}
}
}
impl fmt::Debug for NamedPipe {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.inner.handle.fmt(f)
}
}
impl Drop for NamedPipe {
fn drop(&mut self) {
// Cancel pending reads/connects, but don't cancel writes to ensure that
// everything is flushed out.
unsafe {
if self.inner.connecting.load(SeqCst) {
drop(cancel(&self.inner.handle, &self.inner.connect));
}
let io = self.inner.io.lock().unwrap();
match io.read {
State::Pending(..) => {
drop(cancel(&self.inner.handle, &self.inner.read));
}
_ => {}
}
}
}
}
impl Inner {
/// Schedules a read to happen in the background, executing an overlapped
/// operation.
///
/// This function returns `true` if a normal error happens or if the read
/// is scheduled in the background. If the pipe is no longer connected
/// (ERROR_PIPE_LISTENING) then `false` is returned and no read is
/// scheduled.
fn schedule_read(me: &FromRawArc<Inner>, io: &mut Io) -> bool {
// Check to see if a read is already scheduled/completed
match io.read {
State::None => {}
_ => return true,
}
// Turn off our read readiness
let ready = me.readiness.readiness();
me.readiness.set_readiness(ready & !Ready::readable())
.expect("event loop seems gone");
// Allocate a buffer and schedule the read.
//
// TODO: need to be smarter about buffer management here
let mut buf = Vec::with_capacity(8 * 1024);
let e = unsafe {
let overlapped = me.read.as_mut_ptr();
let slice = slice::from_raw_parts_mut(buf.as_mut_ptr(),
buf.capacity());
me.handle.read_overlapped(slice, overlapped)
};
match e {
// See `connect` above for the rationale behind `forget`
Ok(e) => {
trace!("schedule read success: {:?}", e);
io.read = State::Pending(buf, 0); // 0 is ignored on read side
mem::forget(me.clone());
true
}
// If ERROR_PIPE_LISTENING happens then it's not a real read error,
// we just need to wait for a connect.
Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_LISTENING as i32) => {
false
}
// If some other error happened, though, we're now readable to give
// out the error.
Err(e) => {
trace!("schedule read error: {}", e);
io.read = State::Err(e);
me.readiness.set_readiness(ready | Ready::readable())
.expect("event loop still seems gone");
true
}
}
}
fn schedule_write(me: &FromRawArc<Inner>,
buf: Vec<u8>,
pos: usize,
io: &mut Io) {
// Very similar to `schedule_read` above, just done for the write half.
let ready = me.readiness.readiness();
me.readiness.set_readiness(ready & !Ready::writable())
.expect("event loop seems gone");
let e = unsafe {
let overlapped = me.write.as_mut_ptr();
me.handle.write_overlapped(&buf[pos..], overlapped)
};
match e {
// See `connect` above for the rationale behind `forget`
Ok(e) => {
trace!("schedule write success: {:?}", e);
io.write = State::Pending(buf, pos);
mem::forget(me.clone())
}
Err(e) => {
trace!("schedule write error: {}", e);
io.write = State::Err(e);
me.add_readiness(Ready::writable());
}
}
}
fn add_readiness(&self, ready: Ready) {
self.readiness.set_readiness(ready | self.readiness.readiness())
.expect("event loop still seems gone");
}
fn post_register(me: &FromRawArc<Inner>) {
let mut io = me.io.lock().unwrap();
if Inner::schedule_read(&me, &mut io) {
if let State::None = io.write {
me.add_readiness(Ready::writable());
}
}
}
}
unsafe fn cancel(handle: &AsRawHandle,
overlapped: &windows::Overlapped) -> io::Result<()> {
let ret = kernel32::CancelIoEx(handle.as_raw_handle(),
overlapped.as_mut_ptr());
if ret == 0 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
}
fn connect_done(status: &OVERLAPPED_ENTRY) {
let status = CompletionStatus::from_entry(status);
trace!("connect done");
// Acquire the `FromRawArc<Inner>`. Note that we should be guaranteed that
// the refcount is available to us due to the `mem::forget` in
// `connect` above.
let me = unsafe {
overlapped2arc!(status.overlapped(), Inner, connect)
};
// Flag ourselves as no longer using the `connect` overlapped instances.
let prev = me.connecting.swap(false, SeqCst);
assert!(prev, "wasn't previously connecting");
// Stash away our connect error if one happened
debug_assert_eq!(status.bytes_transferred(), 0);
unsafe {
match me.handle.result(status.overlapped()) {
Ok(n) => debug_assert_eq!(n, 0),
Err(e) => me.io.lock().unwrap().connect_error = Some(e),
}
}
// We essentially just finished a registration, so kick off a
// read and register write readiness.
Inner::post_register(&me);
}
fn read_done(status: &OVERLAPPED_ENTRY) {
let status = CompletionStatus::from_entry(status);
trace!("read finished, bytes={}", status.bytes_transferred());
// Acquire the `FromRawArc<Inner>`. Note that we should be guaranteed that
// the refcount is available to us due to the `mem::forget` in
// `schedule_read` above.
let me = unsafe {
overlapped2arc!(status.overlapped(), Inner, read)
};
// Move from the `Pending` to `Ok` state.
let mut io = me.io.lock().unwrap();
let mut buf = match mem::replace(&mut io.read, State::None) {
State::Pending(buf, _) => buf,
_ => unreachable!(),
};
unsafe {
match me.handle.result(status.overlapped()) {
Ok(n) => {
debug_assert_eq!(status.bytes_transferred() as usize, n);
buf.set_len(status.bytes_transferred() as usize);
io.read = State::Ok(buf, 0);
}
Err(e) => {
debug_assert_eq!(status.bytes_transferred(), 0);
io.read = State::Err(e);
}
}
}
// Flag our readiness that we've got data.
me.add_readiness(Ready::readable());
}
fn write_done(status: &OVERLAPPED_ENTRY) {
let status = CompletionStatus::from_entry(status);
trace!("write finished, bytes={}", status.bytes_transferred());
// Acquire the `FromRawArc<Inner>`. Note that we should be guaranteed that
// the refcount is available to us due to the `mem::forget` in
// `schedule_write` above.
let me = unsafe {
overlapped2arc!(status.overlapped(), Inner, write)
};
// Make the state change out of `Pending`. If we wrote the entire buffer
// then we're writable again and otherwise we schedule another write.
let mut io = me.io.lock().unwrap();
let (buf, pos) = match mem::replace(&mut io.write, State::None) {
State::Pending(buf, pos) => (buf, pos),
_ => unreachable!(),
};
unsafe {
match me.handle.result(status.overlapped()) {
Ok(n) => {
debug_assert_eq!(status.bytes_transferred() as usize, n);
let new_pos = pos + (status.bytes_transferred() as usize);
if new_pos == buf.len() {
me.add_readiness(Ready::writable());
} else {
Inner::schedule_write(&me, buf, new_pos, &mut io);
}
}
Err(e) => {
debug_assert_eq!(status.bytes_transferred(), 0);
io.write = State::Err(e);
me.add_readiness(Ready::writable());
}
}
}
}

View File

@ -0,0 +1,273 @@
extern crate mio;
extern crate mio_named_pipes;
extern crate env_logger;
extern crate rand;
extern crate winapi;
#[macro_use]
extern crate log;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::io;
use std::os::windows::fs::*;
use std::os::windows::io::*;
use std::time::Duration;
use mio_named_pipes::NamedPipe;
use mio::{Poll, Ready, Token, PollOpt, Events};
use rand::Rng;
macro_rules! t {
($e:expr) => (match $e {
Ok(e) => e,
Err(e) => panic!("{} failed with {}", stringify!($e), e),
})
}
fn server() -> (NamedPipe, String) {
let num: u64 = rand::thread_rng().gen();
let name = format!(r"\\.\pipe\my-pipe-{}", num);
let pipe = t!(NamedPipe::new(&name));
(pipe, name)
}
fn client(name: &str) -> NamedPipe {
let mut opts = OpenOptions::new();
opts.read(true)
.write(true)
.custom_flags(winapi::FILE_FLAG_OVERLAPPED);
let file = t!(opts.open(name));
unsafe {
NamedPipe::from_raw_handle(file.into_raw_handle())
}
}
fn pipe() -> (NamedPipe, NamedPipe) {
let (pipe, name) = server();
(pipe, client(&name))
}
#[test]
fn writable_after_register() {
drop(env_logger::init());
let (server, client) = pipe();
let poll = t!(Poll::new());
t!(poll.register(&server,
Token(0),
Ready::writable() | Ready::readable(),
PollOpt::edge()));
t!(poll.register(&client,
Token(1),
Ready::writable(),
PollOpt::edge()));
let mut events = Events::with_capacity(128);
t!(poll.poll(&mut events, None));
let events = events.iter().collect::<Vec<_>>();
debug!("events {:?}", events);
assert!(events.iter().any(|e| {
e.token() == Token(0) && e.readiness() == Ready::writable()
}));
assert!(events.iter().any(|e| {
e.token() == Token(1) && e.readiness() == Ready::writable()
}));
}
#[test]
fn write_then_read() {
drop(env_logger::init());
let (mut server, mut client) = pipe();
let poll = t!(Poll::new());
t!(poll.register(&server,
Token(0),
Ready::readable() | Ready::writable(),
PollOpt::edge()));
t!(poll.register(&client,
Token(1),
Ready::readable() | Ready::writable(),
PollOpt::edge()));
let mut events = Events::with_capacity(128);
t!(poll.poll(&mut events, None));
assert_eq!(t!(client.write(b"1234")), 4);
loop {
t!(poll.poll(&mut events, None));
let events = events.iter().collect::<Vec<_>>();
debug!("events {:?}", events);
if let Some(event) = events.iter().find(|e| e.token() == Token(0)) {
if event.readiness().is_readable() {
break
}
}
}
let mut buf = [0; 10];
assert_eq!(t!(server.read(&mut buf)), 4);
assert_eq!(&buf[..4], b"1234");
}
#[test]
fn connect_before_client() {
drop(env_logger::init());
let (server, name) = server();
let poll = t!(Poll::new());
t!(poll.register(&server,
Token(0),
Ready::readable() | Ready::writable(),
PollOpt::edge()));
let mut events = Events::with_capacity(128);
t!(poll.poll(&mut events, Some(Duration::new(0, 0))));
let e = events.iter().collect::<Vec<_>>();
debug!("events {:?}", e);
assert_eq!(e.len(), 0);
assert_eq!(server.connect().err().unwrap().kind(),
io::ErrorKind::WouldBlock);
let client = client(&name);
t!(poll.register(&client,
Token(1),
Ready::readable() | Ready::writable(),
PollOpt::edge()));
loop {
t!(poll.poll(&mut events, None));
let e = events.iter().collect::<Vec<_>>();
debug!("events {:?}", e);
if let Some(event) = e.iter().find(|e| e.token() == Token(0)) {
if event.readiness().is_writable() {
break
}
}
}
}
#[test]
fn connect_after_client() {
drop(env_logger::init());
let (server, name) = server();
let poll = t!(Poll::new());
t!(poll.register(&server,
Token(0),
Ready::readable() | Ready::writable(),
PollOpt::edge()));
let mut events = Events::with_capacity(128);
t!(poll.poll(&mut events, Some(Duration::new(0, 0))));
let e = events.iter().collect::<Vec<_>>();
debug!("events {:?}", e);
assert_eq!(e.len(), 0);
let client = client(&name);
t!(poll.register(&client,
Token(1),
Ready::readable() | Ready::writable(),
PollOpt::edge()));
t!(server.connect());
loop {
t!(poll.poll(&mut events, None));
let e = events.iter().collect::<Vec<_>>();
debug!("events {:?}", e);
if let Some(event) = e.iter().find(|e| e.token() == Token(0)) {
if event.readiness().is_writable() {
break
}
}
}
}
#[test]
fn write_then_drop() {
drop(env_logger::init());
let (mut server, mut client) = pipe();
let poll = t!(Poll::new());
t!(poll.register(&server,
Token(0),
Ready::readable() | Ready::writable(),
PollOpt::edge()));
t!(poll.register(&client,
Token(1),
Ready::readable() | Ready::writable(),
PollOpt::edge()));
assert_eq!(t!(client.write(b"1234")), 4);
drop(client);
let mut events = Events::with_capacity(128);
loop {
t!(poll.poll(&mut events, None));
let events = events.iter().collect::<Vec<_>>();
debug!("events {:?}", events);
if let Some(event) = events.iter().find(|e| e.token() == Token(0)) {
if event.readiness().is_readable() {
break
}
}
}
let mut buf = [0; 10];
assert_eq!(t!(server.read(&mut buf)), 4);
assert_eq!(&buf[..4], b"1234");
}
#[test]
fn connect_twice() {
drop(env_logger::init());
let (mut server, name) = server();
let c1 = client(&name);
let poll = t!(Poll::new());
t!(poll.register(&server,
Token(0),
Ready::readable() | Ready::writable(),
PollOpt::edge()));
t!(poll.register(&c1,
Token(1),
Ready::readable() | Ready::writable(),
PollOpt::edge()));
drop(c1);
let mut events = Events::with_capacity(128);
loop {
t!(poll.poll(&mut events, None));
let events = events.iter().collect::<Vec<_>>();
debug!("events {:?}", events);
if let Some(event) = events.iter().find(|e| e.token() == Token(0)) {
if event.readiness().is_readable() {
break
}
}
}
let mut buf = [0; 10];
assert_eq!(t!(server.read(&mut buf)), 0);
t!(server.disconnect());
assert_eq!(server.connect().err().unwrap().kind(),
io::ErrorKind::WouldBlock);
let c2 = client(&name);
t!(poll.register(&c2,
Token(2),
Ready::readable() | Ready::writable(),
PollOpt::edge()));
loop {
t!(poll.poll(&mut events, None));
let events = events.iter().collect::<Vec<_>>();
debug!("events {:?}", events);
if let Some(event) = events.iter().find(|e| e.token() == Token(0)) {
if event.readiness().is_writable() {
break
}
}
}
}