From 3041fa8ef188e341522daba0ad005e77a86073c3 Mon Sep 17 00:00:00 2001 From: AzureMarker Date: Tue, 4 Jan 2022 21:33:21 -0800 Subject: [PATCH] Delete ctr-std We use the rustc fork now --- ctr-std/Cargo.toml | 12 - ctr-std/README.md | 69 - ctr-std/src/alloc.rs | 184 - ctr-std/src/ascii.rs | 211 - ctr-std/src/build.rs | 134 - ctr-std/src/collections/hash/bench.rs | 128 - ctr-std/src/collections/hash/map.rs | 3686 --------------- ctr-std/src/collections/hash/mod.rs | 24 - ctr-std/src/collections/hash/set.rs | 1783 ------- ctr-std/src/collections/hash/table.rs | 1133 ----- ctr-std/src/collections/mod.rs | 457 -- ctr-std/src/env.rs | 1091 ----- ctr-std/src/error.rs | 548 --- ctr-std/src/f32.rs | 1539 ------ ctr-std/src/f64.rs | 1480 ------ ctr-std/src/ffi/c_str.rs | 1562 ------- ctr-std/src/ffi/mod.rs | 175 - ctr-std/src/ffi/os_str.rs | 1108 ----- ctr-std/src/fs.rs | 3334 ------------- ctr-std/src/future.rs | 116 - ctr-std/src/io/buffered.rs | 1338 ------ ctr-std/src/io/cursor.rs | 682 --- ctr-std/src/io/error.rs | 620 --- ctr-std/src/io/impls.rs | 337 -- ctr-std/src/io/lazy.rs | 76 - ctr-std/src/io/mod.rs | 2266 --------- ctr-std/src/io/prelude.rs | 24 - ctr-std/src/io/stdio.rs | 764 --- ctr-std/src/io/util.rs | 261 -- ctr-std/src/keyword_docs.rs | 58 - ctr-std/src/lib.rs | 514 -- ctr-std/src/macros.rs | 871 ---- ctr-std/src/memchr.rs | 143 - ctr-std/src/net/addr.rs | 1077 ----- ctr-std/src/net/ip.rs | 1940 -------- ctr-std/src/net/mod.rs | 128 - ctr-std/src/net/parser.rs | 414 -- ctr-std/src/net/tcp.rs | 1713 ------- ctr-std/src/net/test.rs | 57 - ctr-std/src/net/udp.rs | 1163 ----- ctr-std/src/num.rs | 296 -- ctr-std/src/os/android/fs.rs | 131 - ctr-std/src/os/android/mod.rs | 16 - ctr-std/src/os/android/raw.rs | 230 - ctr-std/src/os/bitrig/fs.rs | 151 - ctr-std/src/os/bitrig/mod.rs | 16 - ctr-std/src/os/bitrig/raw.rs | 81 - ctr-std/src/os/dragonfly/fs.rs | 146 - ctr-std/src/os/dragonfly/mod.rs | 16 - ctr-std/src/os/dragonfly/raw.rs | 82 - ctr-std/src/os/emscripten/fs.rs | 130 - ctr-std/src/os/emscripten/mod.rs | 16 - ctr-std/src/os/emscripten/raw.rs | 81 - ctr-std/src/os/freebsd/fs.rs | 156 - ctr-std/src/os/freebsd/mod.rs | 16 - ctr-std/src/os/freebsd/raw.rs | 85 - ctr-std/src/os/fuchsia/fs.rs | 105 - ctr-std/src/os/fuchsia/mod.rs | 16 - ctr-std/src/os/fuchsia/raw.rs | 270 -- ctr-std/src/os/haiku/fs.rs | 140 - ctr-std/src/os/haiku/mod.rs | 16 - ctr-std/src/os/haiku/raw.rs | 74 - ctr-std/src/os/hermit/fs.rs | 389 -- ctr-std/src/os/hermit/mod.rs | 16 - ctr-std/src/os/hermit/raw.rs | 27 - ctr-std/src/os/horizon/fs.rs | 393 -- ctr-std/src/os/horizon/mod.rs | 16 - ctr-std/src/os/horizon/raw.rs | 275 -- ctr-std/src/os/ios/fs.rs | 156 - ctr-std/src/os/ios/mod.rs | 16 - ctr-std/src/os/ios/raw.rs | 83 - ctr-std/src/os/linux/fs.rs | 389 -- ctr-std/src/os/linux/mod.rs | 16 - ctr-std/src/os/linux/raw.rs | 275 -- ctr-std/src/os/macos/fs.rs | 162 - ctr-std/src/os/macos/mod.rs | 16 - ctr-std/src/os/macos/raw.rs | 83 - ctr-std/src/os/mod.rs | 67 - ctr-std/src/os/netbsd/fs.rs | 151 - ctr-std/src/os/netbsd/mod.rs | 16 - ctr-std/src/os/netbsd/raw.rs | 82 - ctr-std/src/os/openbsd/fs.rs | 151 - ctr-std/src/os/openbsd/mod.rs | 16 - ctr-std/src/os/openbsd/raw.rs | 80 - ctr-std/src/os/raw/char.md | 11 - ctr-std/src/os/raw/double.md | 7 - ctr-std/src/os/raw/float.md | 6 - ctr-std/src/os/raw/int.md | 7 - ctr-std/src/os/raw/long.md | 7 - ctr-std/src/os/raw/longlong.md | 7 - ctr-std/src/os/raw/mod.rs | 141 - ctr-std/src/os/raw/schar.md | 6 - ctr-std/src/os/raw/short.md | 6 - ctr-std/src/os/raw/uchar.md | 6 - ctr-std/src/os/raw/uint.md | 7 - ctr-std/src/os/raw/ulong.md | 7 - ctr-std/src/os/raw/ulonglong.md | 7 - ctr-std/src/os/raw/ushort.md | 6 - ctr-std/src/os/solaris/fs.rs | 130 - ctr-std/src/os/solaris/mod.rs | 16 - ctr-std/src/os/solaris/raw.rs | 75 - ctr-std/src/panic.rs | 426 -- ctr-std/src/panicking.rs | 550 --- ctr-std/src/path.rs | 4145 ----------------- ctr-std/src/prelude/mod.rs | 148 - ctr-std/src/prelude/v1.rs | 79 - ctr-std/src/primitive_docs.rs | 1100 ----- ctr-std/src/process.rs | 1990 -------- ctr-std/src/rt.rs | 75 - ctr-std/src/sync/barrier.rs | 232 - ctr-std/src/sync/condvar.rs | 839 ---- ctr-std/src/sync/mod.rs | 44 - ctr-std/src/sync/mpsc/blocking.rs | 96 - ctr-std/src/sync/mpsc/cache_aligned.rs | 37 - ctr-std/src/sync/mpsc/mod.rs | 3130 ------------- ctr-std/src/sync/mpsc/mpsc_queue.rs | 180 - ctr-std/src/sync/mpsc/oneshot.rs | 396 -- ctr-std/src/sync/mpsc/select.rs | 779 ---- ctr-std/src/sync/mpsc/shared.rs | 506 -- ctr-std/src/sync/mpsc/spsc_queue.rs | 347 -- ctr-std/src/sync/mpsc/stream.rs | 504 -- ctr-std/src/sync/mpsc/sync.rs | 528 --- ctr-std/src/sync/mutex.rs | 716 --- ctr-std/src/sync/once.rs | 596 --- ctr-std/src/sync/rwlock.rs | 808 ---- ctr-std/src/sys/cloudabi/abi/bitflags.rs | 51 - ctr-std/src/sys/cloudabi/abi/cloudabi.rs | 2847 ----------- ctr-std/src/sys/cloudabi/abi/mod.rs | 13 - ctr-std/src/sys/cloudabi/args.rs | 17 - ctr-std/src/sys/cloudabi/backtrace.rs | 124 - ctr-std/src/sys/cloudabi/condvar.rs | 169 - ctr-std/src/sys/cloudabi/mod.rs | 76 - ctr-std/src/sys/cloudabi/mutex.rs | 158 - ctr-std/src/sys/cloudabi/os.rs | 37 - ctr-std/src/sys/cloudabi/rwlock.rs | 237 - ctr-std/src/sys/cloudabi/shims/args.rs | 45 - ctr-std/src/sys/cloudabi/shims/env.rs | 19 - ctr-std/src/sys/cloudabi/shims/fs.rs | 302 -- ctr-std/src/sys/cloudabi/shims/mod.rs | 32 - ctr-std/src/sys/cloudabi/shims/net.rs | 296 -- ctr-std/src/sys/cloudabi/shims/os.rs | 95 - ctr-std/src/sys/cloudabi/shims/pipe.rs | 32 - ctr-std/src/sys/cloudabi/shims/process.rs | 159 - ctr-std/src/sys/cloudabi/stack_overflow.rs | 23 - ctr-std/src/sys/cloudabi/stdio.rs | 83 - ctr-std/src/sys/cloudabi/thread.rs | 126 - ctr-std/src/sys/cloudabi/time.rs | 111 - ctr-std/src/sys/horizon/android.rs | 170 - ctr-std/src/sys/horizon/args.rs | 60 - ctr-std/src/sys/horizon/backtrace/mod.rs | 119 - .../sys/horizon/backtrace/printing/dladdr.rs | 45 - .../src/sys/horizon/backtrace/printing/mod.rs | 43 - .../horizon/backtrace/tracing/backtrace_fn.rs | 49 - .../sys/horizon/backtrace/tracing/gcc_s.rs | 107 - .../src/sys/horizon/backtrace/tracing/mod.rs | 18 - ctr-std/src/sys/horizon/cmath.rs | 43 - ctr-std/src/sys/horizon/condvar.rs | 139 - ctr-std/src/sys/horizon/env.rs | 185 - ctr-std/src/sys/horizon/ext/ffi.rs | 119 - ctr-std/src/sys/horizon/ext/fs.rs | 736 --- ctr-std/src/sys/horizon/ext/io.rs | 108 - ctr-std/src/sys/horizon/ext/mod.rs | 59 - ctr-std/src/sys/horizon/ext/raw.rs | 33 - ctr-std/src/sys/horizon/fast_thread_local.rs | 77 - ctr-std/src/sys/horizon/fd.rs | 265 -- ctr-std/src/sys/horizon/fs.rs | 928 ---- ctr-std/src/sys/horizon/l4re.rs | 441 -- ctr-std/src/sys/horizon/memchr.rs | 57 - ctr-std/src/sys/horizon/mod.rs | 179 - ctr-std/src/sys/horizon/mutex.rs | 90 - ctr-std/src/sys/horizon/net.rs | 429 -- ctr-std/src/sys/horizon/os.rs | 191 - ctr-std/src/sys/horizon/os_str.rs | 189 - ctr-std/src/sys/horizon/path.rs | 29 - ctr-std/src/sys/horizon/pipe.rs | 137 - ctr-std/src/sys/horizon/process.rs | 151 - ctr-std/src/sys/horizon/rand.rs | 241 - ctr-std/src/sys/horizon/rwlock.rs | 127 - ctr-std/src/sys/horizon/stack_overflow.rs | 220 - ctr-std/src/sys/horizon/stdio.rs | 81 - ctr-std/src/sys/horizon/thread.rs | 106 - ctr-std/src/sys/horizon/thread_local.rs | 71 - ctr-std/src/sys/horizon/time.rs | 285 -- ctr-std/src/sys/horizon/weak.rs | 79 - ctr-std/src/sys/mod.rs | 108 - ctr-std/src/sys/redox/args.rs | 107 - ctr-std/src/sys/redox/backtrace/mod.rs | 42 - ctr-std/src/sys/redox/backtrace/printing.rs | 11 - ctr-std/src/sys/redox/backtrace/tracing.rs | 109 - ctr-std/src/sys/redox/cmath.rs | 43 - ctr-std/src/sys/redox/condvar.rs | 121 - ctr-std/src/sys/redox/env.rs | 19 - ctr-std/src/sys/redox/ext/ffi.rs | 65 - ctr-std/src/sys/redox/ext/fs.rs | 349 -- ctr-std/src/sys/redox/ext/io.rs | 167 - ctr-std/src/sys/redox/ext/mod.rs | 55 - ctr-std/src/sys/redox/ext/net.rs | 769 --- ctr-std/src/sys/redox/ext/process.rs | 187 - ctr-std/src/sys/redox/ext/thread.rs | 49 - ctr-std/src/sys/redox/fast_thread_local.rs | 121 - ctr-std/src/sys/redox/fd.rs | 98 - ctr-std/src/sys/redox/fs.rs | 483 -- ctr-std/src/sys/redox/memchr.rs | 14 - ctr-std/src/sys/redox/mod.rs | 81 - ctr-std/src/sys/redox/mutex.rs | 179 - ctr-std/src/sys/redox/net/dns/answer.rs | 22 - ctr-std/src/sys/redox/net/dns/mod.rs | 215 - ctr-std/src/sys/redox/net/dns/query.rs | 18 - ctr-std/src/sys/redox/net/mod.rs | 115 - ctr-std/src/sys/redox/net/netc.rs | 57 - ctr-std/src/sys/redox/net/tcp.rs | 253 - ctr-std/src/sys/redox/net/udp.rs | 242 - ctr-std/src/sys/redox/os.rs | 216 - ctr-std/src/sys/redox/os_str.rs | 189 - ctr-std/src/sys/redox/path.rs | 39 - ctr-std/src/sys/redox/pipe.rs | 103 - ctr-std/src/sys/redox/process.rs | 544 --- ctr-std/src/sys/redox/rand.rs | 13 - ctr-std/src/sys/redox/rwlock.rs | 61 - ctr-std/src/sys/redox/stack_overflow.rs | 27 - ctr-std/src/sys/redox/stdio.rs | 81 - ctr-std/src/sys/redox/syscall/arch/arm.rs | 83 - ctr-std/src/sys/redox/syscall/arch/x86.rs | 83 - ctr-std/src/sys/redox/syscall/arch/x86_64.rs | 84 - ctr-std/src/sys/redox/syscall/call.rs | 363 -- ctr-std/src/sys/redox/syscall/data.rs | 201 - ctr-std/src/sys/redox/syscall/error.rs | 325 -- ctr-std/src/sys/redox/syscall/flag.rs | 116 - ctr-std/src/sys/redox/syscall/mod.rs | 43 - ctr-std/src/sys/redox/syscall/number.rs | 83 - ctr-std/src/sys/redox/thread.rs | 95 - ctr-std/src/sys/redox/thread_local.rs | 71 - ctr-std/src/sys/redox/time.rs | 214 - ctr-std/src/sys/unix/android.rs | 170 - ctr-std/src/sys/unix/args.rs | 219 - ctr-std/src/sys/unix/backtrace/mod.rs | 119 - .../src/sys/unix/backtrace/printing/dladdr.rs | 45 - .../src/sys/unix/backtrace/printing/mod.rs | 43 - .../unix/backtrace/tracing/backtrace_fn.rs | 49 - .../src/sys/unix/backtrace/tracing/gcc_s.rs | 109 - ctr-std/src/sys/unix/backtrace/tracing/mod.rs | 18 - ctr-std/src/sys/unix/cmath.rs | 43 - ctr-std/src/sys/unix/condvar.rs | 192 - ctr-std/src/sys/unix/env.rs | 185 - ctr-std/src/sys/unix/ext/ffi.rs | 119 - ctr-std/src/sys/unix/ext/fs.rs | 863 ---- ctr-std/src/sys/unix/ext/io.rs | 108 - ctr-std/src/sys/unix/ext/mod.rs | 67 - ctr-std/src/sys/unix/ext/net.rs | 1824 -------- ctr-std/src/sys/unix/ext/process.rs | 203 - ctr-std/src/sys/unix/ext/raw.rs | 33 - ctr-std/src/sys/unix/ext/thread.rs | 51 - ctr-std/src/sys/unix/fast_thread_local.rs | 72 - ctr-std/src/sys/unix/fd.rs | 288 -- ctr-std/src/sys/unix/fs.rs | 945 ---- ctr-std/src/sys/unix/l4re.rs | 441 -- ctr-std/src/sys/unix/memchr.rs | 57 - ctr-std/src/sys/unix/mod.rs | 167 - ctr-std/src/sys/unix/mutex.rs | 139 - ctr-std/src/sys/unix/net.rs | 424 -- ctr-std/src/sys/unix/os.rs | 571 --- ctr-std/src/sys/unix/os_str.rs | 189 - ctr-std/src/sys/unix/path.rs | 29 - ctr-std/src/sys/unix/pipe.rs | 131 - ctr-std/src/sys/unix/process/mod.rs | 22 - .../src/sys/unix/process/process_common.rs | 510 -- .../src/sys/unix/process/process_fuchsia.rs | 181 - ctr-std/src/sys/unix/process/process_unix.rs | 405 -- ctr-std/src/sys/unix/process/zircon.rs | 279 -- ctr-std/src/sys/unix/rand.rs | 192 - ctr-std/src/sys/unix/rwlock.rs | 142 - ctr-std/src/sys/unix/stack_overflow.rs | 220 - ctr-std/src/sys/unix/stdio.rs | 81 - ctr-std/src/sys/unix/thread.rs | 458 -- ctr-std/src/sys/unix/thread_local.rs | 45 - ctr-std/src/sys/unix/time.rs | 365 -- ctr-std/src/sys/unix/weak.rs | 79 - ctr-std/src/sys/wasm/args.rs | 62 - ctr-std/src/sys/wasm/backtrace.rs | 37 - ctr-std/src/sys/wasm/cmath.rs | 119 - ctr-std/src/sys/wasm/condvar.rs | 43 - ctr-std/src/sys/wasm/env.rs | 19 - ctr-std/src/sys/wasm/fs.rs | 304 -- ctr-std/src/sys/wasm/memchr.rs | 11 - ctr-std/src/sys/wasm/mod.rs | 314 -- ctr-std/src/sys/wasm/mutex.rs | 79 - ctr-std/src/sys/wasm/net.rs | 337 -- ctr-std/src/sys/wasm/os.rs | 112 - ctr-std/src/sys/wasm/os_str.rs | 189 - ctr-std/src/sys/wasm/path.rs | 29 - ctr-std/src/sys/wasm/pipe.rs | 35 - ctr-std/src/sys/wasm/process.rs | 162 - ctr-std/src/sys/wasm/rwlock.rs | 82 - ctr-std/src/sys/wasm/stack_overflow.rs | 23 - ctr-std/src/sys/wasm/stdio.rs | 75 - ctr-std/src/sys/wasm/thread.rs | 50 - ctr-std/src/sys/wasm/thread_local.rs | 50 - ctr-std/src/sys/wasm/time.rs | 57 - ctr-std/src/sys/windows/args.rs | 107 - .../sys/windows/backtrace/backtrace_gnu.rs | 62 - ctr-std/src/sys/windows/backtrace/mod.rs | 326 -- .../src/sys/windows/backtrace/printing/mod.rs | 34 - .../sys/windows/backtrace/printing/msvc.rs | 217 - ctr-std/src/sys/windows/c.rs | 1334 ------ ctr-std/src/sys/windows/cmath.rs | 103 - ctr-std/src/sys/windows/compat.rs | 81 - ctr-std/src/sys/windows/condvar.rs | 65 - ctr-std/src/sys/windows/dynamic_lib.rs | 54 - ctr-std/src/sys/windows/env.rs | 19 - ctr-std/src/sys/windows/ext/ffi.rs | 152 - ctr-std/src/sys/windows/ext/fs.rs | 508 -- ctr-std/src/sys/windows/ext/io.rs | 209 - ctr-std/src/sys/windows/ext/mod.rs | 45 - ctr-std/src/sys/windows/ext/process.rs | 123 - ctr-std/src/sys/windows/ext/raw.rs | 21 - ctr-std/src/sys/windows/ext/thread.rs | 31 - ctr-std/src/sys/windows/fast_thread_local.rs | 18 - ctr-std/src/sys/windows/fs.rs | 804 ---- ctr-std/src/sys/windows/handle.rs | 218 - ctr-std/src/sys/windows/memchr.rs | 15 - ctr-std/src/sys/windows/mod.rs | 277 -- ctr-std/src/sys/windows/mutex.rs | 188 - ctr-std/src/sys/windows/net.rs | 356 -- ctr-std/src/sys/windows/os.rs | 337 -- ctr-std/src/sys/windows/os_str.rs | 182 - ctr-std/src/sys/windows/path.rs | 106 - ctr-std/src/sys/windows/pipe.rs | 364 -- ctr-std/src/sys/windows/process.rs | 581 --- ctr-std/src/sys/windows/rand.rs | 26 - ctr-std/src/sys/windows/rwlock.rs | 52 - ctr-std/src/sys/windows/stack_overflow.rs | 52 - ctr-std/src/sys/windows/stdio.rs | 233 - ctr-std/src/sys/windows/thread.rs | 101 - ctr-std/src/sys/windows/thread_local.rs | 251 - ctr-std/src/sys/windows/time.rs | 206 - ctr-std/src/sys_common/at_exit_imp.rs | 86 - ctr-std/src/sys_common/backtrace.rs | 462 -- ctr-std/src/sys_common/bytestring.rs | 56 - ctr-std/src/sys_common/condvar.rs | 70 - ctr-std/src/sys_common/gnu/libbacktrace.rs | 216 - ctr-std/src/sys_common/gnu/mod.rs | 15 - ctr-std/src/sys_common/io.rs | 50 - ctr-std/src/sys_common/mod.rs | 141 - ctr-std/src/sys_common/mutex.rs | 94 - ctr-std/src/sys_common/net.rs | 630 --- ctr-std/src/sys_common/poison.rs | 269 -- ctr-std/src/sys_common/process.rs | 136 - ctr-std/src/sys_common/remutex.rs | 247 - ctr-std/src/sys_common/rwlock.rs | 82 - ctr-std/src/sys_common/thread.rs | 40 - ctr-std/src/sys_common/thread_info.rs | 51 - ctr-std/src/sys_common/thread_local.rs | 311 -- ctr-std/src/sys_common/util.rs | 37 - ctr-std/src/sys_common/wtf8.rs | 1267 ----- ctr-std/src/tests/env.rs | 94 - ctr-std/src/thread/local.rs | 669 --- ctr-std/src/thread/mod.rs | 1616 ------- ctr-std/src/time.rs | 593 --- 358 files changed, 103830 deletions(-) delete mode 100644 ctr-std/Cargo.toml delete mode 100644 ctr-std/README.md delete mode 100644 ctr-std/src/alloc.rs delete mode 100644 ctr-std/src/ascii.rs delete mode 100644 ctr-std/src/build.rs delete mode 100644 ctr-std/src/collections/hash/bench.rs delete mode 100644 ctr-std/src/collections/hash/map.rs delete mode 100644 ctr-std/src/collections/hash/mod.rs delete mode 100644 ctr-std/src/collections/hash/set.rs delete mode 100644 ctr-std/src/collections/hash/table.rs delete mode 100644 ctr-std/src/collections/mod.rs delete mode 100644 ctr-std/src/env.rs delete mode 100644 ctr-std/src/error.rs delete mode 100644 ctr-std/src/f32.rs delete mode 100644 ctr-std/src/f64.rs delete mode 100644 ctr-std/src/ffi/c_str.rs delete mode 100644 ctr-std/src/ffi/mod.rs delete mode 100644 ctr-std/src/ffi/os_str.rs delete mode 100644 ctr-std/src/fs.rs delete mode 100644 ctr-std/src/future.rs delete mode 100644 ctr-std/src/io/buffered.rs delete mode 100644 ctr-std/src/io/cursor.rs delete mode 100644 ctr-std/src/io/error.rs delete mode 100644 ctr-std/src/io/impls.rs delete mode 100644 ctr-std/src/io/lazy.rs delete mode 100644 ctr-std/src/io/mod.rs delete mode 100644 ctr-std/src/io/prelude.rs delete mode 100644 ctr-std/src/io/stdio.rs delete mode 100644 ctr-std/src/io/util.rs delete mode 100644 ctr-std/src/keyword_docs.rs delete mode 100644 ctr-std/src/lib.rs delete mode 100644 ctr-std/src/macros.rs delete mode 100644 ctr-std/src/memchr.rs delete mode 100644 ctr-std/src/net/addr.rs delete mode 100644 ctr-std/src/net/ip.rs delete mode 100644 ctr-std/src/net/mod.rs delete mode 100644 ctr-std/src/net/parser.rs delete mode 100644 ctr-std/src/net/tcp.rs delete mode 100644 ctr-std/src/net/test.rs delete mode 100644 ctr-std/src/net/udp.rs delete mode 100644 ctr-std/src/num.rs delete mode 100644 ctr-std/src/os/android/fs.rs delete mode 100644 ctr-std/src/os/android/mod.rs delete mode 100644 ctr-std/src/os/android/raw.rs delete mode 100644 ctr-std/src/os/bitrig/fs.rs delete mode 100644 ctr-std/src/os/bitrig/mod.rs delete mode 100644 ctr-std/src/os/bitrig/raw.rs delete mode 100644 ctr-std/src/os/dragonfly/fs.rs delete mode 100644 ctr-std/src/os/dragonfly/mod.rs delete mode 100644 ctr-std/src/os/dragonfly/raw.rs delete mode 100644 ctr-std/src/os/emscripten/fs.rs delete mode 100644 ctr-std/src/os/emscripten/mod.rs delete mode 100644 ctr-std/src/os/emscripten/raw.rs delete mode 100644 ctr-std/src/os/freebsd/fs.rs delete mode 100644 ctr-std/src/os/freebsd/mod.rs delete mode 100644 ctr-std/src/os/freebsd/raw.rs delete mode 100644 ctr-std/src/os/fuchsia/fs.rs delete mode 100644 ctr-std/src/os/fuchsia/mod.rs delete mode 100644 ctr-std/src/os/fuchsia/raw.rs delete mode 100644 ctr-std/src/os/haiku/fs.rs delete mode 100644 ctr-std/src/os/haiku/mod.rs delete mode 100644 ctr-std/src/os/haiku/raw.rs delete mode 100644 ctr-std/src/os/hermit/fs.rs delete mode 100644 ctr-std/src/os/hermit/mod.rs delete mode 100644 ctr-std/src/os/hermit/raw.rs delete mode 100644 ctr-std/src/os/horizon/fs.rs delete mode 100644 ctr-std/src/os/horizon/mod.rs delete mode 100644 ctr-std/src/os/horizon/raw.rs delete mode 100644 ctr-std/src/os/ios/fs.rs delete mode 100644 ctr-std/src/os/ios/mod.rs delete mode 100644 ctr-std/src/os/ios/raw.rs delete mode 100644 ctr-std/src/os/linux/fs.rs delete mode 100644 ctr-std/src/os/linux/mod.rs delete mode 100644 ctr-std/src/os/linux/raw.rs delete mode 100644 ctr-std/src/os/macos/fs.rs delete mode 100644 ctr-std/src/os/macos/mod.rs delete mode 100644 ctr-std/src/os/macos/raw.rs delete mode 100644 ctr-std/src/os/mod.rs delete mode 100644 ctr-std/src/os/netbsd/fs.rs delete mode 100644 ctr-std/src/os/netbsd/mod.rs delete mode 100644 ctr-std/src/os/netbsd/raw.rs delete mode 100644 ctr-std/src/os/openbsd/fs.rs delete mode 100644 ctr-std/src/os/openbsd/mod.rs delete mode 100644 ctr-std/src/os/openbsd/raw.rs delete mode 100644 ctr-std/src/os/raw/char.md delete mode 100644 ctr-std/src/os/raw/double.md delete mode 100644 ctr-std/src/os/raw/float.md delete mode 100644 ctr-std/src/os/raw/int.md delete mode 100644 ctr-std/src/os/raw/long.md delete mode 100644 ctr-std/src/os/raw/longlong.md delete mode 100644 ctr-std/src/os/raw/mod.rs delete mode 100644 ctr-std/src/os/raw/schar.md delete mode 100644 ctr-std/src/os/raw/short.md delete mode 100644 ctr-std/src/os/raw/uchar.md delete mode 100644 ctr-std/src/os/raw/uint.md delete mode 100644 ctr-std/src/os/raw/ulong.md delete mode 100644 ctr-std/src/os/raw/ulonglong.md delete mode 100644 ctr-std/src/os/raw/ushort.md delete mode 100644 ctr-std/src/os/solaris/fs.rs delete mode 100644 ctr-std/src/os/solaris/mod.rs delete mode 100644 ctr-std/src/os/solaris/raw.rs delete mode 100644 ctr-std/src/panic.rs delete mode 100644 ctr-std/src/panicking.rs delete mode 100644 ctr-std/src/path.rs delete mode 100644 ctr-std/src/prelude/mod.rs delete mode 100644 ctr-std/src/prelude/v1.rs delete mode 100644 ctr-std/src/primitive_docs.rs delete mode 100644 ctr-std/src/process.rs delete mode 100644 ctr-std/src/rt.rs delete mode 100644 ctr-std/src/sync/barrier.rs delete mode 100644 ctr-std/src/sync/condvar.rs delete mode 100644 ctr-std/src/sync/mod.rs delete mode 100644 ctr-std/src/sync/mpsc/blocking.rs delete mode 100644 ctr-std/src/sync/mpsc/cache_aligned.rs delete mode 100644 ctr-std/src/sync/mpsc/mod.rs delete mode 100644 ctr-std/src/sync/mpsc/mpsc_queue.rs delete mode 100644 ctr-std/src/sync/mpsc/oneshot.rs delete mode 100644 ctr-std/src/sync/mpsc/select.rs delete mode 100644 ctr-std/src/sync/mpsc/shared.rs delete mode 100644 ctr-std/src/sync/mpsc/spsc_queue.rs delete mode 100644 ctr-std/src/sync/mpsc/stream.rs delete mode 100644 ctr-std/src/sync/mpsc/sync.rs delete mode 100644 ctr-std/src/sync/mutex.rs delete mode 100644 ctr-std/src/sync/once.rs delete mode 100644 ctr-std/src/sync/rwlock.rs delete mode 100644 ctr-std/src/sys/cloudabi/abi/bitflags.rs delete mode 100644 ctr-std/src/sys/cloudabi/abi/cloudabi.rs delete mode 100644 ctr-std/src/sys/cloudabi/abi/mod.rs delete mode 100644 ctr-std/src/sys/cloudabi/args.rs delete mode 100644 ctr-std/src/sys/cloudabi/backtrace.rs delete mode 100644 ctr-std/src/sys/cloudabi/condvar.rs delete mode 100644 ctr-std/src/sys/cloudabi/mod.rs delete mode 100644 ctr-std/src/sys/cloudabi/mutex.rs delete mode 100644 ctr-std/src/sys/cloudabi/os.rs delete mode 100644 ctr-std/src/sys/cloudabi/rwlock.rs delete mode 100644 ctr-std/src/sys/cloudabi/shims/args.rs delete mode 100644 ctr-std/src/sys/cloudabi/shims/env.rs delete mode 100644 ctr-std/src/sys/cloudabi/shims/fs.rs delete mode 100644 ctr-std/src/sys/cloudabi/shims/mod.rs delete mode 100644 ctr-std/src/sys/cloudabi/shims/net.rs delete mode 100644 ctr-std/src/sys/cloudabi/shims/os.rs delete mode 100644 ctr-std/src/sys/cloudabi/shims/pipe.rs delete mode 100644 ctr-std/src/sys/cloudabi/shims/process.rs delete mode 100644 ctr-std/src/sys/cloudabi/stack_overflow.rs delete mode 100644 ctr-std/src/sys/cloudabi/stdio.rs delete mode 100644 ctr-std/src/sys/cloudabi/thread.rs delete mode 100644 ctr-std/src/sys/cloudabi/time.rs delete mode 100644 ctr-std/src/sys/horizon/android.rs delete mode 100644 ctr-std/src/sys/horizon/args.rs delete mode 100644 ctr-std/src/sys/horizon/backtrace/mod.rs delete mode 100644 ctr-std/src/sys/horizon/backtrace/printing/dladdr.rs delete mode 100644 ctr-std/src/sys/horizon/backtrace/printing/mod.rs delete mode 100644 ctr-std/src/sys/horizon/backtrace/tracing/backtrace_fn.rs delete mode 100644 ctr-std/src/sys/horizon/backtrace/tracing/gcc_s.rs delete mode 100644 ctr-std/src/sys/horizon/backtrace/tracing/mod.rs delete mode 100644 ctr-std/src/sys/horizon/cmath.rs delete mode 100644 ctr-std/src/sys/horizon/condvar.rs delete mode 100644 ctr-std/src/sys/horizon/env.rs delete mode 100644 ctr-std/src/sys/horizon/ext/ffi.rs delete mode 100644 ctr-std/src/sys/horizon/ext/fs.rs delete mode 100644 ctr-std/src/sys/horizon/ext/io.rs delete mode 100644 ctr-std/src/sys/horizon/ext/mod.rs delete mode 100644 ctr-std/src/sys/horizon/ext/raw.rs delete mode 100644 ctr-std/src/sys/horizon/fast_thread_local.rs delete mode 100644 ctr-std/src/sys/horizon/fd.rs delete mode 100644 ctr-std/src/sys/horizon/fs.rs delete mode 100644 ctr-std/src/sys/horizon/l4re.rs delete mode 100644 ctr-std/src/sys/horizon/memchr.rs delete mode 100644 ctr-std/src/sys/horizon/mod.rs delete mode 100644 ctr-std/src/sys/horizon/mutex.rs delete mode 100644 ctr-std/src/sys/horizon/net.rs delete mode 100644 ctr-std/src/sys/horizon/os.rs delete mode 100644 ctr-std/src/sys/horizon/os_str.rs delete mode 100644 ctr-std/src/sys/horizon/path.rs delete mode 100644 ctr-std/src/sys/horizon/pipe.rs delete mode 100644 ctr-std/src/sys/horizon/process.rs delete mode 100644 ctr-std/src/sys/horizon/rand.rs delete mode 100644 ctr-std/src/sys/horizon/rwlock.rs delete mode 100644 ctr-std/src/sys/horizon/stack_overflow.rs delete mode 100644 ctr-std/src/sys/horizon/stdio.rs delete mode 100644 ctr-std/src/sys/horizon/thread.rs delete mode 100644 ctr-std/src/sys/horizon/thread_local.rs delete mode 100644 ctr-std/src/sys/horizon/time.rs delete mode 100644 ctr-std/src/sys/horizon/weak.rs delete mode 100644 ctr-std/src/sys/mod.rs delete mode 100644 ctr-std/src/sys/redox/args.rs delete mode 100644 ctr-std/src/sys/redox/backtrace/mod.rs delete mode 100644 ctr-std/src/sys/redox/backtrace/printing.rs delete mode 100644 ctr-std/src/sys/redox/backtrace/tracing.rs delete mode 100644 ctr-std/src/sys/redox/cmath.rs delete mode 100644 ctr-std/src/sys/redox/condvar.rs delete mode 100644 ctr-std/src/sys/redox/env.rs delete mode 100644 ctr-std/src/sys/redox/ext/ffi.rs delete mode 100644 ctr-std/src/sys/redox/ext/fs.rs delete mode 100644 ctr-std/src/sys/redox/ext/io.rs delete mode 100644 ctr-std/src/sys/redox/ext/mod.rs delete mode 100644 ctr-std/src/sys/redox/ext/net.rs delete mode 100644 ctr-std/src/sys/redox/ext/process.rs delete mode 100644 ctr-std/src/sys/redox/ext/thread.rs delete mode 100644 ctr-std/src/sys/redox/fast_thread_local.rs delete mode 100644 ctr-std/src/sys/redox/fd.rs delete mode 100644 ctr-std/src/sys/redox/fs.rs delete mode 100644 ctr-std/src/sys/redox/memchr.rs delete mode 100644 ctr-std/src/sys/redox/mod.rs delete mode 100644 ctr-std/src/sys/redox/mutex.rs delete mode 100644 ctr-std/src/sys/redox/net/dns/answer.rs delete mode 100644 ctr-std/src/sys/redox/net/dns/mod.rs delete mode 100644 ctr-std/src/sys/redox/net/dns/query.rs delete mode 100644 ctr-std/src/sys/redox/net/mod.rs delete mode 100644 ctr-std/src/sys/redox/net/netc.rs delete mode 100644 ctr-std/src/sys/redox/net/tcp.rs delete mode 100644 ctr-std/src/sys/redox/net/udp.rs delete mode 100644 ctr-std/src/sys/redox/os.rs delete mode 100644 ctr-std/src/sys/redox/os_str.rs delete mode 100644 ctr-std/src/sys/redox/path.rs delete mode 100644 ctr-std/src/sys/redox/pipe.rs delete mode 100644 ctr-std/src/sys/redox/process.rs delete mode 100644 ctr-std/src/sys/redox/rand.rs delete mode 100644 ctr-std/src/sys/redox/rwlock.rs delete mode 100644 ctr-std/src/sys/redox/stack_overflow.rs delete mode 100644 ctr-std/src/sys/redox/stdio.rs delete mode 100644 ctr-std/src/sys/redox/syscall/arch/arm.rs delete mode 100644 ctr-std/src/sys/redox/syscall/arch/x86.rs delete mode 100644 ctr-std/src/sys/redox/syscall/arch/x86_64.rs delete mode 100644 ctr-std/src/sys/redox/syscall/call.rs delete mode 100644 ctr-std/src/sys/redox/syscall/data.rs delete mode 100644 ctr-std/src/sys/redox/syscall/error.rs delete mode 100644 ctr-std/src/sys/redox/syscall/flag.rs delete mode 100644 ctr-std/src/sys/redox/syscall/mod.rs delete mode 100644 ctr-std/src/sys/redox/syscall/number.rs delete mode 100644 ctr-std/src/sys/redox/thread.rs delete mode 100644 ctr-std/src/sys/redox/thread_local.rs delete mode 100644 ctr-std/src/sys/redox/time.rs delete mode 100644 ctr-std/src/sys/unix/android.rs delete mode 100644 ctr-std/src/sys/unix/args.rs delete mode 100644 ctr-std/src/sys/unix/backtrace/mod.rs delete mode 100644 ctr-std/src/sys/unix/backtrace/printing/dladdr.rs delete mode 100644 ctr-std/src/sys/unix/backtrace/printing/mod.rs delete mode 100644 ctr-std/src/sys/unix/backtrace/tracing/backtrace_fn.rs delete mode 100644 ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs delete mode 100644 ctr-std/src/sys/unix/backtrace/tracing/mod.rs delete mode 100644 ctr-std/src/sys/unix/cmath.rs delete mode 100644 ctr-std/src/sys/unix/condvar.rs delete mode 100644 ctr-std/src/sys/unix/env.rs delete mode 100644 ctr-std/src/sys/unix/ext/ffi.rs delete mode 100644 ctr-std/src/sys/unix/ext/fs.rs delete mode 100644 ctr-std/src/sys/unix/ext/io.rs delete mode 100644 ctr-std/src/sys/unix/ext/mod.rs delete mode 100644 ctr-std/src/sys/unix/ext/net.rs delete mode 100644 ctr-std/src/sys/unix/ext/process.rs delete mode 100644 ctr-std/src/sys/unix/ext/raw.rs delete mode 100644 ctr-std/src/sys/unix/ext/thread.rs delete mode 100644 ctr-std/src/sys/unix/fast_thread_local.rs delete mode 100644 ctr-std/src/sys/unix/fd.rs delete mode 100644 ctr-std/src/sys/unix/fs.rs delete mode 100644 ctr-std/src/sys/unix/l4re.rs delete mode 100644 ctr-std/src/sys/unix/memchr.rs delete mode 100644 ctr-std/src/sys/unix/mod.rs delete mode 100644 ctr-std/src/sys/unix/mutex.rs delete mode 100644 ctr-std/src/sys/unix/net.rs delete mode 100644 ctr-std/src/sys/unix/os.rs delete mode 100644 ctr-std/src/sys/unix/os_str.rs delete mode 100644 ctr-std/src/sys/unix/path.rs delete mode 100644 ctr-std/src/sys/unix/pipe.rs delete mode 100644 ctr-std/src/sys/unix/process/mod.rs delete mode 100644 ctr-std/src/sys/unix/process/process_common.rs delete mode 100644 ctr-std/src/sys/unix/process/process_fuchsia.rs delete mode 100644 ctr-std/src/sys/unix/process/process_unix.rs delete mode 100644 ctr-std/src/sys/unix/process/zircon.rs delete mode 100644 ctr-std/src/sys/unix/rand.rs delete mode 100644 ctr-std/src/sys/unix/rwlock.rs delete mode 100644 ctr-std/src/sys/unix/stack_overflow.rs delete mode 100644 ctr-std/src/sys/unix/stdio.rs delete mode 100644 ctr-std/src/sys/unix/thread.rs delete mode 100644 ctr-std/src/sys/unix/thread_local.rs delete mode 100644 ctr-std/src/sys/unix/time.rs delete mode 100644 ctr-std/src/sys/unix/weak.rs delete mode 100644 ctr-std/src/sys/wasm/args.rs delete mode 100644 ctr-std/src/sys/wasm/backtrace.rs delete mode 100644 ctr-std/src/sys/wasm/cmath.rs delete mode 100644 ctr-std/src/sys/wasm/condvar.rs delete mode 100644 ctr-std/src/sys/wasm/env.rs delete mode 100644 ctr-std/src/sys/wasm/fs.rs delete mode 100644 ctr-std/src/sys/wasm/memchr.rs delete mode 100644 ctr-std/src/sys/wasm/mod.rs delete mode 100644 ctr-std/src/sys/wasm/mutex.rs delete mode 100644 ctr-std/src/sys/wasm/net.rs delete mode 100644 ctr-std/src/sys/wasm/os.rs delete mode 100644 ctr-std/src/sys/wasm/os_str.rs delete mode 100644 ctr-std/src/sys/wasm/path.rs delete mode 100644 ctr-std/src/sys/wasm/pipe.rs delete mode 100644 ctr-std/src/sys/wasm/process.rs delete mode 100644 ctr-std/src/sys/wasm/rwlock.rs delete mode 100644 ctr-std/src/sys/wasm/stack_overflow.rs delete mode 100644 ctr-std/src/sys/wasm/stdio.rs delete mode 100644 ctr-std/src/sys/wasm/thread.rs delete mode 100644 ctr-std/src/sys/wasm/thread_local.rs delete mode 100644 ctr-std/src/sys/wasm/time.rs delete mode 100644 ctr-std/src/sys/windows/args.rs delete mode 100644 ctr-std/src/sys/windows/backtrace/backtrace_gnu.rs delete mode 100644 ctr-std/src/sys/windows/backtrace/mod.rs delete mode 100644 ctr-std/src/sys/windows/backtrace/printing/mod.rs delete mode 100644 ctr-std/src/sys/windows/backtrace/printing/msvc.rs delete mode 100644 ctr-std/src/sys/windows/c.rs delete mode 100644 ctr-std/src/sys/windows/cmath.rs delete mode 100644 ctr-std/src/sys/windows/compat.rs delete mode 100644 ctr-std/src/sys/windows/condvar.rs delete mode 100644 ctr-std/src/sys/windows/dynamic_lib.rs delete mode 100644 ctr-std/src/sys/windows/env.rs delete mode 100644 ctr-std/src/sys/windows/ext/ffi.rs delete mode 100644 ctr-std/src/sys/windows/ext/fs.rs delete mode 100644 ctr-std/src/sys/windows/ext/io.rs delete mode 100644 ctr-std/src/sys/windows/ext/mod.rs delete mode 100644 ctr-std/src/sys/windows/ext/process.rs delete mode 100644 ctr-std/src/sys/windows/ext/raw.rs delete mode 100644 ctr-std/src/sys/windows/ext/thread.rs delete mode 100644 ctr-std/src/sys/windows/fast_thread_local.rs delete mode 100644 ctr-std/src/sys/windows/fs.rs delete mode 100644 ctr-std/src/sys/windows/handle.rs delete mode 100644 ctr-std/src/sys/windows/memchr.rs delete mode 100644 ctr-std/src/sys/windows/mod.rs delete mode 100644 ctr-std/src/sys/windows/mutex.rs delete mode 100644 ctr-std/src/sys/windows/net.rs delete mode 100644 ctr-std/src/sys/windows/os.rs delete mode 100644 ctr-std/src/sys/windows/os_str.rs delete mode 100644 ctr-std/src/sys/windows/path.rs delete mode 100644 ctr-std/src/sys/windows/pipe.rs delete mode 100644 ctr-std/src/sys/windows/process.rs delete mode 100644 ctr-std/src/sys/windows/rand.rs delete mode 100644 ctr-std/src/sys/windows/rwlock.rs delete mode 100644 ctr-std/src/sys/windows/stack_overflow.rs delete mode 100644 ctr-std/src/sys/windows/stdio.rs delete mode 100644 ctr-std/src/sys/windows/thread.rs delete mode 100644 ctr-std/src/sys/windows/thread_local.rs delete mode 100644 ctr-std/src/sys/windows/time.rs delete mode 100644 ctr-std/src/sys_common/at_exit_imp.rs delete mode 100644 ctr-std/src/sys_common/backtrace.rs delete mode 100644 ctr-std/src/sys_common/bytestring.rs delete mode 100644 ctr-std/src/sys_common/condvar.rs delete mode 100644 ctr-std/src/sys_common/gnu/libbacktrace.rs delete mode 100644 ctr-std/src/sys_common/gnu/mod.rs delete mode 100644 ctr-std/src/sys_common/io.rs delete mode 100644 ctr-std/src/sys_common/mod.rs delete mode 100644 ctr-std/src/sys_common/mutex.rs delete mode 100644 ctr-std/src/sys_common/net.rs delete mode 100644 ctr-std/src/sys_common/poison.rs delete mode 100644 ctr-std/src/sys_common/process.rs delete mode 100644 ctr-std/src/sys_common/remutex.rs delete mode 100644 ctr-std/src/sys_common/rwlock.rs delete mode 100644 ctr-std/src/sys_common/thread.rs delete mode 100644 ctr-std/src/sys_common/thread_info.rs delete mode 100644 ctr-std/src/sys_common/thread_local.rs delete mode 100644 ctr-std/src/sys_common/util.rs delete mode 100644 ctr-std/src/sys_common/wtf8.rs delete mode 100644 ctr-std/src/tests/env.rs delete mode 100644 ctr-std/src/thread/local.rs delete mode 100644 ctr-std/src/thread/mod.rs delete mode 100644 ctr-std/src/time.rs diff --git a/ctr-std/Cargo.toml b/ctr-std/Cargo.toml deleted file mode 100644 index 3424485..0000000 --- a/ctr-std/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "std" -version = "0.0.0" -license = "MIT/Apache 2.0" - -[dependencies.alloc_system] -git = "https://github.com/rust3ds/alloc_system3ds" - -[dependencies.ctru-sys] -path = "../ctru-sys" -default-features = false -features = ["stdbuild"] diff --git a/ctr-std/README.md b/ctr-std/README.md deleted file mode 100644 index e30e54f..0000000 --- a/ctr-std/README.md +++ /dev/null @@ -1,69 +0,0 @@ -A work-in-progress port of the Rust Standard Library for the Nintendo 3DS, based on [ctrulib](https://github.com/smealum/ctrulib/) and the [devkitARM](http://devkitPro.org) toolchain. - -## Structure - -This library aims to mimick the Rust standard library's public interface as closely as possible, exposing functionality that is common between the 3DS and other platforms. System-specific functionality such as control input, save file management, GPU features, and so forth are implemented in `ctru-rs`. - -## Working modules - -* `any` -* `ascii` -* `borrow` -* `boxed` -* `cell` -* `char` -* `clone` -* `cmp` -* `collections` -* `convert` -* `default` -* `error` -* `f32` -* `f64` -* `ffi` -* `fmt` -* `fs` Both `sdmc:/` and `romfs:/` paths are supported in standard file operations -* `hash` -* `i8` -* `i16` -* `i32` -* `i64` -* `io` -* `isize` -* `iter` -* `marker` -* `mem` -* `num` -* `ops` -* `option` -* `panic` -* `path` -* `prelude` -* `ptr` -* `rc` -* `result` -* `slice` -* `str` -* `string` -* `sync` -* `time` -* `thread` Threads are able to be spawned, but without the ability to pin to a specific core or set thread priority -* `u8` -* `u16` -* `u32` -* `u64` -* `usize` -* `vec` -* `heap` -* `i128` -* `intrinsics` -* `raw` -* `u128` - -# Partially working modules -* `net` Anything not involving IPv6 should work after initializing the `Soc` service in `ctru-rs` -* `os` The modules in here should work, but they aren't well-tested - -# Non-working modules -* `env` argc/argv can be implemented but have not been yet -* `process` Unable to be implemented due to platform incompatibilities diff --git a/ctr-std/src/alloc.rs b/ctr-std/src/alloc.rs deleted file mode 100644 index b9aba1e..0000000 --- a/ctr-std/src/alloc.rs +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Memory allocation APIs -//! -//! In a given program, the standard library has one “global” memory allocator -//! that is used for example by `Box` and `Vec`. -//! -//! Currently the default global allocator is unspecified. -//! The compiler may link to a version of [jemalloc] on some platforms, -//! but this is not guaranteed. -//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed -//! to use the [`System`] by default. -//! -//! [jemalloc]: https://github.com/jemalloc/jemalloc -//! [`System`]: struct.System.html -//! -//! # The `#[global_allocator]` attribute -//! -//! This attribute allows configuring the choice of global allocator. -//! You can use this to implement a completely custom global allocator -//! to route all default allocation requests to a custom object. -//! -//! ```rust -//! use std::alloc::{GlobalAlloc, System, Layout}; -//! -//! struct MyAllocator; -//! -//! unsafe impl GlobalAlloc for MyAllocator { -//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 { -//! System.alloc(layout) -//! } -//! -//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { -//! System.dealloc(ptr, layout) -//! } -//! } -//! -//! #[global_allocator] -//! static GLOBAL: MyAllocator = MyAllocator; -//! -//! fn main() { -//! // This `Vec` will allocate memory through `GLOBAL` above -//! let mut v = Vec::new(); -//! v.push(1); -//! } -//! ``` -//! -//! The attribute is used on a `static` item whose type implements the -//! [`GlobalAlloc`] trait. This type can be provided by an external library: -//! -//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html -//! -//! ```rust,ignore (demonstrates crates.io usage) -//! extern crate jemallocator; -//! -//! use jemallocator::Jemalloc; -//! -//! #[global_allocator] -//! static GLOBAL: Jemalloc = Jemalloc; -//! -//! fn main() {} -//! ``` -//! -//! The `#[global_allocator]` can only be used once in a crate -//! or its recursive dependencies. - -#![stable(feature = "alloc_module", since = "1.28.0")] - -use core::sync::atomic::{AtomicPtr, Ordering}; -use core::{mem, ptr}; -use sys_common::util::dumb_print; - -#[stable(feature = "alloc_module", since = "1.28.0")] -#[doc(inline)] -pub use alloc_crate::alloc::*; - -#[stable(feature = "alloc_system_type", since = "1.28.0")] -#[doc(inline)] -pub use alloc_system::System; - -static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); - -/// Registers a custom allocation error hook, replacing any that was previously registered. -/// -/// The allocation error hook is invoked when an infallible memory allocation fails, before -/// the runtime aborts. The default hook prints a message to standard error, -/// but this behavior can be customized with the [`set_alloc_error_hook`] and -/// [`take_alloc_error_hook`] functions. -/// -/// The hook is provided with a `Layout` struct which contains information -/// about the allocation that failed. -/// -/// The allocation error hook is a global resource. -#[unstable(feature = "alloc_error_hook", issue = "51245")] -pub fn set_alloc_error_hook(hook: fn(Layout)) { - HOOK.store(hook as *mut (), Ordering::SeqCst); -} - -/// Unregisters the current allocation error hook, returning it. -/// -/// *See also the function [`set_alloc_error_hook`].* -/// -/// If no custom hook is registered, the default hook will be returned. -#[unstable(feature = "alloc_error_hook", issue = "51245")] -pub fn take_alloc_error_hook() -> fn(Layout) { - let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); - if hook.is_null() { - default_alloc_error_hook - } else { - unsafe { mem::transmute(hook) } - } -} - -fn default_alloc_error_hook(layout: Layout) { - dumb_print(format_args!("memory allocation of {} bytes failed", layout.size())); -} - -#[cfg(not(test))] -#[doc(hidden)] -#[alloc_error_handler] -#[unstable(feature = "alloc_internals", issue = "0")] -pub fn rust_oom(layout: Layout) -> ! { - let hook = HOOK.load(Ordering::SeqCst); - let hook: fn(Layout) = if hook.is_null() { - default_alloc_error_hook - } else { - unsafe { mem::transmute(hook) } - }; - hook(layout); - unsafe { ::sys::abort_internal(); } -} - -#[cfg(not(test))] -#[doc(hidden)] -#[allow(unused_attributes)] -#[unstable(feature = "alloc_internals", issue = "0")] -pub mod __default_lib_allocator { - use super::{System, Layout, GlobalAlloc}; - // for symbol names src/librustc/middle/allocator.rs - // for signatures src/librustc_allocator/lib.rs - - // linkage directives are provided as part of the current compiler allocator - // ABI - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - System.alloc(layout) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, - size: usize, - align: usize) { - System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc(ptr: *mut u8, - old_size: usize, - align: usize, - new_size: usize) -> *mut u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, align); - System.realloc(ptr, old_layout, new_size) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - System.alloc_zeroed(layout) - } -} diff --git a/ctr-std/src/ascii.rs b/ctr-std/src/ascii.rs deleted file mode 100644 index 0c8e95a..0000000 --- a/ctr-std/src/ascii.rs +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations on ASCII strings and characters. -//! -//! Most string operations in Rust act on UTF-8 strings. However, at times it -//! makes more sense to only consider the ASCII character set for a specific -//! operation. -//! -//! The [`AsciiExt`] trait provides methods that allow for character -//! operations that only act on the ASCII subset and leave non-ASCII characters -//! alone. -//! -//! The [`escape_default`] function provides an iterator over the bytes of an -//! escaped version of the character given. -//! -//! [`AsciiExt`]: trait.AsciiExt.html -//! [`escape_default`]: fn.escape_default.html - -#![stable(feature = "rust1", since = "1.0.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::ascii::{EscapeDefault, escape_default}; - -/// Extension methods for ASCII-subset only operations. -/// -/// Be aware that operations on seemingly non-ASCII characters can sometimes -/// have unexpected results. Consider this example: -/// -/// ``` -/// use std::ascii::AsciiExt; -/// -/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFÉ"); -/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFé"); -/// ``` -/// -/// In the first example, the lowercased string is represented `"cafe\u{301}"` -/// (the last character is an acute accent [combining character]). Unlike the -/// other characters in the string, the combining character will not get mapped -/// to an uppercase variant, resulting in `"CAFE\u{301}"`. In the second -/// example, the lowercased string is represented `"caf\u{e9}"` (the last -/// character is a single Unicode character representing an 'e' with an acute -/// accent). Since the last character is defined outside the scope of ASCII, -/// it will not get mapped to an uppercase variant, resulting in `"CAF\u{e9}"`. -/// -/// [combining character]: https://en.wikipedia.org/wiki/Combining_character -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] -pub trait AsciiExt { - /// Container type for copied ASCII characters. - #[stable(feature = "rust1", since = "1.0.0")] - type Owned; - - /// Checks if the value is within the ASCII range. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[stable(feature = "rust1", since = "1.0.0")] - fn is_ascii(&self) -> bool; - - /// Makes a copy of the value in its ASCII upper case equivalent. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To uppercase the value in-place, use [`make_ascii_uppercase`]. - /// - /// To uppercase ASCII characters in addition to non-ASCII characters, use - /// [`str::to_uppercase`]. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - /// - /// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase - /// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - fn to_ascii_uppercase(&self) -> Self::Owned; - - /// Makes a copy of the value in its ASCII lower case equivalent. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To lowercase the value in-place, use [`make_ascii_lowercase`]. - /// - /// To lowercase ASCII characters in addition to non-ASCII characters, use - /// [`str::to_lowercase`]. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - /// - /// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase - /// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - fn to_ascii_lowercase(&self) -> Self::Owned; - - /// Checks that two values are an ASCII case-insensitive match. - /// - /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporaries. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[stable(feature = "rust1", since = "1.0.0")] - fn eq_ignore_ascii_case(&self, other: &Self) -> bool; - - /// Converts this type to its ASCII upper case equivalent in-place. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - /// - /// [`to_ascii_uppercase`]: #tymethod.to_ascii_uppercase - #[stable(feature = "ascii", since = "1.9.0")] - fn make_ascii_uppercase(&mut self); - - /// Converts this type to its ASCII lower case equivalent in-place. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - /// - /// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase - #[stable(feature = "ascii", since = "1.9.0")] - fn make_ascii_lowercase(&mut self); -} - -macro_rules! delegating_ascii_methods { - () => { - #[inline] - fn is_ascii(&self) -> bool { self.is_ascii() } - - #[inline] - fn to_ascii_uppercase(&self) -> Self::Owned { self.to_ascii_uppercase() } - - #[inline] - fn to_ascii_lowercase(&self) -> Self::Owned { self.to_ascii_lowercase() } - - #[inline] - fn eq_ignore_ascii_case(&self, o: &Self) -> bool { self.eq_ignore_ascii_case(o) } - - #[inline] - fn make_ascii_uppercase(&mut self) { self.make_ascii_uppercase(); } - - #[inline] - fn make_ascii_lowercase(&mut self) { self.make_ascii_lowercase(); } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl AsciiExt for u8 { - type Owned = u8; - - delegating_ascii_methods!(); -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl AsciiExt for char { - type Owned = char; - - delegating_ascii_methods!(); -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl AsciiExt for [u8] { - type Owned = Vec; - - delegating_ascii_methods!(); -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl AsciiExt for str { - type Owned = String; - - delegating_ascii_methods!(); -} diff --git a/ctr-std/src/build.rs b/ctr-std/src/build.rs deleted file mode 100644 index 016e7ad..0000000 --- a/ctr-std/src/build.rs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![deny(warnings)] - -extern crate build_helper; -extern crate cc; - -use build_helper::native_lib_boilerplate; -use std::env; -use std::fs::File; - -fn main() { - let target = env::var("TARGET").expect("TARGET was not set"); - if cfg!(feature = "backtrace") && - !target.contains("cloudabi") && - !target.contains("emscripten") && - !target.contains("msvc") && - !target.contains("wasm32") - { - let _ = build_libbacktrace(&target); - } - - if target.contains("linux") { - if target.contains("android") { - println!("cargo:rustc-link-lib=dl"); - println!("cargo:rustc-link-lib=log"); - println!("cargo:rustc-link-lib=gcc"); - } else if !target.contains("musl") { - println!("cargo:rustc-link-lib=dl"); - println!("cargo:rustc-link-lib=rt"); - println!("cargo:rustc-link-lib=pthread"); - } - } else if target.contains("freebsd") { - println!("cargo:rustc-link-lib=execinfo"); - println!("cargo:rustc-link-lib=pthread"); - } else if target.contains("dragonfly") || target.contains("bitrig") || - target.contains("netbsd") || target.contains("openbsd") { - println!("cargo:rustc-link-lib=pthread"); - } else if target.contains("solaris") { - println!("cargo:rustc-link-lib=socket"); - println!("cargo:rustc-link-lib=posix4"); - println!("cargo:rustc-link-lib=pthread"); - println!("cargo:rustc-link-lib=resolv"); - } else if target.contains("apple-darwin") { - println!("cargo:rustc-link-lib=System"); - - // res_init and friends require -lresolv on macOS/iOS. - // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html - println!("cargo:rustc-link-lib=resolv"); - } else if target.contains("apple-ios") { - println!("cargo:rustc-link-lib=System"); - println!("cargo:rustc-link-lib=objc"); - println!("cargo:rustc-link-lib=framework=Security"); - println!("cargo:rustc-link-lib=framework=Foundation"); - println!("cargo:rustc-link-lib=resolv"); - } else if target.contains("windows") { - println!("cargo:rustc-link-lib=advapi32"); - println!("cargo:rustc-link-lib=ws2_32"); - println!("cargo:rustc-link-lib=userenv"); - println!("cargo:rustc-link-lib=shell32"); - } else if target.contains("fuchsia") { - println!("cargo:rustc-link-lib=zircon"); - println!("cargo:rustc-link-lib=fdio"); - } else if target.contains("cloudabi") { - if cfg!(feature = "backtrace") { - println!("cargo:rustc-link-lib=unwind"); - } - println!("cargo:rustc-link-lib=c"); - println!("cargo:rustc-link-lib=compiler_rt"); - } -} - -fn build_libbacktrace(target: &str) -> Result<(), ()> { - let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", "")?; - - let mut build = cc::Build::new(); - build - .flag("-fvisibility=hidden") - .include("../libbacktrace") - .include(&native.out_dir) - .out_dir(&native.out_dir) - .warnings(false) - .file("../libbacktrace/alloc.c") - .file("../libbacktrace/backtrace.c") - .file("../libbacktrace/dwarf.c") - .file("../libbacktrace/fileline.c") - .file("../libbacktrace/posix.c") - .file("../libbacktrace/read.c") - .file("../libbacktrace/sort.c") - .file("../libbacktrace/state.c"); - - if target.contains("darwin") { - build.file("../libbacktrace/macho.c"); - } else if target.contains("windows") { - build.file("../libbacktrace/pecoff.c"); - } else { - build.file("../libbacktrace/elf.c"); - - let pointer_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap(); - if pointer_width == "64" { - build.define("BACKTRACE_ELF_SIZE", "64"); - } else { - build.define("BACKTRACE_ELF_SIZE", "32"); - } - } - - File::create(native.out_dir.join("backtrace-supported.h")).unwrap(); - build.define("BACKTRACE_SUPPORTED", "1"); - build.define("BACKTRACE_USES_MALLOC", "1"); - build.define("BACKTRACE_SUPPORTS_THREADS", "0"); - build.define("BACKTRACE_SUPPORTS_DATA", "0"); - - File::create(native.out_dir.join("config.h")).unwrap(); - if !target.contains("apple-ios") && - !target.contains("solaris") && - !target.contains("redox") && - !target.contains("android") && - !target.contains("haiku") { - build.define("HAVE_DL_ITERATE_PHDR", "1"); - } - build.define("_GNU_SOURCE", "1"); - build.define("_LARGE_FILES", "1"); - - build.compile("backtrace"); - Ok(()) -} diff --git a/ctr-std/src/collections/hash/bench.rs b/ctr-std/src/collections/hash/bench.rs deleted file mode 100644 index ff6cb79..0000000 --- a/ctr-std/src/collections/hash/bench.rs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg(test)] - -extern crate test; - -use self::test::Bencher; - -#[bench] -fn new_drop(b: &mut Bencher) { - use super::map::HashMap; - - b.iter(|| { - let m: HashMap = HashMap::new(); - assert_eq!(m.len(), 0); - }) -} - -#[bench] -fn new_insert_drop(b: &mut Bencher) { - use super::map::HashMap; - - b.iter(|| { - let mut m = HashMap::new(); - m.insert(0, 0); - assert_eq!(m.len(), 1); - }) -} - -#[bench] -fn grow_by_insertion(b: &mut Bencher) { - use super::map::HashMap; - - let mut m = HashMap::new(); - - for i in 1..1001 { - m.insert(i, i); - } - - let mut k = 1001; - - b.iter(|| { - m.insert(k, k); - k += 1; - }); -} - -#[bench] -fn find_existing(b: &mut Bencher) { - use super::map::HashMap; - - let mut m = HashMap::new(); - - for i in 1..1001 { - m.insert(i, i); - } - - b.iter(|| { - for i in 1..1001 { - m.contains_key(&i); - } - }); -} - -#[bench] -fn find_nonexisting(b: &mut Bencher) { - use super::map::HashMap; - - let mut m = HashMap::new(); - - for i in 1..1001 { - m.insert(i, i); - } - - b.iter(|| { - for i in 1001..2001 { - m.contains_key(&i); - } - }); -} - -#[bench] -fn hashmap_as_queue(b: &mut Bencher) { - use super::map::HashMap; - - let mut m = HashMap::new(); - - for i in 1..1001 { - m.insert(i, i); - } - - let mut k = 1; - - b.iter(|| { - m.remove(&k); - m.insert(k + 1000, k + 1000); - k += 1; - }); -} - -#[bench] -fn get_remove_insert(b: &mut Bencher) { - use super::map::HashMap; - - let mut m = HashMap::new(); - - for i in 1..1001 { - m.insert(i, i); - } - - let mut k = 1; - - b.iter(|| { - m.get(&(k + 400)); - m.get(&(k + 2000)); - m.remove(&k); - m.insert(k + 1000, k + 1000); - k += 1; - }) -} diff --git a/ctr-std/src/collections/hash/map.rs b/ctr-std/src/collections/hash/map.rs deleted file mode 100644 index 91912e5..0000000 --- a/ctr-std/src/collections/hash/map.rs +++ /dev/null @@ -1,3686 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use self::Entry::*; -use self::VacantEntryState::*; - -use collections::CollectionAllocErr; -use cell::Cell; -use borrow::Borrow; -use cmp::max; -use fmt::{self, Debug}; -#[allow(deprecated)] -use hash::{Hash, Hasher, BuildHasher, SipHasher13}; -use iter::{FromIterator, FusedIterator}; -use mem::{self, replace}; -use ops::{Deref, Index}; -use sys; - -use super::table::{self, Bucket, EmptyBucket, Fallibility, FullBucket, FullBucketMut, RawTable, - SafeHash}; -use super::table::BucketState::{Empty, Full}; -use super::table::Fallibility::{Fallible, Infallible}; - -const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two - -/// The default behavior of HashMap implements a maximum load factor of 90.9%. -#[derive(Clone)] -struct DefaultResizePolicy; - -impl DefaultResizePolicy { - #[inline] - fn new() -> DefaultResizePolicy { - DefaultResizePolicy - } - - /// A hash map's "capacity" is the number of elements it can hold without - /// being resized. Its "raw capacity" is the number of slots required to - /// provide that capacity, accounting for maximum loading. The raw capacity - /// is always zero or a power of two. - #[inline] - fn try_raw_capacity(&self, len: usize) -> Result { - if len == 0 { - Ok(0) - } else { - // 1. Account for loading: `raw_capacity >= len * 1.1`. - // 2. Ensure it is a power of two. - // 3. Ensure it is at least the minimum size. - let mut raw_cap = len.checked_mul(11) - .map(|l| l / 10) - .and_then(|l| l.checked_next_power_of_two()) - .ok_or(CollectionAllocErr::CapacityOverflow)?; - - raw_cap = max(MIN_NONZERO_RAW_CAPACITY, raw_cap); - Ok(raw_cap) - } - } - - #[inline] - fn raw_capacity(&self, len: usize) -> usize { - self.try_raw_capacity(len).expect("raw_capacity overflow") - } - - /// The capacity of the given raw capacity. - #[inline] - fn capacity(&self, raw_cap: usize) -> usize { - // This doesn't have to be checked for overflow since allocation size - // in bytes will overflow earlier than multiplication by 10. - // - // As per https://github.com/rust-lang/rust/pull/30991 this is updated - // to be: (raw_cap * den + den - 1) / num - (raw_cap * 10 + 10 - 1) / 11 - } -} - -// The main performance trick in this hashmap is called Robin Hood Hashing. -// It gains its excellent performance from one essential operation: -// -// If an insertion collides with an existing element, and that element's -// "probe distance" (how far away the element is from its ideal location) -// is higher than how far we've already probed, swap the elements. -// -// This massively lowers variance in probe distance, and allows us to get very -// high load factors with good performance. The 90% load factor I use is rather -// conservative. -// -// > Why a load factor of approximately 90%? -// -// In general, all the distances to initial buckets will converge on the mean. -// At a load factor of α, the odds of finding the target bucket after k -// probes is approximately 1-α^k. If we set this equal to 50% (since we converge -// on the mean) and set k=8 (64-byte cache line / 8-byte hash), α=0.92. I round -// this down to make the math easier on the CPU and avoid its FPU. -// Since on average we start the probing in the middle of a cache line, this -// strategy pulls in two cache lines of hashes on every lookup. I think that's -// pretty good, but if you want to trade off some space, it could go down to one -// cache line on average with an α of 0.84. -// -// > Wait, what? Where did you get 1-α^k from? -// -// On the first probe, your odds of a collision with an existing element is α. -// The odds of doing this twice in a row is approximately α^2. For three times, -// α^3, etc. Therefore, the odds of colliding k times is α^k. The odds of NOT -// colliding after k tries is 1-α^k. -// -// The paper from 1986 cited below mentions an implementation which keeps track -// of the distance-to-initial-bucket histogram. This approach is not suitable -// for modern architectures because it requires maintaining an internal data -// structure. This allows very good first guesses, but we are most concerned -// with guessing entire cache lines, not individual indexes. Furthermore, array -// accesses are no longer linear and in one direction, as we have now. There -// is also memory and cache pressure that this would entail that would be very -// difficult to properly see in a microbenchmark. -// -// ## Future Improvements (FIXME!) -// -// Allow the load factor to be changed dynamically and/or at initialization. -// -// Also, would it be possible for us to reuse storage when growing the -// underlying table? This is exactly the use case for 'realloc', and may -// be worth exploring. -// -// ## Future Optimizations (FIXME!) -// -// Another possible design choice that I made without any real reason is -// parameterizing the raw table over keys and values. Technically, all we need -// is the size and alignment of keys and values, and the code should be just as -// efficient (well, we might need one for power-of-two size and one for not...). -// This has the potential to reduce code bloat in rust executables, without -// really losing anything except 4 words (key size, key alignment, val size, -// val alignment) which can be passed in to every call of a `RawTable` function. -// This would definitely be an avenue worth exploring if people start complaining -// about the size of rust executables. -// -// Annotate exceedingly likely branches in `table::make_hash` -// and `search_hashed` to reduce instruction cache pressure -// and mispredictions once it becomes possible (blocked on issue #11092). -// -// Shrinking the table could simply reallocate in place after moving buckets -// to the first half. -// -// The growth algorithm (fragment of the Proof of Correctness) -// -------------------- -// -// The growth algorithm is basically a fast path of the naive reinsertion- -// during-resize algorithm. Other paths should never be taken. -// -// Consider growing a robin hood hashtable of capacity n. Normally, we do this -// by allocating a new table of capacity `2n`, and then individually reinsert -// each element in the old table into the new one. This guarantees that the -// new table is a valid robin hood hashtable with all the desired statistical -// properties. Remark that the order we reinsert the elements in should not -// matter. For simplicity and efficiency, we will consider only linear -// reinsertions, which consist of reinserting all elements in the old table -// into the new one by increasing order of index. However we will not be -// starting our reinsertions from index 0 in general. If we start from index -// i, for the purpose of reinsertion we will consider all elements with real -// index j < i to have virtual index n + j. -// -// Our hash generation scheme consists of generating a 64-bit hash and -// truncating the most significant bits. When moving to the new table, we -// simply introduce a new bit to the front of the hash. Therefore, if an -// elements has ideal index i in the old table, it can have one of two ideal -// locations in the new table. If the new bit is 0, then the new ideal index -// is i. If the new bit is 1, then the new ideal index is n + i. Intuitively, -// we are producing two independent tables of size n, and for each element we -// independently choose which table to insert it into with equal probability. -// However the rather than wrapping around themselves on overflowing their -// indexes, the first table overflows into the first, and the first into the -// second. Visually, our new table will look something like: -// -// [yy_xxx_xxxx_xxx|xx_yyy_yyyy_yyy] -// -// Where x's are elements inserted into the first table, y's are elements -// inserted into the second, and _'s are empty sections. We now define a few -// key concepts that we will use later. Note that this is a very abstract -// perspective of the table. A real resized table would be at least half -// empty. -// -// Theorem: A linear robin hood reinsertion from the first ideal element -// produces identical results to a linear naive reinsertion from the same -// element. -// -// FIXME(Gankro, pczarn): review the proof and put it all in a separate README.md -// -// Adaptive early resizing -// ---------------------- -// To protect against degenerate performance scenarios (including DOS attacks), -// the implementation includes an adaptive behavior that can resize the map -// early (before its capacity is exceeded) when suspiciously long probe sequences -// are encountered. -// -// With this algorithm in place it would be possible to turn a CPU attack into -// a memory attack due to the aggressive resizing. To prevent that the -// adaptive behavior only triggers when the map is at least half full. -// This reduces the effectiveness of the algorithm but also makes it completely safe. -// -// The previous safety measure also prevents degenerate interactions with -// really bad quality hash algorithms that can make normal inputs look like a -// DOS attack. -// -const DISPLACEMENT_THRESHOLD: usize = 128; -// -// The threshold of 128 is chosen to minimize the chance of exceeding it. -// In particular, we want that chance to be less than 10^-8 with a load of 90%. -// For displacement, the smallest constant that fits our needs is 90, -// so we round that up to 128. -// -// At a load factor of α, the odds of finding the target bucket after exactly n -// unsuccessful probes[1] are -// -// Pr_α{displacement = n} = -// (1 - α) / α * ∑_{k≥1} e^(-kα) * (kα)^(k+n) / (k + n)! * (1 - kα / (k + n + 1)) -// -// We use this formula to find the probability of triggering the adaptive behavior -// -// Pr_0.909{displacement > 128} = 1.601 * 10^-11 -// -// 1. Alfredo Viola (2005). Distributional analysis of Robin Hood linear probing -// hashing with buckets. - -/// A hash map implemented with linear probing and Robin Hood bucket stealing. -/// -/// By default, `HashMap` uses a hashing algorithm selected to provide -/// resistance against HashDoS attacks. The algorithm is randomly seeded, and a -/// reasonable best-effort is made to generate this seed from a high quality, -/// secure source of randomness provided by the host without blocking the -/// program. Because of this, the randomness of the seed depends on the output -/// quality of the system's random number generator when the seed is created. -/// In particular, seeds generated when the system's entropy pool is abnormally -/// low such as during system boot may be of a lower quality. -/// -/// The default hashing algorithm is currently SipHash 1-3, though this is -/// subject to change at any point in the future. While its performance is very -/// competitive for medium sized keys, other hashing algorithms will outperform -/// it for small keys such as integers as well as large keys such as long -/// strings, though those algorithms will typically *not* protect against -/// attacks such as HashDoS. -/// -/// The hashing algorithm can be replaced on a per-`HashMap` basis using the -/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. Many -/// alternative algorithms are available on crates.io, such as the [`fnv`] crate. -/// -/// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although -/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. -/// If you implement these yourself, it is important that the following -/// property holds: -/// -/// ```text -/// k1 == k2 -> hash(k1) == hash(k2) -/// ``` -/// -/// In other words, if two keys are equal, their hashes must be equal. -/// -/// It is a logic error for a key to be modified in such a way that the key's -/// hash, as determined by the [`Hash`] trait, or its equality, as determined by -/// the [`Eq`] trait, changes while it is in the map. This is normally only -/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. -/// -/// Relevant papers/articles: -/// -/// 1. Pedro Celis. ["Robin Hood Hashing"](https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf) -/// 2. Emmanuel Goossaert. ["Robin Hood -/// hashing"](http://codecapsule.com/2013/11/11/robin-hood-hashing/) -/// 3. Emmanuel Goossaert. ["Robin Hood hashing: backward shift -/// deletion"](http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/) -/// -/// # Examples -/// -/// ``` -/// use std::collections::HashMap; -/// -/// // Type inference lets us omit an explicit type signature (which -/// // would be `HashMap` in this example). -/// let mut book_reviews = HashMap::new(); -/// -/// // Review some books. -/// book_reviews.insert( -/// "Adventures of Huckleberry Finn".to_string(), -/// "My favorite book.".to_string(), -/// ); -/// book_reviews.insert( -/// "Grimms' Fairy Tales".to_string(), -/// "Masterpiece.".to_string(), -/// ); -/// book_reviews.insert( -/// "Pride and Prejudice".to_string(), -/// "Very enjoyable.".to_string(), -/// ); -/// book_reviews.insert( -/// "The Adventures of Sherlock Holmes".to_string(), -/// "Eye lyked it alot.".to_string(), -/// ); -/// -/// // Check for a specific one. -/// // When collections store owned values (String), they can still be -/// // queried using references (&str). -/// if !book_reviews.contains_key("Les Misérables") { -/// println!("We've got {} reviews, but Les Misérables ain't one.", -/// book_reviews.len()); -/// } -/// -/// // oops, this review has a lot of spelling mistakes, let's delete it. -/// book_reviews.remove("The Adventures of Sherlock Holmes"); -/// -/// // Look up the values associated with some keys. -/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; -/// for &book in &to_find { -/// match book_reviews.get(book) { -/// Some(review) => println!("{}: {}", book, review), -/// None => println!("{} is unreviewed.", book) -/// } -/// } -/// -/// // Iterate over everything. -/// for (book, review) in &book_reviews { -/// println!("{}: \"{}\"", book, review); -/// } -/// ``` -/// -/// `HashMap` also implements an [`Entry API`](#method.entry), which allows -/// for more complex methods of getting, setting, updating and removing keys and -/// their values: -/// -/// ``` -/// use std::collections::HashMap; -/// -/// // type inference lets us omit an explicit type signature (which -/// // would be `HashMap<&str, u8>` in this example). -/// let mut player_stats = HashMap::new(); -/// -/// fn random_stat_buff() -> u8 { -/// // could actually return some random value here - let's just return -/// // some fixed value for now -/// 42 -/// } -/// -/// // insert a key only if it doesn't already exist -/// player_stats.entry("health").or_insert(100); -/// -/// // insert a key using a function that provides a new value only if it -/// // doesn't already exist -/// player_stats.entry("defence").or_insert_with(random_stat_buff); -/// -/// // update a key, guarding against the key possibly not being set -/// let stat = player_stats.entry("attack").or_insert(100); -/// *stat += random_stat_buff(); -/// ``` -/// -/// The easiest way to use `HashMap` with a custom type as key is to derive [`Eq`] and [`Hash`]. -/// We must also derive [`PartialEq`]. -/// -/// [`Eq`]: ../../std/cmp/trait.Eq.html -/// [`Hash`]: ../../std/hash/trait.Hash.html -/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`Cell`]: ../../std/cell/struct.Cell.html -/// [`default`]: #method.default -/// [`with_hasher`]: #method.with_hasher -/// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher -/// [`fnv`]: https://crates.io/crates/fnv -/// -/// ``` -/// use std::collections::HashMap; -/// -/// #[derive(Hash, Eq, PartialEq, Debug)] -/// struct Viking { -/// name: String, -/// country: String, -/// } -/// -/// impl Viking { -/// /// Create a new Viking. -/// fn new(name: &str, country: &str) -> Viking { -/// Viking { name: name.to_string(), country: country.to_string() } -/// } -/// } -/// -/// // Use a HashMap to store the vikings' health points. -/// let mut vikings = HashMap::new(); -/// -/// vikings.insert(Viking::new("Einar", "Norway"), 25); -/// vikings.insert(Viking::new("Olaf", "Denmark"), 24); -/// vikings.insert(Viking::new("Harald", "Iceland"), 12); -/// -/// // Use derived implementation to print the status of the vikings. -/// for (viking, health) in &vikings { -/// println!("{:?} has {} hp", viking, health); -/// } -/// ``` -/// -/// A `HashMap` with fixed list of elements can be initialized from an array: -/// -/// ``` -/// use std::collections::HashMap; -/// -/// fn main() { -/// let timber_resources: HashMap<&str, i32> = -/// [("Norway", 100), -/// ("Denmark", 50), -/// ("Iceland", 10)] -/// .iter().cloned().collect(); -/// // use the values stored in map -/// } -/// ``` - -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct HashMap { - // All hashes are keyed on these values, to prevent hash collision attacks. - hash_builder: S, - - table: RawTable, - - resize_policy: DefaultResizePolicy, -} - -/// Search for a pre-hashed key. -/// If you don't already know the hash, use search or search_mut instead -#[inline] -fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalEntry - where M: Deref>, - F: FnMut(&K) -> bool -{ - // This is the only function where capacity can be zero. To avoid - // undefined behavior when Bucket::new gets the raw bucket in this - // case, immediately return the appropriate search result. - if table.capacity() == 0 { - return InternalEntry::TableIsEmpty; - } - - search_hashed_nonempty(table, hash, is_match) -} - -/// Search for a pre-hashed key when the hash map is known to be non-empty. -#[inline] -fn search_hashed_nonempty(table: M, hash: SafeHash, mut is_match: F) - -> InternalEntry - where M: Deref>, - F: FnMut(&K) -> bool -{ - // Do not check the capacity as an extra branch could slow the lookup. - - let size = table.size(); - let mut probe = Bucket::new(table, hash); - let mut displacement = 0; - - loop { - let full = match probe.peek() { - Empty(bucket) => { - // Found a hole! - return InternalEntry::Vacant { - hash, - elem: NoElem(bucket, displacement), - }; - } - Full(bucket) => bucket, - }; - - let probe_displacement = full.displacement(); - - if probe_displacement < displacement { - // Found a luckier bucket than me. - // We can finish the search early if we hit any bucket - // with a lower distance to initial bucket than we've probed. - return InternalEntry::Vacant { - hash, - elem: NeqElem(full, probe_displacement), - }; - } - - // If the hash doesn't match, it can't be this one.. - if hash == full.hash() { - // If the key doesn't match, it can't be this one.. - if is_match(full.read().0) { - return InternalEntry::Occupied { elem: full }; - } - } - displacement += 1; - probe = full.next(); - debug_assert!(displacement <= size); - } -} - -fn pop_internal(starting_bucket: FullBucketMut) - -> (K, V, &mut RawTable) -{ - let (empty, retkey, retval) = starting_bucket.take(); - let mut gap = match empty.gap_peek() { - Ok(b) => b, - Err(b) => return (retkey, retval, b.into_table()), - }; - - while gap.full().displacement() != 0 { - gap = match gap.shift() { - Ok(b) => b, - Err(b) => { - return (retkey, retval, b.into_table()); - }, - }; - } - - // Now we've done all our shifting. Return the value we grabbed earlier. - (retkey, retval, gap.into_table()) -} - -/// Perform robin hood bucket stealing at the given `bucket`. You must -/// also pass that bucket's displacement so we don't have to recalculate it. -/// -/// `hash`, `key`, and `val` are the elements to "robin hood" into the hashtable. -fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, - mut displacement: usize, - mut hash: SafeHash, - mut key: K, - mut val: V) - -> FullBucketMut<'a, K, V> { - let size = bucket.table().size(); - let raw_capacity = bucket.table().capacity(); - // There can be at most `size - dib` buckets to displace, because - // in the worst case, there are `size` elements and we already are - // `displacement` buckets away from the initial one. - let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity; - // Save the *starting point*. - let mut bucket = bucket.stash(); - - loop { - let (old_hash, old_key, old_val) = bucket.replace(hash, key, val); - hash = old_hash; - key = old_key; - val = old_val; - - loop { - displacement += 1; - let probe = bucket.next(); - debug_assert!(probe.index() != idx_end); - - let full_bucket = match probe.peek() { - Empty(bucket) => { - // Found a hole! - let bucket = bucket.put(hash, key, val); - // Now that it's stolen, just read the value's pointer - // right out of the table! Go back to the *starting point*. - // - // This use of `into_table` is misleading. It turns the - // bucket, which is a FullBucket on top of a - // FullBucketMut, into just one FullBucketMut. The "table" - // refers to the inner FullBucketMut in this context. - return bucket.into_table(); - } - Full(bucket) => bucket, - }; - - let probe_displacement = full_bucket.displacement(); - - bucket = full_bucket; - - // Robin hood! Steal the spot. - if probe_displacement < displacement { - displacement = probe_displacement; - break; - } - } - } -} - -impl HashMap - where K: Eq + Hash, - S: BuildHasher -{ - fn make_hash(&self, x: &X) -> SafeHash - where X: Hash - { - table::make_hash(&self.hash_builder, x) - } - - /// Search for a key, yielding the index if it's found in the hashtable. - /// If you already have the hash for the key lying around, or if you need an - /// InternalEntry, use search_hashed or search_hashed_nonempty. - #[inline] - fn search<'a, Q: ?Sized>(&'a self, q: &Q) - -> Option>> - where K: Borrow, - Q: Eq + Hash - { - if self.is_empty() { - return None; - } - - let hash = self.make_hash(q); - search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) - .into_occupied_bucket() - } - - #[inline] - fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) - -> Option>> - where K: Borrow, - Q: Eq + Hash - { - if self.is_empty() { - return None; - } - - let hash = self.make_hash(q); - search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) - .into_occupied_bucket() - } - - // The caller should ensure that invariants by Robin Hood Hashing hold - // and that there's space in the underlying table. - fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { - let mut buckets = Bucket::new(&mut self.table, hash); - let start_index = buckets.index(); - - loop { - // We don't need to compare hashes for value swap. - // Not even DIBs for Robin Hood. - buckets = match buckets.peek() { - Empty(empty) => { - empty.put(hash, k, v); - return; - } - Full(b) => b.into_bucket(), - }; - buckets.next(); - debug_assert!(buckets.index() != start_index); - } - } -} - -impl HashMap { - /// Creates an empty `HashMap`. - /// - /// The hash map is initially created with a capacity of 0, so it will not allocate until it - /// is first inserted into. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// let mut map: HashMap<&str, i32> = HashMap::new(); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> HashMap { - Default::default() - } - - /// Creates an empty `HashMap` with the specified capacity. - /// - /// The hash map will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash map will not allocate. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize) -> HashMap { - HashMap::with_capacity_and_hasher(capacity, Default::default()) - } -} - -impl HashMap - where K: Eq + Hash, - S: BuildHasher -{ - /// Creates an empty `HashMap` which will use the given hash builder to hash - /// keys. - /// - /// The created map has the default initial capacity. - /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::RandomState; - /// - /// let s = RandomState::new(); - /// let mut map = HashMap::with_hasher(s); - /// map.insert(1, 2); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_hasher(hash_builder: S) -> HashMap { - HashMap { - hash_builder, - resize_policy: DefaultResizePolicy::new(), - table: RawTable::new(0), - } - } - - /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` - /// to hash the keys. - /// - /// The hash map will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash map will not allocate. - /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::RandomState; - /// - /// let s = RandomState::new(); - /// let mut map = HashMap::with_capacity_and_hasher(10, s); - /// map.insert(1, 2); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { - let resize_policy = DefaultResizePolicy::new(); - let raw_cap = resize_policy.raw_capacity(capacity); - HashMap { - hash_builder, - resize_policy, - table: RawTable::new(raw_cap), - } - } - - /// Returns a reference to the map's [`BuildHasher`]. - /// - /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::RandomState; - /// - /// let hasher = RandomState::new(); - /// let map: HashMap = HashMap::with_hasher(hasher); - /// let hasher: &RandomState = map.hasher(); - /// ``` - #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] - pub fn hasher(&self) -> &S { - &self.hash_builder - } - - /// Returns the number of elements the map can hold without reallocating. - /// - /// This number is a lower bound; the `HashMap` might be able to hold - /// more, but is guaranteed to be able to hold at least this many. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// let map: HashMap = HashMap::with_capacity(100); - /// assert!(map.capacity() >= 100); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn capacity(&self) -> usize { - self.resize_policy.capacity(self.raw_capacity()) - } - - /// Returns the hash map's raw capacity. - #[inline] - fn raw_capacity(&self) -> usize { - self.table.capacity() - } - - /// Reserves capacity for at least `additional` more elements to be inserted - /// in the `HashMap`. The collection may reserve more space to avoid - /// frequent reallocations. - /// - /// # Panics - /// - /// Panics if the new allocation size overflows [`usize`]. - /// - /// [`usize`]: ../../std/primitive.usize.html - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// let mut map: HashMap<&str, i32> = HashMap::new(); - /// map.reserve(10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn reserve(&mut self, additional: usize) { - match self.reserve_internal(additional, Infallible) { - Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => unreachable!(), - Ok(()) => { /* yay */ } - } - } - - /// Tries to reserve capacity for at least `additional` more elements to be inserted - /// in the given `HashMap`. The collection may reserve more space to avoid - /// frequent reallocations. - /// - /// # Errors - /// - /// If the capacity overflows, or the allocator reports a failure, then an error - /// is returned. - /// - /// # Examples - /// - /// ``` - /// #![feature(try_reserve)] - /// use std::collections::HashMap; - /// let mut map: HashMap<&str, isize> = HashMap::new(); - /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); - /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { - self.reserve_internal(additional, Fallible) - } - - fn reserve_internal(&mut self, additional: usize, fallibility: Fallibility) - -> Result<(), CollectionAllocErr> { - - let remaining = self.capacity() - self.len(); // this can't overflow - if remaining < additional { - let min_cap = self.len() - .checked_add(additional) - .ok_or(CollectionAllocErr::CapacityOverflow)?; - let raw_cap = self.resize_policy.try_raw_capacity(min_cap)?; - self.try_resize(raw_cap, fallibility)?; - } else if self.table.tag() && remaining <= self.len() { - // Probe sequence is too long and table is half full, - // resize early to reduce probing length. - let new_capacity = self.table.capacity() * 2; - self.try_resize(new_capacity, fallibility)?; - } - Ok(()) - } - - /// Resizes the internal vectors to a new capacity. It's your - /// responsibility to: - /// 1) Ensure `new_raw_cap` is enough for all the elements, accounting - /// for the load factor. - /// 2) Ensure `new_raw_cap` is a power of two or zero. - #[inline(never)] - #[cold] - fn try_resize( - &mut self, - new_raw_cap: usize, - fallibility: Fallibility, - ) -> Result<(), CollectionAllocErr> { - assert!(self.table.size() <= new_raw_cap); - assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0); - - let mut old_table = replace( - &mut self.table, - match fallibility { - Infallible => RawTable::new(new_raw_cap), - Fallible => RawTable::try_new(new_raw_cap)?, - } - ); - let old_size = old_table.size(); - - if old_table.size() == 0 { - return Ok(()); - } - - let mut bucket = Bucket::head_bucket(&mut old_table); - - // This is how the buckets might be laid out in memory: - // ($ marks an initialized bucket) - // ________________ - // |$$$_$$$$$$_$$$$$| - // - // But we've skipped the entire initial cluster of buckets - // and will continue iteration in this order: - // ________________ - // |$$$$$$_$$$$$ - // ^ wrap around once end is reached - // ________________ - // $$$_____________| - // ^ exit once table.size == 0 - loop { - bucket = match bucket.peek() { - Full(bucket) => { - let h = bucket.hash(); - let (b, k, v) = bucket.take(); - self.insert_hashed_ordered(h, k, v); - if b.table().size() == 0 { - break; - } - b.into_bucket() - } - Empty(b) => b.into_bucket(), - }; - bucket.next(); - } - - assert_eq!(self.table.size(), old_size); - Ok(()) - } - - /// Shrinks the capacity of the map as much as possible. It will drop - /// down as much as possible while maintaining the internal rules - /// and possibly leaving some space in accordance with the resize policy. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map: HashMap = HashMap::with_capacity(100); - /// map.insert(1, 2); - /// map.insert(3, 4); - /// assert!(map.capacity() >= 100); - /// map.shrink_to_fit(); - /// assert!(map.capacity() >= 2); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn shrink_to_fit(&mut self) { - let new_raw_cap = self.resize_policy.raw_capacity(self.len()); - if self.raw_capacity() != new_raw_cap { - let old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); - let old_size = old_table.size(); - - // Shrink the table. Naive algorithm for resizing: - for (h, k, v) in old_table.into_iter() { - self.insert_hashed_nocheck(h, k, v); - } - - debug_assert_eq!(self.table.size(), old_size); - } - } - - /// Shrinks the capacity of the map with a lower limit. It will drop - /// down no lower than the supplied limit while maintaining the internal rules - /// and possibly leaving some space in accordance with the resize policy. - /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. - /// - /// # Examples - /// - /// ``` - /// #![feature(shrink_to)] - /// use std::collections::HashMap; - /// - /// let mut map: HashMap = HashMap::with_capacity(100); - /// map.insert(1, 2); - /// map.insert(3, 4); - /// assert!(map.capacity() >= 100); - /// map.shrink_to(10); - /// assert!(map.capacity() >= 10); - /// map.shrink_to(0); - /// assert!(map.capacity() >= 2); - /// ``` - #[unstable(feature = "shrink_to", reason = "new API", issue="0")] - pub fn shrink_to(&mut self, min_capacity: usize) { - assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity"); - - let new_raw_cap = self.resize_policy.raw_capacity(max(self.len(), min_capacity)); - if self.raw_capacity() != new_raw_cap { - let old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); - let old_size = old_table.size(); - - // Shrink the table. Naive algorithm for resizing: - for (h, k, v) in old_table.into_iter() { - self.insert_hashed_nocheck(h, k, v); - } - - debug_assert_eq!(self.table.size(), old_size); - } - } - - /// Insert a pre-hashed key-value pair, without first checking - /// that there's enough room in the buckets. Returns a reference to the - /// newly insert value. - /// - /// If the key already exists, the hashtable will be returned untouched - /// and a reference to the existing element will be returned. - fn insert_hashed_nocheck(&mut self, hash: SafeHash, k: K, v: V) -> Option { - let entry = search_hashed(&mut self.table, hash, |key| *key == k).into_entry(k); - match entry { - Some(Occupied(mut elem)) => Some(elem.insert(v)), - Some(Vacant(elem)) => { - elem.insert(v); - None - } - None => unreachable!(), - } - } - - /// An iterator visiting all keys in arbitrary order. - /// The iterator element type is `&'a K`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert("a", 1); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// for key in map.keys() { - /// println!("{}", key); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn keys(&self) -> Keys { - Keys { inner: self.iter() } - } - - /// An iterator visiting all values in arbitrary order. - /// The iterator element type is `&'a V`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert("a", 1); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// for val in map.values() { - /// println!("{}", val); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn values(&self) -> Values { - Values { inner: self.iter() } - } - - /// An iterator visiting all values mutably in arbitrary order. - /// The iterator element type is `&'a mut V`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// - /// map.insert("a", 1); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// for val in map.values_mut() { - /// *val = *val + 10; - /// } - /// - /// for val in map.values() { - /// println!("{}", val); - /// } - /// ``` - #[stable(feature = "map_values_mut", since = "1.10.0")] - pub fn values_mut(&mut self) -> ValuesMut { - ValuesMut { inner: self.iter_mut() } - } - - /// An iterator visiting all key-value pairs in arbitrary order. - /// The iterator element type is `(&'a K, &'a V)`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert("a", 1); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// for (key, val) in map.iter() { - /// println!("key: {} val: {}", key, val); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { - Iter { inner: self.table.iter() } - } - - /// An iterator visiting all key-value pairs in arbitrary order, - /// with mutable references to the values. - /// The iterator element type is `(&'a K, &'a mut V)`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert("a", 1); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// // Update all values - /// for (_, val) in map.iter_mut() { - /// *val *= 2; - /// } - /// - /// for (key, val) in &map { - /// println!("key: {} val: {}", key, val); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut { - IterMut { inner: self.table.iter_mut() } - } - - /// Gets the given key's corresponding entry in the map for in-place manipulation. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut letters = HashMap::new(); - /// - /// for ch in "a short treatise on fungi".chars() { - /// let counter = letters.entry(ch).or_insert(0); - /// *counter += 1; - /// } - /// - /// assert_eq!(letters[&'s'], 2); - /// assert_eq!(letters[&'t'], 3); - /// assert_eq!(letters[&'u'], 1); - /// assert_eq!(letters.get(&'y'), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn entry(&mut self, key: K) -> Entry { - // Gotta resize now. - self.reserve(1); - let hash = self.make_hash(&key); - search_hashed(&mut self.table, hash, |q| q.eq(&key)) - .into_entry(key).expect("unreachable") - } - - /// Returns the number of elements in the map. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut a = HashMap::new(); - /// assert_eq!(a.len(), 0); - /// a.insert(1, "a"); - /// assert_eq!(a.len(), 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> usize { - self.table.size() - } - - /// Returns true if the map contains no elements. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut a = HashMap::new(); - /// assert!(a.is_empty()); - /// a.insert(1, "a"); - /// assert!(!a.is_empty()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Clears the map, returning all key-value pairs as an iterator. Keeps the - /// allocated memory for reuse. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut a = HashMap::new(); - /// a.insert(1, "a"); - /// a.insert(2, "b"); - /// - /// for (k, v) in a.drain().take(1) { - /// assert!(k == 1 || k == 2); - /// assert!(v == "a" || v == "b"); - /// } - /// - /// assert!(a.is_empty()); - /// ``` - #[inline] - #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self) -> Drain { - Drain { inner: self.table.drain() } - } - - /// Clears the map, removing all key-value pairs. Keeps the allocated memory - /// for reuse. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut a = HashMap::new(); - /// a.insert(1, "a"); - /// a.clear(); - /// assert!(a.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn clear(&mut self) { - self.drain(); - } - - /// Returns a reference to the value corresponding to the key. - /// - /// The key may be any borrowed form of the map's key type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the key type. - /// - /// [`Eq`]: ../../std/cmp/trait.Eq.html - /// [`Hash`]: ../../std/hash/trait.Hash.html - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.get(&1), Some(&"a")); - /// assert_eq!(map.get(&2), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn get(&self, k: &Q) -> Option<&V> - where K: Borrow, - Q: Hash + Eq - { - self.search(k).map(|bucket| bucket.into_refs().1) - } - - /// Returns the key-value pair corresponding to the supplied key. - /// - /// The supplied key may be any borrowed form of the map's key type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the key type. - /// - /// [`Eq`]: ../../std/cmp/trait.Eq.html - /// [`Hash`]: ../../std/hash/trait.Hash.html - /// - /// # Examples - /// - /// ``` - /// #![feature(map_get_key_value)] - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); - /// assert_eq!(map.get_key_value(&2), None); - /// ``` - #[unstable(feature = "map_get_key_value", issue = "49347")] - pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> - where K: Borrow, - Q: Hash + Eq - { - self.search(k).map(|bucket| bucket.into_refs()) - } - - /// Returns true if the map contains a value for the specified key. - /// - /// The key may be any borrowed form of the map's key type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the key type. - /// - /// [`Eq`]: ../../std/cmp/trait.Eq.html - /// [`Hash`]: ../../std/hash/trait.Hash.html - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.contains_key(&1), true); - /// assert_eq!(map.contains_key(&2), false); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn contains_key(&self, k: &Q) -> bool - where K: Borrow, - Q: Hash + Eq - { - self.search(k).is_some() - } - - /// Returns a mutable reference to the value corresponding to the key. - /// - /// The key may be any borrowed form of the map's key type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the key type. - /// - /// [`Eq`]: ../../std/cmp/trait.Eq.html - /// [`Hash`]: ../../std/hash/trait.Hash.html - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert(1, "a"); - /// if let Some(x) = map.get_mut(&1) { - /// *x = "b"; - /// } - /// assert_eq!(map[&1], "b"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> - where K: Borrow, - Q: Hash + Eq - { - self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) - } - - /// Inserts a key-value pair into the map. - /// - /// If the map did not have this key present, [`None`] is returned. - /// - /// If the map did have this key present, the value is updated, and the old - /// value is returned. The key is not updated, though; this matters for - /// types that can be `==` without being identical. See the [module-level - /// documentation] for more. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [module-level documentation]: index.html#insert-and-complex-keys - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// assert_eq!(map.insert(37, "a"), None); - /// assert_eq!(map.is_empty(), false); - /// - /// map.insert(37, "b"); - /// assert_eq!(map.insert(37, "c"), Some("b")); - /// assert_eq!(map[&37], "c"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(&mut self, k: K, v: V) -> Option { - let hash = self.make_hash(&k); - self.reserve(1); - self.insert_hashed_nocheck(hash, k, v) - } - - /// Removes a key from the map, returning the value at the key if the key - /// was previously in the map. - /// - /// The key may be any borrowed form of the map's key type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the key type. - /// - /// [`Eq`]: ../../std/cmp/trait.Eq.html - /// [`Hash`]: ../../std/hash/trait.Hash.html - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.remove(&1), Some("a")); - /// assert_eq!(map.remove(&1), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(&mut self, k: &Q) -> Option - where K: Borrow, - Q: Hash + Eq - { - self.search_mut(k).map(|bucket| pop_internal(bucket).1) - } - - /// Removes a key from the map, returning the stored key and value if the - /// key was previously in the map. - /// - /// The key may be any borrowed form of the map's key type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the key type. - /// - /// [`Eq`]: ../../std/cmp/trait.Eq.html - /// [`Hash`]: ../../std/hash/trait.Hash.html - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// # fn main() { - /// let mut map = HashMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.remove_entry(&1), Some((1, "a"))); - /// assert_eq!(map.remove(&1), None); - /// # } - /// ``` - #[stable(feature = "hash_map_remove_entry", since = "1.27.0")] - pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> - where K: Borrow, - Q: Hash + Eq - { - self.search_mut(k) - .map(|bucket| { - let (k, v, _) = pop_internal(bucket); - (k, v) - }) - } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all pairs `(k, v)` such that `f(&k,&mut v)` returns `false`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); - /// map.retain(|&k, _| k % 2 == 0); - /// assert_eq!(map.len(), 4); - /// ``` - #[stable(feature = "retain_hash_collection", since = "1.18.0")] - pub fn retain(&mut self, mut f: F) - where F: FnMut(&K, &mut V) -> bool - { - if self.table.size() == 0 { - return; - } - let mut elems_left = self.table.size(); - let mut bucket = Bucket::head_bucket(&mut self.table); - bucket.prev(); - let start_index = bucket.index(); - while elems_left != 0 { - bucket = match bucket.peek() { - Full(mut full) => { - elems_left -= 1; - let should_remove = { - let (k, v) = full.read_mut(); - !f(k, v) - }; - if should_remove { - let prev_raw = full.raw(); - let (_, _, t) = pop_internal(full); - Bucket::new_from(prev_raw, t) - } else { - full.into_bucket() - } - }, - Empty(b) => { - b.into_bucket() - } - }; - bucket.prev(); // reverse iteration - debug_assert!(elems_left == 0 || bucket.index() != start_index); - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for HashMap - where K: Eq + Hash, - V: PartialEq, - S: BuildHasher -{ - fn eq(&self, other: &HashMap) -> bool { - if self.len() != other.len() { - return false; - } - - self.iter().all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for HashMap - where K: Eq + Hash, - V: Eq, - S: BuildHasher -{ -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Debug for HashMap - where K: Eq + Hash + Debug, - V: Debug, - S: BuildHasher -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_map().entries(self.iter()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for HashMap - where K: Eq + Hash, - S: BuildHasher + Default -{ - /// Creates an empty `HashMap`, with the `Default` value for the hasher. - fn default() -> HashMap { - HashMap::with_hasher(Default::default()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap - where K: Eq + Hash + Borrow, - Q: Eq + Hash, - S: BuildHasher -{ - type Output = V; - - /// Returns a reference to the value corresponding to the supplied key. - /// - /// # Panics - /// - /// Panics if the key is not present in the `HashMap`. - #[inline] - fn index(&self, key: &Q) -> &V { - self.get(key).expect("no entry found for key") - } -} - -/// An iterator over the entries of a `HashMap`. -/// -/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its -/// documentation for more. -/// -/// [`iter`]: struct.HashMap.html#method.iter -/// [`HashMap`]: struct.HashMap.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, K: 'a, V: 'a> { - inner: table::Iter<'a, K, V>, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Clone for Iter<'a, K, V> { - fn clone(&self) -> Iter<'a, K, V> { - Iter { inner: self.inner.clone() } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, K: Debug, V: Debug> fmt::Debug for Iter<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.clone()) - .finish() - } -} - -/// A mutable iterator over the entries of a `HashMap`. -/// -/// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its -/// documentation for more. -/// -/// [`iter_mut`]: struct.HashMap.html#method.iter_mut -/// [`HashMap`]: struct.HashMap.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IterMut<'a, K: 'a, V: 'a> { - inner: table::IterMut<'a, K, V>, -} - -/// An owning iterator over the entries of a `HashMap`. -/// -/// This `struct` is created by the [`into_iter`] method on [`HashMap`][`HashMap`] -/// (provided by the `IntoIterator` trait). See its documentation for more. -/// -/// [`into_iter`]: struct.HashMap.html#method.into_iter -/// [`HashMap`]: struct.HashMap.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter { - pub(super) inner: table::IntoIter, -} - -/// An iterator over the keys of a `HashMap`. -/// -/// This `struct` is created by the [`keys`] method on [`HashMap`]. See its -/// documentation for more. -/// -/// [`keys`]: struct.HashMap.html#method.keys -/// [`HashMap`]: struct.HashMap.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Keys<'a, K: 'a, V: 'a> { - inner: Iter<'a, K, V>, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Clone for Keys<'a, K, V> { - fn clone(&self) -> Keys<'a, K, V> { - Keys { inner: self.inner.clone() } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, K: Debug, V> fmt::Debug for Keys<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.clone()) - .finish() - } -} - -/// An iterator over the values of a `HashMap`. -/// -/// This `struct` is created by the [`values`] method on [`HashMap`]. See its -/// documentation for more. -/// -/// [`values`]: struct.HashMap.html#method.values -/// [`HashMap`]: struct.HashMap.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Values<'a, K: 'a, V: 'a> { - inner: Iter<'a, K, V>, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Clone for Values<'a, K, V> { - fn clone(&self) -> Values<'a, K, V> { - Values { inner: self.inner.clone() } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, K, V: Debug> fmt::Debug for Values<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.clone()) - .finish() - } -} - -/// A draining iterator over the entries of a `HashMap`. -/// -/// This `struct` is created by the [`drain`] method on [`HashMap`]. See its -/// documentation for more. -/// -/// [`drain`]: struct.HashMap.html#method.drain -/// [`HashMap`]: struct.HashMap.html -#[stable(feature = "drain", since = "1.6.0")] -pub struct Drain<'a, K: 'a, V: 'a> { - pub(super) inner: table::Drain<'a, K, V>, -} - -/// A mutable iterator over the values of a `HashMap`. -/// -/// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its -/// documentation for more. -/// -/// [`values_mut`]: struct.HashMap.html#method.values_mut -/// [`HashMap`]: struct.HashMap.html -#[stable(feature = "map_values_mut", since = "1.10.0")] -pub struct ValuesMut<'a, K: 'a, V: 'a> { - inner: IterMut<'a, K, V>, -} - -enum InternalEntry { - Occupied { elem: FullBucket }, - Vacant { - hash: SafeHash, - elem: VacantEntryState, - }, - TableIsEmpty, -} - -impl InternalEntry { - #[inline] - fn into_occupied_bucket(self) -> Option> { - match self { - InternalEntry::Occupied { elem } => Some(elem), - _ => None, - } - } -} - -impl<'a, K, V> InternalEntry> { - #[inline] - fn into_entry(self, key: K) -> Option> { - match self { - InternalEntry::Occupied { elem } => { - Some(Occupied(OccupiedEntry { - key: Some(key), - elem, - })) - } - InternalEntry::Vacant { hash, elem } => { - Some(Vacant(VacantEntry { - hash, - key, - elem, - })) - } - InternalEntry::TableIsEmpty => None, - } - } -} - -/// A view into a single entry in a map, which may either be vacant or occupied. -/// -/// This `enum` is constructed from the [`entry`] method on [`HashMap`]. -/// -/// [`HashMap`]: struct.HashMap.html -/// [`entry`]: struct.HashMap.html#method.entry -#[stable(feature = "rust1", since = "1.0.0")] -pub enum Entry<'a, K: 'a, V: 'a> { - /// An occupied entry. - #[stable(feature = "rust1", since = "1.0.0")] - Occupied(#[stable(feature = "rust1", since = "1.0.0")] - OccupiedEntry<'a, K, V>), - - /// A vacant entry. - #[stable(feature = "rust1", since = "1.0.0")] - Vacant(#[stable(feature = "rust1", since = "1.0.0")] - VacantEntry<'a, K, V>), -} - -#[stable(feature= "debug_hash_map", since = "1.12.0")] -impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Vacant(ref v) => { - f.debug_tuple("Entry") - .field(v) - .finish() - } - Occupied(ref o) => { - f.debug_tuple("Entry") - .field(o) - .finish() - } - } - } -} - -/// A view into an occupied entry in a `HashMap`. -/// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct OccupiedEntry<'a, K: 'a, V: 'a> { - key: Option, - elem: FullBucket>, -} - -#[stable(feature= "debug_hash_map", since = "1.12.0")] -impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("OccupiedEntry") - .field("key", self.key()) - .field("value", self.get()) - .finish() - } -} - -/// A view into a vacant entry in a `HashMap`. -/// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct VacantEntry<'a, K: 'a, V: 'a> { - hash: SafeHash, - key: K, - elem: VacantEntryState>, -} - -#[stable(feature= "debug_hash_map", since = "1.12.0")] -impl<'a, K: 'a + Debug, V: 'a> Debug for VacantEntry<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("VacantEntry") - .field(self.key()) - .finish() - } -} - -/// Possible states of a VacantEntry. -enum VacantEntryState { - /// The index is occupied, but the key to insert has precedence, - /// and will kick the current one out on insertion. - NeqElem(FullBucket, usize), - /// The index is genuinely vacant. - NoElem(EmptyBucket, usize), -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, S> IntoIterator for &'a HashMap - where K: Eq + Hash, - S: BuildHasher -{ - type Item = (&'a K, &'a V); - type IntoIter = Iter<'a, K, V>; - - fn into_iter(self) -> Iter<'a, K, V> { - self.iter() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, S> IntoIterator for &'a mut HashMap - where K: Eq + Hash, - S: BuildHasher -{ - type Item = (&'a K, &'a mut V); - type IntoIter = IterMut<'a, K, V>; - - fn into_iter(self) -> IterMut<'a, K, V> { - self.iter_mut() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for HashMap - where K: Eq + Hash, - S: BuildHasher -{ - type Item = (K, V); - type IntoIter = IntoIter; - - /// Creates a consuming iterator, that is, one that moves each key-value - /// pair out of the map in arbitrary order. The map cannot be used after - /// calling this. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert("a", 1); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// // Not possible with .iter() - /// let vec: Vec<(&str, i32)> = map.into_iter().collect(); - /// ``` - fn into_iter(self) -> IntoIter { - IntoIter { inner: self.table.into_iter() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Iterator for Iter<'a, K, V> { - type Item = (&'a K, &'a V); - - #[inline] - fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.inner.next() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Iterator for IterMut<'a, K, V> { - type Item = (&'a K, &'a mut V); - - #[inline] - fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - self.inner.next() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, K, V> fmt::Debug for IterMut<'a, K, V> - where K: fmt::Debug, - V: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.inner.iter()) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { - type Item = (K, V); - - #[inline] - fn next(&mut self) -> Option<(K, V)> { - self.inner.next().map(|(_, k, v)| (k, v)) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.inner.iter()) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Iterator for Keys<'a, K, V> { - type Item = &'a K; - - #[inline] - fn next(&mut self) -> Option<(&'a K)> { - self.inner.next().map(|(k, _)| k) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Iterator for Values<'a, K, V> { - type Item = &'a V; - - #[inline] - fn next(&mut self) -> Option<(&'a V)> { - self.inner.next().map(|(_, v)| v) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Values<'a, K, V> {} - -#[stable(feature = "map_values_mut", since = "1.10.0")] -impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { - type Item = &'a mut V; - - #[inline] - fn next(&mut self) -> Option<(&'a mut V)> { - self.inner.next().map(|(_, v)| v) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} -#[stable(feature = "map_values_mut", since = "1.10.0")] -impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, K, V> fmt::Debug for ValuesMut<'a, K, V> - where K: fmt::Debug, - V: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.inner.inner.iter()) - .finish() - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl<'a, K, V> Iterator for Drain<'a, K, V> { - type Item = (K, V); - - #[inline] - fn next(&mut self) -> Option<(K, V)> { - self.inner.next().map(|(_, k, v)| (k, v)) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} -#[stable(feature = "drain", since = "1.6.0")] -impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, K, V> fmt::Debug for Drain<'a, K, V> - where K: fmt::Debug, - V: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.inner.iter()) - .finish() - } -} - -impl<'a, K, V> Entry<'a, K, V> { - #[stable(feature = "rust1", since = "1.0.0")] - /// Ensures a value is in the entry by inserting the default if empty, and returns - /// a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// - /// *map.entry("poneyland").or_insert(12) += 10; - /// assert_eq!(map["poneyland"], 22); - /// ``` - pub fn or_insert(self, default: V) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(default), - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - /// Ensures a value is in the entry by inserting the result of the default function if empty, - /// and returns a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map: HashMap<&str, String> = HashMap::new(); - /// let s = "hoho".to_string(); - /// - /// map.entry("poneyland").or_insert_with(|| s); - /// - /// assert_eq!(map["poneyland"], "hoho".to_string()); - /// ``` - pub fn or_insert_with V>(self, default: F) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(default()), - } - } - - /// Returns a reference to this entry's key. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - match *self { - Occupied(ref entry) => entry.key(), - Vacant(ref entry) => entry.key(), - } - } - - /// Provides in-place mutable access to an occupied entry before any - /// potential inserts into the map. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// - /// map.entry("poneyland") - /// .and_modify(|e| { *e += 1 }) - /// .or_insert(42); - /// assert_eq!(map["poneyland"], 42); - /// - /// map.entry("poneyland") - /// .and_modify(|e| { *e += 1 }) - /// .or_insert(42); - /// assert_eq!(map["poneyland"], 43); - /// ``` - #[stable(feature = "entry_and_modify", since = "1.26.0")] - pub fn and_modify(self, f: F) -> Self - where F: FnOnce(&mut V) - { - match self { - Occupied(mut entry) => { - f(entry.get_mut()); - Occupied(entry) - }, - Vacant(entry) => Vacant(entry), - } - } - -} - -impl<'a, K, V: Default> Entry<'a, K, V> { - #[stable(feature = "entry_or_default", since = "1.28.0")] - /// Ensures a value is in the entry by inserting the default value if empty, - /// and returns a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// # fn main() { - /// use std::collections::HashMap; - /// - /// let mut map: HashMap<&str, Option> = HashMap::new(); - /// map.entry("poneyland").or_default(); - /// - /// assert_eq!(map["poneyland"], None); - /// # } - /// ``` - pub fn or_default(self) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(Default::default()), - } - } -} - -impl<'a, K, V> OccupiedEntry<'a, K, V> { - /// Gets a reference to the key in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// map.entry("poneyland").or_insert(12); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - self.elem.read().0 - } - - /// Take the ownership of the key and value from the map. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::Entry; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// // We delete the entry from the map. - /// o.remove_entry(); - /// } - /// - /// assert_eq!(map.contains_key("poneyland"), false); - /// ``` - #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] - pub fn remove_entry(self) -> (K, V) { - let (k, v, _) = pop_internal(self.elem); - (k, v) - } - - /// Gets a reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::Entry; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// assert_eq!(o.get(), &12); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self) -> &V { - self.elem.read().1 - } - - /// Gets a mutable reference to the value in the entry. - /// - /// If you need a reference to the `OccupiedEntry` which may outlive the - /// destruction of the `Entry` value, see [`into_mut`]. - /// - /// [`into_mut`]: #method.into_mut - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::Entry; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// if let Entry::Occupied(mut o) = map.entry("poneyland") { - /// *o.get_mut() += 10; - /// assert_eq!(*o.get(), 22); - /// - /// // We can use the same Entry multiple times. - /// *o.get_mut() += 2; - /// } - /// - /// assert_eq!(map["poneyland"], 24); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut V { - self.elem.read_mut().1 - } - - /// Converts the OccupiedEntry into a mutable reference to the value in the entry - /// with a lifetime bound to the map itself. - /// - /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. - /// - /// [`get_mut`]: #method.get_mut - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::Entry; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// *o.into_mut() += 10; - /// } - /// - /// assert_eq!(map["poneyland"], 22); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_mut(self) -> &'a mut V { - self.elem.into_mut_refs().1 - } - - /// Sets the value of the entry, and returns the entry's old value. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::Entry; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(mut o) = map.entry("poneyland") { - /// assert_eq!(o.insert(15), 12); - /// } - /// - /// assert_eq!(map["poneyland"], 15); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(&mut self, mut value: V) -> V { - let old_value = self.get_mut(); - mem::swap(&mut value, old_value); - value - } - - /// Takes the value out of the entry, and returns it. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::Entry; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// assert_eq!(o.remove(), 12); - /// } - /// - /// assert_eq!(map.contains_key("poneyland"), false); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(self) -> V { - pop_internal(self.elem).1 - } - - /// Returns a key that was used for search. - /// - /// The key was retained for further use. - fn take_key(&mut self) -> Option { - self.key.take() - } - - /// Replaces the entry, returning the old key and value. The new key in the hash map will be - /// the key used to create this entry. - /// - /// # Examples - /// - /// ``` - /// #![feature(map_entry_replace)] - /// use std::collections::hash_map::{Entry, HashMap}; - /// use std::rc::Rc; - /// - /// let mut map: HashMap, u32> = HashMap::new(); - /// map.insert(Rc::new("Stringthing".to_string()), 15); - /// - /// let my_key = Rc::new("Stringthing".to_string()); - /// - /// if let Entry::Occupied(entry) = map.entry(my_key) { - /// // Also replace the key with a handle to our other key. - /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); - /// } - /// - /// ``` - #[unstable(feature = "map_entry_replace", issue = "44286")] - pub fn replace_entry(mut self, value: V) -> (K, V) { - let (old_key, old_value) = self.elem.read_mut(); - - let old_key = mem::replace(old_key, self.key.unwrap()); - let old_value = mem::replace(old_value, value); - - (old_key, old_value) - } - - /// Replaces the key in the hash map with the key used to create this entry. - /// - /// # Examples - /// - /// ``` - /// #![feature(map_entry_replace)] - /// use std::collections::hash_map::{Entry, HashMap}; - /// use std::rc::Rc; - /// - /// let mut map: HashMap, u32> = HashMap::new(); - /// let mut known_strings: Vec> = Vec::new(); - /// - /// // Initialise known strings, run program, etc. - /// - /// reclaim_memory(&mut map, &known_strings); - /// - /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { - /// for s in known_strings { - /// if let Entry::Occupied(entry) = map.entry(s.clone()) { - /// // Replaces the entry's key with our version of it in `known_strings`. - /// entry.replace_key(); - /// } - /// } - /// } - /// ``` - #[unstable(feature = "map_entry_replace", issue = "44286")] - pub fn replace_key(mut self) -> K { - let (old_key, _) = self.elem.read_mut(); - mem::replace(old_key, self.key.unwrap()) - } -} - -impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { - /// Gets a reference to the key that would be used when inserting a value - /// through the `VacantEntry`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - &self.key - } - - /// Take ownership of the key. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::Entry; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// - /// if let Entry::Vacant(v) = map.entry("poneyland") { - /// v.into_key(); - /// } - /// ``` - #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] - pub fn into_key(self) -> K { - self.key - } - - /// Sets the value of the entry with the VacantEntry's key, - /// and returns a mutable reference to it. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// use std::collections::hash_map::Entry; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// - /// if let Entry::Vacant(o) = map.entry("poneyland") { - /// o.insert(37); - /// } - /// assert_eq!(map["poneyland"], 37); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(self, value: V) -> &'a mut V { - let b = match self.elem { - NeqElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - robin_hood(bucket, disp, self.hash, self.key, value) - }, - NoElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - bucket.put(self.hash, self.key, value) - }, - }; - b.into_mut_refs().1 - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl FromIterator<(K, V)> for HashMap - where K: Eq + Hash, - S: BuildHasher + Default -{ - fn from_iter>(iter: T) -> HashMap { - let mut map = HashMap::with_hasher(Default::default()); - map.extend(iter); - map - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Extend<(K, V)> for HashMap - where K: Eq + Hash, - S: BuildHasher -{ - fn extend>(&mut self, iter: T) { - // Keys may be already present or show multiple times in the iterator. - // Reserve the entire hint lower bound if the map is empty. - // Otherwise reserve half the hint (rounded up), so the map - // will only resize twice in the worst case. - let iter = iter.into_iter(); - let reserve = if self.is_empty() { - iter.size_hint().0 - } else { - (iter.size_hint().0 + 1) / 2 - }; - self.reserve(reserve); - for (k, v) in iter { - self.insert(k, v); - } - } -} - -#[stable(feature = "hash_extend_copy", since = "1.4.0")] -impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap - where K: Eq + Hash + Copy, - V: Copy, - S: BuildHasher -{ - fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); - } -} - -/// `RandomState` is the default state for [`HashMap`] types. -/// -/// A particular instance `RandomState` will create the same instances of -/// [`Hasher`], but the hashers created by two different `RandomState` -/// instances are unlikely to produce the same result for the same values. -/// -/// [`HashMap`]: struct.HashMap.html -/// [`Hasher`]: ../../hash/trait.Hasher.html -/// -/// # Examples -/// -/// ``` -/// use std::collections::HashMap; -/// use std::collections::hash_map::RandomState; -/// -/// let s = RandomState::new(); -/// let mut map = HashMap::with_hasher(s); -/// map.insert(1, 2); -/// ``` -#[derive(Clone)] -#[stable(feature = "hashmap_build_hasher", since = "1.7.0")] -pub struct RandomState { - k0: u64, - k1: u64, -} - -impl RandomState { - /// Constructs a new `RandomState` that is initialized with random keys. - /// - /// # Examples - /// - /// ``` - /// use std::collections::hash_map::RandomState; - /// - /// let s = RandomState::new(); - /// ``` - #[inline] - #[allow(deprecated)] - // rand - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn new() -> RandomState { - // Historically this function did not cache keys from the OS and instead - // simply always called `rand::thread_rng().gen()` twice. In #31356 it - // was discovered, however, that because we re-seed the thread-local RNG - // from the OS periodically that this can cause excessive slowdown when - // many hash maps are created on a thread. To solve this performance - // trap we cache the first set of randomly generated keys per-thread. - // - // Later in #36481 it was discovered that exposing a deterministic - // iteration order allows a form of DOS attack. To counter that we - // increment one of the seeds on every RandomState creation, giving - // every corresponding HashMap a different iteration order. - thread_local!(static KEYS: Cell<(u64, u64)> = { - Cell::new(sys::hashmap_random_keys()) - }); - - KEYS.with(|keys| { - let (k0, k1) = keys.get(); - keys.set((k0.wrapping_add(1), k1)); - RandomState { k0: k0, k1: k1 } - }) - } -} - -#[stable(feature = "hashmap_build_hasher", since = "1.7.0")] -impl BuildHasher for RandomState { - type Hasher = DefaultHasher; - #[inline] - #[allow(deprecated)] - fn build_hasher(&self) -> DefaultHasher { - DefaultHasher(SipHasher13::new_with_keys(self.k0, self.k1)) - } -} - -/// The default [`Hasher`] used by [`RandomState`]. -/// -/// The internal algorithm is not specified, and so it and its hashes should -/// not be relied upon over releases. -/// -/// [`RandomState`]: struct.RandomState.html -/// [`Hasher`]: ../../hash/trait.Hasher.html -#[stable(feature = "hashmap_default_hasher", since = "1.13.0")] -#[allow(deprecated)] -#[derive(Clone, Debug)] -pub struct DefaultHasher(SipHasher13); - -impl DefaultHasher { - /// Creates a new `DefaultHasher`. - /// - /// This hasher is not guaranteed to be the same as all other - /// `DefaultHasher` instances, but is the same as all other `DefaultHasher` - /// instances created through `new` or `default`. - #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] - #[allow(deprecated)] - pub fn new() -> DefaultHasher { - DefaultHasher(SipHasher13::new_with_keys(0, 0)) - } -} - -#[stable(feature = "hashmap_default_hasher", since = "1.13.0")] -impl Default for DefaultHasher { - /// Creates a new `DefaultHasher` using [`new`]. See its documentation for more. - /// - /// [`new`]: #method.new - fn default() -> DefaultHasher { - DefaultHasher::new() - } -} - -#[stable(feature = "hashmap_default_hasher", since = "1.13.0")] -impl Hasher for DefaultHasher { - #[inline] - fn write(&mut self, msg: &[u8]) { - self.0.write(msg) - } - - #[inline] - fn finish(&self) -> u64 { - self.0.finish() - } -} - -#[stable(feature = "hashmap_build_hasher", since = "1.7.0")] -impl Default for RandomState { - /// Constructs a new `RandomState`. - #[inline] - fn default() -> RandomState { - RandomState::new() - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for RandomState { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("RandomState { .. }") - } -} - -impl super::Recover for HashMap - where K: Eq + Hash + Borrow, - S: BuildHasher, - Q: Eq + Hash -{ - type Key = K; - - #[inline] - fn get(&self, key: &Q) -> Option<&K> { - self.search(key).map(|bucket| bucket.into_refs().0) - } - - fn take(&mut self, key: &Q) -> Option { - self.search_mut(key).map(|bucket| pop_internal(bucket).0) - } - - #[inline] - fn replace(&mut self, key: K) -> Option { - self.reserve(1); - - match self.entry(key) { - Occupied(mut occupied) => { - let key = occupied.take_key().unwrap(); - Some(mem::replace(occupied.elem.read_mut().0, key)) - } - Vacant(vacant) => { - vacant.insert(()); - None - } - } - } -} - -#[allow(dead_code)] -fn assert_covariance() { - fn map_key<'new>(v: HashMap<&'static str, u8>) -> HashMap<&'new str, u8> { - v - } - fn map_val<'new>(v: HashMap) -> HashMap { - v - } - fn iter_key<'a, 'new>(v: Iter<'a, &'static str, u8>) -> Iter<'a, &'new str, u8> { - v - } - fn iter_val<'a, 'new>(v: Iter<'a, u8, &'static str>) -> Iter<'a, u8, &'new str> { - v - } - fn into_iter_key<'new>(v: IntoIter<&'static str, u8>) -> IntoIter<&'new str, u8> { - v - } - fn into_iter_val<'new>(v: IntoIter) -> IntoIter { - v - } - fn keys_key<'a, 'new>(v: Keys<'a, &'static str, u8>) -> Keys<'a, &'new str, u8> { - v - } - fn keys_val<'a, 'new>(v: Keys<'a, u8, &'static str>) -> Keys<'a, u8, &'new str> { - v - } - fn values_key<'a, 'new>(v: Values<'a, &'static str, u8>) -> Values<'a, &'new str, u8> { - v - } - fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> { - v - } - fn drain<'new>(d: Drain<'static, &'static str, &'static str>) - -> Drain<'new, &'new str, &'new str> { - d - } -} - -#[cfg(test)] -mod test_map { - use super::HashMap; - use super::Entry::{Occupied, Vacant}; - use super::RandomState; - use cell::RefCell; - use rand::{thread_rng, Rng}; - use realstd::collections::CollectionAllocErr::*; - use realstd::mem::size_of; - use realstd::usize; - - #[test] - fn test_zero_capacities() { - type HM = HashMap; - - let m = HM::new(); - assert_eq!(m.capacity(), 0); - - let m = HM::default(); - assert_eq!(m.capacity(), 0); - - let m = HM::with_hasher(RandomState::new()); - assert_eq!(m.capacity(), 0); - - let m = HM::with_capacity(0); - assert_eq!(m.capacity(), 0); - - let m = HM::with_capacity_and_hasher(0, RandomState::new()); - assert_eq!(m.capacity(), 0); - - let mut m = HM::new(); - m.insert(1, 1); - m.insert(2, 2); - m.remove(&1); - m.remove(&2); - m.shrink_to_fit(); - assert_eq!(m.capacity(), 0); - - let mut m = HM::new(); - m.reserve(0); - assert_eq!(m.capacity(), 0); - } - - #[test] - fn test_create_capacity_zero() { - let mut m = HashMap::with_capacity(0); - - assert!(m.insert(1, 1).is_none()); - - assert!(m.contains_key(&1)); - assert!(!m.contains_key(&0)); - } - - #[test] - fn test_insert() { - let mut m = HashMap::new(); - assert_eq!(m.len(), 0); - assert!(m.insert(1, 2).is_none()); - assert_eq!(m.len(), 1); - assert!(m.insert(2, 4).is_none()); - assert_eq!(m.len(), 2); - assert_eq!(*m.get(&1).unwrap(), 2); - assert_eq!(*m.get(&2).unwrap(), 4); - } - - #[test] - fn test_clone() { - let mut m = HashMap::new(); - assert_eq!(m.len(), 0); - assert!(m.insert(1, 2).is_none()); - assert_eq!(m.len(), 1); - assert!(m.insert(2, 4).is_none()); - assert_eq!(m.len(), 2); - let m2 = m.clone(); - assert_eq!(*m2.get(&1).unwrap(), 2); - assert_eq!(*m2.get(&2).unwrap(), 4); - assert_eq!(m2.len(), 2); - } - - thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } - - #[derive(Hash, PartialEq, Eq)] - struct Droppable { - k: usize, - } - - impl Droppable { - fn new(k: usize) -> Droppable { - DROP_VECTOR.with(|slot| { - slot.borrow_mut()[k] += 1; - }); - - Droppable { k: k } - } - } - - impl Drop for Droppable { - fn drop(&mut self) { - DROP_VECTOR.with(|slot| { - slot.borrow_mut()[self.k] -= 1; - }); - } - } - - impl Clone for Droppable { - fn clone(&self) -> Droppable { - Droppable::new(self.k) - } - } - - #[test] - fn test_drops() { - DROP_VECTOR.with(|slot| { - *slot.borrow_mut() = vec![0; 200]; - }); - - { - let mut m = HashMap::new(); - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - - for i in 0..100 { - let d1 = Droppable::new(i); - let d2 = Droppable::new(i + 100); - m.insert(d1, d2); - } - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 1); - } - }); - - for i in 0..50 { - let k = Droppable::new(i); - let v = m.remove(&k); - - assert!(v.is_some()); - - DROP_VECTOR.with(|v| { - assert_eq!(v.borrow()[i], 1); - assert_eq!(v.borrow()[i+100], 1); - }); - } - - DROP_VECTOR.with(|v| { - for i in 0..50 { - assert_eq!(v.borrow()[i], 0); - assert_eq!(v.borrow()[i+100], 0); - } - - for i in 50..100 { - assert_eq!(v.borrow()[i], 1); - assert_eq!(v.borrow()[i+100], 1); - } - }); - } - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - } - - #[test] - fn test_into_iter_drops() { - DROP_VECTOR.with(|v| { - *v.borrow_mut() = vec![0; 200]; - }); - - let hm = { - let mut hm = HashMap::new(); - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - - for i in 0..100 { - let d1 = Droppable::new(i); - let d2 = Droppable::new(i + 100); - hm.insert(d1, d2); - } - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 1); - } - }); - - hm - }; - - // By the way, ensure that cloning doesn't screw up the dropping. - drop(hm.clone()); - - { - let mut half = hm.into_iter().take(50); - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 1); - } - }); - - for _ in half.by_ref() {} - - DROP_VECTOR.with(|v| { - let nk = (0..100) - .filter(|&i| v.borrow()[i] == 1) - .count(); - - let nv = (0..100) - .filter(|&i| v.borrow()[i + 100] == 1) - .count(); - - assert_eq!(nk, 50); - assert_eq!(nv, 50); - }); - }; - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - } - - #[test] - fn test_empty_remove() { - let mut m: HashMap = HashMap::new(); - assert_eq!(m.remove(&0), None); - } - - #[test] - fn test_empty_entry() { - let mut m: HashMap = HashMap::new(); - match m.entry(0) { - Occupied(_) => panic!(), - Vacant(_) => {} - } - assert!(*m.entry(0).or_insert(true)); - assert_eq!(m.len(), 1); - } - - #[test] - fn test_empty_iter() { - let mut m: HashMap = HashMap::new(); - assert_eq!(m.drain().next(), None); - assert_eq!(m.keys().next(), None); - assert_eq!(m.values().next(), None); - assert_eq!(m.values_mut().next(), None); - assert_eq!(m.iter().next(), None); - assert_eq!(m.iter_mut().next(), None); - assert_eq!(m.len(), 0); - assert!(m.is_empty()); - assert_eq!(m.into_iter().next(), None); - } - - #[test] - fn test_lots_of_insertions() { - let mut m = HashMap::new(); - - // Try this a few times to make sure we never screw up the hashmap's - // internal state. - for _ in 0..10 { - assert!(m.is_empty()); - - for i in 1..1001 { - assert!(m.insert(i, i).is_none()); - - for j in 1..i + 1 { - let r = m.get(&j); - assert_eq!(r, Some(&j)); - } - - for j in i + 1..1001 { - let r = m.get(&j); - assert_eq!(r, None); - } - } - - for i in 1001..2001 { - assert!(!m.contains_key(&i)); - } - - // remove forwards - for i in 1..1001 { - assert!(m.remove(&i).is_some()); - - for j in 1..i + 1 { - assert!(!m.contains_key(&j)); - } - - for j in i + 1..1001 { - assert!(m.contains_key(&j)); - } - } - - for i in 1..1001 { - assert!(!m.contains_key(&i)); - } - - for i in 1..1001 { - assert!(m.insert(i, i).is_none()); - } - - // remove backwards - for i in (1..1001).rev() { - assert!(m.remove(&i).is_some()); - - for j in i..1001 { - assert!(!m.contains_key(&j)); - } - - for j in 1..i { - assert!(m.contains_key(&j)); - } - } - } - } - - #[test] - fn test_find_mut() { - let mut m = HashMap::new(); - assert!(m.insert(1, 12).is_none()); - assert!(m.insert(2, 8).is_none()); - assert!(m.insert(5, 14).is_none()); - let new = 100; - match m.get_mut(&5) { - None => panic!(), - Some(x) => *x = new, - } - assert_eq!(m.get(&5), Some(&new)); - } - - #[test] - fn test_insert_overwrite() { - let mut m = HashMap::new(); - assert!(m.insert(1, 2).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert!(!m.insert(1, 3).is_none()); - assert_eq!(*m.get(&1).unwrap(), 3); - } - - #[test] - fn test_insert_conflicts() { - let mut m = HashMap::with_capacity(4); - assert!(m.insert(1, 2).is_none()); - assert!(m.insert(5, 3).is_none()); - assert!(m.insert(9, 4).is_none()); - assert_eq!(*m.get(&9).unwrap(), 4); - assert_eq!(*m.get(&5).unwrap(), 3); - assert_eq!(*m.get(&1).unwrap(), 2); - } - - #[test] - fn test_conflict_remove() { - let mut m = HashMap::with_capacity(4); - assert!(m.insert(1, 2).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert!(m.insert(5, 3).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert_eq!(*m.get(&5).unwrap(), 3); - assert!(m.insert(9, 4).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert_eq!(*m.get(&5).unwrap(), 3); - assert_eq!(*m.get(&9).unwrap(), 4); - assert!(m.remove(&1).is_some()); - assert_eq!(*m.get(&9).unwrap(), 4); - assert_eq!(*m.get(&5).unwrap(), 3); - } - - #[test] - fn test_is_empty() { - let mut m = HashMap::with_capacity(4); - assert!(m.insert(1, 2).is_none()); - assert!(!m.is_empty()); - assert!(m.remove(&1).is_some()); - assert!(m.is_empty()); - } - - #[test] - fn test_remove() { - let mut m = HashMap::new(); - m.insert(1, 2); - assert_eq!(m.remove(&1), Some(2)); - assert_eq!(m.remove(&1), None); - } - - #[test] - fn test_remove_entry() { - let mut m = HashMap::new(); - m.insert(1, 2); - assert_eq!(m.remove_entry(&1), Some((1, 2))); - assert_eq!(m.remove(&1), None); - } - - #[test] - fn test_iterate() { - let mut m = HashMap::with_capacity(4); - for i in 0..32 { - assert!(m.insert(i, i*2).is_none()); - } - assert_eq!(m.len(), 32); - - let mut observed: u32 = 0; - - for (k, v) in &m { - assert_eq!(*v, *k * 2); - observed |= 1 << *k; - } - assert_eq!(observed, 0xFFFF_FFFF); - } - - #[test] - fn test_keys() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: HashMap<_, _> = vec.into_iter().collect(); - let keys: Vec<_> = map.keys().cloned().collect(); - assert_eq!(keys.len(), 3); - assert!(keys.contains(&1)); - assert!(keys.contains(&2)); - assert!(keys.contains(&3)); - } - - #[test] - fn test_values() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: HashMap<_, _> = vec.into_iter().collect(); - let values: Vec<_> = map.values().cloned().collect(); - assert_eq!(values.len(), 3); - assert!(values.contains(&'a')); - assert!(values.contains(&'b')); - assert!(values.contains(&'c')); - } - - #[test] - fn test_values_mut() { - let vec = vec![(1, 1), (2, 2), (3, 3)]; - let mut map: HashMap<_, _> = vec.into_iter().collect(); - for value in map.values_mut() { - *value = (*value) * 2 - } - let values: Vec<_> = map.values().cloned().collect(); - assert_eq!(values.len(), 3); - assert!(values.contains(&2)); - assert!(values.contains(&4)); - assert!(values.contains(&6)); - } - - #[test] - fn test_find() { - let mut m = HashMap::new(); - assert!(m.get(&1).is_none()); - m.insert(1, 2); - match m.get(&1) { - None => panic!(), - Some(v) => assert_eq!(*v, 2), - } - } - - #[test] - fn test_eq() { - let mut m1 = HashMap::new(); - m1.insert(1, 2); - m1.insert(2, 3); - m1.insert(3, 4); - - let mut m2 = HashMap::new(); - m2.insert(1, 2); - m2.insert(2, 3); - - assert!(m1 != m2); - - m2.insert(3, 4); - - assert_eq!(m1, m2); - } - - #[test] - fn test_show() { - let mut map = HashMap::new(); - let empty: HashMap = HashMap::new(); - - map.insert(1, 2); - map.insert(3, 4); - - let map_str = format!("{:?}", map); - - assert!(map_str == "{1: 2, 3: 4}" || - map_str == "{3: 4, 1: 2}"); - assert_eq!(format!("{:?}", empty), "{}"); - } - - #[test] - fn test_expand() { - let mut m = HashMap::new(); - - assert_eq!(m.len(), 0); - assert!(m.is_empty()); - - let mut i = 0; - let old_raw_cap = m.raw_capacity(); - while old_raw_cap == m.raw_capacity() { - m.insert(i, i); - i += 1; - } - - assert_eq!(m.len(), i); - assert!(!m.is_empty()); - } - - #[test] - fn test_behavior_resize_policy() { - let mut m = HashMap::new(); - - assert_eq!(m.len(), 0); - assert_eq!(m.raw_capacity(), 0); - assert!(m.is_empty()); - - m.insert(0, 0); - m.remove(&0); - assert!(m.is_empty()); - let initial_raw_cap = m.raw_capacity(); - m.reserve(initial_raw_cap); - let raw_cap = m.raw_capacity(); - - assert_eq!(raw_cap, initial_raw_cap * 2); - - let mut i = 0; - for _ in 0..raw_cap * 3 / 4 { - m.insert(i, i); - i += 1; - } - // three quarters full - - assert_eq!(m.len(), i); - assert_eq!(m.raw_capacity(), raw_cap); - - for _ in 0..raw_cap / 4 { - m.insert(i, i); - i += 1; - } - // half full - - let new_raw_cap = m.raw_capacity(); - assert_eq!(new_raw_cap, raw_cap * 2); - - for _ in 0..raw_cap / 2 - 1 { - i -= 1; - m.remove(&i); - assert_eq!(m.raw_capacity(), new_raw_cap); - } - // A little more than one quarter full. - m.shrink_to_fit(); - assert_eq!(m.raw_capacity(), raw_cap); - // again, a little more than half full - for _ in 0..raw_cap / 2 - 1 { - i -= 1; - m.remove(&i); - } - m.shrink_to_fit(); - - assert_eq!(m.len(), i); - assert!(!m.is_empty()); - assert_eq!(m.raw_capacity(), initial_raw_cap); - } - - #[test] - fn test_reserve_shrink_to_fit() { - let mut m = HashMap::new(); - m.insert(0, 0); - m.remove(&0); - assert!(m.capacity() >= m.len()); - for i in 0..128 { - m.insert(i, i); - } - m.reserve(256); - - let usable_cap = m.capacity(); - for i in 128..(128 + 256) { - m.insert(i, i); - assert_eq!(m.capacity(), usable_cap); - } - - for i in 100..(128 + 256) { - assert_eq!(m.remove(&i), Some(i)); - } - m.shrink_to_fit(); - - assert_eq!(m.len(), 100); - assert!(!m.is_empty()); - assert!(m.capacity() >= m.len()); - - for i in 0..100 { - assert_eq!(m.remove(&i), Some(i)); - } - m.shrink_to_fit(); - m.insert(0, 0); - - assert_eq!(m.len(), 1); - assert!(m.capacity() >= m.len()); - assert_eq!(m.remove(&0), Some(0)); - } - - #[test] - fn test_from_iter() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let map: HashMap<_, _> = xs.iter().cloned().collect(); - - for &(k, v) in &xs { - assert_eq!(map.get(&k), Some(&v)); - } - } - - #[test] - fn test_size_hint() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.size_hint(), (3, Some(3))); - } - - #[test] - fn test_iter_len() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.len(), 3); - } - - #[test] - fn test_mut_size_hint() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter_mut(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.size_hint(), (3, Some(3))); - } - - #[test] - fn test_iter_mut_len() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter_mut(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.len(), 3); - } - - #[test] - fn test_index() { - let mut map = HashMap::new(); - - map.insert(1, 2); - map.insert(2, 1); - map.insert(3, 4); - - assert_eq!(map[&2], 1); - } - - #[test] - #[should_panic] - fn test_index_nonexistent() { - let mut map = HashMap::new(); - - map.insert(1, 2); - map.insert(2, 1); - map.insert(3, 4); - - map[&4]; - } - - #[test] - fn test_entry() { - let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - // Existing key (insert) - match map.entry(1) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - assert_eq!(view.get(), &10); - assert_eq!(view.insert(100), 10); - } - } - assert_eq!(map.get(&1).unwrap(), &100); - assert_eq!(map.len(), 6); - - - // Existing key (update) - match map.entry(2) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - let v = view.get_mut(); - let new_v = (*v) * 10; - *v = new_v; - } - } - assert_eq!(map.get(&2).unwrap(), &200); - assert_eq!(map.len(), 6); - - // Existing key (take) - match map.entry(3) { - Vacant(_) => unreachable!(), - Occupied(view) => { - assert_eq!(view.remove(), 30); - } - } - assert_eq!(map.get(&3), None); - assert_eq!(map.len(), 5); - - - // Inexistent key (insert) - match map.entry(10) { - Occupied(_) => unreachable!(), - Vacant(view) => { - assert_eq!(*view.insert(1000), 1000); - } - } - assert_eq!(map.get(&10).unwrap(), &1000); - assert_eq!(map.len(), 6); - } - - #[test] - fn test_entry_take_doesnt_corrupt() { - #![allow(deprecated)] //rand - // Test for #19292 - fn check(m: &HashMap) { - for k in m.keys() { - assert!(m.contains_key(k), - "{} is in keys() but not in the map?", k); - } - } - - let mut m = HashMap::new(); - let mut rng = thread_rng(); - - // Populate the map with some items. - for _ in 0..50 { - let x = rng.gen_range(-10, 10); - m.insert(x, ()); - } - - for i in 0..1000 { - let x = rng.gen_range(-10, 10); - match m.entry(x) { - Vacant(_) => {} - Occupied(e) => { - println!("{}: remove {}", i, x); - e.remove(); - } - } - - check(&m); - } - } - - #[test] - fn test_extend_ref() { - let mut a = HashMap::new(); - a.insert(1, "one"); - let mut b = HashMap::new(); - b.insert(2, "two"); - b.insert(3, "three"); - - a.extend(&b); - - assert_eq!(a.len(), 3); - assert_eq!(a[&1], "one"); - assert_eq!(a[&2], "two"); - assert_eq!(a[&3], "three"); - } - - #[test] - fn test_capacity_not_less_than_len() { - let mut a = HashMap::new(); - let mut item = 0; - - for _ in 0..116 { - a.insert(item, 0); - item += 1; - } - - assert!(a.capacity() > a.len()); - - let free = a.capacity() - a.len(); - for _ in 0..free { - a.insert(item, 0); - item += 1; - } - - assert_eq!(a.len(), a.capacity()); - - // Insert at capacity should cause allocation. - a.insert(item, 0); - assert!(a.capacity() > a.len()); - } - - #[test] - fn test_occupied_entry_key() { - let mut a = HashMap::new(); - let key = "hello there"; - let value = "value goes here"; - assert!(a.is_empty()); - a.insert(key.clone(), value.clone()); - assert_eq!(a.len(), 1); - assert_eq!(a[key], value); - - match a.entry(key.clone()) { - Vacant(_) => panic!(), - Occupied(e) => assert_eq!(key, *e.key()), - } - assert_eq!(a.len(), 1); - assert_eq!(a[key], value); - } - - #[test] - fn test_vacant_entry_key() { - let mut a = HashMap::new(); - let key = "hello there"; - let value = "value goes here"; - - assert!(a.is_empty()); - match a.entry(key.clone()) { - Occupied(_) => panic!(), - Vacant(e) => { - assert_eq!(key, *e.key()); - e.insert(value.clone()); - } - } - assert_eq!(a.len(), 1); - assert_eq!(a[key], value); - } - - #[test] - fn test_retain() { - let mut map: HashMap = (0..100).map(|x|(x, x*10)).collect(); - - map.retain(|&k, _| k % 2 == 0); - assert_eq!(map.len(), 50); - assert_eq!(map[&2], 20); - assert_eq!(map[&4], 40); - assert_eq!(map[&6], 60); - } - - #[test] - fn test_adaptive() { - const TEST_LEN: usize = 5000; - // by cloning we get maps with the same hasher seed - let mut first = HashMap::new(); - let mut second = first.clone(); - first.extend((0..TEST_LEN).map(|i| (i, i))); - second.extend((TEST_LEN..TEST_LEN * 2).map(|i| (i, i))); - - for (&k, &v) in &second { - let prev_cap = first.capacity(); - let expect_grow = first.len() == prev_cap; - first.insert(k, v); - if !expect_grow && first.capacity() != prev_cap { - return; - } - } - panic!("Adaptive early resize failed"); - } - - #[test] - fn test_try_reserve() { - - let mut empty_bytes: HashMap = HashMap::new(); - - const MAX_USIZE: usize = usize::MAX; - - // HashMap and RawTables use complicated size calculations - // hashes_size is sizeof(HashUint) * capacity; - // pairs_size is sizeof((K. V)) * capacity; - // alignment_hashes_size is 8 - // alignment_pairs size is 4 - let size_of_multiplier = (size_of::() + size_of::<(u8, u8)>()).next_power_of_two(); - // The following formula is used to calculate the new capacity - let max_no_ovf = ((MAX_USIZE / 11) * 10) / size_of_multiplier - 1; - - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { - } else { panic!("usize::MAX should trigger an overflow!"); } - - if size_of::() < 8 { - if let Err(CapacityOverflow) = empty_bytes.try_reserve(max_no_ovf) { - } else { panic!("isize::MAX + 1 should trigger a CapacityOverflow!") } - } else { - if let Err(AllocErr) = empty_bytes.try_reserve(max_no_ovf) { - } else { panic!("isize::MAX + 1 should trigger an OOM!") } - } - } - -} diff --git a/ctr-std/src/collections/hash/mod.rs b/ctr-std/src/collections/hash/mod.rs deleted file mode 100644 index 7a22bec..0000000 --- a/ctr-std/src/collections/hash/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unordered containers, implemented as hash-tables - -mod bench; -mod table; -pub mod map; -pub mod set; - -trait Recover { - type Key; - - fn get(&self, key: &Q) -> Option<&Self::Key>; - fn take(&mut self, key: &Q) -> Option; - fn replace(&mut self, key: Self::Key) -> Option; -} diff --git a/ctr-std/src/collections/hash/set.rs b/ctr-std/src/collections/hash/set.rs deleted file mode 100644 index 5ac3e8f..0000000 --- a/ctr-std/src/collections/hash/set.rs +++ /dev/null @@ -1,1783 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use borrow::Borrow; -use fmt; -use hash::{Hash, BuildHasher}; -use iter::{Chain, FromIterator, FusedIterator}; -use ops::{BitOr, BitAnd, BitXor, Sub}; - -use super::Recover; -use super::map::{self, HashMap, Keys, RandomState}; - -// Future Optimization (FIXME!) -// ============================= -// -// Iteration over zero sized values is a noop. There is no need -// for `bucket.val` in the case of HashSet. I suppose we would need HKT -// to get rid of it properly. - -/// A hash set implemented as a `HashMap` where the value is `()`. -/// -/// As with the [`HashMap`] type, a `HashSet` requires that the elements -/// implement the [`Eq`] and [`Hash`] traits. This can frequently be achieved by -/// using `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself, -/// it is important that the following property holds: -/// -/// ```text -/// k1 == k2 -> hash(k1) == hash(k2) -/// ``` -/// -/// In other words, if two keys are equal, their hashes must be equal. -/// -/// -/// It is a logic error for an item to be modified in such a way that the -/// item's hash, as determined by the [`Hash`] trait, or its equality, as -/// determined by the [`Eq`] trait, changes while it is in the set. This is -/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or -/// unsafe code. -/// -/// # Examples -/// -/// ``` -/// use std::collections::HashSet; -/// // Type inference lets us omit an explicit type signature (which -/// // would be `HashSet` in this example). -/// let mut books = HashSet::new(); -/// -/// // Add some books. -/// books.insert("A Dance With Dragons".to_string()); -/// books.insert("To Kill a Mockingbird".to_string()); -/// books.insert("The Odyssey".to_string()); -/// books.insert("The Great Gatsby".to_string()); -/// -/// // Check for a specific one. -/// if !books.contains("The Winds of Winter") { -/// println!("We have {} books, but The Winds of Winter ain't one.", -/// books.len()); -/// } -/// -/// // Remove a book. -/// books.remove("The Odyssey"); -/// -/// // Iterate over everything. -/// for book in &books { -/// println!("{}", book); -/// } -/// ``` -/// -/// The easiest way to use `HashSet` with a custom type is to derive -/// [`Eq`] and [`Hash`]. We must also derive [`PartialEq`], this will in the -/// future be implied by [`Eq`]. -/// -/// ``` -/// use std::collections::HashSet; -/// #[derive(Hash, Eq, PartialEq, Debug)] -/// struct Viking { -/// name: String, -/// power: usize, -/// } -/// -/// let mut vikings = HashSet::new(); -/// -/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); -/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); -/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 }); -/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 }); -/// -/// // Use derived implementation to print the vikings. -/// for x in &vikings { -/// println!("{:?}", x); -/// } -/// ``` -/// -/// A `HashSet` with fixed list of elements can be initialized from an array: -/// -/// ``` -/// use std::collections::HashSet; -/// -/// fn main() { -/// let viking_names: HashSet<&'static str> = -/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); -/// // use the values stored in the set -/// } -/// ``` -/// -/// [`Cell`]: ../../std/cell/struct.Cell.html -/// [`Eq`]: ../../std/cmp/trait.Eq.html -/// [`Hash`]: ../../std/hash/trait.Hash.html -/// [`HashMap`]: struct.HashMap.html -/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct HashSet { - map: HashMap, -} - -impl HashSet { - /// Creates an empty `HashSet`. - /// - /// The hash set is initially created with a capacity of 0, so it will not allocate until it - /// is first inserted into. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// let set: HashSet = HashSet::new(); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> HashSet { - HashSet { map: HashMap::new() } - } - - /// Creates an empty `HashSet` with the specified capacity. - /// - /// The hash set will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash set will not allocate. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// let set: HashSet = HashSet::with_capacity(10); - /// assert!(set.capacity() >= 10); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize) -> HashSet { - HashSet { map: HashMap::with_capacity(capacity) } - } -} - -impl HashSet - where T: Eq + Hash, - S: BuildHasher -{ - /// Creates a new empty hash set which will use the given hasher to hash - /// keys. - /// - /// The hash set is also created with the default initial capacity. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// use std::collections::hash_map::RandomState; - /// - /// let s = RandomState::new(); - /// let mut set = HashSet::with_hasher(s); - /// set.insert(2); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_hasher(hasher: S) -> HashSet { - HashSet { map: HashMap::with_hasher(hasher) } - } - - /// Creates an empty `HashSet` with with the specified capacity, using - /// `hasher` to hash the keys. - /// - /// The hash set will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash set will not allocate. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// use std::collections::hash_map::RandomState; - /// - /// let s = RandomState::new(); - /// let mut set = HashSet::with_capacity_and_hasher(10, s); - /// set.insert(1); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { - HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } - } - - /// Returns a reference to the set's [`BuildHasher`]. - /// - /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// use std::collections::hash_map::RandomState; - /// - /// let hasher = RandomState::new(); - /// let set: HashSet = HashSet::with_hasher(hasher); - /// let hasher: &RandomState = set.hasher(); - /// ``` - #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] - pub fn hasher(&self) -> &S { - self.map.hasher() - } - - /// Returns the number of elements the set can hold without reallocating. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// let set: HashSet = HashSet::with_capacity(100); - /// assert!(set.capacity() >= 100); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn capacity(&self) -> usize { - self.map.capacity() - } - - /// Reserves capacity for at least `additional` more elements to be inserted - /// in the `HashSet`. The collection may reserve more space to avoid - /// frequent reallocations. - /// - /// # Panics - /// - /// Panics if the new allocation size overflows `usize`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// let mut set: HashSet = HashSet::new(); - /// set.reserve(10); - /// assert!(set.capacity() >= 10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn reserve(&mut self, additional: usize) { - self.map.reserve(additional) - } - - /// Shrinks the capacity of the set as much as possible. It will drop - /// down as much as possible while maintaining the internal rules - /// and possibly leaving some space in accordance with the resize policy. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut set = HashSet::with_capacity(100); - /// set.insert(1); - /// set.insert(2); - /// assert!(set.capacity() >= 100); - /// set.shrink_to_fit(); - /// assert!(set.capacity() >= 2); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn shrink_to_fit(&mut self) { - self.map.shrink_to_fit() - } - - /// Shrinks the capacity of the set with a lower limit. It will drop - /// down no lower than the supplied limit while maintaining the internal rules - /// and possibly leaving some space in accordance with the resize policy. - /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. - /// - /// # Examples - /// - /// ``` - /// #![feature(shrink_to)] - /// use std::collections::HashSet; - /// - /// let mut set = HashSet::with_capacity(100); - /// set.insert(1); - /// set.insert(2); - /// assert!(set.capacity() >= 100); - /// set.shrink_to(10); - /// assert!(set.capacity() >= 10); - /// set.shrink_to(0); - /// assert!(set.capacity() >= 2); - /// ``` - #[inline] - #[unstable(feature = "shrink_to", reason = "new API", issue="0")] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.map.shrink_to(min_capacity) - } - - /// An iterator visiting all elements in arbitrary order. - /// The iterator element type is `&'a T`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// let mut set = HashSet::new(); - /// set.insert("a"); - /// set.insert("b"); - /// - /// // Will print in an arbitrary order. - /// for x in set.iter() { - /// println!("{}", x); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { - Iter { iter: self.map.keys() } - } - - /// Visits the values representing the difference, - /// i.e. the values that are in `self` but not in `other`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); - /// - /// // Can be seen as `a - b`. - /// for x in a.difference(&b) { - /// println!("{}", x); // Print 1 - /// } - /// - /// let diff: HashSet<_> = a.difference(&b).collect(); - /// assert_eq!(diff, [1].iter().collect()); - /// - /// // Note that difference is not symmetric, - /// // and `b - a` means something else: - /// let diff: HashSet<_> = b.difference(&a).collect(); - /// assert_eq!(diff, [4].iter().collect()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, S> { - Difference { - iter: self.iter(), - other, - } - } - - /// Visits the values representing the symmetric difference, - /// i.e. the values that are in `self` or in `other` but not in both. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); - /// - /// // Print 1, 4 in arbitrary order. - /// for x in a.symmetric_difference(&b) { - /// println!("{}", x); - /// } - /// - /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect(); - /// let diff2: HashSet<_> = b.symmetric_difference(&a).collect(); - /// - /// assert_eq!(diff1, diff2); - /// assert_eq!(diff1, [1, 4].iter().collect()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn symmetric_difference<'a>(&'a self, - other: &'a HashSet) - -> SymmetricDifference<'a, T, S> { - SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) } - } - - /// Visits the values representing the intersection, - /// i.e. the values that are both in `self` and `other`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); - /// - /// // Print 2, 3 in arbitrary order. - /// for x in a.intersection(&b) { - /// println!("{}", x); - /// } - /// - /// let intersection: HashSet<_> = a.intersection(&b).collect(); - /// assert_eq!(intersection, [2, 3].iter().collect()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, T, S> { - Intersection { - iter: self.iter(), - other, - } - } - - /// Visits the values representing the union, - /// i.e. all the values in `self` or `other`, without duplicates. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); - /// - /// // Print 1, 2, 3, 4 in arbitrary order. - /// for x in a.union(&b) { - /// println!("{}", x); - /// } - /// - /// let union: HashSet<_> = a.union(&b).collect(); - /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn union<'a>(&'a self, other: &'a HashSet) -> Union<'a, T, S> { - Union { iter: self.iter().chain(other.difference(self)) } - } - - /// Returns the number of elements in the set. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut v = HashSet::new(); - /// assert_eq!(v.len(), 0); - /// v.insert(1); - /// assert_eq!(v.len(), 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> usize { - self.map.len() - } - - /// Returns true if the set contains no elements. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut v = HashSet::new(); - /// assert!(v.is_empty()); - /// v.insert(1); - /// assert!(!v.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { - self.map.is_empty() - } - - /// Clears the set, returning all elements in an iterator. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// assert!(!set.is_empty()); - /// - /// // print 1, 2, 3 in an arbitrary order - /// for i in set.drain() { - /// println!("{}", i); - /// } - /// - /// assert!(set.is_empty()); - /// ``` - #[inline] - #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self) -> Drain { - Drain { iter: self.map.drain() } - } - - /// Clears the set, removing all values. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut v = HashSet::new(); - /// v.insert(1); - /// v.clear(); - /// assert!(v.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn clear(&mut self) { - self.map.clear() - } - - /// Returns `true` if the set contains a value. - /// - /// The value may be any borrowed form of the set's value type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the value type. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// assert_eq!(set.contains(&1), true); - /// assert_eq!(set.contains(&4), false); - /// ``` - /// - /// [`Eq`]: ../../std/cmp/trait.Eq.html - /// [`Hash`]: ../../std/hash/trait.Hash.html - #[stable(feature = "rust1", since = "1.0.0")] - pub fn contains(&self, value: &Q) -> bool - where T: Borrow, - Q: Hash + Eq - { - self.map.contains_key(value) - } - - /// Returns a reference to the value in the set, if any, that is equal to the given value. - /// - /// The value may be any borrowed form of the set's value type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the value type. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// assert_eq!(set.get(&2), Some(&2)); - /// assert_eq!(set.get(&4), None); - /// ``` - /// - /// [`Eq`]: ../../std/cmp/trait.Eq.html - /// [`Hash`]: ../../std/hash/trait.Hash.html - #[stable(feature = "set_recovery", since = "1.9.0")] - pub fn get(&self, value: &Q) -> Option<&T> - where T: Borrow, - Q: Hash + Eq - { - Recover::get(&self.map, value) - } - - /// Returns `true` if `self` has no elements in common with `other`. - /// This is equivalent to checking for an empty intersection. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let mut b = HashSet::new(); - /// - /// assert_eq!(a.is_disjoint(&b), true); - /// b.insert(4); - /// assert_eq!(a.is_disjoint(&b), true); - /// b.insert(1); - /// assert_eq!(a.is_disjoint(&b), false); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_disjoint(&self, other: &HashSet) -> bool { - self.iter().all(|v| !other.contains(v)) - } - - /// Returns `true` if the set is a subset of another, - /// i.e. `other` contains at least all the values in `self`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let sup: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let mut set = HashSet::new(); - /// - /// assert_eq!(set.is_subset(&sup), true); - /// set.insert(2); - /// assert_eq!(set.is_subset(&sup), true); - /// set.insert(4); - /// assert_eq!(set.is_subset(&sup), false); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_subset(&self, other: &HashSet) -> bool { - self.iter().all(|v| other.contains(v)) - } - - /// Returns `true` if the set is a superset of another, - /// i.e. `self` contains at least all the values in `other`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let sub: HashSet<_> = [1, 2].iter().cloned().collect(); - /// let mut set = HashSet::new(); - /// - /// assert_eq!(set.is_superset(&sub), false); - /// - /// set.insert(0); - /// set.insert(1); - /// assert_eq!(set.is_superset(&sub), false); - /// - /// set.insert(2); - /// assert_eq!(set.is_superset(&sub), true); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_superset(&self, other: &HashSet) -> bool { - other.is_subset(self) - } - - /// Adds a value to the set. - /// - /// If the set did not have this value present, `true` is returned. - /// - /// If the set did have this value present, `false` is returned. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut set = HashSet::new(); - /// - /// assert_eq!(set.insert(2), true); - /// assert_eq!(set.insert(2), false); - /// assert_eq!(set.len(), 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(&mut self, value: T) -> bool { - self.map.insert(value, ()).is_none() - } - - /// Adds a value to the set, replacing the existing value, if any, that is equal to the given - /// one. Returns the replaced value. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut set = HashSet::new(); - /// set.insert(Vec::::new()); - /// - /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0); - /// set.replace(Vec::with_capacity(10)); - /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10); - /// ``` - #[stable(feature = "set_recovery", since = "1.9.0")] - pub fn replace(&mut self, value: T) -> Option { - Recover::replace(&mut self.map, value) - } - - /// Removes a value from the set. Returns `true` if the value was - /// present in the set. - /// - /// The value may be any borrowed form of the set's value type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the value type. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut set = HashSet::new(); - /// - /// set.insert(2); - /// assert_eq!(set.remove(&2), true); - /// assert_eq!(set.remove(&2), false); - /// ``` - /// - /// [`Eq`]: ../../std/cmp/trait.Eq.html - /// [`Hash`]: ../../std/hash/trait.Hash.html - #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(&mut self, value: &Q) -> bool - where T: Borrow, - Q: Hash + Eq - { - self.map.remove(value).is_some() - } - - /// Removes and returns the value in the set, if any, that is equal to the given one. - /// - /// The value may be any borrowed form of the set's value type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the value type. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// assert_eq!(set.take(&2), Some(2)); - /// assert_eq!(set.take(&2), None); - /// ``` - /// - /// [`Eq`]: ../../std/cmp/trait.Eq.html - /// [`Hash`]: ../../std/hash/trait.Hash.html - #[stable(feature = "set_recovery", since = "1.9.0")] - pub fn take(&mut self, value: &Q) -> Option - where T: Borrow, - Q: Hash + Eq - { - Recover::take(&mut self.map, value) - } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all elements `e` such that `f(&e)` returns `false`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let xs = [1,2,3,4,5,6]; - /// let mut set: HashSet = xs.iter().cloned().collect(); - /// set.retain(|&k| k % 2 == 0); - /// assert_eq!(set.len(), 3); - /// ``` - #[stable(feature = "retain_hash_collection", since = "1.18.0")] - pub fn retain(&mut self, mut f: F) - where F: FnMut(&T) -> bool - { - self.map.retain(|k, _| f(k)); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for HashSet - where T: Eq + Hash, - S: BuildHasher -{ - fn eq(&self, other: &HashSet) -> bool { - if self.len() != other.len() { - return false; - } - - self.iter().all(|key| other.contains(key)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for HashSet - where T: Eq + Hash, - S: BuildHasher -{ -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for HashSet - where T: Eq + Hash + fmt::Debug, - S: BuildHasher -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_set().entries(self.iter()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl FromIterator for HashSet - where T: Eq + Hash, - S: BuildHasher + Default -{ - fn from_iter>(iter: I) -> HashSet { - let mut set = HashSet::with_hasher(Default::default()); - set.extend(iter); - set - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Extend for HashSet - where T: Eq + Hash, - S: BuildHasher -{ - fn extend>(&mut self, iter: I) { - self.map.extend(iter.into_iter().map(|k| (k, ()))); - } -} - -#[stable(feature = "hash_extend_copy", since = "1.4.0")] -impl<'a, T, S> Extend<&'a T> for HashSet - where T: 'a + Eq + Hash + Copy, - S: BuildHasher -{ - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for HashSet - where T: Eq + Hash, - S: BuildHasher + Default -{ - /// Creates an empty `HashSet` with the `Default` value for the hasher. - fn default() -> HashSet { - HashSet { map: HashMap::default() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S> BitOr<&'b HashSet> for &'a HashSet - where T: Eq + Hash + Clone, - S: BuildHasher + Default -{ - type Output = HashSet; - - /// Returns the union of `self` and `rhs` as a new `HashSet`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); - /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); - /// - /// let set = &a | &b; - /// - /// let mut i = 0; - /// let expected = [1, 2, 3, 4, 5]; - /// for x in &set { - /// assert!(expected.contains(x)); - /// i += 1; - /// } - /// assert_eq!(i, expected.len()); - /// ``` - fn bitor(self, rhs: &HashSet) -> HashSet { - self.union(rhs).cloned().collect() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S> BitAnd<&'b HashSet> for &'a HashSet - where T: Eq + Hash + Clone, - S: BuildHasher + Default -{ - type Output = HashSet; - - /// Returns the intersection of `self` and `rhs` as a new `HashSet`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); - /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect(); - /// - /// let set = &a & &b; - /// - /// let mut i = 0; - /// let expected = [2, 3]; - /// for x in &set { - /// assert!(expected.contains(x)); - /// i += 1; - /// } - /// assert_eq!(i, expected.len()); - /// ``` - fn bitand(self, rhs: &HashSet) -> HashSet { - self.intersection(rhs).cloned().collect() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S> BitXor<&'b HashSet> for &'a HashSet - where T: Eq + Hash + Clone, - S: BuildHasher + Default -{ - type Output = HashSet; - - /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); - /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); - /// - /// let set = &a ^ &b; - /// - /// let mut i = 0; - /// let expected = [1, 2, 4, 5]; - /// for x in &set { - /// assert!(expected.contains(x)); - /// i += 1; - /// } - /// assert_eq!(i, expected.len()); - /// ``` - fn bitxor(self, rhs: &HashSet) -> HashSet { - self.symmetric_difference(rhs).cloned().collect() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, S> Sub<&'b HashSet> for &'a HashSet - where T: Eq + Hash + Clone, - S: BuildHasher + Default -{ - type Output = HashSet; - - /// Returns the difference of `self` and `rhs` as a new `HashSet`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); - /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); - /// - /// let set = &a - &b; - /// - /// let mut i = 0; - /// let expected = [1, 2]; - /// for x in &set { - /// assert!(expected.contains(x)); - /// i += 1; - /// } - /// assert_eq!(i, expected.len()); - /// ``` - fn sub(self, rhs: &HashSet) -> HashSet { - self.difference(rhs).cloned().collect() - } -} - -/// An iterator over the items of a `HashSet`. -/// -/// This `struct` is created by the [`iter`] method on [`HashSet`]. -/// See its documentation for more. -/// -/// [`HashSet`]: struct.HashSet.html -/// [`iter`]: struct.HashSet.html#method.iter -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, K: 'a> { - iter: Keys<'a, K, ()>, -} - -/// An owning iterator over the items of a `HashSet`. -/// -/// This `struct` is created by the [`into_iter`] method on [`HashSet`][`HashSet`] -/// (provided by the `IntoIterator` trait). See its documentation for more. -/// -/// [`HashSet`]: struct.HashSet.html -/// [`into_iter`]: struct.HashSet.html#method.into_iter -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter { - iter: map::IntoIter, -} - -/// A draining iterator over the items of a `HashSet`. -/// -/// This `struct` is created by the [`drain`] method on [`HashSet`]. -/// See its documentation for more. -/// -/// [`HashSet`]: struct.HashSet.html -/// [`drain`]: struct.HashSet.html#method.drain -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Drain<'a, K: 'a> { - iter: map::Drain<'a, K, ()>, -} - -/// A lazy iterator producing elements in the intersection of `HashSet`s. -/// -/// This `struct` is created by the [`intersection`] method on [`HashSet`]. -/// See its documentation for more. -/// -/// [`HashSet`]: struct.HashSet.html -/// [`intersection`]: struct.HashSet.html#method.intersection -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Intersection<'a, T: 'a, S: 'a> { - // iterator of the first set - iter: Iter<'a, T>, - // the second set - other: &'a HashSet, -} - -/// A lazy iterator producing elements in the difference of `HashSet`s. -/// -/// This `struct` is created by the [`difference`] method on [`HashSet`]. -/// See its documentation for more. -/// -/// [`HashSet`]: struct.HashSet.html -/// [`difference`]: struct.HashSet.html#method.difference -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Difference<'a, T: 'a, S: 'a> { - // iterator of the first set - iter: Iter<'a, T>, - // the second set - other: &'a HashSet, -} - -/// A lazy iterator producing elements in the symmetric difference of `HashSet`s. -/// -/// This `struct` is created by the [`symmetric_difference`] method on -/// [`HashSet`]. See its documentation for more. -/// -/// [`HashSet`]: struct.HashSet.html -/// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SymmetricDifference<'a, T: 'a, S: 'a> { - iter: Chain, Difference<'a, T, S>>, -} - -/// A lazy iterator producing elements in the union of `HashSet`s. -/// -/// This `struct` is created by the [`union`] method on [`HashSet`]. -/// See its documentation for more. -/// -/// [`HashSet`]: struct.HashSet.html -/// [`union`]: struct.HashSet.html#method.union -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Union<'a, T: 'a, S: 'a> { - iter: Chain, Difference<'a, T, S>>, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> IntoIterator for &'a HashSet - where T: Eq + Hash, - S: BuildHasher -{ - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for HashSet - where T: Eq + Hash, - S: BuildHasher -{ - type Item = T; - type IntoIter = IntoIter; - - /// Creates a consuming iterator, that is, one that moves each value out - /// of the set in arbitrary order. The set cannot be used after calling - /// this. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// let mut set = HashSet::new(); - /// set.insert("a".to_string()); - /// set.insert("b".to_string()); - /// - /// // Not possible to collect to a Vec with a regular `.iter()`. - /// let v: Vec = set.into_iter().collect(); - /// - /// // Will print in an arbitrary order. - /// for x in &v { - /// println!("{}", x); - /// } - /// ``` - fn into_iter(self) -> IntoIter { - IntoIter { iter: self.map.into_iter() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K> Clone for Iter<'a, K> { - fn clone(&self) -> Iter<'a, K> { - Iter { iter: self.iter.clone() } - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K> Iterator for Iter<'a, K> { - type Item = &'a K; - - fn next(&mut self) -> Option<&'a K> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K> ExactSizeIterator for Iter<'a, K> { - fn len(&self) -> usize { - self.iter.len() - } -} -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K> FusedIterator for Iter<'a, K> {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, K: fmt::Debug> fmt::Debug for Iter<'a, K> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { - type Item = K; - - fn next(&mut self) -> Option { - self.iter.next().map(|(k, _)| k) - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { - fn len(&self) -> usize { - self.iter.len() - } -} -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let entries_iter = self.iter - .inner - .iter() - .map(|(k, _)| k); - f.debug_list().entries(entries_iter).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K> Iterator for Drain<'a, K> { - type Item = K; - - fn next(&mut self) -> Option { - self.iter.next().map(|(k, _)| k) - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K> ExactSizeIterator for Drain<'a, K> { - fn len(&self) -> usize { - self.iter.len() - } -} -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K> FusedIterator for Drain<'a, K> {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, K: fmt::Debug> fmt::Debug for Drain<'a, K> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let entries_iter = self.iter - .inner - .iter() - .map(|(k, _)| k); - f.debug_list().entries(entries_iter).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Clone for Intersection<'a, T, S> { - fn clone(&self) -> Intersection<'a, T, S> { - Intersection { iter: self.iter.clone(), ..*self } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for Intersection<'a, T, S> - where T: Eq + Hash, - S: BuildHasher -{ - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - loop { - let elt = self.iter.next()?; - if self.other.contains(elt) { - return Some(elt); - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> - where T: fmt::Debug + Eq + Hash, - S: BuildHasher -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T, S> FusedIterator for Intersection<'a, T, S> - where T: Eq + Hash, - S: BuildHasher -{ -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Clone for Difference<'a, T, S> { - fn clone(&self) -> Difference<'a, T, S> { - Difference { iter: self.iter.clone(), ..*self } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for Difference<'a, T, S> - where T: Eq + Hash, - S: BuildHasher -{ - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - loop { - let elt = self.iter.next()?; - if !self.other.contains(elt) { - return Some(elt); - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T, S> FusedIterator for Difference<'a, T, S> - where T: Eq + Hash, - S: BuildHasher -{ -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, T, S> fmt::Debug for Difference<'a, T, S> - where T: fmt::Debug + Eq + Hash, - S: BuildHasher -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> { - fn clone(&self) -> SymmetricDifference<'a, T, S> { - SymmetricDifference { iter: self.iter.clone() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> - where T: Eq + Hash, - S: BuildHasher -{ - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> - where T: Eq + Hash, - S: BuildHasher -{ -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, T, S> fmt::Debug for SymmetricDifference<'a, T, S> - where T: fmt::Debug + Eq + Hash, - S: BuildHasher -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Clone for Union<'a, T, S> { - fn clone(&self) -> Union<'a, T, S> { - Union { iter: self.iter.clone() } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T, S> FusedIterator for Union<'a, T, S> - where T: Eq + Hash, - S: BuildHasher -{ -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, T, S> fmt::Debug for Union<'a, T, S> - where T: fmt::Debug + Eq + Hash, - S: BuildHasher -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for Union<'a, T, S> - where T: Eq + Hash, - S: BuildHasher -{ - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[allow(dead_code)] -fn assert_covariance() { - fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> { - v - } - fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { - v - } - fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> { - v - } - fn difference<'a, 'new>(v: Difference<'a, &'static str, RandomState>) - -> Difference<'a, &'new str, RandomState> { - v - } - fn symmetric_difference<'a, 'new>(v: SymmetricDifference<'a, &'static str, RandomState>) - -> SymmetricDifference<'a, &'new str, RandomState> { - v - } - fn intersection<'a, 'new>(v: Intersection<'a, &'static str, RandomState>) - -> Intersection<'a, &'new str, RandomState> { - v - } - fn union<'a, 'new>(v: Union<'a, &'static str, RandomState>) - -> Union<'a, &'new str, RandomState> { - v - } - fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { - d - } -} - -#[cfg(test)] -mod test_set { - use super::HashSet; - use super::super::map::RandomState; - - #[test] - fn test_zero_capacities() { - type HS = HashSet; - - let s = HS::new(); - assert_eq!(s.capacity(), 0); - - let s = HS::default(); - assert_eq!(s.capacity(), 0); - - let s = HS::with_hasher(RandomState::new()); - assert_eq!(s.capacity(), 0); - - let s = HS::with_capacity(0); - assert_eq!(s.capacity(), 0); - - let s = HS::with_capacity_and_hasher(0, RandomState::new()); - assert_eq!(s.capacity(), 0); - - let mut s = HS::new(); - s.insert(1); - s.insert(2); - s.remove(&1); - s.remove(&2); - s.shrink_to_fit(); - assert_eq!(s.capacity(), 0); - - let mut s = HS::new(); - s.reserve(0); - assert_eq!(s.capacity(), 0); - } - - #[test] - fn test_disjoint() { - let mut xs = HashSet::new(); - let mut ys = HashSet::new(); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(5)); - assert!(ys.insert(11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(7)); - assert!(xs.insert(19)); - assert!(xs.insert(4)); - assert!(ys.insert(2)); - assert!(ys.insert(-11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(ys.insert(7)); - assert!(!xs.is_disjoint(&ys)); - assert!(!ys.is_disjoint(&xs)); - } - - #[test] - fn test_subset_and_superset() { - let mut a = HashSet::new(); - assert!(a.insert(0)); - assert!(a.insert(5)); - assert!(a.insert(11)); - assert!(a.insert(7)); - - let mut b = HashSet::new(); - assert!(b.insert(0)); - assert!(b.insert(7)); - assert!(b.insert(19)); - assert!(b.insert(250)); - assert!(b.insert(11)); - assert!(b.insert(200)); - - assert!(!a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(!b.is_superset(&a)); - - assert!(b.insert(5)); - - assert!(a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(b.is_superset(&a)); - } - - #[test] - fn test_iterate() { - let mut a = HashSet::new(); - for i in 0..32 { - assert!(a.insert(i)); - } - let mut observed: u32 = 0; - for k in &a { - observed |= 1 << *k; - } - assert_eq!(observed, 0xFFFF_FFFF); - } - - #[test] - fn test_intersection() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(11)); - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(77)); - assert!(a.insert(103)); - assert!(a.insert(5)); - assert!(a.insert(-5)); - - assert!(b.insert(2)); - assert!(b.insert(11)); - assert!(b.insert(77)); - assert!(b.insert(-9)); - assert!(b.insert(-42)); - assert!(b.insert(5)); - assert!(b.insert(3)); - - let mut i = 0; - let expected = [3, 5, 11, 77]; - for x in a.intersection(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_difference() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(3)); - assert!(b.insert(9)); - - let mut i = 0; - let expected = [1, 5, 11]; - for x in a.difference(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_symmetric_difference() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(-2)); - assert!(b.insert(3)); - assert!(b.insert(9)); - assert!(b.insert(14)); - assert!(b.insert(22)); - - let mut i = 0; - let expected = [-2, 1, 5, 11, 14, 22]; - for x in a.symmetric_difference(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_union() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - assert!(a.insert(16)); - assert!(a.insert(19)); - assert!(a.insert(24)); - - assert!(b.insert(-2)); - assert!(b.insert(1)); - assert!(b.insert(5)); - assert!(b.insert(9)); - assert!(b.insert(13)); - assert!(b.insert(19)); - - let mut i = 0; - let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; - for x in a.union(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_from_iter() { - let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - - let set: HashSet<_> = xs.iter().cloned().collect(); - - for x in &xs { - assert!(set.contains(x)); - } - } - - #[test] - fn test_move_iter() { - let hs = { - let mut hs = HashSet::new(); - - hs.insert('a'); - hs.insert('b'); - - hs - }; - - let v = hs.into_iter().collect::>(); - assert!(v == ['a', 'b'] || v == ['b', 'a']); - } - - #[test] - fn test_eq() { - // These constants once happened to expose a bug in insert(). - // I'm keeping them around to prevent a regression. - let mut s1 = HashSet::new(); - - s1.insert(1); - s1.insert(2); - s1.insert(3); - - let mut s2 = HashSet::new(); - - s2.insert(1); - s2.insert(2); - - assert!(s1 != s2); - - s2.insert(3); - - assert_eq!(s1, s2); - } - - #[test] - fn test_show() { - let mut set = HashSet::new(); - let empty = HashSet::::new(); - - set.insert(1); - set.insert(2); - - let set_str = format!("{:?}", set); - - assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); - assert_eq!(format!("{:?}", empty), "{}"); - } - - #[test] - fn test_trivial_drain() { - let mut s = HashSet::::new(); - for _ in s.drain() {} - assert!(s.is_empty()); - drop(s); - - let mut s = HashSet::::new(); - drop(s.drain()); - assert!(s.is_empty()); - } - - #[test] - fn test_drain() { - let mut s: HashSet<_> = (1..100).collect(); - - // try this a bunch of times to make sure we don't screw up internal state. - for _ in 0..20 { - assert_eq!(s.len(), 99); - - { - let mut last_i = 0; - let mut d = s.drain(); - for (i, x) in d.by_ref().take(50).enumerate() { - last_i = i; - assert!(x != 0); - } - assert_eq!(last_i, 49); - } - - for _ in &s { - panic!("s should be empty!"); - } - - // reset to try again. - s.extend(1..100); - } - } - - #[test] - fn test_replace() { - use hash; - - #[derive(Debug)] - struct Foo(&'static str, i32); - - impl PartialEq for Foo { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - impl Eq for Foo {} - - impl hash::Hash for Foo { - fn hash(&self, h: &mut H) { - self.0.hash(h); - } - } - - let mut s = HashSet::new(); - assert_eq!(s.replace(Foo("a", 1)), None); - assert_eq!(s.len(), 1); - assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); - assert_eq!(s.len(), 1); - - let mut it = s.iter(); - assert_eq!(it.next(), Some(&Foo("a", 2))); - assert_eq!(it.next(), None); - } - - #[test] - fn test_extend_ref() { - let mut a = HashSet::new(); - a.insert(1); - - a.extend(&[2, 3, 4]); - - assert_eq!(a.len(), 4); - assert!(a.contains(&1)); - assert!(a.contains(&2)); - assert!(a.contains(&3)); - assert!(a.contains(&4)); - - let mut b = HashSet::new(); - b.insert(5); - b.insert(6); - - a.extend(&b); - - assert_eq!(a.len(), 6); - assert!(a.contains(&1)); - assert!(a.contains(&2)); - assert!(a.contains(&3)); - assert!(a.contains(&4)); - assert!(a.contains(&5)); - assert!(a.contains(&6)); - } - - #[test] - fn test_retain() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut set: HashSet = xs.iter().cloned().collect(); - set.retain(|&k| k % 2 == 0); - assert_eq!(set.len(), 3); - assert!(set.contains(&2)); - assert!(set.contains(&4)); - assert!(set.contains(&6)); - } -} diff --git a/ctr-std/src/collections/hash/table.rs b/ctr-std/src/collections/hash/table.rs deleted file mode 100644 index 2b31918..0000000 --- a/ctr-std/src/collections/hash/table.rs +++ /dev/null @@ -1,1133 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use alloc::{Global, Alloc, Layout, LayoutErr, handle_alloc_error}; -use collections::CollectionAllocErr; -use hash::{BuildHasher, Hash, Hasher}; -use marker; -use mem::{size_of, needs_drop}; -use mem; -use ops::{Deref, DerefMut}; -use ptr::{self, Unique, NonNull}; -use hint; - -use self::BucketState::*; - -/// Integer type used for stored hash values. -/// -/// No more than bit_width(usize) bits are needed to select a bucket. -/// -/// The most significant bit is ours to use for tagging `SafeHash`. -/// -/// (Even if we could have usize::MAX bytes allocated for buckets, -/// each bucket stores at least a `HashUint`, so there can be no more than -/// usize::MAX / size_of(usize) buckets.) -type HashUint = usize; - -const EMPTY_BUCKET: HashUint = 0; -const EMPTY: usize = 1; - -/// Special `Unique` that uses the lower bit of the pointer -/// to expose a boolean tag. -/// Note: when the pointer is initialized to EMPTY `.ptr()` will return -/// null and the tag functions shouldn't be used. -struct TaggedHashUintPtr(Unique); - -impl TaggedHashUintPtr { - #[inline] - unsafe fn new(ptr: *mut HashUint) -> Self { - debug_assert!(ptr as usize & 1 == 0 || ptr as usize == EMPTY as usize); - TaggedHashUintPtr(Unique::new_unchecked(ptr)) - } - - #[inline] - fn set_tag(&mut self, value: bool) { - let mut usize_ptr = self.0.as_ptr() as usize; - unsafe { - if value { - usize_ptr |= 1; - } else { - usize_ptr &= !1; - } - self.0 = Unique::new_unchecked(usize_ptr as *mut HashUint) - } - } - - #[inline] - fn tag(&self) -> bool { - (self.0.as_ptr() as usize) & 1 == 1 - } - - #[inline] - fn ptr(&self) -> *mut HashUint { - (self.0.as_ptr() as usize & !1) as *mut HashUint - } -} - -/// The raw hashtable, providing safe-ish access to the unzipped and highly -/// optimized arrays of hashes, and key-value pairs. -/// -/// This design is a lot faster than the naive -/// `Vec>`, because we don't pay for the overhead of an -/// option on every element, and we get a generally more cache-aware design. -/// -/// Essential invariants of this structure: -/// -/// - if `t.hashes[i] == EMPTY_BUCKET`, then `Bucket::at_index(&t, i).raw` -/// points to 'undefined' contents. Don't read from it. This invariant is -/// enforced outside this module with the `EmptyBucket`, `FullBucket`, -/// and `SafeHash` types. -/// -/// - An `EmptyBucket` is only constructed at an index with -/// a hash of EMPTY_BUCKET. -/// -/// - A `FullBucket` is only constructed at an index with a -/// non-EMPTY_BUCKET hash. -/// -/// - A `SafeHash` is only constructed for non-`EMPTY_BUCKET` hash. We get -/// around hashes of zero by changing them to 0x8000_0000_0000_0000, -/// which will likely map to the same bucket, while not being confused -/// with "empty". -/// -/// - Both "arrays represented by pointers" are the same length: -/// `capacity`. This is set at creation and never changes. The arrays -/// are unzipped and are more cache aware (scanning through 8 hashes -/// brings in at most 2 cache lines, since they're all right beside each -/// other). This layout may waste space in padding such as in a map from -/// u64 to u8, but is a more cache conscious layout as the key-value pairs -/// are only very shortly probed and the desired value will be in the same -/// or next cache line. -/// -/// You can kind of think of this module/data structure as a safe wrapper -/// around just the "table" part of the hashtable. It enforces some -/// invariants at the type level and employs some performance trickery, -/// but in general is just a tricked out `Vec>`. -/// -/// The hashtable also exposes a special boolean tag. The tag defaults to false -/// when the RawTable is created and is accessible with the `tag` and `set_tag` -/// functions. -pub struct RawTable { - capacity_mask: usize, - size: usize, - hashes: TaggedHashUintPtr, - - // Because K/V do not appear directly in any of the types in the struct, - // inform rustc that in fact instances of K and V are reachable from here. - marker: marker::PhantomData<(K, V)>, -} - -// An unsafe view of a RawTable bucket -// Valid indexes are within [0..table_capacity) -pub struct RawBucket { - hash_start: *mut HashUint, - // We use *const to ensure covariance with respect to K and V - pair_start: *const (K, V), - idx: usize, - _marker: marker::PhantomData<(K, V)>, -} - -impl Copy for RawBucket {} -impl Clone for RawBucket { - fn clone(&self) -> RawBucket { - *self - } -} - -pub struct Bucket { - raw: RawBucket, - table: M, -} - -impl Copy for Bucket {} -impl Clone for Bucket { - fn clone(&self) -> Bucket { - *self - } -} - -pub struct EmptyBucket { - raw: RawBucket, - table: M, -} - -pub struct FullBucket { - raw: RawBucket, - table: M, -} - -pub type FullBucketMut<'table, K, V> = FullBucket>; - -pub enum BucketState { - Empty(EmptyBucket), - Full(FullBucket), -} - -// A GapThenFull encapsulates the state of two consecutive buckets at once. -// The first bucket, called the gap, is known to be empty. -// The second bucket is full. -pub struct GapThenFull { - gap: EmptyBucket, - full: FullBucket, -} - -/// A hash that is not zero, since we use a hash of zero to represent empty -/// buckets. -#[derive(PartialEq, Copy, Clone)] -pub struct SafeHash { - hash: HashUint, -} - -impl SafeHash { - /// Peek at the hash value, which is guaranteed to be non-zero. - #[inline(always)] - pub fn inspect(&self) -> HashUint { - self.hash - } - - #[inline(always)] - pub fn new(hash: u64) -> Self { - // We need to avoid 0 in order to prevent collisions with - // EMPTY_HASH. We can maintain our precious uniform distribution - // of initial indexes by unconditionally setting the MSB, - // effectively reducing the hashes by one bit. - // - // Truncate hash to fit in `HashUint`. - let hash_bits = size_of::() * 8; - SafeHash { hash: (1 << (hash_bits - 1)) | (hash as HashUint) } - } -} - -/// We need to remove hashes of 0. That's reserved for empty buckets. -/// This function wraps up `hash_keyed` to be the only way outside this -/// module to generate a SafeHash. -pub fn make_hash(hash_state: &S, t: &T) -> SafeHash - where T: Hash, - S: BuildHasher -{ - let mut state = hash_state.build_hasher(); - t.hash(&mut state); - SafeHash::new(state.finish()) -} - -// `replace` casts a `*HashUint` to a `*SafeHash`. Since we statically -// ensure that a `FullBucket` points to an index with a non-zero hash, -// and a `SafeHash` is just a `HashUint` with a different name, this is -// safe. -// -// This test ensures that a `SafeHash` really IS the same size as a -// `HashUint`. If you need to change the size of `SafeHash` (and -// consequently made this test fail), `replace` needs to be -// modified to no longer assume this. -#[test] -fn can_alias_safehash_as_hash() { - assert_eq!(size_of::(), size_of::()) -} - -// RawBucket methods are unsafe as it's possible to -// make a RawBucket point to invalid memory using safe code. -impl RawBucket { - unsafe fn hash(&self) -> *mut HashUint { - self.hash_start.offset(self.idx as isize) - } - unsafe fn pair(&self) -> *mut (K, V) { - self.pair_start.offset(self.idx as isize) as *mut (K, V) - } - unsafe fn hash_pair(&self) -> (*mut HashUint, *mut (K, V)) { - (self.hash(), self.pair()) - } -} - -// Buckets hold references to the table. -impl FullBucket { - /// Borrow a reference to the table. - pub fn table(&self) -> &M { - &self.table - } - /// Borrow a mutable reference to the table. - pub fn table_mut(&mut self) -> &mut M { - &mut self.table - } - /// Move out the reference to the table. - pub fn into_table(self) -> M { - self.table - } - /// Get the raw index. - pub fn index(&self) -> usize { - self.raw.idx - } - /// Get the raw bucket. - pub fn raw(&self) -> RawBucket { - self.raw - } -} - -impl EmptyBucket { - /// Borrow a reference to the table. - pub fn table(&self) -> &M { - &self.table - } - /// Borrow a mutable reference to the table. - pub fn table_mut(&mut self) -> &mut M { - &mut self.table - } -} - -impl Bucket { - /// Get the raw index. - pub fn index(&self) -> usize { - self.raw.idx - } - /// get the table. - pub fn into_table(self) -> M { - self.table - } -} - -impl Deref for FullBucket - where M: Deref> -{ - type Target = RawTable; - fn deref(&self) -> &RawTable { - &self.table - } -} - -/// `Put` is implemented for types which provide access to a table and cannot be invalidated -/// by filling a bucket. A similar implementation for `Take` is possible. -pub trait Put { - unsafe fn borrow_table_mut(&mut self) -> &mut RawTable; -} - - -impl<'t, K, V> Put for &'t mut RawTable { - unsafe fn borrow_table_mut(&mut self) -> &mut RawTable { - *self - } -} - -impl Put for Bucket - where M: Put -{ - unsafe fn borrow_table_mut(&mut self) -> &mut RawTable { - self.table.borrow_table_mut() - } -} - -impl Put for FullBucket - where M: Put -{ - unsafe fn borrow_table_mut(&mut self) -> &mut RawTable { - self.table.borrow_table_mut() - } -} - -impl>> Bucket { - pub fn new(table: M, hash: SafeHash) -> Bucket { - Bucket::at_index(table, hash.inspect() as usize) - } - - pub fn new_from(r: RawBucket, t: M) - -> Bucket - { - Bucket { - raw: r, - table: t, - } - } - - pub fn at_index(table: M, ib_index: usize) -> Bucket { - // if capacity is 0, then the RawBucket will be populated with bogus pointers. - // This is an uncommon case though, so avoid it in release builds. - debug_assert!(table.capacity() > 0, - "Table should have capacity at this point"); - let ib_index = ib_index & table.capacity_mask; - Bucket { - raw: table.raw_bucket_at(ib_index), - table, - } - } - - pub fn first(table: M) -> Bucket { - Bucket { - raw: table.raw_bucket_at(0), - table, - } - } - - // "So a few of the first shall be last: for many be called, - // but few chosen." - // - // We'll most likely encounter a few buckets at the beginning that - // have their initial buckets near the end of the table. They were - // placed at the beginning as the probe wrapped around the table - // during insertion. We must skip forward to a bucket that won't - // get reinserted too early and won't unfairly steal others spot. - // This eliminates the need for robin hood. - pub fn head_bucket(table: M) -> Bucket { - let mut bucket = Bucket::first(table); - - loop { - bucket = match bucket.peek() { - Full(full) => { - if full.displacement() == 0 { - // This bucket occupies its ideal spot. - // It indicates the start of another "cluster". - bucket = full.into_bucket(); - break; - } - // Leaving this bucket in the last cluster for later. - full.into_bucket() - } - Empty(b) => { - // Encountered a hole between clusters. - b.into_bucket() - } - }; - bucket.next(); - } - bucket - } - - /// Reads a bucket at a given index, returning an enum indicating whether - /// it's initialized or not. You need to match on this enum to get - /// the appropriate types to call most of the other functions in - /// this module. - pub fn peek(self) -> BucketState { - match unsafe { *self.raw.hash() } { - EMPTY_BUCKET => { - Empty(EmptyBucket { - raw: self.raw, - table: self.table, - }) - } - _ => { - Full(FullBucket { - raw: self.raw, - table: self.table, - }) - } - } - } - - /// Modifies the bucket in place to make it point to the next slot. - pub fn next(&mut self) { - self.raw.idx = self.raw.idx.wrapping_add(1) & self.table.capacity_mask; - } - - /// Modifies the bucket in place to make it point to the previous slot. - pub fn prev(&mut self) { - self.raw.idx = self.raw.idx.wrapping_sub(1) & self.table.capacity_mask; - } -} - -impl>> EmptyBucket { - #[inline] - pub fn next(self) -> Bucket { - let mut bucket = self.into_bucket(); - bucket.next(); - bucket - } - - #[inline] - pub fn into_bucket(self) -> Bucket { - Bucket { - raw: self.raw, - table: self.table, - } - } - - pub fn gap_peek(self) -> Result, Bucket> { - let gap = EmptyBucket { - raw: self.raw, - table: (), - }; - - match self.next().peek() { - Full(bucket) => { - Ok(GapThenFull { - gap, - full: bucket, - }) - } - Empty(e) => Err(e.into_bucket()), - } - } -} - -impl EmptyBucket - where M: Put -{ - /// Puts given key and value pair, along with the key's hash, - /// into this bucket in the hashtable. Note how `self` is 'moved' into - /// this function, because this slot will no longer be empty when - /// we return! A `FullBucket` is returned for later use, pointing to - /// the newly-filled slot in the hashtable. - /// - /// Use `make_hash` to construct a `SafeHash` to pass to this function. - pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket { - unsafe { - *self.raw.hash() = hash.inspect(); - ptr::write(self.raw.pair(), (key, value)); - - self.table.borrow_table_mut().size += 1; - } - - FullBucket { - raw: self.raw, - table: self.table, - } - } -} - -impl>> FullBucket { - #[inline] - pub fn next(self) -> Bucket { - let mut bucket = self.into_bucket(); - bucket.next(); - bucket - } - - #[inline] - pub fn into_bucket(self) -> Bucket { - Bucket { - raw: self.raw, - table: self.table, - } - } - - /// Duplicates the current position. This can be useful for operations - /// on two or more buckets. - pub fn stash(self) -> FullBucket { - FullBucket { - raw: self.raw, - table: self, - } - } - - /// Get the distance between this bucket and the 'ideal' location - /// as determined by the key's hash stored in it. - /// - /// In the cited blog posts above, this is called the "distance to - /// initial bucket", or DIB. Also known as "probe count". - pub fn displacement(&self) -> usize { - // Calculates the distance one has to travel when going from - // `hash mod capacity` onwards to `idx mod capacity`, wrapping around - // if the destination is not reached before the end of the table. - (self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) & self.table.capacity_mask - } - - #[inline] - pub fn hash(&self) -> SafeHash { - unsafe { SafeHash { hash: *self.raw.hash() } } - } - - /// Gets references to the key and value at a given index. - pub fn read(&self) -> (&K, &V) { - unsafe { - let pair_ptr = self.raw.pair(); - (&(*pair_ptr).0, &(*pair_ptr).1) - } - } -} - -// We take a mutable reference to the table instead of accepting anything that -// implements `DerefMut` to prevent fn `take` from being called on `stash`ed -// buckets. -impl<'t, K, V> FullBucket> { - /// Removes this bucket's key and value from the hashtable. - /// - /// This works similarly to `put`, building an `EmptyBucket` out of the - /// taken bucket. - pub fn take(self) -> (EmptyBucket>, K, V) { - self.table.size -= 1; - - unsafe { - *self.raw.hash() = EMPTY_BUCKET; - let (k, v) = ptr::read(self.raw.pair()); - (EmptyBucket { - raw: self.raw, - table: self.table, - }, - k, - v) - } - } -} - -// This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases -// where `M` is a full bucket or table reference type with mutable access to the table. -impl FullBucket - where M: Put -{ - pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) { - unsafe { - let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h); - let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v)); - - (old_hash, old_key, old_val) - } - } -} - -impl FullBucket - where M: Deref> + DerefMut -{ - /// Gets mutable references to the key and value at a given index. - pub fn read_mut(&mut self) -> (&mut K, &mut V) { - unsafe { - let pair_ptr = self.raw.pair(); - (&mut (*pair_ptr).0, &mut (*pair_ptr).1) - } - } -} - -impl<'t, K, V, M> FullBucket - where M: Deref> + 't -{ - /// Exchange a bucket state for immutable references into the table. - /// Because the underlying reference to the table is also consumed, - /// no further changes to the structure of the table are possible; - /// in exchange for this, the returned references have a longer lifetime - /// than the references returned by `read()`. - pub fn into_refs(self) -> (&'t K, &'t V) { - unsafe { - let pair_ptr = self.raw.pair(); - (&(*pair_ptr).0, &(*pair_ptr).1) - } - } -} - -impl<'t, K, V, M> FullBucket - where M: Deref> + DerefMut + 't -{ - /// This works similarly to `into_refs`, exchanging a bucket state - /// for mutable references into the table. - pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) { - unsafe { - let pair_ptr = self.raw.pair(); - (&mut (*pair_ptr).0, &mut (*pair_ptr).1) - } - } -} - -impl GapThenFull - where M: Deref> -{ - #[inline] - pub fn full(&self) -> &FullBucket { - &self.full - } - - pub fn into_table(self) -> M { - self.full.into_table() - } - - pub fn shift(mut self) -> Result, Bucket> { - unsafe { - let (gap_hash, gap_pair) = self.gap.raw.hash_pair(); - let (full_hash, full_pair) = self.full.raw.hash_pair(); - *gap_hash = mem::replace(&mut *full_hash, EMPTY_BUCKET); - ptr::copy_nonoverlapping(full_pair, gap_pair, 1); - } - - let FullBucket { raw: prev_raw, .. } = self.full; - - match self.full.next().peek() { - Full(bucket) => { - self.gap.raw = prev_raw; - - self.full = bucket; - - Ok(self) - } - Empty(b) => Err(b.into_bucket()), - } - } -} - -// Returns a Layout which describes the allocation required for a hash table, -// and the offset of the array of (key, value) pairs in the allocation. -fn calculate_layout(capacity: usize) -> Result<(Layout, usize), LayoutErr> { - let hashes = Layout::array::(capacity)?; - let pairs = Layout::array::<(K, V)>(capacity)?; - hashes.extend(pairs).map(|(layout, _)| { - // LLVM seems to have trouble properly const-propagating pairs.align(), - // possibly due to the use of NonZeroUsize. This little hack allows it - // to generate optimal code. - // - // See https://github.com/rust-lang/rust/issues/51346 for more details. - ( - layout, - hashes.size() + hashes.padding_needed_for(mem::align_of::<(K, V)>()), - ) - }) -} - -pub(crate) enum Fallibility { - Fallible, - Infallible, -} - -use self::Fallibility::*; - -impl RawTable { - /// Does not initialize the buckets. The caller should ensure they, - /// at the very least, set every hash to EMPTY_BUCKET. - /// Returns an error if it cannot allocate or capacity overflows. - unsafe fn new_uninitialized_internal( - capacity: usize, - fallibility: Fallibility, - ) -> Result, CollectionAllocErr> { - if capacity == 0 { - return Ok(RawTable { - size: 0, - capacity_mask: capacity.wrapping_sub(1), - hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint), - marker: marker::PhantomData, - }); - } - - // Allocating hashmaps is a little tricky. We need to allocate two - // arrays, but since we know their sizes and alignments up front, - // we just allocate a single array, and then have the subarrays - // point into it. - let (layout, _) = calculate_layout::(capacity)?; - let buffer = Global.alloc(layout).map_err(|e| match fallibility { - Infallible => handle_alloc_error(layout), - Fallible => e, - })?; - - Ok(RawTable { - capacity_mask: capacity.wrapping_sub(1), - size: 0, - hashes: TaggedHashUintPtr::new(buffer.cast().as_ptr()), - marker: marker::PhantomData, - }) - } - - /// Does not initialize the buckets. The caller should ensure they, - /// at the very least, set every hash to EMPTY_BUCKET. - unsafe fn new_uninitialized(capacity: usize) -> RawTable { - match Self::new_uninitialized_internal(capacity, Infallible) { - Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => unreachable!(), - Ok(table) => { table } - } - } - - fn raw_bucket_at(&self, index: usize) -> RawBucket { - let (_, pairs_offset) = calculate_layout::(self.capacity()) - .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); - let buffer = self.hashes.ptr() as *mut u8; - unsafe { - RawBucket { - hash_start: buffer as *mut HashUint, - pair_start: buffer.add(pairs_offset) as *const (K, V), - idx: index, - _marker: marker::PhantomData, - } - } - } - - fn new_internal( - capacity: usize, - fallibility: Fallibility, - ) -> Result, CollectionAllocErr> { - unsafe { - let ret = RawTable::new_uninitialized_internal(capacity, fallibility)?; - ptr::write_bytes(ret.hashes.ptr(), 0, capacity); - Ok(ret) - } - } - - /// Tries to create a new raw table from a given capacity. If it cannot allocate, - /// it returns with AllocErr. - pub fn try_new(capacity: usize) -> Result, CollectionAllocErr> { - Self::new_internal(capacity, Fallible) - } - - /// Creates a new raw table from a given capacity. All buckets are - /// initially empty. - pub fn new(capacity: usize) -> RawTable { - match Self::new_internal(capacity, Infallible) { - Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => unreachable!(), - Ok(table) => { table } - } - } - - /// The hashtable's capacity, similar to a vector's. - pub fn capacity(&self) -> usize { - self.capacity_mask.wrapping_add(1) - } - - /// The number of elements ever `put` in the hashtable, minus the number - /// of elements ever `take`n. - pub fn size(&self) -> usize { - self.size - } - - fn raw_buckets(&self) -> RawBuckets { - RawBuckets { - raw: self.raw_bucket_at(0), - elems_left: self.size, - marker: marker::PhantomData, - } - } - - pub fn iter(&self) -> Iter { - Iter { - iter: self.raw_buckets(), - } - } - - pub fn iter_mut(&mut self) -> IterMut { - IterMut { - iter: self.raw_buckets(), - _marker: marker::PhantomData, - } - } - - pub fn into_iter(self) -> IntoIter { - let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); - // Replace the marker regardless of lifetime bounds on parameters. - IntoIter { - iter: RawBuckets { - raw, - elems_left, - marker: marker::PhantomData, - }, - table: self, - } - } - - pub fn drain(&mut self) -> Drain { - let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); - // Replace the marker regardless of lifetime bounds on parameters. - Drain { - iter: RawBuckets { - raw, - elems_left, - marker: marker::PhantomData, - }, - table: NonNull::from(self), - marker: marker::PhantomData, - } - } - - /// Drops buckets in reverse order. It leaves the table in an inconsistent - /// state and should only be used for dropping the table's remaining - /// entries. It's used in the implementation of Drop. - unsafe fn rev_drop_buckets(&mut self) { - // initialize the raw bucket past the end of the table - let mut raw = self.raw_bucket_at(self.capacity()); - let mut elems_left = self.size; - - while elems_left != 0 { - raw.idx -= 1; - - if *raw.hash() != EMPTY_BUCKET { - elems_left -= 1; - ptr::drop_in_place(raw.pair()); - } - } - } - - /// Set the table tag - pub fn set_tag(&mut self, value: bool) { - self.hashes.set_tag(value) - } - - /// Get the table tag - pub fn tag(&self) -> bool { - self.hashes.tag() - } -} - -/// A raw iterator. The basis for some other iterators in this module. Although -/// this interface is safe, it's not used outside this module. -struct RawBuckets<'a, K, V> { - raw: RawBucket, - elems_left: usize, - - // Strictly speaking, this should be &'a (K,V), but that would - // require that K:'a, and we often use RawBuckets<'static...> for - // move iterations, so that messes up a lot of other things. So - // just use `&'a (K,V)` as this is not a publicly exposed type - // anyway. - marker: marker::PhantomData<&'a ()>, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -impl<'a, K, V> Clone for RawBuckets<'a, K, V> { - fn clone(&self) -> RawBuckets<'a, K, V> { - RawBuckets { - raw: self.raw, - elems_left: self.elems_left, - marker: marker::PhantomData, - } - } -} - - -impl<'a, K, V> Iterator for RawBuckets<'a, K, V> { - type Item = RawBucket; - - fn next(&mut self) -> Option> { - if self.elems_left == 0 { - return None; - } - - loop { - unsafe { - let item = self.raw; - self.raw.idx += 1; - if *item.hash() != EMPTY_BUCKET { - self.elems_left -= 1; - return Some(item); - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - (self.elems_left, Some(self.elems_left)) - } -} - -impl<'a, K, V> ExactSizeIterator for RawBuckets<'a, K, V> { - fn len(&self) -> usize { - self.elems_left - } -} - -/// Iterator over shared references to entries in a table. -pub struct Iter<'a, K: 'a, V: 'a> { - iter: RawBuckets<'a, K, V>, -} - -unsafe impl<'a, K: Sync, V: Sync> Sync for Iter<'a, K, V> {} -unsafe impl<'a, K: Sync, V: Sync> Send for Iter<'a, K, V> {} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -impl<'a, K, V> Clone for Iter<'a, K, V> { - fn clone(&self) -> Iter<'a, K, V> { - Iter { - iter: self.iter.clone(), - } - } -} - -/// Iterator over mutable references to entries in a table. -pub struct IterMut<'a, K: 'a, V: 'a> { - iter: RawBuckets<'a, K, V>, - // To ensure invariance with respect to V - _marker: marker::PhantomData<&'a mut V>, -} - -unsafe impl<'a, K: Sync, V: Sync> Sync for IterMut<'a, K, V> {} -// Both K: Sync and K: Send are correct for IterMut's Send impl, -// but Send is the more useful bound -unsafe impl<'a, K: Send, V: Send> Send for IterMut<'a, K, V> {} - -impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> { - pub fn iter(&self) -> Iter { - Iter { - iter: self.iter.clone(), - } - } -} - -/// Iterator over the entries in a table, consuming the table. -pub struct IntoIter { - table: RawTable, - iter: RawBuckets<'static, K, V>, -} - -unsafe impl Sync for IntoIter {} -unsafe impl Send for IntoIter {} - -impl IntoIter { - pub fn iter(&self) -> Iter { - Iter { - iter: self.iter.clone(), - } - } -} - -/// Iterator over the entries in a table, clearing the table. -pub struct Drain<'a, K: 'a, V: 'a> { - table: NonNull>, - iter: RawBuckets<'static, K, V>, - marker: marker::PhantomData<&'a RawTable>, -} - -unsafe impl<'a, K: Sync, V: Sync> Sync for Drain<'a, K, V> {} -unsafe impl<'a, K: Send, V: Send> Send for Drain<'a, K, V> {} - -impl<'a, K, V> Drain<'a, K, V> { - pub fn iter(&self) -> Iter { - Iter { - iter: self.iter.clone(), - } - } -} - -impl<'a, K, V> Iterator for Iter<'a, K, V> { - type Item = (&'a K, &'a V); - - fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.iter.next().map(|raw| unsafe { - let pair_ptr = raw.pair(); - (&(*pair_ptr).0, &(*pair_ptr).1) - }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl<'a, K, V> Iterator for IterMut<'a, K, V> { - type Item = (&'a K, &'a mut V); - - fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - self.iter.next().map(|raw| unsafe { - let pair_ptr = raw.pair(); - (&(*pair_ptr).0, &mut (*pair_ptr).1) - }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl Iterator for IntoIter { - type Item = (SafeHash, K, V); - - fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|raw| { - self.table.size -= 1; - unsafe { - let (k, v) = ptr::read(raw.pair()); - (SafeHash { hash: *raw.hash() }, k, v) - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for IntoIter { - fn len(&self) -> usize { - self.iter().len() - } -} - -impl<'a, K, V> Iterator for Drain<'a, K, V> { - type Item = (SafeHash, K, V); - - #[inline] - fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|raw| { - unsafe { - self.table.as_mut().size -= 1; - let (k, v) = ptr::read(raw.pair()); - (SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v) - } - }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { - fn drop(&mut self) { - self.for_each(drop); - } -} - -impl Clone for RawTable { - fn clone(&self) -> RawTable { - unsafe { - let cap = self.capacity(); - let mut new_ht = RawTable::new_uninitialized(cap); - - let mut new_buckets = new_ht.raw_bucket_at(0); - let mut buckets = self.raw_bucket_at(0); - while buckets.idx < cap { - *new_buckets.hash() = *buckets.hash(); - if *new_buckets.hash() != EMPTY_BUCKET { - let pair_ptr = buckets.pair(); - let kv = ((*pair_ptr).0.clone(), (*pair_ptr).1.clone()); - ptr::write(new_buckets.pair(), kv); - } - buckets.idx += 1; - new_buckets.idx += 1; - } - - new_ht.size = self.size(); - new_ht.set_tag(self.tag()); - - new_ht - } - } -} - -unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { - fn drop(&mut self) { - if self.capacity() == 0 { - return; - } - - // This is done in reverse because we've likely partially taken - // some elements out with `.into_iter()` from the front. - // Check if the size is 0, so we don't do a useless scan when - // dropping empty tables such as on resize. - // Also avoid double drop of elements that have been already moved out. - unsafe { - if needs_drop::<(K, V)>() { - // avoid linear runtime for types that don't need drop - self.rev_drop_buckets(); - } - } - - let (layout, _) = calculate_layout::(self.capacity()) - .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); - unsafe { - Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout); - // Remember how everything was allocated out of one buffer - // during initialization? We only need one call to free here. - } - } -} diff --git a/ctr-std/src/collections/mod.rs b/ctr-std/src/collections/mod.rs deleted file mode 100644 index 8d2c82b..0000000 --- a/ctr-std/src/collections/mod.rs +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Collection types. -//! -//! Rust's standard collection library provides efficient implementations of the -//! most common general purpose programming data structures. By using the -//! standard implementations, it should be possible for two libraries to -//! communicate without significant data conversion. -//! -//! To get this out of the way: you should probably just use [`Vec`] or [`HashMap`]. -//! These two collections cover most use cases for generic data storage and -//! processing. They are exceptionally good at doing what they do. All the other -//! collections in the standard library have specific use cases where they are -//! the optimal choice, but these cases are borderline *niche* in comparison. -//! Even when `Vec` and `HashMap` are technically suboptimal, they're probably a -//! good enough choice to get started. -//! -//! Rust's collections can be grouped into four major categories: -//! -//! * Sequences: [`Vec`], [`VecDeque`], [`LinkedList`] -//! * Maps: [`HashMap`], [`BTreeMap`] -//! * Sets: [`HashSet`], [`BTreeSet`] -//! * Misc: [`BinaryHeap`] -//! -//! # When Should You Use Which Collection? -//! -//! These are fairly high-level and quick break-downs of when each collection -//! should be considered. Detailed discussions of strengths and weaknesses of -//! individual collections can be found on their own documentation pages. -//! -//! ### Use a `Vec` when: -//! * You want to collect items up to be processed or sent elsewhere later, and -//! don't care about any properties of the actual values being stored. -//! * You want a sequence of elements in a particular order, and will only be -//! appending to (or near) the end. -//! * You want a stack. -//! * You want a resizable array. -//! * You want a heap-allocated array. -//! -//! ### Use a `VecDeque` when: -//! * You want a [`Vec`] that supports efficient insertion at both ends of the -//! sequence. -//! * You want a queue. -//! * You want a double-ended queue (deque). -//! -//! ### Use a `LinkedList` when: -//! * You want a [`Vec`] or [`VecDeque`] of unknown size, and can't tolerate -//! amortization. -//! * You want to efficiently split and append lists. -//! * You are *absolutely* certain you *really*, *truly*, want a doubly linked -//! list. -//! -//! ### Use a `HashMap` when: -//! * You want to associate arbitrary keys with an arbitrary value. -//! * You want a cache. -//! * You want a map, with no extra functionality. -//! -//! ### Use a `BTreeMap` when: -//! * You want a map sorted by its keys. -//! * You want to be able to get a range of entries on-demand. -//! * You're interested in what the smallest or largest key-value pair is. -//! * You want to find the largest or smallest key that is smaller or larger -//! than something. -//! -//! ### Use the `Set` variant of any of these `Map`s when: -//! * You just want to remember which keys you've seen. -//! * There is no meaningful value to associate with your keys. -//! * You just want a set. -//! -//! ### Use a `BinaryHeap` when: -//! -//! * You want to store a bunch of elements, but only ever want to process the -//! "biggest" or "most important" one at any given time. -//! * You want a priority queue. -//! -//! # Performance -//! -//! Choosing the right collection for the job requires an understanding of what -//! each collection is good at. Here we briefly summarize the performance of -//! different collections for certain important operations. For further details, -//! see each type's documentation, and note that the names of actual methods may -//! differ from the tables below on certain collections. -//! -//! Throughout the documentation, we will follow a few conventions. For all -//! operations, the collection's size is denoted by n. If another collection is -//! involved in the operation, it contains m elements. Operations which have an -//! *amortized* cost are suffixed with a `*`. Operations with an *expected* -//! cost are suffixed with a `~`. -//! -//! All amortized costs are for the potential need to resize when capacity is -//! exhausted. If a resize occurs it will take O(n) time. Our collections never -//! automatically shrink, so removal operations aren't amortized. Over a -//! sufficiently large series of operations, the average cost per operation will -//! deterministically equal the given cost. -//! -//! Only [`HashMap`] has expected costs, due to the probabilistic nature of hashing. -//! It is theoretically possible, though very unlikely, for [`HashMap`] to -//! experience worse performance. -//! -//! ## Sequences -//! -//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | -//! |----------------|----------------|-----------------|----------------|--------|----------------| -//! | [`Vec`] | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) | -//! | [`VecDeque`] | O(1) | O(min(i, n-i))* | O(min(i, n-i)) | O(m)* | O(min(i, n-i)) | -//! | [`LinkedList`] | O(min(i, n-i)) | O(min(i, n-i)) | O(min(i, n-i)) | O(1) | O(min(i, n-i)) | -//! -//! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and -//! [`VecDeque`] is generally going to be faster than [`LinkedList`]. -//! -//! ## Maps -//! -//! For Sets, all operations have the cost of the equivalent Map operation. -//! -//! | | get | insert | remove | predecessor | append | -//! |--------------|-----------|----------|----------|-------------|--------| -//! | [`HashMap`] | O(1)~ | O(1)~* | O(1)~ | N/A | N/A | -//! | [`BTreeMap`] | O(log n) | O(log n) | O(log n) | O(log n) | O(n+m) | -//! -//! # Correct and Efficient Usage of Collections -//! -//! Of course, knowing which collection is the right one for the job doesn't -//! instantly permit you to use it correctly. Here are some quick tips for -//! efficient and correct usage of the standard collections in general. If -//! you're interested in how to use a specific collection in particular, consult -//! its documentation for detailed discussion and code examples. -//! -//! ## Capacity Management -//! -//! Many collections provide several constructors and methods that refer to -//! "capacity". These collections are generally built on top of an array. -//! Optimally, this array would be exactly the right size to fit only the -//! elements stored in the collection, but for the collection to do this would -//! be very inefficient. If the backing array was exactly the right size at all -//! times, then every time an element is inserted, the collection would have to -//! grow the array to fit it. Due to the way memory is allocated and managed on -//! most computers, this would almost surely require allocating an entirely new -//! array and copying every single element from the old one into the new one. -//! Hopefully you can see that this wouldn't be very efficient to do on every -//! operation. -//! -//! Most collections therefore use an *amortized* allocation strategy. They -//! generally let themselves have a fair amount of unoccupied space so that they -//! only have to grow on occasion. When they do grow, they allocate a -//! substantially larger array to move the elements into so that it will take a -//! while for another grow to be required. While this strategy is great in -//! general, it would be even better if the collection *never* had to resize its -//! backing array. Unfortunately, the collection itself doesn't have enough -//! information to do this itself. Therefore, it is up to us programmers to give -//! it hints. -//! -//! Any `with_capacity` constructor will instruct the collection to allocate -//! enough space for the specified number of elements. Ideally this will be for -//! exactly that many elements, but some implementation details may prevent -//! this. [`Vec`] and [`VecDeque`] can be relied on to allocate exactly the -//! requested amount, though. Use `with_capacity` when you know exactly how many -//! elements will be inserted, or at least have a reasonable upper-bound on that -//! number. -//! -//! When anticipating a large influx of elements, the `reserve` family of -//! methods can be used to hint to the collection how much room it should make -//! for the coming items. As with `with_capacity`, the precise behavior of -//! these methods will be specific to the collection of interest. -//! -//! For optimal performance, collections will generally avoid shrinking -//! themselves. If you believe that a collection will not soon contain any more -//! elements, or just really need the memory, the `shrink_to_fit` method prompts -//! the collection to shrink the backing array to the minimum size capable of -//! holding its elements. -//! -//! Finally, if ever you're interested in what the actual capacity of the -//! collection is, most collections provide a `capacity` method to query this -//! information on demand. This can be useful for debugging purposes, or for -//! use with the `reserve` methods. -//! -//! ## Iterators -//! -//! Iterators are a powerful and robust mechanism used throughout Rust's -//! standard libraries. Iterators provide a sequence of values in a generic, -//! safe, efficient and convenient way. The contents of an iterator are usually -//! *lazily* evaluated, so that only the values that are actually needed are -//! ever actually produced, and no allocation need be done to temporarily store -//! them. Iterators are primarily consumed using a `for` loop, although many -//! functions also take iterators where a collection or sequence of values is -//! desired. -//! -//! All of the standard collections provide several iterators for performing -//! bulk manipulation of their contents. The three primary iterators almost -//! every collection should provide are `iter`, `iter_mut`, and `into_iter`. -//! Some of these are not provided on collections where it would be unsound or -//! unreasonable to provide them. -//! -//! `iter` provides an iterator of immutable references to all the contents of a -//! collection in the most "natural" order. For sequence collections like [`Vec`], -//! this means the items will be yielded in increasing order of index starting -//! at 0. For ordered collections like [`BTreeMap`], this means that the items -//! will be yielded in sorted order. For unordered collections like [`HashMap`], -//! the items will be yielded in whatever order the internal representation made -//! most convenient. This is great for reading through all the contents of the -//! collection. -//! -//! ``` -//! let vec = vec![1, 2, 3, 4]; -//! for x in vec.iter() { -//! println!("vec contained {}", x); -//! } -//! ``` -//! -//! `iter_mut` provides an iterator of *mutable* references in the same order as -//! `iter`. This is great for mutating all the contents of the collection. -//! -//! ``` -//! let mut vec = vec![1, 2, 3, 4]; -//! for x in vec.iter_mut() { -//! *x += 1; -//! } -//! ``` -//! -//! `into_iter` transforms the actual collection into an iterator over its -//! contents by-value. This is great when the collection itself is no longer -//! needed, and the values are needed elsewhere. Using `extend` with `into_iter` -//! is the main way that contents of one collection are moved into another. -//! `extend` automatically calls `into_iter`, and takes any `T: `[`IntoIterator`]. -//! Calling `collect` on an iterator itself is also a great way to convert one -//! collection into another. Both of these methods should internally use the -//! capacity management tools discussed in the previous section to do this as -//! efficiently as possible. -//! -//! ``` -//! let mut vec1 = vec![1, 2, 3, 4]; -//! let vec2 = vec![10, 20, 30, 40]; -//! vec1.extend(vec2); -//! ``` -//! -//! ``` -//! use std::collections::VecDeque; -//! -//! let vec = vec![1, 2, 3, 4]; -//! let buf: VecDeque<_> = vec.into_iter().collect(); -//! ``` -//! -//! Iterators also provide a series of *adapter* methods for performing common -//! threads to sequences. Among the adapters are functional favorites like `map`, -//! `fold`, `skip` and `take`. Of particular interest to collections is the -//! `rev` adapter, that reverses any iterator that supports this operation. Most -//! collections provide reversible iterators as the way to iterate over them in -//! reverse order. -//! -//! ``` -//! let vec = vec![1, 2, 3, 4]; -//! for x in vec.iter().rev() { -//! println!("vec contained {}", x); -//! } -//! ``` -//! -//! Several other collection methods also return iterators to yield a sequence -//! of results but avoid allocating an entire collection to store the result in. -//! This provides maximum flexibility as `collect` or `extend` can be called to -//! "pipe" the sequence into any collection if desired. Otherwise, the sequence -//! can be looped over with a `for` loop. The iterator can also be discarded -//! after partial use, preventing the computation of the unused items. -//! -//! ## Entries -//! -//! The `entry` API is intended to provide an efficient mechanism for -//! manipulating the contents of a map conditionally on the presence of a key or -//! not. The primary motivating use case for this is to provide efficient -//! accumulator maps. For instance, if one wishes to maintain a count of the -//! number of times each key has been seen, they will have to perform some -//! conditional logic on whether this is the first time the key has been seen or -//! not. Normally, this would require a `find` followed by an `insert`, -//! effectively duplicating the search effort on each insertion. -//! -//! When a user calls `map.entry(&key)`, the map will search for the key and -//! then yield a variant of the `Entry` enum. -//! -//! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case -//! the only valid operation is to `insert` a value into the entry. When this is -//! done, the vacant entry is consumed and converted into a mutable reference to -//! the value that was inserted. This allows for further manipulation of the -//! value beyond the lifetime of the search itself. This is useful if complex -//! logic needs to be performed on the value regardless of whether the value was -//! just inserted. -//! -//! If an `Occupied(entry)` is yielded, then the key *was* found. In this case, -//! the user has several options: they can `get`, `insert` or `remove` the -//! value of the occupied entry. Additionally, they can convert the occupied -//! entry into a mutable reference to its value, providing symmetry to the -//! vacant `insert` case. -//! -//! ### Examples -//! -//! Here are the two primary ways in which `entry` is used. First, a simple -//! example where the logic performed on the values is trivial. -//! -//! #### Counting the number of times each character in a string occurs -//! -//! ``` -//! use std::collections::btree_map::BTreeMap; -//! -//! let mut count = BTreeMap::new(); -//! let message = "she sells sea shells by the sea shore"; -//! -//! for c in message.chars() { -//! *count.entry(c).or_insert(0) += 1; -//! } -//! -//! assert_eq!(count.get(&'s'), Some(&8)); -//! -//! println!("Number of occurrences of each character"); -//! for (char, count) in &count { -//! println!("{}: {}", char, count); -//! } -//! ``` -//! -//! When the logic to be performed on the value is more complex, we may simply -//! use the `entry` API to ensure that the value is initialized and perform the -//! logic afterwards. -//! -//! #### Tracking the inebriation of customers at a bar -//! -//! ``` -//! use std::collections::btree_map::BTreeMap; -//! -//! // A client of the bar. They have a blood alcohol level. -//! struct Person { blood_alcohol: f32 } -//! -//! // All the orders made to the bar, by client id. -//! let orders = vec![1,2,1,2,3,4,1,2,2,3,4,1,1,1]; -//! -//! // Our clients. -//! let mut blood_alcohol = BTreeMap::new(); -//! -//! for id in orders { -//! // If this is the first time we've seen this customer, initialize them -//! // with no blood alcohol. Otherwise, just retrieve them. -//! let person = blood_alcohol.entry(id).or_insert(Person { blood_alcohol: 0.0 }); -//! -//! // Reduce their blood alcohol level. It takes time to order and drink a beer! -//! person.blood_alcohol *= 0.9; -//! -//! // Check if they're sober enough to have another beer. -//! if person.blood_alcohol > 0.3 { -//! // Too drunk... for now. -//! println!("Sorry {}, I have to cut you off", id); -//! } else { -//! // Have another! -//! person.blood_alcohol += 0.1; -//! } -//! } -//! ``` -//! -//! # Insert and complex keys -//! -//! If we have a more complex key, calls to `insert` will -//! not update the value of the key. For example: -//! -//! ``` -//! use std::cmp::Ordering; -//! use std::collections::BTreeMap; -//! use std::hash::{Hash, Hasher}; -//! -//! #[derive(Debug)] -//! struct Foo { -//! a: u32, -//! b: &'static str, -//! } -//! -//! // we will compare `Foo`s by their `a` value only. -//! impl PartialEq for Foo { -//! fn eq(&self, other: &Self) -> bool { self.a == other.a } -//! } -//! -//! impl Eq for Foo {} -//! -//! // we will hash `Foo`s by their `a` value only. -//! impl Hash for Foo { -//! fn hash(&self, h: &mut H) { self.a.hash(h); } -//! } -//! -//! impl PartialOrd for Foo { -//! fn partial_cmp(&self, other: &Self) -> Option { self.a.partial_cmp(&other.a) } -//! } -//! -//! impl Ord for Foo { -//! fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) } -//! } -//! -//! let mut map = BTreeMap::new(); -//! map.insert(Foo { a: 1, b: "baz" }, 99); -//! -//! // We already have a Foo with an a of 1, so this will be updating the value. -//! map.insert(Foo { a: 1, b: "xyz" }, 100); -//! -//! // The value has been updated... -//! assert_eq!(map.values().next().unwrap(), &100); -//! -//! // ...but the key hasn't changed. b is still "baz", not "xyz". -//! assert_eq!(map.keys().next().unwrap().b, "baz"); -//! ``` -//! -//! [`Vec`]: ../../std/vec/struct.Vec.html -//! [`HashMap`]: ../../std/collections/struct.HashMap.html -//! [`VecDeque`]: ../../std/collections/struct.VecDeque.html -//! [`LinkedList`]: ../../std/collections/struct.LinkedList.html -//! [`BTreeMap`]: ../../std/collections/struct.BTreeMap.html -//! [`HashSet`]: ../../std/collections/struct.HashSet.html -//! [`BTreeSet`]: ../../std/collections/struct.BTreeSet.html -//! [`BinaryHeap`]: ../../std/collections/struct.BinaryHeap.html -//! [`IntoIterator`]: ../../std/iter/trait.IntoIterator.html - -#![stable(feature = "rust1", since = "1.0.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.26.0")] -#[doc(hidden)] -pub use ops::Bound; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::collections::{BinaryHeap, BTreeMap, BTreeSet}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::collections::{LinkedList, VecDeque}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::collections::{binary_heap, btree_map, btree_set}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::collections::{linked_list, vec_deque}; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::hash_map::HashMap; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::hash_set::HashSet; - -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub use alloc_crate::collections::CollectionAllocErr; - -mod hash; - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod hash_map { - //! A hash map implemented with linear probing and Robin Hood bucket stealing. - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::hash::map::*; -} - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod hash_set { - //! A hash set implemented as a `HashMap` where the value is `()`. - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::hash::set::*; -} diff --git a/ctr-std/src/env.rs b/ctr-std/src/env.rs deleted file mode 100644 index 9066c0b..0000000 --- a/ctr-std/src/env.rs +++ /dev/null @@ -1,1091 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Inspection and manipulation of the process's environment. -//! -//! This module contains functions to inspect various aspects such as -//! environment variables, process arguments, the current directory, and various -//! other important directories. -//! -//! There are several functions and structs in this module that have a -//! counterpart ending in `os`. Those ending in `os` will return an [`OsString`] -//! and those without will be returning a [`String`]. -//! -//! [`OsString`]: ../../std/ffi/struct.OsString.html -//! [`String`]: ../string/struct.String.html - -#![stable(feature = "env", since = "1.0.0")] - -use error::Error; -use ffi::{OsStr, OsString}; -use fmt; -use io; -use path::{Path, PathBuf}; -use sys; -use sys::os as os_imp; - -/// Returns the current working directory as a [`PathBuf`]. -/// -/// # Errors -/// -/// Returns an [`Err`] if the current working directory value is invalid. -/// Possible cases: -/// -/// * Current directory does not exist. -/// * There are insufficient permissions to access the current directory. -/// -/// [`PathBuf`]: ../../std/path/struct.PathBuf.html -/// [`Err`]: ../../std/result/enum.Result.html#method.err -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// fn main() -> std::io::Result<()> { -/// let path = env::current_dir()?; -/// println!("The current directory is {}", path.display()); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn current_dir() -> io::Result { - os_imp::getcwd() -} - -/// Changes the current working directory to the specified path. -/// -/// Returns an [`Err`] if the operation fails. -/// -/// [`Err`]: ../../std/result/enum.Result.html#method.err -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// use std::path::Path; -/// -/// let root = Path::new("/"); -/// assert!(env::set_current_dir(&root).is_ok()); -/// println!("Successfully changed working directory to {}!", root.display()); -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn set_current_dir>(path: P) -> io::Result<()> { - os_imp::chdir(path.as_ref()) -} - -/// An iterator over a snapshot of the environment variables of this process. -/// -/// This structure is created by the [`std::env::vars`] function. See its -/// documentation for more. -/// -/// [`std::env::vars`]: fn.vars.html -#[stable(feature = "env", since = "1.0.0")] -pub struct Vars { inner: VarsOs } - -/// An iterator over a snapshot of the environment variables of this process. -/// -/// This structure is created by the [`std::env::vars_os`] function. See -/// its documentation for more. -/// -/// [`std::env::vars_os`]: fn.vars_os.html -#[stable(feature = "env", since = "1.0.0")] -pub struct VarsOs { inner: os_imp::Env } - -/// Returns an iterator of (variable, value) pairs of strings, for all the -/// environment variables of the current process. -/// -/// The returned iterator contains a snapshot of the process's environment -/// variables at the time of this invocation. Modifications to environment -/// variables afterwards will not be reflected in the returned iterator. -/// -/// # Panics -/// -/// While iterating, the returned iterator will panic if any key or value in the -/// environment is not valid unicode. If this is not desired, consider using the -/// [`env::vars_os`] function. -/// -/// [`env::vars_os`]: fn.vars_os.html -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// // We will iterate through the references to the element returned by -/// // env::vars(); -/// for (key, value) in env::vars() { -/// println!("{}: {}", key, value); -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn vars() -> Vars { - Vars { inner: vars_os() } -} - -/// Returns an iterator of (variable, value) pairs of OS strings, for all the -/// environment variables of the current process. -/// -/// The returned iterator contains a snapshot of the process's environment -/// variables at the time of this invocation. Modifications to environment -/// variables afterwards will not be reflected in the returned iterator. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// // We will iterate through the references to the element returned by -/// // env::vars_os(); -/// for (key, value) in env::vars_os() { -/// println!("{:?}: {:?}", key, value); -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn vars_os() -> VarsOs { - VarsOs { inner: os_imp::env() } -} - -#[stable(feature = "env", since = "1.0.0")] -impl Iterator for Vars { - type Item = (String, String); - fn next(&mut self) -> Option<(String, String)> { - self.inner.next().map(|(a, b)| { - (a.into_string().unwrap(), b.into_string().unwrap()) - }) - } - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Vars { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Vars { .. }") - } -} - -#[stable(feature = "env", since = "1.0.0")] -impl Iterator for VarsOs { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { self.inner.next() } - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for VarsOs { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("VarsOs { .. }") - } -} - -/// Fetches the environment variable `key` from the current process. -/// -/// # Errors -/// -/// * Environment variable is not present -/// * Environment variable is not valid unicode -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// let key = "HOME"; -/// match env::var(key) { -/// Ok(val) => println!("{}: {:?}", key, val), -/// Err(e) => println!("couldn't interpret {}: {}", key, e), -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn var>(key: K) -> Result { - _var(key.as_ref()) -} - -fn _var(key: &OsStr) -> Result { - match var_os(key) { - Some(s) => s.into_string().map_err(VarError::NotUnicode), - None => Err(VarError::NotPresent), - } -} - -/// Fetches the environment variable `key` from the current process, returning -/// [`None`] if the variable isn't set. -/// -/// [`None`]: ../option/enum.Option.html#variant.None -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// let key = "HOME"; -/// match env::var_os(key) { -/// Some(val) => println!("{}: {:?}", key, val), -/// None => println!("{} is not defined in the environment.", key) -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn var_os>(key: K) -> Option { - _var_os(key.as_ref()) -} - -fn _var_os(key: &OsStr) -> Option { - os_imp::getenv(key).unwrap_or_else(|e| { - panic!("failed to get environment variable `{:?}`: {}", key, e) - }) -} - -/// The error type for operations interacting with environment variables. -/// Possibly returned from the [`env::var`] function. -/// -/// [`env::var`]: fn.var.html -#[derive(Debug, PartialEq, Eq, Clone)] -#[stable(feature = "env", since = "1.0.0")] -pub enum VarError { - /// The specified environment variable was not present in the current - /// process's environment. - #[stable(feature = "env", since = "1.0.0")] - NotPresent, - - /// The specified environment variable was found, but it did not contain - /// valid unicode data. The found data is returned as a payload of this - /// variant. - #[stable(feature = "env", since = "1.0.0")] - NotUnicode(#[stable(feature = "env", since = "1.0.0")] OsString), -} - -#[stable(feature = "env", since = "1.0.0")] -impl fmt::Display for VarError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - VarError::NotPresent => write!(f, "environment variable not found"), - VarError::NotUnicode(ref s) => { - write!(f, "environment variable was not valid unicode: {:?}", s) - } - } - } -} - -#[stable(feature = "env", since = "1.0.0")] -impl Error for VarError { - fn description(&self) -> &str { - match *self { - VarError::NotPresent => "environment variable not found", - VarError::NotUnicode(..) => "environment variable was not valid unicode", - } - } -} - -/// Sets the environment variable `k` to the value `v` for the currently running -/// process. -/// -/// Note that while concurrent access to environment variables is safe in Rust, -/// some platforms only expose inherently unsafe non-threadsafe APIs for -/// inspecting the environment. As a result extra care needs to be taken when -/// auditing calls to unsafe external FFI functions to ensure that any external -/// environment accesses are properly synchronized with accesses in Rust. -/// -/// Discussion of this unsafety on Unix may be found in: -/// -/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188) -/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) -/// -/// # Panics -/// -/// This function may panic if `key` is empty, contains an ASCII equals sign -/// `'='` or the NUL character `'\0'`, or when the value contains the NUL -/// character. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// let key = "KEY"; -/// env::set_var(key, "VALUE"); -/// assert_eq!(env::var(key), Ok("VALUE".to_string())); -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn set_var, V: AsRef>(k: K, v: V) { - _set_var(k.as_ref(), v.as_ref()) -} - -fn _set_var(k: &OsStr, v: &OsStr) { - os_imp::setenv(k, v).unwrap_or_else(|e| { - panic!("failed to set environment variable `{:?}` to `{:?}`: {}", - k, v, e) - }) -} - -/// Removes an environment variable from the environment of the currently running process. -/// -/// Note that while concurrent access to environment variables is safe in Rust, -/// some platforms only expose inherently unsafe non-threadsafe APIs for -/// inspecting the environment. As a result extra care needs to be taken when -/// auditing calls to unsafe external FFI functions to ensure that any external -/// environment accesses are properly synchronized with accesses in Rust. -/// -/// Discussion of this unsafety on Unix may be found in: -/// -/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188) -/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) -/// -/// # Panics -/// -/// This function may panic if `key` is empty, contains an ASCII equals sign -/// `'='` or the NUL character `'\0'`, or when the value contains the NUL -/// character. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// let key = "KEY"; -/// env::set_var(key, "VALUE"); -/// assert_eq!(env::var(key), Ok("VALUE".to_string())); -/// -/// env::remove_var(key); -/// assert!(env::var(key).is_err()); -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn remove_var>(k: K) { - _remove_var(k.as_ref()) -} - -fn _remove_var(k: &OsStr) { - os_imp::unsetenv(k).unwrap_or_else(|e| { - panic!("failed to remove environment variable `{:?}`: {}", k, e) - }) -} - -/// An iterator that splits an environment variable into paths according to -/// platform-specific conventions. -/// -/// This structure is created by the [`std::env::split_paths`] function. See its -/// documentation for more. -/// -/// [`std::env::split_paths`]: fn.split_paths.html -#[stable(feature = "env", since = "1.0.0")] -pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> } - -/// Parses input according to platform conventions for the `PATH` -/// environment variable. -/// -/// Returns an iterator over the paths contained in `unparsed`. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// let key = "PATH"; -/// match env::var_os(key) { -/// Some(paths) => { -/// for path in env::split_paths(&paths) { -/// println!("'{}'", path.display()); -/// } -/// } -/// None => println!("{} is not defined in the environment.", key) -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn split_paths + ?Sized>(unparsed: &T) -> SplitPaths { - SplitPaths { inner: os_imp::split_paths(unparsed.as_ref()) } -} - -#[stable(feature = "env", since = "1.0.0")] -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { self.inner.next() } - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a> fmt::Debug for SplitPaths<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("SplitPaths { .. }") - } -} - -/// The error type for operations on the `PATH` variable. Possibly returned from -/// the [`env::join_paths`] function. -/// -/// [`env::join_paths`]: fn.join_paths.html -#[derive(Debug)] -#[stable(feature = "env", since = "1.0.0")] -pub struct JoinPathsError { - inner: os_imp::JoinPathsError -} - -/// Joins a collection of [`Path`]s appropriately for the `PATH` -/// environment variable. -/// -/// # Errors -/// -/// Returns an [`Err`][err] (containing an error message) if one of the input -/// [`Path`]s contains an invalid character for constructing the `PATH` -/// variable (a double quote on Windows or a colon on Unix). -/// -/// [`Path`]: ../../std/path/struct.Path.html -/// [`OsString`]: ../../std/ffi/struct.OsString.html -/// [err]: ../../std/result/enum.Result.html#variant.Err -/// -/// # Examples -/// -/// Joining paths on a Unix-like platform: -/// -/// ``` -/// use std::env; -/// use std::ffi::OsString; -/// use std::path::Path; -/// -/// fn main() -> Result<(), env::JoinPathsError> { -/// # if cfg!(unix) { -/// let paths = [Path::new("/bin"), Path::new("/usr/bin")]; -/// let path_os_string = env::join_paths(paths.iter())?; -/// assert_eq!(path_os_string, OsString::from("/bin:/usr/bin")); -/// # } -/// Ok(()) -/// } -/// ``` -/// -/// Joining a path containing a colon on a Unix-like platform results in an error: -/// -/// ``` -/// # if cfg!(unix) { -/// use std::env; -/// use std::path::Path; -/// -/// let paths = [Path::new("/bin"), Path::new("/usr/bi:n")]; -/// assert!(env::join_paths(paths.iter()).is_err()); -/// # } -/// ``` -/// -/// Using `env::join_paths` with `env::spit_paths` to append an item to the `PATH` environment -/// variable: -/// -/// ``` -/// use std::env; -/// use std::path::PathBuf; -/// -/// fn main() -> Result<(), env::JoinPathsError> { -/// if let Some(path) = env::var_os("PATH") { -/// let mut paths = env::split_paths(&path).collect::>(); -/// paths.push(PathBuf::from("/home/xyz/bin")); -/// let new_path = env::join_paths(paths)?; -/// env::set_var("PATH", &new_path); -/// } -/// -/// Ok(()) -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn join_paths(paths: I) -> Result - where I: IntoIterator, T: AsRef -{ - os_imp::join_paths(paths.into_iter()).map_err(|e| { - JoinPathsError { inner: e } - }) -} - -#[stable(feature = "env", since = "1.0.0")] -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.inner.fmt(f) - } -} - -#[stable(feature = "env", since = "1.0.0")] -impl Error for JoinPathsError { - fn description(&self) -> &str { self.inner.description() } -} - -/// Returns the path of the current user's home directory if known. -/// -/// # Unix -/// -/// - Returns the value of the 'HOME' environment variable if it is set -/// (including to an empty string). -/// - Otherwise, it tries to determine the home directory by invoking the `getpwuid_r` function -/// using the UID of the current user. An empty home directory field returned from the -/// `getpwuid_r` function is considered to be a valid value. -/// - Returns `None` if the current user has no entry in the /etc/passwd file. -/// -/// # Windows -/// -/// - Returns the value of the 'HOME' environment variable if it is set -/// (including to an empty string). -/// - Otherwise, returns the value of the 'USERPROFILE' environment variable if it is set -/// (including to an empty string). -/// - If both do not exist, [`GetUserProfileDirectory`][msdn] is used to return the path. -/// -/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// match env::home_dir() { -/// Some(path) => println!("Your home directory, probably: {}", path.display()), -/// None => println!("Impossible to get your home dir!"), -/// } -/// ``` -#[rustc_deprecated(since = "1.29.0", - reason = "This function's behavior is unexpected and probably not what you want. \ - Consider using the home_dir function from https://crates.io/crates/dirs instead.")] -#[stable(feature = "env", since = "1.0.0")] -pub fn home_dir() -> Option { - os_imp::home_dir() -} - -/// Returns the path of a temporary directory. -/// -/// # Unix -/// -/// Returns the value of the `TMPDIR` environment variable if it is -/// set, otherwise for non-Android it returns `/tmp`. If Android, since there -/// is no global temporary folder (it is usually allocated per-app), it returns -/// `/data/local/tmp`. -/// -/// # Windows -/// -/// Returns the value of, in order, the `TMP`, `TEMP`, -/// `USERPROFILE` environment variable if any are set and not the empty -/// string. Otherwise, `temp_dir` returns the path of the Windows directory. -/// This behavior is identical to that of [`GetTempPath`][msdn], which this -/// function uses internally. -/// -/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx -/// -/// ```no_run -/// use std::env; -/// use std::fs::File; -/// -/// fn main() -> std::io::Result<()> { -/// let mut dir = env::temp_dir(); -/// dir.push("foo.txt"); -/// -/// let f = File::create(dir)?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn temp_dir() -> PathBuf { - os_imp::temp_dir() -} - -/// Returns the full filesystem path of the current running executable. -/// -/// # Platform-specific behavior -/// -/// If the executable was invoked through a symbolic link, some platforms will -/// return the path of the symbolic link and other platforms will return the -/// path of the symbolic link’s target. -/// -/// # Errors -/// -/// Acquiring the path of the current executable is a platform-specific operation -/// that can fail for a good number of reasons. Some errors can include, but not -/// be limited to, filesystem operations failing or general syscall failures. -/// -/// # Security -/// -/// The output of this function should not be used in anything that might have -/// security implications. For example: -/// -/// ``` -/// fn main() { -/// println!("{:?}", std::env::current_exe()); -/// } -/// ``` -/// -/// On Linux systems, if this is compiled as `foo`: -/// -/// ```bash -/// $ rustc foo.rs -/// $ ./foo -/// Ok("/home/alex/foo") -/// ``` -/// -/// And you make a hard link of the program: -/// -/// ```bash -/// $ ln foo bar -/// ``` -/// -/// When you run it, you won’t get the path of the original executable, you’ll -/// get the path of the hard link: -/// -/// ```bash -/// $ ./bar -/// Ok("/home/alex/bar") -/// ``` -/// -/// This sort of behavior has been known to [lead to privilege escalation] when -/// used incorrectly. -/// -/// [lead to privilege escalation]: https://securityvulns.com/Wdocument183.html -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// match env::current_exe() { -/// Ok(exe_path) => println!("Path of this executable is: {}", -/// exe_path.display()), -/// Err(e) => println!("failed to get current exe path: {}", e), -/// }; -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn current_exe() -> io::Result { - os_imp::current_exe() -} - -/// An iterator over the arguments of a process, yielding a [`String`] value for -/// each argument. -/// -/// This struct is created by the [`std::env::args`] function. See its -/// documentation for more. -/// -/// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and may not even exist. This means this property -/// should not be relied upon for security purposes. -/// -/// [`String`]: ../string/struct.String.html -/// [`std::env::args`]: ./fn.args.html -#[stable(feature = "env", since = "1.0.0")] -pub struct Args { inner: ArgsOs } - -/// An iterator over the arguments of a process, yielding an [`OsString`] value -/// for each argument. -/// -/// This struct is created by the [`std::env::args_os`] function. See its -/// documentation for more. -/// -/// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and may not even exist. This means this property -/// should not be relied upon for security purposes. -/// -/// [`OsString`]: ../ffi/struct.OsString.html -/// [`std::env::args_os`]: ./fn.args_os.html -#[stable(feature = "env", since = "1.0.0")] -pub struct ArgsOs { inner: sys::args::Args } - -/// Returns the arguments which this program was started with (normally passed -/// via the command line). -/// -/// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and may not even exist. This means this property should -/// not be relied upon for security purposes. -/// -/// On Unix systems shell usually expands unquoted arguments with glob patterns -/// (such as `*` and `?`). On Windows this is not done, and such arguments are -/// passed as-is. -/// -/// # Panics -/// -/// The returned iterator will panic during iteration if any argument to the -/// process is not valid unicode. If this is not desired, -/// use the [`args_os`] function instead. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// // Prints each argument on a separate line -/// for argument in env::args() { -/// println!("{}", argument); -/// } -/// ``` -/// -/// [`args_os`]: ./fn.args_os.html -#[stable(feature = "env", since = "1.0.0")] -pub fn args() -> Args { - Args { inner: args_os() } -} - -/// Returns the arguments which this program was started with (normally passed -/// via the command line). -/// -/// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and it may not even exist, so this property should -/// not be relied upon for security purposes. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// // Prints each argument on a separate line -/// for argument in env::args_os() { -/// println!("{:?}", argument); -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn args_os() -> ArgsOs { - ArgsOs { inner: sys::args::args() } -} - -#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] -impl !Send for Args {} - -#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] -impl !Sync for Args {} - -#[stable(feature = "env", since = "1.0.0")] -impl Iterator for Args { - type Item = String; - fn next(&mut self) -> Option { - self.inner.next().map(|s| s.into_string().unwrap()) - } - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } -} - -#[stable(feature = "env", since = "1.0.0")] -impl ExactSizeIterator for Args { - fn len(&self) -> usize { self.inner.len() } - fn is_empty(&self) -> bool { self.inner.is_empty() } -} - -#[stable(feature = "env_iterators", since = "1.12.0")] -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.inner.next_back().map(|s| s.into_string().unwrap()) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Args") - .field("inner", &self.inner.inner.inner_debug()) - .finish() - } -} - -#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] -impl !Send for ArgsOs {} - -#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] -impl !Sync for ArgsOs {} - -#[stable(feature = "env", since = "1.0.0")] -impl Iterator for ArgsOs { - type Item = OsString; - fn next(&mut self) -> Option { self.inner.next() } - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } -} - -#[stable(feature = "env", since = "1.0.0")] -impl ExactSizeIterator for ArgsOs { - fn len(&self) -> usize { self.inner.len() } - fn is_empty(&self) -> bool { self.inner.is_empty() } -} - -#[stable(feature = "env_iterators", since = "1.12.0")] -impl DoubleEndedIterator for ArgsOs { - fn next_back(&mut self) -> Option { self.inner.next_back() } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ArgsOs { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("ArgsOs") - .field("inner", &self.inner.inner_debug()) - .finish() - } -} - -/// Constants associated with the current target -#[stable(feature = "env", since = "1.0.0")] -pub mod consts { - use sys::env::os; - - /// A string describing the architecture of the CPU that is currently - /// in use. - /// - /// Some possible values: - /// - /// - x86 - /// - x86_64 - /// - arm - /// - aarch64 - /// - mips - /// - mips64 - /// - powerpc - /// - powerpc64 - /// - s390x - /// - sparc64 - #[stable(feature = "env", since = "1.0.0")] - pub const ARCH: &'static str = super::arch::ARCH; - - /// The family of the operating system. Example value is `unix`. - /// - /// Some possible values: - /// - /// - unix - /// - windows - #[stable(feature = "env", since = "1.0.0")] - pub const FAMILY: &'static str = os::FAMILY; - - /// A string describing the specific operating system in use. - /// Example value is `linux`. - /// - /// Some possible values: - /// - /// - linux - /// - macos - /// - ios - /// - freebsd - /// - dragonfly - /// - bitrig - /// - netbsd - /// - openbsd - /// - solaris - /// - android - /// - windows - #[stable(feature = "env", since = "1.0.0")] - pub const OS: &'static str = os::OS; - - /// Specifies the filename prefix used for shared libraries on this - /// platform. Example value is `lib`. - /// - /// Some possible values: - /// - /// - lib - /// - `""` (an empty string) - #[stable(feature = "env", since = "1.0.0")] - pub const DLL_PREFIX: &'static str = os::DLL_PREFIX; - - /// Specifies the filename suffix used for shared libraries on this - /// platform. Example value is `.so`. - /// - /// Some possible values: - /// - /// - .so - /// - .dylib - /// - .dll - #[stable(feature = "env", since = "1.0.0")] - pub const DLL_SUFFIX: &'static str = os::DLL_SUFFIX; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot. Example value is `so`. - /// - /// Some possible values: - /// - /// - so - /// - dylib - /// - dll - #[stable(feature = "env", since = "1.0.0")] - pub const DLL_EXTENSION: &'static str = os::DLL_EXTENSION; - - /// Specifies the filename suffix used for executable binaries on this - /// platform. Example value is `.exe`. - /// - /// Some possible values: - /// - /// - .exe - /// - .nexe - /// - .pexe - /// - `""` (an empty string) - #[stable(feature = "env", since = "1.0.0")] - pub const EXE_SUFFIX: &'static str = os::EXE_SUFFIX; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform. Example value is `exe`. - /// - /// Some possible values: - /// - /// - exe - /// - `""` (an empty string) - #[stable(feature = "env", since = "1.0.0")] - pub const EXE_EXTENSION: &'static str = os::EXE_EXTENSION; -} - -#[cfg(target_arch = "x86")] -mod arch { - pub const ARCH: &'static str = "x86"; -} - -#[cfg(target_arch = "x86_64")] -mod arch { - pub const ARCH: &'static str = "x86_64"; -} - -#[cfg(target_arch = "arm")] -mod arch { - pub const ARCH: &'static str = "arm"; -} - -#[cfg(target_arch = "aarch64")] -mod arch { - pub const ARCH: &'static str = "aarch64"; -} - -#[cfg(target_arch = "mips")] -mod arch { - pub const ARCH: &'static str = "mips"; -} - -#[cfg(target_arch = "mips64")] -mod arch { - pub const ARCH: &'static str = "mips64"; -} - -#[cfg(target_arch = "powerpc")] -mod arch { - pub const ARCH: &'static str = "powerpc"; -} - -#[cfg(target_arch = "powerpc64")] -mod arch { - pub const ARCH: &'static str = "powerpc64"; -} - -#[cfg(target_arch = "s390x")] -mod arch { - pub const ARCH: &'static str = "s390x"; -} - -#[cfg(target_arch = "sparc64")] -mod arch { - pub const ARCH: &'static str = "sparc64"; -} - -#[cfg(target_arch = "le32")] -mod arch { - pub const ARCH: &'static str = "le32"; -} - -#[cfg(target_arch = "asmjs")] -mod arch { - pub const ARCH: &'static str = "asmjs"; -} - -#[cfg(target_arch = "wasm32")] -mod arch { - pub const ARCH: &'static str = "wasm32"; -} - -#[cfg(test)] -mod tests { - use super::*; - - use path::Path; - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn test_self_exe_path() { - let path = current_exe(); - assert!(path.is_ok()); - let path = path.unwrap(); - - // Hard to test this function - assert!(path.is_absolute()); - } - - #[test] - fn test() { - assert!((!Path::new("test-path").is_absolute())); - - current_dir().unwrap(); - } - - #[test] - #[cfg(windows)] - fn split_paths_windows() { - use path::PathBuf; - - fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { - split_paths(unparsed).collect::>() == - parsed.iter().map(|s| PathBuf::from(*s)).collect::>() - } - - assert!(check_parse("", &mut [""])); - assert!(check_parse(r#""""#, &mut [""])); - assert!(check_parse(";;", &mut ["", "", ""])); - assert!(check_parse(r"c:\", &mut [r"c:\"])); - assert!(check_parse(r"c:\;", &mut [r"c:\", ""])); - assert!(check_parse(r"c:\;c:\Program Files\", - &mut [r"c:\", r"c:\Program Files\"])); - assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"])); - assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, - &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"])); - } - - #[test] - #[cfg(unix)] - fn split_paths_unix() { - use path::PathBuf; - - fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { - split_paths(unparsed).collect::>() == - parsed.iter().map(|s| PathBuf::from(*s)).collect::>() - } - - assert!(check_parse("", &mut [""])); - assert!(check_parse("::", &mut ["", "", ""])); - assert!(check_parse("/", &mut ["/"])); - assert!(check_parse("/:", &mut ["/", ""])); - assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"])); - } - - #[test] - #[cfg(unix)] - fn join_paths_unix() { - use ffi::OsStr; - - fn test_eq(input: &[&str], output: &str) -> bool { - &*join_paths(input.iter().cloned()).unwrap() == - OsStr::new(output) - } - - assert!(test_eq(&[], "")); - assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], - "/bin:/usr/bin:/usr/local/bin")); - assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], - ":/bin:::/usr/bin:")); - assert!(join_paths(["/te:st"].iter().cloned()).is_err()); - } - - #[test] - #[cfg(windows)] - fn join_paths_windows() { - use ffi::OsStr; - - fn test_eq(input: &[&str], output: &str) -> bool { - &*join_paths(input.iter().cloned()).unwrap() == - OsStr::new(output) - } - - assert!(test_eq(&[], "")); - assert!(test_eq(&[r"c:\windows", r"c:\"], - r"c:\windows;c:\")); - assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], - r";c:\windows;;;c:\;")); - assert!(test_eq(&[r"c:\te;st", r"c:\"], - r#""c:\te;st";c:\"#)); - assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err()); - } - - #[test] - fn args_debug() { - assert_eq!( - format!("Args {{ inner: {:?} }}", args().collect::>()), - format!("{:?}", args())); - assert_eq!( - format!("ArgsOs {{ inner: {:?} }}", args_os().collect::>()), - format!("{:?}", args_os())); - } -} diff --git a/ctr-std/src/error.rs b/ctr-std/src/error.rs deleted file mode 100644 index 2953469..0000000 --- a/ctr-std/src/error.rs +++ /dev/null @@ -1,548 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Traits for working with Errors. - -#![stable(feature = "rust1", since = "1.0.0")] - -// A note about crates and the facade: -// -// Originally, the `Error` trait was defined in libcore, and the impls -// were scattered about. However, coherence objected to this -// arrangement, because to create the blanket impls for `Box` required -// knowing that `&str: !Error`, and we have no means to deal with that -// sort of conflict just now. Therefore, for the time being, we have -// moved the `Error` trait into libstd. As we evolve a sol'n to the -// coherence challenge (e.g., specialization, neg impls, etc) we can -// reconsider what crate these items belong in. - -use alloc::{AllocErr, LayoutErr, CannotReallocInPlace}; -use any::TypeId; -use borrow::Cow; -use cell; -use char; -use core::array; -use fmt::{self, Debug, Display}; -use mem::transmute; -use num; -use str; -use string; - -/// `Error` is a trait representing the basic expectations for error values, -/// i.e. values of type `E` in [`Result`]. Errors must describe -/// themselves through the [`Display`] and [`Debug`] traits, and may provide -/// cause chain information: -/// -/// The [`cause`] method is generally used when errors cross "abstraction -/// boundaries", i.e. when a one module must report an error that is "caused" -/// by an error from a lower-level module. This setup makes it possible for the -/// high-level module to provide its own errors that do not commit to any -/// particular implementation, but also reveal some of its implementation for -/// debugging via [`cause`] chains. -/// -/// [`Result`]: ../result/enum.Result.html -/// [`Display`]: ../fmt/trait.Display.html -/// [`Debug`]: ../fmt/trait.Debug.html -/// [`cause`]: trait.Error.html#method.cause -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Error: Debug + Display { - /// **This method is soft-deprecated.** - /// - /// Although using it won’t cause compilation warning, - /// new code should use [`Display`] instead - /// and new `impl`s can omit it. - /// - /// To obtain error description as a string, use `to_string()`. - /// - /// [`Display`]: ../fmt/trait.Display.html - /// - /// # Examples - /// - /// ``` - /// match "xc".parse::() { - /// Err(e) => { - /// // Print `e` itself, not `e.description()`. - /// println!("Error: {}", e); - /// } - /// _ => println!("No error"), - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn description(&self) -> &str { - "description() is deprecated; use Display" - } - - /// The lower-level cause of this error, if any. - /// - /// # Examples - /// - /// ``` - /// use std::error::Error; - /// use std::fmt; - /// - /// #[derive(Debug)] - /// struct SuperError { - /// side: SuperErrorSideKick, - /// } - /// - /// impl fmt::Display for SuperError { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - /// write!(f, "SuperError is here!") - /// } - /// } - /// - /// impl Error for SuperError { - /// fn description(&self) -> &str { - /// "I'm the superhero of errors" - /// } - /// - /// fn cause(&self) -> Option<&Error> { - /// Some(&self.side) - /// } - /// } - /// - /// #[derive(Debug)] - /// struct SuperErrorSideKick; - /// - /// impl fmt::Display for SuperErrorSideKick { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - /// write!(f, "SuperErrorSideKick is here!") - /// } - /// } - /// - /// impl Error for SuperErrorSideKick { - /// fn description(&self) -> &str { - /// "I'm SuperError side kick" - /// } - /// } - /// - /// fn get_super_error() -> Result<(), SuperError> { - /// Err(SuperError { side: SuperErrorSideKick }) - /// } - /// - /// fn main() { - /// match get_super_error() { - /// Err(e) => { - /// println!("Error: {}", e.description()); - /// println!("Caused by: {}", e.cause().unwrap()); - /// } - /// _ => println!("No error"), - /// } - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn cause(&self) -> Option<&dyn Error> { None } - - /// Get the `TypeId` of `self` - #[doc(hidden)] - #[unstable(feature = "error_type_id", - reason = "unclear whether to commit to this public implementation detail", - issue = "27745")] - fn type_id(&self) -> TypeId where Self: 'static { - TypeId::of::() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + 'a> From for Box { - fn from(err: E) -> Box { - Box::new(err) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + Send + Sync + 'a> From for Box { - fn from(err: E) -> Box { - Box::new(err) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl From for Box { - fn from(err: String) -> Box { - #[derive(Debug)] - struct StringError(String); - - impl Error for StringError { - fn description(&self) -> &str { &self.0 } - } - - impl Display for StringError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - Display::fmt(&self.0, f) - } - } - - Box::new(StringError(err)) - } -} - -#[stable(feature = "string_box_error", since = "1.6.0")] -impl From for Box { - fn from(str_err: String) -> Box { - let err1: Box = From::from(str_err); - let err2: Box = err1; - err2 - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> From<&'b str> for Box { - fn from(err: &'b str) -> Box { - From::from(String::from(err)) - } -} - -#[stable(feature = "string_box_error", since = "1.6.0")] -impl<'a> From<&'a str> for Box { - fn from(err: &'a str) -> Box { - From::from(String::from(err)) - } -} - -#[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a, 'b> From> for Box { - fn from(err: Cow<'b, str>) -> Box { - From::from(String::from(err)) - } -} - -#[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a> From> for Box { - fn from(err: Cow<'a, str>) -> Box { - From::from(String::from(err)) - } -} - -#[unstable(feature = "never_type", issue = "35121")] -impl Error for ! { - fn description(&self) -> &str { *self } -} - -#[unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked.", - issue = "32838")] -impl Error for AllocErr { - fn description(&self) -> &str { - "memory allocation failed" - } -} - -#[unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked.", - issue = "32838")] -impl Error for LayoutErr { - fn description(&self) -> &str { - "invalid parameters to Layout::from_size_align" - } -} - -#[unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked.", - issue = "32838")] -impl Error for CannotReallocInPlace { - fn description(&self) -> &str { - CannotReallocInPlace::description(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for str::ParseBoolError { - fn description(&self) -> &str { "failed to parse bool" } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for str::Utf8Error { - fn description(&self) -> &str { - "invalid utf-8: corrupt contents" - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for num::ParseIntError { - fn description(&self) -> &str { - self.__description() - } -} - -#[unstable(feature = "try_from", issue = "33417")] -impl Error for num::TryFromIntError { - fn description(&self) -> &str { - self.__description() - } -} - -#[unstable(feature = "try_from", issue = "33417")] -impl Error for array::TryFromSliceError { - fn description(&self) -> &str { - self.__description() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for num::ParseFloatError { - fn description(&self) -> &str { - self.__description() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for string::FromUtf8Error { - fn description(&self) -> &str { - "invalid utf-8" - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for string::FromUtf16Error { - fn description(&self) -> &str { - "invalid utf-16" - } -} - -#[stable(feature = "str_parse_error2", since = "1.8.0")] -impl Error for string::ParseError { - fn description(&self) -> &str { - match *self {} - } -} - -#[stable(feature = "decode_utf16", since = "1.9.0")] -impl Error for char::DecodeUtf16Error { - fn description(&self) -> &str { - "unpaired surrogate found" - } -} - -#[stable(feature = "box_error", since = "1.8.0")] -impl Error for Box { - fn description(&self) -> &str { - Error::description(&**self) - } - - fn cause(&self) -> Option<&dyn Error> { - Error::cause(&**self) - } -} - -#[stable(feature = "fmt_error", since = "1.11.0")] -impl Error for fmt::Error { - fn description(&self) -> &str { - "an error occurred when formatting an argument" - } -} - -#[stable(feature = "try_borrow", since = "1.13.0")] -impl Error for cell::BorrowError { - fn description(&self) -> &str { - "already mutably borrowed" - } -} - -#[stable(feature = "try_borrow", since = "1.13.0")] -impl Error for cell::BorrowMutError { - fn description(&self) -> &str { - "already borrowed" - } -} - -#[unstable(feature = "try_from", issue = "33417")] -impl Error for char::CharTryFromError { - fn description(&self) -> &str { - "converted integer out of range for `char`" - } -} - -#[stable(feature = "char_from_str", since = "1.20.0")] -impl Error for char::ParseCharError { - fn description(&self) -> &str { - self.__description() - } -} - -// copied from any.rs -impl dyn Error + 'static { - /// Returns true if the boxed type is the same as `T` - #[stable(feature = "error_downcast", since = "1.3.0")] - #[inline] - pub fn is(&self) -> bool { - // Get TypeId of the type this function is instantiated with - let t = TypeId::of::(); - - // Get TypeId of the type in the trait object - let boxed = self.type_id(); - - // Compare both TypeIds on equality - t == boxed - } - - /// Returns some reference to the boxed value if it is of type `T`, or - /// `None` if it isn't. - #[stable(feature = "error_downcast", since = "1.3.0")] - #[inline] - pub fn downcast_ref(&self) -> Option<&T> { - if self.is::() { - unsafe { - Some(&*(self as *const dyn Error as *const T)) - } - } else { - None - } - } - - /// Returns some mutable reference to the boxed value if it is of type `T`, or - /// `None` if it isn't. - #[stable(feature = "error_downcast", since = "1.3.0")] - #[inline] - pub fn downcast_mut(&mut self) -> Option<&mut T> { - if self.is::() { - unsafe { - Some(&mut *(self as *mut dyn Error as *mut T)) - } - } else { - None - } - } -} - -impl dyn Error + 'static + Send { - /// Forwards to the method defined on the type `Any`. - #[stable(feature = "error_downcast", since = "1.3.0")] - #[inline] - pub fn is(&self) -> bool { - ::is::(self) - } - - /// Forwards to the method defined on the type `Any`. - #[stable(feature = "error_downcast", since = "1.3.0")] - #[inline] - pub fn downcast_ref(&self) -> Option<&T> { - ::downcast_ref::(self) - } - - /// Forwards to the method defined on the type `Any`. - #[stable(feature = "error_downcast", since = "1.3.0")] - #[inline] - pub fn downcast_mut(&mut self) -> Option<&mut T> { - ::downcast_mut::(self) - } -} - -impl dyn Error + 'static + Send + Sync { - /// Forwards to the method defined on the type `Any`. - #[stable(feature = "error_downcast", since = "1.3.0")] - #[inline] - pub fn is(&self) -> bool { - ::is::(self) - } - - /// Forwards to the method defined on the type `Any`. - #[stable(feature = "error_downcast", since = "1.3.0")] - #[inline] - pub fn downcast_ref(&self) -> Option<&T> { - ::downcast_ref::(self) - } - - /// Forwards to the method defined on the type `Any`. - #[stable(feature = "error_downcast", since = "1.3.0")] - #[inline] - pub fn downcast_mut(&mut self) -> Option<&mut T> { - ::downcast_mut::(self) - } -} - -impl dyn Error { - #[inline] - #[stable(feature = "error_downcast", since = "1.3.0")] - /// Attempt to downcast the box to a concrete type. - pub fn downcast(self: Box) -> Result, Box> { - if self.is::() { - unsafe { - let raw: *mut dyn Error = Box::into_raw(self); - Ok(Box::from_raw(raw as *mut T)) - } - } else { - Err(self) - } - } -} - -impl dyn Error + Send { - #[inline] - #[stable(feature = "error_downcast", since = "1.3.0")] - /// Attempt to downcast the box to a concrete type. - pub fn downcast(self: Box) - -> Result, Box> { - let err: Box = self; - ::downcast(err).map_err(|s| unsafe { - // reapply the Send marker - transmute::, Box>(s) - }) - } -} - -impl dyn Error + Send + Sync { - #[inline] - #[stable(feature = "error_downcast", since = "1.3.0")] - /// Attempt to downcast the box to a concrete type. - pub fn downcast(self: Box) - -> Result, Box> { - let err: Box = self; - ::downcast(err).map_err(|s| unsafe { - // reapply the Send+Sync marker - transmute::, Box>(s) - }) - } -} - -#[cfg(test)] -mod tests { - use super::Error; - use fmt; - - #[derive(Debug, PartialEq)] - struct A; - #[derive(Debug, PartialEq)] - struct B; - - impl fmt::Display for A { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "A") - } - } - impl fmt::Display for B { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "B") - } - } - - impl Error for A { - fn description(&self) -> &str { "A-desc" } - } - impl Error for B { - fn description(&self) -> &str { "A-desc" } - } - - #[test] - fn downcasting() { - let mut a = A; - let a = &mut a as &mut (dyn Error + 'static); - assert_eq!(a.downcast_ref::(), Some(&A)); - assert_eq!(a.downcast_ref::(), None); - assert_eq!(a.downcast_mut::(), Some(&mut A)); - assert_eq!(a.downcast_mut::(), None); - - let a: Box = Box::new(A); - match a.downcast::() { - Ok(..) => panic!("expected error"), - Err(e) => assert_eq!(*e.downcast::().unwrap(), A), - } - } -} diff --git a/ctr-std/src/f32.rs b/ctr-std/src/f32.rs deleted file mode 100644 index 8e8340b..0000000 --- a/ctr-std/src/f32.rs +++ /dev/null @@ -1,1539 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! This module provides constants which are specific to the implementation -//! of the `f32` floating point data type. -//! -//! *[See also the `f32` primitive type](../../std/primitive.f32.html).* -//! -//! Mathematically significant numbers are provided in the `consts` sub-module. - -#![stable(feature = "rust1", since = "1.0.0")] -#![allow(missing_docs)] - -#[cfg(not(test))] -use intrinsics; -#[cfg(not(test))] -use sys::cmath; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::f32::{MIN_EXP, MAX_EXP, MIN_10_EXP}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::f32::{MAX_10_EXP, NAN, INFINITY, NEG_INFINITY}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::f32::{MIN, MIN_POSITIVE, MAX}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::f32::consts; - -#[cfg(not(test))] -#[lang = "f32_runtime"] -impl f32 { - /// Returns the largest integer less than or equal to a number. - /// - /// # Examples - /// - /// ``` - /// let f = 3.99_f32; - /// let g = 3.0_f32; - /// - /// assert_eq!(f.floor(), 3.0); - /// assert_eq!(g.floor(), 3.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn floor(self) -> f32 { - // On MSVC LLVM will lower many math intrinsics to a call to the - // corresponding function. On MSVC, however, many of these functions - // aren't actually available as symbols to call, but rather they are all - // `static inline` functions in header files. This means that from a C - // perspective it's "compatible", but not so much from an ABI - // perspective (which we're worried about). - // - // The inline header functions always just cast to a f64 and do their - // operation, so we do that here as well, but only for MSVC targets. - // - // Note that there are many MSVC-specific float operations which - // redirect to this comment, so `floorf` is just one case of a missing - // function on MSVC, but there are many others elsewhere. - #[cfg(target_env = "msvc")] - return (self as f64).floor() as f32; - #[cfg(not(target_env = "msvc"))] - return unsafe { intrinsics::floorf32(self) }; - } - - /// Returns the smallest integer greater than or equal to a number. - /// - /// # Examples - /// - /// ``` - /// let f = 3.01_f32; - /// let g = 4.0_f32; - /// - /// assert_eq!(f.ceil(), 4.0); - /// assert_eq!(g.ceil(), 4.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn ceil(self) -> f32 { - // see notes above in `floor` - #[cfg(target_env = "msvc")] - return (self as f64).ceil() as f32; - #[cfg(not(target_env = "msvc"))] - return unsafe { intrinsics::ceilf32(self) }; - } - - /// Returns the nearest integer to a number. Round half-way cases away from - /// `0.0`. - /// - /// # Examples - /// - /// ``` - /// let f = 3.3_f32; - /// let g = -3.3_f32; - /// - /// assert_eq!(f.round(), 3.0); - /// assert_eq!(g.round(), -3.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn round(self) -> f32 { - unsafe { intrinsics::roundf32(self) } - } - - /// Returns the integer part of a number. - /// - /// # Examples - /// - /// ``` - /// let f = 3.3_f32; - /// let g = -3.7_f32; - /// - /// assert_eq!(f.trunc(), 3.0); - /// assert_eq!(g.trunc(), -3.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn trunc(self) -> f32 { - unsafe { intrinsics::truncf32(self) } - } - - /// Returns the fractional part of a number. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = 3.5_f32; - /// let y = -3.5_f32; - /// let abs_difference_x = (x.fract() - 0.5).abs(); - /// let abs_difference_y = (y.fract() - (-0.5)).abs(); - /// - /// assert!(abs_difference_x <= f32::EPSILON); - /// assert!(abs_difference_y <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn fract(self) -> f32 { self - self.trunc() } - - /// Computes the absolute value of `self`. Returns `NAN` if the - /// number is `NAN`. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = 3.5_f32; - /// let y = -3.5_f32; - /// - /// let abs_difference_x = (x.abs() - x).abs(); - /// let abs_difference_y = (y.abs() - (-y)).abs(); - /// - /// assert!(abs_difference_x <= f32::EPSILON); - /// assert!(abs_difference_y <= f32::EPSILON); - /// - /// assert!(f32::NAN.abs().is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn abs(self) -> f32 { - unsafe { intrinsics::fabsf32(self) } - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `INFINITY` - /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - `NAN` if the number is `NAN` - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let f = 3.5_f32; - /// - /// assert_eq!(f.signum(), 1.0); - /// assert_eq!(f32::NEG_INFINITY.signum(), -1.0); - /// - /// assert!(f32::NAN.signum().is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn signum(self) -> f32 { - if self.is_nan() { - NAN - } else { - unsafe { intrinsics::copysignf32(1.0, self) } - } - } - - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error, yielding a more accurate result than an unfused multiply-add. - /// - /// Using `mul_add` can be more performant than an unfused multiply-add if - /// the target architecture has a dedicated `fma` CPU instruction. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let m = 10.0_f32; - /// let x = 4.0_f32; - /// let b = 60.0_f32; - /// - /// // 100.0 - /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn mul_add(self, a: f32, b: f32) -> f32 { - unsafe { intrinsics::fmaf32(self, a, b) } - } - - /// Calculates Euclidean division, the matching method for `mod_euc`. - /// - /// This computes the integer `n` such that - /// `self = n * rhs + self.mod_euc(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer `n` - /// such that `self >= n * rhs`. - /// - /// # Examples - /// - /// ``` - /// #![feature(euclidean_division)] - /// let a: f32 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 - /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 - /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 - /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 - /// ``` - #[inline] - #[unstable(feature = "euclidean_division", issue = "49048")] - pub fn div_euc(self, rhs: f32) -> f32 { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } - } - q - } - - /// Calculates the Euclidean modulo (self mod rhs), which is never negative. - /// - /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in - /// most cases. However, due to a floating point round-off error it can - /// result in `r == rhs.abs()`, violating the mathematical definition, if - /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. - /// This result is not an element of the function's codomain, but it is the - /// closest floating point number in the real numbers and thus fulfills the - /// property `self == self.div_euc(rhs) * rhs + self.mod_euc(rhs)` - /// approximatively. - /// - /// # Examples - /// - /// ``` - /// #![feature(euclidean_division)] - /// let a: f32 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.mod_euc(b), 3.0); - /// assert_eq!((-a).mod_euc(b), 1.0); - /// assert_eq!(a.mod_euc(-b), 3.0); - /// assert_eq!((-a).mod_euc(-b), 1.0); - /// // limitation due to round-off error - /// assert!((-std::f32::EPSILON).mod_euc(3.0) != 0.0); - /// ``` - #[inline] - #[unstable(feature = "euclidean_division", issue = "49048")] - pub fn mod_euc(self, rhs: f32) -> f32 { - let r = self % rhs; - if r < 0.0 { - r + rhs.abs() - } else { - r - } - } - - - /// Raises a number to an integer power. - /// - /// Using this function is generally faster than using `powf` - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = 2.0_f32; - /// let abs_difference = (x.powi(2) - x*x).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn powi(self, n: i32) -> f32 { - unsafe { intrinsics::powif32(self, n) } - } - - /// Raises a number to a floating point power. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = 2.0_f32; - /// let abs_difference = (x.powf(2.0) - x*x).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn powf(self, n: f32) -> f32 { - // see notes above in `floor` - #[cfg(target_env = "msvc")] - return (self as f64).powf(n as f64) as f32; - #[cfg(not(target_env = "msvc"))] - return unsafe { intrinsics::powf32(self, n) }; - } - - /// Takes the square root of a number. - /// - /// Returns NaN if `self` is a negative number. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let positive = 4.0_f32; - /// let negative = -4.0_f32; - /// - /// let abs_difference = (positive.sqrt() - 2.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// assert!(negative.sqrt().is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn sqrt(self) -> f32 { - if self < 0.0 { - NAN - } else { - unsafe { intrinsics::sqrtf32(self) } - } - } - - /// Returns `e^(self)`, (the exponential function). - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let one = 1.0f32; - /// // e^1 - /// let e = one.exp(); - /// - /// // ln(e) - 1 == 0 - /// let abs_difference = (e.ln() - 1.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn exp(self) -> f32 { - // see notes above in `floor` - #[cfg(target_env = "msvc")] - return (self as f64).exp() as f32; - #[cfg(not(target_env = "msvc"))] - return unsafe { intrinsics::expf32(self) }; - } - - /// Returns `2^(self)`. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let f = 2.0f32; - /// - /// // 2^2 - 4 == 0 - /// let abs_difference = (f.exp2() - 4.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn exp2(self) -> f32 { - unsafe { intrinsics::exp2f32(self) } - } - - /// Returns the natural logarithm of the number. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let one = 1.0f32; - /// // e^1 - /// let e = one.exp(); - /// - /// // ln(e) - 1 == 0 - /// let abs_difference = (e.ln() - 1.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn ln(self) -> f32 { - // see notes above in `floor` - #[cfg(target_env = "msvc")] - return (self as f64).ln() as f32; - #[cfg(not(target_env = "msvc"))] - return unsafe { intrinsics::logf32(self) }; - } - - /// Returns the logarithm of the number with respect to an arbitrary base. - /// - /// The result may not be correctly rounded owing to implementation details; - /// `self.log2()` can produce more accurate results for base 2, and - /// `self.log10()` can produce more accurate results for base 10. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let five = 5.0f32; - /// - /// // log5(5) - 1 == 0 - /// let abs_difference = (five.log(5.0) - 1.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn log(self, base: f32) -> f32 { self.ln() / base.ln() } - - /// Returns the base 2 logarithm of the number. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let two = 2.0f32; - /// - /// // log2(2) - 1 == 0 - /// let abs_difference = (two.log2() - 1.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn log2(self) -> f32 { - #[cfg(target_os = "android")] - return ::sys::android::log2f32(self); - #[cfg(not(target_os = "android"))] - return unsafe { intrinsics::log2f32(self) }; - } - - /// Returns the base 10 logarithm of the number. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let ten = 10.0f32; - /// - /// // log10(10) - 1 == 0 - /// let abs_difference = (ten.log10() - 1.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn log10(self) -> f32 { - // see notes above in `floor` - #[cfg(target_env = "msvc")] - return (self as f64).log10() as f32; - #[cfg(not(target_env = "msvc"))] - return unsafe { intrinsics::log10f32(self) }; - } - - /// The positive difference of two numbers. - /// - /// * If `self <= other`: `0:0` - /// * Else: `self - other` - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = 3.0f32; - /// let y = -3.0f32; - /// - /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs(); - /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs(); - /// - /// assert!(abs_difference_x <= f32::EPSILON); - /// assert!(abs_difference_y <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - #[rustc_deprecated(since = "1.10.0", - reason = "you probably meant `(self - other).abs()`: \ - this operation is `(self - other).max(0.0)` (also \ - known as `fdimf` in C). If you truly need the positive \ - difference, consider using that expression or the C function \ - `fdimf`, depending on how you wish to handle NaN (please consider \ - filing an issue describing your use-case too).")] - pub fn abs_sub(self, other: f32) -> f32 { - unsafe { cmath::fdimf(self, other) } - } - - /// Takes the cubic root of a number. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = 8.0f32; - /// - /// // x^(1/3) - 2 == 0 - /// let abs_difference = (x.cbrt() - 2.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn cbrt(self) -> f32 { - unsafe { cmath::cbrtf(self) } - } - - /// Calculates the length of the hypotenuse of a right-angle triangle given - /// legs of length `x` and `y`. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = 2.0f32; - /// let y = 3.0f32; - /// - /// // sqrt(x^2 + y^2) - /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn hypot(self, other: f32) -> f32 { - unsafe { cmath::hypotf(self, other) } - } - - /// Computes the sine of a number (in radians). - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = f32::consts::PI/2.0; - /// - /// let abs_difference = (x.sin() - 1.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn sin(self) -> f32 { - // see notes in `core::f32::Float::floor` - #[cfg(target_env = "msvc")] - return (self as f64).sin() as f32; - #[cfg(not(target_env = "msvc"))] - return unsafe { intrinsics::sinf32(self) }; - } - - /// Computes the cosine of a number (in radians). - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = 2.0*f32::consts::PI; - /// - /// let abs_difference = (x.cos() - 1.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn cos(self) -> f32 { - // see notes in `core::f32::Float::floor` - #[cfg(target_env = "msvc")] - return (self as f64).cos() as f32; - #[cfg(not(target_env = "msvc"))] - return unsafe { intrinsics::cosf32(self) }; - } - - /// Computes the tangent of a number (in radians). - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = f32::consts::PI / 4.0; - /// let abs_difference = (x.tan() - 1.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn tan(self) -> f32 { - unsafe { cmath::tanf(self) } - } - - /// Computes the arcsine of a number. Return value is in radians in - /// the range [-pi/2, pi/2] or NaN if the number is outside the range - /// [-1, 1]. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let f = f32::consts::PI / 2.0; - /// - /// // asin(sin(pi/2)) - /// let abs_difference = (f.sin().asin() - f32::consts::PI / 2.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn asin(self) -> f32 { - unsafe { cmath::asinf(self) } - } - - /// Computes the arccosine of a number. Return value is in radians in - /// the range [0, pi] or NaN if the number is outside the range - /// [-1, 1]. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let f = f32::consts::PI / 4.0; - /// - /// // acos(cos(pi/4)) - /// let abs_difference = (f.cos().acos() - f32::consts::PI / 4.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn acos(self) -> f32 { - unsafe { cmath::acosf(self) } - } - - /// Computes the arctangent of a number. Return value is in radians in the - /// range [-pi/2, pi/2]; - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let f = 1.0f32; - /// - /// // atan(tan(1)) - /// let abs_difference = (f.tan().atan() - 1.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn atan(self) -> f32 { - unsafe { cmath::atanf(self) } - } - - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. - /// - /// * `x = 0`, `y = 0`: `0` - /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` - /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` - /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let pi = f32::consts::PI; - /// // Positive angles measured counter-clockwise - /// // from positive x axis - /// // -pi/4 radians (45 deg clockwise) - /// let x1 = 3.0f32; - /// let y1 = -3.0f32; - /// - /// // 3pi/4 radians (135 deg counter-clockwise) - /// let x2 = -3.0f32; - /// let y2 = 3.0f32; - /// - /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); - /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); - /// - /// assert!(abs_difference_1 <= f32::EPSILON); - /// assert!(abs_difference_2 <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn atan2(self, other: f32) -> f32 { - unsafe { cmath::atan2f(self, other) } - } - - /// Simultaneously computes the sine and cosine of the number, `x`. Returns - /// `(sin(x), cos(x))`. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = f32::consts::PI/4.0; - /// let f = x.sin_cos(); - /// - /// let abs_difference_0 = (f.0 - x.sin()).abs(); - /// let abs_difference_1 = (f.1 - x.cos()).abs(); - /// - /// assert!(abs_difference_0 <= f32::EPSILON); - /// assert!(abs_difference_1 <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn sin_cos(self) -> (f32, f32) { - (self.sin(), self.cos()) - } - - /// Returns `e^(self) - 1` in a way that is accurate even if the - /// number is close to zero. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = 6.0f32; - /// - /// // e^(ln(6)) - 1 - /// let abs_difference = (x.ln().exp_m1() - 5.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn exp_m1(self) -> f32 { - unsafe { cmath::expm1f(self) } - } - - /// Returns `ln(1+n)` (natural logarithm) more accurately than if - /// the operations were performed separately. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = f32::consts::E - 1.0; - /// - /// // ln(1 + (e - 1)) == ln(e) == 1 - /// let abs_difference = (x.ln_1p() - 1.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn ln_1p(self) -> f32 { - unsafe { cmath::log1pf(self) } - } - - /// Hyperbolic sine function. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let e = f32::consts::E; - /// let x = 1.0f32; - /// - /// let f = x.sinh(); - /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` - /// let g = (e*e - 1.0)/(2.0*e); - /// let abs_difference = (f - g).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn sinh(self) -> f32 { - unsafe { cmath::sinhf(self) } - } - - /// Hyperbolic cosine function. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let e = f32::consts::E; - /// let x = 1.0f32; - /// let f = x.cosh(); - /// // Solving cosh() at 1 gives this result - /// let g = (e*e + 1.0)/(2.0*e); - /// let abs_difference = (f - g).abs(); - /// - /// // Same result - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn cosh(self) -> f32 { - unsafe { cmath::coshf(self) } - } - - /// Hyperbolic tangent function. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let e = f32::consts::E; - /// let x = 1.0f32; - /// - /// let f = x.tanh(); - /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` - /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); - /// let abs_difference = (f - g).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn tanh(self) -> f32 { - unsafe { cmath::tanhf(self) } - } - - /// Inverse hyperbolic sine function. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = 1.0f32; - /// let f = x.sinh().asinh(); - /// - /// let abs_difference = (f - x).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn asinh(self) -> f32 { - if self == NEG_INFINITY { - NEG_INFINITY - } else { - (self + ((self * self) + 1.0).sqrt()).ln() - } - } - - /// Inverse hyperbolic cosine function. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let x = 1.0f32; - /// let f = x.cosh().acosh(); - /// - /// let abs_difference = (f - x).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn acosh(self) -> f32 { - match self { - x if x < 1.0 => ::f32::NAN, - x => (x + ((x * x) - 1.0).sqrt()).ln(), - } - } - - /// Inverse hyperbolic tangent function. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// - /// let e = f32::consts::E; - /// let f = e.tanh().atanh(); - /// - /// let abs_difference = (f - e).abs(); - /// - /// assert!(abs_difference <= 1e-5); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn atanh(self) -> f32 { - 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() - } -} - -#[cfg(test)] -mod tests { - use f32; - use f32::*; - use num::*; - use num::FpCategory as Fp; - - #[test] - fn test_num_f32() { - test_num(10f32, 2f32); - } - - #[test] - fn test_min_nan() { - assert_eq!(NAN.min(2.0), 2.0); - assert_eq!(2.0f32.min(NAN), 2.0); - } - - #[test] - fn test_max_nan() { - assert_eq!(NAN.max(2.0), 2.0); - assert_eq!(2.0f32.max(NAN), 2.0); - } - - #[test] - fn test_nan() { - let nan: f32 = f32::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(!nan.is_normal()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert_eq!(Fp::Nan, nan.classify()); - } - - #[test] - fn test_infinity() { - let inf: f32 = f32::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); - } - - #[test] - fn test_neg_infinity() { - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); - } - - #[test] - fn test_zero() { - let zero: f32 = 0.0f32; - assert_eq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); - } - - #[test] - fn test_neg_zero() { - let neg_zero: f32 = -0.0; - assert_eq!(0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); - } - - #[test] - fn test_one() { - let one: f32 = 1.0f32; - assert_eq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); - } - - #[test] - fn test_is_nan() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f32.is_nan()); - assert!(!5.3f32.is_nan()); - assert!(!(-10.732f32).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); - } - - #[test] - fn test_is_infinite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f32.is_infinite()); - assert!(!42.8f32.is_infinite()); - assert!(!(-109.2f32).is_infinite()); - } - - #[test] - fn test_is_finite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f32.is_finite()); - assert!(42.8f32.is_finite()); - assert!((-109.2f32).is_finite()); - } - - #[test] - fn test_is_normal() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f32.is_normal()); - assert!(1e-37f32.is_normal()); - assert!(!1e-38f32.is_normal()); - } - - #[test] - fn test_classify() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f32.classify(), Fp::Normal); - assert_eq!(1e-37f32.classify(), Fp::Normal); - assert_eq!(1e-38f32.classify(), Fp::Subnormal); - } - - #[test] - fn test_floor() { - assert_approx_eq!(1.0f32.floor(), 1.0f32); - assert_approx_eq!(1.3f32.floor(), 1.0f32); - assert_approx_eq!(1.5f32.floor(), 1.0f32); - assert_approx_eq!(1.7f32.floor(), 1.0f32); - assert_approx_eq!(0.0f32.floor(), 0.0f32); - assert_approx_eq!((-0.0f32).floor(), -0.0f32); - assert_approx_eq!((-1.0f32).floor(), -1.0f32); - assert_approx_eq!((-1.3f32).floor(), -2.0f32); - assert_approx_eq!((-1.5f32).floor(), -2.0f32); - assert_approx_eq!((-1.7f32).floor(), -2.0f32); - } - - #[test] - fn test_ceil() { - assert_approx_eq!(1.0f32.ceil(), 1.0f32); - assert_approx_eq!(1.3f32.ceil(), 2.0f32); - assert_approx_eq!(1.5f32.ceil(), 2.0f32); - assert_approx_eq!(1.7f32.ceil(), 2.0f32); - assert_approx_eq!(0.0f32.ceil(), 0.0f32); - assert_approx_eq!((-0.0f32).ceil(), -0.0f32); - assert_approx_eq!((-1.0f32).ceil(), -1.0f32); - assert_approx_eq!((-1.3f32).ceil(), -1.0f32); - assert_approx_eq!((-1.5f32).ceil(), -1.0f32); - assert_approx_eq!((-1.7f32).ceil(), -1.0f32); - } - - #[test] - fn test_round() { - assert_approx_eq!(1.0f32.round(), 1.0f32); - assert_approx_eq!(1.3f32.round(), 1.0f32); - assert_approx_eq!(1.5f32.round(), 2.0f32); - assert_approx_eq!(1.7f32.round(), 2.0f32); - assert_approx_eq!(0.0f32.round(), 0.0f32); - assert_approx_eq!((-0.0f32).round(), -0.0f32); - assert_approx_eq!((-1.0f32).round(), -1.0f32); - assert_approx_eq!((-1.3f32).round(), -1.0f32); - assert_approx_eq!((-1.5f32).round(), -2.0f32); - assert_approx_eq!((-1.7f32).round(), -2.0f32); - } - - #[test] - fn test_trunc() { - assert_approx_eq!(1.0f32.trunc(), 1.0f32); - assert_approx_eq!(1.3f32.trunc(), 1.0f32); - assert_approx_eq!(1.5f32.trunc(), 1.0f32); - assert_approx_eq!(1.7f32.trunc(), 1.0f32); - assert_approx_eq!(0.0f32.trunc(), 0.0f32); - assert_approx_eq!((-0.0f32).trunc(), -0.0f32); - assert_approx_eq!((-1.0f32).trunc(), -1.0f32); - assert_approx_eq!((-1.3f32).trunc(), -1.0f32); - assert_approx_eq!((-1.5f32).trunc(), -1.0f32); - assert_approx_eq!((-1.7f32).trunc(), -1.0f32); - } - - #[test] - fn test_fract() { - assert_approx_eq!(1.0f32.fract(), 0.0f32); - assert_approx_eq!(1.3f32.fract(), 0.3f32); - assert_approx_eq!(1.5f32.fract(), 0.5f32); - assert_approx_eq!(1.7f32.fract(), 0.7f32); - assert_approx_eq!(0.0f32.fract(), 0.0f32); - assert_approx_eq!((-0.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.3f32).fract(), -0.3f32); - assert_approx_eq!((-1.5f32).fract(), -0.5f32); - assert_approx_eq!((-1.7f32).fract(), -0.7f32); - } - - #[test] - fn test_abs() { - assert_eq!(INFINITY.abs(), INFINITY); - assert_eq!(1f32.abs(), 1f32); - assert_eq!(0f32.abs(), 0f32); - assert_eq!((-0f32).abs(), 0f32); - assert_eq!((-1f32).abs(), 1f32); - assert_eq!(NEG_INFINITY.abs(), INFINITY); - assert_eq!((1f32/NEG_INFINITY).abs(), 0f32); - assert!(NAN.abs().is_nan()); - } - - #[test] - fn test_signum() { - assert_eq!(INFINITY.signum(), 1f32); - assert_eq!(1f32.signum(), 1f32); - assert_eq!(0f32.signum(), 1f32); - assert_eq!((-0f32).signum(), -1f32); - assert_eq!((-1f32).signum(), -1f32); - assert_eq!(NEG_INFINITY.signum(), -1f32); - assert_eq!((1f32/NEG_INFINITY).signum(), -1f32); - assert!(NAN.signum().is_nan()); - } - - #[test] - fn test_is_sign_positive() { - assert!(INFINITY.is_sign_positive()); - assert!(1f32.is_sign_positive()); - assert!(0f32.is_sign_positive()); - assert!(!(-0f32).is_sign_positive()); - assert!(!(-1f32).is_sign_positive()); - assert!(!NEG_INFINITY.is_sign_positive()); - assert!(!(1f32/NEG_INFINITY).is_sign_positive()); - assert!(NAN.is_sign_positive()); - assert!(!(-NAN).is_sign_positive()); - } - - #[test] - fn test_is_sign_negative() { - assert!(!INFINITY.is_sign_negative()); - assert!(!1f32.is_sign_negative()); - assert!(!0f32.is_sign_negative()); - assert!((-0f32).is_sign_negative()); - assert!((-1f32).is_sign_negative()); - assert!(NEG_INFINITY.is_sign_negative()); - assert!((1f32/NEG_INFINITY).is_sign_negative()); - assert!(!NAN.is_sign_negative()); - assert!((-NAN).is_sign_negative()); - } - - #[test] - fn test_mul_add() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05); - assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65); - assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2); - assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_eq!(inf.mul_add(7.8, 9.0), inf); - assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_eq!(8.9f32.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf); - } - - #[test] - fn test_recip() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.recip(), 1.0); - assert_eq!(2.0f32.recip(), 0.5); - assert_eq!((-0.4f32).recip(), -2.5); - assert_eq!(0.0f32.recip(), inf); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); - } - - #[test] - fn test_powi() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.powi(1), 1.0); - assert_approx_eq!((-3.1f32).powi(2), 9.61); - assert_approx_eq!(5.9f32.powi(-2), 0.028727); - assert_eq!(8.3f32.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_eq!(inf.powi(3), inf); - assert_eq!(neg_inf.powi(2), inf); - } - - #[test] - fn test_powf() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.powf(1.0), 1.0); - assert_approx_eq!(3.4f32.powf(4.5), 246.408218); - assert_approx_eq!(2.7f32.powf(-3.2), 0.041652); - assert_approx_eq!((-3.1f32).powf(2.0), 9.61); - assert_approx_eq!(5.9f32.powf(-2.0), 0.028727); - assert_eq!(8.3f32.powf(0.0), 1.0); - assert!(nan.powf(2.0).is_nan()); - assert_eq!(inf.powf(2.0), inf); - assert_eq!(neg_inf.powf(3.0), neg_inf); - } - - #[test] - fn test_sqrt_domain() { - assert!(NAN.sqrt().is_nan()); - assert!(NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f32).sqrt().is_nan()); - assert_eq!((-0.0f32).sqrt(), -0.0); - assert_eq!(0.0f32.sqrt(), 0.0); - assert_eq!(1.0f32.sqrt(), 1.0); - assert_eq!(INFINITY.sqrt(), INFINITY); - } - - #[test] - fn test_exp() { - assert_eq!(1.0, 0.0f32.exp()); - assert_approx_eq!(2.718282, 1.0f32.exp()); - assert_approx_eq!(148.413162, 5.0f32.exp()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); - } - - #[test] - fn test_exp2() { - assert_eq!(32.0, 5.0f32.exp2()); - assert_eq!(1.0, 0.0f32.exp2()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); - } - - #[test] - fn test_ln() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(1.0f32.exp().ln(), 1.0); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f32).ln().is_nan()); - assert_eq!((-0.0f32).ln(), neg_inf); - assert_eq!(0.0f32.ln(), neg_inf); - assert_approx_eq!(4.0f32.ln(), 1.386294); - } - - #[test] - fn test_log() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(10.0f32.log(10.0), 1.0); - assert_approx_eq!(2.3f32.log(3.5), 0.664858); - assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0); - assert!(1.0f32.log(1.0).is_nan()); - assert!(1.0f32.log(-13.9).is_nan()); - assert!(nan.log(2.3).is_nan()); - assert_eq!(inf.log(10.0), inf); - assert!(neg_inf.log(8.8).is_nan()); - assert!((-2.3f32).log(0.1).is_nan()); - assert_eq!((-0.0f32).log(2.0), neg_inf); - assert_eq!(0.0f32.log(7.0), neg_inf); - } - - #[test] - fn test_log2() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(10.0f32.log2(), 3.321928); - assert_approx_eq!(2.3f32.log2(), 1.201634); - assert_approx_eq!(1.0f32.exp().log2(), 1.442695); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f32).log2().is_nan()); - assert_eq!((-0.0f32).log2(), neg_inf); - assert_eq!(0.0f32.log2(), neg_inf); - } - - #[test] - fn test_log10() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(10.0f32.log10(), 1.0); - assert_approx_eq!(2.3f32.log10(), 0.361728); - assert_approx_eq!(1.0f32.exp().log10(), 0.434294); - assert_eq!(1.0f32.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f32).log10().is_nan()); - assert_eq!((-0.0f32).log10(), neg_inf); - assert_eq!(0.0f32.log10(), neg_inf); - } - - #[test] - fn test_to_degrees() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(0.0f32.to_degrees(), 0.0); - assert_approx_eq!((-5.8f32).to_degrees(), -332.315521); - assert_eq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); - assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); - } - - #[test] - fn test_to_radians() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(0.0f32.to_radians(), 0.0); - assert_approx_eq!(154.6f32.to_radians(), 2.698279); - assert_approx_eq!((-332.31f32).to_radians(), -5.799903); - assert_eq!(180.0f32.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); - } - - #[test] - fn test_asinh() { - assert_eq!(0.0f32.asinh(), 0.0f32); - assert_eq!((-0.0f32).asinh(), -0.0f32); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); - assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); - } - - #[test] - fn test_acosh() { - assert_eq!(1.0f32.acosh(), 0.0f32); - assert!(0.999f32.acosh().is_nan()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); - assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); - } - - #[test] - fn test_atanh() { - assert_eq!(0.0f32.atanh(), 0.0f32); - assert_eq!((-0.0f32).atanh(), -0.0f32); - - let inf32: f32 = f32::INFINITY; - let neg_inf32: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.atanh(), inf32); - assert_eq!((-1.0f32).atanh(), neg_inf32); - - assert!(2f64.atanh().atanh().is_nan()); - assert!((-2f64).atanh().atanh().is_nan()); - - let inf64: f32 = f32::INFINITY; - let neg_inf64: f32 = f32::NEG_INFINITY; - let nan32: f32 = f32::NAN; - assert!(inf64.atanh().is_nan()); - assert!(neg_inf64.atanh().is_nan()); - assert!(nan32.atanh().is_nan()); - - assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); - assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); - } - - #[test] - fn test_real_consts() { - use super::consts; - - let pi: f32 = consts::PI; - let frac_pi_2: f32 = consts::FRAC_PI_2; - let frac_pi_3: f32 = consts::FRAC_PI_3; - let frac_pi_4: f32 = consts::FRAC_PI_4; - let frac_pi_6: f32 = consts::FRAC_PI_6; - let frac_pi_8: f32 = consts::FRAC_PI_8; - let frac_1_pi: f32 = consts::FRAC_1_PI; - let frac_2_pi: f32 = consts::FRAC_2_PI; - let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI; - let sqrt2: f32 = consts::SQRT_2; - let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2; - let e: f32 = consts::E; - let log2_e: f32 = consts::LOG2_E; - let log10_e: f32 = consts::LOG10_E; - let ln_2: f32 = consts::LN_2; - let ln_10: f32 = consts::LN_10; - - assert_approx_eq!(frac_pi_2, pi / 2f32); - assert_approx_eq!(frac_pi_3, pi / 3f32); - assert_approx_eq!(frac_pi_4, pi / 4f32); - assert_approx_eq!(frac_pi_6, pi / 6f32); - assert_approx_eq!(frac_pi_8, pi / 8f32); - assert_approx_eq!(frac_1_pi, 1f32 / pi); - assert_approx_eq!(frac_2_pi, 2f32 / pi); - assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt()); - assert_approx_eq!(sqrt2, 2f32.sqrt()); - assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt()); - assert_approx_eq!(log2_e, e.log2()); - assert_approx_eq!(log10_e, e.log10()); - assert_approx_eq!(ln_2, 2f32.ln()); - assert_approx_eq!(ln_10, 10f32.ln()); - } - - #[test] - fn test_float_bits_conv() { - assert_eq!((1f32).to_bits(), 0x3f800000); - assert_eq!((12.5f32).to_bits(), 0x41480000); - assert_eq!((1337f32).to_bits(), 0x44a72000); - assert_eq!((-14.25f32).to_bits(), 0xc1640000); - assert_approx_eq!(f32::from_bits(0x3f800000), 1.0); - assert_approx_eq!(f32::from_bits(0x41480000), 12.5); - assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); - assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signalingness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA; - let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555; - assert!(f32::from_bits(masked_nan1).is_nan()); - assert!(f32::from_bits(masked_nan2).is_nan()); - - assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2); - } -} diff --git a/ctr-std/src/f64.rs b/ctr-std/src/f64.rs deleted file mode 100644 index 6880294..0000000 --- a/ctr-std/src/f64.rs +++ /dev/null @@ -1,1480 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! This module provides constants which are specific to the implementation -//! of the `f64` floating point data type. -//! -//! *[See also the `f64` primitive type](../../std/primitive.f64.html).* -//! -//! Mathematically significant numbers are provided in the `consts` sub-module. - -#![stable(feature = "rust1", since = "1.0.0")] -#![allow(missing_docs)] - -#[cfg(not(test))] -use intrinsics; -#[cfg(not(test))] -use sys::cmath; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::f64::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::f64::{MIN_EXP, MAX_EXP, MIN_10_EXP}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::f64::{MAX_10_EXP, NAN, INFINITY, NEG_INFINITY}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::f64::{MIN, MIN_POSITIVE, MAX}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::f64::consts; - -#[cfg(not(test))] -#[lang = "f64_runtime"] -impl f64 { - /// Returns the largest integer less than or equal to a number. - /// - /// # Examples - /// - /// ``` - /// let f = 3.99_f64; - /// let g = 3.0_f64; - /// - /// assert_eq!(f.floor(), 3.0); - /// assert_eq!(g.floor(), 3.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn floor(self) -> f64 { - unsafe { intrinsics::floorf64(self) } - } - - /// Returns the smallest integer greater than or equal to a number. - /// - /// # Examples - /// - /// ``` - /// let f = 3.01_f64; - /// let g = 4.0_f64; - /// - /// assert_eq!(f.ceil(), 4.0); - /// assert_eq!(g.ceil(), 4.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn ceil(self) -> f64 { - unsafe { intrinsics::ceilf64(self) } - } - - /// Returns the nearest integer to a number. Round half-way cases away from - /// `0.0`. - /// - /// # Examples - /// - /// ``` - /// let f = 3.3_f64; - /// let g = -3.3_f64; - /// - /// assert_eq!(f.round(), 3.0); - /// assert_eq!(g.round(), -3.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn round(self) -> f64 { - unsafe { intrinsics::roundf64(self) } - } - - /// Returns the integer part of a number. - /// - /// # Examples - /// - /// ``` - /// let f = 3.3_f64; - /// let g = -3.7_f64; - /// - /// assert_eq!(f.trunc(), 3.0); - /// assert_eq!(g.trunc(), -3.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn trunc(self) -> f64 { - unsafe { intrinsics::truncf64(self) } - } - - /// Returns the fractional part of a number. - /// - /// # Examples - /// - /// ``` - /// let x = 3.5_f64; - /// let y = -3.5_f64; - /// let abs_difference_x = (x.fract() - 0.5).abs(); - /// let abs_difference_y = (y.fract() - (-0.5)).abs(); - /// - /// assert!(abs_difference_x < 1e-10); - /// assert!(abs_difference_y < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn fract(self) -> f64 { self - self.trunc() } - - /// Computes the absolute value of `self`. Returns `NAN` if the - /// number is `NAN`. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let x = 3.5_f64; - /// let y = -3.5_f64; - /// - /// let abs_difference_x = (x.abs() - x).abs(); - /// let abs_difference_y = (y.abs() - (-y)).abs(); - /// - /// assert!(abs_difference_x < 1e-10); - /// assert!(abs_difference_y < 1e-10); - /// - /// assert!(f64::NAN.abs().is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn abs(self) -> f64 { - unsafe { intrinsics::fabsf64(self) } - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `INFINITY` - /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - `NAN` if the number is `NAN` - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let f = 3.5_f64; - /// - /// assert_eq!(f.signum(), 1.0); - /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0); - /// - /// assert!(f64::NAN.signum().is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn signum(self) -> f64 { - if self.is_nan() { - NAN - } else { - unsafe { intrinsics::copysignf64(1.0, self) } - } - } - - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error, yielding a more accurate result than an unfused multiply-add. - /// - /// Using `mul_add` can be more performant than an unfused multiply-add if - /// the target architecture has a dedicated `fma` CPU instruction. - /// - /// # Examples - /// - /// ``` - /// let m = 10.0_f64; - /// let x = 4.0_f64; - /// let b = 60.0_f64; - /// - /// // 100.0 - /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn mul_add(self, a: f64, b: f64) -> f64 { - unsafe { intrinsics::fmaf64(self, a, b) } - } - - /// Calculates Euclidean division, the matching method for `mod_euc`. - /// - /// This computes the integer `n` such that - /// `self = n * rhs + self.mod_euc(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer `n` - /// such that `self >= n * rhs`. - /// - /// # Examples - /// - /// ``` - /// #![feature(euclidean_division)] - /// let a: f64 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 - /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 - /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 - /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 - /// ``` - #[inline] - #[unstable(feature = "euclidean_division", issue = "49048")] - pub fn div_euc(self, rhs: f64) -> f64 { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } - } - q - } - - /// Calculates the Euclidean modulo (self mod rhs), which is never negative. - /// - /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in - /// most cases. However, due to a floating point round-off error it can - /// result in `r == rhs.abs()`, violating the mathematical definition, if - /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. - /// This result is not an element of the function's codomain, but it is the - /// closest floating point number in the real numbers and thus fulfills the - /// property `self == self.div_euc(rhs) * rhs + self.mod_euc(rhs)` - /// approximatively. - /// - /// # Examples - /// - /// ``` - /// #![feature(euclidean_division)] - /// let a: f64 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.mod_euc(b), 3.0); - /// assert_eq!((-a).mod_euc(b), 1.0); - /// assert_eq!(a.mod_euc(-b), 3.0); - /// assert_eq!((-a).mod_euc(-b), 1.0); - /// // limitation due to round-off error - /// assert!((-std::f64::EPSILON).mod_euc(3.0) != 0.0); - /// ``` - #[inline] - #[unstable(feature = "euclidean_division", issue = "49048")] - pub fn mod_euc(self, rhs: f64) -> f64 { - let r = self % rhs; - if r < 0.0 { - r + rhs.abs() - } else { - r - } - } - - /// Raises a number to an integer power. - /// - /// Using this function is generally faster than using `powf` - /// - /// # Examples - /// - /// ``` - /// let x = 2.0_f64; - /// let abs_difference = (x.powi(2) - x*x).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn powi(self, n: i32) -> f64 { - unsafe { intrinsics::powif64(self, n) } - } - - /// Raises a number to a floating point power. - /// - /// # Examples - /// - /// ``` - /// let x = 2.0_f64; - /// let abs_difference = (x.powf(2.0) - x*x).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn powf(self, n: f64) -> f64 { - unsafe { intrinsics::powf64(self, n) } - } - - /// Takes the square root of a number. - /// - /// Returns NaN if `self` is a negative number. - /// - /// # Examples - /// - /// ``` - /// let positive = 4.0_f64; - /// let negative = -4.0_f64; - /// - /// let abs_difference = (positive.sqrt() - 2.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// assert!(negative.sqrt().is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn sqrt(self) -> f64 { - if self < 0.0 { - NAN - } else { - unsafe { intrinsics::sqrtf64(self) } - } - } - - /// Returns `e^(self)`, (the exponential function). - /// - /// # Examples - /// - /// ``` - /// let one = 1.0_f64; - /// // e^1 - /// let e = one.exp(); - /// - /// // ln(e) - 1 == 0 - /// let abs_difference = (e.ln() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn exp(self) -> f64 { - unsafe { intrinsics::expf64(self) } - } - - /// Returns `2^(self)`. - /// - /// # Examples - /// - /// ``` - /// let f = 2.0_f64; - /// - /// // 2^2 - 4 == 0 - /// let abs_difference = (f.exp2() - 4.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn exp2(self) -> f64 { - unsafe { intrinsics::exp2f64(self) } - } - - /// Returns the natural logarithm of the number. - /// - /// # Examples - /// - /// ``` - /// let one = 1.0_f64; - /// // e^1 - /// let e = one.exp(); - /// - /// // ln(e) - 1 == 0 - /// let abs_difference = (e.ln() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn ln(self) -> f64 { - self.log_wrapper(|n| { unsafe { intrinsics::logf64(n) } }) - } - - /// Returns the logarithm of the number with respect to an arbitrary base. - /// - /// The result may not be correctly rounded owing to implementation details; - /// `self.log2()` can produce more accurate results for base 2, and - /// `self.log10()` can produce more accurate results for base 10. - /// - /// # Examples - /// - /// ``` - /// let five = 5.0_f64; - /// - /// // log5(5) - 1 == 0 - /// let abs_difference = (five.log(5.0) - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn log(self, base: f64) -> f64 { self.ln() / base.ln() } - - /// Returns the base 2 logarithm of the number. - /// - /// # Examples - /// - /// ``` - /// let two = 2.0_f64; - /// - /// // log2(2) - 1 == 0 - /// let abs_difference = (two.log2() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn log2(self) -> f64 { - self.log_wrapper(|n| { - #[cfg(target_os = "android")] - return ::sys::android::log2f64(n); - #[cfg(not(target_os = "android"))] - return unsafe { intrinsics::log2f64(n) }; - }) - } - - /// Returns the base 10 logarithm of the number. - /// - /// # Examples - /// - /// ``` - /// let ten = 10.0_f64; - /// - /// // log10(10) - 1 == 0 - /// let abs_difference = (ten.log10() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn log10(self) -> f64 { - self.log_wrapper(|n| { unsafe { intrinsics::log10f64(n) } }) - } - - /// The positive difference of two numbers. - /// - /// * If `self <= other`: `0:0` - /// * Else: `self - other` - /// - /// # Examples - /// - /// ``` - /// let x = 3.0_f64; - /// let y = -3.0_f64; - /// - /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs(); - /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs(); - /// - /// assert!(abs_difference_x < 1e-10); - /// assert!(abs_difference_y < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - #[rustc_deprecated(since = "1.10.0", - reason = "you probably meant `(self - other).abs()`: \ - this operation is `(self - other).max(0.0)` (also \ - known as `fdim` in C). If you truly need the positive \ - difference, consider using that expression or the C function \ - `fdim`, depending on how you wish to handle NaN (please consider \ - filing an issue describing your use-case too).")] - pub fn abs_sub(self, other: f64) -> f64 { - unsafe { cmath::fdim(self, other) } - } - - /// Takes the cubic root of a number. - /// - /// # Examples - /// - /// ``` - /// let x = 8.0_f64; - /// - /// // x^(1/3) - 2 == 0 - /// let abs_difference = (x.cbrt() - 2.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn cbrt(self) -> f64 { - unsafe { cmath::cbrt(self) } - } - - /// Calculates the length of the hypotenuse of a right-angle triangle given - /// legs of length `x` and `y`. - /// - /// # Examples - /// - /// ``` - /// let x = 2.0_f64; - /// let y = 3.0_f64; - /// - /// // sqrt(x^2 + y^2) - /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn hypot(self, other: f64) -> f64 { - unsafe { cmath::hypot(self, other) } - } - - /// Computes the sine of a number (in radians). - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let x = f64::consts::PI/2.0; - /// - /// let abs_difference = (x.sin() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn sin(self) -> f64 { - unsafe { intrinsics::sinf64(self) } - } - - /// Computes the cosine of a number (in radians). - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let x = 2.0*f64::consts::PI; - /// - /// let abs_difference = (x.cos() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn cos(self) -> f64 { - unsafe { intrinsics::cosf64(self) } - } - - /// Computes the tangent of a number (in radians). - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let x = f64::consts::PI/4.0; - /// let abs_difference = (x.tan() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-14); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn tan(self) -> f64 { - unsafe { cmath::tan(self) } - } - - /// Computes the arcsine of a number. Return value is in radians in - /// the range [-pi/2, pi/2] or NaN if the number is outside the range - /// [-1, 1]. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let f = f64::consts::PI / 2.0; - /// - /// // asin(sin(pi/2)) - /// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn asin(self) -> f64 { - unsafe { cmath::asin(self) } - } - - /// Computes the arccosine of a number. Return value is in radians in - /// the range [0, pi] or NaN if the number is outside the range - /// [-1, 1]. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let f = f64::consts::PI / 4.0; - /// - /// // acos(cos(pi/4)) - /// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn acos(self) -> f64 { - unsafe { cmath::acos(self) } - } - - /// Computes the arctangent of a number. Return value is in radians in the - /// range [-pi/2, pi/2]; - /// - /// # Examples - /// - /// ``` - /// let f = 1.0_f64; - /// - /// // atan(tan(1)) - /// let abs_difference = (f.tan().atan() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn atan(self) -> f64 { - unsafe { cmath::atan(self) } - } - - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. - /// - /// * `x = 0`, `y = 0`: `0` - /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` - /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` - /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let pi = f64::consts::PI; - /// // Positive angles measured counter-clockwise - /// // from positive x axis - /// // -pi/4 radians (45 deg clockwise) - /// let x1 = 3.0_f64; - /// let y1 = -3.0_f64; - /// - /// // 3pi/4 radians (135 deg counter-clockwise) - /// let x2 = -3.0_f64; - /// let y2 = 3.0_f64; - /// - /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); - /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); - /// - /// assert!(abs_difference_1 < 1e-10); - /// assert!(abs_difference_2 < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn atan2(self, other: f64) -> f64 { - unsafe { cmath::atan2(self, other) } - } - - /// Simultaneously computes the sine and cosine of the number, `x`. Returns - /// `(sin(x), cos(x))`. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let x = f64::consts::PI/4.0; - /// let f = x.sin_cos(); - /// - /// let abs_difference_0 = (f.0 - x.sin()).abs(); - /// let abs_difference_1 = (f.1 - x.cos()).abs(); - /// - /// assert!(abs_difference_0 < 1e-10); - /// assert!(abs_difference_1 < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn sin_cos(self) -> (f64, f64) { - (self.sin(), self.cos()) - } - - /// Returns `e^(self) - 1` in a way that is accurate even if the - /// number is close to zero. - /// - /// # Examples - /// - /// ``` - /// let x = 7.0_f64; - /// - /// // e^(ln(7)) - 1 - /// let abs_difference = (x.ln().exp_m1() - 6.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn exp_m1(self) -> f64 { - unsafe { cmath::expm1(self) } - } - - /// Returns `ln(1+n)` (natural logarithm) more accurately than if - /// the operations were performed separately. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let x = f64::consts::E - 1.0; - /// - /// // ln(1 + (e - 1)) == ln(e) == 1 - /// let abs_difference = (x.ln_1p() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn ln_1p(self) -> f64 { - unsafe { cmath::log1p(self) } - } - - /// Hyperbolic sine function. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let e = f64::consts::E; - /// let x = 1.0_f64; - /// - /// let f = x.sinh(); - /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` - /// let g = (e*e - 1.0)/(2.0*e); - /// let abs_difference = (f - g).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn sinh(self) -> f64 { - unsafe { cmath::sinh(self) } - } - - /// Hyperbolic cosine function. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let e = f64::consts::E; - /// let x = 1.0_f64; - /// let f = x.cosh(); - /// // Solving cosh() at 1 gives this result - /// let g = (e*e + 1.0)/(2.0*e); - /// let abs_difference = (f - g).abs(); - /// - /// // Same result - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn cosh(self) -> f64 { - unsafe { cmath::cosh(self) } - } - - /// Hyperbolic tangent function. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let e = f64::consts::E; - /// let x = 1.0_f64; - /// - /// let f = x.tanh(); - /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` - /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); - /// let abs_difference = (f - g).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn tanh(self) -> f64 { - unsafe { cmath::tanh(self) } - } - - /// Inverse hyperbolic sine function. - /// - /// # Examples - /// - /// ``` - /// let x = 1.0_f64; - /// let f = x.sinh().asinh(); - /// - /// let abs_difference = (f - x).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn asinh(self) -> f64 { - if self == NEG_INFINITY { - NEG_INFINITY - } else { - (self + ((self * self) + 1.0).sqrt()).ln() - } - } - - /// Inverse hyperbolic cosine function. - /// - /// # Examples - /// - /// ``` - /// let x = 1.0_f64; - /// let f = x.cosh().acosh(); - /// - /// let abs_difference = (f - x).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn acosh(self) -> f64 { - match self { - x if x < 1.0 => NAN, - x => (x + ((x * x) - 1.0).sqrt()).ln(), - } - } - - /// Inverse hyperbolic tangent function. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// - /// let e = f64::consts::E; - /// let f = e.tanh().atanh(); - /// - /// let abs_difference = (f - e).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn atanh(self) -> f64 { - 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() - } - - // Solaris/Illumos requires a wrapper around log, log2, and log10 functions - // because of their non-standard behavior (e.g. log(-n) returns -Inf instead - // of expected NaN). - fn log_wrapper f64>(self, log_fn: F) -> f64 { - if !cfg!(target_os = "solaris") { - log_fn(self) - } else { - if self.is_finite() { - if self > 0.0 { - log_fn(self) - } else if self == 0.0 { - NEG_INFINITY // log(0) = -Inf - } else { - NAN // log(-n) = NaN - } - } else if self.is_nan() { - self // log(NaN) = NaN - } else if self > 0.0 { - self // log(Inf) = Inf - } else { - NAN // log(-Inf) = NaN - } - } - } -} - -#[cfg(test)] -mod tests { - use f64; - use f64::*; - use num::*; - use num::FpCategory as Fp; - - #[test] - fn test_num_f64() { - test_num(10f64, 2f64); - } - - #[test] - fn test_min_nan() { - assert_eq!(NAN.min(2.0), 2.0); - assert_eq!(2.0f64.min(NAN), 2.0); - } - - #[test] - fn test_max_nan() { - assert_eq!(NAN.max(2.0), 2.0); - assert_eq!(2.0f64.max(NAN), 2.0); - } - - #[test] - fn test_nan() { - let nan: f64 = NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(!nan.is_normal()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert_eq!(Fp::Nan, nan.classify()); - } - - #[test] - fn test_infinity() { - let inf: f64 = INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); - } - - #[test] - fn test_neg_infinity() { - let neg_inf: f64 = NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); - } - - #[test] - fn test_zero() { - let zero: f64 = 0.0f64; - assert_eq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); - } - - #[test] - fn test_neg_zero() { - let neg_zero: f64 = -0.0; - assert_eq!(0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); - } - - #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 - #[test] - fn test_one() { - let one: f64 = 1.0f64; - assert_eq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); - } - - #[test] - fn test_is_nan() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f64.is_nan()); - assert!(!5.3f64.is_nan()); - assert!(!(-10.732f64).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); - } - - #[test] - fn test_is_infinite() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f64.is_infinite()); - assert!(!42.8f64.is_infinite()); - assert!(!(-109.2f64).is_infinite()); - } - - #[test] - fn test_is_finite() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f64.is_finite()); - assert!(42.8f64.is_finite()); - assert!((-109.2f64).is_finite()); - } - - #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 - #[test] - fn test_is_normal() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f64.is_normal()); - assert!(1e-307f64.is_normal()); - assert!(!1e-308f64.is_normal()); - } - - #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 - #[test] - fn test_classify() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1e-307f64.classify(), Fp::Normal); - assert_eq!(1e-308f64.classify(), Fp::Subnormal); - } - - #[test] - fn test_floor() { - assert_approx_eq!(1.0f64.floor(), 1.0f64); - assert_approx_eq!(1.3f64.floor(), 1.0f64); - assert_approx_eq!(1.5f64.floor(), 1.0f64); - assert_approx_eq!(1.7f64.floor(), 1.0f64); - assert_approx_eq!(0.0f64.floor(), 0.0f64); - assert_approx_eq!((-0.0f64).floor(), -0.0f64); - assert_approx_eq!((-1.0f64).floor(), -1.0f64); - assert_approx_eq!((-1.3f64).floor(), -2.0f64); - assert_approx_eq!((-1.5f64).floor(), -2.0f64); - assert_approx_eq!((-1.7f64).floor(), -2.0f64); - } - - #[test] - fn test_ceil() { - assert_approx_eq!(1.0f64.ceil(), 1.0f64); - assert_approx_eq!(1.3f64.ceil(), 2.0f64); - assert_approx_eq!(1.5f64.ceil(), 2.0f64); - assert_approx_eq!(1.7f64.ceil(), 2.0f64); - assert_approx_eq!(0.0f64.ceil(), 0.0f64); - assert_approx_eq!((-0.0f64).ceil(), -0.0f64); - assert_approx_eq!((-1.0f64).ceil(), -1.0f64); - assert_approx_eq!((-1.3f64).ceil(), -1.0f64); - assert_approx_eq!((-1.5f64).ceil(), -1.0f64); - assert_approx_eq!((-1.7f64).ceil(), -1.0f64); - } - - #[test] - fn test_round() { - assert_approx_eq!(1.0f64.round(), 1.0f64); - assert_approx_eq!(1.3f64.round(), 1.0f64); - assert_approx_eq!(1.5f64.round(), 2.0f64); - assert_approx_eq!(1.7f64.round(), 2.0f64); - assert_approx_eq!(0.0f64.round(), 0.0f64); - assert_approx_eq!((-0.0f64).round(), -0.0f64); - assert_approx_eq!((-1.0f64).round(), -1.0f64); - assert_approx_eq!((-1.3f64).round(), -1.0f64); - assert_approx_eq!((-1.5f64).round(), -2.0f64); - assert_approx_eq!((-1.7f64).round(), -2.0f64); - } - - #[test] - fn test_trunc() { - assert_approx_eq!(1.0f64.trunc(), 1.0f64); - assert_approx_eq!(1.3f64.trunc(), 1.0f64); - assert_approx_eq!(1.5f64.trunc(), 1.0f64); - assert_approx_eq!(1.7f64.trunc(), 1.0f64); - assert_approx_eq!(0.0f64.trunc(), 0.0f64); - assert_approx_eq!((-0.0f64).trunc(), -0.0f64); - assert_approx_eq!((-1.0f64).trunc(), -1.0f64); - assert_approx_eq!((-1.3f64).trunc(), -1.0f64); - assert_approx_eq!((-1.5f64).trunc(), -1.0f64); - assert_approx_eq!((-1.7f64).trunc(), -1.0f64); - } - - #[test] - fn test_fract() { - assert_approx_eq!(1.0f64.fract(), 0.0f64); - assert_approx_eq!(1.3f64.fract(), 0.3f64); - assert_approx_eq!(1.5f64.fract(), 0.5f64); - assert_approx_eq!(1.7f64.fract(), 0.7f64); - assert_approx_eq!(0.0f64.fract(), 0.0f64); - assert_approx_eq!((-0.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.3f64).fract(), -0.3f64); - assert_approx_eq!((-1.5f64).fract(), -0.5f64); - assert_approx_eq!((-1.7f64).fract(), -0.7f64); - } - - #[test] - fn test_abs() { - assert_eq!(INFINITY.abs(), INFINITY); - assert_eq!(1f64.abs(), 1f64); - assert_eq!(0f64.abs(), 0f64); - assert_eq!((-0f64).abs(), 0f64); - assert_eq!((-1f64).abs(), 1f64); - assert_eq!(NEG_INFINITY.abs(), INFINITY); - assert_eq!((1f64/NEG_INFINITY).abs(), 0f64); - assert!(NAN.abs().is_nan()); - } - - #[test] - fn test_signum() { - assert_eq!(INFINITY.signum(), 1f64); - assert_eq!(1f64.signum(), 1f64); - assert_eq!(0f64.signum(), 1f64); - assert_eq!((-0f64).signum(), -1f64); - assert_eq!((-1f64).signum(), -1f64); - assert_eq!(NEG_INFINITY.signum(), -1f64); - assert_eq!((1f64/NEG_INFINITY).signum(), -1f64); - assert!(NAN.signum().is_nan()); - } - - #[test] - fn test_is_sign_positive() { - assert!(INFINITY.is_sign_positive()); - assert!(1f64.is_sign_positive()); - assert!(0f64.is_sign_positive()); - assert!(!(-0f64).is_sign_positive()); - assert!(!(-1f64).is_sign_positive()); - assert!(!NEG_INFINITY.is_sign_positive()); - assert!(!(1f64/NEG_INFINITY).is_sign_positive()); - assert!(NAN.is_sign_positive()); - assert!(!(-NAN).is_sign_positive()); - } - - #[test] - fn test_is_sign_negative() { - assert!(!INFINITY.is_sign_negative()); - assert!(!1f64.is_sign_negative()); - assert!(!0f64.is_sign_negative()); - assert!((-0f64).is_sign_negative()); - assert!((-1f64).is_sign_negative()); - assert!(NEG_INFINITY.is_sign_negative()); - assert!((1f64/NEG_INFINITY).is_sign_negative()); - assert!(!NAN.is_sign_negative()); - assert!((-NAN).is_sign_negative()); - } - - #[test] - fn test_mul_add() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05); - assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65); - assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2); - assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_eq!(inf.mul_add(7.8, 9.0), inf); - assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_eq!(8.9f64.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); - } - - #[test] - fn test_recip() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert_eq!(1.0f64.recip(), 1.0); - assert_eq!(2.0f64.recip(), 0.5); - assert_eq!((-0.4f64).recip(), -2.5); - assert_eq!(0.0f64.recip(), inf); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); - } - - #[test] - fn test_powi() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert_eq!(1.0f64.powi(1), 1.0); - assert_approx_eq!((-3.1f64).powi(2), 9.61); - assert_approx_eq!(5.9f64.powi(-2), 0.028727); - assert_eq!(8.3f64.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_eq!(inf.powi(3), inf); - assert_eq!(neg_inf.powi(2), inf); - } - - #[test] - fn test_powf() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert_eq!(1.0f64.powf(1.0), 1.0); - assert_approx_eq!(3.4f64.powf(4.5), 246.408183); - assert_approx_eq!(2.7f64.powf(-3.2), 0.041652); - assert_approx_eq!((-3.1f64).powf(2.0), 9.61); - assert_approx_eq!(5.9f64.powf(-2.0), 0.028727); - assert_eq!(8.3f64.powf(0.0), 1.0); - assert!(nan.powf(2.0).is_nan()); - assert_eq!(inf.powf(2.0), inf); - assert_eq!(neg_inf.powf(3.0), neg_inf); - } - - #[test] - fn test_sqrt_domain() { - assert!(NAN.sqrt().is_nan()); - assert!(NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f64).sqrt().is_nan()); - assert_eq!((-0.0f64).sqrt(), -0.0); - assert_eq!(0.0f64.sqrt(), 0.0); - assert_eq!(1.0f64.sqrt(), 1.0); - assert_eq!(INFINITY.sqrt(), INFINITY); - } - - #[test] - fn test_exp() { - assert_eq!(1.0, 0.0f64.exp()); - assert_approx_eq!(2.718282, 1.0f64.exp()); - assert_approx_eq!(148.413159, 5.0f64.exp()); - - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); - } - - #[test] - fn test_exp2() { - assert_eq!(32.0, 5.0f64.exp2()); - assert_eq!(1.0, 0.0f64.exp2()); - - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); - } - - #[test] - fn test_ln() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert_approx_eq!(1.0f64.exp().ln(), 1.0); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f64).ln().is_nan()); - assert_eq!((-0.0f64).ln(), neg_inf); - assert_eq!(0.0f64.ln(), neg_inf); - assert_approx_eq!(4.0f64.ln(), 1.386294); - } - - #[test] - fn test_log() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert_eq!(10.0f64.log(10.0), 1.0); - assert_approx_eq!(2.3f64.log(3.5), 0.664858); - assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); - assert!(1.0f64.log(1.0).is_nan()); - assert!(1.0f64.log(-13.9).is_nan()); - assert!(nan.log(2.3).is_nan()); - assert_eq!(inf.log(10.0), inf); - assert!(neg_inf.log(8.8).is_nan()); - assert!((-2.3f64).log(0.1).is_nan()); - assert_eq!((-0.0f64).log(2.0), neg_inf); - assert_eq!(0.0f64.log(7.0), neg_inf); - } - - #[test] - fn test_log2() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert_approx_eq!(10.0f64.log2(), 3.321928); - assert_approx_eq!(2.3f64.log2(), 1.201634); - assert_approx_eq!(1.0f64.exp().log2(), 1.442695); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f64).log2().is_nan()); - assert_eq!((-0.0f64).log2(), neg_inf); - assert_eq!(0.0f64.log2(), neg_inf); - } - - #[test] - fn test_log10() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert_eq!(10.0f64.log10(), 1.0); - assert_approx_eq!(2.3f64.log10(), 0.361728); - assert_approx_eq!(1.0f64.exp().log10(), 0.434294); - assert_eq!(1.0f64.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f64).log10().is_nan()); - assert_eq!((-0.0f64).log10(), neg_inf); - assert_eq!(0.0f64.log10(), neg_inf); - } - - #[test] - fn test_to_degrees() { - let pi: f64 = consts::PI; - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert_eq!(0.0f64.to_degrees(), 0.0); - assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); - assert_eq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); - } - - #[test] - fn test_to_radians() { - let pi: f64 = consts::PI; - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - assert_eq!(0.0f64.to_radians(), 0.0); - assert_approx_eq!(154.6f64.to_radians(), 2.698279); - assert_approx_eq!((-332.31f64).to_radians(), -5.799903); - assert_eq!(180.0f64.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); - } - - #[test] - fn test_asinh() { - assert_eq!(0.0f64.asinh(), 0.0f64); - assert_eq!((-0.0f64).asinh(), -0.0f64); - - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); - assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); - } - - #[test] - fn test_acosh() { - assert_eq!(1.0f64.acosh(), 0.0f64); - assert!(0.999f64.acosh().is_nan()); - - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); - assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); - } - - #[test] - fn test_atanh() { - assert_eq!(0.0f64.atanh(), 0.0f64); - assert_eq!((-0.0f64).atanh(), -0.0f64); - - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(1.0f64.atanh(), inf); - assert_eq!((-1.0f64).atanh(), neg_inf); - assert!(2f64.atanh().atanh().is_nan()); - assert!((-2f64).atanh().atanh().is_nan()); - assert!(inf.atanh().is_nan()); - assert!(neg_inf.atanh().is_nan()); - assert!(nan.atanh().is_nan()); - assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); - assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64); - } - - #[test] - fn test_real_consts() { - use super::consts; - let pi: f64 = consts::PI; - let frac_pi_2: f64 = consts::FRAC_PI_2; - let frac_pi_3: f64 = consts::FRAC_PI_3; - let frac_pi_4: f64 = consts::FRAC_PI_4; - let frac_pi_6: f64 = consts::FRAC_PI_6; - let frac_pi_8: f64 = consts::FRAC_PI_8; - let frac_1_pi: f64 = consts::FRAC_1_PI; - let frac_2_pi: f64 = consts::FRAC_2_PI; - let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI; - let sqrt2: f64 = consts::SQRT_2; - let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2; - let e: f64 = consts::E; - let log2_e: f64 = consts::LOG2_E; - let log10_e: f64 = consts::LOG10_E; - let ln_2: f64 = consts::LN_2; - let ln_10: f64 = consts::LN_10; - - assert_approx_eq!(frac_pi_2, pi / 2f64); - assert_approx_eq!(frac_pi_3, pi / 3f64); - assert_approx_eq!(frac_pi_4, pi / 4f64); - assert_approx_eq!(frac_pi_6, pi / 6f64); - assert_approx_eq!(frac_pi_8, pi / 8f64); - assert_approx_eq!(frac_1_pi, 1f64 / pi); - assert_approx_eq!(frac_2_pi, 2f64 / pi); - assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt()); - assert_approx_eq!(sqrt2, 2f64.sqrt()); - assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt()); - assert_approx_eq!(log2_e, e.log2()); - assert_approx_eq!(log10_e, e.log10()); - assert_approx_eq!(ln_2, 2f64.ln()); - assert_approx_eq!(ln_10, 10f64.ln()); - } - - #[test] - fn test_float_bits_conv() { - assert_eq!((1f64).to_bits(), 0x3ff0000000000000); - assert_eq!((12.5f64).to_bits(), 0x4029000000000000); - assert_eq!((1337f64).to_bits(), 0x4094e40000000000); - assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); - assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0); - assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5); - assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); - assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signalingness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; - let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; - assert!(f64::from_bits(masked_nan1).is_nan()); - assert!(f64::from_bits(masked_nan2).is_nan()); - - assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2); - } -} diff --git a/ctr-std/src/ffi/c_str.rs b/ctr-std/src/ffi/c_str.rs deleted file mode 100644 index 06edd29..0000000 --- a/ctr-std/src/ffi/c_str.rs +++ /dev/null @@ -1,1562 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ascii; -use borrow::{Cow, Borrow}; -use cmp::Ordering; -use error::Error; -use fmt::{self, Write}; -use io; -use mem; -use memchr; -use ops; -use os::raw::c_char; -use ptr; -use rc::Rc; -use slice; -use str::{self, Utf8Error}; -use sync::Arc; -use sys; - -/// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the -/// middle. -/// -/// This type serves the purpose of being able to safely generate a -/// C-compatible string from a Rust byte slice or vector. An instance of this -/// type is a static guarantee that the underlying bytes contain no interior 0 -/// bytes ("nul characters") and that the final byte is 0 ("nul terminator"). -/// -/// `CString` is to [`CStr`] as [`String`] is to [`&str`]: the former -/// in each pair are owned strings; the latter are borrowed -/// references. -/// -/// # Creating a `CString` -/// -/// A `CString` is created from either a byte slice or a byte vector, -/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for -/// example, you can build a `CString` straight out of a [`String`] or -/// a [`&str`], since both implement that trait). -/// -/// The [`new`] method will actually check that the provided `&[u8]` -/// does not have 0 bytes in the middle, and return an error if it -/// finds one. -/// -/// # Extracting a raw pointer to the whole C string -/// -/// `CString` implements a [`as_ptr`] method through the [`Deref`] -/// trait. This method will give you a `*const c_char` which you can -/// feed directly to extern functions that expect a nul-terminated -/// string, like C's `strdup()`. -/// -/// # Extracting a slice of the whole C string -/// -/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a -/// `CString` with the [`as_bytes`] method. Slices produced in this -/// way do *not* contain the trailing nul terminator. This is useful -/// when you will be calling an extern function that takes a `*const -/// u8` argument which is not necessarily nul-terminated, plus another -/// argument with the length of the string — like C's `strndup()`. -/// You can of course get the slice's length with its -/// [`len`][slice.len] method. -/// -/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you -/// can use [`as_bytes_with_nul`] instead. -/// -/// Once you have the kind of slice you need (with or without a nul -/// terminator), you can call the slice's own -/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to -/// extern functions. See the documentation for that function for a -/// discussion on ensuring the lifetime of the raw pointer. -/// -/// [`Into`]: ../convert/trait.Into.html -/// [`Vec`]: ../vec/struct.Vec.html -/// [`String`]: ../string/struct.String.html -/// [`&str`]: ../primitive.str.html -/// [`u8`]: ../primitive.u8.html -/// [`new`]: #method.new -/// [`as_bytes`]: #method.as_bytes -/// [`as_bytes_with_nul`]: #method.as_bytes_with_nul -/// [`as_ptr`]: #method.as_ptr -/// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr -/// [slice.len]: ../primitive.slice.html#method.len -/// [`Deref`]: ../ops/trait.Deref.html -/// [`CStr`]: struct.CStr.html -/// -/// # Examples -/// -/// ```ignore (extern-declaration) -/// # fn main() { -/// use std::ffi::CString; -/// use std::os::raw::c_char; -/// -/// extern { -/// fn my_printer(s: *const c_char); -/// } -/// -/// // We are certain that our string doesn't have 0 bytes in the middle, -/// // so we can .unwrap() -/// let c_to_print = CString::new("Hello, world!").unwrap(); -/// unsafe { -/// my_printer(c_to_print.as_ptr()); -/// } -/// # } -/// ``` -/// -/// # Safety -/// -/// `CString` is intended for working with traditional C-style strings -/// (a sequence of non-nul bytes terminated by a single nul byte); the -/// primary use case for these kinds of strings is interoperating with C-like -/// code. Often you will need to transfer ownership to/from that external -/// code. It is strongly recommended that you thoroughly read through the -/// documentation of `CString` before use, as improper ownership management -/// of `CString` instances can lead to invalid memory accesses, memory leaks, -/// and other memory errors. - -#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct CString { - // Invariant 1: the slice ends with a zero byte and has a length of at least one. - // Invariant 2: the slice contains only one zero byte. - // Improper usage of unsafe function can break Invariant 2, but not Invariant 1. - inner: Box<[u8]>, -} - -/// Representation of a borrowed C string. -/// -/// This type represents a borrowed reference to a nul-terminated -/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]` -/// slice, or unsafely from a raw `*const c_char`. It can then be -/// converted to a Rust [`&str`] by performing UTF-8 validation, or -/// into an owned [`CString`]. -/// -/// `CStr` is to [`CString`] as [`&str`] is to [`String`]: the former -/// in each pair are borrowed references; the latter are owned -/// strings. -/// -/// Note that this structure is **not** `repr(C)` and is not recommended to be -/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI -/// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe -/// interface to other consumers. -/// -/// # Examples -/// -/// Inspecting a foreign C string: -/// -/// ```ignore (extern-declaration) -/// use std::ffi::CStr; -/// use std::os::raw::c_char; -/// -/// extern { fn my_string() -> *const c_char; } -/// -/// unsafe { -/// let slice = CStr::from_ptr(my_string()); -/// println!("string buffer size without nul terminator: {}", slice.to_bytes().len()); -/// } -/// ``` -/// -/// Passing a Rust-originating C string: -/// -/// ```ignore (extern-declaration) -/// use std::ffi::{CString, CStr}; -/// use std::os::raw::c_char; -/// -/// fn work(data: &CStr) { -/// extern { fn work_with(data: *const c_char); } -/// -/// unsafe { work_with(data.as_ptr()) } -/// } -/// -/// let s = CString::new("data data data data").unwrap(); -/// work(&s); -/// ``` -/// -/// Converting a foreign C string into a Rust [`String`]: -/// -/// ```ignore (extern-declaration) -/// use std::ffi::CStr; -/// use std::os::raw::c_char; -/// -/// extern { fn my_string() -> *const c_char; } -/// -/// fn my_string_safe() -> String { -/// unsafe { -/// CStr::from_ptr(my_string()).to_string_lossy().into_owned() -/// } -/// } -/// -/// println!("string: {}", my_string_safe()); -/// ``` -/// -/// [`u8`]: ../primitive.u8.html -/// [`&str`]: ../primitive.str.html -/// [`String`]: ../string/struct.String.html -/// [`CString`]: struct.CString.html -/// [`from_ptr`]: #method.from_ptr -#[derive(Hash)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct CStr { - // FIXME: this should not be represented with a DST slice but rather with - // just a raw `c_char` along with some form of marker to make - // this an unsized type. Essentially `sizeof(&CStr)` should be the - // same as `sizeof(&c_char)` but `CStr` should be an unsized type. - inner: [c_char] -} - -/// An error indicating that an interior nul byte was found. -/// -/// While Rust strings may contain nul bytes in the middle, C strings -/// can't, as that byte would effectively truncate the string. -/// -/// This error is created by the [`new`][`CString::new`] method on -/// [`CString`]. See its documentation for more. -/// -/// [`CString`]: struct.CString.html -/// [`CString::new`]: struct.CString.html#method.new -/// -/// # Examples -/// -/// ``` -/// use std::ffi::{CString, NulError}; -/// -/// let _: NulError = CString::new(b"f\0oo".to_vec()).unwrap_err(); -/// ``` -#[derive(Clone, PartialEq, Eq, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct NulError(usize, Vec); - -/// An error indicating that a nul byte was not in the expected position. -/// -/// The slice used to create a [`CStr`] must have one and only one nul -/// byte at the end of the slice. -/// -/// This error is created by the -/// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on -/// [`CStr`]. See its documentation for more. -/// -/// [`CStr`]: struct.CStr.html -/// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul -/// -/// # Examples -/// -/// ``` -/// use std::ffi::{CStr, FromBytesWithNulError}; -/// -/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err(); -/// ``` -#[derive(Clone, PartialEq, Eq, Debug)] -#[stable(feature = "cstr_from_bytes", since = "1.10.0")] -pub struct FromBytesWithNulError { - kind: FromBytesWithNulErrorKind, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -enum FromBytesWithNulErrorKind { - InteriorNul(usize), - NotNulTerminated, -} - -impl FromBytesWithNulError { - fn interior_nul(pos: usize) -> FromBytesWithNulError { - FromBytesWithNulError { - kind: FromBytesWithNulErrorKind::InteriorNul(pos), - } - } - fn not_nul_terminated() -> FromBytesWithNulError { - FromBytesWithNulError { - kind: FromBytesWithNulErrorKind::NotNulTerminated, - } - } -} - -/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`]. -/// -/// `CString` is just a wrapper over a buffer of bytes with a nul -/// terminator; [`into_string`][`CString::into_string`] performs UTF-8 -/// validation on those bytes and may return this error. -/// -/// This `struct` is created by the -/// [`into_string`][`CString::into_string`] method on [`CString`]. See -/// its documentation for more. -/// -/// [`String`]: ../string/struct.String.html -/// [`CString`]: struct.CString.html -/// [`CString::into_string`]: struct.CString.html#method.into_string -#[derive(Clone, PartialEq, Eq, Debug)] -#[stable(feature = "cstring_into", since = "1.7.0")] -pub struct IntoStringError { - inner: CString, - error: Utf8Error, -} - -impl CString { - /// Creates a new C-compatible string from a container of bytes. - /// - /// This function will consume the provided data and use the - /// underlying bytes to construct a new string, ensuring that - /// there is a trailing 0 byte. This trailing 0 byte will be - /// appended by this function; the provided data should *not* - /// contain any 0 bytes in it. - /// - /// # Examples - /// - /// ```ignore (extern-declaration) - /// use std::ffi::CString; - /// use std::os::raw::c_char; - /// - /// extern { fn puts(s: *const c_char); } - /// - /// let to_print = CString::new("Hello!").unwrap(); - /// unsafe { - /// puts(to_print.as_ptr()); - /// } - /// ``` - /// - /// # Errors - /// - /// This function will return an error if the supplied bytes contain an - /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as - /// the position of the nul byte. - /// - /// [`NulError`]: struct.NulError.html - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new>>(t: T) -> Result { - Self::_new(t.into()) - } - - fn _new(bytes: Vec) -> Result { - match memchr::memchr(0, &bytes) { - Some(i) => Err(NulError(i, bytes)), - None => Ok(unsafe { CString::from_vec_unchecked(bytes) }), - } - } - - /// Creates a C-compatible string by consuming a byte vector, - /// without checking for interior 0 bytes. - /// - /// This method is equivalent to [`new`] except that no runtime assertion - /// is made that `v` contains no 0 bytes, and it requires an actual - /// byte vector, not anything that can be converted to one with Into. - /// - /// [`new`]: #method.new - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CString; - /// - /// let raw = b"foo".to_vec(); - /// unsafe { - /// let c_string = CString::from_vec_unchecked(raw); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { - v.reserve_exact(1); - v.push(0); - CString { inner: v.into_boxed_slice() } - } - - /// Retakes ownership of a `CString` that was transferred to C via [`into_raw`]. - /// - /// Additionally, the length of the string will be recalculated from the pointer. - /// - /// # Safety - /// - /// This should only ever be called with a pointer that was earlier - /// obtained by calling [`into_raw`] on a `CString`. Other usage (e.g. trying to take - /// ownership of a string that was allocated by foreign code) is likely to lead - /// to undefined behavior or allocator corruption. - /// - /// > **Note:** If you need to borrow a string that was allocated by - /// > foreign code, use [`CStr`]. If you need to take ownership of - /// > a string that was allocated by foreign code, you will need to - /// > make your own provisions for freeing it appropriately, likely - /// > with the foreign code's API to do that. - /// - /// [`into_raw`]: #method.into_raw - /// [`CStr`]: struct.CStr.html - /// - /// # Examples - /// - /// Create a `CString`, pass ownership to an `extern` function (via raw pointer), then retake - /// ownership with `from_raw`: - /// - /// ```ignore (extern-declaration) - /// use std::ffi::CString; - /// use std::os::raw::c_char; - /// - /// extern { - /// fn some_extern_function(s: *mut c_char); - /// } - /// - /// let c_string = CString::new("Hello!").unwrap(); - /// let raw = c_string.into_raw(); - /// unsafe { - /// some_extern_function(raw); - /// let c_string = CString::from_raw(raw); - /// } - /// ``` - #[cfg(not(target_os = "horizon"))] - #[stable(feature = "cstr_memory", since = "1.4.0")] - pub unsafe fn from_raw(ptr: *mut c_char) -> CString { - let len = sys::strlen(ptr) + 1; // Including the NUL byte - let slice = slice::from_raw_parts_mut(ptr, len as usize); - CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) } - } - - - /// Retakes ownership of a `CString` that was transferred to C via [`into_raw`]. - /// - /// Additionally, the length of the string will be recalculated from the pointer. - /// - /// # Safety - /// - /// This should only ever be called with a pointer that was earlier - /// obtained by calling [`into_raw`] on a `CString`. Other usage (e.g. trying to take - /// ownership of a string that was allocated by foreign code) is likely to lead - /// to undefined behavior or allocator corruption. - /// - /// > **Note:** If you need to borrow a string that was allocated by - /// > foreign code, use [`CStr`]. If you need to take ownership of - /// > a string that was allocated by foreign code, you will need to - /// > make your own provisions for freeing it appropriately, likely - /// > with the foreign code's API to do that. - /// - /// [`into_raw`]: #method.into_raw - /// [`CStr`]: struct.CStr.html - /// - /// # Examples - /// - /// Create a `CString`, pass ownership to an `extern` function (via raw pointer), then retake - /// ownership with `from_raw`: - /// - /// ```ignore (extern-declaration) - /// use std::ffi::CString; - /// use std::os::raw::c_char; - /// - /// extern { - /// fn some_extern_function(s: *mut c_char); - /// } - /// - /// let c_string = CString::new("Hello!").unwrap(); - /// let raw = c_string.into_raw(); - /// unsafe { - /// some_extern_function(raw); - /// let c_string = CString::from_raw(raw); - /// } - /// ``` - #[cfg(target_os = "horizon")] - #[stable(feature = "cstr_memory", since = "1.4.0")] - pub unsafe fn from_raw(ptr: *mut c_char) -> CString { - let len = sys::strlen(ptr as *const u8) + 1; // Including the NUL byte - let slice = slice::from_raw_parts_mut(ptr, len as usize); - CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) } - } - - /// Consumes the `CString` and transfers ownership of the string to a C caller. - /// - /// The pointer which this function returns must be returned to Rust and reconstituted using - /// [`from_raw`] to be properly deallocated. Specifically, one - /// should *not* use the standard C `free()` function to deallocate - /// this string. - /// - /// Failure to call [`from_raw`] will lead to a memory leak. - /// - /// [`from_raw`]: #method.from_raw - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CString; - /// - /// let c_string = CString::new("foo").unwrap(); - /// - /// let ptr = c_string.into_raw(); - /// - /// unsafe { - /// assert_eq!(b'f', *ptr as u8); - /// assert_eq!(b'o', *ptr.offset(1) as u8); - /// assert_eq!(b'o', *ptr.offset(2) as u8); - /// assert_eq!(b'\0', *ptr.offset(3) as u8); - /// - /// // retake pointer to free memory - /// let _ = CString::from_raw(ptr); - /// } - /// ``` - #[inline] - #[stable(feature = "cstr_memory", since = "1.4.0")] - pub fn into_raw(self) -> *mut c_char { - Box::into_raw(self.into_inner()) as *mut c_char - } - - /// Converts the `CString` into a [`String`] if it contains valid UTF-8 data. - /// - /// On failure, ownership of the original `CString` is returned. - /// - /// [`String`]: ../string/struct.String.html - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CString; - /// - /// let valid_utf8 = vec![b'f', b'o', b'o']; - /// let cstring = CString::new(valid_utf8).unwrap(); - /// assert_eq!(cstring.into_string().unwrap(), "foo"); - /// - /// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o']; - /// let cstring = CString::new(invalid_utf8).unwrap(); - /// let err = cstring.into_string().err().unwrap(); - /// assert_eq!(err.utf8_error().valid_up_to(), 1); - /// ``` - - #[stable(feature = "cstring_into", since = "1.7.0")] - pub fn into_string(self) -> Result { - String::from_utf8(self.into_bytes()) - .map_err(|e| IntoStringError { - error: e.utf8_error(), - inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) }, - }) - } - - /// Consumes the `CString` and returns the underlying byte buffer. - /// - /// The returned buffer does **not** contain the trailing nul - /// terminator, and it is guaranteed to not have any interior nul - /// bytes. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CString; - /// - /// let c_string = CString::new("foo").unwrap(); - /// let bytes = c_string.into_bytes(); - /// assert_eq!(bytes, vec![b'f', b'o', b'o']); - /// ``` - #[stable(feature = "cstring_into", since = "1.7.0")] - pub fn into_bytes(self) -> Vec { - let mut vec = self.into_inner().into_vec(); - let _nul = vec.pop(); - debug_assert_eq!(_nul, Some(0u8)); - vec - } - - /// Equivalent to the [`into_bytes`] function except that the returned vector - /// includes the trailing nul terminator. - /// - /// [`into_bytes`]: #method.into_bytes - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CString; - /// - /// let c_string = CString::new("foo").unwrap(); - /// let bytes = c_string.into_bytes_with_nul(); - /// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']); - /// ``` - #[stable(feature = "cstring_into", since = "1.7.0")] - pub fn into_bytes_with_nul(self) -> Vec { - self.into_inner().into_vec() - } - - /// Returns the contents of this `CString` as a slice of bytes. - /// - /// The returned slice does **not** contain the trailing nul - /// terminator, and it is guaranteed to not have any interior nul - /// bytes. If you need the nul terminator, use - /// [`as_bytes_with_nul`] instead. - /// - /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CString; - /// - /// let c_string = CString::new("foo").unwrap(); - /// let bytes = c_string.as_bytes(); - /// assert_eq!(bytes, &[b'f', b'o', b'o']); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_bytes(&self) -> &[u8] { - &self.inner[..self.inner.len() - 1] - } - - /// Equivalent to the [`as_bytes`] function except that the returned slice - /// includes the trailing nul terminator. - /// - /// [`as_bytes`]: #method.as_bytes - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CString; - /// - /// let c_string = CString::new("foo").unwrap(); - /// let bytes = c_string.as_bytes_with_nul(); - /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_bytes_with_nul(&self) -> &[u8] { - &self.inner - } - - /// Extracts a [`CStr`] slice containing the entire string. - /// - /// [`CStr`]: struct.CStr.html - /// - /// # Examples - /// - /// ``` - /// use std::ffi::{CString, CStr}; - /// - /// let c_string = CString::new(b"foo".to_vec()).unwrap(); - /// let c_str = c_string.as_c_str(); - /// assert_eq!(c_str, CStr::from_bytes_with_nul(b"foo\0").unwrap()); - /// ``` - #[inline] - #[stable(feature = "as_c_str", since = "1.20.0")] - pub fn as_c_str(&self) -> &CStr { - &*self - } - - /// Converts this `CString` into a boxed [`CStr`]. - /// - /// [`CStr`]: struct.CStr.html - /// - /// # Examples - /// - /// ``` - /// use std::ffi::{CString, CStr}; - /// - /// let c_string = CString::new(b"foo".to_vec()).unwrap(); - /// let boxed = c_string.into_boxed_c_str(); - /// assert_eq!(&*boxed, CStr::from_bytes_with_nul(b"foo\0").unwrap()); - /// ``` - #[stable(feature = "into_boxed_c_str", since = "1.20.0")] - pub fn into_boxed_c_str(self) -> Box { - unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) } - } - - // Bypass "move out of struct which implements [`Drop`] trait" restriction. - /// - /// [`Drop`]: ../ops/trait.Drop.html - fn into_inner(self) -> Box<[u8]> { - unsafe { - let result = ptr::read(&self.inner); - mem::forget(self); - result - } - } -} - -// Turns this `CString` into an empty string to prevent -// memory unsafe code from working by accident. Inline -// to prevent LLVM from optimizing it away in debug builds. -#[stable(feature = "cstring_drop", since = "1.13.0")] -impl Drop for CString { - #[inline] - fn drop(&mut self) { - unsafe { *self.inner.get_unchecked_mut(0) = 0; } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::Deref for CString { - type Target = CStr; - - #[inline] - fn deref(&self) -> &CStr { - unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for CString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -#[stable(feature = "cstring_into", since = "1.7.0")] -impl From for Vec { - /// Converts a [`CString`] into a [`Vec`]``. - /// - /// The conversion consumes the [`CString`], and removes the terminating NUL byte. - /// - /// [`Vec`]: ../vec/struct.Vec.html - /// [`CString`]: ../ffi/struct.CString.html - #[inline] - fn from(s: CString) -> Vec { - s.into_bytes() - } -} - -#[stable(feature = "cstr_debug", since = "1.3.0")] -impl fmt::Debug for CStr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "\"")?; - for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) { - f.write_char(byte as char)?; - } - write!(f, "\"") - } -} - -#[stable(feature = "cstr_default", since = "1.10.0")] -impl<'a> Default for &'a CStr { - fn default() -> &'a CStr { - const SLICE: &'static [c_char] = &[0]; - unsafe { CStr::from_ptr(SLICE.as_ptr()) } - } -} - -#[stable(feature = "cstr_default", since = "1.10.0")] -impl Default for CString { - /// Creates an empty `CString`. - fn default() -> CString { - let a: &CStr = Default::default(); - a.to_owned() - } -} - -#[stable(feature = "cstr_borrow", since = "1.3.0")] -impl Borrow for CString { - #[inline] - fn borrow(&self) -> &CStr { self } -} - -#[stable(feature = "cstring_from_cow_cstr", since = "1.28.0")] -impl<'a> From> for CString { - #[inline] - fn from(s: Cow<'a, CStr>) -> Self { - s.into_owned() - } -} - -#[stable(feature = "box_from_c_str", since = "1.17.0")] -impl<'a> From<&'a CStr> for Box { - fn from(s: &'a CStr) -> Box { - let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul()); - unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) } - } -} - -#[stable(feature = "c_string_from_box", since = "1.18.0")] -impl From> for CString { - /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. - /// - /// [`Box`]: ../boxed/struct.Box.html - /// [`CString`]: ../ffi/struct.CString.html - #[inline] - fn from(s: Box) -> CString { - s.into_c_string() - } -} - -#[stable(feature = "more_box_slice_clone", since = "1.29.0")] -impl Clone for Box { - #[inline] - fn clone(&self) -> Self { - (**self).into() - } -} - -#[stable(feature = "box_from_c_string", since = "1.20.0")] -impl From for Box { - /// Converts a [`CString`] into a [`Box`]`` without copying or allocating. - /// - /// [`CString`]: ../ffi/struct.CString.html - /// [`Box`]: ../boxed/struct.Box.html - #[inline] - fn from(s: CString) -> Box { - s.into_boxed_c_str() - } -} - -#[stable(feature = "cow_from_cstr", since = "1.28.0")] -impl<'a> From for Cow<'a, CStr> { - #[inline] - fn from(s: CString) -> Cow<'a, CStr> { - Cow::Owned(s) - } -} - -#[stable(feature = "cow_from_cstr", since = "1.28.0")] -impl<'a> From<&'a CStr> for Cow<'a, CStr> { - #[inline] - fn from(s: &'a CStr) -> Cow<'a, CStr> { - Cow::Borrowed(s) - } -} - -#[stable(feature = "cow_from_cstr", since = "1.28.0")] -impl<'a> From<&'a CString> for Cow<'a, CStr> { - #[inline] - fn from(s: &'a CString) -> Cow<'a, CStr> { - Cow::Borrowed(s.as_c_str()) - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl From for Arc { - /// Converts a [`CString`] into a [`Arc`]`` without copying or allocating. - /// - /// [`CString`]: ../ffi/struct.CString.html - /// [`Arc`]: ../sync/struct.Arc.html - #[inline] - fn from(s: CString) -> Arc { - let arc: Arc<[u8]> = Arc::from(s.into_inner()); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) } - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a CStr> for Arc { - #[inline] - fn from(s: &CStr) -> Arc { - let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul()); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) } - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl From for Rc { - /// Converts a [`CString`] into a [`Rc`]`` without copying or allocating. - /// - /// [`CString`]: ../ffi/struct.CString.html - /// [`Rc`]: ../rc/struct.Rc.html - #[inline] - fn from(s: CString) -> Rc { - let rc: Rc<[u8]> = Rc::from(s.into_inner()); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) } - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a CStr> for Rc { - #[inline] - fn from(s: &CStr) -> Rc { - let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul()); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) } - } -} - -#[stable(feature = "default_box_extra", since = "1.17.0")] -impl Default for Box { - fn default() -> Box { - let boxed: Box<[u8]> = Box::from([0]); - unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) } - } -} - -impl NulError { - /// Returns the position of the nul byte in the slice that caused - /// [`CString::new`] to fail. - /// - /// [`CString::new`]: struct.CString.html#method.new - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CString; - /// - /// let nul_error = CString::new("foo\0bar").unwrap_err(); - /// assert_eq!(nul_error.nul_position(), 3); - /// - /// let nul_error = CString::new("foo bar\0").unwrap_err(); - /// assert_eq!(nul_error.nul_position(), 7); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn nul_position(&self) -> usize { self.0 } - - /// Consumes this error, returning the underlying vector of bytes which - /// generated the error in the first place. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CString; - /// - /// let nul_error = CString::new("foo\0bar").unwrap_err(); - /// assert_eq!(nul_error.into_vec(), b"foo\0bar"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_vec(self) -> Vec { self.1 } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for NulError { - fn description(&self) -> &str { "nul byte found in data" } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for NulError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "nul byte found in provided data at position: {}", self.0) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl From for io::Error { - /// Converts a [`NulError`] into a [`io::Error`]. - /// - /// [`NulError`]: ../ffi/struct.NulError.html - /// [`io::Error`]: ../io/struct.Error.html - fn from(_: NulError) -> io::Error { - io::Error::new(io::ErrorKind::InvalidInput, - "data provided contains a nul byte") - } -} - -#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] -impl Error for FromBytesWithNulError { - fn description(&self) -> &str { - match self.kind { - FromBytesWithNulErrorKind::InteriorNul(..) => - "data provided contains an interior nul byte", - FromBytesWithNulErrorKind::NotNulTerminated => - "data provided is not nul terminated", - } - } -} - -#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] -impl fmt::Display for FromBytesWithNulError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.description())?; - if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind { - write!(f, " at byte pos {}", pos)?; - } - Ok(()) - } -} - -impl IntoStringError { - /// Consumes this error, returning original [`CString`] which generated the - /// error. - /// - /// [`CString`]: struct.CString.html - #[stable(feature = "cstring_into", since = "1.7.0")] - pub fn into_cstring(self) -> CString { - self.inner - } - - /// Access the underlying UTF-8 error that was the cause of this error. - #[stable(feature = "cstring_into", since = "1.7.0")] - pub fn utf8_error(&self) -> Utf8Error { - self.error - } -} - -#[stable(feature = "cstring_into", since = "1.7.0")] -impl Error for IntoStringError { - fn description(&self) -> &str { - "C string contained non-utf8 bytes" - } - - fn cause(&self) -> Option<&dyn Error> { - Some(&self.error) - } -} - -#[stable(feature = "cstring_into", since = "1.7.0")] -impl fmt::Display for IntoStringError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) - } -} - -impl CStr { - /// Wraps a raw C string with a safe C string wrapper. - /// - /// This function will wrap the provided `ptr` with a `CStr` wrapper, which - /// allows inspection and interoperation of non-owned C strings. This method - /// is unsafe for a number of reasons: - /// - /// * There is no guarantee to the validity of `ptr`. - /// * The returned lifetime is not guaranteed to be the actual lifetime of - /// `ptr`. - /// * There is no guarantee that the memory pointed to by `ptr` contains a - /// valid nul terminator byte at the end of the string. - /// * It is not guaranteed that the memory pointed by `ptr` won't change - /// before the `CStr` has been destroyed. - /// - /// > **Note**: This operation is intended to be a 0-cost cast but it is - /// > currently implemented with an up-front calculation of the length of - /// > the string. This is not guaranteed to always be the case. - /// - /// # Examples - /// - /// ```ignore (extern-declaration) - /// # fn main() { - /// use std::ffi::CStr; - /// use std::os::raw::c_char; - /// - /// extern { - /// fn my_string() -> *const c_char; - /// } - /// - /// unsafe { - /// let slice = CStr::from_ptr(my_string()); - /// println!("string returned: {}", slice.to_str().unwrap()); - /// } - /// # } - /// ``` - #[cfg(not(target_os = "horizon"))] - #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { - let len = sys::strlen(ptr); - let ptr = ptr as *const u8; - CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) - } - - /// Wraps a raw C string with a safe C string wrapper. - /// - /// This function will wrap the provided `ptr` with a `CStr` wrapper, which - /// allows inspection and interoperation of non-owned C strings. This method - /// is unsafe for a number of reasons: - /// - /// * There is no guarantee to the validity of `ptr`. - /// * The returned lifetime is not guaranteed to be the actual lifetime of - /// `ptr`. - /// * There is no guarantee that the memory pointed to by `ptr` contains a - /// valid nul terminator byte at the end of the string. - /// * It is not guaranteed that the memory pointed by `ptr` won't change - /// before the `CStr` has been destroyed. - /// - /// > **Note**: This operation is intended to be a 0-cost cast but it is - /// > currently implemented with an up-front calculation of the length of - /// > the string. This is not guaranteed to always be the case. - /// - /// # Examples - /// - /// ```ignore (extern-declaration) - /// # fn main() { - /// use std::ffi::CStr; - /// use std::os::raw::c_char; - /// - /// extern { - /// fn my_string() -> *const c_char; - /// } - /// - /// unsafe { - /// let slice = CStr::from_ptr(my_string()); - /// println!("string returned: {}", slice.to_str().unwrap()); - /// } - /// # } - /// ``` - #[cfg(target_os = "horizon")] - #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { - let len = sys::strlen(ptr as *const u8); - let ptr = ptr as *const u8; - CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) - } - /// Creates a C string wrapper from a byte slice. - /// - /// This function will cast the provided `bytes` to a `CStr` - /// wrapper after ensuring that the byte slice is nul-terminated - /// and does not contain any interior nul bytes. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CStr; - /// - /// let cstr = CStr::from_bytes_with_nul(b"hello\0"); - /// assert!(cstr.is_ok()); - /// ``` - /// - /// Creating a `CStr` without a trailing nul terminator is an error: - /// - /// ``` - /// use std::ffi::CStr; - /// - /// let c_str = CStr::from_bytes_with_nul(b"hello"); - /// assert!(c_str.is_err()); - /// ``` - /// - /// Creating a `CStr` with an interior nul byte is an error: - /// - /// ``` - /// use std::ffi::CStr; - /// - /// let c_str = CStr::from_bytes_with_nul(b"he\0llo\0"); - /// assert!(c_str.is_err()); - /// ``` - #[stable(feature = "cstr_from_bytes", since = "1.10.0")] - pub fn from_bytes_with_nul(bytes: &[u8]) - -> Result<&CStr, FromBytesWithNulError> { - let nul_pos = memchr::memchr(0, bytes); - if let Some(nul_pos) = nul_pos { - if nul_pos + 1 != bytes.len() { - return Err(FromBytesWithNulError::interior_nul(nul_pos)); - } - Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }) - } else { - Err(FromBytesWithNulError::not_nul_terminated()) - } - } - - /// Unsafely creates a C string wrapper from a byte slice. - /// - /// This function will cast the provided `bytes` to a `CStr` wrapper without - /// performing any sanity checks. The provided slice **must** be nul-terminated - /// and not contain any interior nul bytes. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::{CStr, CString}; - /// - /// unsafe { - /// let cstring = CString::new("hello").unwrap(); - /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul()); - /// assert_eq!(cstr, &*cstring); - /// } - /// ``` - #[inline] - #[stable(feature = "cstr_from_bytes", since = "1.10.0")] - pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { - &*(bytes as *const [u8] as *const CStr) - } - - /// Returns the inner pointer to this C string. - /// - /// The returned pointer will be valid for as long as `self` is, and points - /// to a contiguous region of memory terminated with a 0 byte to represent - /// the end of the string. - /// - /// **WARNING** - /// - /// It is your responsibility to make sure that the underlying memory is not - /// freed too early. For example, the following code will cause undefined - /// behavior when `ptr` is used inside the `unsafe` block: - /// - /// ```no_run - /// # #![allow(unused_must_use)] - /// use std::ffi::{CString}; - /// - /// let ptr = CString::new("Hello").unwrap().as_ptr(); - /// unsafe { - /// // `ptr` is dangling - /// *ptr; - /// } - /// ``` - /// - /// This happens because the pointer returned by `as_ptr` does not carry any - /// lifetime information and the [`CString`] is deallocated immediately after - /// the `CString::new("Hello").unwrap().as_ptr()` expression is evaluated. - /// To fix the problem, bind the `CString` to a local variable: - /// - /// ```no_run - /// # #![allow(unused_must_use)] - /// use std::ffi::{CString}; - /// - /// let hello = CString::new("Hello").unwrap(); - /// let ptr = hello.as_ptr(); - /// unsafe { - /// // `ptr` is valid because `hello` is in scope - /// *ptr; - /// } - /// ``` - /// - /// This way, the lifetime of the `CString` in `hello` encompasses - /// the lifetime of `ptr` and the `unsafe` block. - /// - /// [`CString`]: struct.CString.html - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_ptr(&self) -> *const c_char { - self.inner.as_ptr() - } - - /// Converts this C string to a byte slice. - /// - /// The returned slice will **not** contain the trailing nul terminator that this C - /// string has. - /// - /// > **Note**: This method is currently implemented as a constant-time - /// > cast, but it is planned to alter its definition in the future to - /// > perform the length calculation whenever this method is called. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CStr; - /// - /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap(); - /// assert_eq!(c_str.to_bytes(), b"foo"); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_bytes(&self) -> &[u8] { - let bytes = self.to_bytes_with_nul(); - &bytes[..bytes.len() - 1] - } - - /// Converts this C string to a byte slice containing the trailing 0 byte. - /// - /// This function is the equivalent of [`to_bytes`] except that it will retain - /// the trailing nul terminator instead of chopping it off. - /// - /// > **Note**: This method is currently implemented as a 0-cost cast, but - /// > it is planned to alter its definition in the future to perform the - /// > length calculation whenever this method is called. - /// - /// [`to_bytes`]: #method.to_bytes - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CStr; - /// - /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap(); - /// assert_eq!(c_str.to_bytes_with_nul(), b"foo\0"); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_bytes_with_nul(&self) -> &[u8] { - unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } - } - - /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. - /// - /// If the contents of the `CStr` are valid UTF-8 data, this - /// function will return the corresponding [`&str`] slice. Otherwise, - /// it will return an error with details of where UTF-8 validation failed. - /// - /// > **Note**: This method is currently implemented to check for validity - /// > after a constant-time cast, but it is planned to alter its definition - /// > in the future to perform the length calculation in addition to the - /// > UTF-8 check whenever this method is called. - /// - /// [`&str`]: ../primitive.str.html - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CStr; - /// - /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap(); - /// assert_eq!(c_str.to_str(), Ok("foo")); - /// ``` - #[stable(feature = "cstr_to_str", since = "1.4.0")] - pub fn to_str(&self) -> Result<&str, str::Utf8Error> { - // NB: When CStr is changed to perform the length check in .to_bytes() - // instead of in from_ptr(), it may be worth considering if this should - // be rewritten to do the UTF-8 check inline with the length calculation - // instead of doing it afterwards. - str::from_utf8(self.to_bytes()) - } - - /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`. - /// - /// If the contents of the `CStr` are valid UTF-8 data, this - /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)` - /// with the the corresponding [`&str`] slice. Otherwise, it will - /// replace any invalid UTF-8 sequences with - /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a - /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. - /// - /// > **Note**: This method is currently implemented to check for validity - /// > after a constant-time cast, but it is planned to alter its definition - /// > in the future to perform the length calculation in addition to the - /// > UTF-8 check whenever this method is called. - /// - /// [`Cow`]: ../borrow/enum.Cow.html - /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed - /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned - /// [`str`]: ../primitive.str.html - /// [`String`]: ../string/struct.String.html - /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html - /// - /// # Examples - /// - /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8: - /// - /// ``` - /// use std::borrow::Cow; - /// use std::ffi::CStr; - /// - /// let c_str = CStr::from_bytes_with_nul(b"Hello World\0").unwrap(); - /// assert_eq!(c_str.to_string_lossy(), Cow::Borrowed("Hello World")); - /// ``` - /// - /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8: - /// - /// ``` - /// use std::borrow::Cow; - /// use std::ffi::CStr; - /// - /// let c_str = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0").unwrap(); - /// assert_eq!( - /// c_str.to_string_lossy(), - /// Cow::Owned(String::from("Hello �World")) as Cow - /// ); - /// ``` - #[stable(feature = "cstr_to_str", since = "1.4.0")] - pub fn to_string_lossy(&self) -> Cow { - String::from_utf8_lossy(self.to_bytes()) - } - - /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. - /// - /// [`Box`]: ../boxed/struct.Box.html - /// [`CString`]: struct.CString.html - /// - /// # Examples - /// - /// ``` - /// use std::ffi::CString; - /// - /// let c_string = CString::new(b"foo".to_vec()).unwrap(); - /// let boxed = c_string.into_boxed_c_str(); - /// assert_eq!(boxed.into_c_string(), CString::new("foo").unwrap()); - /// ``` - #[stable(feature = "into_boxed_c_str", since = "1.20.0")] - pub fn into_c_string(self: Box) -> CString { - let raw = Box::into_raw(self) as *mut [u8]; - CString { inner: unsafe { Box::from_raw(raw) } } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for CStr { - fn eq(&self, other: &CStr) -> bool { - self.to_bytes().eq(other.to_bytes()) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for CStr {} -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for CStr { - fn partial_cmp(&self, other: &CStr) -> Option { - self.to_bytes().partial_cmp(&other.to_bytes()) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for CStr { - fn cmp(&self, other: &CStr) -> Ordering { - self.to_bytes().cmp(&other.to_bytes()) - } -} - -#[stable(feature = "cstr_borrow", since = "1.3.0")] -impl ToOwned for CStr { - type Owned = CString; - - fn to_owned(&self) -> CString { - CString { inner: self.to_bytes_with_nul().into() } - } -} - -#[stable(feature = "cstring_asref", since = "1.7.0")] -impl<'a> From<&'a CStr> for CString { - fn from(s: &'a CStr) -> CString { - s.to_owned() - } -} - -#[stable(feature = "cstring_asref", since = "1.7.0")] -impl ops::Index for CString { - type Output = CStr; - - #[inline] - fn index(&self, _index: ops::RangeFull) -> &CStr { - self - } -} - -#[stable(feature = "cstring_asref", since = "1.7.0")] -impl AsRef for CStr { - #[inline] - fn as_ref(&self) -> &CStr { - self - } -} - -#[stable(feature = "cstring_asref", since = "1.7.0")] -impl AsRef for CString { - #[inline] - fn as_ref(&self) -> &CStr { - self - } -} - -#[cfg(test)] -mod tests { - use super::*; - use os::raw::c_char; - use borrow::Cow::{Borrowed, Owned}; - use hash::{Hash, Hasher}; - use collections::hash_map::DefaultHasher; - use rc::Rc; - use sync::Arc; - - #[test] - fn c_to_rust() { - let data = b"123\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123"); - assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0"); - } - } - - #[test] - fn simple() { - let s = CString::new("1234").unwrap(); - assert_eq!(s.as_bytes(), b"1234"); - assert_eq!(s.as_bytes_with_nul(), b"1234\0"); - } - - #[test] - fn build_with_zero1() { - assert!(CString::new(&b"\0"[..]).is_err()); - } - #[test] - fn build_with_zero2() { - assert!(CString::new(vec![0]).is_err()); - } - - #[test] - fn build_with_zero3() { - unsafe { - let s = CString::from_vec_unchecked(vec![0]); - assert_eq!(s.as_bytes(), b"\0"); - } - } - - #[test] - fn formatted() { - let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); - assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); - } - - #[test] - fn borrowed() { - unsafe { - let s = CStr::from_ptr(b"12\0".as_ptr() as *const _); - assert_eq!(s.to_bytes(), b"12"); - assert_eq!(s.to_bytes_with_nul(), b"12\0"); - } - } - - #[test] - fn to_str() { - let data = b"123\xE2\x80\xA6\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…")); - assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…")); - } - let data = b"123\xE2\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert!(CStr::from_ptr(ptr).to_str().is_err()); - assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::(format!("123\u{FFFD}"))); - } - } - - #[test] - fn to_owned() { - let data = b"123\0"; - let ptr = data.as_ptr() as *const c_char; - - let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; - assert_eq!(owned.as_bytes_with_nul(), data); - } - - #[test] - fn equal_hash() { - let data = b"123\xE2\xFA\xA6\0"; - let ptr = data.as_ptr() as *const c_char; - let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; - - let mut s = DefaultHasher::new(); - cstr.hash(&mut s); - let cstr_hash = s.finish(); - let mut s = DefaultHasher::new(); - CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s); - let cstring_hash = s.finish(); - - assert_eq!(cstr_hash, cstring_hash); - } - - #[test] - fn from_bytes_with_nul() { - let data = b"123\0"; - let cstr = CStr::from_bytes_with_nul(data); - assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..])); - let cstr = CStr::from_bytes_with_nul(data); - assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..])); - - unsafe { - let cstr = CStr::from_bytes_with_nul(data); - let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data); - assert_eq!(cstr, Ok(cstr_unchecked)); - } - } - - #[test] - fn from_bytes_with_nul_unterminated() { - let data = b"123"; - let cstr = CStr::from_bytes_with_nul(data); - assert!(cstr.is_err()); - } - - #[test] - fn from_bytes_with_nul_interior() { - let data = b"1\023\0"; - let cstr = CStr::from_bytes_with_nul(data); - assert!(cstr.is_err()); - } - - #[test] - fn into_boxed() { - let orig: &[u8] = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(orig).unwrap(); - let boxed: Box = Box::from(cstr); - let cstring = cstr.to_owned().into_boxed_c_str().into_c_string(); - assert_eq!(cstr, &*boxed); - assert_eq!(&*boxed, &*cstring); - assert_eq!(&*cstring, cstr); - } - - #[test] - fn boxed_default() { - let boxed = >::default(); - assert_eq!(boxed.to_bytes_with_nul(), &[0]); - } - - #[test] - fn into_rc() { - let orig: &[u8] = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(orig).unwrap(); - let rc: Rc = Rc::from(cstr); - let arc: Arc = Arc::from(cstr); - - assert_eq!(&*rc, cstr); - assert_eq!(&*arc, cstr); - - let rc2: Rc = Rc::from(cstr.to_owned()); - let arc2: Arc = Arc::from(cstr.to_owned()); - - assert_eq!(&*rc2, cstr); - assert_eq!(&*arc2, cstr); - } -} diff --git a/ctr-std/src/ffi/mod.rs b/ctr-std/src/ffi/mod.rs deleted file mode 100644 index a37a5e8..0000000 --- a/ctr-std/src/ffi/mod.rs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Utilities related to FFI bindings. -//! -//! This module provides utilities to handle data across non-Rust -//! interfaces, like other programming languages and the underlying -//! operating system. It is mainly of use for FFI (Foreign Function -//! Interface) bindings and code that needs to exchange C-like strings -//! with other languages. -//! -//! # Overview -//! -//! Rust represents owned strings with the [`String`] type, and -//! borrowed slices of strings with the [`str`] primitive. Both are -//! always in UTF-8 encoding, and may contain nul bytes in the middle, -//! i.e. if you look at the bytes that make up the string, there may -//! be a `\0` among them. Both `String` and `str` store their length -//! explicitly; there are no nul terminators at the end of strings -//! like in C. -//! -//! C strings are different from Rust strings: -//! -//! * **Encodings** - Rust strings are UTF-8, but C strings may use -//! other encodings. If you are using a string from C, you should -//! check its encoding explicitly, rather than just assuming that it -//! is UTF-8 like you can do in Rust. -//! -//! * **Character size** - C strings may use `char` or `wchar_t`-sized -//! characters; please **note** that C's `char` is different from Rust's. -//! The C standard leaves the actual sizes of those types open to -//! interpretation, but defines different APIs for strings made up of -//! each character type. Rust strings are always UTF-8, so different -//! Unicode characters will be encoded in a variable number of bytes -//! each. The Rust type [`char`] represents a '[Unicode scalar -//! value]', which is similar to, but not the same as, a '[Unicode -//! code point]'. -//! -//! * **Nul terminators and implicit string lengths** - Often, C -//! strings are nul-terminated, i.e. they have a `\0` character at the -//! end. The length of a string buffer is not stored, but has to be -//! calculated; to compute the length of a string, C code must -//! manually call a function like `strlen()` for `char`-based strings, -//! or `wcslen()` for `wchar_t`-based ones. Those functions return -//! the number of characters in the string excluding the nul -//! terminator, so the buffer length is really `len+1` characters. -//! Rust strings don't have a nul terminator; their length is always -//! stored and does not need to be calculated. While in Rust -//! accessing a string's length is a O(1) operation (because the -//! length is stored); in C it is an O(length) operation because the -//! length needs to be computed by scanning the string for the nul -//! terminator. -//! -//! * **Internal nul characters** - When C strings have a nul -//! terminator character, this usually means that they cannot have nul -//! characters in the middle — a nul character would essentially -//! truncate the string. Rust strings *can* have nul characters in -//! the middle, because nul does not have to mark the end of the -//! string in Rust. -//! -//! # Representations of non-Rust strings -//! -//! [`CString`] and [`CStr`] are useful when you need to transfer -//! UTF-8 strings to and from languages with a C ABI, like Python. -//! -//! * **From Rust to C:** [`CString`] represents an owned, C-friendly -//! string: it is nul-terminated, and has no internal nul characters. -//! Rust code can create a `CString` out of a normal string (provided -//! that the string doesn't have nul characters in the middle), and -//! then use a variety of methods to obtain a raw `*mut u8` that can -//! then be passed as an argument to functions which use the C -//! conventions for strings. -//! -//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it -//! is what you would use to wrap a raw `*const u8` that you got from -//! a C function. A `CStr` is guaranteed to be a nul-terminated array -//! of bytes. Once you have a `CStr`, you can convert it to a Rust -//! `&str` if it's valid UTF-8, or lossily convert it by adding -//! replacement characters. -//! -//! [`OsString`] and [`OsStr`] are useful when you need to transfer -//! strings to and from the operating system itself, or when capturing -//! the output of external commands. Conversions between `OsString`, -//! `OsStr` and Rust strings work similarly to those for [`CString`] -//! and [`CStr`]. -//! -//! * [`OsString`] represents an owned string in whatever -//! representation the operating system prefers. In the Rust standard -//! library, various APIs that transfer strings to/from the operating -//! system use `OsString` instead of plain strings. For example, -//! [`env::var_os()`] is used to query environment variables; it -//! returns an `Option`. If the environment variable exists -//! you will get a `Some(os_string)`, which you can *then* try to -//! convert to a Rust string. This yields a [`Result<>`], so that -//! your code can detect errors in case the environment variable did -//! not in fact contain valid Unicode data. -//! -//! * [`OsStr`] represents a borrowed reference to a string in a -//! format that can be passed to the operating system. It can be -//! converted into an UTF-8 Rust string slice in a similar way to -//! `OsString`. -//! -//! # Conversions -//! -//! ## On Unix -//! -//! On Unix, [`OsStr`] implements the -//! `std::os::unix:ffi::`[`OsStrExt`][unix.OsStrExt] trait, which -//! augments it with two methods, [`from_bytes`] and [`as_bytes`]. -//! These do inexpensive conversions from and to UTF-8 byte slices. -//! -//! Additionally, on Unix [`OsString`] implements the -//! `std::os::unix:ffi::`[`OsStringExt`][unix.OsStringExt] trait, -//! which provides [`from_vec`] and [`into_vec`] methods that consume -//! their arguments, and take or produce vectors of [`u8`]. -//! -//! ## On Windows -//! -//! On Windows, [`OsStr`] implements the -//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait, -//! which provides an [`encode_wide`] method. This provides an -//! iterator that can be [`collect`]ed into a vector of [`u16`]. -//! -//! Additionally, on Windows [`OsString`] implements the -//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt] -//! trait, which provides a [`from_wide`] method. The result of this -//! method is an `OsString` which can be round-tripped to a Windows -//! string losslessly. -//! -//! [`String`]: ../string/struct.String.html -//! [`str`]: ../primitive.str.html -//! [`char`]: ../primitive.char.html -//! [`u8`]: ../primitive.u8.html -//! [`u16`]: ../primitive.u16.html -//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value -//! [Unicode code point]: http://www.unicode.org/glossary/#code_point -//! [`CString`]: struct.CString.html -//! [`CStr`]: struct.CStr.html -//! [`OsString`]: struct.OsString.html -//! [`OsStr`]: struct.OsStr.html -//! [`env::set_var()`]: ../env/fn.set_var.html -//! [`env::var_os()`]: ../env/fn.var_os.html -//! [`Result<>`]: ../result/enum.Result.html -//! [unix.OsStringExt]: ../os/unix/ffi/trait.OsStringExt.html -//! [`from_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.from_vec -//! [`into_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.into_vec -//! [unix.OsStrExt]: ../os/unix/ffi/trait.OsStrExt.html -//! [`from_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.from_bytes -//! [`as_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.as_bytes -//! [`OsStrExt`]: ../os/unix/ffi/trait.OsStrExt.html -//! [windows.OsStrExt]: ../os/windows/ffi/trait.OsStrExt.html -//! [`encode_wide`]: ../os/windows/ffi/trait.OsStrExt.html#tymethod.encode_wide -//! [`collect`]: ../iter/trait.Iterator.html#method.collect -//! [windows.OsStringExt]: ../os/windows/ffi/trait.OsStringExt.html -//! [`from_wide`]: ../os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide - -#![stable(feature = "rust1", since = "1.0.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::c_str::{CString, CStr, NulError, IntoStringError}; -#[stable(feature = "cstr_from_bytes", since = "1.10.0")] -pub use self::c_str::{FromBytesWithNulError}; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::os_str::{OsString, OsStr}; - -mod c_str; -mod os_str; diff --git a/ctr-std/src/ffi/os_str.rs b/ctr-std/src/ffi/os_str.rs deleted file mode 100644 index 6bcd62d..0000000 --- a/ctr-std/src/ffi/os_str.rs +++ /dev/null @@ -1,1108 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use borrow::{Borrow, Cow}; -use fmt; -use ops; -use cmp; -use hash::{Hash, Hasher}; -use rc::Rc; -use sync::Arc; - -use sys::os_str::{Buf, Slice}; -use sys_common::{AsInner, IntoInner, FromInner}; - -/// A type that can represent owned, mutable platform-native strings, but is -/// cheaply inter-convertible with Rust strings. -/// -/// The need for this type arises from the fact that: -/// -/// * On Unix systems, strings are often arbitrary sequences of non-zero -/// bytes, in many cases interpreted as UTF-8. -/// -/// * On Windows, strings are often arbitrary sequences of non-zero 16-bit -/// values, interpreted as UTF-16 when it is valid to do so. -/// -/// * In Rust, strings are always valid UTF-8, which may contain zeros. -/// -/// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust -/// and platform-native string values, and in particular allowing a Rust string -/// to be converted into an "OS" string with no cost if possible. -/// -/// `OsString` is to [`&OsStr`] as [`String`] is to [`&str`]: the former -/// in each pair are owned strings; the latter are borrowed -/// references. -/// -/// # Creating an `OsString` -/// -/// **From a Rust string**: `OsString` implements -/// [`From`]`<`[`String`]`>`, so you can use `my_string.from` to -/// create an `OsString` from a normal Rust string. -/// -/// **From slices:** Just like you can start with an empty Rust -/// [`String`] and then [`push_str`][String.push_str] `&str` -/// sub-string slices into it, you can create an empty `OsString` with -/// the [`new`] method and then push string slices into it with the -/// [`push`] method. -/// -/// # Extracting a borrowed reference to the whole OS string -/// -/// You can use the [`as_os_str`] method to get an `&`[`OsStr`] from -/// an `OsString`; this is effectively a borrowed reference to the -/// whole string. -/// -/// # Conversions -/// -/// See the [module's toplevel documentation about conversions][conversions] for a discussion on -/// the traits which `OsString` implements for [conversions] from/to native representations. -/// -/// [`OsStr`]: struct.OsStr.html -/// [`&OsStr`]: struct.OsStr.html -/// [`From`]: ../convert/trait.From.html -/// [`String`]: ../string/struct.String.html -/// [`&str`]: ../primitive.str.html -/// [`u8`]: ../primitive.u8.html -/// [`u16`]: ../primitive.u16.html -/// [String.push_str]: ../string/struct.String.html#method.push_str -/// [`new`]: #method.new -/// [`push`]: #method.push -/// [`as_os_str`]: #method.as_os_str -/// [conversions]: index.html#conversions -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct OsString { - inner: Buf -} - -/// Borrowed reference to an OS string (see [`OsString`]). -/// -/// This type represents a borrowed reference to a string in the operating system's preferred -/// representation. -/// -/// `&OsStr` is to [`OsString`] as [`&str`] is to [`String`]: the former in each pair are borrowed -/// references; the latter are owned strings. -/// -/// See the [module's toplevel documentation about conversions][conversions] for a discussion on -/// the traits which `OsStr` implements for [conversions] from/to native representations. -/// -/// [`OsString`]: struct.OsString.html -/// [`&str`]: ../primitive.str.html -/// [`String`]: ../string/struct.String.html -/// [conversions]: index.html#conversions -#[stable(feature = "rust1", since = "1.0.0")] -pub struct OsStr { - inner: Slice -} - -impl OsString { - /// Constructs a new empty `OsString`. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// - /// let os_string = OsString::new(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> OsString { - OsString { inner: Buf::from_string(String::new()) } - } - - /// Converts to an [`OsStr`] slice. - /// - /// [`OsStr`]: struct.OsStr.html - /// - /// # Examples - /// - /// ``` - /// use std::ffi::{OsString, OsStr}; - /// - /// let os_string = OsString::from("foo"); - /// let os_str = OsStr::new("foo"); - /// assert_eq!(os_string.as_os_str(), os_str); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_os_str(&self) -> &OsStr { - self - } - - /// Converts the `OsString` into a [`String`] if it contains valid Unicode data. - /// - /// On failure, ownership of the original `OsString` is returned. - /// - /// [`String`]: ../../std/string/struct.String.html - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// - /// let os_string = OsString::from("foo"); - /// let string = os_string.into_string(); - /// assert_eq!(string, Ok(String::from("foo"))); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_string(self) -> Result { - self.inner.into_string().map_err(|buf| OsString { inner: buf} ) - } - - /// Extends the string with the given [`&OsStr`] slice. - /// - /// [`&OsStr`]: struct.OsStr.html - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// - /// let mut os_string = OsString::from("foo"); - /// os_string.push("bar"); - /// assert_eq!(&os_string, "foobar"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn push>(&mut self, s: T) { - self.inner.push_slice(&s.as_ref().inner) - } - - /// Creates a new `OsString` with the given capacity. - /// - /// The string will be able to hold exactly `capacity` length units of other - /// OS strings without reallocating. If `capacity` is 0, the string will not - /// allocate. - /// - /// See main `OsString` documentation information about encoding. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// - /// let mut os_string = OsString::with_capacity(10); - /// let capacity = os_string.capacity(); - /// - /// // This push is done without reallocating - /// os_string.push("foo"); - /// - /// assert_eq!(capacity, os_string.capacity()); - /// ``` - #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - pub fn with_capacity(capacity: usize) -> OsString { - OsString { - inner: Buf::with_capacity(capacity) - } - } - - /// Truncates the `OsString` to zero length. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// - /// let mut os_string = OsString::from("foo"); - /// assert_eq!(&os_string, "foo"); - /// - /// os_string.clear(); - /// assert_eq!(&os_string, ""); - /// ``` - #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - pub fn clear(&mut self) { - self.inner.clear() - } - - /// Returns the capacity this `OsString` can hold without reallocating. - /// - /// See `OsString` introduction for information about encoding. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// - /// let mut os_string = OsString::with_capacity(10); - /// assert!(os_string.capacity() >= 10); - /// ``` - #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - /// Reserves capacity for at least `additional` more capacity to be inserted - /// in the given `OsString`. - /// - /// The collection may reserve more space to avoid frequent reallocations. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// - /// let mut s = OsString::new(); - /// s.reserve(10); - /// assert!(s.capacity() >= 10); - /// ``` - #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - /// Reserves the minimum capacity for exactly `additional` more capacity to - /// be inserted in the given `OsString`. Does nothing if the capacity is - /// already sufficient. - /// - /// Note that the allocator may give the collection more space than it - /// requests. Therefore capacity can not be relied upon to be precisely - /// minimal. Prefer reserve if future insertions are expected. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// - /// let mut s = OsString::new(); - /// s.reserve_exact(10); - /// assert!(s.capacity() >= 10); - /// ``` - #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - /// Shrinks the capacity of the `OsString` to match its length. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// - /// let mut s = OsString::from("foo"); - /// - /// s.reserve(100); - /// assert!(s.capacity() >= 100); - /// - /// s.shrink_to_fit(); - /// assert_eq!(3, s.capacity()); - /// ``` - #[stable(feature = "osstring_shrink_to_fit", since = "1.19.0")] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - /// Shrinks the capacity of the `OsString` with a lower bound. - /// - /// The capacity will remain at least as large as both the length - /// and the supplied value. - /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. - /// - /// # Examples - /// - /// ``` - /// #![feature(shrink_to)] - /// use std::ffi::OsString; - /// - /// let mut s = OsString::from("foo"); - /// - /// s.reserve(100); - /// assert!(s.capacity() >= 100); - /// - /// s.shrink_to(10); - /// assert!(s.capacity() >= 10); - /// s.shrink_to(0); - /// assert!(s.capacity() >= 3); - /// ``` - #[inline] - #[unstable(feature = "shrink_to", reason = "new API", issue="0")] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - /// Converts this `OsString` into a boxed [`OsStr`]. - /// - /// [`OsStr`]: struct.OsStr.html - /// - /// # Examples - /// - /// ``` - /// use std::ffi::{OsString, OsStr}; - /// - /// let s = OsString::from("hello"); - /// - /// let b: Box = s.into_boxed_os_str(); - /// ``` - #[stable(feature = "into_boxed_os_str", since = "1.20.0")] - pub fn into_boxed_os_str(self) -> Box { - let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr; - unsafe { Box::from_raw(rw) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl From for OsString { - /// Converts a [`String`] into a [`OsString`]. - /// - /// The conversion copies the data, and includes an allocation on the heap. - /// - /// [`String`]: ../string/struct.String.html - /// [`OsString`]: struct.OsString.html - fn from(s: String) -> OsString { - OsString { inner: Buf::from_string(s) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized + AsRef> From<&'a T> for OsString { - fn from(s: &'a T) -> OsString { - s.as_ref().to_os_string() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for OsString { - type Output = OsStr; - - #[inline] - fn index(&self, _index: ops::RangeFull) -> &OsStr { - OsStr::from_inner(self.inner.as_slice()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::Deref for OsString { - type Target = OsStr; - - #[inline] - fn deref(&self) -> &OsStr { - &self[..] - } -} - -#[stable(feature = "osstring_default", since = "1.9.0")] -impl Default for OsString { - /// Constructs an empty `OsString`. - #[inline] - fn default() -> OsString { - OsString::new() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for OsString { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&**self, formatter) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for OsString { - fn eq(&self, other: &OsString) -> bool { - &**self == &**other - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for OsString { - fn eq(&self, other: &str) -> bool { - &**self == other - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for str { - fn eq(&self, other: &OsString) -> bool { - &**other == self - } -} - -#[stable(feature = "os_str_str_ref_eq", since = "1.28.0")] -impl<'a> PartialEq<&'a str> for OsString { - fn eq(&self, other: &&'a str) -> bool { - **self == **other - } -} - -#[stable(feature = "os_str_str_ref_eq", since = "1.28.0")] -impl<'a> PartialEq for &'a str { - fn eq(&self, other: &OsString) -> bool { - **other == **self - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for OsString {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for OsString { - #[inline] - fn partial_cmp(&self, other: &OsString) -> Option { - (&**self).partial_cmp(&**other) - } - #[inline] - fn lt(&self, other: &OsString) -> bool { &**self < &**other } - #[inline] - fn le(&self, other: &OsString) -> bool { &**self <= &**other } - #[inline] - fn gt(&self, other: &OsString) -> bool { &**self > &**other } - #[inline] - fn ge(&self, other: &OsString) -> bool { &**self >= &**other } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for OsString { - #[inline] - fn partial_cmp(&self, other: &str) -> Option { - (&**self).partial_cmp(other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for OsString { - #[inline] - fn cmp(&self, other: &OsString) -> cmp::Ordering { - (&**self).cmp(&**other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for OsString { - #[inline] - fn hash(&self, state: &mut H) { - (&**self).hash(state) - } -} - -impl OsStr { - /// Coerces into an `OsStr` slice. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// - /// let os_str = OsStr::new("foo"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new + ?Sized>(s: &S) -> &OsStr { - s.as_ref() - } - - fn from_inner(inner: &Slice) -> &OsStr { - unsafe { &*(inner as *const Slice as *const OsStr) } - } - - /// Yields a [`&str`] slice if the `OsStr` is valid Unicode. - /// - /// This conversion may entail doing a check for UTF-8 validity. - /// - /// [`&str`]: ../../std/primitive.str.html - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// - /// let os_str = OsStr::new("foo"); - /// assert_eq!(os_str.to_str(), Some("foo")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_str(&self) -> Option<&str> { - self.inner.to_str() - } - - /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`. - /// - /// Any non-Unicode sequences are replaced with - /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. - /// - /// [`Cow`]: ../../std/borrow/enum.Cow.html - /// [`str`]: ../../std/primitive.str.html - /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html - /// - /// # Examples - /// - /// Calling `to_string_lossy` on an `OsStr` with valid unicode: - /// - /// ``` - /// use std::ffi::OsStr; - /// - /// let os_str = OsStr::new("foo"); - /// assert_eq!(os_str.to_string_lossy(), "foo"); - /// ``` - /// - /// Had `os_str` contained invalid unicode, the `to_string_lossy` call might - /// have returned `"fo�"`. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_string_lossy(&self) -> Cow { - self.inner.to_string_lossy() - } - - /// Copies the slice into an owned [`OsString`]. - /// - /// [`OsString`]: struct.OsString.html - /// - /// # Examples - /// - /// ``` - /// use std::ffi::{OsStr, OsString}; - /// - /// let os_str = OsStr::new("foo"); - /// let os_string = os_str.to_os_string(); - /// assert_eq!(os_string, OsString::from("foo")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_os_string(&self) -> OsString { - OsString { inner: self.inner.to_owned() } - } - - /// Checks whether the `OsStr` is empty. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// - /// let os_str = OsStr::new(""); - /// assert!(os_str.is_empty()); - /// - /// let os_str = OsStr::new("foo"); - /// assert!(!os_str.is_empty()); - /// ``` - #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - pub fn is_empty(&self) -> bool { - self.inner.inner.is_empty() - } - - /// Returns the length of this `OsStr`. - /// - /// Note that this does **not** return the number of bytes in this string - /// as, for example, OS strings on Windows are encoded as a list of [`u16`] - /// rather than a list of bytes. This number is simply useful for passing to - /// other methods like [`OsString::with_capacity`] to avoid reallocations. - /// - /// See `OsStr` introduction for more information about encoding. - /// - /// [`u16`]: ../primitive.u16.html - /// [`OsString::with_capacity`]: struct.OsString.html#method.with_capacity - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// - /// let os_str = OsStr::new(""); - /// assert_eq!(os_str.len(), 0); - /// - /// let os_str = OsStr::new("foo"); - /// assert_eq!(os_str.len(), 3); - /// ``` - #[stable(feature = "osstring_simple_functions", since = "1.9.0")] - pub fn len(&self) -> usize { - self.inner.inner.len() - } - - /// Converts a [`Box`]`` into an [`OsString`] without copying or allocating. - /// - /// [`Box`]: ../boxed/struct.Box.html - /// [`OsString`]: struct.OsString.html - #[stable(feature = "into_boxed_os_str", since = "1.20.0")] - pub fn into_os_string(self: Box) -> OsString { - let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) }; - OsString { inner: Buf::from_box(boxed) } - } - - /// Gets the underlying byte representation. - /// - /// Note: it is *crucial* that this API is private, to avoid - /// revealing the internal, platform-specific encodings. - fn bytes(&self) -> &[u8] { - unsafe { &*(&self.inner as *const _ as *const [u8]) } - } -} - -#[stable(feature = "box_from_os_str", since = "1.17.0")] -impl<'a> From<&'a OsStr> for Box { - fn from(s: &'a OsStr) -> Box { - let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr; - unsafe { Box::from_raw(rw) } - } -} - -#[stable(feature = "os_string_from_box", since = "1.18.0")] -impl From> for OsString { - /// Converts a `Box` into a `OsString` without copying or allocating. - /// - /// [`Box`]: ../boxed/struct.Box.html - /// [`OsString`]: ../ffi/struct.OsString.html - fn from(boxed: Box) -> OsString { - boxed.into_os_string() - } -} - -#[stable(feature = "box_from_os_string", since = "1.20.0")] -impl From for Box { - /// Converts a [`OsString`] into a [`Box`]`` without copying or allocating. - /// - /// [`Box`]: ../boxed/struct.Box.html - /// [`OsString`]: ../ffi/struct.OsString.html - fn from(s: OsString) -> Box { - s.into_boxed_os_str() - } -} - -#[stable(feature = "more_box_slice_clone", since = "1.29.0")] -impl Clone for Box { - #[inline] - fn clone(&self) -> Self { - self.to_os_string().into_boxed_os_str() - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl From for Arc { - /// Converts a [`OsString`] into a [`Arc`]`` without copying or allocating. - /// - /// [`Arc`]: ../sync/struct.Arc.html - /// [`OsString`]: ../ffi/struct.OsString.html - #[inline] - fn from(s: OsString) -> Arc { - let arc = s.inner.into_arc(); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) } - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a OsStr> for Arc { - #[inline] - fn from(s: &OsStr) -> Arc { - let arc = s.inner.into_arc(); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) } - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl From for Rc { - /// Converts a [`OsString`] into a [`Rc`]`` without copying or allocating. - /// - /// [`Rc`]: ../rc/struct.Rc.html - /// [`OsString`]: ../ffi/struct.OsString.html - #[inline] - fn from(s: OsString) -> Rc { - let rc = s.inner.into_rc(); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) } - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a OsStr> for Rc { - #[inline] - fn from(s: &OsStr) -> Rc { - let rc = s.inner.into_rc(); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) } - } -} - -#[stable(feature = "cow_from_osstr", since = "1.28.0")] -impl<'a> From for Cow<'a, OsStr> { - #[inline] - fn from(s: OsString) -> Cow<'a, OsStr> { - Cow::Owned(s) - } -} - -#[stable(feature = "cow_from_osstr", since = "1.28.0")] -impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { - #[inline] - fn from(s: &'a OsStr) -> Cow<'a, OsStr> { - Cow::Borrowed(s) - } -} - -#[stable(feature = "cow_from_osstr", since = "1.28.0")] -impl<'a> From<&'a OsString> for Cow<'a, OsStr> { - #[inline] - fn from(s: &'a OsString) -> Cow<'a, OsStr> { - Cow::Borrowed(s.as_os_str()) - } -} - -#[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")] -impl<'a> From> for OsString { - #[inline] - fn from(s: Cow<'a, OsStr>) -> Self { - s.into_owned() - } -} - -#[stable(feature = "box_default_extra", since = "1.17.0")] -impl Default for Box { - fn default() -> Box { - let rw = Box::into_raw(Slice::empty_box()) as *mut OsStr; - unsafe { Box::from_raw(rw) } - } -} - -#[stable(feature = "osstring_default", since = "1.9.0")] -impl<'a> Default for &'a OsStr { - /// Creates an empty `OsStr`. - #[inline] - fn default() -> &'a OsStr { - OsStr::new("") - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for OsStr { - fn eq(&self, other: &OsStr) -> bool { - self.bytes().eq(other.bytes()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for OsStr { - fn eq(&self, other: &str) -> bool { - *self == *OsStr::new(other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for str { - fn eq(&self, other: &OsStr) -> bool { - *other == *OsStr::new(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for OsStr {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for OsStr { - #[inline] - fn partial_cmp(&self, other: &OsStr) -> Option { - self.bytes().partial_cmp(other.bytes()) - } - #[inline] - fn lt(&self, other: &OsStr) -> bool { self.bytes().lt(other.bytes()) } - #[inline] - fn le(&self, other: &OsStr) -> bool { self.bytes().le(other.bytes()) } - #[inline] - fn gt(&self, other: &OsStr) -> bool { self.bytes().gt(other.bytes()) } - #[inline] - fn ge(&self, other: &OsStr) -> bool { self.bytes().ge(other.bytes()) } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for OsStr { - #[inline] - fn partial_cmp(&self, other: &str) -> Option { - self.partial_cmp(OsStr::new(other)) - } -} - -// FIXME (#19470): cannot provide PartialOrd for str until we -// have more flexible coherence rules. - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for OsStr { - #[inline] - fn cmp(&self, other: &OsStr) -> cmp::Ordering { self.bytes().cmp(other.bytes()) } -} - -macro_rules! impl_cmp { - ($lhs:ty, $rhs: ty) => { - #[stable(feature = "cmp_os_str", since = "1.8.0")] - impl<'a, 'b> PartialEq<$rhs> for $lhs { - #[inline] - fn eq(&self, other: &$rhs) -> bool { ::eq(self, other) } - } - - #[stable(feature = "cmp_os_str", since = "1.8.0")] - impl<'a, 'b> PartialEq<$lhs> for $rhs { - #[inline] - fn eq(&self, other: &$lhs) -> bool { ::eq(self, other) } - } - - #[stable(feature = "cmp_os_str", since = "1.8.0")] - impl<'a, 'b> PartialOrd<$rhs> for $lhs { - #[inline] - fn partial_cmp(&self, other: &$rhs) -> Option { - ::partial_cmp(self, other) - } - } - - #[stable(feature = "cmp_os_str", since = "1.8.0")] - impl<'a, 'b> PartialOrd<$lhs> for $rhs { - #[inline] - fn partial_cmp(&self, other: &$lhs) -> Option { - ::partial_cmp(self, other) - } - } - } -} - -impl_cmp!(OsString, OsStr); -impl_cmp!(OsString, &'a OsStr); -impl_cmp!(Cow<'a, OsStr>, OsStr); -impl_cmp!(Cow<'a, OsStr>, &'b OsStr); -impl_cmp!(Cow<'a, OsStr>, OsString); - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for OsStr { - #[inline] - fn hash(&self, state: &mut H) { - self.bytes().hash(state) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for OsStr { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.inner, formatter) - } -} - -impl OsStr { - pub(crate) fn display(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.inner, formatter) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Borrow for OsString { - fn borrow(&self) -> &OsStr { &self[..] } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToOwned for OsStr { - type Owned = OsString; - fn to_owned(&self) -> OsString { - self.to_os_string() - } - fn clone_into(&self, target: &mut OsString) { - target.clear(); - target.push(self); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for OsStr { - fn as_ref(&self) -> &OsStr { - self - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for OsString { - fn as_ref(&self) -> &OsStr { - self - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for str { - fn as_ref(&self) -> &OsStr { - OsStr::from_inner(Slice::from_str(self)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for String { - fn as_ref(&self) -> &OsStr { - (&**self).as_ref() - } -} - -impl FromInner for OsString { - fn from_inner(buf: Buf) -> OsString { - OsString { inner: buf } - } -} - -impl IntoInner for OsString { - fn into_inner(self) -> Buf { - self.inner - } -} - -impl AsInner for OsStr { - fn as_inner(&self) -> &Slice { - &self.inner - } -} - -#[cfg(test)] -mod tests { - use super::*; - use sys_common::{AsInner, IntoInner}; - - use rc::Rc; - use sync::Arc; - - #[test] - fn test_os_string_with_capacity() { - let os_string = OsString::with_capacity(0); - assert_eq!(0, os_string.inner.into_inner().capacity()); - - let os_string = OsString::with_capacity(10); - assert_eq!(10, os_string.inner.into_inner().capacity()); - - let mut os_string = OsString::with_capacity(0); - os_string.push("abc"); - assert!(os_string.inner.into_inner().capacity() >= 3); - } - - #[test] - fn test_os_string_clear() { - let mut os_string = OsString::from("abc"); - assert_eq!(3, os_string.inner.as_inner().len()); - - os_string.clear(); - assert_eq!(&os_string, ""); - assert_eq!(0, os_string.inner.as_inner().len()); - } - - #[test] - fn test_os_string_capacity() { - let os_string = OsString::with_capacity(0); - assert_eq!(0, os_string.capacity()); - - let os_string = OsString::with_capacity(10); - assert_eq!(10, os_string.capacity()); - - let mut os_string = OsString::with_capacity(0); - os_string.push("abc"); - assert!(os_string.capacity() >= 3); - } - - #[test] - fn test_os_string_reserve() { - let mut os_string = OsString::new(); - assert_eq!(os_string.capacity(), 0); - - os_string.reserve(2); - assert!(os_string.capacity() >= 2); - - for _ in 0..16 { - os_string.push("a"); - } - - assert!(os_string.capacity() >= 16); - os_string.reserve(16); - assert!(os_string.capacity() >= 32); - - os_string.push("a"); - - os_string.reserve(16); - assert!(os_string.capacity() >= 33) - } - - #[test] - fn test_os_string_reserve_exact() { - let mut os_string = OsString::new(); - assert_eq!(os_string.capacity(), 0); - - os_string.reserve_exact(2); - assert!(os_string.capacity() >= 2); - - for _ in 0..16 { - os_string.push("a"); - } - - assert!(os_string.capacity() >= 16); - os_string.reserve_exact(16); - assert!(os_string.capacity() >= 32); - - os_string.push("a"); - - os_string.reserve_exact(16); - assert!(os_string.capacity() >= 33) - } - - #[test] - fn test_os_string_default() { - let os_string: OsString = Default::default(); - assert_eq!("", &os_string); - } - - #[test] - fn test_os_str_is_empty() { - let mut os_string = OsString::new(); - assert!(os_string.is_empty()); - - os_string.push("abc"); - assert!(!os_string.is_empty()); - - os_string.clear(); - assert!(os_string.is_empty()); - } - - #[test] - fn test_os_str_len() { - let mut os_string = OsString::new(); - assert_eq!(0, os_string.len()); - - os_string.push("abc"); - assert_eq!(3, os_string.len()); - - os_string.clear(); - assert_eq!(0, os_string.len()); - } - - #[test] - fn test_os_str_default() { - let os_str: &OsStr = Default::default(); - assert_eq!("", os_str); - } - - #[test] - fn into_boxed() { - let orig = "Hello, world!"; - let os_str = OsStr::new(orig); - let boxed: Box = Box::from(os_str); - let os_string = os_str.to_owned().into_boxed_os_str().into_os_string(); - assert_eq!(os_str, &*boxed); - assert_eq!(&*boxed, &*os_string); - assert_eq!(&*os_string, os_str); - } - - #[test] - fn boxed_default() { - let boxed = >::default(); - assert!(boxed.is_empty()); - } - - #[test] - fn test_os_str_clone_into() { - let mut os_string = OsString::with_capacity(123); - os_string.push("hello"); - let os_str = OsStr::new("bonjour"); - os_str.clone_into(&mut os_string); - assert_eq!(os_str, os_string); - assert!(os_string.capacity() >= 123); - } - - #[test] - fn into_rc() { - let orig = "Hello, world!"; - let os_str = OsStr::new(orig); - let rc: Rc = Rc::from(os_str); - let arc: Arc = Arc::from(os_str); - - assert_eq!(&*rc, os_str); - assert_eq!(&*arc, os_str); - - let rc2: Rc = Rc::from(os_str.to_owned()); - let arc2: Arc = Arc::from(os_str.to_owned()); - - assert_eq!(&*rc2, os_str); - assert_eq!(&*arc2, os_str); - } -} diff --git a/ctr-std/src/fs.rs b/ctr-std/src/fs.rs deleted file mode 100644 index 7632fbc..0000000 --- a/ctr-std/src/fs.rs +++ /dev/null @@ -1,3334 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Filesystem manipulation operations. -//! -//! This module contains basic methods to manipulate the contents of the local -//! filesystem. All methods in this module represent cross-platform filesystem -//! operations. Extra platform-specific functionality can be found in the -//! extension traits of `std::os::$platform`. - -#![stable(feature = "rust1", since = "1.0.0")] - -use fmt; -use ffi::OsString; -use io::{self, SeekFrom, Seek, Read, Initializer, Write}; -use path::{Path, PathBuf}; -use sys::fs as fs_imp; -use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner}; -use time::SystemTime; - -/// A reference to an open file on the filesystem. -/// -/// An instance of a `File` can be read and/or written depending on what options -/// it was opened with. Files also implement [`Seek`] to alter the logical cursor -/// that the file contains internally. -/// -/// Files are automatically closed when they go out of scope. -/// -/// # Examples -/// -/// Create a new file and write bytes to it: -/// -/// ```no_run -/// use std::fs::File; -/// use std::io::prelude::*; -/// -/// fn main() -> std::io::Result<()> { -/// let mut file = File::create("foo.txt")?; -/// file.write_all(b"Hello, world!")?; -/// Ok(()) -/// } -/// ``` -/// -/// Read the contents of a file into a [`String`]: -/// -/// ```no_run -/// use std::fs::File; -/// use std::io::prelude::*; -/// -/// fn main() -> std::io::Result<()> { -/// let mut file = File::open("foo.txt")?; -/// let mut contents = String::new(); -/// file.read_to_string(&mut contents)?; -/// assert_eq!(contents, "Hello, world!"); -/// Ok(()) -/// } -/// ``` -/// -/// It can be more efficient to read the contents of a file with a buffered -/// [`Read`]er. This can be accomplished with [`BufReader`]: -/// -/// ```no_run -/// use std::fs::File; -/// use std::io::BufReader; -/// use std::io::prelude::*; -/// -/// fn main() -> std::io::Result<()> { -/// let file = File::open("foo.txt")?; -/// let mut buf_reader = BufReader::new(file); -/// let mut contents = String::new(); -/// buf_reader.read_to_string(&mut contents)?; -/// assert_eq!(contents, "Hello, world!"); -/// Ok(()) -/// } -/// ``` -/// -/// Note that, although read and write methods require a `&mut File`, because -/// of the interfaces for [`Read`] and [`Write`], the holder of a `&File` can -/// still modify the file, either through methods that take `&File` or by -/// retrieving the underlying OS object and modifying the file that way. -/// Additionally, many operating systems allow concurrent modification of files -/// by different processes. Avoid assuming that holding a `&File` means that the -/// file will not change. -/// -/// [`Seek`]: ../io/trait.Seek.html -/// [`String`]: ../string/struct.String.html -/// [`Read`]: ../io/trait.Read.html -/// [`Write`]: ../io/trait.Write.html -/// [`BufReader`]: ../io/struct.BufReader.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct File { - inner: fs_imp::File, -} - -/// Metadata information about a file. -/// -/// This structure is returned from the [`metadata`] or -/// [`symlink_metadata`] function or method and represents known -/// metadata about a file such as its permissions, size, modification -/// times, etc. -/// -/// [`metadata`]: fn.metadata.html -/// [`symlink_metadata`]: fn.symlink_metadata.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Metadata(fs_imp::FileAttr); - -/// Iterator over the entries in a directory. -/// -/// This iterator is returned from the [`read_dir`] function of this module and -/// will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. Through a [`DirEntry`] -/// information like the entry's path and possibly other metadata can be -/// learned. -/// -/// # Errors -/// -/// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent -/// IO error during iteration. -/// -/// [`read_dir`]: fn.read_dir.html -/// [`DirEntry`]: struct.DirEntry.html -/// [`io::Result`]: ../io/type.Result.html -/// [`Err`]: ../result/enum.Result.html#variant.Err -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct ReadDir(fs_imp::ReadDir); - -/// Entries returned by the [`ReadDir`] iterator. -/// -/// [`ReadDir`]: struct.ReadDir.html -/// -/// An instance of `DirEntry` represents an entry inside of a directory on the -/// filesystem. Each entry can be inspected via methods to learn about the full -/// path or possibly other metadata through per-platform extension traits. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct DirEntry(fs_imp::DirEntry); - -/// Options and flags which can be used to configure how a file is opened. -/// -/// This builder exposes the ability to configure how a [`File`] is opened and -/// what operations are permitted on the open file. The [`File::open`] and -/// [`File::create`] methods are aliases for commonly used options using this -/// builder. -/// -/// [`File`]: struct.File.html -/// [`File::open`]: struct.File.html#method.open -/// [`File::create`]: struct.File.html#method.create -/// -/// Generally speaking, when using `OpenOptions`, you'll first call [`new`], -/// then chain calls to methods to set each option, then call [`open`], -/// passing the path of the file you're trying to open. This will give you a -/// [`io::Result`][result] with a [`File`][file] inside that you can further -/// operate on. -/// -/// [`new`]: struct.OpenOptions.html#method.new -/// [`open`]: struct.OpenOptions.html#method.open -/// [result]: ../io/type.Result.html -/// [file]: struct.File.html -/// -/// # Examples -/// -/// Opening a file to read: -/// -/// ```no_run -/// use std::fs::OpenOptions; -/// -/// let file = OpenOptions::new().read(true).open("foo.txt"); -/// ``` -/// -/// Opening a file for both reading and writing, as well as creating it if it -/// doesn't exist: -/// -/// ```no_run -/// use std::fs::OpenOptions; -/// -/// let file = OpenOptions::new() -/// .read(true) -/// .write(true) -/// .create(true) -/// .open("foo.txt"); -/// ``` -#[derive(Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct OpenOptions(fs_imp::OpenOptions); - -/// Representation of the various permissions on a file. -/// -/// This module only currently provides one bit of information, [`readonly`], -/// which is exposed on all currently supported platforms. Unix-specific -/// functionality, such as mode bits, is available through the -/// `os::unix::PermissionsExt` trait. -/// -/// [`readonly`]: struct.Permissions.html#method.readonly -#[derive(Clone, PartialEq, Eq, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Permissions(fs_imp::FilePermissions); - -/// A structure representing a type of file with accessors for each file type. -/// It is returned by [`Metadata::file_type`] method. -/// -/// [`Metadata::file_type`]: struct.Metadata.html#method.file_type -#[stable(feature = "file_type", since = "1.1.0")] -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct FileType(fs_imp::FileType); - -/// A builder used to create directories in various manners. -/// -/// This builder also supports platform-specific options. -#[stable(feature = "dir_builder", since = "1.6.0")] -#[derive(Debug)] -pub struct DirBuilder { - inner: fs_imp::DirBuilder, - recursive: bool, -} - -/// How large a buffer to pre-allocate before reading the entire file. -fn initial_buffer_size(file: &File) -> usize { - // Allocate one extra byte so the buffer doesn't need to grow before the - // final `read` call at the end of the file. Don't worry about `usize` - // overflow because reading will fail regardless in that case. - file.metadata().map(|m| m.len() as usize + 1).unwrap_or(0) -} - -/// Read the entire contents of a file into a bytes vector. -/// -/// This is a convenience function for using [`File::open`] and [`read_to_end`] -/// with fewer imports and without an intermediate variable. It pre-allocates a -/// buffer based on the file size when available, so it is generally faster than -/// reading into a vector created with `Vec::new()`. -/// -/// [`File::open`]: struct.File.html#method.open -/// [`read_to_end`]: ../io/trait.Read.html#method.read_to_end -/// -/// # Errors -/// -/// This function will return an error if `path` does not already exist. -/// Other errors may also be returned according to [`OpenOptions::open`]. -/// -/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open -/// -/// It will also return an error if it encounters while reading an error -/// of a kind other than [`ErrorKind::Interrupted`]. -/// -/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// use std::net::SocketAddr; -/// -/// fn main() -> Result<(), Box> { -/// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "fs_read_write_bytes", since = "1.26.0")] -pub fn read>(path: P) -> io::Result> { - let mut file = File::open(path)?; - let mut bytes = Vec::with_capacity(initial_buffer_size(&file)); - file.read_to_end(&mut bytes)?; - Ok(bytes) -} - -/// Read the entire contents of a file into a string. -/// -/// This is a convenience function for using [`File::open`] and [`read_to_string`] -/// with fewer imports and without an intermediate variable. It pre-allocates a -/// buffer based on the file size when available, so it is generally faster than -/// reading into a string created with `String::new()`. -/// -/// [`File::open`]: struct.File.html#method.open -/// [`read_to_string`]: ../io/trait.Read.html#method.read_to_string -/// -/// # Errors -/// -/// This function will return an error if `path` does not already exist. -/// Other errors may also be returned according to [`OpenOptions::open`]. -/// -/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open -/// -/// It will also return an error if it encounters while reading an error -/// of a kind other than [`ErrorKind::Interrupted`], -/// or if the contents of the file are not valid UTF-8. -/// -/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// use std::net::SocketAddr; -/// -/// fn main() -> Result<(), Box> { -/// let foo: SocketAddr = fs::read_to_string("address.txt")?.parse()?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "fs_read_write", since = "1.26.0")] -pub fn read_to_string>(path: P) -> io::Result { - let mut file = File::open(path)?; - let mut string = String::with_capacity(initial_buffer_size(&file)); - file.read_to_string(&mut string)?; - Ok(string) -} - -/// Write a slice as the entire contents of a file. -/// -/// This function will create a file if it does not exist, -/// and will entirely replace its contents if it does. -/// -/// This is a convenience function for using [`File::create`] and [`write_all`] -/// with fewer imports. -/// -/// [`File::create`]: struct.File.html#method.create -/// [`write_all`]: ../io/trait.Write.html#method.write_all -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::write("foo.txt", b"Lorem ipsum")?; -/// fs::write("bar.txt", "dolor sit")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "fs_read_write_bytes", since = "1.26.0")] -pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { - File::create(path)?.write_all(contents.as_ref()) -} - -impl File { - /// Attempts to open a file in read-only mode. - /// - /// See the [`OpenOptions::open`] method for more details. - /// - /// # Errors - /// - /// This function will return an error if `path` does not already exist. - /// Other errors may also be returned according to [`OpenOptions::open`]. - /// - /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn open>(path: P) -> io::Result { - OpenOptions::new().read(true).open(path.as_ref()) - } - - /// Opens a file in write-only mode. - /// - /// This function will create a file if it does not exist, - /// and will truncate it if it does. - /// - /// See the [`OpenOptions::open`] function for more details. - /// - /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn create>(path: P) -> io::Result { - OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref()) - } - - /// Attempts to sync all OS-internal metadata to disk. - /// - /// This function will attempt to ensure that all in-core data reaches the - /// filesystem before returning. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::prelude::*; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.write_all(b"Hello, world!")?; - /// - /// f.sync_all()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn sync_all(&self) -> io::Result<()> { - self.inner.fsync() - } - - /// This function is similar to [`sync_all`], except that it may not - /// synchronize file metadata to the filesystem. - /// - /// This is intended for use cases that must synchronize content, but don't - /// need the metadata on disk. The goal of this method is to reduce disk - /// operations. - /// - /// Note that some platforms may simply implement this in terms of - /// [`sync_all`]. - /// - /// [`sync_all`]: struct.File.html#method.sync_all - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::prelude::*; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.write_all(b"Hello, world!")?; - /// - /// f.sync_data()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn sync_data(&self) -> io::Result<()> { - self.inner.datasync() - } - - /// Truncates or extends the underlying file, updating the size of - /// this file to become `size`. - /// - /// If the `size` is less than the current file's size, then the file will - /// be shrunk. If it is greater than the current file's size, then the file - /// will be extended to `size` and have all of the intermediate data filled - /// in with 0s. - /// - /// The file's cursor isn't changed. In particular, if the cursor was at the - /// end and the file is shrunk using this operation, the cursor will now be - /// past the end. - /// - /// # Errors - /// - /// This function will return an error if the file is not opened for writing. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.set_len(10)?; - /// Ok(()) - /// } - /// ``` - /// - /// Note that this method alters the content of the underlying file, even - /// though it takes `&self` rather than `&mut self`. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_len(&self, size: u64) -> io::Result<()> { - self.inner.truncate(size) - } - - /// Queries metadata about the underlying file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let metadata = f.metadata()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn metadata(&self) -> io::Result { - self.inner.file_attr().map(Metadata) - } - - /// Create a new `File` instance that shares the same underlying file handle - /// as the existing `File` instance. Reads, writes, and seeks will affect - /// both `File` instances simultaneously. - /// - /// # Examples - /// - /// Create two handles for a file named `foo.txt`: - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// let file_copy = file.try_clone()?; - /// Ok(()) - /// } - /// ``` - /// - /// Assuming there’s a file named `foo.txt` with contents `abcdef\n`, create - /// two handles, seek one of them, and read the remaining bytes from the - /// other handle: - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::SeekFrom; - /// use std::io::prelude::*; - /// - /// fn main() -> std::io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// let mut file_copy = file.try_clone()?; - /// - /// file.seek(SeekFrom::Start(3))?; - /// - /// let mut contents = vec![]; - /// file_copy.read_to_end(&mut contents)?; - /// assert_eq!(contents, b"def\n"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_try_clone", since = "1.9.0")] - pub fn try_clone(&self) -> io::Result { - Ok(File { - inner: self.inner.duplicate()? - }) - } - - /// Changes the permissions on the underlying file. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `fchmod` function on Unix and - /// the `SetFileInformationByHandle` function on Windows. Note that, this - /// [may change in the future][changes]. - /// - /// [changes]: ../io/index.html#platform-specific-behavior - /// - /// # Errors - /// - /// This function will return an error if the user lacks permission change - /// attributes on the underlying file. It may also return an error in other - /// os-specific unspecified cases. - /// - /// # Examples - /// - /// ```no_run - /// fn main() -> std::io::Result<()> { - /// use std::fs::File; - /// - /// let file = File::open("foo.txt")?; - /// let mut perms = file.metadata()?.permissions(); - /// perms.set_readonly(true); - /// file.set_permissions(perms)?; - /// Ok(()) - /// } - /// ``` - /// - /// Note that this method alters the permissions of the underlying file, - /// even though it takes `&self` rather than `&mut self`. - #[stable(feature = "set_permissions_atomic", since = "1.16.0")] - pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> { - self.inner.set_permissions(perm.0) - } -} - -impl AsInner for File { - fn as_inner(&self) -> &fs_imp::File { &self.inner } -} -impl FromInner for File { - fn from_inner(f: fs_imp::File) -> File { - File { inner: f } - } -} -impl IntoInner for File { - fn into_inner(self) -> fs_imp::File { - self.inner - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.inner.fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for File { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for File { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) - } - fn flush(&mut self) -> io::Result<()> { self.inner.flush() } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Seek for File { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.inner.seek(pos) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Read for &'a File { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Write for &'a File { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) - } - fn flush(&mut self) -> io::Result<()> { self.inner.flush() } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Seek for &'a File { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.inner.seek(pos) - } -} - -impl OpenOptions { - /// Creates a blank new set of options ready for configuration. - /// - /// All options are initially set to `false`. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let mut options = OpenOptions::new(); - /// let file = options.read(true).open("foo.txt"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> OpenOptions { - OpenOptions(fs_imp::OpenOptions::new()) - } - - /// Sets the option for read access. - /// - /// This option, when true, will indicate that the file should be - /// `read`-able if opened. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().read(true).open("foo.txt"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn read(&mut self, read: bool) -> &mut OpenOptions { - self.0.read(read); self - } - - /// Sets the option for write access. - /// - /// This option, when true, will indicate that the file should be - /// `write`-able if opened. - /// - /// If the file already exists, any write calls on it will overwrite its - /// contents, without truncating it. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().write(true).open("foo.txt"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn write(&mut self, write: bool) -> &mut OpenOptions { - self.0.write(write); self - } - - /// Sets the option for the append mode. - /// - /// This option, when true, means that writes will append to a file instead - /// of overwriting previous contents. - /// Note that setting `.write(true).append(true)` has the same effect as - /// setting only `.append(true)`. - /// - /// For most filesystems, the operating system guarantees that all writes are - /// atomic: no writes get mangled because another process writes at the same - /// time. - /// - /// One maybe obvious note when using append-mode: make sure that all data - /// that belongs together is written to the file in one operation. This - /// can be done by concatenating strings before passing them to [`write()`], - /// or using a buffered writer (with a buffer of adequate size), - /// and calling [`flush()`] when the message is complete. - /// - /// If a file is opened with both read and append access, beware that after - /// opening, and after every write, the position for reading may be set at the - /// end of the file. So, before writing, save the current position (using - /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`, and restore it before the next read. - /// - /// ## Note - /// - /// This function doesn't create the file if it doesn't exist. Use the [`create`] - /// method to do so. - /// - /// [`write()`]: ../../std/fs/struct.File.html#method.write - /// [`flush()`]: ../../std/fs/struct.File.html#method.flush - /// [`seek`]: ../../std/fs/struct.File.html#method.seek - /// [`SeekFrom`]: ../../std/io/enum.SeekFrom.html - /// [`Current`]: ../../std/io/enum.SeekFrom.html#variant.Current - /// [`create`]: #method.create - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().append(true).open("foo.txt"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn append(&mut self, append: bool) -> &mut OpenOptions { - self.0.append(append); self - } - - /// Sets the option for truncating a previous file. - /// - /// If a file is successfully opened with this option set it will truncate - /// the file to 0 length if it already exists. - /// - /// The file must be opened with write access for truncate to work. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().write(true).truncate(true).open("foo.txt"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions { - self.0.truncate(truncate); self - } - - /// Sets the option for creating a new file. - /// - /// This option indicates whether a new file will be created if the file - /// does not yet already exist. - /// - /// In order for the file to be created, [`write`] or [`append`] access must - /// be used. - /// - /// [`write`]: #method.write - /// [`append`]: #method.append - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().write(true).create(true).open("foo.txt"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn create(&mut self, create: bool) -> &mut OpenOptions { - self.0.create(create); self - } - - /// Sets the option to always create a new file. - /// - /// This option indicates whether a new file will be created. - /// No file is allowed to exist at the target location, also no (dangling) - /// symlink. - /// - /// This option is useful because it is atomic. Otherwise between checking - /// whether a file exists and creating a new one, the file may have been - /// created by another process (a TOCTOU race condition / attack). - /// - /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are - /// ignored. - /// - /// The file must be opened with write or append access in order to create - /// a new file. - /// - /// [`.create()`]: #method.create - /// [`.truncate()`]: #method.truncate - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().write(true) - /// .create_new(true) - /// .open("foo.txt"); - /// ``` - #[stable(feature = "expand_open_options2", since = "1.9.0")] - pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions { - self.0.create_new(create_new); self - } - - /// Opens a file at `path` with the options specified by `self`. - /// - /// # Errors - /// - /// This function will return an error under a number of different - /// circumstances. Some of these error conditions are listed here, together - /// with their [`ErrorKind`]. The mapping to [`ErrorKind`]s is not part of - /// the compatibility contract of the function, especially the `Other` kind - /// might change to more specific kinds in the future. - /// - /// * [`NotFound`]: The specified file does not exist and neither `create` - /// or `create_new` is set. - /// * [`NotFound`]: One of the directory components of the file path does - /// not exist. - /// * [`PermissionDenied`]: The user lacks permission to get the specified - /// access rights for the file. - /// * [`PermissionDenied`]: The user lacks permission to open one of the - /// directory components of the specified path. - /// * [`AlreadyExists`]: `create_new` was specified and the file already - /// exists. - /// * [`InvalidInput`]: Invalid combinations of open options (truncate - /// without write access, no access mode set, etc.). - /// * [`Other`]: One of the directory components of the specified file path - /// was not, in fact, a directory. - /// * [`Other`]: Filesystem-level errors: full disk, write permission - /// requested on a read-only file system, exceeded disk quota, too many - /// open files, too long filename, too many symbolic links in the - /// specified path (Unix-like systems only), etc. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().open("foo.txt"); - /// ``` - /// - /// [`ErrorKind`]: ../io/enum.ErrorKind.html - /// [`AlreadyExists`]: ../io/enum.ErrorKind.html#variant.AlreadyExists - /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput - /// [`NotFound`]: ../io/enum.ErrorKind.html#variant.NotFound - /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other - /// [`PermissionDenied`]: ../io/enum.ErrorKind.html#variant.PermissionDenied - #[stable(feature = "rust1", since = "1.0.0")] - pub fn open>(&self, path: P) -> io::Result { - self._open(path.as_ref()) - } - - fn _open(&self, path: &Path) -> io::Result { - let inner = fs_imp::File::open(path, &self.0)?; - Ok(File { inner: inner }) - } -} - -impl AsInnerMut for OpenOptions { - fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 } -} - -impl Metadata { - /// Returns the file type for this metadata. - /// - /// # Examples - /// - /// ```no_run - /// fn main() -> std::io::Result<()> { - /// use std::fs; - /// - /// let metadata = fs::metadata("foo.txt")?; - /// - /// println!("{:?}", metadata.file_type()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type", since = "1.1.0")] - pub fn file_type(&self) -> FileType { - FileType(self.0.file_type()) - } - - /// Returns whether this metadata is for a directory. The - /// result is mutually exclusive to the result of - /// [`is_file`], and will be false for symlink metadata - /// obtained from [`symlink_metadata`]. - /// - /// [`is_file`]: struct.Metadata.html#method.is_file - /// [`symlink_metadata`]: fn.symlink_metadata.html - /// - /// # Examples - /// - /// ```no_run - /// fn main() -> std::io::Result<()> { - /// use std::fs; - /// - /// let metadata = fs::metadata("foo.txt")?; - /// - /// assert!(!metadata.is_dir()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_dir(&self) -> bool { self.file_type().is_dir() } - - /// Returns whether this metadata is for a regular file. The - /// result is mutually exclusive to the result of - /// [`is_dir`], and will be false for symlink metadata - /// obtained from [`symlink_metadata`]. - /// - /// [`is_dir`]: struct.Metadata.html#method.is_dir - /// [`symlink_metadata`]: fn.symlink_metadata.html - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// assert!(metadata.is_file()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_file(&self) -> bool { self.file_type().is_file() } - - /// Returns the size of the file, in bytes, this metadata is for. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// assert_eq!(0, metadata.len()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> u64 { self.0.size() } - - /// Returns the permissions of the file this metadata is for. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// assert!(!metadata.permissions().readonly()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn permissions(&self) -> Permissions { - Permissions(self.0.perm()) - } - - /// Returns the last modification time listed in this metadata. - /// - /// The returned value corresponds to the `mtime` field of `stat` on Unix - /// platforms and the `ftLastWriteTime` field on Windows platforms. - /// - /// # Errors - /// - /// This field may not be available on all platforms, and will return an - /// `Err` on platforms where it is not available. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// if let Ok(time) = metadata.modified() { - /// println!("{:?}", time); - /// } else { - /// println!("Not supported on this platform"); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "fs_time", since = "1.10.0")] - pub fn modified(&self) -> io::Result { - self.0.modified().map(FromInner::from_inner) - } - - /// Returns the last access time of this metadata. - /// - /// The returned value corresponds to the `atime` field of `stat` on Unix - /// platforms and the `ftLastAccessTime` field on Windows platforms. - /// - /// Note that not all platforms will keep this field update in a file's - /// metadata, for example Windows has an option to disable updating this - /// time when files are accessed and Linux similarly has `noatime`. - /// - /// # Errors - /// - /// This field may not be available on all platforms, and will return an - /// `Err` on platforms where it is not available. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// if let Ok(time) = metadata.accessed() { - /// println!("{:?}", time); - /// } else { - /// println!("Not supported on this platform"); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "fs_time", since = "1.10.0")] - pub fn accessed(&self) -> io::Result { - self.0.accessed().map(FromInner::from_inner) - } - - /// Returns the creation time listed in this metadata. - /// - /// The returned value corresponds to the `birthtime` field of `stat` on - /// Unix platforms and the `ftCreationTime` field on Windows platforms. - /// - /// # Errors - /// - /// This field may not be available on all platforms, and will return an - /// `Err` on platforms where it is not available. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// if let Ok(time) = metadata.created() { - /// println!("{:?}", time); - /// } else { - /// println!("Not supported on this platform"); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "fs_time", since = "1.10.0")] - pub fn created(&self) -> io::Result { - self.0.created().map(FromInner::from_inner) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Metadata { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Metadata") - .field("file_type", &self.file_type()) - .field("is_dir", &self.is_dir()) - .field("is_file", &self.is_file()) - .field("permissions", &self.permissions()) - .field("modified", &self.modified()) - .field("accessed", &self.accessed()) - .field("created", &self.created()) - .finish() - } -} - -impl AsInner for Metadata { - fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 } -} - -impl Permissions { - /// Returns whether these permissions describe a readonly (unwritable) file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// - /// assert_eq!(false, metadata.permissions().readonly()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn readonly(&self) -> bool { self.0.readonly() } - - /// Modifies the readonly flag for this set of permissions. If the - /// `readonly` argument is `true`, using the resulting `Permission` will - /// update file permissions to forbid writing. Conversely, if it's `false`, - /// using the resulting `Permission` will update file permissions to allow - /// writing. - /// - /// This operation does **not** modify the filesystem. To modify the - /// filesystem use the `fs::set_permissions` function. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); - /// - /// permissions.set_readonly(true); - /// - /// // filesystem doesn't change - /// assert_eq!(false, metadata.permissions().readonly()); - /// - /// // just this particular `permissions`. - /// assert_eq!(true, permissions.readonly()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_readonly(&mut self, readonly: bool) { - self.0.set_readonly(readonly) - } -} - -impl FileType { - /// Test whether this file type represents a directory. The - /// result is mutually exclusive to the results of - /// [`is_file`] and [`is_symlink`]; only zero or one of these - /// tests may pass. - /// - /// [`is_file`]: struct.FileType.html#method.is_file - /// [`is_symlink`]: struct.FileType.html#method.is_symlink - /// - /// # Examples - /// - /// ```no_run - /// fn main() -> std::io::Result<()> { - /// use std::fs; - /// - /// let metadata = fs::metadata("foo.txt")?; - /// let file_type = metadata.file_type(); - /// - /// assert_eq!(file_type.is_dir(), false); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type", since = "1.1.0")] - pub fn is_dir(&self) -> bool { self.0.is_dir() } - - /// Test whether this file type represents a regular file. - /// The result is mutually exclusive to the results of - /// [`is_dir`] and [`is_symlink`]; only zero or one of these - /// tests may pass. - /// - /// [`is_dir`]: struct.FileType.html#method.is_dir - /// [`is_symlink`]: struct.FileType.html#method.is_symlink - /// - /// # Examples - /// - /// ```no_run - /// fn main() -> std::io::Result<()> { - /// use std::fs; - /// - /// let metadata = fs::metadata("foo.txt")?; - /// let file_type = metadata.file_type(); - /// - /// assert_eq!(file_type.is_file(), true); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type", since = "1.1.0")] - pub fn is_file(&self) -> bool { self.0.is_file() } - - /// Test whether this file type represents a symbolic link. - /// The result is mutually exclusive to the results of - /// [`is_dir`] and [`is_file`]; only zero or one of these - /// tests may pass. - /// - /// The underlying [`Metadata`] struct needs to be retrieved - /// with the [`fs::symlink_metadata`] function and not the - /// [`fs::metadata`] function. The [`fs::metadata`] function - /// follows symbolic links, so [`is_symlink`] would always - /// return false for the target file. - /// - /// [`Metadata`]: struct.Metadata.html - /// [`fs::metadata`]: fn.metadata.html - /// [`fs::symlink_metadata`]: fn.symlink_metadata.html - /// [`is_dir`]: struct.FileType.html#method.is_dir - /// [`is_file`]: struct.FileType.html#method.is_file - /// [`is_symlink`]: struct.FileType.html#method.is_symlink - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::symlink_metadata("foo.txt")?; - /// let file_type = metadata.file_type(); - /// - /// assert_eq!(file_type.is_symlink(), false); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type", since = "1.1.0")] - pub fn is_symlink(&self) -> bool { self.0.is_symlink() } -} - -impl AsInner for FileType { - fn as_inner(&self) -> &fs_imp::FileType { &self.0 } -} - -impl FromInner for Permissions { - fn from_inner(f: fs_imp::FilePermissions) -> Permissions { - Permissions(f) - } -} - -impl AsInner for Permissions { - fn as_inner(&self) -> &fs_imp::FilePermissions { &self.0 } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - self.0.next().map(|entry| entry.map(DirEntry)) - } -} - -impl DirEntry { - /// Returns the full path to the file that this entry represents. - /// - /// The full path is created by joining the original path to `read_dir` - /// with the filename of this entry. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// for entry in fs::read_dir(".")? { - /// let dir = entry?; - /// println!("{:?}", dir.path()); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// This prints output like: - /// - /// ```text - /// "./whatever.txt" - /// "./foo.html" - /// "./hello_world.rs" - /// ``` - /// - /// The exact text, of course, depends on what files you have in `.`. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn path(&self) -> PathBuf { self.0.path() } - - /// Return the metadata for the file that this entry points at. - /// - /// This function will not traverse symlinks if this entry points at a - /// symlink. - /// - /// # Platform-specific behavior - /// - /// On Windows this function is cheap to call (no extra system calls - /// needed), but on Unix platforms this function is the equivalent of - /// calling `symlink_metadata` on the path. - /// - /// # Examples - /// - /// ``` - /// use std::fs; - /// - /// if let Ok(entries) = fs::read_dir(".") { - /// for entry in entries { - /// if let Ok(entry) = entry { - /// // Here, `entry` is a `DirEntry`. - /// if let Ok(metadata) = entry.metadata() { - /// // Now let's show our entry's permissions! - /// println!("{:?}: {:?}", entry.path(), metadata.permissions()); - /// } else { - /// println!("Couldn't get metadata for {:?}", entry.path()); - /// } - /// } - /// } - /// } - /// ``` - #[stable(feature = "dir_entry_ext", since = "1.1.0")] - pub fn metadata(&self) -> io::Result { - self.0.metadata().map(Metadata) - } - - /// Return the file type for the file that this entry points at. - /// - /// This function will not traverse symlinks if this entry points at a - /// symlink. - /// - /// # Platform-specific behavior - /// - /// On Windows and most Unix platforms this function is free (no extra - /// system calls needed), but some Unix platforms may require the equivalent - /// call to `symlink_metadata` to learn about the target file type. - /// - /// # Examples - /// - /// ``` - /// use std::fs; - /// - /// if let Ok(entries) = fs::read_dir(".") { - /// for entry in entries { - /// if let Ok(entry) = entry { - /// // Here, `entry` is a `DirEntry`. - /// if let Ok(file_type) = entry.file_type() { - /// // Now let's show our entry's file type! - /// println!("{:?}: {:?}", entry.path(), file_type); - /// } else { - /// println!("Couldn't get file type for {:?}", entry.path()); - /// } - /// } - /// } - /// } - /// ``` - #[stable(feature = "dir_entry_ext", since = "1.1.0")] - pub fn file_type(&self) -> io::Result { - self.0.file_type().map(FileType) - } - - /// Returns the bare file name of this directory entry without any other - /// leading path component. - /// - /// # Examples - /// - /// ``` - /// use std::fs; - /// - /// if let Ok(entries) = fs::read_dir(".") { - /// for entry in entries { - /// if let Ok(entry) = entry { - /// // Here, `entry` is a `DirEntry`. - /// println!("{:?}", entry.file_name()); - /// } - /// } - /// } - /// ``` - #[stable(feature = "dir_entry_ext", since = "1.1.0")] - pub fn file_name(&self) -> OsString { - self.0.file_name() - } -} - -#[stable(feature = "dir_entry_debug", since = "1.13.0")] -impl fmt::Debug for DirEntry { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("DirEntry") - .field(&self.path()) - .finish() - } -} - -impl AsInner for DirEntry { - fn as_inner(&self) -> &fs_imp::DirEntry { &self.0 } -} - -/// Removes a file from the filesystem. -/// -/// Note that there is no -/// guarantee that the file is immediately deleted (e.g. depending on -/// platform, other open file descriptors may prevent immediate removal). -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `unlink` function on Unix -/// and the `DeleteFile` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * `path` points to a directory. -/// * The user lacks permissions to remove the file. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::remove_file("a.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_file>(path: P) -> io::Result<()> { - fs_imp::unlink(path.as_ref()) -} - -/// Given a path, query the file system to get information about a file, -/// directory, etc. -/// -/// This function will traverse symbolic links to query information about the -/// destination file. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `stat` function on Unix -/// and the `GetFileAttributesEx` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The user lacks permissions to perform `metadata` call on `path`. -/// * `path` does not exist. -/// -/// # Examples -/// -/// ```rust,no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// let attr = fs::metadata("/some/file/path.txt")?; -/// // inspect attr ... -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn metadata>(path: P) -> io::Result { - fs_imp::stat(path.as_ref()).map(Metadata) -} - -/// Query the metadata about a file without following symlinks. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `lstat` function on Unix -/// and the `GetFileAttributesEx` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The user lacks permissions to perform `metadata` call on `path`. -/// * `path` does not exist. -/// -/// # Examples -/// -/// ```rust,no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// let attr = fs::symlink_metadata("/some/file/path.txt")?; -/// // inspect attr ... -/// Ok(()) -/// } -/// ``` -#[stable(feature = "symlink_metadata", since = "1.1.0")] -pub fn symlink_metadata>(path: P) -> io::Result { - fs_imp::lstat(path.as_ref()).map(Metadata) -} - -/// Rename a file or directory to a new name, replacing the original file if -/// `to` already exists. -/// -/// This will not work if the new name is on a different mount point. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `rename` function on Unix -/// and the `MoveFileEx` function with the `MOVEFILE_REPLACE_EXISTING` flag on Windows. -/// -/// Because of this, the behavior when both `from` and `to` exist differs. On -/// Unix, if `from` is a directory, `to` must also be an (empty) directory. If -/// `from` is not a directory, `to` must also be not a directory. In contrast, -/// on Windows, `from` can be anything, but `to` must *not* be a directory. -/// -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * `from` does not exist. -/// * The user lacks permissions to view contents. -/// * `from` and `to` are on separate filesystems. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::rename("a.txt", "b.txt")?; // Rename a.txt to b.txt -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> { - fs_imp::rename(from.as_ref(), to.as_ref()) -} - -/// Copies the contents of one file to another. This function will also -/// copy the permission bits of the original file to the destination file. -/// -/// This function will **overwrite** the contents of `to`. -/// -/// Note that if `from` and `to` both point to the same file, then the file -/// will likely get truncated by this operation. -/// -/// On success, the total number of bytes copied is returned and it is equal to -/// the length of the `to` file as reported by `metadata`. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `open` function in Unix -/// with `O_RDONLY` for `from` and `O_WRONLY`, `O_CREAT`, and `O_TRUNC` for `to`. -/// `O_CLOEXEC` is set for returned file descriptors. -/// On Windows, this function currently corresponds to `CopyFileEx`. Alternate -/// NTFS streams are copied but only the size of the main stream is returned by -/// this function. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The `from` path is not a file. -/// * The `from` file does not exist. -/// * The current process does not have the permission rights to access -/// `from` or write `to`. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::copy("foo.txt", "bar.txt")?; // Copy foo.txt to bar.txt -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { - fs_imp::copy(from.as_ref(), to.as_ref()) -} - -/// Creates a new hard link on the filesystem. -/// -/// The `dst` path will be a link pointing to the `src` path. Note that systems -/// often require these two paths to both be located on the same filesystem. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `link` function on Unix -/// and the `CreateHardLink` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The `src` path is not a file or doesn't exist. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::hard_link("a.txt", "b.txt")?; // Hard link a.txt to b.txt -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn hard_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - fs_imp::link(src.as_ref(), dst.as_ref()) -} - -/// Creates a new symbolic link on the filesystem. -/// -/// The `dst` path will be a symbolic link pointing to the `src` path. -/// On Windows, this will be a file symlink, not a directory symlink; -/// for this reason, the platform-specific `std::os::unix::fs::symlink` -/// and `std::os::windows::fs::{symlink_file, symlink_dir}` should be -/// used instead to make the intent explicit. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::soft_link("a.txt", "b.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "1.1.0", - reason = "replaced with std::os::unix::fs::symlink and \ - std::os::windows::fs::{symlink_file, symlink_dir}")] -pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - fs_imp::symlink(src.as_ref(), dst.as_ref()) -} - -/// Reads a symbolic link, returning the file that the link points to. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `readlink` function on Unix -/// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and -/// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * `path` is not a symbolic link. -/// * `path` does not exist. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// let path = fs::read_link("a.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn read_link>(path: P) -> io::Result { - fs_imp::readlink(path.as_ref()) -} - -/// Returns the canonical, absolute form of a path with all intermediate -/// components normalized and symbolic links resolved. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `realpath` function on Unix -/// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// On Windows, this converts the path to use [extended length path][path] -/// syntax, which allows your program to use longer path names, but means you -/// can only join backslash-delimited paths to it, and it may be incompatible -/// with other applications (if passed to the application on the command-line, -/// or written to a file another application may read). -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// [path]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * `path` does not exist. -/// * A component in path is not a directory. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// let path = fs::canonicalize("../a/../foo.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "fs_canonicalize", since = "1.5.0")] -pub fn canonicalize>(path: P) -> io::Result { - fs_imp::canonicalize(path.as_ref()) -} - -/// Creates a new, empty directory at the provided path -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `mkdir` function on Unix -/// and the `CreateDirectory` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * User lacks permissions to create directory at `path`. -/// * `path` already exists. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::create_dir("/some/dir")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn create_dir>(path: P) -> io::Result<()> { - DirBuilder::new().create(path.as_ref()) -} - -/// Recursively create a directory and all of its parent components if they -/// are missing. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `mkdir` function on Unix -/// and the `CreateDirectory` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * If any directory in the path specified by `path` -/// does not already exist and it could not be created otherwise. The specific -/// error conditions for when a directory is being created (after it is -/// determined to not exist) are outlined by `fs::create_dir`. -/// -/// Notable exception is made for situations where any of the directories -/// specified in the `path` could not be created as it was being created concurrently. -/// Such cases are considered to be successful. That is, calling `create_dir_all` -/// concurrently from multiple threads or processes is guaranteed not to fail -/// due to a race condition with itself. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::create_dir_all("/some/dir")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn create_dir_all>(path: P) -> io::Result<()> { - DirBuilder::new().recursive(true).create(path.as_ref()) -} - -/// Removes an existing, empty directory. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `rmdir` function on Unix -/// and the `RemoveDirectory` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The user lacks permissions to remove the directory at the provided `path`. -/// * The directory isn't empty. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::remove_dir("/some/dir")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_dir>(path: P) -> io::Result<()> { - fs_imp::rmdir(path.as_ref()) -} - -/// Removes a directory at this path, after removing all its contents. Use -/// carefully! -/// -/// This function does **not** follow symbolic links and it will simply remove the -/// symbolic link itself. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to `opendir`, `lstat`, `rm` and `rmdir` functions on Unix -/// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions -/// on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// See `file::remove_file` and `fs::remove_dir`. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::remove_dir_all("/some/dir")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_dir_all>(path: P) -> io::Result<()> { - fs_imp::remove_dir_all(path.as_ref()) -} - -/// Returns an iterator over the entries within a directory. -/// -/// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. -/// New errors may be encountered after an iterator is initially constructed. -/// -/// [`io::Result`]: ../io/type.Result.html -/// [`DirEntry`]: struct.DirEntry.html -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `opendir` function on Unix -/// and the `FindFirstFile` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The provided `path` doesn't exist. -/// * The process lacks permissions to view the contents. -/// * The `path` points at a non-directory file. -/// -/// # Examples -/// -/// ``` -/// use std::io; -/// use std::fs::{self, DirEntry}; -/// use std::path::Path; -/// -/// // one possible implementation of walking a directory only visiting files -/// fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> { -/// if dir.is_dir() { -/// for entry in fs::read_dir(dir)? { -/// let entry = entry?; -/// let path = entry.path(); -/// if path.is_dir() { -/// visit_dirs(&path, cb)?; -/// } else { -/// cb(&entry); -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn read_dir>(path: P) -> io::Result { - fs_imp::readdir(path.as_ref()).map(ReadDir) -} - -/// Changes the permissions found on a file or a directory. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `chmod` function on Unix -/// and the `SetFileAttributes` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: ../io/index.html#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * `path` does not exist. -/// * The user lacks the permission to change attributes of the file. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// let mut perms = fs::metadata("foo.txt")?.permissions(); -/// perms.set_readonly(true); -/// fs::set_permissions("foo.txt", perms)?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "set_permissions", since = "1.1.0")] -pub fn set_permissions>(path: P, perm: Permissions) - -> io::Result<()> { - fs_imp::set_perm(path.as_ref(), perm.0) -} - -impl DirBuilder { - /// Creates a new set of options with default mode/security settings for all - /// platforms and also non-recursive. - /// - /// # Examples - /// - /// ``` - /// use std::fs::DirBuilder; - /// - /// let builder = DirBuilder::new(); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - pub fn new() -> DirBuilder { - DirBuilder { - inner: fs_imp::DirBuilder::new(), - recursive: false, - } - } - - /// Indicates that directories should be created recursively, creating all - /// parent directories. Parents that do not exist are created with the same - /// security and permissions settings. - /// - /// This option defaults to `false`. - /// - /// # Examples - /// - /// ``` - /// use std::fs::DirBuilder; - /// - /// let mut builder = DirBuilder::new(); - /// builder.recursive(true); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - pub fn recursive(&mut self, recursive: bool) -> &mut Self { - self.recursive = recursive; - self - } - - /// Create the specified directory with the options configured in this - /// builder. - /// - /// It is considered an error if the directory already exists unless - /// recursive mode is enabled. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::{self, DirBuilder}; - /// - /// let path = "/tmp/foo/bar/baz"; - /// DirBuilder::new() - /// .recursive(true) - /// .create(path).unwrap(); - /// - /// assert!(fs::metadata(path).unwrap().is_dir()); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - pub fn create>(&self, path: P) -> io::Result<()> { - self._create(path.as_ref()) - } - - fn _create(&self, path: &Path) -> io::Result<()> { - if self.recursive { - self.create_dir_all(path) - } else { - self.inner.mkdir(path) - } - } - - fn create_dir_all(&self, path: &Path) -> io::Result<()> { - if path == Path::new("") { - return Ok(()) - } - - match self.inner.mkdir(path) { - Ok(()) => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} - Err(_) if path.is_dir() => return Ok(()), - Err(e) => return Err(e), - } - match path.parent() { - Some(p) => try!(self.create_dir_all(p)), - None => return Err(io::Error::new(io::ErrorKind::Other, "failed to create whole tree")), - } - match self.inner.mkdir(path) { - Ok(()) => Ok(()), - Err(_) if path.is_dir() => Ok(()), - Err(e) => Err(e), - } - } -} - -impl AsInnerMut for DirBuilder { - fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder { - &mut self.inner - } -} - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] -mod tests { - use io::prelude::*; - - use fs::{self, File, OpenOptions}; - use io::{ErrorKind, SeekFrom}; - use path::Path; - use rand::{StdRng, Rng}; - use str; - use sys_common::io::test::{TempDir, tmpdir}; - use thread; - - #[cfg(windows)] - use os::windows::fs::{symlink_dir, symlink_file}; - #[cfg(windows)] - use sys::fs::symlink_junction; - #[cfg(unix)] - use os::unix::fs::symlink as symlink_dir; - #[cfg(unix)] - use os::unix::fs::symlink as symlink_file; - #[cfg(unix)] - use os::unix::fs::symlink as symlink_junction; - - macro_rules! check { ($e:expr) => ( - match $e { - Ok(t) => t, - Err(e) => panic!("{} failed with: {}", stringify!($e), e), - } - ) } - - #[cfg(windows)] - macro_rules! error { ($e:expr, $s:expr) => ( - match $e { - Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), - Err(ref err) => assert!(err.raw_os_error() == Some($s), - format!("`{}` did not have a code of `{}`", err, $s)) - } - ) } - - #[cfg(unix)] - macro_rules! error { ($e:expr, $s:expr) => ( error_contains!($e, $s) ) } - - macro_rules! error_contains { ($e:expr, $s:expr) => ( - match $e { - Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), - Err(ref err) => assert!(err.to_string().contains($s), - format!("`{}` did not contain `{}`", err, $s)) - } - ) } - - // Several test fail on windows if the user does not have permission to - // create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of - // disabling these test on Windows, use this function to test whether we - // have permission, and return otherwise. This way, we still don't run these - // tests most of the time, but at least we do if the user has the right - // permissions. - pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { - if cfg!(unix) { return true } - let link = tmpdir.join("some_hopefully_unique_link_name"); - - match symlink_file(r"nonexisting_target", link) { - Ok(_) => true, - // ERROR_PRIVILEGE_NOT_HELD = 1314 - Err(ref err) if err.raw_os_error() == Some(1314) => false, - Err(_) => true, - } - } - - #[test] - fn file_test_io_smoke_test() { - let message = "it's alright. have a good time"; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test.txt"); - { - let mut write_stream = check!(File::create(filename)); - check!(write_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - let mut read_buf = [0; 1028]; - let read_str = match check!(read_stream.read(&mut read_buf)) { - 0 => panic!("shouldn't happen"), - n => str::from_utf8(&read_buf[..n]).unwrap().to_string() - }; - assert_eq!(read_str, message); - } - check!(fs::remove_file(filename)); - } - - #[test] - fn invalid_path_raises() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_that_does_not_exist.txt"); - let result = File::open(filename); - - #[cfg(unix)] - error!(result, "No such file or directory"); - #[cfg(windows)] - error!(result, 2); // ERROR_FILE_NOT_FOUND - } - - #[test] - fn file_test_iounlinking_invalid_path_should_raise_condition() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt"); - - let result = fs::remove_file(filename); - - #[cfg(unix)] - error!(result, "No such file or directory"); - #[cfg(windows)] - error!(result, 2); // ERROR_FILE_NOT_FOUND - } - - #[test] - fn file_test_io_non_positional_read() { - let message: &str = "ten-four"; - let mut read_mem = [0; 8]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_positional.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - { - let read_buf = &mut read_mem[0..4]; - check!(read_stream.read(read_buf)); - } - { - let read_buf = &mut read_mem[4..8]; - check!(read_stream.read(read_buf)); - } - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, message); - } - - #[test] - fn file_test_io_seek_and_tell_smoke_test() { - let message = "ten-four"; - let mut read_mem = [0; 4]; - let set_cursor = 4 as u64; - let tell_pos_pre_read; - let tell_pos_post_read; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - check!(read_stream.seek(SeekFrom::Start(set_cursor))); - tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0))); - check!(read_stream.read(&mut read_mem)); - tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0))); - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, &message[4..8]); - assert_eq!(tell_pos_pre_read, set_cursor); - assert_eq!(tell_pos_post_read, message.len() as u64); - } - - #[test] - fn file_test_io_seek_and_write() { - let initial_msg = "food-is-yummy"; - let overwrite_msg = "-the-bar!!"; - let final_msg = "foo-the-bar!!"; - let seek_idx = 3; - let mut read_mem = [0; 13]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(initial_msg.as_bytes())); - check!(rw_stream.seek(SeekFrom::Start(seek_idx))); - check!(rw_stream.write(overwrite_msg.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - check!(read_stream.read(&mut read_mem)); - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert!(read_str == final_msg); - } - - #[test] - fn file_test_io_seek_shakedown() { - // 01234567890123 - let initial_msg = "qwer-asdf-zxcv"; - let chunk_one: &str = "qwer"; - let chunk_two: &str = "asdf"; - let chunk_three: &str = "zxcv"; - let mut read_mem = [0; 4]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(initial_msg.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - - check!(read_stream.seek(SeekFrom::End(-4))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three); - - check!(read_stream.seek(SeekFrom::Current(-9))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two); - - check!(read_stream.seek(SeekFrom::Start(0))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one); - } - check!(fs::remove_file(filename)); - } - - #[test] - fn file_test_io_eof() { - let tmpdir = tmpdir(); - let filename = tmpdir.join("file_rt_io_file_test_eof.txt"); - let mut buf = [0; 256]; - { - let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); - let mut rw = check!(oo.open(&filename)); - assert_eq!(check!(rw.read(&mut buf)), 0); - assert_eq!(check!(rw.read(&mut buf)), 0); - } - check!(fs::remove_file(&filename)); - } - - #[test] - #[cfg(unix)] - fn file_test_io_read_write_at() { - use os::unix::fs::FileExt; - - let tmpdir = tmpdir(); - let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt"); - let mut buf = [0; 256]; - let write1 = "asdf"; - let write2 = "qwer-"; - let write3 = "-zxcv"; - let content = "qwer-asdf-zxcv"; - { - let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); - let mut rw = check!(oo.open(&filename)); - assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); - assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0")); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); - assert_eq!(check!(rw.read(&mut buf)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); - assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - } - { - let mut read = check!(File::open(&filename)); - assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); - assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(read.read(&mut buf)), write3.len()); - assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.read_at(&mut buf, 14)), 0); - assert_eq!(check!(read.read_at(&mut buf, 15)), 0); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - } - check!(fs::remove_file(&filename)); - } - - #[test] - #[cfg(unix)] - fn set_get_unix_permissions() { - use os::unix::fs::PermissionsExt; - - let tmpdir = tmpdir(); - let filename = &tmpdir.join("set_get_unix_permissions"); - check!(fs::create_dir(filename)); - let mask = 0o7777; - - check!(fs::set_permissions(filename, - fs::Permissions::from_mode(0))); - let metadata0 = check!(fs::metadata(filename)); - assert_eq!(mask & metadata0.permissions().mode(), 0); - - check!(fs::set_permissions(filename, - fs::Permissions::from_mode(0o1777))); - let metadata1 = check!(fs::metadata(filename)); - assert_eq!(mask & metadata1.permissions().mode(), 0o1777); - } - - #[test] - #[cfg(windows)] - fn file_test_io_seek_read_write() { - use os::windows::fs::FileExt; - - let tmpdir = tmpdir(); - let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt"); - let mut buf = [0; 256]; - let write1 = "asdf"; - let write2 = "qwer-"; - let write3 = "-zxcv"; - let content = "qwer-asdf-zxcv"; - { - let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); - let mut rw = check!(oo.open(&filename)); - assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0); - assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); - assert_eq!(check!(rw.read(&mut buf)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len()); - assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); - assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14); - } - { - let mut read = check!(File::open(&filename)); - assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); - assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); - assert_eq!(check!(read.read(&mut buf)), write3.len()); - assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek_read(&mut buf, 14)), 0); - assert_eq!(check!(read.seek_read(&mut buf, 15)), 0); - } - check!(fs::remove_file(&filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_file() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_file.txt"); - { - let mut opts = OpenOptions::new(); - let mut fs = check!(opts.read(true).write(true) - .create(true).open(filename)); - let msg = "hw"; - fs.write(msg.as_bytes()).unwrap(); - - let fstat_res = check!(fs.metadata()); - assert!(fstat_res.is_file()); - } - let stat_res_fn = check!(fs::metadata(filename)); - assert!(stat_res_fn.is_file()); - let stat_res_meth = check!(filename.metadata()); - assert!(stat_res_meth.is_file()); - check!(fs::remove_file(filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_dir() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_dir"); - check!(fs::create_dir(filename)); - let stat_res_fn = check!(fs::metadata(filename)); - assert!(stat_res_fn.is_dir()); - let stat_res_meth = check!(filename.metadata()); - assert!(stat_res_meth.is_dir()); - check!(fs::remove_dir(filename)); - } - - #[test] - fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("fileinfo_false_on_dir"); - check!(fs::create_dir(dir)); - assert!(!dir.is_file()); - check!(fs::remove_dir(dir)); - } - - #[test] - fn file_test_fileinfo_check_exists_before_and_after_file_creation() { - let tmpdir = tmpdir(); - let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); - check!(check!(File::create(file)).write(b"foo")); - assert!(file.exists()); - check!(fs::remove_file(file)); - assert!(!file.exists()); - } - - #[test] - fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("before_and_after_dir"); - assert!(!dir.exists()); - check!(fs::create_dir(dir)); - assert!(dir.exists()); - assert!(dir.is_dir()); - check!(fs::remove_dir(dir)); - assert!(!dir.exists()); - } - - #[test] - fn file_test_directoryinfo_readdir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("di_readdir"); - check!(fs::create_dir(dir)); - let prefix = "foo"; - for n in 0..3 { - let f = dir.join(&format!("{}.txt", n)); - let mut w = check!(File::create(&f)); - let msg_str = format!("{}{}", prefix, n.to_string()); - let msg = msg_str.as_bytes(); - check!(w.write(msg)); - } - let files = check!(fs::read_dir(dir)); - let mut mem = [0; 4]; - for f in files { - let f = f.unwrap().path(); - { - let n = f.file_stem().unwrap(); - check!(check!(File::open(&f)).read(&mut mem)); - let read_str = str::from_utf8(&mem).unwrap(); - let expected = format!("{}{}", prefix, n.to_str().unwrap()); - assert_eq!(expected, read_str); - } - check!(fs::remove_file(&f)); - } - check!(fs::remove_dir(dir)); - } - - #[test] - fn file_create_new_already_exists_error() { - let tmpdir = tmpdir(); - let file = &tmpdir.join("file_create_new_error_exists"); - check!(fs::File::create(file)); - let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err(); - assert_eq!(e.kind(), ErrorKind::AlreadyExists); - } - - #[test] - fn mkdir_path_already_exists_error() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("mkdir_error_twice"); - check!(fs::create_dir(dir)); - let e = fs::create_dir(dir).unwrap_err(); - assert_eq!(e.kind(), ErrorKind::AlreadyExists); - } - - #[test] - fn recursive_mkdir() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1/d2"); - check!(fs::create_dir_all(&dir)); - assert!(dir.is_dir()) - } - - #[test] - fn recursive_mkdir_failure() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1"); - let file = dir.join("f1"); - - check!(fs::create_dir_all(&dir)); - check!(File::create(&file)); - - let result = fs::create_dir_all(&file); - - assert!(result.is_err()); - } - - #[test] - fn concurrent_recursive_mkdir() { - for _ in 0..100 { - let dir = tmpdir(); - let mut dir = dir.join("a"); - for _ in 0..40 { - dir = dir.join("a"); - } - let mut join = vec!(); - for _ in 0..8 { - let dir = dir.clone(); - join.push(thread::spawn(move || { - check!(fs::create_dir_all(&dir)); - })) - } - - // No `Display` on result of `join()` - join.drain(..).map(|join| join.join().unwrap()).count(); - } - } - - #[test] - fn recursive_mkdir_slash() { - check!(fs::create_dir_all(Path::new("/"))); - } - - #[test] - fn recursive_mkdir_dot() { - check!(fs::create_dir_all(Path::new("."))); - } - - #[test] - fn recursive_mkdir_empty() { - check!(fs::create_dir_all(Path::new(""))); - } - - #[test] - fn recursive_rmdir() { - let tmpdir = tmpdir(); - let d1 = tmpdir.join("d1"); - let dt = d1.join("t"); - let dtt = dt.join("t"); - let d2 = tmpdir.join("d2"); - let canary = d2.join("do_not_delete"); - check!(fs::create_dir_all(&dtt)); - check!(fs::create_dir_all(&d2)); - check!(check!(File::create(&canary)).write(b"foo")); - check!(symlink_junction(&d2, &dt.join("d2"))); - let _ = symlink_file(&canary, &d1.join("canary")); - check!(fs::remove_dir_all(&d1)); - - assert!(!d1.is_dir()); - assert!(canary.exists()); - } - - #[test] - fn recursive_rmdir_of_symlink() { - // test we do not recursively delete a symlink but only dirs. - let tmpdir = tmpdir(); - let link = tmpdir.join("d1"); - let dir = tmpdir.join("d2"); - let canary = dir.join("do_not_delete"); - check!(fs::create_dir_all(&dir)); - check!(check!(File::create(&canary)).write(b"foo")); - check!(symlink_junction(&dir, &link)); - check!(fs::remove_dir_all(&link)); - - assert!(!link.is_dir()); - assert!(canary.exists()); - } - - #[test] - // only Windows makes a distinction between file and directory symlinks. - #[cfg(windows)] - fn recursive_rmdir_of_file_symlink() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { return }; - - let f1 = tmpdir.join("f1"); - let f2 = tmpdir.join("f2"); - check!(check!(File::create(&f1)).write(b"foo")); - check!(symlink_file(&f1, &f2)); - match fs::remove_dir_all(&f2) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn unicode_path_is_dir() { - assert!(Path::new(".").is_dir()); - assert!(!Path::new("test/stdtest/fs.rs").is_dir()); - - let tmpdir = tmpdir(); - - let mut dirpath = tmpdir.path().to_path_buf(); - dirpath.push("test-가一ー你好"); - check!(fs::create_dir(&dirpath)); - assert!(dirpath.is_dir()); - - let mut filepath = dirpath; - filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs"); - check!(File::create(&filepath)); // ignore return; touch only - assert!(!filepath.is_dir()); - assert!(filepath.exists()); - } - - #[test] - fn unicode_path_exists() { - assert!(Path::new(".").exists()); - assert!(!Path::new("test/nonexistent-bogus-path").exists()); - - let tmpdir = tmpdir(); - let unicode = tmpdir.path(); - let unicode = unicode.join("test-각丁ー再见"); - check!(fs::create_dir(&unicode)); - assert!(unicode.exists()); - assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists()); - } - - #[test] - fn copy_file_does_not_exist() { - let from = Path::new("test/nonexistent-bogus-path"); - let to = Path::new("test/other-bogus-path"); - - match fs::copy(&from, &to) { - Ok(..) => panic!(), - Err(..) => { - assert!(!from.exists()); - assert!(!to.exists()); - } - } - } - - #[test] - fn copy_src_does_not_exist() { - let tmpdir = tmpdir(); - let from = Path::new("test/nonexistent-bogus-path"); - let to = tmpdir.join("out.txt"); - check!(check!(File::create(&to)).write(b"hello")); - assert!(fs::copy(&from, &to).is_err()); - assert!(!from.exists()); - let mut v = Vec::new(); - check!(check!(File::open(&to)).read_to_end(&mut v)); - assert_eq!(v, b"hello"); - } - - #[test] - fn copy_file_ok() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write(b"hello")); - check!(fs::copy(&input, &out)); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v, b"hello"); - - assert_eq!(check!(input.metadata()).permissions(), - check!(out.metadata()).permissions()); - } - - #[test] - fn copy_file_dst_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - check!(File::create(&out)); - match fs::copy(&*out, tmpdir.path()) { - Ok(..) => panic!(), Err(..) => {} - } - } - - #[test] - fn copy_file_dst_exists() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in"); - let output = tmpdir.join("out"); - - check!(check!(File::create(&input)).write("foo".as_bytes())); - check!(check!(File::create(&output)).write("bar".as_bytes())); - check!(fs::copy(&input, &output)); - - let mut v = Vec::new(); - check!(check!(File::open(&output)).read_to_end(&mut v)); - assert_eq!(v, b"foo".to_vec()); - } - - #[test] - fn copy_file_src_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - match fs::copy(tmpdir.path(), &out) { - Ok(..) => panic!(), Err(..) => {} - } - assert!(!out.exists()); - } - - #[test] - fn copy_file_preserves_perm_bits() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - let attr = check!(check!(File::create(&input)).metadata()); - let mut p = attr.permissions(); - p.set_readonly(true); - check!(fs::set_permissions(&input, p)); - check!(fs::copy(&input, &out)); - assert!(check!(out.metadata()).permissions().readonly()); - check!(fs::set_permissions(&input, attr.permissions())); - check!(fs::set_permissions(&out, attr.permissions())); - } - - #[test] - #[cfg(windows)] - fn copy_file_preserves_streams() { - let tmp = tmpdir(); - check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes())); - assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0); - assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0); - let mut v = Vec::new(); - check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v)); - assert_eq!(v, b"carrot".to_vec()); - } - - #[test] - fn copy_file_returns_metadata_len() { - let tmp = tmpdir(); - let in_path = tmp.join("in.txt"); - let out_path = tmp.join("out.txt"); - check!(check!(File::create(&in_path)).write(b"lettuce")); - #[cfg(windows)] - check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot")); - let copied_len = check!(fs::copy(&in_path, &out_path)); - assert_eq!(check!(out_path.metadata()).len(), copied_len); - } - - #[test] - fn symlinks_work() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { return }; - - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write("foobar".as_bytes())); - check!(symlink_file(&input, &out)); - assert!(check!(out.symlink_metadata()).file_type().is_symlink()); - assert_eq!(check!(fs::metadata(&out)).len(), - check!(fs::metadata(&input)).len()); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v, b"foobar".to_vec()); - } - - #[test] - fn symlink_noexist() { - // Symlinks can point to things that don't exist - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { return }; - - // Use a relative path for testing. Symlinks get normalized by Windows, - // so we may not get the same path back for absolute paths - check!(symlink_file(&"foo", &tmpdir.join("bar"))); - assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), - "foo"); - } - - #[test] - fn read_link() { - if cfg!(windows) { - // directory symlink - assert_eq!(check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(), - r"C:\ProgramData"); - // junction - assert_eq!(check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(), - r"C:\Users\Default"); - // junction with special permissions - assert_eq!(check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(), - r"C:\Users"); - } - let tmpdir = tmpdir(); - let link = tmpdir.join("link"); - if !got_symlink_permission(&tmpdir) { return }; - check!(symlink_file(&"foo", &link)); - assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo"); - } - - #[test] - fn readlink_not_symlink() { - let tmpdir = tmpdir(); - match fs::read_link(tmpdir.path()) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn links_work() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write("foobar".as_bytes())); - check!(fs::hard_link(&input, &out)); - assert_eq!(check!(fs::metadata(&out)).len(), - check!(fs::metadata(&input)).len()); - assert_eq!(check!(fs::metadata(&out)).len(), - check!(input.metadata()).len()); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v, b"foobar".to_vec()); - - // can't link to yourself - match fs::hard_link(&input, &input) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - // can't link to something that doesn't exist - match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn chmod_works() { - let tmpdir = tmpdir(); - let file = tmpdir.join("in.txt"); - - check!(File::create(&file)); - let attr = check!(fs::metadata(&file)); - assert!(!attr.permissions().readonly()); - let mut p = attr.permissions(); - p.set_readonly(true); - check!(fs::set_permissions(&file, p.clone())); - let attr = check!(fs::metadata(&file)); - assert!(attr.permissions().readonly()); - - match fs::set_permissions(&tmpdir.join("foo"), p.clone()) { - Ok(..) => panic!("wanted an error"), - Err(..) => {} - } - - p.set_readonly(false); - check!(fs::set_permissions(&file, p)); - } - - #[test] - fn fchmod_works() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let file = check!(File::create(&path)); - let attr = check!(fs::metadata(&path)); - assert!(!attr.permissions().readonly()); - let mut p = attr.permissions(); - p.set_readonly(true); - check!(file.set_permissions(p.clone())); - let attr = check!(fs::metadata(&path)); - assert!(attr.permissions().readonly()); - - p.set_readonly(false); - check!(file.set_permissions(p)); - } - - #[test] - fn sync_doesnt_kill_anything() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::create(&path)); - check!(file.sync_all()); - check!(file.sync_data()); - check!(file.write(b"foo")); - check!(file.sync_all()); - check!(file.sync_data()); - } - - #[test] - fn truncate_works() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::create(&path)); - check!(file.write(b"foo")); - check!(file.sync_all()); - - // Do some simple things with truncation - assert_eq!(check!(file.metadata()).len(), 3); - check!(file.set_len(10)); - assert_eq!(check!(file.metadata()).len(), 10); - check!(file.write(b"bar")); - check!(file.sync_all()); - assert_eq!(check!(file.metadata()).len(), 10); - - let mut v = Vec::new(); - check!(check!(File::open(&path)).read_to_end(&mut v)); - assert_eq!(v, b"foobar\0\0\0\0".to_vec()); - - // Truncate to a smaller length, don't seek, and then write something. - // Ensure that the intermediate zeroes are all filled in (we have `seek`ed - // past the end of the file). - check!(file.set_len(2)); - assert_eq!(check!(file.metadata()).len(), 2); - check!(file.write(b"wut")); - check!(file.sync_all()); - assert_eq!(check!(file.metadata()).len(), 9); - let mut v = Vec::new(); - check!(check!(File::open(&path)).read_to_end(&mut v)); - assert_eq!(v, b"fo\0\0\0\0wut".to_vec()); - } - - #[test] - fn open_flavors() { - use fs::OpenOptions as OO; - fn c(t: &T) -> T { t.clone() } - - let tmpdir = tmpdir(); - - let mut r = OO::new(); r.read(true); - let mut w = OO::new(); w.write(true); - let mut rw = OO::new(); rw.read(true).write(true); - let mut a = OO::new(); a.append(true); - let mut ra = OO::new(); ra.read(true).append(true); - - #[cfg(windows)] - let invalid_options = 87; // ERROR_INVALID_PARAMETER - #[cfg(unix)] - let invalid_options = "Invalid argument"; - - // Test various combinations of creation modes and access modes. - // - // Allowed: - // creation mode | read | write | read-write | append | read-append | - // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:| - // not set (open existing) | X | X | X | X | X | - // create | | X | X | X | X | - // truncate | | X | X | | | - // create and truncate | | X | X | | | - // create_new | | X | X | X | X | - // - // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it. - - // write-only - check!(c(&w).create_new(true).open(&tmpdir.join("a"))); - check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a"))); - check!(c(&w).truncate(true).open(&tmpdir.join("a"))); - check!(c(&w).create(true).open(&tmpdir.join("a"))); - check!(c(&w).open(&tmpdir.join("a"))); - - // read-only - error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options); - error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options); - error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options); - error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options); - check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only - - // read-write - check!(c(&rw).create_new(true).open(&tmpdir.join("c"))); - check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c"))); - check!(c(&rw).truncate(true).open(&tmpdir.join("c"))); - check!(c(&rw).create(true).open(&tmpdir.join("c"))); - check!(c(&rw).open(&tmpdir.join("c"))); - - // append - check!(c(&a).create_new(true).open(&tmpdir.join("d"))); - error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options); - error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options); - check!(c(&a).create(true).open(&tmpdir.join("d"))); - check!(c(&a).open(&tmpdir.join("d"))); - - // read-append - check!(c(&ra).create_new(true).open(&tmpdir.join("e"))); - error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options); - error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options); - check!(c(&ra).create(true).open(&tmpdir.join("e"))); - check!(c(&ra).open(&tmpdir.join("e"))); - - // Test opening a file without setting an access mode - let mut blank = OO::new(); - error!(blank.create(true).open(&tmpdir.join("f")), invalid_options); - - // Test write works - check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes())); - - // Test write fails for read-only - check!(r.open(&tmpdir.join("h"))); - { - let mut f = check!(r.open(&tmpdir.join("h"))); - assert!(f.write("wut".as_bytes()).is_err()); - } - - // Test write overwrites - { - let mut f = check!(c(&w).open(&tmpdir.join("h"))); - check!(f.write("baz".as_bytes())); - } - { - let mut f = check!(c(&r).open(&tmpdir.join("h"))); - let mut b = vec![0; 6]; - check!(f.read(&mut b)); - assert_eq!(b, "bazbar".as_bytes()); - } - - // Test truncate works - { - let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h"))); - check!(f.write("foo".as_bytes())); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); - - // Test append works - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); - { - let mut f = check!(c(&a).open(&tmpdir.join("h"))); - check!(f.write("bar".as_bytes())); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6); - - // Test .append(true) equals .write(true).append(true) - { - let mut f = check!(c(&w).append(true).open(&tmpdir.join("h"))); - check!(f.write("baz".as_bytes())); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9); - } - - #[test] - fn _assert_send_sync() { - fn _assert_send_sync() {} - _assert_send_sync::(); - } - - #[test] - fn binary_file() { - let mut bytes = [0; 1024]; - StdRng::new().unwrap().fill_bytes(&mut bytes); - - let tmpdir = tmpdir(); - - check!(check!(File::create(&tmpdir.join("test"))).write(&bytes)); - let mut v = Vec::new(); - check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v)); - assert!(v == &bytes[..]); - } - - #[test] - fn write_then_read() { - let mut bytes = [0; 1024]; - StdRng::new().unwrap().fill_bytes(&mut bytes); - - let tmpdir = tmpdir(); - - check!(fs::write(&tmpdir.join("test"), &bytes[..])); - let v = check!(fs::read(&tmpdir.join("test"))); - assert!(v == &bytes[..]); - - check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF])); - error_contains!(fs::read_to_string(&tmpdir.join("not-utf8")), - "stream did not contain valid UTF-8"); - - let s = "𐁁𐀓𐀠𐀴𐀍"; - check!(fs::write(&tmpdir.join("utf8"), s.as_bytes())); - let string = check!(fs::read_to_string(&tmpdir.join("utf8"))); - assert_eq!(string, s); - } - - #[test] - fn file_try_clone() { - let tmpdir = tmpdir(); - - let mut f1 = check!(OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(&tmpdir.join("test"))); - let mut f2 = check!(f1.try_clone()); - - check!(f1.write_all(b"hello world")); - check!(f1.seek(SeekFrom::Start(2))); - - let mut buf = vec![]; - check!(f2.read_to_end(&mut buf)); - assert_eq!(buf, b"llo world"); - drop(f2); - - check!(f1.write_all(b"!")); - } - - #[test] - #[cfg(not(windows))] - fn unlink_readonly() { - let tmpdir = tmpdir(); - let path = tmpdir.join("file"); - check!(File::create(&path)); - let mut perm = check!(fs::metadata(&path)).permissions(); - perm.set_readonly(true); - check!(fs::set_permissions(&path, perm)); - check!(fs::remove_file(&path)); - } - - #[test] - fn mkdir_trailing_slash() { - let tmpdir = tmpdir(); - let path = tmpdir.join("file"); - check!(fs::create_dir_all(&path.join("a/"))); - } - - #[test] - fn canonicalize_works_simple() { - let tmpdir = tmpdir(); - let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); - let file = tmpdir.join("test"); - File::create(&file).unwrap(); - assert_eq!(fs::canonicalize(&file).unwrap(), file); - } - - #[test] - fn realpath_works() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { return }; - - let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); - let file = tmpdir.join("test"); - let dir = tmpdir.join("test2"); - let link = dir.join("link"); - let linkdir = tmpdir.join("test3"); - - File::create(&file).unwrap(); - fs::create_dir(&dir).unwrap(); - symlink_file(&file, &link).unwrap(); - symlink_dir(&dir, &linkdir).unwrap(); - - assert!(link.symlink_metadata().unwrap().file_type().is_symlink()); - - assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir); - assert_eq!(fs::canonicalize(&file).unwrap(), file); - assert_eq!(fs::canonicalize(&link).unwrap(), file); - assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir); - assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file); - } - - #[test] - fn realpath_works_tricky() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { return }; - - let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); - let a = tmpdir.join("a"); - let b = a.join("b"); - let c = b.join("c"); - let d = a.join("d"); - let e = d.join("e"); - let f = a.join("f"); - - fs::create_dir_all(&b).unwrap(); - fs::create_dir_all(&d).unwrap(); - File::create(&f).unwrap(); - if cfg!(not(windows)) { - symlink_dir("../d/e", &c).unwrap(); - symlink_file("../f", &e).unwrap(); - } - if cfg!(windows) { - symlink_dir(r"..\d\e", &c).unwrap(); - symlink_file(r"..\f", &e).unwrap(); - } - - assert_eq!(fs::canonicalize(&c).unwrap(), f); - assert_eq!(fs::canonicalize(&e).unwrap(), f); - } - - #[test] - fn dir_entry_methods() { - let tmpdir = tmpdir(); - - fs::create_dir_all(&tmpdir.join("a")).unwrap(); - File::create(&tmpdir.join("b")).unwrap(); - - for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) { - let fname = file.file_name(); - match fname.to_str() { - Some("a") => { - assert!(file.file_type().unwrap().is_dir()); - assert!(file.metadata().unwrap().is_dir()); - } - Some("b") => { - assert!(file.file_type().unwrap().is_file()); - assert!(file.metadata().unwrap().is_file()); - } - f => panic!("unknown file name: {:?}", f), - } - } - } - - #[test] - fn dir_entry_debug() { - let tmpdir = tmpdir(); - File::create(&tmpdir.join("b")).unwrap(); - let mut read_dir = tmpdir.path().read_dir().unwrap(); - let dir_entry = read_dir.next().unwrap().unwrap(); - let actual = format!("{:?}", dir_entry); - let expected = format!("DirEntry({:?})", dir_entry.0.path()); - assert_eq!(actual, expected); - } - - #[test] - fn read_dir_not_found() { - let res = fs::read_dir("/path/that/does/not/exist"); - assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound); - } - - #[test] - fn create_dir_all_with_junctions() { - let tmpdir = tmpdir(); - let target = tmpdir.join("target"); - - let junction = tmpdir.join("junction"); - let b = junction.join("a/b"); - - let link = tmpdir.join("link"); - let d = link.join("c/d"); - - fs::create_dir(&target).unwrap(); - - check!(symlink_junction(&target, &junction)); - check!(fs::create_dir_all(&b)); - // the junction itself is not a directory, but `is_dir()` on a Path - // follows links - assert!(junction.is_dir()); - assert!(b.exists()); - - if !got_symlink_permission(&tmpdir) { return }; - check!(symlink_dir(&target, &link)); - check!(fs::create_dir_all(&d)); - assert!(link.is_dir()); - assert!(d.exists()); - } - - #[test] - fn metadata_access_times() { - let tmpdir = tmpdir(); - - let b = tmpdir.join("b"); - File::create(&b).unwrap(); - - let a = check!(fs::metadata(&tmpdir.path())); - let b = check!(fs::metadata(&b)); - - assert_eq!(check!(a.accessed()), check!(a.accessed())); - assert_eq!(check!(a.modified()), check!(a.modified())); - assert_eq!(check!(b.accessed()), check!(b.modified())); - - if cfg!(target_os = "macos") || cfg!(target_os = "windows") { - check!(a.created()); - check!(b.created()); - } - } -} diff --git a/ctr-std/src/future.rs b/ctr-std/src/future.rs deleted file mode 100644 index 12ea1ea..0000000 --- a/ctr-std/src/future.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Asynchronous values. - -use core::cell::Cell; -use core::marker::Unpin; -use core::mem::PinMut; -use core::option::Option; -use core::ptr::NonNull; -use core::task::{self, Poll}; -use core::ops::{Drop, Generator, GeneratorState}; - -#[doc(inline)] -pub use core::future::*; - -/// Wrap a future in a generator. -/// -/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give -/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). -#[unstable(feature = "gen_future", issue = "50547")] -pub fn from_generator>(x: T) -> impl Future { - GenFuture(x) -} - -/// A wrapper around generators used to implement `Future` for `async`/`await` code. -#[unstable(feature = "gen_future", issue = "50547")] -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] -struct GenFuture>(T); - -// We rely on the fact that async/await futures are immovable in order to create -// self-referential borrows in the underlying generator. -impl> !Unpin for GenFuture {} - -#[unstable(feature = "gen_future", issue = "50547")] -impl> Future for GenFuture { - type Output = T::Return; - fn poll(self: PinMut, cx: &mut task::Context) -> Poll { - set_task_cx(cx, || match unsafe { PinMut::get_mut_unchecked(self).0.resume() } { - GeneratorState::Yielded(()) => Poll::Pending, - GeneratorState::Complete(x) => Poll::Ready(x), - }) - } -} - -thread_local! { - static TLS_CX: Cell>>> = Cell::new(None); -} - -struct SetOnDrop(Option>>); - -impl Drop for SetOnDrop { - fn drop(&mut self) { - TLS_CX.with(|tls_cx| { - tls_cx.set(self.0.take()); - }); - } -} - -#[unstable(feature = "gen_future", issue = "50547")] -/// Sets the thread-local task context used by async/await futures. -pub fn set_task_cx(cx: &mut task::Context, f: F) -> R -where - F: FnOnce() -> R -{ - let old_cx = TLS_CX.with(|tls_cx| { - tls_cx.replace(NonNull::new( - cx - as *mut task::Context - as *mut () - as *mut task::Context<'static> - )) - }); - let _reset_cx = SetOnDrop(old_cx); - f() -} - -#[unstable(feature = "gen_future", issue = "50547")] -/// Retrieves the thread-local task context used by async/await futures. -/// -/// This function acquires exclusive access to the task context. -/// -/// Panics if no task has been set or if the task context has already been -/// retrived by a surrounding call to get_task_cx. -pub fn get_task_cx(f: F) -> R -where - F: FnOnce(&mut task::Context) -> R -{ - let cx_ptr = TLS_CX.with(|tls_cx| { - // Clear the entry so that nested `with_get_cx` calls - // will fail or set their own value. - tls_cx.replace(None) - }); - let _reset_cx = SetOnDrop(cx_ptr); - - let mut cx_ptr = cx_ptr.expect( - "TLS task::Context not set. This is a rustc bug. \ - Please file an issue on https://github.com/rust-lang/rust."); - unsafe { f(cx_ptr.as_mut()) } -} - -#[unstable(feature = "gen_future", issue = "50547")] -/// Polls a future in the current thread-local task context. -pub fn poll_in_task_cx(f: PinMut) -> Poll -where - F: Future -{ - get_task_cx(|cx| f.poll(cx)) -} diff --git a/ctr-std/src/io/buffered.rs b/ctr-std/src/io/buffered.rs deleted file mode 100644 index 03c97de..0000000 --- a/ctr-std/src/io/buffered.rs +++ /dev/null @@ -1,1338 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Buffering wrappers for I/O traits - -use io::prelude::*; - -use cmp; -use error; -use fmt; -use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom}; -use memchr; - -/// The `BufReader` struct adds buffering to any reader. -/// -/// It can be excessively inefficient to work directly with a [`Read`] instance. -/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] -/// results in a system call. A `BufReader` performs large, infrequent reads on -/// the underlying [`Read`] and maintains an in-memory buffer of the results. -/// -/// `BufReader` can improve the speed of programs that make *small* and -/// *repeated* read calls to the same file or network socket. It does not -/// help when reading very large amounts at once, or reading just one or a few -/// times. It also provides no advantage when reading from a source that is -/// already in memory, like a `Vec`. -/// -/// [`Read`]: ../../std/io/trait.Read.html -/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read -/// [`TcpStream`]: ../../std/net/struct.TcpStream.html -/// -/// # Examples -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::io::BufReader; -/// use std::fs::File; -/// -/// fn main() -> std::io::Result<()> { -/// let f = File::open("log.txt")?; -/// let mut reader = BufReader::new(f); -/// -/// let mut line = String::new(); -/// let len = reader.read_line(&mut line)?; -/// println!("First line is {} bytes long", len); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BufReader { - inner: R, - buf: Box<[u8]>, - pos: usize, - cap: usize, -} - -impl BufReader { - /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, - /// but may change in the future. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::new(f); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: R) -> BufReader { - BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufReader` with the specified buffer capacity. - /// - /// # Examples - /// - /// Creating a buffer with ten bytes of capacity: - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::with_capacity(10, f); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(cap: usize, inner: R) -> BufReader { - unsafe { - let mut buffer = Vec::with_capacity(cap); - buffer.set_len(cap); - inner.initializer().initialize(&mut buffer); - BufReader { - inner, - buf: buffer.into_boxed_slice(), - pos: 0, - cap: 0, - } - } - } - - /// Gets a reference to the underlying reader. - /// - /// It is inadvisable to directly read from the underlying reader. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); - /// - /// let f2 = reader.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &R { &self.inner } - - /// Gets a mutable reference to the underlying reader. - /// - /// It is inadvisable to directly read from the underlying reader. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let mut reader = BufReader::new(f1); - /// - /// let f2 = reader.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut R { &mut self.inner } - - /// Returns a reference to the internally buffered data. - /// - /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(bufreader_buffer)] - /// use std::io::{BufReader, BufRead}; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let mut reader = BufReader::new(f); - /// assert!(reader.buffer().is_empty()); - /// - /// if reader.fill_buf()?.len() > 0 { - /// assert!(!reader.buffer().is_empty()); - /// } - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "bufreader_buffer", issue = "45323")] - pub fn buffer(&self) -> &[u8] { - &self.buf[self.pos..self.cap] - } - - /// Unwraps this `BufReader`, returning the underlying reader. - /// - /// Note that any leftover data in the internal buffer is lost. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); - /// - /// let f2 = reader.into_inner(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> R { self.inner } -} - -impl BufReader { - /// Seeks relative to the current position. If the new position lies within the buffer, - /// the buffer will not be flushed, allowing for more efficient seeks. - /// This method does not return the location of the underlying reader, so the caller - /// must track this information themselves if it is required. - #[unstable(feature = "bufreader_seek_relative", issue = "31100")] - pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> { - let pos = self.pos as u64; - if offset < 0 { - if let Some(new_pos) = pos.checked_sub((-offset) as u64) { - self.pos = new_pos as usize; - return Ok(()) - } - } else { - if let Some(new_pos) = pos.checked_add(offset as u64) { - if new_pos <= self.cap as u64 { - self.pos = new_pos as usize; - return Ok(()) - } - } - } - self.seek(SeekFrom::Current(offset)).map(|_|()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for BufReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - // If we don't have any buffered data and we're doing a massive read - // (larger than our internal buffer), bypass our internal buffer - // entirely. - if self.pos == self.cap && buf.len() >= self.buf.len() { - return self.inner.read(buf); - } - let nread = { - let mut rem = self.fill_buf()?; - rem.read(buf)? - }; - self.consume(nread); - Ok(nread) - } - - // we can't skip unconditionally because of the large buffer case in read. - unsafe fn initializer(&self) -> Initializer { - self.inner.initializer() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl BufRead for BufReader { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - // If we've reached the end of our internal buffer then we need to fetch - // some more data from the underlying reader. - // Branch using `>=` instead of the more correct `==` - // to tell the compiler that the pos..cap slice is always valid. - if self.pos >= self.cap { - debug_assert!(self.pos == self.cap); - self.cap = self.inner.read(&mut self.buf)?; - self.pos = 0; - } - Ok(&self.buf[self.pos..self.cap]) - } - - fn consume(&mut self, amt: usize) { - self.pos = cmp::min(self.pos + amt, self.cap); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufReader where R: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("BufReader") - .field("reader", &self.inner) - .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Seek for BufReader { - /// Seek to an offset, in bytes, in the underlying reader. - /// - /// The position used for seeking with `SeekFrom::Current(_)` is the - /// position the underlying reader would be at if the `BufReader` had no - /// internal buffer. - /// - /// Seeking always discards the internal buffer, even if the seek position - /// would otherwise fall within it. This guarantees that calling - /// `.into_inner()` immediately after a seek yields the underlying reader - /// at the same position. - /// - /// To seek without discarding the internal buffer, use [`seek_relative`]. - /// - /// See `std::io::Seek` for more details. - /// - /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)` - /// where `n` minus the internal buffer length overflows an `i64`, two - /// seeks will be performed instead of one. If the second seek returns - /// `Err`, the underlying reader will be left at the same position it would - /// have if you called `seek` with `SeekFrom::Current(0)`. - /// - /// [`seek_relative`]: #method.seek_relative - fn seek(&mut self, pos: SeekFrom) -> io::Result { - let result: u64; - if let SeekFrom::Current(n) = pos { - let remainder = (self.cap - self.pos) as i64; - // it should be safe to assume that remainder fits within an i64 as the alternative - // means we managed to allocate 8 exbibytes and that's absurd. - // But it's not out of the realm of possibility for some weird underlying reader to - // support seeking by i64::min_value() so we need to handle underflow when subtracting - // remainder. - if let Some(offset) = n.checked_sub(remainder) { - result = self.inner.seek(SeekFrom::Current(offset))?; - } else { - // seek backwards by our remainder, and then by the offset - self.inner.seek(SeekFrom::Current(-remainder))?; - self.pos = self.cap; // empty the buffer - result = self.inner.seek(SeekFrom::Current(n))?; - } - } else { - // Seeking with Start/End doesn't care about our buffer length. - result = self.inner.seek(pos)?; - } - self.pos = self.cap; // empty the buffer - Ok(result) - } -} - -/// Wraps a writer and buffers its output. -/// -/// It can be excessively inefficient to work directly with something that -/// implements [`Write`]. For example, every call to -/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A -/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying -/// writer in large, infrequent batches. -/// -/// `BufWriter` can improve the speed of programs that make *small* and -/// *repeated* write calls to the same file or network socket. It does not -/// help when writing very large amounts at once, or writing just one or a few -/// times. It also provides no advantage when writing to a destination that is -/// in memory, like a `Vec`. -/// -/// When the `BufWriter` is dropped, the contents of its buffer will be written -/// out. However, any errors that happen in the process of flushing the buffer -/// when the writer is dropped will be ignored. Code that wishes to handle such -/// errors must manually call [`flush`] before the writer is dropped. -/// -/// # Examples -/// -/// Let's write the numbers one through ten to a [`TcpStream`]: -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::net::TcpStream; -/// -/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); -/// -/// for i in 0..10 { -/// stream.write(&[i+1]).unwrap(); -/// } -/// ``` -/// -/// Because we're not buffering, we write each one in turn, incurring the -/// overhead of a system call per byte written. We can fix this with a -/// `BufWriter`: -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::io::BufWriter; -/// use std::net::TcpStream; -/// -/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); -/// -/// for i in 0..10 { -/// stream.write(&[i+1]).unwrap(); -/// } -/// ``` -/// -/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped -/// together by the buffer, and will all be written out in one system call when -/// the `stream` is dropped. -/// -/// [`Write`]: ../../std/io/trait.Write.html -/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write -/// [`TcpStream`]: ../../std/net/struct.TcpStream.html -/// [`flush`]: #method.flush -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BufWriter { - inner: Option, - buf: Vec, - // #30888: If the inner writer panics in a call to write, we don't want to - // write the buffered data a second time in BufWriter's destructor. This - // flag tells the Drop impl if it should skip the flush. - panicked: bool, -} - -/// An error returned by `into_inner` which combines an error that -/// happened while writing out the buffer, and the buffered writer object -/// which may be used to recover from the condition. -/// -/// # Examples -/// -/// ```no_run -/// use std::io::BufWriter; -/// use std::net::TcpStream; -/// -/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); -/// -/// // do stuff with the stream -/// -/// // we want to get our `TcpStream` back, so let's try: -/// -/// let stream = match stream.into_inner() { -/// Ok(s) => s, -/// Err(e) => { -/// // Here, e is an IntoInnerError -/// panic!("An error occurred"); -/// } -/// }; -/// ``` -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoInnerError(W, Error); - -impl BufWriter { - /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, - /// but may change in the future. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: W) -> BufWriter { - BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufWriter` with the specified buffer capacity. - /// - /// # Examples - /// - /// Creating a buffer with a buffer of a hundred bytes. - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); - /// let mut buffer = BufWriter::with_capacity(100, stream); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(cap: usize, inner: W) -> BufWriter { - BufWriter { - inner: Some(inner), - buf: Vec::with_capacity(cap), - panicked: false, - } - } - - fn flush_buf(&mut self) -> io::Result<()> { - let mut written = 0; - let len = self.buf.len(); - let mut ret = Ok(()); - while written < len { - self.panicked = true; - let r = self.inner.as_mut().unwrap().write(&self.buf[written..]); - self.panicked = false; - - match r { - Ok(0) => { - ret = Err(Error::new(ErrorKind::WriteZero, - "failed to write the buffered data")); - break; - } - Ok(n) => written += n, - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => { ret = Err(e); break } - - } - } - if written > 0 { - self.buf.drain(..written); - } - ret - } - - /// Gets a reference to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // we can use reference just like buffer - /// let reference = buffer.get_ref(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } - - /// Gets a mutable reference to the underlying writer. - /// - /// It is inadvisable to directly write to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // we can use reference just like buffer - /// let reference = buffer.get_mut(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } - - /// Unwraps this `BufWriter`, returning the underlying writer. - /// - /// The buffer is written out before returning the writer. - /// - /// # Errors - /// - /// An `Err` will be returned if an error occurs while flushing the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // unwrap the TcpStream and flush the buffer - /// let stream = buffer.into_inner().unwrap(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(mut self) -> Result>> { - match self.flush_buf() { - Err(e) => Err(IntoInnerError(self, e)), - Ok(()) => Ok(self.inner.take().unwrap()) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for BufWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - if self.buf.len() + buf.len() > self.buf.capacity() { - self.flush_buf()?; - } - if buf.len() >= self.buf.capacity() { - self.panicked = true; - let r = self.inner.as_mut().unwrap().write(buf); - self.panicked = false; - r - } else { - Write::write(&mut self.buf, buf) - } - } - fn flush(&mut self) -> io::Result<()> { - self.flush_buf().and_then(|()| self.get_mut().flush()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufWriter where W: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("BufWriter") - .field("writer", &self.inner.as_ref().unwrap()) - .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Seek for BufWriter { - /// Seek to the offset, in bytes, in the underlying writer. - /// - /// Seeking always writes out the internal buffer before seeking. - fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.flush_buf().and_then(|_| self.get_mut().seek(pos)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Drop for BufWriter { - fn drop(&mut self) { - if self.inner.is_some() && !self.panicked { - // dtors should not panic, so we ignore a failed flush - let _r = self.flush_buf(); - } - } -} - -impl IntoInnerError { - /// Returns the error which caused the call to `into_inner()` to fail. - /// - /// This error was returned when attempting to write the internal buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // do stuff with the stream - /// - /// // we want to get our `TcpStream` back, so let's try: - /// - /// let stream = match stream.into_inner() { - /// Ok(s) => s, - /// Err(e) => { - /// // Here, e is an IntoInnerError, let's log the inner error. - /// // - /// // We'll just 'log' to stdout for this example. - /// println!("{}", e.error()); - /// - /// panic!("An unexpected error occurred."); - /// } - /// }; - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn error(&self) -> &Error { &self.1 } - - /// Returns the buffered writer instance which generated the error. - /// - /// The returned object can be used for error recovery, such as - /// re-inspecting the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // do stuff with the stream - /// - /// // we want to get our `TcpStream` back, so let's try: - /// - /// let stream = match stream.into_inner() { - /// Ok(s) => s, - /// Err(e) => { - /// // Here, e is an IntoInnerError, let's re-examine the buffer: - /// let buffer = e.into_inner(); - /// - /// // do stuff to try to recover - /// - /// // afterwards, let's just return the stream - /// buffer.into_inner().unwrap() - /// } - /// }; - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> W { self.0 } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl From> for Error { - fn from(iie: IntoInnerError) -> Error { iie.1 } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for IntoInnerError { - fn description(&self) -> &str { - error::Error::description(self.error()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for IntoInnerError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.error().fmt(f) - } -} - -/// Wraps a writer and buffers output to it, flushing whenever a newline -/// (`0x0a`, `'\n'`) is detected. -/// -/// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output. -/// But it only does this batched write when it goes out of scope, or when the -/// internal buffer is full. Sometimes, you'd prefer to write each line as it's -/// completed, rather than the entire buffer at once. Enter `LineWriter`. It -/// does exactly that. -/// -/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the -/// `LineWriter` goes out of scope or when its internal buffer is full. -/// -/// [bufwriter]: struct.BufWriter.html -/// -/// If there's still a partial line in the buffer when the `LineWriter` is -/// dropped, it will flush those contents. -/// -/// # Examples -/// -/// We can use `LineWriter` to write one line at a time, significantly -/// reducing the number of actual writes to the file. -/// -/// ```no_run -/// use std::fs::{self, File}; -/// use std::io::prelude::*; -/// use std::io::LineWriter; -/// -/// fn main() -> std::io::Result<()> { -/// let road_not_taken = b"I shall be telling this with a sigh -/// Somewhere ages and ages hence: -/// Two roads diverged in a wood, and I - -/// I took the one less traveled by, -/// And that has made all the difference."; -/// -/// let file = File::create("poem.txt")?; -/// let mut file = LineWriter::new(file); -/// -/// file.write_all(b"I shall be telling this with a sigh")?; -/// -/// // No bytes are written until a newline is encountered (or -/// // the internal buffer is filled). -/// assert_eq!(fs::read_to_string("poem.txt")?, ""); -/// file.write_all(b"\n")?; -/// assert_eq!( -/// fs::read_to_string("poem.txt")?, -/// "I shall be telling this with a sigh\n", -/// ); -/// -/// // Write the rest of the poem. -/// file.write_all(b"Somewhere ages and ages hence: -/// Two roads diverged in a wood, and I - -/// I took the one less traveled by, -/// And that has made all the difference.")?; -/// -/// // The last line of the poem doesn't end in a newline, so -/// // we have to flush or drop the `LineWriter` to finish -/// // writing. -/// file.flush()?; -/// -/// // Confirm the whole poem was written. -/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct LineWriter { - inner: BufWriter, - need_flush: bool, -} - -impl LineWriter { - /// Creates a new `LineWriter`. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: W) -> LineWriter { - // Lines typically aren't that long, don't use a giant buffer - LineWriter::with_capacity(1024, inner) - } - - /// Creates a new `LineWriter` with a specified capacity for the internal - /// buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::with_capacity(100, file); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(cap: usize, inner: W) -> LineWriter { - LineWriter { - inner: BufWriter::with_capacity(cap, inner), - need_flush: false, - } - } - - /// Gets a reference to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); - /// - /// let reference = file.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &W { self.inner.get_ref() } - - /// Gets a mutable reference to the underlying writer. - /// - /// Caution must be taken when calling methods on the mutable reference - /// returned as extra writes could corrupt the output stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let mut file = LineWriter::new(file); - /// - /// // we can use reference just like file - /// let reference = file.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() } - - /// Unwraps this `LineWriter`, returning the underlying writer. - /// - /// The internal buffer is written out before returning the writer. - /// - /// # Errors - /// - /// An `Err` will be returned if an error occurs while flushing the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// - /// let writer: LineWriter = LineWriter::new(file); - /// - /// let file: File = writer.into_inner()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> Result>> { - self.inner.into_inner().map_err(|IntoInnerError(buf, e)| { - IntoInnerError(LineWriter { - inner: buf, - need_flush: false, - }, e) - }) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for LineWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - if self.need_flush { - self.flush()?; - } - - // Find the last newline character in the buffer provided. If found then - // we're going to write all the data up to that point and then flush, - // otherewise we just write the whole block to the underlying writer. - let i = match memchr::memrchr(b'\n', buf) { - Some(i) => i, - None => return self.inner.write(buf), - }; - - - // Ok, we're going to write a partial amount of the data given first - // followed by flushing the newline. After we've successfully written - // some data then we *must* report that we wrote that data, so future - // errors are ignored. We set our internal `need_flush` flag, though, in - // case flushing fails and we need to try it first next time. - let n = self.inner.write(&buf[..i + 1])?; - self.need_flush = true; - if self.flush().is_err() || n != i + 1 { - return Ok(n) - } - - // At this point we successfully wrote `i + 1` bytes and flushed it out, - // meaning that the entire line is now flushed out on the screen. While - // we can attempt to finish writing the rest of the data provided. - // Remember though that we ignore errors here as we've successfully - // written data, so we need to report that. - match self.inner.write(&buf[i + 1..]) { - Ok(i) => Ok(n + i), - Err(_) => Ok(n), - } - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush()?; - self.need_flush = false; - Ok(()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for LineWriter where W: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("LineWriter") - .field("writer", &self.inner.inner) - .field("buffer", - &format_args!("{}/{}", self.inner.buf.len(), self.inner.buf.capacity())) - .finish() - } -} - -#[cfg(test)] -mod tests { - use io::prelude::*; - use io::{self, BufReader, BufWriter, LineWriter, SeekFrom}; - use sync::atomic::{AtomicUsize, Ordering}; - use thread; - use test; - - /// A dummy reader intended at testing short-reads propagation. - pub struct ShortReader { - lengths: Vec, - } - - impl Read for ShortReader { - fn read(&mut self, _: &mut [u8]) -> io::Result { - if self.lengths.is_empty() { - Ok(0) - } else { - Ok(self.lengths.remove(0)) - } - } - } - - #[test] - fn test_buffered_reader() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, inner); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(buf, b); - - let mut buf = [0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 2); - let b: &[_] = &[0, 1]; - assert_eq!(buf, b); - - let mut buf = [0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - let b: &[_] = &[2]; - assert_eq!(buf, b); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - let b: &[_] = &[3, 0, 0]; - assert_eq!(buf, b); - - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - let b: &[_] = &[4, 0, 0]; - assert_eq!(buf, b); - - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_buffered_reader_seek() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); - - assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); - assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); - reader.consume(1); - assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3)); - } - - #[test] - fn test_buffered_reader_seek_relative() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); - - assert!(reader.seek_relative(3).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert!(reader.seek_relative(0).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert!(reader.seek_relative(1).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[1][..])); - assert!(reader.seek_relative(-1).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert!(reader.seek_relative(2).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..])); - } - - #[test] - fn test_buffered_reader_seek_underflow() { - // gimmick reader that yields its position modulo 256 for each byte - struct PositionReader { - pos: u64 - } - impl Read for PositionReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let len = buf.len(); - for x in buf { - *x = self.pos as u8; - self.pos = self.pos.wrapping_add(1); - } - Ok(len) - } - } - impl Seek for PositionReader { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - match pos { - SeekFrom::Start(n) => { - self.pos = n; - } - SeekFrom::Current(n) => { - self.pos = self.pos.wrapping_add(n as u64); - } - SeekFrom::End(n) => { - self.pos = u64::max_value().wrapping_add(n as u64); - } - } - Ok(self.pos) - } - } - - let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); - assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::max_value()-5)); - assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); - // the following seek will require two underlying seeks - let expected = 9223372036854775802; - assert_eq!(reader.seek(SeekFrom::Current(i64::min_value())).ok(), Some(expected)); - assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); - // seeking to 0 should empty the buffer. - assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); - assert_eq!(reader.get_ref().pos, expected); - } - - #[test] - fn test_buffered_writer() { - let inner = Vec::new(); - let mut writer = BufWriter::with_capacity(2, inner); - - writer.write(&[0, 1]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.write(&[2]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.write(&[3]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); - - writer.write(&[4]).unwrap(); - writer.write(&[5]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); - - writer.write(&[6]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); - - writer.write(&[7, 8]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); - - writer.write(&[9, 10, 11]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); - - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); - } - - #[test] - fn test_buffered_writer_inner_flushes() { - let mut w = BufWriter::with_capacity(3, Vec::new()); - w.write(&[0, 1]).unwrap(); - assert_eq!(*w.get_ref(), []); - let w = w.into_inner().unwrap(); - assert_eq!(w, [0, 1]); - } - - #[test] - fn test_buffered_writer_seek() { - let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); - w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); - w.write_all(&[6, 7]).unwrap(); - assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); - assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); - assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); - w.write_all(&[8, 9]).unwrap(); - assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); - } - - #[test] - fn test_read_until() { - let inner: &[u8] = &[0, 1, 2, 1, 0]; - let mut reader = BufReader::with_capacity(2, inner); - let mut v = Vec::new(); - reader.read_until(0, &mut v).unwrap(); - assert_eq!(v, [0]); - v.truncate(0); - reader.read_until(2, &mut v).unwrap(); - assert_eq!(v, [1, 2]); - v.truncate(0); - reader.read_until(1, &mut v).unwrap(); - assert_eq!(v, [1]); - v.truncate(0); - reader.read_until(8, &mut v).unwrap(); - assert_eq!(v, [0]); - v.truncate(0); - reader.read_until(9, &mut v).unwrap(); - assert_eq!(v, []); - } - - #[test] - fn test_line_buffer_fail_flush() { - // Issue #32085 - struct FailFlushWriter<'a>(&'a mut Vec); - - impl<'a> Write for FailFlushWriter<'a> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.extend_from_slice(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Err(io::Error::new(io::ErrorKind::Other, "flush failed")) - } - } - - let mut buf = Vec::new(); - { - let mut writer = LineWriter::new(FailFlushWriter(&mut buf)); - let to_write = b"abc\ndef"; - if let Ok(written) = writer.write(to_write) { - assert!(written < to_write.len(), "didn't flush on new line"); - // PASS - return; - } - } - assert!(buf.is_empty(), "write returned an error but wrote data"); - } - - #[test] - fn test_line_buffer() { - let mut writer = LineWriter::new(Vec::new()); - writer.write(&[0]).unwrap(); - assert_eq!(*writer.get_ref(), []); - writer.write(&[1]).unwrap(); - assert_eq!(*writer.get_ref(), []); - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1]); - writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']); - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]); - writer.write(&[3, b'\n']).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); - } - - #[test] - fn test_read_line() { - let in_buf: &[u8] = b"a\nb\nc"; - let mut reader = BufReader::with_capacity(2, in_buf); - let mut s = String::new(); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "a\n"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "b\n"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "c"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, ""); - } - - #[test] - fn test_lines() { - let in_buf: &[u8] = b"a\nb\nc"; - let reader = BufReader::with_capacity(2, in_buf); - let mut it = reader.lines(); - assert_eq!(it.next().unwrap().unwrap(), "a".to_string()); - assert_eq!(it.next().unwrap().unwrap(), "b".to_string()); - assert_eq!(it.next().unwrap().unwrap(), "c".to_string()); - assert!(it.next().is_none()); - } - - #[test] - fn test_short_reads() { - let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]}; - let mut reader = BufReader::new(inner); - let mut buf = [0, 0]; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.read(&mut buf).unwrap(), 2); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - #[should_panic] - fn dont_panic_in_drop_on_panicked_flush() { - struct FailFlushWriter; - - impl Write for FailFlushWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } - fn flush(&mut self) -> io::Result<()> { - Err(io::Error::last_os_error()) - } - } - - let writer = FailFlushWriter; - let _writer = BufWriter::new(writer); - - // If writer panics *again* due to the flush error then the process will - // abort. - panic!(); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn panic_in_write_doesnt_flush_in_drop() { - static WRITES: AtomicUsize = AtomicUsize::new(0); - - struct PanicWriter; - - impl Write for PanicWriter { - fn write(&mut self, _: &[u8]) -> io::Result { - WRITES.fetch_add(1, Ordering::SeqCst); - panic!(); - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } - } - - thread::spawn(|| { - let mut writer = BufWriter::new(PanicWriter); - let _ = writer.write(b"hello world"); - let _ = writer.flush(); - }).join().unwrap_err(); - - assert_eq!(WRITES.load(Ordering::SeqCst), 1); - } - - #[bench] - fn bench_buffered_reader(b: &mut test::Bencher) { - b.iter(|| { - BufReader::new(io::empty()) - }); - } - - #[bench] - fn bench_buffered_writer(b: &mut test::Bencher) { - b.iter(|| { - BufWriter::new(io::sink()) - }); - } - - struct AcceptOneThenFail { - written: bool, - flushed: bool, - } - - impl Write for AcceptOneThenFail { - fn write(&mut self, data: &[u8]) -> io::Result { - if !self.written { - assert_eq!(data, b"a\nb\n"); - self.written = true; - Ok(data.len()) - } else { - Err(io::Error::new(io::ErrorKind::NotFound, "test")) - } - } - - fn flush(&mut self) -> io::Result<()> { - assert!(self.written); - assert!(!self.flushed); - self.flushed = true; - Err(io::Error::new(io::ErrorKind::Other, "test")) - } - } - - #[test] - fn erroneous_flush_retried() { - let a = AcceptOneThenFail { - written: false, - flushed: false, - }; - - let mut l = LineWriter::new(a); - assert_eq!(l.write(b"a\nb\na").unwrap(), 4); - assert!(l.get_ref().written); - assert!(l.get_ref().flushed); - l.get_mut().flushed = false; - - assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other) - } -} diff --git a/ctr-std/src/io/cursor.rs b/ctr-std/src/io/cursor.rs deleted file mode 100644 index 14f2015..0000000 --- a/ctr-std/src/io/cursor.rs +++ /dev/null @@ -1,682 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io::prelude::*; - -use core::convert::TryInto; -use cmp; -use io::{self, Initializer, SeekFrom, Error, ErrorKind}; - -/// A `Cursor` wraps an in-memory buffer and provides it with a -/// [`Seek`] implementation. -/// -/// `Cursor`s are used with in-memory buffers, anything implementing -/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`], -/// allowing these buffers to be used anywhere you might use a reader or writer -/// that does actual I/O. -/// -/// The standard library implements some I/O traits on various types which -/// are commonly used as a buffer, like `Cursor<`[`Vec`]`>` and -/// `Cursor<`[`&[u8]`][bytes]`>`. -/// -/// # Examples -/// -/// We may want to write bytes to a [`File`] in our production -/// code, but use an in-memory buffer in our tests. We can do this with -/// `Cursor`: -/// -/// [`Seek`]: trait.Seek.html -/// [`Read`]: ../../std/io/trait.Read.html -/// [`Write`]: ../../std/io/trait.Write.html -/// [`Vec`]: ../../std/vec/struct.Vec.html -/// [bytes]: ../../std/primitive.slice.html -/// [`File`]: ../fs/struct.File.html -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::io::{self, SeekFrom}; -/// use std::fs::File; -/// -/// // a library function we've written -/// fn write_ten_bytes_at_end(writer: &mut W) -> io::Result<()> { -/// writer.seek(SeekFrom::End(-10))?; -/// -/// for i in 0..10 { -/// writer.write(&[i])?; -/// } -/// -/// // all went well -/// Ok(()) -/// } -/// -/// # fn foo() -> io::Result<()> { -/// // Here's some code that uses this library function. -/// // -/// // We might want to use a BufReader here for efficiency, but let's -/// // keep this example focused. -/// let mut file = File::create("foo.txt")?; -/// -/// write_ten_bytes_at_end(&mut file)?; -/// # Ok(()) -/// # } -/// -/// // now let's write a test -/// #[test] -/// fn test_writes_bytes() { -/// // setting up a real File is much slower than an in-memory buffer, -/// // let's use a cursor instead -/// use std::io::Cursor; -/// let mut buff = Cursor::new(vec![0; 15]); -/// -/// write_ten_bytes_at_end(&mut buff).unwrap(); -/// -/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone, Debug)] -pub struct Cursor { - inner: T, - pos: u64, -} - -impl Cursor { - /// Creates a new cursor wrapping the provided underlying in-memory buffer. - /// - /// Cursor initial position is `0` even if underlying buffer (e.g. `Vec`) - /// is not empty. So writing to cursor starts with overwriting `Vec` - /// content, not with appending to it. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// - /// let buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: T) -> Cursor { - Cursor { pos: 0, inner: inner } - } - - /// Consumes this cursor, returning the underlying value. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// - /// let buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// - /// let vec = buff.into_inner(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> T { self.inner } - - /// Gets a reference to the underlying value in this cursor. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// - /// let buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// - /// let reference = buff.get_ref(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &T { &self.inner } - - /// Gets a mutable reference to the underlying value in this cursor. - /// - /// Care should be taken to avoid modifying the internal I/O state of the - /// underlying value as it may corrupt this cursor's position. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// - /// let mut buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// - /// let reference = buff.get_mut(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut T { &mut self.inner } - - /// Returns the current position of this cursor. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// use std::io::prelude::*; - /// use std::io::SeekFrom; - /// - /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]); - /// - /// assert_eq!(buff.position(), 0); - /// - /// buff.seek(SeekFrom::Current(2)).unwrap(); - /// assert_eq!(buff.position(), 2); - /// - /// buff.seek(SeekFrom::Current(-1)).unwrap(); - /// assert_eq!(buff.position(), 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn position(&self) -> u64 { self.pos } - - /// Sets the position of this cursor. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// - /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]); - /// - /// assert_eq!(buff.position(), 0); - /// - /// buff.set_position(2); - /// assert_eq!(buff.position(), 2); - /// - /// buff.set_position(4); - /// assert_eq!(buff.position(), 4); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_position(&mut self, pos: u64) { self.pos = pos; } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl io::Seek for Cursor where T: AsRef<[u8]> { - fn seek(&mut self, style: SeekFrom) -> io::Result { - let (base_pos, offset) = match style { - SeekFrom::Start(n) => { self.pos = n; return Ok(n); } - SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n), - SeekFrom::Current(n) => (self.pos, n), - }; - let new_pos = if offset >= 0 { - base_pos.checked_add(offset as u64) - } else { - base_pos.checked_sub((offset.wrapping_neg()) as u64) - }; - match new_pos { - Some(n) => {self.pos = n; Ok(self.pos)} - None => Err(Error::new(ErrorKind::InvalidInput, - "invalid seek to a negative or overflowing position")) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for Cursor where T: AsRef<[u8]> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let n = Read::read(&mut self.fill_buf()?, buf)?; - self.pos += n as u64; - Ok(n) - } - - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - let n = buf.len(); - Read::read_exact(&mut self.fill_buf()?, buf)?; - self.pos += n as u64; - Ok(()) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl BufRead for Cursor where T: AsRef<[u8]> { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64); - Ok(&self.inner.as_ref()[(amt as usize)..]) - } - fn consume(&mut self, amt: usize) { self.pos += amt as u64; } -} - -// Non-resizing write implementation -fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result { - let pos = cmp::min(*pos_mut, slice.len() as u64); - let amt = (&mut slice[(pos as usize)..]).write(buf)?; - *pos_mut += amt as u64; - Ok(amt) -} - -// Resizing write implementation -fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result { - let pos: usize = (*pos_mut).try_into().map_err(|_| { - Error::new(ErrorKind::InvalidInput, - "cursor position exceeds maximum possible vector length") - })?; - // Make sure the internal buffer is as least as big as where we - // currently are - let len = vec.len(); - if len < pos { - // use `resize` so that the zero filling is as efficient as possible - vec.resize(pos, 0); - } - // Figure out what bytes will be used to overwrite what's currently - // there (left), and what will be appended on the end (right) - { - let space = vec.len() - pos; - let (left, right) = buf.split_at(cmp::min(space, buf.len())); - vec[pos..pos + left.len()].copy_from_slice(left); - vec.extend_from_slice(right); - } - - // Bump us forward - *pos_mut = (pos + buf.len()) as u64; - Ok(buf.len()) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Write for Cursor<&'a mut [u8]> { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - slice_write(&mut self.pos, self.inner, buf) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -#[stable(feature = "cursor_mut_vec", since = "1.25.0")] -impl<'a> Write for Cursor<&'a mut Vec> { - fn write(&mut self, buf: &[u8]) -> io::Result { - vec_write(&mut self.pos, self.inner, buf) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Cursor> { - fn write(&mut self, buf: &[u8]) -> io::Result { - vec_write(&mut self.pos, &mut self.inner, buf) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -#[stable(feature = "cursor_box_slice", since = "1.5.0")] -impl Write for Cursor> { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - slice_write(&mut self.pos, &mut self.inner, buf) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -#[cfg(test)] -mod tests { - use io::prelude::*; - use io::{Cursor, SeekFrom}; - - #[test] - fn test_vec_writer() { - let mut writer = Vec::new(); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(writer, b); - } - - #[test] - fn test_mem_writer() { - let mut writer = Cursor::new(Vec::new()); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn test_mem_mut_writer() { - let mut vec = Vec::new(); - let mut writer = Cursor::new(&mut vec); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn test_box_slice_writer() { - let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write(&[8, 9]).unwrap(), 1); - assert_eq!(writer.write(&[10]).unwrap(), 0); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(&**writer.get_ref(), b); - } - - #[test] - fn test_buf_writer() { - let mut buf = [0 as u8; 9]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write(&[8, 9]).unwrap(), 1); - assert_eq!(writer.write(&[10]).unwrap(), 0); - } - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_seek() { - let mut buf = [0 as u8; 8]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[1]).unwrap(), 1); - assert_eq!(writer.position(), 1); - - assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2); - assert_eq!(writer.position(), 2); - assert_eq!(writer.write(&[2]).unwrap(), 1); - assert_eq!(writer.position(), 3); - - assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[3]).unwrap(), 1); - assert_eq!(writer.position(), 2); - - assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); - assert_eq!(writer.position(), 7); - assert_eq!(writer.write(&[4]).unwrap(), 1); - assert_eq!(writer.position(), 8); - - } - let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_error() { - let mut buf = [0 as u8; 2]; - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[0, 0]).unwrap(), 1); - assert_eq!(writer.write(&[0, 0]).unwrap(), 0); - } - - #[test] - fn test_mem_reader() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_boxed_slice_reader() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn read_to_end() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); - let mut v = Vec::new(); - reader.read_to_end(&mut v).unwrap(); - assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]); - } - - #[test] - fn test_slice_reader() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let reader = &mut &in_buf[..]; - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.len(), 7); - let b: &[_] = &[0]; - assert_eq!(&buf[..], b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.len(), 3); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(&buf[..], b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_read_exact() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let reader = &mut &in_buf[..]; - let mut buf = []; - assert!(reader.read_exact(&mut buf).is_ok()); - let mut buf = [8]; - assert!(reader.read_exact(&mut buf).is_ok()); - assert_eq!(buf[0], 0); - assert_eq!(reader.len(), 7); - let mut buf = [0, 0, 0, 0, 0, 0, 0]; - assert!(reader.read_exact(&mut buf).is_ok()); - assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]); - assert_eq!(reader.len(), 0); - let mut buf = [0]; - assert!(reader.read_exact(&mut buf).is_err()); - } - - #[test] - fn test_buf_reader() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let mut reader = Cursor::new(&in_buf[..]); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn seek_past_end() { - let buf = [0xff]; - let mut r = Cursor::new(&buf[..]); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.read(&mut [0]).unwrap(), 0); - - let mut r = Cursor::new(vec![10]); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.read(&mut [0]).unwrap(), 0); - - let mut buf = [0]; - let mut r = Cursor::new(&mut buf[..]); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 0); - - let mut r = Cursor::new(vec![10].into_boxed_slice()); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 0); - } - - #[test] - fn seek_past_i64() { - let buf = [0xff]; - let mut r = Cursor::new(&buf[..]); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - - let mut r = Cursor::new(vec![10]); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - - let mut buf = [0]; - let mut r = Cursor::new(&mut buf[..]); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - - let mut r = Cursor::new(vec![10].into_boxed_slice()); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - } - - #[test] - fn seek_before_0() { - let buf = [0xff]; - let mut r = Cursor::new(&buf[..]); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut r = Cursor::new(vec![10]); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut buf = [0]; - let mut r = Cursor::new(&mut buf[..]); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut r = Cursor::new(vec![10].into_boxed_slice()); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - } - - #[test] - fn test_seekable_mem_writer() { - let mut writer = Cursor::new(Vec::::new()); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[3, 4]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3); - assert_eq!(writer.write(&[0, 1]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); - assert_eq!(writer.write(&[1, 2]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10); - assert_eq!(writer.write(&[1]).unwrap(), 1); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn vec_seek_past_end() { - let mut r = Cursor::new(Vec::new()); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 1); - } - - #[test] - fn vec_seek_before_0() { - let mut r = Cursor::new(Vec::new()); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - } - - #[test] - #[cfg(target_pointer_width = "32")] - fn vec_seek_and_write_past_usize_max() { - let mut c = Cursor::new(Vec::new()); - c.set_position(::max_value() as u64 + 1); - assert!(c.write_all(&[1, 2, 3]).is_err()); - } -} diff --git a/ctr-std/src/io/error.rs b/ctr-std/src/io/error.rs deleted file mode 100644 index 3e50988..0000000 --- a/ctr-std/src/io/error.rs +++ /dev/null @@ -1,620 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use error; -use fmt; -use result; -use sys; -use convert::From; - -/// A specialized [`Result`](../result/enum.Result.html) type for I/O -/// operations. -/// -/// This type is broadly used across [`std::io`] for any operation which may -/// produce an error. -/// -/// This typedef is generally used to avoid writing out [`io::Error`] directly and -/// is otherwise a direct mapping to [`Result`]. -/// -/// While usual Rust style is to import types directly, aliases of [`Result`] -/// often are not, to make it easier to distinguish between them. [`Result`] is -/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias -/// will generally use `io::Result` instead of shadowing the prelude's import -/// of [`std::result::Result`][`Result`]. -/// -/// [`std::io`]: ../io/index.html -/// [`io::Error`]: ../io/struct.Error.html -/// [`Result`]: ../result/enum.Result.html -/// -/// # Examples -/// -/// A convenience function that bubbles an `io::Result` to its caller: -/// -/// ``` -/// use std::io; -/// -/// fn get_string() -> io::Result { -/// let mut buffer = String::new(); -/// -/// io::stdin().read_line(&mut buffer)?; -/// -/// Ok(buffer) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub type Result = result::Result; - -/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and -/// associated traits. -/// -/// Errors mostly originate from the underlying OS, but custom instances of -/// `Error` can be created with crafted error messages and a particular value of -/// [`ErrorKind`]. -/// -/// [`Read`]: ../io/trait.Read.html -/// [`Write`]: ../io/trait.Write.html -/// [`Seek`]: ../io/trait.Seek.html -/// [`ErrorKind`]: enum.ErrorKind.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Error { - repr: Repr, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.repr, f) - } -} - -enum Repr { - Os(i32), - Simple(ErrorKind), - Custom(Box), -} - -#[derive(Debug)] -struct Custom { - kind: ErrorKind, - error: Box, -} - -/// A list specifying general categories of I/O error. -/// -/// This list is intended to grow over time and it is not recommended to -/// exhaustively match against it. -/// -/// It is used with the [`io::Error`] type. -/// -/// [`io::Error`]: struct.Error.html -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -#[non_exhaustive] -pub enum ErrorKind { - /// An entity was not found, often a file. - #[stable(feature = "rust1", since = "1.0.0")] - NotFound, - /// The operation lacked the necessary privileges to complete. - #[stable(feature = "rust1", since = "1.0.0")] - PermissionDenied, - /// The connection was refused by the remote server. - #[stable(feature = "rust1", since = "1.0.0")] - ConnectionRefused, - /// The connection was reset by the remote server. - #[stable(feature = "rust1", since = "1.0.0")] - ConnectionReset, - /// The connection was aborted (terminated) by the remote server. - #[stable(feature = "rust1", since = "1.0.0")] - ConnectionAborted, - /// The network operation failed because it was not connected yet. - #[stable(feature = "rust1", since = "1.0.0")] - NotConnected, - /// A socket address could not be bound because the address is already in - /// use elsewhere. - #[stable(feature = "rust1", since = "1.0.0")] - AddrInUse, - /// A nonexistent interface was requested or the requested address was not - /// local. - #[stable(feature = "rust1", since = "1.0.0")] - AddrNotAvailable, - /// The operation failed because a pipe was closed. - #[stable(feature = "rust1", since = "1.0.0")] - BrokenPipe, - /// An entity already exists, often a file. - #[stable(feature = "rust1", since = "1.0.0")] - AlreadyExists, - /// The operation needs to block to complete, but the blocking operation was - /// requested to not occur. - #[stable(feature = "rust1", since = "1.0.0")] - WouldBlock, - /// A parameter was incorrect. - #[stable(feature = "rust1", since = "1.0.0")] - InvalidInput, - /// Data not valid for the operation were encountered. - /// - /// Unlike [`InvalidInput`], this typically means that the operation - /// parameters were valid, however the error was caused by malformed - /// input data. - /// - /// For example, a function that reads a file into a string will error with - /// `InvalidData` if the file's contents are not valid UTF-8. - /// - /// [`InvalidInput`]: #variant.InvalidInput - #[stable(feature = "io_invalid_data", since = "1.2.0")] - InvalidData, - /// The I/O operation's timeout expired, causing it to be canceled. - #[stable(feature = "rust1", since = "1.0.0")] - TimedOut, - /// An error returned when an operation could not be completed because a - /// call to [`write`] returned [`Ok(0)`]. - /// - /// This typically means that an operation could only succeed if it wrote a - /// particular number of bytes but only a smaller number of bytes could be - /// written. - /// - /// [`write`]: ../../std/io/trait.Write.html#tymethod.write - /// [`Ok(0)`]: ../../std/io/type.Result.html - #[stable(feature = "rust1", since = "1.0.0")] - WriteZero, - /// This operation was interrupted. - /// - /// Interrupted operations can typically be retried. - #[stable(feature = "rust1", since = "1.0.0")] - Interrupted, - /// Any I/O error not part of this list. - #[stable(feature = "rust1", since = "1.0.0")] - Other, - - /// An error returned when an operation could not be completed because an - /// "end of file" was reached prematurely. - /// - /// This typically means that an operation could only succeed if it read a - /// particular number of bytes but only a smaller number of bytes could be - /// read. - #[stable(feature = "read_exact", since = "1.6.0")] - UnexpectedEof, -} - -impl ErrorKind { - fn as_str(&self) -> &'static str { - match *self { - ErrorKind::NotFound => "entity not found", - ErrorKind::PermissionDenied => "permission denied", - ErrorKind::ConnectionRefused => "connection refused", - ErrorKind::ConnectionReset => "connection reset", - ErrorKind::ConnectionAborted => "connection aborted", - ErrorKind::NotConnected => "not connected", - ErrorKind::AddrInUse => "address in use", - ErrorKind::AddrNotAvailable => "address not available", - ErrorKind::BrokenPipe => "broken pipe", - ErrorKind::AlreadyExists => "entity already exists", - ErrorKind::WouldBlock => "operation would block", - ErrorKind::InvalidInput => "invalid input parameter", - ErrorKind::InvalidData => "invalid data", - ErrorKind::TimedOut => "timed out", - ErrorKind::WriteZero => "write zero", - ErrorKind::Interrupted => "operation interrupted", - ErrorKind::Other => "other os error", - ErrorKind::UnexpectedEof => "unexpected end of file", - } - } -} - -/// Intended for use for errors not exposed to the user, where allocating onto -/// the heap (for normal construction via Error::new) is too costly. -#[stable(feature = "io_error_from_errorkind", since = "1.14.0")] -impl From for Error { - #[inline] - fn from(kind: ErrorKind) -> Error { - Error { - repr: Repr::Simple(kind) - } - } -} - -impl Error { - /// Creates a new I/O error from a known kind of error as well as an - /// arbitrary error payload. - /// - /// This function is used to generically create I/O errors which do not - /// originate from the OS itself. The `error` argument is an arbitrary - /// payload which will be contained in this `Error`. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// // errors can be created from strings - /// let custom_error = Error::new(ErrorKind::Other, "oh no!"); - /// - /// // errors can also be created from other errors - /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(kind: ErrorKind, error: E) -> Error - where E: Into> - { - Self::_new(kind, error.into()) - } - - fn _new(kind: ErrorKind, error: Box) -> Error { - Error { - repr: Repr::Custom(Box::new(Custom { - kind, - error, - })) - } - } - - /// Returns an error representing the last OS error which occurred. - /// - /// This function reads the value of `errno` for the target platform (e.g. - /// `GetLastError` on Windows) and will return a corresponding instance of - /// `Error` for the error code. - /// - /// # Examples - /// - /// ``` - /// use std::io::Error; - /// - /// println!("last OS error: {:?}", Error::last_os_error()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn last_os_error() -> Error { - Error::from_raw_os_error(sys::os::errno() as i32) - } - - /// Creates a new instance of an `Error` from a particular OS error code. - /// - /// # Examples - /// - /// On Linux: - /// - /// ``` - /// # if cfg!(target_os = "linux") { - /// use std::io; - /// - /// let error = io::Error::from_raw_os_error(22); - /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput); - /// # } - /// ``` - /// - /// On Windows: - /// - /// ``` - /// # if cfg!(windows) { - /// use std::io; - /// - /// let error = io::Error::from_raw_os_error(10022); - /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput); - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_raw_os_error(code: i32) -> Error { - Error { repr: Repr::Os(code) } - } - - /// Returns the OS error that this error represents (if any). - /// - /// If this `Error` was constructed via `last_os_error` or - /// `from_raw_os_error`, then this function will return `Some`, otherwise - /// it will return `None`. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// fn print_os_error(err: &Error) { - /// if let Some(raw_os_err) = err.raw_os_error() { - /// println!("raw OS error: {:?}", raw_os_err); - /// } else { - /// println!("Not an OS error"); - /// } - /// } - /// - /// fn main() { - /// // Will print "raw OS error: ...". - /// print_os_error(&Error::last_os_error()); - /// // Will print "Not an OS error". - /// print_os_error(&Error::new(ErrorKind::Other, "oh no!")); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn raw_os_error(&self) -> Option { - match self.repr { - Repr::Os(i) => Some(i), - Repr::Custom(..) => None, - Repr::Simple(..) => None, - } - } - - /// Returns a reference to the inner error wrapped by this error (if any). - /// - /// If this `Error` was constructed via `new` then this function will - /// return `Some`, otherwise it will return `None`. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// fn print_error(err: &Error) { - /// if let Some(inner_err) = err.get_ref() { - /// println!("Inner error: {:?}", inner_err); - /// } else { - /// println!("No inner error"); - /// } - /// } - /// - /// fn main() { - /// // Will print "No inner error". - /// print_error(&Error::last_os_error()); - /// // Will print "Inner error: ...". - /// print_error(&Error::new(ErrorKind::Other, "oh no!")); - /// } - /// ``` - #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn get_ref(&self) -> Option<&(dyn error::Error+Send+Sync+'static)> { - match self.repr { - Repr::Os(..) => None, - Repr::Simple(..) => None, - Repr::Custom(ref c) => Some(&*c.error), - } - } - - /// Returns a mutable reference to the inner error wrapped by this error - /// (if any). - /// - /// If this `Error` was constructed via `new` then this function will - /// return `Some`, otherwise it will return `None`. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// use std::{error, fmt}; - /// use std::fmt::Display; - /// - /// #[derive(Debug)] - /// struct MyError { - /// v: String, - /// } - /// - /// impl MyError { - /// fn new() -> MyError { - /// MyError { - /// v: "oh no!".to_string() - /// } - /// } - /// - /// fn change_message(&mut self, new_message: &str) { - /// self.v = new_message.to_string(); - /// } - /// } - /// - /// impl error::Error for MyError { - /// fn description(&self) -> &str { &self.v } - /// } - /// - /// impl Display for MyError { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - /// write!(f, "MyError: {}", &self.v) - /// } - /// } - /// - /// fn change_error(mut err: Error) -> Error { - /// if let Some(inner_err) = err.get_mut() { - /// inner_err.downcast_mut::().unwrap().change_message("I've been changed!"); - /// } - /// err - /// } - /// - /// fn print_error(err: &Error) { - /// if let Some(inner_err) = err.get_ref() { - /// println!("Inner error: {}", inner_err); - /// } else { - /// println!("No inner error"); - /// } - /// } - /// - /// fn main() { - /// // Will print "No inner error". - /// print_error(&change_error(Error::last_os_error())); - /// // Will print "Inner error: ...". - /// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new()))); - /// } - /// ``` - #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error+Send+Sync+'static)> { - match self.repr { - Repr::Os(..) => None, - Repr::Simple(..) => None, - Repr::Custom(ref mut c) => Some(&mut *c.error), - } - } - - /// Consumes the `Error`, returning its inner error (if any). - /// - /// If this `Error` was constructed via `new` then this function will - /// return `Some`, otherwise it will return `None`. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// fn print_error(err: Error) { - /// if let Some(inner_err) = err.into_inner() { - /// println!("Inner error: {}", inner_err); - /// } else { - /// println!("No inner error"); - /// } - /// } - /// - /// fn main() { - /// // Will print "No inner error". - /// print_error(Error::last_os_error()); - /// // Will print "Inner error: ...". - /// print_error(Error::new(ErrorKind::Other, "oh no!")); - /// } - /// ``` - #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn into_inner(self) -> Option> { - match self.repr { - Repr::Os(..) => None, - Repr::Simple(..) => None, - Repr::Custom(c) => Some(c.error) - } - } - - /// Returns the corresponding `ErrorKind` for this error. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// fn print_error(err: Error) { - /// println!("{:?}", err.kind()); - /// } - /// - /// fn main() { - /// // Will print "No inner error". - /// print_error(Error::last_os_error()); - /// // Will print "Inner error: ...". - /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn kind(&self) -> ErrorKind { - match self.repr { - Repr::Os(code) => sys::decode_error_kind(code), - Repr::Custom(ref c) => c.kind, - Repr::Simple(kind) => kind, - } - } -} - -impl fmt::Debug for Repr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - Repr::Os(code) => - fmt.debug_struct("Os") - .field("code", &code) - .field("kind", &sys::decode_error_kind(code)) - .field("message", &sys::os::error_string(code)).finish(), - Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt), - Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self.repr { - Repr::Os(code) => { - let detail = sys::os::error_string(code); - write!(fmt, "{} (os error {})", detail, code) - } - Repr::Custom(ref c) => c.error.fmt(fmt), - Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for Error { - fn description(&self) -> &str { - match self.repr { - Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(), - Repr::Custom(ref c) => c.error.description(), - } - } - - fn cause(&self) -> Option<&dyn error::Error> { - match self.repr { - Repr::Os(..) => None, - Repr::Simple(..) => None, - Repr::Custom(ref c) => c.error.cause(), - } - } -} - -fn _assert_error_is_sync_send() { - fn _is_sync_send() {} - _is_sync_send::(); -} - -#[cfg(test)] -mod test { - use super::{Error, ErrorKind, Repr, Custom}; - use error; - use fmt; - use sys::os::error_string; - use sys::decode_error_kind; - - #[test] - fn test_debug_error() { - let code = 6; - let msg = error_string(code); - let kind = decode_error_kind(code); - let err = Error { - repr: Repr::Custom(box Custom { - kind: ErrorKind::InvalidInput, - error: box Error { - repr: super::Repr::Os(code) - }, - }) - }; - let expected = format!( - "Custom {{ \ - kind: InvalidInput, \ - error: Os {{ \ - code: {:?}, \ - kind: {:?}, \ - message: {:?} \ - }} \ - }}", - code, kind, msg - ); - assert_eq!(format!("{:?}", err), expected); - } - - #[test] - fn test_downcasting() { - #[derive(Debug)] - struct TestError; - - impl fmt::Display for TestError { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { - Ok(()) - } - } - - impl error::Error for TestError { - fn description(&self) -> &str { - "asdf" - } - } - - // we have to call all of these UFCS style right now since method - // resolution won't implicitly drop the Send+Sync bounds - let mut err = Error::new(ErrorKind::Other, TestError); - assert!(err.get_ref().unwrap().is::()); - assert_eq!("asdf", err.get_ref().unwrap().description()); - assert!(err.get_mut().unwrap().is::()); - let extracted = err.into_inner().unwrap(); - extracted.downcast::().unwrap(); - } -} diff --git a/ctr-std/src/io/impls.rs b/ctr-std/src/io/impls.rs deleted file mode 100644 index fe1179a..0000000 --- a/ctr-std/src/io/impls.rs +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cmp; -use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind}; -use fmt; -use mem; - -// ============================================================================= -// Forwarding implementations - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, R: Read + ?Sized> Read for &'a mut R { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (**self).read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - (**self).initializer() - } - - #[inline] - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - (**self).read_to_end(buf) - } - - #[inline] - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - (**self).read_to_string(buf) - } - - #[inline] - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - (**self).read_exact(buf) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, W: Write + ?Sized> Write for &'a mut W { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } - - #[inline] - fn flush(&mut self) -> io::Result<()> { (**self).flush() } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - (**self).write_all(buf) - } - - #[inline] - fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { - (**self).write_fmt(fmt) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, S: Seek + ?Sized> Seek for &'a mut S { - #[inline] - fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B { - #[inline] - fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } - - #[inline] - fn consume(&mut self, amt: usize) { (**self).consume(amt) } - - #[inline] - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { - (**self).read_until(byte, buf) - } - - #[inline] - fn read_line(&mut self, buf: &mut String) -> io::Result { - (**self).read_line(buf) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for Box { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (**self).read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - (**self).initializer() - } - - #[inline] - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - (**self).read_to_end(buf) - } - - #[inline] - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - (**self).read_to_string(buf) - } - - #[inline] - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - (**self).read_exact(buf) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Box { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } - - #[inline] - fn flush(&mut self) -> io::Result<()> { (**self).flush() } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - (**self).write_all(buf) - } - - #[inline] - fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { - (**self).write_fmt(fmt) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Seek for Box { - #[inline] - fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl BufRead for Box { - #[inline] - fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } - - #[inline] - fn consume(&mut self, amt: usize) { (**self).consume(amt) } - - #[inline] - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { - (**self).read_until(byte, buf) - } - - #[inline] - fn read_line(&mut self, buf: &mut String) -> io::Result { - (**self).read_line(buf) - } -} - -// ============================================================================= -// In-memory buffer implementations - -/// Read is implemented for `&[u8]` by copying from the slice. -/// -/// Note that reading updates the slice to point to the yet unread part. -/// The slice will be empty when EOF is reached. -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Read for &'a [u8] { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let amt = cmp::min(buf.len(), self.len()); - let (a, b) = self.split_at(amt); - - // First check if the amount of bytes we want to read is small: - // `copy_from_slice` will generally expand to a call to `memcpy`, and - // for a single byte the overhead is significant. - if amt == 1 { - buf[0] = a[0]; - } else { - buf[..amt].copy_from_slice(a); - } - - *self = b; - Ok(amt) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } - - #[inline] - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - if buf.len() > self.len() { - return Err(Error::new(ErrorKind::UnexpectedEof, - "failed to fill whole buffer")); - } - let (a, b) = self.split_at(buf.len()); - - // First check if the amount of bytes we want to read is small: - // `copy_from_slice` will generally expand to a call to `memcpy`, and - // for a single byte the overhead is significant. - if buf.len() == 1 { - buf[0] = a[0]; - } else { - buf.copy_from_slice(a); - } - - *self = b; - Ok(()) - } - - #[inline] - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - buf.extend_from_slice(*self); - let len = self.len(); - *self = &self[len..]; - Ok(len) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> BufRead for &'a [u8] { - #[inline] - fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) } - - #[inline] - fn consume(&mut self, amt: usize) { *self = &self[amt..]; } -} - -/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting -/// its data. -/// -/// Note that writing updates the slice to point to the yet unwritten part. -/// The slice will be empty when it has been completely overwritten. -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Write for &'a mut [u8] { - #[inline] - fn write(&mut self, data: &[u8]) -> io::Result { - let amt = cmp::min(data.len(), self.len()); - let (a, b) = mem::replace(self, &mut []).split_at_mut(amt); - a.copy_from_slice(&data[..amt]); - *self = b; - Ok(amt) - } - - #[inline] - fn write_all(&mut self, data: &[u8]) -> io::Result<()> { - if self.write(data)? == data.len() { - Ok(()) - } else { - Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer")) - } - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -/// Write is implemented for `Vec` by appending to the vector. -/// The vector will grow as needed. -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Vec { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.extend_from_slice(buf); - Ok(buf.len()) - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.extend_from_slice(buf); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -#[cfg(test)] -mod tests { - use io::prelude::*; - use test; - - #[bench] - fn bench_read_slice(b: &mut test::Bencher) { - let buf = [5; 1024]; - let mut dst = [0; 128]; - - b.iter(|| { - let mut rd = &buf[..]; - for _ in 0..8 { - let _ = rd.read(&mut dst); - test::black_box(&dst); - } - }) - } - - #[bench] - fn bench_write_slice(b: &mut test::Bencher) { - let mut buf = [0; 1024]; - let src = [5; 128]; - - b.iter(|| { - let mut wr = &mut buf[..]; - for _ in 0..8 { - let _ = wr.write_all(&src); - test::black_box(&wr); - } - }) - } - - #[bench] - fn bench_read_vec(b: &mut test::Bencher) { - let buf = vec![5; 1024]; - let mut dst = [0; 128]; - - b.iter(|| { - let mut rd = &buf[..]; - for _ in 0..8 { - let _ = rd.read(&mut dst); - test::black_box(&dst); - } - }) - } - - #[bench] - fn bench_write_vec(b: &mut test::Bencher) { - let mut buf = Vec::with_capacity(1024); - let src = [5; 128]; - - b.iter(|| { - let mut wr = &mut buf[..]; - for _ in 0..8 { - let _ = wr.write_all(&src); - test::black_box(&wr); - } - }) - } -} diff --git a/ctr-std/src/io/lazy.rs b/ctr-std/src/io/lazy.rs deleted file mode 100644 index 4fb367f..0000000 --- a/ctr-std/src/io/lazy.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::Cell; -use ptr; -use sync::Arc; -use sys_common; -use sys_common::mutex::Mutex; - -pub struct Lazy { - // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly! - lock: Mutex, - ptr: Cell<*mut Arc>, - init: fn() -> Arc, -} - -#[inline] -const fn done() -> *mut Arc { 1_usize as *mut _ } - -unsafe impl Sync for Lazy {} - -impl Lazy { - /// Safety: `init` must not call `get` on the variable that is being - /// initialized. - pub const unsafe fn new(init: fn() -> Arc) -> Lazy { - Lazy { - lock: Mutex::new(), - ptr: Cell::new(ptr::null_mut()), - init, - } - } - - pub fn get(&'static self) -> Option> { - unsafe { - let _guard = self.lock.lock(); - let ptr = self.ptr.get(); - if ptr.is_null() { - Some(self.init()) - } else if ptr == done() { - None - } else { - Some((*ptr).clone()) - } - } - } - - // Must only be called with `lock` held - unsafe fn init(&'static self) -> Arc { - // If we successfully register an at exit handler, then we cache the - // `Arc` allocation in our own internal box (it will get deallocated by - // the at exit handler). Otherwise we just return the freshly allocated - // `Arc`. - let registered = sys_common::at_exit(move || { - let ptr = { - let _guard = self.lock.lock(); - self.ptr.replace(done()) - }; - drop(Box::from_raw(ptr)) - }); - // This could reentrantly call `init` again, which is a problem - // because our `lock` allows reentrancy! - // That's why `new` is unsafe and requires the caller to ensure no reentrancy happens. - let ret = (self.init)(); - if registered.is_ok() { - self.ptr.set(Box::into_raw(Box::new(ret.clone()))); - } - ret - } -} diff --git a/ctr-std/src/io/mod.rs b/ctr-std/src/io/mod.rs deleted file mode 100644 index b83f3fb..0000000 --- a/ctr-std/src/io/mod.rs +++ /dev/null @@ -1,2266 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Traits, helpers, and type definitions for core I/O functionality. -//! -//! The `std::io` module contains a number of common things you'll need -//! when doing input and output. The most core part of this module is -//! the [`Read`] and [`Write`] traits, which provide the -//! most general interface for reading and writing input and output. -//! -//! # Read and Write -//! -//! Because they are traits, [`Read`] and [`Write`] are implemented by a number -//! of other types, and you can implement them for your types too. As such, -//! you'll see a few different types of I/O throughout the documentation in -//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For -//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on -//! [`File`]s: -//! -//! ```no_run -//! use std::io; -//! use std::io::prelude::*; -//! use std::fs::File; -//! -//! fn main() -> io::Result<()> { -//! let mut f = File::open("foo.txt")?; -//! let mut buffer = [0; 10]; -//! -//! // read up to 10 bytes -//! f.read(&mut buffer)?; -//! -//! println!("The bytes: {:?}", buffer); -//! Ok(()) -//! } -//! ``` -//! -//! [`Read`] and [`Write`] are so important, implementors of the two traits have a -//! nickname: readers and writers. So you'll sometimes see 'a reader' instead -//! of 'a type that implements the [`Read`] trait'. Much easier! -//! -//! ## Seek and BufRead -//! -//! Beyond that, there are two important traits that are provided: [`Seek`] -//! and [`BufRead`]. Both of these build on top of a reader to control -//! how the reading happens. [`Seek`] lets you control where the next byte is -//! coming from: -//! -//! ```no_run -//! use std::io; -//! use std::io::prelude::*; -//! use std::io::SeekFrom; -//! use std::fs::File; -//! -//! fn main() -> io::Result<()> { -//! let mut f = File::open("foo.txt")?; -//! let mut buffer = [0; 10]; -//! -//! // skip to the last 10 bytes of the file -//! f.seek(SeekFrom::End(-10))?; -//! -//! // read up to 10 bytes -//! f.read(&mut buffer)?; -//! -//! println!("The bytes: {:?}", buffer); -//! Ok(()) -//! } -//! ``` -//! -//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but -//! to show it off, we'll need to talk about buffers in general. Keep reading! -//! -//! ## BufReader and BufWriter -//! -//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be -//! making near-constant calls to the operating system. To help with this, -//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap -//! readers and writers. The wrapper uses a buffer, reducing the number of -//! calls and providing nicer methods for accessing exactly what you want. -//! -//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra -//! methods to any reader: -//! -//! ```no_run -//! use std::io; -//! use std::io::prelude::*; -//! use std::io::BufReader; -//! use std::fs::File; -//! -//! fn main() -> io::Result<()> { -//! let f = File::open("foo.txt")?; -//! let mut reader = BufReader::new(f); -//! let mut buffer = String::new(); -//! -//! // read a line into buffer -//! reader.read_line(&mut buffer)?; -//! -//! println!("{}", buffer); -//! Ok(()) -//! } -//! ``` -//! -//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call -//! to [`write`][`Write::write`]: -//! -//! ```no_run -//! use std::io; -//! use std::io::prelude::*; -//! use std::io::BufWriter; -//! use std::fs::File; -//! -//! fn main() -> io::Result<()> { -//! let f = File::create("foo.txt")?; -//! { -//! let mut writer = BufWriter::new(f); -//! -//! // write a byte to the buffer -//! writer.write(&[42])?; -//! -//! } // the buffer is flushed once writer goes out of scope -//! -//! Ok(()) -//! } -//! ``` -//! -//! ## Standard input and output -//! -//! A very common source of input is standard input: -//! -//! ```no_run -//! use std::io; -//! -//! fn main() -> io::Result<()> { -//! let mut input = String::new(); -//! -//! io::stdin().read_line(&mut input)?; -//! -//! println!("You typed: {}", input.trim()); -//! Ok(()) -//! } -//! ``` -//! -//! Note that you cannot use the [`?` operator] in functions that do not return -//! a [`Result`][`Result`]. Instead, you can call [`.unwrap()`] -//! or `match` on the return value to catch any possible errors: -//! -//! ```no_run -//! use std::io; -//! -//! let mut input = String::new(); -//! -//! io::stdin().read_line(&mut input).unwrap(); -//! ``` -//! -//! And a very common source of output is standard output: -//! -//! ```no_run -//! use std::io; -//! use std::io::prelude::*; -//! -//! fn main() -> io::Result<()> { -//! io::stdout().write(&[42])?; -//! Ok(()) -//! } -//! ``` -//! -//! Of course, using [`io::stdout`] directly is less common than something like -//! [`println!`]. -//! -//! ## Iterator types -//! -//! A large number of the structures provided by `std::io` are for various -//! ways of iterating over I/O. For example, [`Lines`] is used to split over -//! lines: -//! -//! ```no_run -//! use std::io; -//! use std::io::prelude::*; -//! use std::io::BufReader; -//! use std::fs::File; -//! -//! fn main() -> io::Result<()> { -//! let f = File::open("foo.txt")?; -//! let reader = BufReader::new(f); -//! -//! for line in reader.lines() { -//! println!("{}", line?); -//! } -//! Ok(()) -//! } -//! ``` -//! -//! ## Functions -//! -//! There are a number of [functions][functions-list] that offer access to various -//! features. For example, we can use three of these functions to copy everything -//! from standard input to standard output: -//! -//! ```no_run -//! use std::io; -//! -//! fn main() -> io::Result<()> { -//! io::copy(&mut io::stdin(), &mut io::stdout())?; -//! Ok(()) -//! } -//! ``` -//! -//! [functions-list]: #functions-1 -//! -//! ## io::Result -//! -//! Last, but certainly not least, is [`io::Result`]. This type is used -//! as the return type of many `std::io` functions that can cause an error, and -//! can be returned from your own functions as well. Many of the examples in this -//! module use the [`?` operator]: -//! -//! ``` -//! use std::io; -//! -//! fn read_input() -> io::Result<()> { -//! let mut input = String::new(); -//! -//! io::stdin().read_line(&mut input)?; -//! -//! println!("You typed: {}", input.trim()); -//! -//! Ok(()) -//! } -//! ``` -//! -//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very -//! common type for functions which don't have a 'real' return value, but do want to -//! return errors if they happen. In this case, the only purpose of this function is -//! to read the line and print it, so we use `()`. -//! -//! ## Platform-specific behavior -//! -//! Many I/O functions throughout the standard library are documented to indicate -//! what various library or syscalls they are delegated to. This is done to help -//! applications both understand what's happening under the hood as well as investigate -//! any possibly unclear semantics. Note, however, that this is informative, not a binding -//! contract. The implementation of many of these functions are subject to change over -//! time and may call fewer or more syscalls/library functions. -//! -//! [`Read`]: trait.Read.html -//! [`Write`]: trait.Write.html -//! [`Seek`]: trait.Seek.html -//! [`BufRead`]: trait.BufRead.html -//! [`File`]: ../fs/struct.File.html -//! [`TcpStream`]: ../net/struct.TcpStream.html -//! [`Vec`]: ../vec/struct.Vec.html -//! [`BufReader`]: struct.BufReader.html -//! [`BufWriter`]: struct.BufWriter.html -//! [`Write::write`]: trait.Write.html#tymethod.write -//! [`io::stdout`]: fn.stdout.html -//! [`println!`]: ../macro.println.html -//! [`Lines`]: struct.Lines.html -//! [`io::Result`]: type.Result.html -//! [`?` operator]: ../../book/first-edition/syntax-index.html -//! [`Read::read`]: trait.Read.html#tymethod.read -//! [`Result`]: ../result/enum.Result.html -//! [`.unwrap()`]: ../result/enum.Result.html#method.unwrap - -#![stable(feature = "rust1", since = "1.0.0")] - -use cmp; -use fmt; -use str; -use memchr; -use ptr; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::buffered::{BufReader, BufWriter, LineWriter}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::buffered::IntoInnerError; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::cursor::Cursor; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::error::{Result, Error, ErrorKind}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::stdio::{stdin, stdout, stderr, Stdin, Stdout, Stderr}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::stdio::{StdoutLock, StderrLock, StdinLock}; -#[unstable(feature = "print_internals", issue = "0")] -pub use self::stdio::{_print, _eprint}; -#[unstable(feature = "libstd_io_internals", issue = "42788")] -#[doc(no_inline, hidden)] -pub use self::stdio::{set_panic, set_print}; - -pub mod prelude; -mod buffered; -mod cursor; -mod error; -mod impls; -mod lazy; -mod util; -mod stdio; - -const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; - -struct Guard<'a> { buf: &'a mut Vec, len: usize } - -impl<'a> Drop for Guard<'a> { - fn drop(&mut self) { - unsafe { self.buf.set_len(self.len); } - } -} - -// A few methods below (read_to_string, read_line) will append data into a -// `String` buffer, but we need to be pretty careful when doing this. The -// implementation will just call `.as_mut_vec()` and then delegate to a -// byte-oriented reading method, but we must ensure that when returning we never -// leave `buf` in a state such that it contains invalid UTF-8 in its bounds. -// -// To this end, we use an RAII guard (to protect against panics) which updates -// the length of the string when it is dropped. This guard initially truncates -// the string to the prior length and only after we've validated that the -// new contents are valid UTF-8 do we allow it to set a longer length. -// -// The unsafety in this function is twofold: -// -// 1. We're looking at the raw bytes of `buf`, so we take on the burden of UTF-8 -// checks. -// 2. We're passing a raw buffer to the function `f`, and it is expected that -// the function only *appends* bytes to the buffer. We'll get undefined -// behavior if existing bytes are overwritten to have non-UTF-8 data. -fn append_to_string(buf: &mut String, f: F) -> Result - where F: FnOnce(&mut Vec) -> Result -{ - unsafe { - let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() }; - let ret = f(g.buf); - if str::from_utf8(&g.buf[g.len..]).is_err() { - ret.and_then(|_| { - Err(Error::new(ErrorKind::InvalidData, - "stream did not contain valid UTF-8")) - }) - } else { - g.len = g.buf.len(); - ret - } - } -} - -// This uses an adaptive system to extend the vector when it fills. We want to -// avoid paying to allocate and zero a huge chunk of memory if the reader only -// has 4 bytes while still making large reads if the reader does have a ton -// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every -// time is 4,500 times (!) slower than a default reservation size of 32 if the -// reader has a very small amount of data to return. -// -// Because we're extending the buffer with uninitialized data for trusted -// readers, we need to make sure to truncate that if any of this panics. -fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { - read_to_end_with_reservation(r, buf, 32) -} - -fn read_to_end_with_reservation(r: &mut R, - buf: &mut Vec, - reservation_size: usize) -> Result -{ - let start_len = buf.len(); - let mut g = Guard { len: buf.len(), buf: buf }; - let ret; - loop { - if g.len == g.buf.len() { - unsafe { - g.buf.reserve(reservation_size); - let capacity = g.buf.capacity(); - g.buf.set_len(capacity); - r.initializer().initialize(&mut g.buf[g.len..]); - } - } - - match r.read(&mut g.buf[g.len..]) { - Ok(0) => { - ret = Ok(g.len - start_len); - break; - } - Ok(n) => g.len += n, - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => { - ret = Err(e); - break; - } - } - } - - ret -} - -/// The `Read` trait allows for reading bytes from a source. -/// -/// Implementors of the `Read` trait are called 'readers'. -/// -/// Readers are defined by one required method, [`read()`]. Each call to [`read()`] -/// will attempt to pull bytes from this source into a provided buffer. A -/// number of other methods are implemented in terms of [`read()`], giving -/// implementors a number of ways to read bytes while only needing to implement -/// a single method. -/// -/// Readers are intended to be composable with one another. Many implementors -/// throughout [`std::io`] take and provide types which implement the `Read` -/// trait. -/// -/// Please note that each call to [`read()`] may involve a system call, and -/// therefore, using something that implements [`BufRead`], such as -/// [`BufReader`], will be more efficient. -/// -/// # Examples -/// -/// [`File`]s implement `Read`: -/// -/// ```no_run -/// use std::io; -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// fn main() -> io::Result<()> { -/// let mut f = File::open("foo.txt")?; -/// let mut buffer = [0; 10]; -/// -/// // read up to 10 bytes -/// f.read(&mut buffer)?; -/// -/// let mut buffer = vec![0; 10]; -/// // read the whole file -/// f.read_to_end(&mut buffer)?; -/// -/// // read into a String, so that you don't need to do the conversion. -/// let mut buffer = String::new(); -/// f.read_to_string(&mut buffer)?; -/// -/// // and more! See the other methods for more details. -/// Ok(()) -/// } -/// ``` -/// -/// Read from [`&str`] because [`&[u8]`][slice] implements `Read`: -/// -/// ```no_run -/// # use std::io; -/// use std::io::prelude::*; -/// -/// fn main() -> io::Result<()> { -/// let mut b = "This string will be read".as_bytes(); -/// let mut buffer = [0; 10]; -/// -/// // read up to 10 bytes -/// b.read(&mut buffer)?; -/// -/// // etc... it works exactly as a File does! -/// Ok(()) -/// } -/// ``` -/// -/// [`read()`]: trait.Read.html#tymethod.read -/// [`std::io`]: ../../std/io/index.html -/// [`File`]: ../fs/struct.File.html -/// [`BufRead`]: trait.BufRead.html -/// [`BufReader`]: struct.BufReader.html -/// [`&str`]: ../../std/primitive.str.html -/// [slice]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(spotlight)] -pub trait Read { - /// Pull some bytes from this source into the specified buffer, returning - /// how many bytes were read. - /// - /// This function does not provide any guarantees about whether it blocks - /// waiting for data, but if an object needs to block for a read but cannot - /// it will typically signal this via an [`Err`] return value. - /// - /// If the return value of this method is [`Ok(n)`], then it must be - /// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates - /// that the buffer `buf` has been filled in with `n` bytes of data from this - /// source. If `n` is `0`, then it can indicate one of two scenarios: - /// - /// 1. This reader has reached its "end of file" and will likely no longer - /// be able to produce bytes. Note that this does not mean that the - /// reader will *always* no longer be able to produce bytes. - /// 2. The buffer specified was 0 bytes in length. - /// - /// No guarantees are provided about the contents of `buf` when this - /// function is called, implementations cannot rely on any property of the - /// contents of `buf` being true. It is recommended that implementations - /// only write data to `buf` instead of reading its contents. - /// - /// # Errors - /// - /// If this function encounters any form of I/O or other error, an error - /// variant will be returned. If an error is returned then it must be - /// guaranteed that no bytes were read. - /// - /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read - /// operation should be retried if there is nothing else to do. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok - /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted - /// [`File`]: ../fs/struct.File.html - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = [0; 10]; - /// - /// // read up to 10 bytes - /// f.read(&mut buffer[..])?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn read(&mut self, buf: &mut [u8]) -> Result; - - /// Determines if this `Read`er can work with buffers of uninitialized - /// memory. - /// - /// The default implementation returns an initializer which will zero - /// buffers. - /// - /// If a `Read`er guarantees that it can work properly with uninitialized - /// memory, it should call [`Initializer::nop()`]. See the documentation for - /// [`Initializer`] for details. - /// - /// The behavior of this method must be independent of the state of the - /// `Read`er - the method only takes `&self` so that it can be used through - /// trait objects. - /// - /// # Safety - /// - /// This method is unsafe because a `Read`er could otherwise return a - /// non-zeroing `Initializer` from another `Read` type without an `unsafe` - /// block. - /// - /// [`Initializer::nop()`]: ../../std/io/struct.Initializer.html#method.nop - /// [`Initializer`]: ../../std/io/struct.Initializer.html - #[unstable(feature = "read_initializer", issue = "42788")] - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::zeroing() - } - - /// Read all bytes until EOF in this source, placing them into `buf`. - /// - /// All bytes read from this source will be appended to the specified buffer - /// `buf`. This function will continuously call [`read()`] to append more data to - /// `buf` until [`read()`] returns either [`Ok(0)`] or an error of - /// non-[`ErrorKind::Interrupted`] kind. - /// - /// If successful, this function will return the total number of bytes read. - /// - /// # Errors - /// - /// If this function encounters an error of the kind - /// [`ErrorKind::Interrupted`] then the error is ignored and the operation - /// will continue. - /// - /// If any other read error is encountered then this function immediately - /// returns. Any bytes which have already been read will be appended to - /// `buf`. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`read()`]: trait.Read.html#tymethod.read - /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok - /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted - /// [`File`]: ../fs/struct.File.html - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = Vec::new(); - /// - /// // read the whole file - /// f.read_to_end(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - /// - /// (See also the [`std::fs::read`] convenience function for reading from a - /// file.) - /// - /// [`std::fs::read`]: ../fs/fn.read.html - #[stable(feature = "rust1", since = "1.0.0")] - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - read_to_end(self, buf) - } - - /// Read all bytes until EOF in this source, appending them to `buf`. - /// - /// If successful, this function returns the number of bytes which were read - /// and appended to `buf`. - /// - /// # Errors - /// - /// If the data in this stream is *not* valid UTF-8 then an error is - /// returned and `buf` is unchanged. - /// - /// See [`read_to_end`][readtoend] for other error semantics. - /// - /// [readtoend]: #method.read_to_end - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = String::new(); - /// - /// f.read_to_string(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - /// - /// (See also the [`std::fs::read_to_string`] convenience function for - /// reading from a file.) - /// - /// [`std::fs::read_to_string`]: ../fs/fn.read_to_string.html - #[stable(feature = "rust1", since = "1.0.0")] - fn read_to_string(&mut self, buf: &mut String) -> Result { - // Note that we do *not* call `.read_to_end()` here. We are passing - // `&mut Vec` (the raw contents of `buf`) into the `read_to_end` - // method to fill it up. An arbitrary implementation could overwrite the - // entire contents of the vector, not just append to it (which is what - // we are expecting). - // - // To prevent extraneously checking the UTF-8-ness of the entire buffer - // we pass it to our hardcoded `read_to_end` implementation which we - // know is guaranteed to only read data into the end of the buffer. - append_to_string(buf, |b| read_to_end(self, b)) - } - - /// Read the exact number of bytes required to fill `buf`. - /// - /// This function reads as many bytes as necessary to completely fill the - /// specified buffer `buf`. - /// - /// No guarantees are provided about the contents of `buf` when this - /// function is called, implementations cannot rely on any property of the - /// contents of `buf` being true. It is recommended that implementations - /// only write data to `buf` instead of reading its contents. - /// - /// # Errors - /// - /// If this function encounters an error of the kind - /// [`ErrorKind::Interrupted`] then the error is ignored and the operation - /// will continue. - /// - /// If this function encounters an "end of file" before completely filling - /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. - /// The contents of `buf` are unspecified in this case. - /// - /// If any other read error is encountered then this function immediately - /// returns. The contents of `buf` are unspecified in this case. - /// - /// If this function returns an error, it is unspecified how many bytes it - /// has read, but it will never read more than would be necessary to - /// completely fill the buffer. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`File`]: ../fs/struct.File.html - /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted - /// [`ErrorKind::UnexpectedEof`]: ../../std/io/enum.ErrorKind.html#variant.UnexpectedEof - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = [0; 10]; - /// - /// // read exactly 10 bytes - /// f.read_exact(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "read_exact", since = "1.6.0")] - fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> { - while !buf.is_empty() { - match self.read(buf) { - Ok(0) => break, - Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; } - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - if !buf.is_empty() { - Err(Error::new(ErrorKind::UnexpectedEof, - "failed to fill whole buffer")) - } else { - Ok(()) - } - } - - /// Creates a "by reference" adaptor for this instance of `Read`. - /// - /// The returned adaptor also implements `Read` and will simply borrow this - /// current reader. - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ```no_run - /// use std::io; - /// use std::io::Read; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = Vec::new(); - /// let mut other_buffer = Vec::new(); - /// - /// { - /// let reference = f.by_ref(); - /// - /// // read at most 5 bytes - /// reference.take(5).read_to_end(&mut buffer)?; - /// - /// } // drop our &mut reference so we can use f again - /// - /// // original file still usable, read the rest - /// f.read_to_end(&mut other_buffer)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn by_ref(&mut self) -> &mut Self where Self: Sized { self } - - /// Transforms this `Read` instance to an [`Iterator`] over its bytes. - /// - /// The returned type implements [`Iterator`] where the `Item` is - /// [`Result`]`<`[`u8`]`, `[`io::Error`]`>`. - /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`] - /// otherwise. EOF is mapped to returning [`None`] from this iterator. - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// [`Iterator`]: ../../std/iter/trait.Iterator.html - /// [`Result`]: ../../std/result/enum.Result.html - /// [`io::Error`]: ../../std/io/struct.Error.html - /// [`u8`]: ../../std/primitive.u8.html - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// - /// for byte in f.bytes() { - /// println!("{}", byte.unwrap()); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn bytes(self) -> Bytes where Self: Sized { - Bytes { inner: self } - } - - /// Creates an adaptor which will chain this stream with another. - /// - /// The returned `Read` instance will first read all bytes from this object - /// until EOF is encountered. Afterwards the output is equivalent to the - /// output of `next`. - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f1 = File::open("foo.txt")?; - /// let mut f2 = File::open("bar.txt")?; - /// - /// let mut handle = f1.chain(f2); - /// let mut buffer = String::new(); - /// - /// // read the value into a String. We could use any Read method here, - /// // this is just one example. - /// handle.read_to_string(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn chain(self, next: R) -> Chain where Self: Sized { - Chain { first: self, second: next, done_first: false } - } - - /// Creates an adaptor which will read at most `limit` bytes from it. - /// - /// This function returns a new instance of `Read` which will read at most - /// `limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any - /// read errors will not count towards the number of bytes read and future - /// calls to [`read()`] may succeed. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`File`]: ../fs/struct.File.html - /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok - /// [`read()`]: trait.Read.html#tymethod.read - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = [0; 5]; - /// - /// // read at most five bytes - /// let mut handle = f.take(5); - /// - /// handle.read(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn take(self, limit: u64) -> Take where Self: Sized { - Take { inner: self, limit: limit } - } -} - -/// A type used to conditionally initialize buffers passed to `Read` methods. -#[unstable(feature = "read_initializer", issue = "42788")] -#[derive(Debug)] -pub struct Initializer(bool); - -impl Initializer { - /// Returns a new `Initializer` which will zero out buffers. - #[unstable(feature = "read_initializer", issue = "42788")] - #[inline] - pub fn zeroing() -> Initializer { - Initializer(true) - } - - /// Returns a new `Initializer` which will not zero out buffers. - /// - /// # Safety - /// - /// This may only be called by `Read`ers which guarantee that they will not - /// read from buffers passed to `Read` methods, and that the return value of - /// the method accurately reflects the number of bytes that have been - /// written to the head of the buffer. - #[unstable(feature = "read_initializer", issue = "42788")] - #[inline] - pub unsafe fn nop() -> Initializer { - Initializer(false) - } - - /// Indicates if a buffer should be initialized. - #[unstable(feature = "read_initializer", issue = "42788")] - #[inline] - pub fn should_initialize(&self) -> bool { - self.0 - } - - /// Initializes a buffer if necessary. - #[unstable(feature = "read_initializer", issue = "42788")] - #[inline] - pub fn initialize(&self, buf: &mut [u8]) { - if self.should_initialize() { - unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) } - } - } -} - -/// A trait for objects which are byte-oriented sinks. -/// -/// Implementors of the `Write` trait are sometimes called 'writers'. -/// -/// Writers are defined by two required methods, [`write`] and [`flush`]: -/// -/// * The [`write`] method will attempt to write some data into the object, -/// returning how many bytes were successfully written. -/// -/// * The [`flush`] method is useful for adaptors and explicit buffers -/// themselves for ensuring that all buffered data has been pushed out to the -/// 'true sink'. -/// -/// Writers are intended to be composable with one another. Many implementors -/// throughout [`std::io`] take and provide types which implement the `Write` -/// trait. -/// -/// [`write`]: #tymethod.write -/// [`flush`]: #tymethod.flush -/// [`std::io`]: index.html -/// -/// # Examples -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// fn main() -> std::io::Result<()> { -/// let mut buffer = File::create("foo.txt")?; -/// -/// buffer.write(b"some bytes")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(spotlight)] -pub trait Write { - /// Write a buffer into this object, returning how many bytes were written. - /// - /// This function will attempt to write the entire contents of `buf`, but - /// the entire write may not succeed, or the write may also generate an - /// error. A call to `write` represents *at most one* attempt to write to - /// any wrapped object. - /// - /// Calls to `write` are not guaranteed to block waiting for data to be - /// written, and a write which would otherwise block can be indicated through - /// an [`Err`] variant. - /// - /// If the return value is [`Ok(n)`] then it must be guaranteed that - /// `0 <= n <= buf.len()`. A return value of `0` typically means that the - /// underlying object is no longer able to accept bytes and will likely not - /// be able to in the future as well, or that the buffer provided is empty. - /// - /// # Errors - /// - /// Each call to `write` may generate an I/O error indicating that the - /// operation could not be completed. If an error is returned then no bytes - /// in the buffer were written to this writer. - /// - /// It is **not** considered an error if the entire buffer could not be - /// written to this writer. - /// - /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the - /// write operation should be retried if there is nothing else to do. - /// - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok - /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// // Writes some prefix of the byte string, not necessarily all of it. - /// buffer.write(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn write(&mut self, buf: &[u8]) -> Result; - - /// Flush this output stream, ensuring that all intermediately buffered - /// contents reach their destination. - /// - /// # Errors - /// - /// It is considered an error if not all bytes could be written due to - /// I/O errors or EOF being reached. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::io::BufWriter; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = BufWriter::new(File::create("foo.txt")?); - /// - /// buffer.write(b"some bytes")?; - /// buffer.flush()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn flush(&mut self) -> Result<()>; - - /// Attempts to write an entire buffer into this write. - /// - /// This method will continuously call [`write`] until there is no more data - /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is - /// returned. This method will not return until the entire buffer has been - /// successfully written or such an error occurs. The first error that is - /// not of [`ErrorKind::Interrupted`] kind generated from this method will be - /// returned. - /// - /// # Errors - /// - /// This function will return the first error of - /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns. - /// - /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted - /// [`write`]: #tymethod.write - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// buffer.write_all(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { - while !buf.is_empty() { - match self.write(buf) { - Ok(0) => return Err(Error::new(ErrorKind::WriteZero, - "failed to write whole buffer")), - Ok(n) => buf = &buf[n..], - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - - /// Writes a formatted string into this writer, returning any error - /// encountered. - /// - /// This method is primarily used to interface with the - /// [`format_args!`][formatargs] macro, but it is rare that this should - /// explicitly be called. The [`write!`][write] macro should be favored to - /// invoke this method instead. - /// - /// [formatargs]: ../macro.format_args.html - /// [write]: ../macro.write.html - /// - /// This function internally uses the [`write_all`][writeall] method on - /// this trait and hence will continuously write data so long as no errors - /// are received. This also means that partial writes are not indicated in - /// this signature. - /// - /// [writeall]: #method.write_all - /// - /// # Errors - /// - /// This function will return any I/O error reported while formatting. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// // this call - /// write!(buffer, "{:.*}", 2, 1.234567)?; - /// // turns into this: - /// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> { - // Create a shim which translates a Write to a fmt::Write and saves - // off I/O errors. instead of discarding them - struct Adaptor<'a, T: ?Sized + 'a> { - inner: &'a mut T, - error: Result<()>, - } - - impl<'a, T: Write + ?Sized> fmt::Write for Adaptor<'a, T> { - fn write_str(&mut self, s: &str) -> fmt::Result { - match self.inner.write_all(s.as_bytes()) { - Ok(()) => Ok(()), - Err(e) => { - self.error = Err(e); - Err(fmt::Error) - } - } - } - } - - let mut output = Adaptor { inner: self, error: Ok(()) }; - match fmt::write(&mut output, fmt) { - Ok(()) => Ok(()), - Err(..) => { - // check if the error came from the underlying `Write` or not - if output.error.is_err() { - output.error - } else { - Err(Error::new(ErrorKind::Other, "formatter error")) - } - } - } - } - - /// Creates a "by reference" adaptor for this instance of `Write`. - /// - /// The returned adaptor also implements `Write` and will simply borrow this - /// current writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::Write; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// let reference = buffer.by_ref(); - /// - /// // we can use reference just like our original buffer - /// reference.write_all(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn by_ref(&mut self) -> &mut Self where Self: Sized { self } -} - -/// The `Seek` trait provides a cursor which can be moved within a stream of -/// bytes. -/// -/// The stream typically has a fixed size, allowing seeking relative to either -/// end or the current offset. -/// -/// # Examples -/// -/// [`File`][file]s implement `Seek`: -/// -/// [file]: ../fs/struct.File.html -/// -/// ```no_run -/// use std::io; -/// use std::io::prelude::*; -/// use std::fs::File; -/// use std::io::SeekFrom; -/// -/// fn main() -> io::Result<()> { -/// let mut f = File::open("foo.txt")?; -/// -/// // move the cursor 42 bytes from the start of the file -/// f.seek(SeekFrom::Start(42))?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Seek { - /// Seek to an offset, in bytes, in a stream. - /// - /// A seek beyond the end of a stream is allowed, but implementation - /// defined. - /// - /// If the seek operation completed successfully, - /// this method returns the new position from the start of the stream. - /// That position can be used later with [`SeekFrom::Start`]. - /// - /// # Errors - /// - /// Seeking to a negative offset is considered an error. - /// - /// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start - #[stable(feature = "rust1", since = "1.0.0")] - fn seek(&mut self, pos: SeekFrom) -> Result; -} - -/// Enumeration of possible methods to seek within an I/O object. -/// -/// It is used by the [`Seek`] trait. -/// -/// [`Seek`]: trait.Seek.html -#[derive(Copy, PartialEq, Eq, Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub enum SeekFrom { - /// Set the offset to the provided number of bytes. - #[stable(feature = "rust1", since = "1.0.0")] - Start(#[stable(feature = "rust1", since = "1.0.0")] u64), - - /// Set the offset to the size of this object plus the specified number of - /// bytes. - /// - /// It is possible to seek beyond the end of an object, but it's an error to - /// seek before byte 0. - #[stable(feature = "rust1", since = "1.0.0")] - End(#[stable(feature = "rust1", since = "1.0.0")] i64), - - /// Set the offset to the current position plus the specified number of - /// bytes. - /// - /// It is possible to seek beyond the end of an object, but it's an error to - /// seek before byte 0. - #[stable(feature = "rust1", since = "1.0.0")] - Current(#[stable(feature = "rust1", since = "1.0.0")] i64), -} - -fn read_until(r: &mut R, delim: u8, buf: &mut Vec) - -> Result { - let mut read = 0; - loop { - let (done, used) = { - let available = match r.fill_buf() { - Ok(n) => n, - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => return Err(e) - }; - match memchr::memchr(delim, available) { - Some(i) => { - buf.extend_from_slice(&available[..i + 1]); - (true, i + 1) - } - None => { - buf.extend_from_slice(available); - (false, available.len()) - } - } - }; - r.consume(used); - read += used; - if done || used == 0 { - return Ok(read); - } - } -} - -/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it -/// to perform extra ways of reading. -/// -/// For example, reading line-by-line is inefficient without using a buffer, so -/// if you want to read by line, you'll need `BufRead`, which includes a -/// [`read_line`] method as well as a [`lines`] iterator. -/// -/// # Examples -/// -/// A locked standard input implements `BufRead`: -/// -/// ```no_run -/// use std::io; -/// use std::io::prelude::*; -/// -/// let stdin = io::stdin(); -/// for line in stdin.lock().lines() { -/// println!("{}", line.unwrap()); -/// } -/// ``` -/// -/// If you have something that implements [`Read`], you can use the [`BufReader` -/// type][`BufReader`] to turn it into a `BufRead`. -/// -/// For example, [`File`] implements [`Read`], but not `BufRead`. -/// [`BufReader`] to the rescue! -/// -/// [`BufReader`]: struct.BufReader.html -/// [`File`]: ../fs/struct.File.html -/// [`read_line`]: #method.read_line -/// [`lines`]: #method.lines -/// [`Read`]: trait.Read.html -/// -/// ```no_run -/// use std::io::{self, BufReader}; -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// fn main() -> io::Result<()> { -/// let f = File::open("foo.txt")?; -/// let f = BufReader::new(f); -/// -/// for line in f.lines() { -/// println!("{}", line.unwrap()); -/// } -/// -/// Ok(()) -/// } -/// ``` -/// -#[stable(feature = "rust1", since = "1.0.0")] -pub trait BufRead: Read { - /// Fills the internal buffer of this object, returning the buffer contents. - /// - /// This function is a lower-level call. It needs to be paired with the - /// [`consume`] method to function properly. When calling this - /// method, none of the contents will be "read" in the sense that later - /// calling `read` may return the same contents. As such, [`consume`] must - /// be called with the number of bytes that are consumed from this buffer to - /// ensure that the bytes are never returned twice. - /// - /// [`consume`]: #tymethod.consume - /// - /// An empty buffer returned indicates that the stream has reached EOF. - /// - /// # Errors - /// - /// This function will return an I/O error if the underlying reader was - /// read, but returned an error. - /// - /// # Examples - /// - /// A locked standard input implements `BufRead`: - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// - /// // we can't have two `&mut` references to `stdin`, so use a block - /// // to end the borrow early. - /// let length = { - /// let buffer = stdin.fill_buf().unwrap(); - /// - /// // work with buffer - /// println!("{:?}", buffer); - /// - /// buffer.len() - /// }; - /// - /// // ensure the bytes we worked with aren't returned again later - /// stdin.consume(length); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn fill_buf(&mut self) -> Result<&[u8]>; - - /// Tells this buffer that `amt` bytes have been consumed from the buffer, - /// so they should no longer be returned in calls to `read`. - /// - /// This function is a lower-level call. It needs to be paired with the - /// [`fill_buf`] method to function properly. This function does - /// not perform any I/O, it simply informs this object that some amount of - /// its buffer, returned from [`fill_buf`], has been consumed and should - /// no longer be returned. As such, this function may do odd things if - /// [`fill_buf`] isn't called before calling it. - /// - /// The `amt` must be `<=` the number of bytes in the buffer returned by - /// [`fill_buf`]. - /// - /// # Examples - /// - /// Since `consume()` is meant to be used with [`fill_buf`], - /// that method's example includes an example of `consume()`. - /// - /// [`fill_buf`]: #tymethod.fill_buf - #[stable(feature = "rust1", since = "1.0.0")] - fn consume(&mut self, amt: usize); - - /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached. - /// - /// This function will read bytes from the underlying stream until the - /// delimiter or EOF is found. Once found, all bytes up to, and including, - /// the delimiter (if found) will be appended to `buf`. - /// - /// If successful, this function will return the total number of bytes read. - /// - /// # Errors - /// - /// This function will ignore all instances of [`ErrorKind::Interrupted`] and - /// will otherwise return any errors returned by [`fill_buf`]. - /// - /// If an I/O error is encountered then all bytes read so far will be - /// present in `buf` and its length will have been adjusted appropriately. - /// - /// [`fill_buf`]: #tymethod.fill_buf - /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted - /// - /// # Examples - /// - /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In - /// this example, we use [`Cursor`] to read all the bytes in a byte slice - /// in hyphen delimited segments: - /// - /// [`Cursor`]: struct.Cursor.html - /// - /// ``` - /// use std::io::{self, BufRead}; - /// - /// let mut cursor = io::Cursor::new(b"lorem-ipsum"); - /// let mut buf = vec![]; - /// - /// // cursor is at 'l' - /// let num_bytes = cursor.read_until(b'-', &mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 6); - /// assert_eq!(buf, b"lorem-"); - /// buf.clear(); - /// - /// // cursor is at 'i' - /// let num_bytes = cursor.read_until(b'-', &mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 5); - /// assert_eq!(buf, b"ipsum"); - /// buf.clear(); - /// - /// // cursor is at EOF - /// let num_bytes = cursor.read_until(b'-', &mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 0); - /// assert_eq!(buf, b""); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { - read_until(self, byte, buf) - } - - /// Read all bytes until a newline (the 0xA byte) is reached, and append - /// them to the provided buffer. - /// - /// This function will read bytes from the underlying stream until the - /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes - /// up to, and including, the delimiter (if found) will be appended to - /// `buf`. - /// - /// If successful, this function will return the total number of bytes read. - /// - /// An empty buffer returned indicates that the stream has reached EOF. - /// - /// # Errors - /// - /// This function has the same error semantics as [`read_until`] and will - /// also return an error if the read bytes are not valid UTF-8. If an I/O - /// error is encountered then `buf` may contain some bytes already read in - /// the event that all data read so far was valid UTF-8. - /// - /// [`read_until`]: #method.read_until - /// - /// # Examples - /// - /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In - /// this example, we use [`Cursor`] to read all the lines in a byte slice: - /// - /// [`Cursor`]: struct.Cursor.html - /// - /// ``` - /// use std::io::{self, BufRead}; - /// - /// let mut cursor = io::Cursor::new(b"foo\nbar"); - /// let mut buf = String::new(); - /// - /// // cursor is at 'f' - /// let num_bytes = cursor.read_line(&mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 4); - /// assert_eq!(buf, "foo\n"); - /// buf.clear(); - /// - /// // cursor is at 'b' - /// let num_bytes = cursor.read_line(&mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 3); - /// assert_eq!(buf, "bar"); - /// buf.clear(); - /// - /// // cursor is at EOF - /// let num_bytes = cursor.read_line(&mut buf) - /// .expect("reading from cursor won't fail"); - /// assert_eq!(num_bytes, 0); - /// assert_eq!(buf, ""); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn read_line(&mut self, buf: &mut String) -> Result { - // Note that we are not calling the `.read_until` method here, but - // rather our hardcoded implementation. For more details as to why, see - // the comments in `read_to_end`. - append_to_string(buf, |b| read_until(self, b'\n', b)) - } - - /// Returns an iterator over the contents of this reader split on the byte - /// `byte`. - /// - /// The iterator returned from this function will return instances of - /// [`io::Result`]`<`[`Vec`]`>`. Each vector returned will *not* have - /// the delimiter byte at the end. - /// - /// This function will yield errors whenever [`read_until`] would have - /// also yielded an error. - /// - /// [`io::Result`]: type.Result.html - /// [`Vec`]: ../vec/struct.Vec.html - /// [`read_until`]: #method.read_until - /// - /// # Examples - /// - /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In - /// this example, we use [`Cursor`] to iterate over all hyphen delimited - /// segments in a byte slice - /// - /// [`Cursor`]: struct.Cursor.html - /// - /// ``` - /// use std::io::{self, BufRead}; - /// - /// let cursor = io::Cursor::new(b"lorem-ipsum-dolor"); - /// - /// let mut split_iter = cursor.split(b'-').map(|l| l.unwrap()); - /// assert_eq!(split_iter.next(), Some(b"lorem".to_vec())); - /// assert_eq!(split_iter.next(), Some(b"ipsum".to_vec())); - /// assert_eq!(split_iter.next(), Some(b"dolor".to_vec())); - /// assert_eq!(split_iter.next(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn split(self, byte: u8) -> Split where Self: Sized { - Split { buf: self, delim: byte } - } - - /// Returns an iterator over the lines of this reader. - /// - /// The iterator returned from this function will yield instances of - /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline - /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end. - /// - /// [`io::Result`]: type.Result.html - /// [`String`]: ../string/struct.String.html - /// - /// # Examples - /// - /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In - /// this example, we use [`Cursor`] to iterate over all the lines in a byte - /// slice. - /// - /// [`Cursor`]: struct.Cursor.html - /// - /// ``` - /// use std::io::{self, BufRead}; - /// - /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); - /// - /// let mut lines_iter = cursor.lines().map(|l| l.unwrap()); - /// assert_eq!(lines_iter.next(), Some(String::from("lorem"))); - /// assert_eq!(lines_iter.next(), Some(String::from("ipsum"))); - /// assert_eq!(lines_iter.next(), Some(String::from("dolor"))); - /// assert_eq!(lines_iter.next(), None); - /// ``` - /// - /// # Errors - /// - /// Each line of the iterator has the same error semantics as [`BufRead::read_line`]. - /// - /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line - #[stable(feature = "rust1", since = "1.0.0")] - fn lines(self) -> Lines where Self: Sized { - Lines { buf: self } - } -} - -/// Adaptor to chain together two readers. -/// -/// This struct is generally created by calling [`chain`] on a reader. -/// Please see the documentation of [`chain`] for more details. -/// -/// [`chain`]: trait.Read.html#method.chain -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Chain { - first: T, - second: U, - done_first: bool, -} - -impl Chain { - /// Consumes the `Chain`, returning the wrapped readers. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut foo_file = File::open("foo.txt")?; - /// let mut bar_file = File::open("bar.txt")?; - /// - /// let chain = foo_file.chain(bar_file); - /// let (foo_file, bar_file) = chain.into_inner(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "more_io_inner_methods", since = "1.20.0")] - pub fn into_inner(self) -> (T, U) { - (self.first, self.second) - } - - /// Gets references to the underlying readers in this `Chain`. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut foo_file = File::open("foo.txt")?; - /// let mut bar_file = File::open("bar.txt")?; - /// - /// let chain = foo_file.chain(bar_file); - /// let (foo_file, bar_file) = chain.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "more_io_inner_methods", since = "1.20.0")] - pub fn get_ref(&self) -> (&T, &U) { - (&self.first, &self.second) - } - - /// Gets mutable references to the underlying readers in this `Chain`. - /// - /// Care should be taken to avoid modifying the internal I/O state of the - /// underlying readers as doing so may corrupt the internal state of this - /// `Chain`. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut foo_file = File::open("foo.txt")?; - /// let mut bar_file = File::open("bar.txt")?; - /// - /// let mut chain = foo_file.chain(bar_file); - /// let (foo_file, bar_file) = chain.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "more_io_inner_methods", since = "1.20.0")] - pub fn get_mut(&mut self) -> (&mut T, &mut U) { - (&mut self.first, &mut self.second) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Chain { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Chain") - .field("t", &self.first) - .field("u", &self.second) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for Chain { - fn read(&mut self, buf: &mut [u8]) -> Result { - if !self.done_first { - match self.first.read(buf)? { - 0 if buf.len() != 0 => { self.done_first = true; } - n => return Ok(n), - } - } - self.second.read(buf) - } - - unsafe fn initializer(&self) -> Initializer { - let initializer = self.first.initializer(); - if initializer.should_initialize() { - initializer - } else { - self.second.initializer() - } - } -} - -#[stable(feature = "chain_bufread", since = "1.9.0")] -impl BufRead for Chain { - fn fill_buf(&mut self) -> Result<&[u8]> { - if !self.done_first { - match self.first.fill_buf()? { - buf if buf.len() == 0 => { self.done_first = true; } - buf => return Ok(buf), - } - } - self.second.fill_buf() - } - - fn consume(&mut self, amt: usize) { - if !self.done_first { - self.first.consume(amt) - } else { - self.second.consume(amt) - } - } -} - -/// Reader adaptor which limits the bytes read from an underlying reader. -/// -/// This struct is generally created by calling [`take`] on a reader. -/// Please see the documentation of [`take`] for more details. -/// -/// [`take`]: trait.Read.html#method.take -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct Take { - inner: T, - limit: u64, -} - -impl Take { - /// Returns the number of bytes that can be read before this instance will - /// return EOF. - /// - /// # Note - /// - /// This instance may reach `EOF` after reading fewer bytes than indicated by - /// this method if the underlying [`Read`] instance reaches EOF. - /// - /// [`Read`]: ../../std/io/trait.Read.html - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let f = File::open("foo.txt")?; - /// - /// // read at most five bytes - /// let handle = f.take(5); - /// - /// println!("limit: {}", handle.limit()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn limit(&self) -> u64 { self.limit } - - /// Sets the number of bytes that can be read before this instance will - /// return EOF. This is the same as constructing a new `Take` instance, so - /// the amount of bytes read and the previous limit value don't matter when - /// calling this method. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let f = File::open("foo.txt")?; - /// - /// // read at most five bytes - /// let mut handle = f.take(5); - /// handle.set_limit(10); - /// - /// assert_eq!(handle.limit(), 10); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "take_set_limit", since = "1.27.0")] - pub fn set_limit(&mut self, limit: u64) { - self.limit = limit; - } - - /// Consumes the `Take`, returning the wrapped reader. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// - /// let mut buffer = [0; 5]; - /// let mut handle = file.take(5); - /// handle.read(&mut buffer)?; - /// - /// let file = handle.into_inner(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "io_take_into_inner", since = "1.15.0")] - pub fn into_inner(self) -> T { - self.inner - } - - /// Gets a reference to the underlying reader. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// - /// let mut buffer = [0; 5]; - /// let mut handle = file.take(5); - /// handle.read(&mut buffer)?; - /// - /// let file = handle.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "more_io_inner_methods", since = "1.20.0")] - pub fn get_ref(&self) -> &T { - &self.inner - } - - /// Gets a mutable reference to the underlying reader. - /// - /// Care should be taken to avoid modifying the internal I/O state of the - /// underlying reader as doing so may corrupt the internal limit of this - /// `Take`. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// - /// let mut buffer = [0; 5]; - /// let mut handle = file.take(5); - /// handle.read(&mut buffer)?; - /// - /// let file = handle.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "more_io_inner_methods", since = "1.20.0")] - pub fn get_mut(&mut self) -> &mut T { - &mut self.inner - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for Take { - fn read(&mut self, buf: &mut [u8]) -> Result { - // Don't call into inner reader at all at EOF because it may still block - if self.limit == 0 { - return Ok(0); - } - - let max = cmp::min(buf.len() as u64, self.limit) as usize; - let n = self.inner.read(&mut buf[..max])?; - self.limit -= n as u64; - Ok(n) - } - - unsafe fn initializer(&self) -> Initializer { - self.inner.initializer() - } - - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - let reservation_size = cmp::min(self.limit, 32) as usize; - - read_to_end_with_reservation(self, buf, reservation_size) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl BufRead for Take { - fn fill_buf(&mut self) -> Result<&[u8]> { - // Don't call into inner reader at all at EOF because it may still block - if self.limit == 0 { - return Ok(&[]); - } - - let buf = self.inner.fill_buf()?; - let cap = cmp::min(buf.len() as u64, self.limit) as usize; - Ok(&buf[..cap]) - } - - fn consume(&mut self, amt: usize) { - // Don't let callers reset the limit by passing an overlarge value - let amt = cmp::min(amt as u64, self.limit) as usize; - self.limit -= amt as u64; - self.inner.consume(amt); - } -} - -fn read_one_byte(reader: &mut dyn Read) -> Option> { - let mut buf = [0]; - loop { - return match reader.read(&mut buf) { - Ok(0) => None, - Ok(..) => Some(Ok(buf[0])), - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => Some(Err(e)), - }; - } -} - -/// An iterator over `u8` values of a reader. -/// -/// This struct is generally created by calling [`bytes`] on a reader. -/// Please see the documentation of [`bytes`] for more details. -/// -/// [`bytes`]: trait.Read.html#method.bytes -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct Bytes { - inner: R, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Bytes { - type Item = Result; - - fn next(&mut self) -> Option> { - read_one_byte(&mut self.inner) - } -} - -/// An iterator over the contents of an instance of `BufRead` split on a -/// particular byte. -/// -/// This struct is generally created by calling [`split`][split] on a -/// `BufRead`. Please see the documentation of `split()` for more details. -/// -/// [split]: trait.BufRead.html#method.split -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct Split { - buf: B, - delim: u8, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Split { - type Item = Result>; - - fn next(&mut self) -> Option>> { - let mut buf = Vec::new(); - match self.buf.read_until(self.delim, &mut buf) { - Ok(0) => None, - Ok(_n) => { - if buf[buf.len() - 1] == self.delim { - buf.pop(); - } - Some(Ok(buf)) - } - Err(e) => Some(Err(e)) - } - } -} - -/// An iterator over the lines of an instance of `BufRead`. -/// -/// This struct is generally created by calling [`lines`][lines] on a -/// `BufRead`. Please see the documentation of `lines()` for more details. -/// -/// [lines]: trait.BufRead.html#method.lines -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct Lines { - buf: B, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Lines { - type Item = Result; - - fn next(&mut self) -> Option> { - let mut buf = String::new(); - match self.buf.read_line(&mut buf) { - Ok(0) => None, - Ok(_n) => { - if buf.ends_with("\n") { - buf.pop(); - if buf.ends_with("\r") { - buf.pop(); - } - } - Some(Ok(buf)) - } - Err(e) => Some(Err(e)) - } - } -} - -#[cfg(test)] -mod tests { - use io::prelude::*; - use io; - use super::Cursor; - use test; - use super::repeat; - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn read_until() { - let mut buf = Cursor::new(&b"12"[..]); - let mut v = Vec::new(); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2); - assert_eq!(v, b"12"); - - let mut buf = Cursor::new(&b"1233"[..]); - let mut v = Vec::new(); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3); - assert_eq!(v, b"123"); - v.truncate(0); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1); - assert_eq!(v, b"3"); - v.truncate(0); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0); - assert_eq!(v, []); - } - - #[test] - fn split() { - let buf = Cursor::new(&b"12"[..]); - let mut s = buf.split(b'3'); - assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); - assert!(s.next().is_none()); - - let buf = Cursor::new(&b"1233"[..]); - let mut s = buf.split(b'3'); - assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); - assert_eq!(s.next().unwrap().unwrap(), vec![]); - assert!(s.next().is_none()); - } - - #[test] - fn read_line() { - let mut buf = Cursor::new(&b"12"[..]); - let mut v = String::new(); - assert_eq!(buf.read_line(&mut v).unwrap(), 2); - assert_eq!(v, "12"); - - let mut buf = Cursor::new(&b"12\n\n"[..]); - let mut v = String::new(); - assert_eq!(buf.read_line(&mut v).unwrap(), 3); - assert_eq!(v, "12\n"); - v.truncate(0); - assert_eq!(buf.read_line(&mut v).unwrap(), 1); - assert_eq!(v, "\n"); - v.truncate(0); - assert_eq!(buf.read_line(&mut v).unwrap(), 0); - assert_eq!(v, ""); - } - - #[test] - fn lines() { - let buf = Cursor::new(&b"12\r"[..]); - let mut s = buf.lines(); - assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string()); - assert!(s.next().is_none()); - - let buf = Cursor::new(&b"12\r\n\n"[..]); - let mut s = buf.lines(); - assert_eq!(s.next().unwrap().unwrap(), "12".to_string()); - assert_eq!(s.next().unwrap().unwrap(), "".to_string()); - assert!(s.next().is_none()); - } - - #[test] - fn read_to_end() { - let mut c = Cursor::new(&b""[..]); - let mut v = Vec::new(); - assert_eq!(c.read_to_end(&mut v).unwrap(), 0); - assert_eq!(v, []); - - let mut c = Cursor::new(&b"1"[..]); - let mut v = Vec::new(); - assert_eq!(c.read_to_end(&mut v).unwrap(), 1); - assert_eq!(v, b"1"); - - let cap = 1024 * 1024; - let data = (0..cap).map(|i| (i / 3) as u8).collect::>(); - let mut v = Vec::new(); - let (a, b) = data.split_at(data.len() / 2); - assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len()); - assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len()); - assert_eq!(v, data); - } - - #[test] - fn read_to_string() { - let mut c = Cursor::new(&b""[..]); - let mut v = String::new(); - assert_eq!(c.read_to_string(&mut v).unwrap(), 0); - assert_eq!(v, ""); - - let mut c = Cursor::new(&b"1"[..]); - let mut v = String::new(); - assert_eq!(c.read_to_string(&mut v).unwrap(), 1); - assert_eq!(v, "1"); - - let mut c = Cursor::new(&b"\xff"[..]); - let mut v = String::new(); - assert!(c.read_to_string(&mut v).is_err()); - } - - #[test] - fn read_exact() { - let mut buf = [0; 4]; - - let mut c = Cursor::new(&b""[..]); - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), - io::ErrorKind::UnexpectedEof); - - let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..])); - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"1234"); - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"5678"); - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), - io::ErrorKind::UnexpectedEof); - } - - #[test] - fn read_exact_slice() { - let mut buf = [0; 4]; - - let mut c = &b""[..]; - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), - io::ErrorKind::UnexpectedEof); - - let mut c = &b"123"[..]; - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), - io::ErrorKind::UnexpectedEof); - // make sure the optimized (early returning) method is being used - assert_eq!(&buf, &[0; 4]); - - let mut c = &b"1234"[..]; - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"1234"); - - let mut c = &b"56789"[..]; - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"5678"); - assert_eq!(c, b"9"); - } - - #[test] - fn take_eof() { - struct R; - - impl Read for R { - fn read(&mut self, _: &mut [u8]) -> io::Result { - Err(io::Error::new(io::ErrorKind::Other, "")) - } - } - impl BufRead for R { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - Err(io::Error::new(io::ErrorKind::Other, "")) - } - fn consume(&mut self, _amt: usize) { } - } - - let mut buf = [0; 1]; - assert_eq!(0, R.take(0).read(&mut buf).unwrap()); - assert_eq!(b"", R.take(0).fill_buf().unwrap()); - } - - fn cmp_bufread(mut br1: Br1, mut br2: Br2, exp: &[u8]) { - let mut cat = Vec::new(); - loop { - let consume = { - let buf1 = br1.fill_buf().unwrap(); - let buf2 = br2.fill_buf().unwrap(); - let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() }; - assert_eq!(buf1[..minlen], buf2[..minlen]); - cat.extend_from_slice(&buf1[..minlen]); - minlen - }; - if consume == 0 { - break; - } - br1.consume(consume); - br2.consume(consume); - } - assert_eq!(br1.fill_buf().unwrap().len(), 0); - assert_eq!(br2.fill_buf().unwrap().len(), 0); - assert_eq!(&cat[..], &exp[..]) - } - - #[test] - fn chain_bufread() { - let testdata = b"ABCDEFGHIJKL"; - let chain1 = (&testdata[..3]).chain(&testdata[3..6]) - .chain(&testdata[6..9]) - .chain(&testdata[9..]); - let chain2 = (&testdata[..4]).chain(&testdata[4..8]) - .chain(&testdata[8..]); - cmp_bufread(chain1, chain2, &testdata[..]); - } - - #[test] - fn chain_zero_length_read_is_not_eof() { - let a = b"A"; - let b = b"B"; - let mut s = String::new(); - let mut chain = (&a[..]).chain(&b[..]); - chain.read(&mut []).unwrap(); - chain.read_to_string(&mut s).unwrap(); - assert_eq!("AB", s); - } - - #[bench] - #[cfg_attr(target_os = "emscripten", ignore)] - fn bench_read_to_end(b: &mut test::Bencher) { - b.iter(|| { - let mut lr = repeat(1).take(10000000); - let mut vec = Vec::with_capacity(1024); - super::read_to_end(&mut lr, &mut vec) - }); - } -} diff --git a/ctr-std/src/io/prelude.rs b/ctr-std/src/io/prelude.rs deleted file mode 100644 index 8772d0f..0000000 --- a/ctr-std/src/io/prelude.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The I/O Prelude -//! -//! The purpose of this module is to alleviate imports of many common I/O traits -//! by adding a glob import to the top of I/O heavy modules: -//! -//! ``` -//! # #![allow(unused_imports)] -//! use std::io::prelude::*; -//! ``` - -#![stable(feature = "rust1", since = "1.0.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -pub use super::{Read, Write, BufRead, Seek}; diff --git a/ctr-std/src/io/stdio.rs b/ctr-std/src/io/stdio.rs deleted file mode 100644 index 1f256f5..0000000 --- a/ctr-std/src/io/stdio.rs +++ /dev/null @@ -1,764 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io::prelude::*; - -use cell::RefCell; -use fmt; -use io::lazy::Lazy; -use io::{self, Initializer, BufReader, LineWriter}; -use sync::{Arc, Mutex, MutexGuard}; -use sys::stdio; -use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; -use thread::LocalKey; - -/// Stdout used by print! and println! macros -thread_local! { - static LOCAL_STDOUT: RefCell>> = { - RefCell::new(None) - } -} - -/// A handle to a raw instance of the standard input stream of this process. -/// -/// This handle is not synchronized or buffered in any fashion. Constructed via -/// the `std::io::stdio::stdin_raw` function. -struct StdinRaw(stdio::Stdin); - -/// A handle to a raw instance of the standard output stream of this process. -/// -/// This handle is not synchronized or buffered in any fashion. Constructed via -/// the `std::io::stdio::stdout_raw` function. -struct StdoutRaw(stdio::Stdout); - -/// A handle to a raw instance of the standard output stream of this process. -/// -/// This handle is not synchronized or buffered in any fashion. Constructed via -/// the `std::io::stdio::stderr_raw` function. -struct StderrRaw(stdio::Stderr); - -/// Constructs a new raw handle to the standard input of this process. -/// -/// The returned handle does not interact with any other handles created nor -/// handles returned by `std::io::stdin`. Data buffered by the `std::io::stdin` -/// handles is **not** available to raw handles returned from this function. -/// -/// The returned handle has no external synchronization or buffering. -fn stdin_raw() -> io::Result { stdio::Stdin::new().map(StdinRaw) } - -/// Constructs a new raw handle to the standard output stream of this process. -/// -/// The returned handle does not interact with any other handles created nor -/// handles returned by `std::io::stdout`. Note that data is buffered by the -/// `std::io::stdout` handles so writes which happen via this raw handle may -/// appear before previous writes. -/// -/// The returned handle has no external synchronization or buffering layered on -/// top. -fn stdout_raw() -> io::Result { stdio::Stdout::new().map(StdoutRaw) } - -/// Constructs a new raw handle to the standard error stream of this process. -/// -/// The returned handle does not interact with any other handles created nor -/// handles returned by `std::io::stderr`. -/// -/// The returned handle has no external synchronization or buffering layered on -/// top. -fn stderr_raw() -> io::Result { stdio::Stderr::new().map(StderrRaw) } - -impl Read for StdinRaw { - fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} -impl Write for StdoutRaw { - fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } - fn flush(&mut self) -> io::Result<()> { self.0.flush() } -} -impl Write for StderrRaw { - fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } - fn flush(&mut self) -> io::Result<()> { self.0.flush() } -} - -enum Maybe { - Real(T), - Fake, -} - -impl io::Write for Maybe { - fn write(&mut self, buf: &[u8]) -> io::Result { - match *self { - Maybe::Real(ref mut w) => handle_ebadf(w.write(buf), buf.len()), - Maybe::Fake => Ok(buf.len()) - } - } - - fn flush(&mut self) -> io::Result<()> { - match *self { - Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()), - Maybe::Fake => Ok(()) - } - } -} - -impl io::Read for Maybe { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match *self { - Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), 0), - Maybe::Fake => Ok(0) - } - } -} - -fn handle_ebadf(r: io::Result, default: T) -> io::Result { - match r { - Err(ref e) if stdio::is_ebadf(e) => Ok(default), - r => r - } -} - -/// A handle to the standard input stream of a process. -/// -/// Each handle is a shared reference to a global buffer of input data to this -/// process. A handle can be `lock`'d to gain full access to [`BufRead`] methods -/// (e.g. `.lines()`). Reads to this handle are otherwise locked with respect -/// to other reads. -/// -/// This handle implements the `Read` trait, but beware that concurrent reads -/// of `Stdin` must be executed with care. -/// -/// Created by the [`io::stdin`] method. -/// -/// [`io::stdin`]: fn.stdin.html -/// [`BufRead`]: trait.BufRead.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Stdin { - inner: Arc>>>, -} - -/// A locked reference to the `Stdin` handle. -/// -/// This handle implements both the [`Read`] and [`BufRead`] traits, and -/// is constructed via the [`Stdin::lock`] method. -/// -/// [`Read`]: trait.Read.html -/// [`BufRead`]: trait.BufRead.html -/// [`Stdin::lock`]: struct.Stdin.html#method.lock -#[stable(feature = "rust1", since = "1.0.0")] -pub struct StdinLock<'a> { - inner: MutexGuard<'a, BufReader>>, -} - -/// Constructs a new handle to the standard input of the current process. -/// -/// Each handle returned is a reference to a shared global buffer whose access -/// is synchronized via a mutex. If you need more explicit control over -/// locking, see the [`lock() method`][lock]. -/// -/// [lock]: struct.Stdin.html#method.lock -/// -/// # Examples -/// -/// Using implicit synchronization: -/// -/// ```no_run -/// use std::io::{self, Read}; -/// -/// fn main() -> io::Result<()> { -/// let mut buffer = String::new(); -/// io::stdin().read_to_string(&mut buffer)?; -/// Ok(()) -/// } -/// ``` -/// -/// Using explicit synchronization: -/// -/// ```no_run -/// use std::io::{self, Read}; -/// -/// fn main() -> io::Result<()> { -/// let mut buffer = String::new(); -/// let stdin = io::stdin(); -/// let mut handle = stdin.lock(); -/// -/// handle.read_to_string(&mut buffer)?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn stdin() -> Stdin { - static INSTANCE: Lazy>>> = unsafe { Lazy::new(stdin_init) }; - return Stdin { - inner: INSTANCE.get().expect("cannot access stdin during shutdown"), - }; - - fn stdin_init() -> Arc>>> { - // This must not reentrantly access `INSTANCE` - let stdin = match stdin_raw() { - Ok(stdin) => Maybe::Real(stdin), - _ => Maybe::Fake - }; - - Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin))) - } -} - -impl Stdin { - /// Locks this handle to the standard input stream, returning a readable - /// guard. - /// - /// The lock is released when the returned lock goes out of scope. The - /// returned guard also implements the [`Read`] and [`BufRead`] traits for - /// accessing the underlying data. - /// - /// [`Read`]: trait.Read.html - /// [`BufRead`]: trait.BufRead.html - /// - /// # Examples - /// - /// ```no_run - /// use std::io::{self, Read}; - /// - /// fn main() -> io::Result<()> { - /// let mut buffer = String::new(); - /// let stdin = io::stdin(); - /// let mut handle = stdin.lock(); - /// - /// handle.read_to_string(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StdinLock { - StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } - } - - /// Locks this handle and reads a line of input into the specified buffer. - /// - /// For detailed semantics of this method, see the documentation on - /// [`BufRead::read_line`]. - /// - /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// - /// let mut input = String::new(); - /// match io::stdin().read_line(&mut input) { - /// Ok(n) => { - /// println!("{} bytes read", n); - /// println!("{}", input); - /// } - /// Err(error) => println!("error: {}", error), - /// } - /// ``` - /// - /// You can run the example one of two ways: - /// - /// - Pipe some text to it, e.g. `printf foo | path/to/executable` - /// - Give it text interactively by running the executable directly, - /// in which case it will wait for the Enter key to be pressed before - /// continuing - #[stable(feature = "rust1", since = "1.0.0")] - pub fn read_line(&self, buf: &mut String) -> io::Result { - self.lock().read_line(buf) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Stdin { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Stdin { .. }") - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.lock().read(buf) - } - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.lock().read_to_end(buf) - } - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - self.lock().read_to_string(buf) - } - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - self.lock().read_exact(buf) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Read for StdinLock<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> BufRead for StdinLock<'a> { - fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() } - fn consume(&mut self, n: usize) { self.inner.consume(n) } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a> fmt::Debug for StdinLock<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("StdinLock { .. }") - } -} - -/// A handle to the global standard output stream of the current process. -/// -/// Each handle shares a global buffer of data to be written to the standard -/// output stream. Access is also synchronized via a lock and explicit control -/// over locking is available via the [`lock`] method. -/// -/// Created by the [`io::stdout`] method. -/// -/// [`lock`]: #method.lock -/// [`io::stdout`]: fn.stdout.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Stdout { - // FIXME: this should be LineWriter or BufWriter depending on the state of - // stdout (tty or not). Note that if this is not line buffered it - // should also flush-on-panic or some form of flush-on-abort. - inner: Arc>>>>, -} - -/// A locked reference to the `Stdout` handle. -/// -/// This handle implements the [`Write`] trait, and is constructed via -/// the [`Stdout::lock`] method. -/// -/// [`Write`]: trait.Write.html -/// [`Stdout::lock`]: struct.Stdout.html#method.lock -#[stable(feature = "rust1", since = "1.0.0")] -pub struct StdoutLock<'a> { - inner: ReentrantMutexGuard<'a, RefCell>>>, -} - -/// Constructs a new handle to the standard output of the current process. -/// -/// Each handle returned is a reference to a shared global buffer whose access -/// is synchronized via a mutex. If you need more explicit control over -/// locking, see the [Stdout::lock] method. -/// -/// [Stdout::lock]: struct.Stdout.html#method.lock -/// -/// # Examples -/// -/// Using implicit synchronization: -/// -/// ```no_run -/// use std::io::{self, Write}; -/// -/// fn main() -> io::Result<()> { -/// io::stdout().write(b"hello world")?; -/// -/// Ok(()) -/// } -/// ``` -/// -/// Using explicit synchronization: -/// -/// ```no_run -/// use std::io::{self, Write}; -/// -/// fn main() -> io::Result<()> { -/// let stdout = io::stdout(); -/// let mut handle = stdout.lock(); -/// -/// handle.write(b"hello world")?; -/// -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn stdout() -> Stdout { - static INSTANCE: Lazy>>>> - = unsafe { Lazy::new(stdout_init) }; - return Stdout { - inner: INSTANCE.get().expect("cannot access stdout during shutdown"), - }; - - fn stdout_init() -> Arc>>>> { - // This must not reentrantly access `INSTANCE` - let stdout = match stdout_raw() { - Ok(stdout) => Maybe::Real(stdout), - _ => Maybe::Fake, - }; - Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout)))) - } -} - -impl Stdout { - /// Locks this handle to the standard output stream, returning a writable - /// guard. - /// - /// The lock is released when the returned lock goes out of scope. The - /// returned guard also implements the `Write` trait for writing data. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::{self, Write}; - /// - /// fn main() -> io::Result<()> { - /// let stdout = io::stdout(); - /// let mut handle = stdout.lock(); - /// - /// handle.write(b"hello world")?; - /// - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StdoutLock { - StdoutLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Stdout { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Stdout { .. }") - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.lock().write(buf) - } - fn flush(&mut self) -> io::Result<()> { - self.lock().flush() - } - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.lock().write_all(buf) - } - fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> { - self.lock().write_fmt(args) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Write for StdoutLock<'a> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.borrow_mut().write(buf) - } - fn flush(&mut self) -> io::Result<()> { - self.inner.borrow_mut().flush() - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a> fmt::Debug for StdoutLock<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("StdoutLock { .. }") - } -} - -/// A handle to the standard error stream of a process. -/// -/// For more information, see the [`io::stderr`] method. -/// -/// [`io::stderr`]: fn.stderr.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Stderr { - inner: Arc>>>, -} - -/// A locked reference to the `Stderr` handle. -/// -/// This handle implements the `Write` trait and is constructed via -/// the [`Stderr::lock`] method. -/// -/// [`Stderr::lock`]: struct.Stderr.html#method.lock -#[stable(feature = "rust1", since = "1.0.0")] -pub struct StderrLock<'a> { - inner: ReentrantMutexGuard<'a, RefCell>>, -} - -/// Constructs a new handle to the standard error of the current process. -/// -/// This handle is not buffered. -/// -/// # Examples -/// -/// Using implicit synchronization: -/// -/// ```no_run -/// use std::io::{self, Write}; -/// -/// fn main() -> io::Result<()> { -/// io::stderr().write(b"hello world")?; -/// -/// Ok(()) -/// } -/// ``` -/// -/// Using explicit synchronization: -/// -/// ```no_run -/// use std::io::{self, Write}; -/// -/// fn main() -> io::Result<()> { -/// let stderr = io::stderr(); -/// let mut handle = stderr.lock(); -/// -/// handle.write(b"hello world")?; -/// -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn stderr() -> Stderr { - static INSTANCE: Lazy>>> = - unsafe { Lazy::new(stderr_init) }; - return Stderr { - inner: INSTANCE.get().expect("cannot access stderr during shutdown"), - }; - - fn stderr_init() -> Arc>>> { - // This must not reentrantly access `INSTANCE` - let stderr = match stderr_raw() { - Ok(stderr) => Maybe::Real(stderr), - _ => Maybe::Fake, - }; - Arc::new(ReentrantMutex::new(RefCell::new(stderr))) - } -} - -impl Stderr { - /// Locks this handle to the standard error stream, returning a writable - /// guard. - /// - /// The lock is released when the returned lock goes out of scope. The - /// returned guard also implements the `Write` trait for writing data. - /// - /// # Examples - /// - /// ``` - /// use std::io::{self, Write}; - /// - /// fn foo() -> io::Result<()> { - /// let stderr = io::stderr(); - /// let mut handle = stderr.lock(); - /// - /// handle.write(b"hello world")?; - /// - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StderrLock { - StderrLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Stderr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Stderr { .. }") - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.lock().write(buf) - } - fn flush(&mut self) -> io::Result<()> { - self.lock().flush() - } - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.lock().write_all(buf) - } - fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> { - self.lock().write_fmt(args) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Write for StderrLock<'a> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.borrow_mut().write(buf) - } - fn flush(&mut self) -> io::Result<()> { - self.inner.borrow_mut().flush() - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a> fmt::Debug for StderrLock<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("StderrLock { .. }") - } -} - -/// Resets the thread-local stderr handle to the specified writer -/// -/// This will replace the current thread's stderr handle, returning the old -/// handle. All future calls to `panic!` and friends will emit their output to -/// this specified handle. -/// -/// Note that this does not need to be called for all new threads; the default -/// output handle is to the process's stderr stream. -#[unstable(feature = "set_stdio", - reason = "this function may disappear completely or be replaced \ - with a more general mechanism", - issue = "0")] -#[doc(hidden)] -pub fn set_panic(sink: Option>) -> Option> { - use panicking::LOCAL_STDERR; - use mem; - LOCAL_STDERR.with(move |slot| { - mem::replace(&mut *slot.borrow_mut(), sink) - }).and_then(|mut s| { - let _ = s.flush(); - Some(s) - }) -} - -/// Resets the thread-local stdout handle to the specified writer -/// -/// This will replace the current thread's stdout handle, returning the old -/// handle. All future calls to `print!` and friends will emit their output to -/// this specified handle. -/// -/// Note that this does not need to be called for all new threads; the default -/// output handle is to the process's stdout stream. -#[unstable(feature = "set_stdio", - reason = "this function may disappear completely or be replaced \ - with a more general mechanism", - issue = "0")] -#[doc(hidden)] -pub fn set_print(sink: Option>) -> Option> { - use mem; - LOCAL_STDOUT.with(move |slot| { - mem::replace(&mut *slot.borrow_mut(), sink) - }).and_then(|mut s| { - let _ = s.flush(); - Some(s) - }) -} - -/// Write `args` to output stream `local_s` if possible, `global_s` -/// otherwise. `label` identifies the stream in a panic message. -/// -/// This function is used to print error messages, so it takes extra -/// care to avoid causing a panic when `local_stream` is unusable. -/// For instance, if the TLS key for the local stream is -/// already destroyed, or if the local stream is locked by another -/// thread, it will just fall back to the global stream. -/// -/// However, if the actual I/O causes an error, this function does panic. -fn print_to( - args: fmt::Arguments, - local_s: &'static LocalKey>>>, - global_s: fn() -> T, - label: &str, -) -where - T: Write, -{ - let result = local_s.try_with(|s| { - if let Ok(mut borrowed) = s.try_borrow_mut() { - if let Some(w) = borrowed.as_mut() { - return w.write_fmt(args); - } - } - global_s().write_fmt(args) - }).unwrap_or_else(|_| { - global_s().write_fmt(args) - }); - - if let Err(e) = result { - panic!("failed printing to {}: {}", label, e); - } -} - -#[unstable(feature = "print_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "0")] -#[doc(hidden)] -pub fn _print(args: fmt::Arguments) { - print_to(args, &LOCAL_STDOUT, stdout, "stdout"); -} - -#[unstable(feature = "print_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "0")] -#[doc(hidden)] -pub fn _eprint(args: fmt::Arguments) { - use panicking::LOCAL_STDERR; - print_to(args, &LOCAL_STDERR, stderr, "stderr"); -} - -#[cfg(test)] -mod tests { - use panic::{UnwindSafe, RefUnwindSafe}; - use thread; - use super::*; - - #[test] - fn stdout_unwind_safe() { - assert_unwind_safe::(); - } - #[test] - fn stdoutlock_unwind_safe() { - assert_unwind_safe::(); - assert_unwind_safe::>(); - } - #[test] - fn stderr_unwind_safe() { - assert_unwind_safe::(); - } - #[test] - fn stderrlock_unwind_safe() { - assert_unwind_safe::(); - assert_unwind_safe::>(); - } - - fn assert_unwind_safe() {} - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn panic_doesnt_poison() { - thread::spawn(|| { - let _a = stdin(); - let _a = _a.lock(); - let _a = stdout(); - let _a = _a.lock(); - let _a = stderr(); - let _a = _a.lock(); - panic!(); - }).join().unwrap_err(); - - let _a = stdin(); - let _a = _a.lock(); - let _a = stdout(); - let _a = _a.lock(); - let _a = stderr(); - let _a = _a.lock(); - } -} diff --git a/ctr-std/src/io/util.rs b/ctr-std/src/io/util.rs deleted file mode 100644 index 33f741d..0000000 --- a/ctr-std/src/io/util.rs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(missing_copy_implementations)] - -use fmt; -use io::{self, Read, Initializer, Write, ErrorKind, BufRead}; -use mem; - -/// Copies the entire contents of a reader into a writer. -/// -/// This function will continuously read data from `reader` and then -/// write it into `writer` in a streaming fashion until `reader` -/// returns EOF. -/// -/// On success, the total number of bytes that were copied from -/// `reader` to `writer` is returned. -/// -/// # Errors -/// -/// This function will return an error immediately if any call to `read` or -/// `write` returns an error. All instances of `ErrorKind::Interrupted` are -/// handled by this function and the underlying operation is retried. -/// -/// # Examples -/// -/// ``` -/// use std::io; -/// -/// fn main() -> io::Result<()> { -/// let mut reader: &[u8] = b"hello"; -/// let mut writer: Vec = vec![]; -/// -/// io::copy(&mut reader, &mut writer)?; -/// -/// assert_eq!(&b"hello"[..], &writer[..]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn copy(reader: &mut R, writer: &mut W) -> io::Result - where R: Read, W: Write -{ - let mut buf = unsafe { - let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized(); - reader.initializer().initialize(&mut buf); - buf - }; - - let mut written = 0; - loop { - let len = match reader.read(&mut buf) { - Ok(0) => return Ok(written), - Ok(len) => len, - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => return Err(e), - }; - writer.write_all(&buf[..len])?; - written += len as u64; - } -} - -/// A reader which is always at EOF. -/// -/// This struct is generally created by calling [`empty`]. Please see -/// the documentation of [`empty()`][`empty`] for more details. -/// -/// [`empty`]: fn.empty.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Empty { _priv: () } - -/// Constructs a new handle to an empty reader. -/// -/// All reads from the returned reader will return [`Ok`]`(0)`. -/// -/// [`Ok`]: ../result/enum.Result.html#variant.Ok -/// -/// # Examples -/// -/// A slightly sad example of not reading anything into a buffer: -/// -/// ``` -/// use std::io::{self, Read}; -/// -/// let mut buffer = String::new(); -/// io::empty().read_to_string(&mut buffer).unwrap(); -/// assert!(buffer.is_empty()); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn empty() -> Empty { Empty { _priv: () } } - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for Empty { - #[inline] - fn read(&mut self, _buf: &mut [u8]) -> io::Result { Ok(0) } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl BufRead for Empty { - #[inline] - fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) } - #[inline] - fn consume(&mut self, _n: usize) {} -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Empty { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Empty { .. }") - } -} - -/// A reader which yields one byte over and over and over and over and over and... -/// -/// This struct is generally created by calling [`repeat`][repeat]. Please -/// see the documentation of `repeat()` for more details. -/// -/// [repeat]: fn.repeat.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Repeat { byte: u8 } - -/// Creates an instance of a reader that infinitely repeats one byte. -/// -/// All reads from this reader will succeed by filling the specified buffer with -/// the given byte. -/// -/// # Examples -/// -/// ``` -/// use std::io::{self, Read}; -/// -/// let mut buffer = [0; 3]; -/// io::repeat(0b101).read_exact(&mut buffer).unwrap(); -/// assert_eq!(buffer, [0b101, 0b101, 0b101]); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } } - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for Repeat { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - for slot in &mut *buf { - *slot = self.byte; - } - Ok(buf.len()) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Repeat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Repeat { .. }") - } -} - -/// A writer which will move data into the void. -/// -/// This struct is generally created by calling [`sink`][sink]. Please -/// see the documentation of `sink()` for more details. -/// -/// [sink]: fn.sink.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Sink { _priv: () } - -/// Creates an instance of a writer which will successfully consume all data. -/// -/// All calls to `write` on the returned instance will return `Ok(buf.len())` -/// and the contents of the buffer will not be inspected. -/// -/// # Examples -/// -/// ```rust -/// use std::io::{self, Write}; -/// -/// let buffer = vec![1, 2, 3, 5, 8]; -/// let num_bytes = io::sink().write(&buffer).unwrap(); -/// assert_eq!(num_bytes, 5); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn sink() -> Sink { Sink { _priv: () } } - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Sink { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } - #[inline] - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Sink { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Sink { .. }") - } -} - -#[cfg(test)] -mod tests { - use io::prelude::*; - use io::{copy, sink, empty, repeat}; - - #[test] - fn copy_copies() { - let mut r = repeat(0).take(4); - let mut w = sink(); - assert_eq!(copy(&mut r, &mut w).unwrap(), 4); - - let mut r = repeat(0).take(1 << 17); - assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); - } - - #[test] - fn sink_sinks() { - let mut s = sink(); - assert_eq!(s.write(&[]).unwrap(), 0); - assert_eq!(s.write(&[0]).unwrap(), 1); - assert_eq!(s.write(&[0; 1024]).unwrap(), 1024); - assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024); - } - - #[test] - fn empty_reads() { - let mut e = empty(); - assert_eq!(e.read(&mut []).unwrap(), 0); - assert_eq!(e.read(&mut [0]).unwrap(), 0); - assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0); - assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0); - } - - #[test] - fn repeat_repeats() { - let mut r = repeat(4); - let mut b = [0; 1024]; - assert_eq!(r.read(&mut b).unwrap(), 1024); - assert!(b.iter().all(|b| *b == 4)); - } - - #[test] - fn take_some_bytes() { - assert_eq!(repeat(4).take(100).bytes().count(), 100); - assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4); - assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20); - } -} diff --git a/ctr-std/src/keyword_docs.rs b/ctr-std/src/keyword_docs.rs deleted file mode 100644 index 4f6bda6..0000000 --- a/ctr-std/src/keyword_docs.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[doc(keyword = "fn")] -// -/// The `fn` keyword. -/// -/// The `fn` keyword is used to declare a function. -/// -/// Example: -/// -/// ```rust -/// fn some_function() { -/// // code goes in here -/// } -/// ``` -/// -/// For more information about functions, take a look at the [Rust Book][book]. -/// -/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html -mod fn_keyword { } - -#[doc(keyword = "let")] -// -/// The `let` keyword. -/// -/// The `let` keyword is used to declare a variable. -/// -/// Example: -/// -/// ```rust -/// # #![allow(unused_assignments)] -/// let x = 3; // We create a variable named `x` with the value `3`. -/// ``` -/// -/// By default, all variables are **not** mutable. If you want a mutable variable, -/// you'll have to use the `mut` keyword. -/// -/// Example: -/// -/// ```rust -/// # #![allow(unused_assignments)] -/// let mut x = 3; // We create a mutable variable named `x` with the value `3`. -/// -/// x += 4; // `x` is now equal to `7`. -/// ``` -/// -/// For more information about the `let` keyword, take a look at the [Rust Book][book]. -/// -/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html -mod let_keyword { } diff --git a/ctr-std/src/lib.rs b/ctr-std/src/lib.rs deleted file mode 100644 index 19ea930..0000000 --- a/ctr-std/src/lib.rs +++ /dev/null @@ -1,514 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! # The Rust Standard Library -//! -//! The Rust Standard Library is the foundation of portable Rust software, a -//! set of minimal and battle-tested shared abstractions for the [broader Rust -//! ecosystem][crates.io]. It offers core types, like [`Vec`] and -//! [`Option`], library-defined [operations on language -//! primitives](#primitives), [standard macros](#macros), [I/O] and -//! [multithreading], among [many other things][other]. -//! -//! `std` is available to all Rust crates by default, just as if each one -//! contained an `extern crate std;` import at the [crate root]. Therefore the -//! standard library can be accessed in [`use`] statements through the path -//! `std`, as in [`use std::env`], or in expressions through the absolute path -//! `::std`, as in [`::std::env::args`]. -//! -//! # How to read this documentation -//! -//! If you already know the name of what you are looking for, the fastest way to -//! find it is to use the search -//! bar at the top of the page. -//! -//! Otherwise, you may want to jump to one of these useful sections: -//! -//! * [`std::*` modules](#modules) -//! * [Primitive types](#primitives) -//! * [Standard macros](#macros) -//! * [The Rust Prelude](prelude/index.html) -//! -//! If this is your first time, the documentation for the standard library is -//! written to be casually perused. Clicking on interesting things should -//! generally lead you to interesting places. Still, there are important bits -//! you don't want to miss, so read on for a tour of the standard library and -//! its documentation! -//! -//! Once you are familiar with the contents of the standard library you may -//! begin to find the verbosity of the prose distracting. At this stage in your -//! development you may want to press the `[-]` button near the top of the -//! page to collapse it into a more skimmable view. -//! -//! While you are looking at that `[-]` button also notice the `[src]` -//! button. Rust's API documentation comes with the source code and you are -//! encouraged to read it. The standard library source is generally high -//! quality and a peek behind the curtains is often enlightening. -//! -//! # What is in the standard library documentation? -//! -//! First of all, The Rust Standard Library is divided into a number of focused -//! modules, [all listed further down this page](#modules). These modules are -//! the bedrock upon which all of Rust is forged, and they have mighty names -//! like [`std::slice`] and [`std::cmp`]. Modules' documentation typically -//! includes an overview of the module along with examples, and are a smart -//! place to start familiarizing yourself with the library. -//! -//! Second, implicit methods on [primitive types] are documented here. This can -//! be a source of confusion for two reasons: -//! -//! 1. While primitives are implemented by the compiler, the standard library -//! implements methods directly on the primitive types (and it is the only -//! library that does so), which are [documented in the section on -//! primitives](#primitives). -//! 2. The standard library exports many modules *with the same name as -//! primitive types*. These define additional items related to the primitive -//! type, but not the all-important methods. -//! -//! So for example there is a [page for the primitive type -//! `i32`](primitive.i32.html) that lists all the methods that can be called on -//! 32-bit integers (very useful), and there is a [page for the module -//! `std::i32`](i32/index.html) that documents the constant values [`MIN`] and -//! [`MAX`](i32/constant.MAX.html) (rarely useful). -//! -//! Note the documentation for the primitives [`str`] and [`[T]`][slice] (also -//! called 'slice'). Many method calls on [`String`] and [`Vec`] are actually -//! calls to methods on [`str`] and [`[T]`][slice] respectively, via [deref -//! coercions][deref-coercions]. -//! -//! Third, the standard library defines [The Rust Prelude], a small collection -//! of items - mostly traits - that are imported into every module of every -//! crate. The traits in the prelude are pervasive, making the prelude -//! documentation a good entry point to learning about the library. -//! -//! And finally, the standard library exports a number of standard macros, and -//! [lists them on this page](#macros) (technically, not all of the standard -//! macros are defined by the standard library - some are defined by the -//! compiler - but they are documented here the same). Like the prelude, the -//! standard macros are imported by default into all crates. -//! -//! # Contributing changes to the documentation -//! -//! Check out the rust contribution guidelines [here]( -//! https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md). -//! The source for this documentation can be found on [Github](https://github.com/rust-lang). -//! To contribute changes, make sure you read the guidelines first, then submit -//! pull-requests for your suggested changes. -//! -//! Contributions are appreciated! If you see a part of the docs that can be -//! improved, submit a PR, or chat with us first on irc.mozilla.org #rust-docs. -//! -//! # A Tour of The Rust Standard Library -//! -//! The rest of this crate documentation is dedicated to pointing out notable -//! features of The Rust Standard Library. -//! -//! ## Containers and collections -//! -//! The [`option`] and [`result`] modules define optional and error-handling -//! types, [`Option`] and [`Result`]. The [`iter`] module defines -//! Rust's iterator trait, [`Iterator`], which works with the [`for`] loop to -//! access collections. -//! -//! The standard library exposes three common ways to deal with contiguous -//! regions of memory: -//! -//! * [`Vec`] - A heap-allocated *vector* that is resizable at runtime. -//! * [`[T; n]`][array] - An inline *array* with a fixed size at compile time. -//! * [`[T]`][slice] - A dynamically sized *slice* into any other kind of contiguous -//! storage, whether heap-allocated or not. -//! -//! Slices can only be handled through some kind of *pointer*, and as such come -//! in many flavors such as: -//! -//! * `&[T]` - *shared slice* -//! * `&mut [T]` - *mutable slice* -//! * [`Box<[T]>`][owned slice] - *owned slice* -//! -//! [`str`], a UTF-8 string slice, is a primitive type, and the standard library -//! defines many methods for it. Rust [`str`]s are typically accessed as -//! immutable references: `&str`. Use the owned [`String`] for building and -//! mutating strings. -//! -//! For converting to strings use the [`format!`] macro, and for converting from -//! strings use the [`FromStr`] trait. -//! -//! Data may be shared by placing it in a reference-counted box or the [`Rc`] -//! type, and if further contained in a [`Cell`] or [`RefCell`], may be mutated -//! as well as shared. Likewise, in a concurrent setting it is common to pair an -//! atomically-reference-counted box, [`Arc`], with a [`Mutex`] to get the same -//! effect. -//! -//! The [`collections`] module defines maps, sets, linked lists and other -//! typical collection types, including the common [`HashMap`]. -//! -//! ## Platform abstractions and I/O -//! -//! Besides basic data types, the standard library is largely concerned with -//! abstracting over differences in common platforms, most notably Windows and -//! Unix derivatives. -//! -//! Common types of I/O, including [files], [TCP], [UDP], are defined in the -//! [`io`], [`fs`], and [`net`] modules. -//! -//! The [`thread`] module contains Rust's threading abstractions. [`sync`] -//! contains further primitive shared memory types, including [`atomic`] and -//! [`mpsc`], which contains the channel types for message passing. -//! -//! [I/O]: io/index.html -//! [`MIN`]: i32/constant.MIN.html -//! [TCP]: net/struct.TcpStream.html -//! [The Rust Prelude]: prelude/index.html -//! [UDP]: net/struct.UdpSocket.html -//! [`::std::env::args`]: env/fn.args.html -//! [`Arc`]: sync/struct.Arc.html -//! [owned slice]: boxed/index.html -//! [`Cell`]: cell/struct.Cell.html -//! [`FromStr`]: str/trait.FromStr.html -//! [`HashMap`]: collections/struct.HashMap.html -//! [`Iterator`]: iter/trait.Iterator.html -//! [`Mutex`]: sync/struct.Mutex.html -//! [`Option`]: option/enum.Option.html -//! [`Rc`]: rc/index.html -//! [`RefCell`]: cell/struct.RefCell.html -//! [`Result`]: result/enum.Result.html -//! [`String`]: string/struct.String.html -//! [`Vec`]: vec/index.html -//! [array]: primitive.array.html -//! [slice]: primitive.slice.html -//! [`atomic`]: sync/atomic/index.html -//! [`collections`]: collections/index.html -//! [`for`]: ../book/first-edition/loops.html#for -//! [`format!`]: macro.format.html -//! [`fs`]: fs/index.html -//! [`io`]: io/index.html -//! [`iter`]: iter/index.html -//! [`mpsc`]: sync/mpsc/index.html -//! [`net`]: net/index.html -//! [`option`]: option/index.html -//! [`result`]: result/index.html -//! [`std::cmp`]: cmp/index.html -//! [`std::slice`]: slice/index.html -//! [`str`]: primitive.str.html -//! [`sync`]: sync/index.html -//! [`thread`]: thread/index.html -//! [`use std::env`]: env/index.html -//! [`use`]: ../book/first-edition/crates-and-modules.html#importing-modules-with-use -//! [crate root]: ../book/first-edition/crates-and-modules.html#basic-terminology-crates-and-modules -//! [crates.io]: https://crates.io -//! [deref-coercions]: ../book/second-edition/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods -//! [files]: fs/struct.File.html -//! [multithreading]: thread/index.html -//! [other]: #what-is-in-the-standard-library-documentation -//! [primitive types]: ../book/first-edition/primitive-types.html - -#![stable(feature = "rust1", since = "1.0.0")] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", - test(no_crate_inject, attr(deny(warnings))), - test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] - -// Don't link to std. We are std. -#![no_std] - -#![deny(missing_docs)] -#![deny(missing_debug_implementations)] - -// Tell the compiler to link to either panic_abort or panic_unwind -#![needs_panic_runtime] - -// std may use features in a platform-specific way -#![allow(unused_features)] - -// std is implemented with unstable features, many of which are internal -// compiler details that will never be stable -#![cfg_attr(test, feature(test, update_panic_count))] -#![feature(alloc)] -#![feature(alloc_error_handler)] -#![feature(allocator_api)] -#![feature(allocator_internals)] -#![feature(allow_internal_unsafe)] -#![feature(allow_internal_unstable)] -#![feature(align_offset)] -#![feature(arbitrary_self_types)] -#![feature(array_error_internals)] -#![feature(asm)] -#![feature(attr_literals)] -#![feature(box_syntax)] -#![feature(cfg_target_has_atomic)] -#![feature(cfg_target_thread_local)] -#![feature(cfg_target_vendor)] -#![feature(char_error_internals)] -#![feature(compiler_builtins_lib)] -#![feature(const_fn)] -#![feature(const_int_ops)] -#![feature(const_ip)] -#![feature(core_intrinsics)] -#![feature(dropck_eyepatch)] -#![feature(exact_size_is_empty)] -#![feature(external_doc)] -#![feature(fixed_size_array)] -#![feature(fn_traits)] -#![feature(fnbox)] -#![feature(futures_api)] -#![feature(generator_trait)] -#![feature(hashmap_internals)] -#![feature(int_error_internals)] -#![feature(integer_atomics)] -#![feature(lang_items)] -#![feature(libc)] -#![feature(link_args)] -#![feature(linkage)] -#![feature(macro_vis_matcher)] -#![feature(needs_panic_runtime)] -#![feature(never_type)] -#![cfg_attr(not(stage0), feature(nll))] -#![feature(exhaustive_patterns)] -#![feature(on_unimplemented)] -#![feature(optin_builtin_traits)] -#![feature(panic_internals)] -#![feature(panic_unwind)] -#![feature(pin)] -#![feature(prelude_import)] -#![feature(ptr_internals)] -#![feature(raw)] -#![feature(rustc_attrs)] -#![feature(rustc_const_unstable)] -#![feature(std_internals)] -#![feature(stdsimd)] -#![feature(shrink_to)] -#![feature(slice_concat_ext)] -#![feature(slice_internals)] -#![feature(slice_patterns)] -#![feature(staged_api)] -#![feature(stmt_expr_attributes)] -#![feature(str_internals)] -#![feature(rustc_private)] -#![feature(thread_local)] -#![feature(toowned_clone_into)] -#![feature(try_from)] -#![feature(try_reserve)] -#![feature(unboxed_closures)] -#![feature(untagged_unions)] -#![feature(unwind_attributes)] -#![cfg_attr(stage0, feature(use_extern_macros))] -#![feature(doc_cfg)] -#![feature(doc_masked)] -#![feature(doc_spotlight)] -#![cfg_attr(windows, feature(used))] -#![feature(doc_alias)] -#![feature(doc_keyword)] -#![feature(panic_info_message)] -#![feature(panic_implementation)] -#![feature(non_exhaustive)] - -#![default_lib_allocator] - -// Always use alloc_system during stage0 since we don't know if the alloc_* -// crate the stage0 compiler will pick by default is enabled (e.g. -// if the user has disabled jemalloc in `./configure`). -// `force_alloc_system` is *only* intended as a workaround for local rebuilds -// with a rustc without jemalloc. -// FIXME(#44236) shouldn't need MSVC logic -#[cfg(all(not(target_env = "msvc"), - any(all(stage0, not(test)), feature = "force_alloc_system")))] -#[global_allocator] -static ALLOC: alloc_system::System = alloc_system::System; - -// Explicitly import the prelude. The compiler uses this same unstable attribute -// to import the prelude implicitly when building crates that depend on std. -#[prelude_import] -#[allow(unused)] -use prelude::v1::*; - -// Access to Bencher, etc. -#[cfg(test)] extern crate test; -#[cfg(test)] extern crate rand; - -// Re-export a few macros from core -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::{unreachable, unimplemented, write, writeln, try}; - -#[allow(unused_imports)] // macros from `alloc` are not used on all platforms -#[macro_use] -extern crate alloc as alloc_crate; -extern crate alloc_system; -#[doc(masked)] -extern crate libc; - -// 3DS-specific dependency -extern crate ctru_sys as libctru; - -// We always need an unwinder currently for backtraces -#[doc(masked)] -#[allow(unused_extern_crates)] -extern crate unwind; - -// During testing, this crate is not actually the "real" std library, but rather -// it links to the real std library, which was compiled from this same source -// code. So any lang items std defines are conditionally excluded (or else they -// would generate duplicate lang item errors), and any globals it defines are -// _not_ the globals used by "real" std. So this import, defined only during -// testing gives test-std access to real-std lang items and globals. See #2912 -#[cfg(test)] extern crate std as realstd; - -// The standard macros that are not built-in to the compiler. -#[macro_use] -mod macros; - -// The Rust prelude -pub mod prelude; - -// Public module declarations and re-exports -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::any; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::cell; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::clone; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::cmp; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::convert; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::default; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::hash; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::intrinsics; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::iter; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::marker; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::mem; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::ops; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::ptr; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::raw; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::result; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::option; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::isize; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::i8; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::i16; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::i32; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::i64; -#[stable(feature = "i128", since = "1.26.0")] -pub use core::i128; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::usize; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::u8; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::u16; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::u32; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::u64; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::boxed; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::rc; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::borrow; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::fmt; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::format; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::slice; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::str; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::string; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::vec; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::char; -#[stable(feature = "i128", since = "1.26.0")] -pub use core::u128; -#[stable(feature = "core_hint", since = "1.27.0")] -pub use core::hint; - -pub mod f32; -pub mod f64; - -#[macro_use] -pub mod thread; -pub mod ascii; -pub mod collections; -pub mod env; -pub mod error; -pub mod ffi; -pub mod fs; -pub mod io; -pub mod net; -pub mod num; -pub mod os; -pub mod panic; -pub mod path; -pub mod process; -pub mod sync; -pub mod time; - -#[unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] -pub mod task { - //! Types and Traits for working with asynchronous tasks. - #[doc(inline)] - pub use core::task::*; - #[doc(inline)] - pub use alloc_crate::task::*; -} - -#[unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] -pub mod future; - -// Platform-abstraction modules -#[macro_use] -mod sys_common; -mod sys; - -pub mod alloc; - -// Private support modules -mod panicking; -mod memchr; - -// The runtime entry point and a few unstable public functions used by the -// compiler -pub mod rt; - -// Include a number of private modules that exist solely to provide -// the rustdoc documentation for primitive types. Using `include!` -// because rustdoc only looks for these modules at the crate level. -include!("primitive_docs.rs"); - -// Include a number of private modules that exist solely to provide -// the rustdoc documentation for the existing keywords. Using `include!` -// because rustdoc only looks for these modules at the crate level. -include!("keyword_docs.rs"); diff --git a/ctr-std/src/macros.rs b/ctr-std/src/macros.rs deleted file mode 100644 index f15494c..0000000 --- a/ctr-std/src/macros.rs +++ /dev/null @@ -1,871 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Standard library macros -//! -//! This modules contains a set of macros which are exported from the standard -//! library. Each macro is available for use when linking against the standard -//! library. - -/// The entry point for panic of Rust threads. -/// -/// This allows a program to to terminate immediately and provide feedback -/// to the caller of the program. `panic!` should be used when a program reaches -/// an unrecoverable problem. -/// -/// This macro is the perfect way to assert conditions in example code and in -/// tests. `panic!` is closely tied with the `unwrap` method of both [`Option`] -/// and [`Result`][runwrap] enums. Both implementations call `panic!` when they are set -/// to None or Err variants. -/// -/// This macro is used to inject panic into a Rust thread, causing the thread to -/// panic entirely. Each thread's panic can be reaped as the `Box` type, -/// and the single-argument form of the `panic!` macro will be the value which -/// is transmitted. -/// -/// [`Result`] enum is often a better solution for recovering from errors than -/// using the `panic!` macro. This macro should be used to avoid proceeding using -/// incorrect values, such as from external sources. Detailed information about -/// error handling is found in the [book]. -/// -/// The multi-argument form of this macro panics with a string and has the -/// [`format!`] syntax for building a string. -/// -/// See also the macro [`compile_error!`], for raising errors during compilation. -/// -/// [runwrap]: ../std/result/enum.Result.html#method.unwrap -/// [`Option`]: ../std/option/enum.Option.html#method.unwrap -/// [`Result`]: ../std/result/enum.Result.html -/// [`format!`]: ../std/macro.format.html -/// [`compile_error!`]: ../std/macro.compile_error.html -/// [book]: ../book/second-edition/ch09-01-unrecoverable-errors-with-panic.html -/// -/// # Current implementation -/// -/// If the main thread panics it will terminate all your threads and end your -/// program with code `101`. -/// -/// # Examples -/// -/// ```should_panic -/// # #![allow(unreachable_code)] -/// panic!(); -/// panic!("this is a terrible mistake!"); -/// panic!(4); // panic with the value of 4 to be collected elsewhere -/// panic!("this is a {} {message}", "fancy", message = "message"); -/// ``` -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable] -macro_rules! panic { - () => ({ - panic!("explicit panic") - }); - ($msg:expr) => ({ - $crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!())) - }); - ($msg:expr,) => ({ - panic!($msg) - }); - ($fmt:expr, $($arg:tt)+) => ({ - $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), - &(file!(), line!(), __rust_unstable_column!())) - }); -} - -/// Macro for printing to the standard output. -/// -/// Equivalent to the [`println!`] macro except that a newline is not printed at -/// the end of the message. -/// -/// Note that stdout is frequently line-buffered by default so it may be -/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted -/// immediately. -/// -/// Use `print!` only for the primary output of your program. Use -/// [`eprint!`] instead to print error and progress messages. -/// -/// [`println!`]: ../std/macro.println.html -/// [flush]: ../std/io/trait.Write.html#tymethod.flush -/// [`eprint!`]: ../std/macro.eprint.html -/// -/// # Panics -/// -/// Panics if writing to `io::stdout()` fails. -/// -/// # Examples -/// -/// ``` -/// use std::io::{self, Write}; -/// -/// print!("this "); -/// print!("will "); -/// print!("be "); -/// print!("on "); -/// print!("the "); -/// print!("same "); -/// print!("line "); -/// -/// io::stdout().flush().unwrap(); -/// -/// print!("this string has a newline, why not choose println! instead?\n"); -/// -/// io::stdout().flush().unwrap(); -/// ``` -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable] -macro_rules! print { - ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*))); -} - -/// Macro for printing to the standard output, with a newline. -/// -/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone -/// (no additional CARRIAGE RETURN (`\r`/`U+000D`). -/// -/// Use the [`format!`] syntax to write data to the standard output. -/// See [`std::fmt`] for more information. -/// -/// Use `println!` only for the primary output of your program. Use -/// [`eprintln!`] instead to print error and progress messages. -/// -/// [`format!`]: ../std/macro.format.html -/// [`std::fmt`]: ../std/fmt/index.html -/// [`eprintln!`]: ../std/macro.eprint.html -/// # Panics -/// -/// Panics if writing to `io::stdout` fails. -/// -/// # Examples -/// -/// ``` -/// println!(); // prints just a newline -/// println!("hello there!"); -/// println!("format {} arguments", "some"); -/// ``` -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable] -macro_rules! println { - () => (print!("\n")); - ($($arg:tt)*) => ({ - $crate::io::_print(format_args_nl!($($arg)*)); - }) -} - -/// Macro for printing to the standard error. -/// -/// Equivalent to the [`print!`] macro, except that output goes to -/// [`io::stderr`] instead of `io::stdout`. See [`print!`] for -/// example usage. -/// -/// Use `eprint!` only for error and progress messages. Use `print!` -/// instead for the primary output of your program. -/// -/// [`io::stderr`]: ../std/io/struct.Stderr.html -/// [`print!`]: ../std/macro.print.html -/// -/// # Panics -/// -/// Panics if writing to `io::stderr` fails. -/// -/// # Examples -/// -/// ``` -/// eprint!("Error: Could not complete task"); -/// ``` -#[macro_export] -#[stable(feature = "eprint", since = "1.19.0")] -#[allow_internal_unstable] -macro_rules! eprint { - ($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*))); -} - -/// Macro for printing to the standard error, with a newline. -/// -/// Equivalent to the [`println!`] macro, except that output goes to -/// [`io::stderr`] instead of `io::stdout`. See [`println!`] for -/// example usage. -/// -/// Use `eprintln!` only for error and progress messages. Use `println!` -/// instead for the primary output of your program. -/// -/// [`io::stderr`]: ../std/io/struct.Stderr.html -/// [`println!`]: ../std/macro.println.html -/// -/// # Panics -/// -/// Panics if writing to `io::stderr` fails. -/// -/// # Examples -/// -/// ``` -/// eprintln!("Error: Could not complete task"); -/// ``` -#[macro_export] -#[stable(feature = "eprint", since = "1.19.0")] -#[allow_internal_unstable] -macro_rules! eprintln { - () => (eprint!("\n")); - ($($arg:tt)*) => ({ - $crate::io::_eprint(format_args_nl!($($arg)*)); - }) -} - -#[macro_export] -#[unstable(feature = "await_macro", issue = "50547")] -#[allow_internal_unstable] -#[allow_internal_unsafe] -macro_rules! await { - ($e:expr) => { { - let mut pinned = $e; - loop { - if let $crate::task::Poll::Ready(x) = - $crate::future::poll_in_task_cx(unsafe { - $crate::mem::PinMut::new_unchecked(&mut pinned) - }) - { - break x; - } - // FIXME(cramertj) prior to stabilizing await, we have to ensure that this - // can't be used to create a generator on stable via `|| await!()`. - yield - } - } } -} - -/// A macro to select an event from a number of receivers. -/// -/// This macro is used to wait for the first event to occur on a number of -/// receivers. It places no restrictions on the types of receivers given to -/// this macro, this can be viewed as a heterogeneous select. -/// -/// # Examples -/// -/// ``` -/// #![feature(mpsc_select)] -/// -/// use std::thread; -/// use std::sync::mpsc; -/// -/// // two placeholder functions for now -/// fn long_running_thread() {} -/// fn calculate_the_answer() -> u32 { 42 } -/// -/// let (tx1, rx1) = mpsc::channel(); -/// let (tx2, rx2) = mpsc::channel(); -/// -/// thread::spawn(move|| { long_running_thread(); tx1.send(()).unwrap(); }); -/// thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); }); -/// -/// select! { -/// _ = rx1.recv() => println!("the long running thread finished first"), -/// answer = rx2.recv() => { -/// println!("the answer was: {}", answer.unwrap()); -/// } -/// } -/// # drop(rx1.recv()); -/// # drop(rx2.recv()); -/// ``` -/// -/// For more information about select, see the `std::sync::mpsc::Select` structure. -#[macro_export] -#[unstable(feature = "mpsc_select", issue = "27800")] -macro_rules! select { - ( - $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ - ) => ({ - use $crate::sync::mpsc::Select; - let sel = Select::new(); - $( let mut $rx = sel.handle(&$rx); )+ - unsafe { - $( $rx.add(); )+ - } - let ret = sel.wait(); - $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+ - { unreachable!() } - }) -} - -#[cfg(test)] -macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => ({ - let (a, b) = (&$a, &$b); - assert!((*a - *b).abs() < 1.0e-6, - "{} is not approximately equal to {}", *a, *b); - }) -} - -/// Built-in macros to the compiler itself. -/// -/// These macros do not have any corresponding definition with a `macro_rules!` -/// macro, but are documented here. Their implementations can be found hardcoded -/// into libsyntax itself. -#[cfg(dox)] -mod builtin { - - /// Unconditionally causes compilation to fail with the given error message when encountered. - /// - /// This macro should be used when a crate uses a conditional compilation strategy to provide - /// better error messages for erroneous conditions. It's the compiler-level form of [`panic!`], - /// which emits an error at *runtime*, rather than during compilation. - /// - /// # Examples - /// - /// Two such examples are macros and `#[cfg]` environments. - /// - /// Emit better compiler error if a macro is passed invalid values. Without the final branch, - /// the compiler would still emit an error, but the error's message would not mention the two - /// valid values. - /// - /// ```compile_fail - /// macro_rules! give_me_foo_or_bar { - /// (foo) => {}; - /// (bar) => {}; - /// ($x:ident) => { - /// compile_error!("This macro only accepts `foo` or `bar`"); - /// } - /// } - /// - /// give_me_foo_or_bar!(neither); - /// // ^ will fail at compile time with message "This macro only accepts `foo` or `bar`" - /// ``` - /// - /// Emit compiler error if one of a number of features isn't available. - /// - /// ```compile_fail - /// #[cfg(not(any(feature = "foo", feature = "bar")))] - /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.") - /// ``` - /// - /// [`panic!`]: ../std/macro.panic.html - #[stable(feature = "compile_error_macro", since = "1.20.0")] - #[rustc_doc_only_macro] - macro_rules! compile_error { - ($msg:expr) => ({ /* compiler built-in */ }); - ($msg:expr,) => ({ /* compiler built-in */ }); - } - - /// The core macro for formatted string creation & output. - /// - /// This macro functions by taking a formatting string literal containing - /// `{}` for each additional argument passed. `format_args!` prepares the - /// additional parameters to ensure the output can be interpreted as a string - /// and canonicalizes the arguments into a single type. Any value that implements - /// the [`Display`] trait can be passed to `format_args!`, as can any - /// [`Debug`] implementation be passed to a `{:?}` within the formatting string. - /// - /// This macro produces a value of type [`fmt::Arguments`]. This value can be - /// passed to the macros within [`std::fmt`] for performing useful redirection. - /// All other formatting macros ([`format!`], [`write!`], [`println!`], etc) are - /// proxied through this one. `format_args!`, unlike its derived macros, avoids - /// heap allocations. - /// - /// You can use the [`fmt::Arguments`] value that `format_args!` returns - /// in `Debug` and `Display` contexts as seen below. The example also shows - /// that `Debug` and `Display` format to the same thing: the interpolated - /// format string in `format_args!`. - /// - /// ```rust - /// let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); - /// let display = format!("{}", format_args!("{} foo {:?}", 1, 2)); - /// assert_eq!("1 foo 2", display); - /// assert_eq!(display, debug); - /// ``` - /// - /// For more information, see the documentation in [`std::fmt`]. - /// - /// [`Display`]: ../std/fmt/trait.Display.html - /// [`Debug`]: ../std/fmt/trait.Debug.html - /// [`fmt::Arguments`]: ../std/fmt/struct.Arguments.html - /// [`std::fmt`]: ../std/fmt/index.html - /// [`format!`]: ../std/macro.format.html - /// [`write!`]: ../std/macro.write.html - /// [`println!`]: ../std/macro.println.html - /// - /// # Examples - /// - /// ``` - /// use std::fmt; - /// - /// let s = fmt::format(format_args!("hello {}", "world")); - /// assert_eq!(s, format!("hello {}", "world")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! format_args { - ($fmt:expr) => ({ /* compiler built-in */ }); - ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); - } - - /// Inspect an environment variable at compile time. - /// - /// This macro will expand to the value of the named environment variable at - /// compile time, yielding an expression of type `&'static str`. - /// - /// If the environment variable is not defined, then a compilation error - /// will be emitted. To not emit a compile error, use the [`option_env!`] - /// macro instead. - /// - /// [`option_env!`]: ../std/macro.option_env.html - /// - /// # Examples - /// - /// ``` - /// let path: &'static str = env!("PATH"); - /// println!("the $PATH variable at the time of compiling was: {}", path); - /// ``` - /// - /// You can customize the error message by passing a string as the second - /// parameter: - /// - /// ```compile_fail - /// let doc: &'static str = env!("documentation", "what's that?!"); - /// ``` - /// - /// If the `documentation` environment variable is not defined, you'll get - /// the following error: - /// - /// ```text - /// error: what's that?! - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! env { - ($name:expr) => ({ /* compiler built-in */ }); - ($name:expr,) => ({ /* compiler built-in */ }); - } - - /// Optionally inspect an environment variable at compile time. - /// - /// If the named environment variable is present at compile time, this will - /// expand into an expression of type `Option<&'static str>` whose value is - /// `Some` of the value of the environment variable. If the environment - /// variable is not present, then this will expand to `None`. See - /// [`Option`][option] for more information on this type. - /// - /// A compile time error is never emitted when using this macro regardless - /// of whether the environment variable is present or not. - /// - /// [option]: ../std/option/enum.Option.html - /// - /// # Examples - /// - /// ``` - /// let key: Option<&'static str> = option_env!("SECRET_KEY"); - /// println!("the secret key might be: {:?}", key); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! option_env { - ($name:expr) => ({ /* compiler built-in */ }); - ($name:expr,) => ({ /* compiler built-in */ }); - } - - /// Concatenate identifiers into one identifier. - /// - /// This macro takes any number of comma-separated identifiers, and - /// concatenates them all into one, yielding an expression which is a new - /// identifier. Note that hygiene makes it such that this macro cannot - /// capture local variables. Also, as a general rule, macros are only - /// allowed in item, statement or expression position. That means while - /// you may use this macro for referring to existing variables, functions or - /// modules etc, you cannot define a new one with it. - /// - /// # Examples - /// - /// ``` - /// #![feature(concat_idents)] - /// - /// # fn main() { - /// fn foobar() -> u32 { 23 } - /// - /// let f = concat_idents!(foo, bar); - /// println!("{}", f()); - /// - /// // fn concat_idents!(new, fun, name) { } // not usable in this way! - /// # } - /// ``` - #[unstable(feature = "concat_idents_macro", issue = "29599")] - #[rustc_doc_only_macro] - macro_rules! concat_idents { - ($($e:ident),+) => ({ /* compiler built-in */ }); - ($($e:ident,)+) => ({ /* compiler built-in */ }); - } - - /// Concatenates literals into a static string slice. - /// - /// This macro takes any number of comma-separated literals, yielding an - /// expression of type `&'static str` which represents all of the literals - /// concatenated left-to-right. - /// - /// Integer and floating point literals are stringified in order to be - /// concatenated. - /// - /// # Examples - /// - /// ``` - /// let s = concat!("test", 10, 'b', true); - /// assert_eq!(s, "test10btrue"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! concat { - ($($e:expr),*) => ({ /* compiler built-in */ }); - ($($e:expr,)*) => ({ /* compiler built-in */ }); - } - - /// A macro which expands to the line number on which it was invoked. - /// - /// With [`column!`] and [`file!`], these macros provide debugging information for - /// developers about the location within the source. - /// - /// The expanded expression has type `u32` and is 1-based, so the first line - /// in each file evaluates to 1, the second to 2, etc. This is consistent - /// with error messages by common compilers or popular editors. - /// The returned line is *not necessarily* the line of the `line!` invocation itself, - /// but rather the first macro invocation leading up to the invocation - /// of the `line!` macro. - /// - /// [`column!`]: macro.column.html - /// [`file!`]: macro.file.html - /// - /// # Examples - /// - /// ``` - /// let current_line = line!(); - /// println!("defined on line: {}", current_line); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! line { () => ({ /* compiler built-in */ }) } - - /// A macro which expands to the column number on which it was invoked. - /// - /// With [`line!`] and [`file!`], these macros provide debugging information for - /// developers about the location within the source. - /// - /// The expanded expression has type `u32` and is 1-based, so the first column - /// in each line evaluates to 1, the second to 2, etc. This is consistent - /// with error messages by common compilers or popular editors. - /// The returned column is *not necessarily* the line of the `column!` invocation itself, - /// but rather the first macro invocation leading up to the invocation - /// of the `column!` macro. - /// - /// [`line!`]: macro.line.html - /// [`file!`]: macro.file.html - /// - /// # Examples - /// - /// ``` - /// let current_col = column!(); - /// println!("defined on column: {}", current_col); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! column { () => ({ /* compiler built-in */ }) } - - /// A macro which expands to the file name from which it was invoked. - /// - /// With [`line!`] and [`column!`], these macros provide debugging information for - /// developers about the location within the source. - /// - /// - /// The expanded expression has type `&'static str`, and the returned file - /// is not the invocation of the `file!` macro itself, but rather the - /// first macro invocation leading up to the invocation of the `file!` - /// macro. - /// - /// [`line!`]: macro.line.html - /// [`column!`]: macro.column.html - /// - /// # Examples - /// - /// ``` - /// let this_file = file!(); - /// println!("defined in file: {}", this_file); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! file { () => ({ /* compiler built-in */ }) } - - /// A macro which stringifies its arguments. - /// - /// This macro will yield an expression of type `&'static str` which is the - /// stringification of all the tokens passed to the macro. No restrictions - /// are placed on the syntax of the macro invocation itself. - /// - /// Note that the expanded results of the input tokens may change in the - /// future. You should be careful if you rely on the output. - /// - /// # Examples - /// - /// ``` - /// let one_plus_one = stringify!(1 + 1); - /// assert_eq!(one_plus_one, "1 + 1"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) } - - /// Includes a utf8-encoded file as a string. - /// - /// The file is located relative to the current file. (similarly to how - /// modules are found) - /// - /// This macro will yield an expression of type `&'static str` which is the - /// contents of the file. - /// - /// # Examples - /// - /// Assume there are two files in the same directory with the following - /// contents: - /// - /// File 'spanish.in': - /// - /// ```text - /// adiós - /// ``` - /// - /// File 'main.rs': - /// - /// ```ignore (cannot-doctest-external-file-dependency) - /// fn main() { - /// let my_str = include_str!("spanish.in"); - /// assert_eq!(my_str, "adiós\n"); - /// print!("{}", my_str); - /// } - /// ``` - /// - /// Compiling 'main.rs' and running the resulting binary will print "adiós". - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! include_str { - ($file:expr) => ({ /* compiler built-in */ }); - ($file:expr,) => ({ /* compiler built-in */ }); - } - - /// Includes a file as a reference to a byte array. - /// - /// The file is located relative to the current file. (similarly to how - /// modules are found) - /// - /// This macro will yield an expression of type `&'static [u8; N]` which is - /// the contents of the file. - /// - /// # Examples - /// - /// Assume there are two files in the same directory with the following - /// contents: - /// - /// File 'spanish.in': - /// - /// ```text - /// adiós - /// ``` - /// - /// File 'main.rs': - /// - /// ```ignore (cannot-doctest-external-file-dependency) - /// fn main() { - /// let bytes = include_bytes!("spanish.in"); - /// assert_eq!(bytes, b"adi\xc3\xb3s\n"); - /// print!("{}", String::from_utf8_lossy(bytes)); - /// } - /// ``` - /// - /// Compiling 'main.rs' and running the resulting binary will print "adiós". - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! include_bytes { - ($file:expr) => ({ /* compiler built-in */ }); - ($file:expr,) => ({ /* compiler built-in */ }); - } - - /// Expands to a string that represents the current module path. - /// - /// The current module path can be thought of as the hierarchy of modules - /// leading back up to the crate root. The first component of the path - /// returned is the name of the crate currently being compiled. - /// - /// # Examples - /// - /// ``` - /// mod test { - /// pub fn foo() { - /// assert!(module_path!().ends_with("test")); - /// } - /// } - /// - /// test::foo(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! module_path { () => ({ /* compiler built-in */ }) } - - /// Boolean evaluation of configuration flags, at compile-time. - /// - /// In addition to the `#[cfg]` attribute, this macro is provided to allow - /// boolean expression evaluation of configuration flags. This frequently - /// leads to less duplicated code. - /// - /// The syntax given to this macro is the same syntax as [the `cfg` - /// attribute](../book/first-edition/conditional-compilation.html). - /// - /// # Examples - /// - /// ``` - /// let my_directory = if cfg!(windows) { - /// "windows-specific-directory" - /// } else { - /// "unix-directory" - /// }; - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } - - /// Parse a file as an expression or an item according to the context. - /// - /// The file is located relative to the current file (similarly to how - /// modules are found). - /// - /// Using this macro is often a bad idea, because if the file is - /// parsed as an expression, it is going to be placed in the - /// surrounding code unhygienically. This could result in variables - /// or functions being different from what the file expected if - /// there are variables or functions that have the same name in - /// the current file. - /// - /// # Examples - /// - /// Assume there are two files in the same directory with the following - /// contents: - /// - /// File 'monkeys.in': - /// - /// ```ignore (only-for-syntax-highlight) - /// ['🙈', '🙊', '🙉'] - /// .iter() - /// .cycle() - /// .take(6) - /// .collect::() - /// ``` - /// - /// File 'main.rs': - /// - /// ```ignore (cannot-doctest-external-file-dependency) - /// fn main() { - /// let my_string = include!("monkeys.in"); - /// assert_eq!("🙈🙊🙉🙈🙊🙉", my_string); - /// println!("{}", my_string); - /// } - /// ``` - /// - /// Compiling 'main.rs' and running the resulting binary will print - /// "🙈🙊🙉🙈🙊🙉". - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! include { - ($file:expr) => ({ /* compiler built-in */ }); - ($file:expr,) => ({ /* compiler built-in */ }); - } - - /// Ensure that a boolean expression is `true` at runtime. - /// - /// This will invoke the [`panic!`] macro if the provided expression cannot be - /// evaluated to `true` at runtime. - /// - /// # Uses - /// - /// Assertions are always checked in both debug and release builds, and cannot - /// be disabled. See [`debug_assert!`] for assertions that are not enabled in - /// release builds by default. - /// - /// Unsafe code relies on `assert!` to enforce run-time invariants that, if - /// violated could lead to unsafety. - /// - /// Other use-cases of `assert!` include [testing] and enforcing run-time - /// invariants in safe code (whose violation cannot result in unsafety). - /// - /// # Custom Messages - /// - /// This macro has a second form, where a custom panic message can - /// be provided with or without arguments for formatting. See [`std::fmt`] - /// for syntax for this form. - /// - /// [`panic!`]: macro.panic.html - /// [`debug_assert!`]: macro.debug_assert.html - /// [testing]: ../book/second-edition/ch11-01-writing-tests.html#checking-results-with-the-assert-macro - /// [`std::fmt`]: ../std/fmt/index.html - /// - /// # Examples - /// - /// ``` - /// // the panic message for these assertions is the stringified value of the - /// // expression given. - /// assert!(true); - /// - /// fn some_computation() -> bool { true } // a very simple function - /// - /// assert!(some_computation()); - /// - /// // assert with a custom message - /// let x = true; - /// assert!(x, "x wasn't true!"); - /// - /// let a = 3; let b = 27; - /// assert!(a + b == 30, "a = {}, b = {}", a, b); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_doc_only_macro] - macro_rules! assert { - ($cond:expr) => ({ /* compiler built-in */ }); - ($cond:expr,) => ({ /* compiler built-in */ }); - ($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ }); - } -} - -/// A macro for defining `#[cfg]` if-else statements. -/// -/// This is similar to the `if/elif` C preprocessor macro by allowing definition -/// of a cascade of `#[cfg]` cases, emitting the implementation which matches -/// first. -/// -/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code -/// without having to rewrite each clause multiple times. -macro_rules! cfg_if { - ($( - if #[cfg($($meta:meta),*)] { $($it:item)* } - ) else * else { - $($it2:item)* - }) => { - __cfg_if_items! { - () ; - $( ( ($($meta),*) ($($it)*) ), )* - ( () ($($it2)*) ), - } - } -} - -macro_rules! __cfg_if_items { - (($($not:meta,)*) ; ) => {}; - (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { - __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* } - __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* } - } -} - -macro_rules! __cfg_if_apply { - ($m:meta, $($it:item)*) => { - $(#[$m] $it)* - } -} diff --git a/ctr-std/src/memchr.rs b/ctr-std/src/memchr.rs deleted file mode 100644 index 240e820..0000000 --- a/ctr-std/src/memchr.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// Original implementation taken from rust-memchr -// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch - -/// A safe interface to `memchr`. -/// -/// Returns the index corresponding to the first occurrence of `needle` in -/// `haystack`, or `None` if one is not found. -/// -/// memchr reduces to super-optimized machine code at around an order of -/// magnitude faster than `haystack.iter().position(|&b| b == needle)`. -/// (See benchmarks.) -/// -/// # Examples -/// -/// This shows how to find the first position of a byte in a byte string. -/// -/// ```ignore (cannot-doctest-private-modules) -/// use memchr::memchr; -/// -/// let haystack = b"the quick brown fox"; -/// assert_eq!(memchr(b'k', haystack), Some(8)); -/// ``` -#[inline] -pub fn memchr(needle: u8, haystack: &[u8]) -> Option { - ::sys::memchr::memchr(needle, haystack) -} - -/// A safe interface to `memrchr`. -/// -/// Returns the index corresponding to the last occurrence of `needle` in -/// `haystack`, or `None` if one is not found. -/// -/// # Examples -/// -/// This shows how to find the last position of a byte in a byte string. -/// -/// ```ignore (cannot-doctest-private-modules) -/// use memchr::memrchr; -/// -/// let haystack = b"the quick brown fox"; -/// assert_eq!(memrchr(b'o', haystack), Some(17)); -/// ``` -#[inline] -pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { - ::sys::memchr::memrchr(needle, haystack) -} - -#[cfg(test)] -mod tests { - // test the implementations for the current plattform - use super::{memchr, memrchr}; - - #[test] - fn matches_one() { - assert_eq!(Some(0), memchr(b'a', b"a")); - } - - #[test] - fn matches_begin() { - assert_eq!(Some(0), memchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end() { - assert_eq!(Some(4), memchr(b'z', b"aaaaz")); - } - - #[test] - fn matches_nul() { - assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul() { - assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); - } - - #[test] - fn no_match_empty() { - assert_eq!(None, memchr(b'a', b"")); - } - - #[test] - fn no_match() { - assert_eq!(None, memchr(b'a', b"xyz")); - } - - #[test] - fn matches_one_reversed() { - assert_eq!(Some(0), memrchr(b'a', b"a")); - } - - #[test] - fn matches_begin_reversed() { - assert_eq!(Some(3), memrchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); - } - - #[test] - fn matches_nul_reversed() { - assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); - } - - #[test] - fn no_match_empty_reversed() { - assert_eq!(None, memrchr(b'a', b"")); - } - - #[test] - fn no_match_reversed() { - assert_eq!(None, memrchr(b'a', b"xyz")); - } - - #[test] - fn each_alignment() { - let mut data = [1u8; 64]; - let needle = 2; - let pos = 40; - data[pos] = needle; - for start in 0..16 { - assert_eq!(Some(pos - start), memchr(needle, &data[start..])); - } - } -} diff --git a/ctr-std/src/net/addr.rs b/ctr-std/src/net/addr.rs deleted file mode 100644 index e80c3ee..0000000 --- a/ctr-std/src/net/addr.rs +++ /dev/null @@ -1,1077 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use fmt; -use hash; -use io; -use mem; -use net::{ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr}; -use option; -use sys::net::netc as c; -use sys_common::{FromInner, AsInner, IntoInner}; -use sys_common::net::lookup_host; -use vec; -use iter; -use slice; - -/// An internet socket address, either IPv4 or IPv6. -/// -/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well -/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and -/// [`SocketAddrV6`]'s respective documentation for more details. -/// -/// The size of a `SocketAddr` instance may vary depending on the target operating -/// system. -/// -/// [IP address]: ../../std/net/enum.IpAddr.html -/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html -/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html -/// -/// # Examples -/// -/// ``` -/// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -/// -/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); -/// -/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); -/// assert_eq!(socket.port(), 8080); -/// assert_eq!(socket.is_ipv4(), true); -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub enum SocketAddr { - /// An IPv4 socket address. - #[stable(feature = "rust1", since = "1.0.0")] - V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4), - /// An IPv6 socket address. - #[stable(feature = "rust1", since = "1.0.0")] - V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6), -} - -/// An IPv4 socket address. -/// -/// IPv4 socket addresses consist of an [IPv4 address] and a 16-bit port number, as -/// stated in [IETF RFC 793]. -/// -/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. -/// -/// The size of a `SocketAddrV4` struct may vary depending on the target operating -/// system. -/// -/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 -/// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html -/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html -/// -/// # Examples -/// -/// ``` -/// use std::net::{Ipv4Addr, SocketAddrV4}; -/// -/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); -/// -/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); -/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); -/// assert_eq!(socket.port(), 8080); -/// ``` -#[derive(Copy)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SocketAddrV4 { inner: c::sockaddr_in } - -/// An IPv6 socket address. -/// -/// IPv6 socket addresses consist of an [Ipv6 address], a 16-bit port number, as well -/// as fields containing the traffic class, the flow label, and a scope identifier -/// (see [IETF RFC 2553, Section 3.3] for more details). -/// -/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. -/// -/// The size of a `SocketAddrV6` struct may vary depending on the target operating -/// system. -/// -/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 -/// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html -/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html -/// -/// # Examples -/// -/// ``` -/// use std::net::{Ipv6Addr, SocketAddrV6}; -/// -/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0); -/// -/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket)); -/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); -/// assert_eq!(socket.port(), 8080); -/// ``` -#[derive(Copy)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SocketAddrV6 { inner: c::sockaddr_in6 } - -impl SocketAddr { - /// Creates a new socket address from an [IP address] and a port number. - /// - /// [IP address]: ../../std/net/enum.IpAddr.html - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); - /// assert_eq!(socket.port(), 8080); - /// ``` - #[stable(feature = "ip_addr", since = "1.7.0")] - pub fn new(ip: IpAddr, port: u16) -> SocketAddr { - match ip { - IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), - IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)), - } - } - - /// Returns the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); - /// ``` - #[stable(feature = "ip_addr", since = "1.7.0")] - pub fn ip(&self) -> IpAddr { - match *self { - SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()), - SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()), - } - } - - /// Changes the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); - /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_ip(&mut self, new_ip: IpAddr) { - // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. - match (self, new_ip) { - (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip), - (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip), - (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()), - } - } - - /// Returns the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// assert_eq!(socket.port(), 8080); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn port(&self) -> u16 { - match *self { - SocketAddr::V4(ref a) => a.port(), - SocketAddr::V6(ref a) => a.port(), - } - } - - /// Changes the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// socket.set_port(1025); - /// assert_eq!(socket.port(), 1025); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_port(&mut self, new_port: u16) { - match *self { - SocketAddr::V4(ref mut a) => a.set_port(new_port), - SocketAddr::V6(ref mut a) => a.set_port(new_port), - } - } - - /// Returns [`true`] if the [IP address] in this `SocketAddr` is an - /// [IPv4 address], and [`false`] otherwise. - /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html - /// [IP address]: ../../std/net/enum.IpAddr.html - /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4 - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - /// - /// fn main() { - /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); - /// assert_eq!(socket.is_ipv4(), true); - /// assert_eq!(socket.is_ipv6(), false); - /// } - /// ``` - #[stable(feature = "sockaddr_checker", since = "1.16.0")] - pub fn is_ipv4(&self) -> bool { - match *self { - SocketAddr::V4(_) => true, - SocketAddr::V6(_) => false, - } - } - - /// Returns [`true`] if the [IP address] in this `SocketAddr` is an - /// [IPv6 address], and [`false`] otherwise. - /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html - /// [IP address]: ../../std/net/enum.IpAddr.html - /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6 - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv6Addr, SocketAddr}; - /// - /// fn main() { - /// let socket = SocketAddr::new( - /// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080); - /// assert_eq!(socket.is_ipv4(), false); - /// assert_eq!(socket.is_ipv6(), true); - /// } - /// ``` - #[stable(feature = "sockaddr_checker", since = "1.16.0")] - pub fn is_ipv6(&self) -> bool { - match *self { - SocketAddr::V4(_) => false, - SocketAddr::V6(_) => true, - } - } -} - -impl SocketAddrV4 { - /// Creates a new socket address from an [IPv4 address] and a port number. - /// - /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV4, Ipv4Addr}; - /// - /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { - SocketAddrV4 { - inner: c::sockaddr_in { - sin_family: c::AF_INET as c::sa_family_t, - sin_port: hton(port), - sin_addr: *ip.as_inner(), - .. unsafe { mem::zeroed() } - }, - } - } - - /// Returns the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV4, Ipv4Addr}; - /// - /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); - /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn ip(&self) -> &Ipv4Addr { - unsafe { - &*(&self.inner.sin_addr as *const c::in_addr as *const Ipv4Addr) - } - } - - /// Changes the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV4, Ipv4Addr}; - /// - /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); - /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1)); - /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1)); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_ip(&mut self, new_ip: Ipv4Addr) { - self.inner.sin_addr = *new_ip.as_inner() - } - - /// Returns the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV4, Ipv4Addr}; - /// - /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); - /// assert_eq!(socket.port(), 8080); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn port(&self) -> u16 { - ntoh(self.inner.sin_port) - } - - /// Changes the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV4, Ipv4Addr}; - /// - /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); - /// socket.set_port(4242); - /// assert_eq!(socket.port(), 4242); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_port(&mut self, new_port: u16) { - self.inner.sin_port = hton(new_port); - } -} - -impl SocketAddrV6 { - /// Creates a new socket address from an [IPv6 address], a 16-bit port number, - /// and the `flowinfo` and `scope_id` fields. - /// - /// For more information on the meaning and layout of the `flowinfo` and `scope_id` - /// parameters, see [IETF RFC 2553, Section 3.3]. - /// - /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 - /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) - -> SocketAddrV6 { - SocketAddrV6 { - inner: c::sockaddr_in6 { - sin6_family: c::AF_INET6 as c::sa_family_t, - sin6_port: hton(port), - sin6_addr: *ip.as_inner(), - sin6_flowinfo: flowinfo, - sin6_scope_id: scope_id, - .. unsafe { mem::zeroed() } - }, - } - } - - /// Returns the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); - /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn ip(&self) -> &Ipv6Addr { - unsafe { - &*(&self.inner.sin6_addr as *const c::in6_addr as *const Ipv6Addr) - } - } - - /// Changes the IP address associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); - /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); - /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_ip(&mut self, new_ip: Ipv6Addr) { - self.inner.sin6_addr = *new_ip.as_inner() - } - - /// Returns the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); - /// assert_eq!(socket.port(), 8080); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn port(&self) -> u16 { - ntoh(self.inner.sin6_port) - } - - /// Changes the port number associated with this socket address. - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0); - /// socket.set_port(4242); - /// assert_eq!(socket.port(), 4242); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_port(&mut self, new_port: u16) { - self.inner.sin6_port = hton(new_port); - } - - /// Returns the flow information associated with this address. - /// - /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`, - /// as specified in [IETF RFC 2553, Section 3.3]. - /// It combines information about the flow label and the traffic class as specified - /// in [IETF RFC 2460], respectively [Section 6] and [Section 7]. - /// - /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 - /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460 - /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6 - /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7 - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); - /// assert_eq!(socket.flowinfo(), 10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn flowinfo(&self) -> u32 { - self.inner.sin6_flowinfo - } - - /// Changes the flow information associated with this socket address. - /// - /// See the [`flowinfo`] method's documentation for more details. - /// - /// [`flowinfo`]: #method.flowinfo - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0); - /// socket.set_flowinfo(56); - /// assert_eq!(socket.flowinfo(), 56); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_flowinfo(&mut self, new_flowinfo: u32) { - self.inner.sin6_flowinfo = new_flowinfo; - } - - /// Returns the scope ID associated with this address. - /// - /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`, - /// as specified in [IETF RFC 2553, Section 3.3]. - /// - /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); - /// assert_eq!(socket.scope_id(), 78); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn scope_id(&self) -> u32 { - self.inner.sin6_scope_id - } - - /// Change the scope ID associated with this socket address. - /// - /// See the [`scope_id`] method's documentation for more details. - /// - /// [`scope_id`]: #method.scope_id - /// - /// # Examples - /// - /// ``` - /// use std::net::{SocketAddrV6, Ipv6Addr}; - /// - /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78); - /// socket.set_scope_id(42); - /// assert_eq!(socket.scope_id(), 42); - /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] - pub fn set_scope_id(&mut self, new_scope_id: u32) { - self.inner.sin6_scope_id = new_scope_id; - } -} - -impl FromInner for SocketAddrV4 { - fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 { - SocketAddrV4 { inner: addr } - } -} - -impl FromInner for SocketAddrV6 { - fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 { - SocketAddrV6 { inner: addr } - } -} - -#[stable(feature = "ip_from_ip", since = "1.16.0")] -impl From for SocketAddr { - fn from(sock4: SocketAddrV4) -> SocketAddr { - SocketAddr::V4(sock4) - } -} - -#[stable(feature = "ip_from_ip", since = "1.16.0")] -impl From for SocketAddr { - fn from(sock6: SocketAddrV6) -> SocketAddr { - SocketAddr::V6(sock6) - } -} - -#[stable(feature = "addr_from_into_ip", since = "1.17.0")] -impl> From<(I, u16)> for SocketAddr { - fn from(pieces: (I, u16)) -> SocketAddr { - SocketAddr::new(pieces.0.into(), pieces.1) - } -} - -impl<'a> IntoInner<(*const c::sockaddr, c::socklen_t)> for &'a SocketAddr { - fn into_inner(self) -> (*const c::sockaddr, c::socklen_t) { - match *self { - SocketAddr::V4(ref a) => { - (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t) - } - SocketAddr::V6(ref a) => { - (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t) - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for SocketAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - SocketAddr::V4(ref a) => a.fmt(f), - SocketAddr::V6(ref a) => a.fmt(f), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for SocketAddrV4 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}:{}", self.ip(), self.port()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for SocketAddrV4 { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, fmt) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for SocketAddrV6 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[{}]:{}", self.ip(), self.port()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for SocketAddrV6 { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, fmt) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for SocketAddrV4 { - fn clone(&self) -> SocketAddrV4 { *self } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for SocketAddrV6 { - fn clone(&self) -> SocketAddrV6 { *self } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for SocketAddrV4 { - fn eq(&self, other: &SocketAddrV4) -> bool { - self.inner.sin_port == other.inner.sin_port && - self.inner.sin_addr.s_addr == other.inner.sin_addr.s_addr - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for SocketAddrV6 { - fn eq(&self, other: &SocketAddrV6) -> bool { - self.inner.sin6_port == other.inner.sin6_port && - self.inner.sin6_addr.s6_addr == other.inner.sin6_addr.s6_addr && - self.inner.sin6_flowinfo == other.inner.sin6_flowinfo && - self.inner.sin6_scope_id == other.inner.sin6_scope_id - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for SocketAddrV4 {} -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for SocketAddrV6 {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for SocketAddrV4 { - fn hash(&self, s: &mut H) { - (self.inner.sin_port, self.inner.sin_addr.s_addr).hash(s) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for SocketAddrV6 { - fn hash(&self, s: &mut H) { - (self.inner.sin6_port, &self.inner.sin6_addr.s6_addr, - self.inner.sin6_flowinfo, self.inner.sin6_scope_id).hash(s) - } -} - -/// A trait for objects which can be converted or resolved to one or more -/// [`SocketAddr`] values. -/// -/// This trait is used for generic address resolution when constructing network -/// objects. By default it is implemented for the following types: -/// -/// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function. -/// -/// * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`, -/// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`: -/// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. -/// -/// * `(`[`&str`]`, `[`u16`]`)`: the string should be either a string representation -/// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host -/// name. -/// -/// * [`&str`]: the string should be either a string representation of a -/// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like -/// `:` pair where `` is a [`u16`] value. -/// -/// This trait allows constructing network objects like [`TcpStream`] or -/// [`UdpSocket`] easily with values of various types for the bind/connection -/// address. It is needed because sometimes one type is more appropriate than -/// the other: for simple uses a string like `"localhost:12345"` is much nicer -/// than manual construction of the corresponding [`SocketAddr`], but sometimes -/// [`SocketAddr`] value is *the* main source of the address, and converting it to -/// some other type (e.g. a string) just for it to be converted back to -/// [`SocketAddr`] in constructor methods is pointless. -/// -/// Addresses returned by the operating system that are not IP addresses are -/// silently ignored. -/// -/// [`FromStr`]: ../../std/str/trait.FromStr.html -/// [`IpAddr`]: ../../std/net/enum.IpAddr.html -/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html -/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html -/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html -/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html -/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html -/// [`&str`]: ../../std/primitive.str.html -/// [`TcpStream`]: ../../std/net/struct.TcpStream.html -/// [`to_socket_addrs`]: #tymethod.to_socket_addrs -/// [`UdpSocket`]: ../../std/net/struct.UdpSocket.html -/// [`u16`]: ../../std/primitive.u16.html -/// -/// # Examples -/// -/// Creating a [`SocketAddr`] iterator that yields one item: -/// -/// ``` -/// use std::net::{ToSocketAddrs, SocketAddr}; -/// -/// let addr = SocketAddr::from(([127, 0, 0, 1], 443)); -/// let mut addrs_iter = addr.to_socket_addrs().unwrap(); -/// -/// assert_eq!(Some(addr), addrs_iter.next()); -/// assert!(addrs_iter.next().is_none()); -/// ``` -/// -/// Creating a [`SocketAddr`] iterator from a hostname: -/// -/// ```no_run -/// use std::net::{SocketAddr, ToSocketAddrs}; -/// -/// // assuming 'localhost' resolves to 127.0.0.1 -/// let mut addrs_iter = "localhost:443".to_socket_addrs().unwrap(); -/// assert_eq!(addrs_iter.next(), Some(SocketAddr::from(([127, 0, 0, 1], 443)))); -/// assert!(addrs_iter.next().is_none()); -/// -/// // assuming 'foo' does not resolve -/// assert!("foo:443".to_socket_addrs().is_err()); -/// ``` -/// -/// Creating a [`SocketAddr`] iterator that yields multiple items: -/// -/// ``` -/// use std::net::{SocketAddr, ToSocketAddrs}; -/// -/// let addr1 = SocketAddr::from(([0, 0, 0, 0], 80)); -/// let addr2 = SocketAddr::from(([127, 0, 0, 1], 443)); -/// let addrs = vec![addr1, addr2]; -/// -/// let mut addrs_iter = (&addrs[..]).to_socket_addrs().unwrap(); -/// -/// assert_eq!(Some(addr1), addrs_iter.next()); -/// assert_eq!(Some(addr2), addrs_iter.next()); -/// assert!(addrs_iter.next().is_none()); -/// ``` -/// -/// Attempting to create a [`SocketAddr`] iterator from an improperly formatted -/// socket address `&str` (missing the port): -/// -/// ``` -/// use std::io; -/// use std::net::ToSocketAddrs; -/// -/// let err = "127.0.0.1".to_socket_addrs().unwrap_err(); -/// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); -/// ``` -/// -/// [`TcpStream::connect`] is an example of an function that utilizes -/// `ToSocketAddrs` as a trait bound on its parameter in order to accept -/// different types: -/// -/// ```no_run -/// use std::net::{TcpStream, Ipv4Addr}; -/// -/// let stream = TcpStream::connect(("127.0.0.1", 443)); -/// // or -/// let stream = TcpStream::connect("127.0.0.1:443"); -/// // or -/// let stream = TcpStream::connect((Ipv4Addr::new(127, 0, 0, 1), 443)); -/// ``` -/// -/// [`TcpStream::connect`]: ../../std/net/struct.TcpStream.html#method.connect -#[stable(feature = "rust1", since = "1.0.0")] -pub trait ToSocketAddrs { - /// Returned iterator over socket addresses which this type may correspond - /// to. - #[stable(feature = "rust1", since = "1.0.0")] - type Iter: Iterator; - - /// Converts this object to an iterator of resolved `SocketAddr`s. - /// - /// The returned iterator may not actually yield any values depending on the - /// outcome of any resolution performed. - /// - /// Note that this function may block the current thread while resolution is - /// performed. - #[stable(feature = "rust1", since = "1.0.0")] - fn to_socket_addrs(&self) -> io::Result; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for SocketAddr { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - Ok(Some(*self).into_iter()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for SocketAddrV4 { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - SocketAddr::V4(*self).to_socket_addrs() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for SocketAddrV6 { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - SocketAddr::V6(*self).to_socket_addrs() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for (IpAddr, u16) { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (ip, port) = *self; - match ip { - IpAddr::V4(ref a) => (*a, port).to_socket_addrs(), - IpAddr::V6(ref a) => (*a, port).to_socket_addrs(), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for (Ipv4Addr, u16) { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (ip, port) = *self; - SocketAddrV4::new(ip, port).to_socket_addrs() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for (Ipv6Addr, u16) { - type Iter = option::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (ip, port) = *self; - SocketAddrV6::new(ip, port, 0, 0).to_socket_addrs() - } -} - -fn resolve_socket_addr(s: &str, p: u16) -> io::Result> { - let ips = lookup_host(s)?; - let v: Vec<_> = ips.map(|mut a| { a.set_port(p); a }).collect(); - Ok(v.into_iter()) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> ToSocketAddrs for (&'a str, u16) { - type Iter = vec::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - let (host, port) = *self; - - // try to parse the host as a regular IP address first - if let Ok(addr) = host.parse::() { - let addr = SocketAddrV4::new(addr, port); - return Ok(vec![SocketAddr::V4(addr)].into_iter()) - } - if let Ok(addr) = host.parse::() { - let addr = SocketAddrV6::new(addr, port, 0, 0); - return Ok(vec![SocketAddr::V6(addr)].into_iter()) - } - - resolve_socket_addr(host, port) - } -} - -// accepts strings like 'localhost:12345' -#[stable(feature = "rust1", since = "1.0.0")] -impl ToSocketAddrs for str { - type Iter = vec::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - // try to parse as a regular SocketAddr first - if let Some(addr) = self.parse().ok() { - return Ok(vec![addr].into_iter()); - } - - macro_rules! try_opt { - ($e:expr, $msg:expr) => ( - match $e { - Some(r) => r, - None => return Err(io::Error::new(io::ErrorKind::InvalidInput, - $msg)), - } - ) - } - - // split the string by ':' and convert the second part to u16 - let mut parts_iter = self.rsplitn(2, ':'); - let port_str = try_opt!(parts_iter.next(), "invalid socket address"); - let host = try_opt!(parts_iter.next(), "invalid socket address"); - let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); - resolve_socket_addr(host, port) - } -} - -#[stable(feature = "slice_to_socket_addrs", since = "1.8.0")] -impl<'a> ToSocketAddrs for &'a [SocketAddr] { - type Iter = iter::Cloned>; - - fn to_socket_addrs(&self) -> io::Result { - Ok(self.iter().cloned()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ToSocketAddrs + ?Sized> ToSocketAddrs for &'a T { - type Iter = T::Iter; - fn to_socket_addrs(&self) -> io::Result { - (**self).to_socket_addrs() - } -} - -#[stable(feature = "string_to_socket_addrs", since = "1.16.0")] -impl ToSocketAddrs for String { - type Iter = vec::IntoIter; - fn to_socket_addrs(&self) -> io::Result> { - (&**self).to_socket_addrs() - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use net::*; - use net::test::{tsa, sa6, sa4}; - - #[test] - fn to_socket_addr_ipaddr_u16() { - let a = Ipv4Addr::new(77, 88, 21, 11); - let p = 12345; - let e = SocketAddr::V4(SocketAddrV4::new(a, p)); - assert_eq!(Ok(vec![e]), tsa((a, p))); - } - - #[test] - fn to_socket_addr_str_u16() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); - assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352))); - - let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); - assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53))); - - let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); - assert!(tsa(("localhost", 23924)).unwrap().contains(&a)); - } - - #[test] - fn to_socket_addr_str() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); - assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352")); - - let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); - assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53")); - - let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); - assert!(tsa("localhost:23924").unwrap().contains(&a)); - } - - #[test] - fn to_socket_addr_string() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); - assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352"))); - assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352"))); - assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352"))); - - let s = format!("{}:{}", "77.88.21.11", "24352"); - assert_eq!(Ok(vec![a]), tsa(s)); - // s has been moved into the tsa call - } - - // FIXME: figure out why this fails on openbsd and bitrig and fix it - #[test] - #[cfg(not(any(windows, target_os = "openbsd", target_os = "bitrig")))] - fn to_socket_addr_str_bad() { - assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err()); - } - - #[test] - fn set_ip() { - fn ip4(low: u8) -> Ipv4Addr { Ipv4Addr::new(77, 88, 21, low) } - fn ip6(low: u16) -> Ipv6Addr { Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low) } - - let mut v4 = SocketAddrV4::new(ip4(11), 80); - assert_eq!(v4.ip(), &ip4(11)); - v4.set_ip(ip4(12)); - assert_eq!(v4.ip(), &ip4(12)); - - let mut addr = SocketAddr::V4(v4); - assert_eq!(addr.ip(), IpAddr::V4(ip4(12))); - addr.set_ip(IpAddr::V4(ip4(13))); - assert_eq!(addr.ip(), IpAddr::V4(ip4(13))); - addr.set_ip(IpAddr::V6(ip6(14))); - assert_eq!(addr.ip(), IpAddr::V6(ip6(14))); - - let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0); - assert_eq!(v6.ip(), &ip6(1)); - v6.set_ip(ip6(2)); - assert_eq!(v6.ip(), &ip6(2)); - - let mut addr = SocketAddr::V6(v6); - assert_eq!(addr.ip(), IpAddr::V6(ip6(2))); - addr.set_ip(IpAddr::V6(ip6(3))); - assert_eq!(addr.ip(), IpAddr::V6(ip6(3))); - addr.set_ip(IpAddr::V4(ip4(4))); - assert_eq!(addr.ip(), IpAddr::V4(ip4(4))); - } - - #[test] - fn set_port() { - let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80); - assert_eq!(v4.port(), 80); - v4.set_port(443); - assert_eq!(v4.port(), 443); - - let mut addr = SocketAddr::V4(v4); - assert_eq!(addr.port(), 443); - addr.set_port(8080); - assert_eq!(addr.port(), 8080); - - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0); - assert_eq!(v6.port(), 80); - v6.set_port(443); - assert_eq!(v6.port(), 443); - - let mut addr = SocketAddr::V6(v6); - assert_eq!(addr.port(), 443); - addr.set_port(8080); - assert_eq!(addr.port(), 8080); - } - - #[test] - fn set_flowinfo() { - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0); - assert_eq!(v6.flowinfo(), 10); - v6.set_flowinfo(20); - assert_eq!(v6.flowinfo(), 20); - } - - #[test] - fn set_scope_id() { - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10); - assert_eq!(v6.scope_id(), 10); - v6.set_scope_id(20); - assert_eq!(v6.scope_id(), 20); - } - - #[test] - fn is_v4() { - let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)); - assert!(v4.is_ipv4()); - assert!(!v4.is_ipv6()); - } - - #[test] - fn is_v6() { - let v6 = SocketAddr::V6(SocketAddrV6::new( - Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0)); - assert!(!v6.is_ipv4()); - assert!(v6.is_ipv6()); - } -} diff --git a/ctr-std/src/net/ip.rs b/ctr-std/src/net/ip.rs deleted file mode 100644 index 9a610cd..0000000 --- a/ctr-std/src/net/ip.rs +++ /dev/null @@ -1,1940 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "ip", reason = "extra functionality has not been \ - scrutinized to the level that it should \ - be to be stable", - issue = "27709")] - -use cmp::Ordering; -use fmt; -use hash; -use sys::net::netc as c; -use sys_common::{AsInner, FromInner}; - -/// An IP address, either IPv4 or IPv6. -/// -/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their -/// respective documentation for more details. -/// -/// The size of an `IpAddr` instance may vary depending on the target operating -/// system. -/// -/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html -/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html -/// -/// # Examples -/// -/// ``` -/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -/// -/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); -/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); -/// -/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); -/// assert_eq!("::1".parse(), Ok(localhost_v6)); -/// -/// assert_eq!(localhost_v4.is_ipv6(), false); -/// assert_eq!(localhost_v4.is_ipv4(), true); -/// ``` -#[stable(feature = "ip_addr", since = "1.7.0")] -#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] -pub enum IpAddr { - /// An IPv4 address. - #[stable(feature = "ip_addr", since = "1.7.0")] - V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr), - /// An IPv6 address. - #[stable(feature = "ip_addr", since = "1.7.0")] - V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr), -} - -/// An IPv4 address. -/// -/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. -/// They are usually represented as four octets. -/// -/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. -/// -/// The size of an `Ipv4Addr` struct may vary depending on the target operating -/// system. -/// -/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 -/// [`IpAddr`]: ../../std/net/enum.IpAddr.html -/// -/// # Textual representation -/// -/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal -/// notation, divided by `.` (this is called "dot-decimal notation"). -/// -/// [`FromStr`]: ../../std/str/trait.FromStr.html -/// -/// # Examples -/// -/// ``` -/// use std::net::Ipv4Addr; -/// -/// let localhost = Ipv4Addr::new(127, 0, 0, 1); -/// assert_eq!("127.0.0.1".parse(), Ok(localhost)); -/// assert_eq!(localhost.is_loopback(), true); -/// ``` -#[derive(Copy)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Ipv4Addr { - inner: c::in_addr, -} - -/// An IPv6 address. -/// -/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. -/// They are usually represented as eight 16-bit segments. -/// -/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. -/// -/// The size of an `Ipv6Addr` struct may vary depending on the target operating -/// system. -/// -/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 -/// [`IpAddr`]: ../../std/net/enum.IpAddr.html -/// -/// # Textual representation -/// -/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent -/// an IPv6 address in text, but in general, each segments is written in hexadecimal -/// notation, and segments are separated by `:`. For more information, see -/// [IETF RFC 5952]. -/// -/// [`FromStr`]: ../../std/str/trait.FromStr.html -/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 -/// -/// # Examples -/// -/// ``` -/// use std::net::Ipv6Addr; -/// -/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); -/// assert_eq!("::1".parse(), Ok(localhost)); -/// assert_eq!(localhost.is_loopback(), true); -/// ``` -#[derive(Copy)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Ipv6Addr { - inner: c::in6_addr, -} - -#[allow(missing_docs)] -#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] -pub enum Ipv6MulticastScope { - InterfaceLocal, - LinkLocal, - RealmLocal, - AdminLocal, - SiteLocal, - OrganizationLocal, - Global -} - -impl IpAddr { - /// Returns [`true`] for the special 'unspecified' address. - /// - /// See the documentation for [`Ipv4Addr::is_unspecified`][IPv4] and - /// [`Ipv6Addr::is_unspecified`][IPv6] for more details. - /// - /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified - /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); - /// ``` - #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_unspecified(&self) -> bool { - match self { - IpAddr::V4(ip) => ip.is_unspecified(), - IpAddr::V6(ip) => ip.is_unspecified(), - } - } - - /// Returns [`true`] if this is a loopback address. - /// - /// See the documentation for [`Ipv4Addr::is_loopback`][IPv4] and - /// [`Ipv6Addr::is_loopback`][IPv6] for more details. - /// - /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback - /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); - /// ``` - #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_loopback(&self) -> bool { - match self { - IpAddr::V4(ip) => ip.is_loopback(), - IpAddr::V6(ip) => ip.is_loopback(), - } - } - - /// Returns [`true`] if the address appears to be globally routable. - /// - /// See the documentation for [`Ipv4Addr::is_global`][IPv4] and - /// [`Ipv6Addr::is_global`][IPv6] for more details. - /// - /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global - /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), - /// true); - /// } - /// ``` - pub fn is_global(&self) -> bool { - match self { - IpAddr::V4(ip) => ip.is_global(), - IpAddr::V6(ip) => ip.is_global(), - } - } - - /// Returns [`true`] if this is a multicast address. - /// - /// See the documentation for [`Ipv4Addr::is_multicast`][IPv4] and - /// [`Ipv6Addr::is_multicast`][IPv6] for more details. - /// - /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast - /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); - /// ``` - #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_multicast(&self) -> bool { - match self { - IpAddr::V4(ip) => ip.is_multicast(), - IpAddr::V6(ip) => ip.is_multicast(), - } - } - - /// Returns [`true`] if this address is in a range designated for documentation. - /// - /// See the documentation for [`Ipv4Addr::is_documentation`][IPv4] and - /// [`Ipv6Addr::is_documentation`][IPv6] for more details. - /// - /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation - /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)) - /// .is_documentation(), true); - /// } - /// ``` - pub fn is_documentation(&self) -> bool { - match self { - IpAddr::V4(ip) => ip.is_documentation(), - IpAddr::V6(ip) => ip.is_documentation(), - } - } - - /// Returns [`true`] if this address is an [IPv4 address], and [`false`] otherwise. - /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html - /// [IPv4 address]: #variant.V4 - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), - /// false); - /// } - /// ``` - #[stable(feature = "ipaddr_checker", since = "1.16.0")] - pub fn is_ipv4(&self) -> bool { - match self { - IpAddr::V4(_) => true, - IpAddr::V6(_) => false, - } - } - - /// Returns [`true`] if this address is an [IPv6 address], and [`false`] otherwise. - /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html - /// [IPv6 address]: #variant.V6 - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - /// - /// fn main() { - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); - /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), - /// true); - /// } - /// ``` - #[stable(feature = "ipaddr_checker", since = "1.16.0")] - pub fn is_ipv6(&self) -> bool { - match self { - IpAddr::V4(_) => false, - IpAddr::V6(_) => true, - } - } -} - -impl Ipv4Addr { - /// Creates a new IPv4 address from four eight-bit octets. - /// - /// The result will represent the IP address `a`.`b`.`c`.`d`. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::new(127, 0, 0, 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ip")] - pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { - Ipv4Addr { - inner: c::in_addr { - s_addr: u32::to_be( - ((a as u32) << 24) | - ((b as u32) << 16) | - ((c as u32) << 8) | - (d as u32) - ), - } - } - } - - /// An IPv4 address with the address pointing to localhost: 127.0.0.1. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip_constructors)] - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::LOCALHOST; - /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); - /// ``` - #[unstable(feature = "ip_constructors", - reason = "requires greater scrutiny before stabilization", - issue = "44582")] - pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); - - /// An IPv4 address representing an unspecified address: 0.0.0.0 - /// - /// # Examples - /// - /// ``` - /// #![feature(ip_constructors)] - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::UNSPECIFIED; - /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); - /// ``` - #[unstable(feature = "ip_constructors", - reason = "requires greater scrutiny before stabilization", - issue = "44582")] - pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); - - /// An IPv4 address representing the broadcast address: 255.255.255.255 - /// - /// # Examples - /// - /// ``` - /// #![feature(ip_constructors)] - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::BROADCAST; - /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); - /// ``` - #[unstable(feature = "ip_constructors", - reason = "requires greater scrutiny before stabilization", - issue = "44582")] - pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); - - /// Returns the four eight-bit integers that make up this address. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::new(127, 0, 0, 1); - /// assert_eq!(addr.octets(), [127, 0, 0, 1]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn octets(&self) -> [u8; 4] { - let bits = u32::from_be(self.inner.s_addr); - [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] - } - - /// Returns [`true`] for the special 'unspecified' address (0.0.0.0). - /// - /// This property is defined in _UNIX Network Programming, Second Edition_, - /// W. Richard Stevens, p. 891; see also [ip7]. - /// - /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); - /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); - /// ``` - #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_unspecified(&self) -> bool { - self.inner.s_addr == 0 - } - - /// Returns [`true`] if this is a loopback address (127.0.0.0/8). - /// - /// This property is defined by [IETF RFC 1122]. - /// - /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); - /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); - /// ``` - #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_loopback(&self) -> bool { - self.octets()[0] == 127 - } - - /// Returns [`true`] if this is a private address. - /// - /// The private address ranges are defined in [IETF RFC 1918] and include: - /// - /// - 10.0.0.0/8 - /// - 172.16.0.0/12 - /// - 192.168.0.0/16 - /// - /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); - /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); - /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); - /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); - /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); - /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); - /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); - /// ``` - #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_private(&self) -> bool { - match self.octets() { - [10, ..] => true, - [172, b, ..] if b >= 16 && b <= 31 => true, - [192, 168, ..] => true, - _ => false, - } - } - - /// Returns [`true`] if the address is link-local (169.254.0.0/16). - /// - /// This property is defined by [IETF RFC 3927]. - /// - /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); - /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); - /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); - /// ``` - #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_link_local(&self) -> bool { - match self.octets() { - [169, 254, ..] => true, - _ => false, - } - } - - /// Returns [`true`] if the address appears to be globally routable. - /// See [iana-ipv4-special-registry][ipv4-sr]. - /// - /// The following return false: - /// - /// - private address (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16) - /// - the loopback address (127.0.0.0/8) - /// - the link-local address (169.254.0.0/16) - /// - the broadcast address (255.255.255.255/32) - /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24) - /// - the unspecified address (0.0.0.0) - /// - /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv4Addr; - /// - /// fn main() { - /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); - /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); - /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); - /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); - /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); - /// } - /// ``` - pub fn is_global(&self) -> bool { - !self.is_private() && !self.is_loopback() && !self.is_link_local() && - !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() - } - - /// Returns [`true`] if this is a multicast address (224.0.0.0/4). - /// - /// Multicast addresses have a most significant octet between 224 and 239, - /// and is defined by [IETF RFC 5771]. - /// - /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); - /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); - /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); - /// ``` - #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_multicast(&self) -> bool { - self.octets()[0] >= 224 && self.octets()[0] <= 239 - } - - /// Returns [`true`] if this is a broadcast address (255.255.255.255). - /// - /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. - /// - /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); - /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); - /// ``` - #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_broadcast(&self) -> bool { - self == &Self::BROADCAST - } - - /// Returns [`true`] if this address is in a range designated for documentation. - /// - /// This is defined in [IETF RFC 5737]: - /// - /// - 192.0.2.0/24 (TEST-NET-1) - /// - 198.51.100.0/24 (TEST-NET-2) - /// - 203.0.113.0/24 (TEST-NET-3) - /// - /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); - /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); - /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); - /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); - /// ``` - #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_documentation(&self) -> bool { - match self.octets() { - [192, 0, 2, _] => true, - [198, 51, 100, _] => true, - [203, 0, 113, _] => true, - _ => false, - } - } - - /// Converts this address to an IPv4-compatible [IPv6 address]. - /// - /// a.b.c.d becomes ::a.b.c.d - /// - /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html - /// - /// # Examples - /// - /// ``` - /// use std::net::{Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), - /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv6_compatible(&self) -> Ipv6Addr { - Ipv6Addr::new(0, 0, 0, 0, 0, 0, - ((self.octets()[0] as u16) << 8) | self.octets()[1] as u16, - ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) - } - - /// Converts this address to an IPv4-mapped [IPv6 address]. - /// - /// a.b.c.d becomes ::ffff:a.b.c.d - /// - /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html - /// - /// # Examples - /// - /// ``` - /// use std::net::{Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), - /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv6_mapped(&self) -> Ipv6Addr { - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, - ((self.octets()[0] as u16) << 8) | self.octets()[1] as u16, - ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) - } -} - -#[stable(feature = "ip_addr", since = "1.7.0")] -impl fmt::Display for IpAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self { - IpAddr::V4(ip) => ip.fmt(fmt), - IpAddr::V6(ip) => ip.fmt(fmt), - } - } -} - -#[stable(feature = "ip_from_ip", since = "1.16.0")] -impl From for IpAddr { - fn from(ipv4: Ipv4Addr) -> IpAddr { - IpAddr::V4(ipv4) - } -} - -#[stable(feature = "ip_from_ip", since = "1.16.0")] -impl From for IpAddr { - fn from(ipv6: Ipv6Addr) -> IpAddr { - IpAddr::V6(ipv6) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Ipv4Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let octets = self.octets(); - write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Ipv4Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, fmt) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Ipv4Addr { - fn clone(&self) -> Ipv4Addr { *self } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Ipv4Addr { - fn eq(&self, other: &Ipv4Addr) -> bool { - self.inner.s_addr == other.inner.s_addr - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialEq for IpAddr { - fn eq(&self, other: &Ipv4Addr) -> bool { - match self { - IpAddr::V4(v4) => v4 == other, - IpAddr::V6(_) => false, - } - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialEq for Ipv4Addr { - fn eq(&self, other: &IpAddr) -> bool { - match other { - IpAddr::V4(v4) => self == v4, - IpAddr::V6(_) => false, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Ipv4Addr {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for Ipv4Addr { - fn hash(&self, s: &mut H) { - // `inner` is #[repr(packed)], so we need to copy `s_addr`. - {self.inner.s_addr}.hash(s) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Ipv4Addr { - fn partial_cmp(&self, other: &Ipv4Addr) -> Option { - Some(self.cmp(other)) - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialOrd for IpAddr { - fn partial_cmp(&self, other: &Ipv4Addr) -> Option { - match self { - IpAddr::V4(v4) => v4.partial_cmp(other), - IpAddr::V6(_) => Some(Ordering::Greater), - } - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialOrd for Ipv4Addr { - fn partial_cmp(&self, other: &IpAddr) -> Option { - match other { - IpAddr::V4(v4) => self.partial_cmp(v4), - IpAddr::V6(_) => Some(Ordering::Less), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Ipv4Addr { - fn cmp(&self, other: &Ipv4Addr) -> Ordering { - u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr)) - } -} - -impl AsInner for Ipv4Addr { - fn as_inner(&self) -> &c::in_addr { &self.inner } -} -impl FromInner for Ipv4Addr { - fn from_inner(addr: c::in_addr) -> Ipv4Addr { - Ipv4Addr { inner: addr } - } -} - -#[stable(feature = "ip_u32", since = "1.1.0")] -impl From for u32 { - /// Convert an `Ipv4Addr` into a host byte order `u32`. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::new(13, 12, 11, 10); - /// assert_eq!(0x0d0c0b0au32, u32::from(addr)); - /// ``` - fn from(ip: Ipv4Addr) -> u32 { - let ip = ip.octets(); - ((ip[0] as u32) << 24) + ((ip[1] as u32) << 16) + ((ip[2] as u32) << 8) + (ip[3] as u32) - } -} - -#[stable(feature = "ip_u32", since = "1.1.0")] -impl From for Ipv4Addr { - /// Convert a host byte order `u32` into an `Ipv4Addr`. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::from(0x0d0c0b0au32); - /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); - /// ``` - fn from(ip: u32) -> Ipv4Addr { - Ipv4Addr::new((ip >> 24) as u8, (ip >> 16) as u8, (ip >> 8) as u8, ip as u8) - } -} - -#[stable(feature = "from_slice_v4", since = "1.9.0")] -impl From<[u8; 4]> for Ipv4Addr { - /// # Examples - /// - /// ``` - /// use std::net::Ipv4Addr; - /// - /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); - /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); - /// ``` - fn from(octets: [u8; 4]) -> Ipv4Addr { - Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) - } -} - -#[stable(feature = "ip_from_slice", since = "1.17.0")] -impl From<[u8; 4]> for IpAddr { - /// Create an `IpAddr::V4` from a four element byte array. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv4Addr}; - /// - /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); - /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); - /// ``` - fn from(octets: [u8; 4]) -> IpAddr { - IpAddr::V4(Ipv4Addr::from(octets)) - } -} - -impl Ipv6Addr { - /// Creates a new IPv6 address from eight 16-bit segments. - /// - /// The result will represent the IP address a:b:c:d:e:f:g:h. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ip")] - pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, - g: u16, h: u16) -> Ipv6Addr { - Ipv6Addr { - inner: c::in6_addr { - s6_addr: [ - (a >> 8) as u8, a as u8, - (b >> 8) as u8, b as u8, - (c >> 8) as u8, c as u8, - (d >> 8) as u8, d as u8, - (e >> 8) as u8, e as u8, - (f >> 8) as u8, f as u8, - (g >> 8) as u8, g as u8, - (h >> 8) as u8, h as u8 - ], - } - } - - } - - /// An IPv6 address representing localhost: `::1`. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip_constructors)] - /// use std::net::Ipv6Addr; - /// - /// let addr = Ipv6Addr::LOCALHOST; - /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - /// ``` - #[unstable(feature = "ip_constructors", - reason = "requires greater scrutiny before stabilization", - issue = "44582")] - pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); - - /// An IPv6 address representing the unspecified address: `::` - /// - /// # Examples - /// - /// ``` - /// #![feature(ip_constructors)] - /// use std::net::Ipv6Addr; - /// - /// let addr = Ipv6Addr::UNSPECIFIED; - /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - /// ``` - #[unstable(feature = "ip_constructors", - reason = "requires greater scrutiny before stabilization", - issue = "44582")] - pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); - - /// Returns the eight 16-bit segments that make up this address. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), - /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn segments(&self) -> [u16; 8] { - let arr = &self.inner.s6_addr; - [ - (arr[0] as u16) << 8 | (arr[1] as u16), - (arr[2] as u16) << 8 | (arr[3] as u16), - (arr[4] as u16) << 8 | (arr[5] as u16), - (arr[6] as u16) << 8 | (arr[7] as u16), - (arr[8] as u16) << 8 | (arr[9] as u16), - (arr[10] as u16) << 8 | (arr[11] as u16), - (arr[12] as u16) << 8 | (arr[13] as u16), - (arr[14] as u16) << 8 | (arr[15] as u16), - ] - } - - /// Returns [`true`] for the special 'unspecified' address (::). - /// - /// This property is defined in [IETF RFC 4291]. - /// - /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); - /// ``` - #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_unspecified(&self) -> bool { - self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] - } - - /// Returns [`true`] if this is a loopback address (::1). - /// - /// This property is defined in [IETF RFC 4291]. - /// - /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); - /// ``` - #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_loopback(&self) -> bool { - self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] - } - - /// Returns [`true`] if the address appears to be globally routable. - /// - /// The following return [`false`]: - /// - /// - the loopback address - /// - link-local, site-local, and unique local unicast addresses - /// - interface-, link-, realm-, admin- and site-local multicast addresses - /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); - /// } - /// ``` - pub fn is_global(&self) -> bool { - match self.multicast_scope() { - Some(Ipv6MulticastScope::Global) => true, - None => self.is_unicast_global(), - _ => false - } - } - - /// Returns [`true`] if this is a unique local address (fc00::/7). - /// - /// This property is defined in [IETF RFC 4193]. - /// - /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), - /// false); - /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); - /// } - /// ``` - pub fn is_unique_local(&self) -> bool { - (self.segments()[0] & 0xfe00) == 0xfc00 - } - - /// Returns [`true`] if the address is unicast and link-local (fe80::/10). - /// - /// This property is defined in [IETF RFC 4291]. - /// - /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_link_local(), - /// false); - /// assert_eq!(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); - /// } - /// ``` - pub fn is_unicast_link_local(&self) -> bool { - (self.segments()[0] & 0xffc0) == 0xfe80 - } - - /// Returns [`true`] if this is a deprecated unicast site-local address - /// (fec0::/10). - /// - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), - /// false); - /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); - /// } - /// ``` - pub fn is_unicast_site_local(&self) -> bool { - (self.segments()[0] & 0xffc0) == 0xfec0 - } - - /// Returns [`true`] if this is an address reserved for documentation - /// (2001:db8::/32). - /// - /// This property is defined in [IETF RFC 3849]. - /// - /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), - /// false); - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); - /// } - /// ``` - pub fn is_documentation(&self) -> bool { - (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) - } - - /// Returns [`true`] if the address is a globally routable unicast address. - /// - /// The following return false: - /// - /// - the loopback address - /// - the link-local addresses - /// - the (deprecated) site-local addresses - /// - unique local addresses - /// - the unspecified address - /// - the address range reserved for documentation - /// - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), - /// true); - /// } - /// ``` - pub fn is_unicast_global(&self) -> bool { - !self.is_multicast() - && !self.is_loopback() && !self.is_unicast_link_local() - && !self.is_unicast_site_local() && !self.is_unique_local() - && !self.is_unspecified() && !self.is_documentation() - } - - /// Returns the address's multicast scope if the address is multicast. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; - /// - /// fn main() { - /// assert_eq!(Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), - /// Some(Ipv6MulticastScope::Global)); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); - /// } - /// ``` - pub fn multicast_scope(&self) -> Option { - if self.is_multicast() { - match self.segments()[0] & 0x000f { - 1 => Some(Ipv6MulticastScope::InterfaceLocal), - 2 => Some(Ipv6MulticastScope::LinkLocal), - 3 => Some(Ipv6MulticastScope::RealmLocal), - 4 => Some(Ipv6MulticastScope::AdminLocal), - 5 => Some(Ipv6MulticastScope::SiteLocal), - 8 => Some(Ipv6MulticastScope::OrganizationLocal), - 14 => Some(Ipv6MulticastScope::Global), - _ => None - } - } else { - None - } - } - - /// Returns [`true`] if this is a multicast address (ff00::/8). - /// - /// This property is defined by [IETF RFC 4291]. - /// - /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 - /// [`true`]: ../../std/primitive.bool.html - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); - /// ``` - #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_multicast(&self) -> bool { - (self.segments()[0] & 0xff00) == 0xff00 - } - - /// Converts this address to an [IPv4 address]. Returns [`None`] if this address is - /// neither IPv4-compatible or IPv4-mapped. - /// - /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d - /// - /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::net::{Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), - /// Some(Ipv4Addr::new(192, 10, 2, 255))); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), - /// Some(Ipv4Addr::new(0, 0, 0, 1))); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv4(&self) -> Option { - match self.segments() { - [0, 0, 0, 0, 0, f, g, h] if f == 0 || f == 0xffff => { - Some(Ipv4Addr::new((g >> 8) as u8, g as u8, - (h >> 8) as u8, h as u8)) - }, - _ => None - } - } - - /// Returns the sixteen eight-bit integers the IPv6 address consists of. - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), - /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - /// ``` - #[stable(feature = "ipv6_to_octets", since = "1.12.0")] - pub fn octets(&self) -> [u8; 16] { - self.inner.s6_addr - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Ipv6Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self.segments() { - // We need special cases for :: and ::1, otherwise they're formatted - // as ::0.0.0.[01] - [0, 0, 0, 0, 0, 0, 0, 0] => write!(fmt, "::"), - [0, 0, 0, 0, 0, 0, 0, 1] => write!(fmt, "::1"), - // Ipv4 Compatible address - [0, 0, 0, 0, 0, 0, g, h] => { - write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8, - (h >> 8) as u8, h as u8) - } - // Ipv4-Mapped address - [0, 0, 0, 0, 0, 0xffff, g, h] => { - write!(fmt, "::ffff:{}.{}.{}.{}", (g >> 8) as u8, g as u8, - (h >> 8) as u8, h as u8) - }, - _ => { - fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) { - let mut longest_span_len = 0; - let mut longest_span_at = 0; - let mut cur_span_len = 0; - let mut cur_span_at = 0; - - for i in 0..8 { - if segments[i] == 0 { - if cur_span_len == 0 { - cur_span_at = i; - } - - cur_span_len += 1; - - if cur_span_len > longest_span_len { - longest_span_len = cur_span_len; - longest_span_at = cur_span_at; - } - } else { - cur_span_len = 0; - cur_span_at = 0; - } - } - - (longest_span_at, longest_span_len) - } - - let (zeros_at, zeros_len) = find_zero_slice(&self.segments()); - - if zeros_len > 1 { - fn fmt_subslice(segments: &[u16], fmt: &mut fmt::Formatter) -> fmt::Result { - if !segments.is_empty() { - write!(fmt, "{:x}", segments[0])?; - for &seg in &segments[1..] { - write!(fmt, ":{:x}", seg)?; - } - } - Ok(()) - } - - fmt_subslice(&self.segments()[..zeros_at], fmt)?; - fmt.write_str("::")?; - fmt_subslice(&self.segments()[zeros_at + zeros_len..], fmt) - } else { - let &[a, b, c, d, e, f, g, h] = &self.segments(); - write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", - a, b, c, d, e, f, g, h) - } - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Ipv6Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, fmt) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Ipv6Addr { - fn clone(&self) -> Ipv6Addr { *self } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Ipv6Addr { - fn eq(&self, other: &Ipv6Addr) -> bool { - self.inner.s6_addr == other.inner.s6_addr - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialEq for Ipv6Addr { - fn eq(&self, other: &IpAddr) -> bool { - match other { - IpAddr::V4(_) => false, - IpAddr::V6(v6) => self == v6, - } - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialEq for IpAddr { - fn eq(&self, other: &Ipv6Addr) -> bool { - match self { - IpAddr::V4(_) => false, - IpAddr::V6(v6) => v6 == other, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Ipv6Addr {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for Ipv6Addr { - fn hash(&self, s: &mut H) { - self.inner.s6_addr.hash(s) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Ipv6Addr { - fn partial_cmp(&self, other: &Ipv6Addr) -> Option { - Some(self.cmp(other)) - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialOrd for IpAddr { - fn partial_cmp(&self, other: &Ipv6Addr) -> Option { - match self { - IpAddr::V4(_) => Some(Ordering::Less), - IpAddr::V6(v6) => v6.partial_cmp(other), - } - } -} - -#[stable(feature = "ip_cmp", since = "1.16.0")] -impl PartialOrd for Ipv6Addr { - fn partial_cmp(&self, other: &IpAddr) -> Option { - match other { - IpAddr::V4(_) => Some(Ordering::Greater), - IpAddr::V6(v6) => self.partial_cmp(v6), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Ipv6Addr { - fn cmp(&self, other: &Ipv6Addr) -> Ordering { - self.segments().cmp(&other.segments()) - } -} - -impl AsInner for Ipv6Addr { - fn as_inner(&self) -> &c::in6_addr { &self.inner } -} -impl FromInner for Ipv6Addr { - fn from_inner(addr: c::in6_addr) -> Ipv6Addr { - Ipv6Addr { inner: addr } - } -} - -#[stable(feature = "i128", since = "1.26.0")] -impl From for u128 { - fn from(ip: Ipv6Addr) -> u128 { - let ip = ip.segments(); - ((ip[0] as u128) << 112) + ((ip[1] as u128) << 96) + ((ip[2] as u128) << 80) + - ((ip[3] as u128) << 64) + ((ip[4] as u128) << 48) + ((ip[5] as u128) << 32) + - ((ip[6] as u128) << 16) + (ip[7] as u128) - } -} -#[stable(feature = "i128", since = "1.26.0")] -impl From for Ipv6Addr { - fn from(ip: u128) -> Ipv6Addr { - Ipv6Addr::new( - (ip >> 112) as u16, (ip >> 96) as u16, (ip >> 80) as u16, - (ip >> 64) as u16, (ip >> 48) as u16, (ip >> 32) as u16, - (ip >> 16) as u16, ip as u16, - ) - } -} - -#[stable(feature = "ipv6_from_octets", since = "1.9.0")] -impl From<[u8; 16]> for Ipv6Addr { - fn from(octets: [u8; 16]) -> Ipv6Addr { - let inner = c::in6_addr { s6_addr: octets }; - Ipv6Addr::from_inner(inner) - } -} - -#[stable(feature = "ipv6_from_segments", since = "1.16.0")] -impl From<[u16; 8]> for Ipv6Addr { - fn from(segments: [u16; 8]) -> Ipv6Addr { - let [a, b, c, d, e, f, g, h] = segments; - Ipv6Addr::new(a, b, c, d, e, f, g, h) - } -} - - -#[stable(feature = "ip_from_slice", since = "1.17.0")] -impl From<[u8; 16]> for IpAddr { - /// Create an `IpAddr::V6` from a sixteen element byte array. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv6Addr}; - /// - /// let addr = IpAddr::from([ - /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, - /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, - /// ]); - /// assert_eq!( - /// IpAddr::V6(Ipv6Addr::new( - /// 0x1918, 0x1716, - /// 0x1514, 0x1312, - /// 0x1110, 0x0f0e, - /// 0x0d0c, 0x0b0a - /// )), - /// addr - /// ); - /// ``` - fn from(octets: [u8; 16]) -> IpAddr { - IpAddr::V6(Ipv6Addr::from(octets)) - } -} - -#[stable(feature = "ip_from_slice", since = "1.17.0")] -impl From<[u16; 8]> for IpAddr { - /// Create an `IpAddr::V6` from an eight element 16-bit array. - /// - /// # Examples - /// - /// ``` - /// use std::net::{IpAddr, Ipv6Addr}; - /// - /// let addr = IpAddr::from([ - /// 525u16, 524u16, 523u16, 522u16, - /// 521u16, 520u16, 519u16, 518u16, - /// ]); - /// assert_eq!( - /// IpAddr::V6(Ipv6Addr::new( - /// 0x20d, 0x20c, - /// 0x20b, 0x20a, - /// 0x209, 0x208, - /// 0x207, 0x206 - /// )), - /// addr - /// ); - /// ``` - fn from(segments: [u16; 8]) -> IpAddr { - IpAddr::V6(Ipv6Addr::from(segments)) - } -} - -// Tests for this module -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use net::*; - use net::Ipv6MulticastScope::*; - use net::test::{tsa, sa6, sa4}; - - #[test] - fn test_from_str_ipv4() { - assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); - assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); - assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); - - // out of range - let none: Option = "256.0.0.1".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "255.0.0".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "255.0.0.1.2".parse().ok(); - assert_eq!(None, none); - // no number between dots - let none: Option = "255.0..1".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); - - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); - - assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), - "2a02:6b8::11:11".parse()); - - // too long group - let none: Option = "::00000".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "1:2:3:4:5:6:7".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); - assert_eq!(None, none); - // triple colon - let none: Option = "1:2:::6:7:8".parse().ok(); - assert_eq!(None, none); - // two double colons - let none: Option = "1:2::6::8".parse().ok(); - assert_eq!(None, none); - // `::` indicating zero groups of zeros - let none: Option = "1:2:3:4::5:6:7:8".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_ipv4_in_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), - "::192.0.2.33".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), - "::FFFF:192.0.2.33".parse()); - assert_eq!(Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), - "64:ff9b::192.0.2.33".parse()); - assert_eq!(Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), - "2001:db8:122:c000:2:2100:192.0.2.33".parse()); - - // colon after v4 - let none: Option = "::127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // not enough groups - let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); - assert_eq!(None, none); - // too many groups - let none: Option = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_socket_addr() { - assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), - "77.88.21.11:80".parse()); - assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), - "77.88.21.11:80".parse()); - assert_eq!(Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), - "[2a02:6b8:0:1::1]:53".parse()); - assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, - 0, 0, 0, 1), 53, 0, 0)), - "[2a02:6b8:0:1::1]:53".parse()); - assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), - "[::127.0.0.1]:22".parse()); - assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, - 0x7F00, 1), 22, 0, 0)), - "[::127.0.0.1]:22".parse()); - - // without port - let none: Option = "127.0.0.1".parse().ok(); - assert_eq!(None, none); - // without port - let none: Option = "127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // wrong brackets around v4 - let none: Option = "[127.0.0.1]:22".parse().ok(); - assert_eq!(None, none); - // port out of range - let none: Option = "127.0.0.1:123456".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn ipv6_addr_to_string() { - // ipv4-mapped address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); - - // ipv4-compatible address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::192.0.2.128"); - - // v6 address with no zero segments - assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), - "8:9:a:b:c:d:e:f"); - - // reduce a single run of zeros - assert_eq!("ae::ffff:102:304", - Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()); - - // don't reduce just a single zero segment - assert_eq!("1:2:3:4:5:6:0:8", - Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); - - // 'any' address - assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // loopback address - assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); - - // ends in zeros - assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // two runs of zeros, second one is longer - assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); - - // two runs of zeros, equal length - assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); - } - - #[test] - fn ipv4_to_ipv6() { - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()); - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()); - } - - #[test] - fn ipv6_to_ipv4() { - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))); - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))); - assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), - None); - } - - #[test] - fn ip_properties() { - fn check4(octets: &[u8; 4], unspec: bool, loopback: bool, - global: bool, multicast: bool, documentation: bool) { - let ip = IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])); - assert_eq!(ip.is_unspecified(), unspec); - assert_eq!(ip.is_loopback(), loopback); - assert_eq!(ip.is_global(), global); - assert_eq!(ip.is_multicast(), multicast); - assert_eq!(ip.is_documentation(), documentation); - } - - fn check6(str_addr: &str, unspec: bool, loopback: bool, - global: bool, u_doc: bool, mcast: bool) { - let ip = IpAddr::V6(str_addr.parse().unwrap()); - assert_eq!(ip.is_unspecified(), unspec); - assert_eq!(ip.is_loopback(), loopback); - assert_eq!(ip.is_global(), global); - assert_eq!(ip.is_documentation(), u_doc); - assert_eq!(ip.is_multicast(), mcast); - } - - // address unspec loopbk global multicast doc - check4(&[0, 0, 0, 0], true, false, false, false, false); - check4(&[0, 0, 0, 1], false, false, true, false, false); - check4(&[0, 1, 0, 0], false, false, true, false, false); - check4(&[10, 9, 8, 7], false, false, false, false, false); - check4(&[127, 1, 2, 3], false, true, false, false, false); - check4(&[172, 31, 254, 253], false, false, false, false, false); - check4(&[169, 254, 253, 242], false, false, false, false, false); - check4(&[192, 0, 2, 183], false, false, false, false, true); - check4(&[192, 1, 2, 183], false, false, true, false, false); - check4(&[192, 168, 254, 253], false, false, false, false, false); - check4(&[198, 51, 100, 0], false, false, false, false, true); - check4(&[203, 0, 113, 0], false, false, false, false, true); - check4(&[203, 2, 113, 0], false, false, true, false, false); - check4(&[224, 0, 0, 0], false, false, true, true, false); - check4(&[239, 255, 255, 255], false, false, true, true, false); - check4(&[255, 255, 255, 255], false, false, false, false, false); - - // address unspec loopbk global doc mcast - check6("::", true, false, false, false, false); - check6("::1", false, true, false, false, false); - check6("::0.0.0.2", false, false, true, false, false); - check6("1::", false, false, true, false, false); - check6("fc00::", false, false, false, false, false); - check6("fdff:ffff::", false, false, false, false, false); - check6("fe80:ffff::", false, false, false, false, false); - check6("febf:ffff::", false, false, false, false, false); - check6("fec0::", false, false, false, false, false); - check6("ff01::", false, false, false, false, true); - check6("ff02::", false, false, false, false, true); - check6("ff03::", false, false, false, false, true); - check6("ff04::", false, false, false, false, true); - check6("ff05::", false, false, false, false, true); - check6("ff08::", false, false, false, false, true); - check6("ff0e::", false, false, true, false, true); - check6("2001:db8:85a3::8a2e:370:7334", false, false, false, true, false); - check6("102:304:506:708:90a:b0c:d0e:f10", false, false, true, false, false); - } - - #[test] - fn ipv4_properties() { - fn check(octets: &[u8; 4], unspec: bool, loopback: bool, - private: bool, link_local: bool, global: bool, - multicast: bool, broadcast: bool, documentation: bool) { - let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]); - assert_eq!(octets, &ip.octets()); - - assert_eq!(ip.is_unspecified(), unspec); - assert_eq!(ip.is_loopback(), loopback); - assert_eq!(ip.is_private(), private); - assert_eq!(ip.is_link_local(), link_local); - assert_eq!(ip.is_global(), global); - assert_eq!(ip.is_multicast(), multicast); - assert_eq!(ip.is_broadcast(), broadcast); - assert_eq!(ip.is_documentation(), documentation); - } - - // address unspec loopbk privt linloc global multicast brdcast doc - check(&[0, 0, 0, 0], true, false, false, false, false, false, false, false); - check(&[0, 0, 0, 1], false, false, false, false, true, false, false, false); - check(&[0, 1, 0, 0], false, false, false, false, true, false, false, false); - check(&[10, 9, 8, 7], false, false, true, false, false, false, false, false); - check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false); - check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false); - check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false); - check(&[192, 0, 2, 183], false, false, false, false, false, false, false, true); - check(&[192, 1, 2, 183], false, false, false, false, true, false, false, false); - check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false); - check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true); - check(&[203, 0, 113, 0], false, false, false, false, false, false, false, true); - check(&[203, 2, 113, 0], false, false, false, false, true, false, false, false); - check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false); - check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false); - check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false); - } - - #[test] - fn ipv6_properties() { - fn check(str_addr: &str, octets: &[u8; 16], unspec: bool, loopback: bool, - unique_local: bool, global: bool, - u_link_local: bool, u_site_local: bool, u_global: bool, u_doc: bool, - m_scope: Option) { - let ip: Ipv6Addr = str_addr.parse().unwrap(); - assert_eq!(str_addr, ip.to_string()); - assert_eq!(&ip.octets(), octets); - assert_eq!(Ipv6Addr::from(*octets), ip); - - assert_eq!(ip.is_unspecified(), unspec); - assert_eq!(ip.is_loopback(), loopback); - assert_eq!(ip.is_unique_local(), unique_local); - assert_eq!(ip.is_global(), global); - assert_eq!(ip.is_unicast_link_local(), u_link_local); - assert_eq!(ip.is_unicast_site_local(), u_site_local); - assert_eq!(ip.is_unicast_global(), u_global); - assert_eq!(ip.is_documentation(), u_doc); - assert_eq!(ip.multicast_scope(), m_scope); - assert_eq!(ip.is_multicast(), m_scope.is_some()); - } - - // unspec loopbk uniqlo global unill unisl uniglo doc mscope - check("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - true, false, false, false, false, false, false, false, None); - check("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], - false, true, false, false, false, false, false, false, None); - check("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], - false, false, false, true, false, false, true, false, None); - check("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, true, false, false, true, false, None); - check("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, true, false, false, false, false, false, None); - check("fdff:ffff::", &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, true, false, false, false, false, false, None); - check("fe80:ffff::", &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, true, false, false, false, None); - check("febf:ffff::", &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, true, false, false, false, None); - check("fec0::", &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, true, false, false, None); - check("ff01::", &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(InterfaceLocal)); - check("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(LinkLocal)); - check("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(RealmLocal)); - check("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(AdminLocal)); - check("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(SiteLocal)); - check("ff08::", &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, false, false, false, false, false, Some(OrganizationLocal)); - check("ff0e::", &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - false, false, false, true, false, false, false, false, Some(Global)); - check("2001:db8:85a3::8a2e:370:7334", - &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], - false, false, false, false, false, false, false, true, None); - check("102:304:506:708:90a:b0c:d0e:f10", - &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], - false, false, false, true, false, false, true, false, None); - } - - #[test] - fn to_socket_addr_socketaddr() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); - assert_eq!(Ok(vec![a]), tsa(a)); - } - - #[test] - fn test_ipv4_to_int() { - let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); - assert_eq!(u32::from(a), 0x11223344); - } - - #[test] - fn test_int_to_ipv4() { - let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); - assert_eq!(Ipv4Addr::from(0x11223344), a); - } - - #[test] - fn test_ipv6_to_int() { - let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); - assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); - } - - #[test] - fn test_int_to_ipv6() { - let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); - assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); - } - - #[test] - fn ipv4_from_constructors() { - assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); - assert!(Ipv4Addr::LOCALHOST.is_loopback()); - assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); - assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); - assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); - assert!(Ipv4Addr::BROADCAST.is_broadcast()); - } - - #[test] - fn ipv6_from_contructors() { - assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - assert!(Ipv6Addr::LOCALHOST.is_loopback()); - assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); - } - - #[test] - fn ipv4_from_octets() { - assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)) - } - - #[test] - fn ipv6_from_segments() { - let from_u16s = Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, - 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, - 0x8899, 0xaabb, 0xccdd, 0xeeff); - assert_eq!(new, from_u16s); - } - - #[test] - fn ipv6_from_octets() { - let from_u16s = Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, - 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let from_u8s = Ipv6Addr::from([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]); - assert_eq!(from_u16s, from_u8s); - } - - #[test] - fn cmp() { - let v41 = Ipv4Addr::new(100, 64, 3, 3); - let v42 = Ipv4Addr::new(192, 0, 2, 2); - let v61 = "2001:db8:f00::1002".parse::().unwrap(); - let v62 = "2001:db8:f00::2001".parse::().unwrap(); - assert!(v41 < v42); - assert!(v61 < v62); - - assert_eq!(v41, IpAddr::V4(v41)); - assert_eq!(v61, IpAddr::V6(v61)); - assert!(v41 != IpAddr::V4(v42)); - assert!(v61 != IpAddr::V6(v62)); - - assert!(v41 < IpAddr::V4(v42)); - assert!(v61 < IpAddr::V6(v62)); - assert!(IpAddr::V4(v41) < v42); - assert!(IpAddr::V6(v61) < v62); - - assert!(v41 < IpAddr::V6(v61)); - assert!(IpAddr::V4(v41) < v61); - } - - #[test] - fn is_v4() { - let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); - assert!(ip.is_ipv4()); - assert!(!ip.is_ipv6()); - } - - #[test] - fn is_v6() { - let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); - assert!(!ip.is_ipv4()); - assert!(ip.is_ipv6()); - } -} diff --git a/ctr-std/src/net/mod.rs b/ctr-std/src/net/mod.rs deleted file mode 100644 index be4bcee..0000000 --- a/ctr-std/src/net/mod.rs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Networking primitives for TCP/UDP communication. -//! -//! This module provides networking functionality for the Transmission Control and User -//! Datagram Protocols, as well as types for IP and socket addresses. -//! -//! # Organization -//! -//! * [`TcpListener`] and [`TcpStream`] provide functionality for communication over TCP -//! * [`UdpSocket`] provides functionality for communication over UDP -//! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and -//! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses -//! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`] -//! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses -//! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting -//! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`] -//! * Other types are return or parameter types for various methods in this module -//! -//! [`IpAddr`]: ../../std/net/enum.IpAddr.html -//! [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html -//! [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html -//! [`SocketAddr`]: ../../std/net/enum.SocketAddr.html -//! [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html -//! [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html -//! [`TcpListener`]: ../../std/net/struct.TcpListener.html -//! [`TcpStream`]: ../../std/net/struct.TcpStream.html -//! [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html -//! [`UdpSocket`]: ../../std/net/struct.UdpSocket.html - -#![stable(feature = "rust1", since = "1.0.0")] - -use io::{self, Error, ErrorKind}; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::tcp::{TcpStream, TcpListener, Incoming}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::udp::UdpSocket; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::parser::AddrParseError; - -mod ip; -mod addr; -mod tcp; -mod udp; -mod parser; -#[cfg(test)] -mod test; - -/// Possible values which can be passed to the [`shutdown`] method of -/// [`TcpStream`]. -/// -/// [`shutdown`]: struct.TcpStream.html#method.shutdown -/// [`TcpStream`]: struct.TcpStream.html -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub enum Shutdown { - /// The reading portion of the [`TcpStream`] should be shut down. - /// - /// All currently blocked and future [reads] will return [`Ok(0)`]. - /// - /// [`TcpStream`]: ../../std/net/struct.TcpStream.html - /// [reads]: ../../std/io/trait.Read.html - /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok - #[stable(feature = "rust1", since = "1.0.0")] - Read, - /// The writing portion of the [`TcpStream`] should be shut down. - /// - /// All currently blocked and future [writes] will return an error. - /// - /// [`TcpStream`]: ../../std/net/struct.TcpStream.html - /// [writes]: ../../std/io/trait.Write.html - #[stable(feature = "rust1", since = "1.0.0")] - Write, - /// Both the reading and the writing portions of the [`TcpStream`] should be shut down. - /// - /// See [`Shutdown::Read`] and [`Shutdown::Write`] for more information. - /// - /// [`TcpStream`]: ../../std/net/struct.TcpStream.html - /// [`Shutdown::Read`]: #variant.Read - /// [`Shutdown::Write`]: #variant.Write - #[stable(feature = "rust1", since = "1.0.0")] - Both, -} - -#[doc(hidden)] -trait NetInt { - fn from_be(i: Self) -> Self; - fn to_be(&self) -> Self; -} -macro_rules! doit { - ($($t:ident)*) => ($(impl NetInt for $t { - fn from_be(i: Self) -> Self { <$t>::from_be(i) } - fn to_be(&self) -> Self { <$t>::to_be(*self) } - })*) -} -doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } - -fn hton(i: I) -> I { i.to_be() } -fn ntoh(i: I) -> I { I::from_be(i) } - -fn each_addr(addr: A, mut f: F) -> io::Result - where F: FnMut(&SocketAddr) -> io::Result -{ - let mut last_err = None; - for addr in addr.to_socket_addrs()? { - match f(&addr) { - Ok(l) => return Ok(l), - Err(e) => last_err = Some(e), - } - } - Err(last_err.unwrap_or_else(|| { - Error::new(ErrorKind::InvalidInput, - "could not resolve to any addresses") - })) -} diff --git a/ctr-std/src/net/parser.rs b/ctr-std/src/net/parser.rs deleted file mode 100644 index cf3e535..0000000 --- a/ctr-std/src/net/parser.rs +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A private parser implementation of IPv4, IPv6, and socket addresses. -//! -//! This module is "publicly exported" through the `FromStr` implementations -//! below. - -use error::Error; -use fmt; -use net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; -use str::FromStr; - -struct Parser<'a> { - // parsing as ASCII, so can use byte array - s: &'a [u8], - pos: usize, -} - -impl<'a> Parser<'a> { - fn new(s: &'a str) -> Parser<'a> { - Parser { - s: s.as_bytes(), - pos: 0, - } - } - - fn is_eof(&self) -> bool { - self.pos == self.s.len() - } - - // Commit only if parser returns Some - fn read_atomically(&mut self, cb: F) -> Option where - F: FnOnce(&mut Parser) -> Option, - { - let pos = self.pos; - let r = cb(self); - if r.is_none() { - self.pos = pos; - } - r - } - - // Commit only if parser read till EOF - fn read_till_eof(&mut self, cb: F) -> Option where - F: FnOnce(&mut Parser) -> Option, - { - self.read_atomically(move |p| { - cb(p).filter(|_| p.is_eof()) - }) - } - - // Return result of first successful parser - fn read_or(&mut self, parsers: &mut [Box Option + 'static>]) - -> Option { - for pf in parsers { - if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) { - return Some(r); - } - } - None - } - - // Apply 3 parsers sequentially - fn read_seq_3(&mut self, - pa: PA, - pb: PB, - pc: PC) - -> Option<(A, B, C)> where - PA: FnOnce(&mut Parser) -> Option, - PB: FnOnce(&mut Parser) -> Option, - PC: FnOnce(&mut Parser) -> Option, - { - self.read_atomically(move |p| { - let a = pa(p); - let b = if a.is_some() { pb(p) } else { None }; - let c = if b.is_some() { pc(p) } else { None }; - match (a, b, c) { - (Some(a), Some(b), Some(c)) => Some((a, b, c)), - _ => None - } - }) - } - - // Read next char - fn read_char(&mut self) -> Option { - if self.is_eof() { - None - } else { - let r = self.s[self.pos] as char; - self.pos += 1; - Some(r) - } - } - - // Return char and advance iff next char is equal to requested - fn read_given_char(&mut self, c: char) -> Option { - self.read_atomically(|p| { - match p.read_char() { - Some(next) if next == c => Some(next), - _ => None, - } - }) - } - - // Read digit - fn read_digit(&mut self, radix: u8) -> Option { - fn parse_digit(c: char, radix: u8) -> Option { - let c = c as u8; - // assuming radix is either 10 or 16 - if c >= b'0' && c <= b'9' { - Some(c - b'0') - } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) { - Some(c - b'a' + 10) - } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) { - Some(c - b'A' + 10) - } else { - None - } - } - - self.read_atomically(|p| { - p.read_char().and_then(|c| parse_digit(c, radix)) - }) - } - - fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { - let mut r = 0; - let mut digit_count = 0; - loop { - match self.read_digit(radix) { - Some(d) => { - r = r * (radix as u32) + (d as u32); - digit_count += 1; - if digit_count > max_digits || r >= upto { - return None - } - } - None => { - if digit_count == 0 { - return None - } else { - return Some(r) - } - } - }; - } - } - - // Read number, failing if max_digits of number value exceeded - fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { - self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto)) - } - - fn read_ipv4_addr_impl(&mut self) -> Option { - let mut bs = [0; 4]; - let mut i = 0; - while i < 4 { - if i != 0 && self.read_given_char('.').is_none() { - return None; - } - - bs[i] = self.read_number(10, 3, 0x100).map(|n| n as u8)?; - i += 1; - } - Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3])) - } - - // Read IPv4 address - fn read_ipv4_addr(&mut self) -> Option { - self.read_atomically(|p| p.read_ipv4_addr_impl()) - } - - fn read_ipv6_addr_impl(&mut self) -> Option { - fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr { - assert!(head.len() + tail.len() <= 8); - let mut gs = [0; 8]; - gs[..head.len()].copy_from_slice(head); - gs[(8 - tail.len()) .. 8].copy_from_slice(tail); - Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7]) - } - - fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize) - -> (usize, bool) { - let mut i = 0; - while i < limit { - if i < limit - 1 { - let ipv4 = p.read_atomically(|p| { - if i == 0 || p.read_given_char(':').is_some() { - p.read_ipv4_addr() - } else { - None - } - }); - if let Some(v4_addr) = ipv4 { - let octets = v4_addr.octets(); - groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16); - groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16); - return (i + 2, true); - } - } - - let group = p.read_atomically(|p| { - if i == 0 || p.read_given_char(':').is_some() { - p.read_number(16, 4, 0x10000).map(|n| n as u16) - } else { - None - } - }); - match group { - Some(g) => groups[i] = g, - None => return (i, false) - } - i += 1; - } - (i, false) - } - - let mut head = [0; 8]; - let (head_size, head_ipv4) = read_groups(self, &mut head, 8); - - if head_size == 8 { - return Some(Ipv6Addr::new( - head[0], head[1], head[2], head[3], - head[4], head[5], head[6], head[7])) - } - - // IPv4 part is not allowed before `::` - if head_ipv4 { - return None - } - - // read `::` if previous code parsed less than 8 groups - if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() { - return None; - } - - let mut tail = [0; 8]; - // `::` indicates one or more groups of 16 bits of zeros - let limit = 8 - (head_size + 1); - let (tail_size, _) = read_groups(self, &mut tail, limit); - Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size])) - } - - fn read_ipv6_addr(&mut self) -> Option { - self.read_atomically(|p| p.read_ipv6_addr_impl()) - } - - fn read_ip_addr(&mut self) -> Option { - let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr().map(IpAddr::V4); - let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr().map(IpAddr::V6); - self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)]) - } - - fn read_socket_addr_v4(&mut self) -> Option { - let ip_addr = |p: &mut Parser| p.read_ipv4_addr(); - let colon = |p: &mut Parser| p.read_given_char(':'); - let port = |p: &mut Parser| { - p.read_number(10, 5, 0x10000).map(|n| n as u16) - }; - - self.read_seq_3(ip_addr, colon, port).map(|t| { - let (ip, _, port): (Ipv4Addr, char, u16) = t; - SocketAddrV4::new(ip, port) - }) - } - - fn read_socket_addr_v6(&mut self) -> Option { - let ip_addr = |p: &mut Parser| { - let open_br = |p: &mut Parser| p.read_given_char('['); - let ip_addr = |p: &mut Parser| p.read_ipv6_addr(); - let clos_br = |p: &mut Parser| p.read_given_char(']'); - p.read_seq_3(open_br, ip_addr, clos_br).map(|t| t.1) - }; - let colon = |p: &mut Parser| p.read_given_char(':'); - let port = |p: &mut Parser| { - p.read_number(10, 5, 0x10000).map(|n| n as u16) - }; - - self.read_seq_3(ip_addr, colon, port).map(|t| { - let (ip, _, port): (Ipv6Addr, char, u16) = t; - SocketAddrV6::new(ip, port, 0, 0) - }) - } - - fn read_socket_addr(&mut self) -> Option { - let v4 = |p: &mut Parser| p.read_socket_addr_v4().map(SocketAddr::V4); - let v6 = |p: &mut Parser| p.read_socket_addr_v6().map(SocketAddr::V6); - self.read_or(&mut [Box::new(v4), Box::new(v6)]) - } -} - -#[stable(feature = "ip_addr", since = "1.7.0")] -impl FromStr for IpAddr { - type Err = AddrParseError; - fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl FromStr for Ipv4Addr { - type Err = AddrParseError; - fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl FromStr for Ipv6Addr { - type Err = AddrParseError; - fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())) - } - } -} - -#[stable(feature = "socket_addr_from_str", since = "1.5.0")] -impl FromStr for SocketAddrV4 { - type Err = AddrParseError; - fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v4()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())), - } - } -} - -#[stable(feature = "socket_addr_from_str", since = "1.5.0")] -impl FromStr for SocketAddrV6 { - type Err = AddrParseError; - fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v6()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl FromStr for SocketAddr { - type Err = AddrParseError; - fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())), - } - } -} - -/// An error which can be returned when parsing an IP address or a socket address. -/// -/// This error is used as the error type for the [`FromStr`] implementation for -/// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and -/// [`SocketAddrV6`]. -/// -/// # Potential causes -/// -/// `AddrParseError` may be thrown because the provided string does not parse as the given type, -/// often because it includes information only handled by a different address type. -/// -/// ```should_panic -/// use std::net::IpAddr; -/// let _foo: IpAddr = "127.0.0.1:8080".parse().expect("Cannot handle the socket port"); -/// ``` -/// -/// [`IpAddr`] doesn't handle the port. Use [`SocketAddr`] instead. -/// -/// ``` -/// use std::net::SocketAddr; -/// -/// // No problem, the `panic!` message has disappeared. -/// let _foo: SocketAddr = "127.0.0.1:8080".parse().expect("unreachable panic"); -/// ``` -/// -/// [`FromStr`]: ../../std/str/trait.FromStr.html -/// [`IpAddr`]: ../../std/net/enum.IpAddr.html -/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html -/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html -/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html -/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html -/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct AddrParseError(()); - -#[stable(feature = "addr_parse_error_error", since = "1.4.0")] -impl fmt::Display for AddrParseError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_str(self.description()) - } -} - -#[stable(feature = "addr_parse_error_error", since = "1.4.0")] -impl Error for AddrParseError { - fn description(&self) -> &str { - "invalid IP address syntax" - } -} diff --git a/ctr-std/src/net/tcp.rs b/ctr-std/src/net/tcp.rs deleted file mode 100644 index 75c7a3d..0000000 --- a/ctr-std/src/net/tcp.rs +++ /dev/null @@ -1,1713 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io::prelude::*; - -use fmt; -use io::{self, Initializer}; -use net::{ToSocketAddrs, SocketAddr, Shutdown}; -use sys_common::net as net_imp; -use sys_common::{AsInner, FromInner, IntoInner}; -use time::Duration; - -/// A TCP stream between a local and a remote socket. -/// -/// After creating a `TcpStream` by either [`connect`]ing to a remote host or -/// [`accept`]ing a connection on a [`TcpListener`], data can be transmitted -/// by [reading] and [writing] to it. -/// -/// The connection will be closed when the value is dropped. The reading and writing -/// portions of the connection can also be shut down individually with the [`shutdown`] -/// method. -/// -/// The Transmission Control Protocol is specified in [IETF RFC 793]. -/// -/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept -/// [`connect`]: #method.connect -/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 -/// [reading]: ../../std/io/trait.Read.html -/// [`shutdown`]: #method.shutdown -/// [`TcpListener`]: ../../std/net/struct.TcpListener.html -/// [writing]: ../../std/io/trait.Write.html -/// -/// # Examples -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::net::TcpStream; -/// -/// { -/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); -/// -/// // ignore the Result -/// let _ = stream.write(&[1]); -/// let _ = stream.read(&mut [0; 128]); // ignore here too -/// } // the stream is closed here -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct TcpStream(net_imp::TcpStream); - -/// A TCP socket server, listening for connections. -/// -/// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens -/// for incoming TCP connections. These can be accepted by calling [`accept`] or by -/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`]. -/// -/// The socket will be closed when the value is dropped. -/// -/// The Transmission Control Protocol is specified in [IETF RFC 793]. -/// -/// [`accept`]: #method.accept -/// [`bind`]: #method.bind -/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 -/// [`Incoming`]: ../../std/net/struct.Incoming.html -/// [`TcpListener::incoming`]: #method.incoming -/// -/// # Examples -/// -/// ```no_run -/// # use std::io; -/// use std::net::{TcpListener, TcpStream}; -/// -/// fn handle_client(stream: TcpStream) { -/// // ... -/// } -/// -/// fn main() -> io::Result<()> { -/// let listener = TcpListener::bind("127.0.0.1:80")?; -/// -/// // accept connections and process them serially -/// for stream in listener.incoming() { -/// handle_client(stream?); -/// } -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct TcpListener(net_imp::TcpListener); - -/// An iterator that infinitely [`accept`]s connections on a [`TcpListener`]. -/// -/// This `struct` is created by the [`incoming`] method on [`TcpListener`]. -/// See its documentation for more. -/// -/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept -/// [`incoming`]: ../../std/net/struct.TcpListener.html#method.incoming -/// [`TcpListener`]: ../../std/net/struct.TcpListener.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct Incoming<'a> { listener: &'a TcpListener } - -impl TcpStream { - /// Opens a TCP connection to a remote host. - /// - /// `addr` is an address of the remote host. Anything which implements - /// [`ToSocketAddrs`] trait can be supplied for the address; see this trait - /// documentation for concrete examples. - /// - /// If `addr` yields multiple addresses, `connect` will be attempted with - /// each of the addresses until a connection is successful. If none of - /// the addresses result in a successful connection, the error returned from - /// the last connection attempt (the last address) is returned. - /// - /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html - /// - /// # Examples - /// - /// Open a TCP connection to `127.0.0.1:8080`: - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// if let Ok(stream) = TcpStream::connect("127.0.0.1:8080") { - /// println!("Connected to the server!"); - /// } else { - /// println!("Couldn't connect to server..."); - /// } - /// ``` - /// - /// Open a TCP connection to `127.0.0.1:8080`. If the connection fails, open - /// a TCP connection to `127.0.0.1:8081`: - /// - /// ```no_run - /// use std::net::{SocketAddr, TcpStream}; - /// - /// let addrs = [ - /// SocketAddr::from(([127, 0, 0, 1], 8080)), - /// SocketAddr::from(([127, 0, 0, 1], 8081)), - /// ]; - /// if let Ok(stream) = TcpStream::connect(&addrs[..]) { - /// println!("Connected to the server!"); - /// } else { - /// println!("Couldn't connect to server..."); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn connect(addr: A) -> io::Result { - super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream) - } - - /// Opens a TCP connection to a remote host with a timeout. - /// - /// Unlike `connect`, `connect_timeout` takes a single [`SocketAddr`] since - /// timeout must be applied to individual addresses. - /// - /// It is an error to pass a zero `Duration` to this function. - /// - /// Unlike other methods on `TcpStream`, this does not correspond to a - /// single system call. It instead calls `connect` in nonblocking mode and - /// then uses an OS-specific mechanism to await the completion of the - /// connection request. - /// - /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html - #[stable(feature = "tcpstream_connect_timeout", since = "1.21.0")] - pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { - net_imp::TcpStream::connect_timeout(addr, timeout).map(TcpStream) - } - - /// Returns the socket address of the remote peer of this TCP connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpStream}; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// assert_eq!(stream.peer_addr().unwrap(), - /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080))); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn peer_addr(&self) -> io::Result { - self.0.peer_addr() - } - - /// Returns the socket address of the local half of this TCP connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::{IpAddr, Ipv4Addr, TcpStream}; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// assert_eq!(stream.local_addr().unwrap().ip(), - /// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn local_addr(&self) -> io::Result { - self.0.socket_addr() - } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O on the specified - /// portions to return immediately with an appropriate value (see the - /// documentation of [`Shutdown`]). - /// - /// [`Shutdown`]: ../../std/net/enum.Shutdown.html - /// - /// # Platform-specific behavior - /// - /// Calling this function multiple times may result in different behavior, - /// depending on the operating system. On Linux, the second call will - /// return `Ok(())`, but on macOS, it will return `ErrorKind::NotConnected`. - /// This may change in the future. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::{Shutdown, TcpStream}; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// stream.shutdown(Shutdown::Both).expect("shutdown call failed"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `TcpStream` is a reference to the same stream that this - /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propagated to the other - /// stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// let stream_clone = stream.try_clone().expect("clone failed..."); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(TcpStream) - } - - /// Sets the read timeout to the timeout specified. - /// - /// If the value specified is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// # Platform-specific behavior - /// - /// Platforms may return a different error code whenever a read times out as - /// a result of setting this option. For example Unix typically returns an - /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// [`read`]: ../../std/io/trait.Read.html#tymethod.read - /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock - /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut - /// [`Duration`]: ../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// stream.set_read_timeout(None).expect("set_read_timeout call failed"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::TcpStream; - /// use std::time::Duration; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080").unwrap(); - /// let result = stream.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "socket_timeout", since = "1.4.0")] - pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { - self.0.set_read_timeout(dur) - } - - /// Sets the write timeout to the timeout specified. - /// - /// If the value specified is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// # Platform-specific behavior - /// - /// Platforms may return a different error code whenever a write times out - /// as a result of setting this option. For example Unix typically returns - /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// [`write`]: ../../std/io/trait.Write.html#tymethod.write - /// [`Duration`]: ../../std/time/struct.Duration.html - /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock - /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// stream.set_write_timeout(None).expect("set_write_timeout call failed"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::TcpStream; - /// use std::time::Duration; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080").unwrap(); - /// let result = stream.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "socket_timeout", since = "1.4.0")] - pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { - self.0.set_write_timeout(dur) - } - - /// Returns the read timeout of this socket. - /// - /// If the timeout is [`None`], then [`read`] calls will block indefinitely. - /// - /// # Platform-specific behavior - /// - /// Some platforms do not provide access to the current timeout. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`read`]: ../../std/io/trait.Read.html#tymethod.read - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// stream.set_read_timeout(None).expect("set_read_timeout call failed"); - /// assert_eq!(stream.read_timeout().unwrap(), None); - /// ``` - #[stable(feature = "socket_timeout", since = "1.4.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.read_timeout() - } - - /// Returns the write timeout of this socket. - /// - /// If the timeout is [`None`], then [`write`] calls will block indefinitely. - /// - /// # Platform-specific behavior - /// - /// Some platforms do not provide access to the current timeout. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`write`]: ../../std/io/trait.Write.html#tymethod.write - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// stream.set_write_timeout(None).expect("set_write_timeout call failed"); - /// assert_eq!(stream.write_timeout().unwrap(), None); - /// ``` - #[stable(feature = "socket_timeout", since = "1.4.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.write_timeout() - } - - /// Receives data on the socket from the remote address to which it is - /// connected, without removing that data from the queue. On success, - /// returns the number of bytes peeked. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:8000") - /// .expect("couldn't bind to address"); - /// let mut buf = [0; 10]; - /// let len = stream.peek(&mut buf).expect("peek failed"); - /// ``` - #[stable(feature = "peek", since = "1.18.0")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } - - /// Sets the value of the `TCP_NODELAY` option on this socket. - /// - /// If set, this option disables the Nagle algorithm. This means that - /// segments are always sent as soon as possible, even if there is only a - /// small amount of data. When not set, data is buffered until there is a - /// sufficient amount to send out, thereby avoiding the frequent sending of - /// small packets. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// stream.set_nodelay(true).expect("set_nodelay call failed"); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - self.0.set_nodelay(nodelay) - } - - /// Gets the value of the `TCP_NODELAY` option on this socket. - /// - /// For more information about this option, see [`set_nodelay`][link]. - /// - /// [link]: #method.set_nodelay - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// stream.set_nodelay(true).expect("set_nodelay call failed"); - /// assert_eq!(stream.nodelay().unwrap_or(false), true); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn nodelay(&self) -> io::Result { - self.0.nodelay() - } - - /// Sets the value for the `IP_TTL` option on this socket. - /// - /// This value sets the time-to-live field that is used in every packet sent - /// from this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// stream.set_ttl(100).expect("set_ttl call failed"); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - self.0.set_ttl(ttl) - } - - /// Gets the value of the `IP_TTL` option for this socket. - /// - /// For more information about this option, see [`set_ttl`][link]. - /// - /// [link]: #method.set_ttl - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// stream.set_ttl(100).expect("set_ttl call failed"); - /// assert_eq!(stream.ttl().unwrap_or(0), 100); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn ttl(&self) -> io::Result { - self.0.ttl() - } - - /// Get the value of the `SO_ERROR` option on this socket. - /// - /// This will retrieve the stored error in the underlying socket, clearing - /// the field in the process. This can be useful for checking errors between - /// calls. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:8080") - /// .expect("Couldn't connect to the server..."); - /// stream.take_error().expect("No error was expected..."); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Moves this TCP stream into or out of nonblocking mode. - /// - /// This will result in `read`, `write`, `recv` and `send` operations - /// becoming nonblocking, i.e. immediately returning from their calls. - /// If the IO operation is successful, `Ok` is returned and no further - /// action is required. If the IO operation could not be completed and needs - /// to be retried, an error with kind [`io::ErrorKind::WouldBlock`] is - /// returned. - /// - /// On Unix platforms, calling this method corresponds to calling `fcntl` - /// `FIONBIO`. On Windows calling this method corresponds to calling - /// `ioctlsocket` `FIONBIO`. - /// - /// # Examples - /// - /// Reading bytes from a TCP stream in non-blocking mode: - /// - /// ```no_run - /// use std::io::{self, Read}; - /// use std::net::TcpStream; - /// - /// let mut stream = TcpStream::connect("127.0.0.1:7878") - /// .expect("Couldn't connect to the server..."); - /// stream.set_nonblocking(true).expect("set_nonblocking call failed"); - /// - /// # fn wait_for_fd() { unimplemented!() } - /// let mut buf = vec![]; - /// loop { - /// match stream.read_to_end(&mut buf) { - /// Ok(_) => break, - /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { - /// // wait until network socket is ready, typically implemented - /// // via platform-specific APIs such as epoll or IOCP - /// wait_for_fd(); - /// } - /// Err(e) => panic!("encountered IO error: {}", e), - /// }; - /// }; - /// println!("bytes: {:?}", buf); - /// ``` - /// - /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for TcpStream { - fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Read for &'a TcpStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Write for &'a TcpStream { - fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -impl AsInner for TcpStream { - fn as_inner(&self) -> &net_imp::TcpStream { &self.0 } -} - -impl FromInner for TcpStream { - fn from_inner(inner: net_imp::TcpStream) -> TcpStream { TcpStream(inner) } -} - -impl IntoInner for TcpStream { - fn into_inner(self) -> net_imp::TcpStream { self.0 } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for TcpStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl TcpListener { - /// Creates a new `TcpListener` which will be bound to the specified - /// address. - /// - /// The returned listener is ready for accepting connections. - /// - /// Binding with a port number of 0 will request that the OS assigns a port - /// to this listener. The port allocated can be queried via the - /// [`local_addr`] method. - /// - /// The address type can be any implementor of [`ToSocketAddrs`] trait. See - /// its documentation for concrete examples. - /// - /// If `addr` yields multiple addresses, `bind` will be attempted with - /// each of the addresses until one succeeds and returns the listener. If - /// none of the addresses succeed in creating a listener, the error returned - /// from the last attempt (the last address) is returned. - /// - /// [`local_addr`]: #method.local_addr - /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html - /// - /// # Examples - /// - /// Create a TCP listener bound to `127.0.0.1:80`: - /// - /// ```no_run - /// use std::net::TcpListener; - /// - /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); - /// ``` - /// - /// Create a TCP listener bound to `127.0.0.1:80`. If that fails, create a - /// TCP listener bound to `127.0.0.1:443`: - /// - /// ```no_run - /// use std::net::{SocketAddr, TcpListener}; - /// - /// let addrs = [ - /// SocketAddr::from(([127, 0, 0, 1], 80)), - /// SocketAddr::from(([127, 0, 0, 1], 443)), - /// ]; - /// let listener = TcpListener::bind(&addrs[..]).unwrap(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn bind(addr: A) -> io::Result { - super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener) - } - - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener}; - /// - /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); - /// assert_eq!(listener.local_addr().unwrap(), - /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080))); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn local_addr(&self) -> io::Result { - self.0.socket_addr() - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned [`TcpListener`] is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one listener will affect the other. - /// - /// [`TcpListener`]: ../../std/net/struct.TcpListener.html - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpListener; - /// - /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); - /// let listener_clone = listener.try_clone().unwrap(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(TcpListener) - } - - /// Accept a new incoming connection from this listener. - /// - /// This function will block the calling thread until a new TCP connection - /// is established. When established, the corresponding [`TcpStream`] and the - /// remote peer's address will be returned. - /// - /// [`TcpStream`]: ../../std/net/struct.TcpStream.html - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpListener; - /// - /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); - /// match listener.accept() { - /// Ok((_socket, addr)) => println!("new client: {:?}", addr), - /// Err(e) => println!("couldn't get client: {:?}", e), - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - self.0.accept().map(|(a, b)| (TcpStream(a), b)) - } - - /// Returns an iterator over the connections being received on this - /// listener. - /// - /// The returned iterator will never return [`None`] and will also not yield - /// the peer's [`SocketAddr`] structure. Iterating over it is equivalent to - /// calling [`accept`] in a loop. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html - /// [`accept`]: #method.accept - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpListener; - /// - /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// println!("new client!"); - /// } - /// Err(e) => { /* connection failed */ } - /// } - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn incoming(&self) -> Incoming { - Incoming { listener: self } - } - - /// Sets the value for the `IP_TTL` option on this socket. - /// - /// This value sets the time-to-live field that is used in every packet sent - /// from this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpListener; - /// - /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); - /// listener.set_ttl(100).expect("could not set TTL"); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - self.0.set_ttl(ttl) - } - - /// Gets the value of the `IP_TTL` option for this socket. - /// - /// For more information about this option, see [`set_ttl`][link]. - /// - /// [link]: #method.set_ttl - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpListener; - /// - /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); - /// listener.set_ttl(100).expect("could not set TTL"); - /// assert_eq!(listener.ttl().unwrap_or(0), 100); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn ttl(&self) -> io::Result { - self.0.ttl() - } - - #[stable(feature = "net2_mutators", since = "1.9.0")] - #[rustc_deprecated(since = "1.16.0", - reason = "this option can only be set before the socket is bound")] - #[allow(missing_docs)] - pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { - self.0.set_only_v6(only_v6) - } - - #[stable(feature = "net2_mutators", since = "1.9.0")] - #[rustc_deprecated(since = "1.16.0", - reason = "this option can only be set before the socket is bound")] - #[allow(missing_docs)] - pub fn only_v6(&self) -> io::Result { - self.0.only_v6() - } - - /// Get the value of the `SO_ERROR` option on this socket. - /// - /// This will retrieve the stored error in the underlying socket, clearing - /// the field in the process. This can be useful for checking errors between - /// calls. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpListener; - /// - /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); - /// listener.take_error().expect("No error was expected"); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Moves this TCP stream into or out of nonblocking mode. - /// - /// This will result in the `accept` operation becoming nonblocking, - /// i.e. immediately returning from their calls. If the IO operation is - /// successful, `Ok` is returned and no further action is required. If the - /// IO operation could not be completed and needs to be retried, an error - /// with kind [`io::ErrorKind::WouldBlock`] is returned. - /// - /// On Unix platforms, calling this method corresponds to calling `fcntl` - /// `FIONBIO`. On Windows calling this method corresponds to calling - /// `ioctlsocket` `FIONBIO`. - /// - /// # Examples - /// - /// Bind a TCP listener to an address, listen for connections, and read - /// bytes in nonblocking mode: - /// - /// ```no_run - /// use std::io; - /// use std::net::TcpListener; - /// - /// let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); - /// listener.set_nonblocking(true).expect("Cannot set non-blocking"); - /// - /// # fn wait_for_fd() { unimplemented!() } - /// # fn handle_connection(stream: std::net::TcpStream) { unimplemented!() } - /// for stream in listener.incoming() { - /// match stream { - /// Ok(s) => { - /// // do something with the TcpStream - /// handle_connection(s); - /// } - /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { - /// // wait until network socket is ready, typically implemented - /// // via platform-specific APIs such as epoll or IOCP - /// wait_for_fd(); - /// continue; - /// } - /// Err(e) => panic!("encountered IO error: {}", e), - /// } - /// } - /// ``` - /// - /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for Incoming<'a> { - type Item = io::Result; - fn next(&mut self) -> Option> { - Some(self.listener.accept().map(|p| p.0)) - } -} - -impl AsInner for TcpListener { - fn as_inner(&self) -> &net_imp::TcpListener { &self.0 } -} - -impl FromInner for TcpListener { - fn from_inner(inner: net_imp::TcpListener) -> TcpListener { - TcpListener(inner) - } -} - -impl IntoInner for TcpListener { - fn into_inner(self) -> net_imp::TcpListener { self.0 } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for TcpListener { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] -mod tests { - use io::ErrorKind; - use io::prelude::*; - use net::*; - use net::test::{next_test_ip4, next_test_ip6}; - use sync::mpsc::channel; - use sys_common::AsInner; - use time::{Instant, Duration}; - use thread; - - fn each_ip(f: &mut dyn FnMut(SocketAddr)) { - f(next_test_ip4()); - f(next_test_ip6()); - } - - macro_rules! t { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), - } - } - } - - #[test] - fn bind_error() { - match TcpListener::bind("1.1.1.1:9999") { - Ok(..) => panic!(), - Err(e) => - assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), - } - } - - #[test] - fn connect_error() { - match TcpStream::connect("0.0.0.0:1") { - Ok(..) => panic!(), - Err(e) => assert!(e.kind() == ErrorKind::ConnectionRefused || - e.kind() == ErrorKind::InvalidInput || - e.kind() == ErrorKind::AddrInUse || - e.kind() == ErrorKind::AddrNotAvailable, - "bad error: {} {:?}", e, e.kind()), - } - } - - #[test] - fn listen_localhost() { - let socket_addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&socket_addr)); - - let _t = thread::spawn(move || { - let mut stream = t!(TcpStream::connect(&("localhost", - socket_addr.port()))); - t!(stream.write(&[144])); - }); - - let mut stream = t!(listener.accept()).0; - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 144); - } - - #[test] - fn connect_loopback() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move|| { - let host = match addr { - SocketAddr::V4(..) => "127.0.0.1", - SocketAddr::V6(..) => "::1", - }; - let mut stream = t!(TcpStream::connect(&(host, addr.port()))); - t!(stream.write(&[66])); - }); - - let mut stream = t!(acceptor.accept()).0; - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 66); - }) - } - - #[test] - fn smoke_test() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let mut stream = t!(TcpStream::connect(&addr)); - t!(stream.write(&[99])); - tx.send(t!(stream.local_addr())).unwrap(); - }); - - let (mut stream, addr) = t!(acceptor.accept()); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 99); - assert_eq!(addr, t!(rx.recv())); - }) - } - - #[test] - fn read_eof() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move|| { - let _stream = t!(TcpStream::connect(&addr)); - // Close - }); - - let mut stream = t!(acceptor.accept()).0; - let mut buf = [0]; - let nread = t!(stream.read(&mut buf)); - assert_eq!(nread, 0); - let nread = t!(stream.read(&mut buf)); - assert_eq!(nread, 0); - }) - } - - #[test] - fn write_close() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - drop(t!(TcpStream::connect(&addr))); - tx.send(()).unwrap(); - }); - - let mut stream = t!(acceptor.accept()).0; - rx.recv().unwrap(); - let buf = [0]; - match stream.write(&buf) { - Ok(..) => {} - Err(e) => { - assert!(e.kind() == ErrorKind::ConnectionReset || - e.kind() == ErrorKind::BrokenPipe || - e.kind() == ErrorKind::ConnectionAborted, - "unknown error: {}", e); - } - } - }) - } - - #[test] - fn multiple_connect_serial() { - each_ip(&mut |addr| { - let max = 10; - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move|| { - for _ in 0..max { - let mut stream = t!(TcpStream::connect(&addr)); - t!(stream.write(&[99])); - } - }); - - for stream in acceptor.incoming().take(max) { - let mut stream = t!(stream); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert_eq!(buf[0], 99); - } - }) - } - - #[test] - fn multiple_connect_interleaved_greedy_schedule() { - const MAX: usize = 10; - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move|| { - let acceptor = acceptor; - for (i, stream) in acceptor.incoming().enumerate().take(MAX) { - // Start another thread to handle the connection - let _t = thread::spawn(move|| { - let mut stream = t!(stream); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == i as u8); - }); - } - }); - - connect(0, addr); - }); - - fn connect(i: usize, addr: SocketAddr) { - if i == MAX { return } - - let t = thread::spawn(move|| { - let mut stream = t!(TcpStream::connect(&addr)); - // Connect again before writing - connect(i + 1, addr); - t!(stream.write(&[i as u8])); - }); - t.join().ok().unwrap(); - } - } - - #[test] - fn multiple_connect_interleaved_lazy_schedule() { - const MAX: usize = 10; - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move|| { - for stream in acceptor.incoming().take(MAX) { - // Start another thread to handle the connection - let _t = thread::spawn(move|| { - let mut stream = t!(stream); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 99); - }); - } - }); - - connect(0, addr); - }); - - fn connect(i: usize, addr: SocketAddr) { - if i == MAX { return } - - let t = thread::spawn(move|| { - let mut stream = t!(TcpStream::connect(&addr)); - connect(i + 1, addr); - t!(stream.write(&[99])); - }); - t.join().ok().unwrap(); - } - } - - #[test] - fn socket_and_peer_name() { - each_ip(&mut |addr| { - let listener = t!(TcpListener::bind(&addr)); - let so_name = t!(listener.local_addr()); - assert_eq!(addr, so_name); - let _t = thread::spawn(move|| { - t!(listener.accept()); - }); - - let stream = t!(TcpStream::connect(&addr)); - assert_eq!(addr, t!(stream.peer_addr())); - }) - } - - #[test] - fn partial_read() { - each_ip(&mut |addr| { - let (tx, rx) = channel(); - let srv = t!(TcpListener::bind(&addr)); - let _t = thread::spawn(move|| { - let mut cl = t!(srv.accept()).0; - cl.write(&[10]).unwrap(); - let mut b = [0]; - t!(cl.read(&mut b)); - tx.send(()).unwrap(); - }); - - let mut c = t!(TcpStream::connect(&addr)); - let mut b = [0; 10]; - assert_eq!(c.read(&mut b).unwrap(), 1); - t!(c.write(&[1])); - rx.recv().unwrap(); - }) - } - - #[test] - fn double_bind() { - each_ip(&mut |addr| { - let _listener = t!(TcpListener::bind(&addr)); - match TcpListener::bind(&addr) { - Ok(..) => panic!(), - Err(e) => { - assert!(e.kind() == ErrorKind::ConnectionRefused || - e.kind() == ErrorKind::Other || - e.kind() == ErrorKind::AddrInUse, - "unknown error: {} {:?}", e, e.kind()); - } - } - }) - } - - #[test] - fn fast_rebind() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move|| { - t!(TcpStream::connect(&addr)); - }); - - t!(acceptor.accept()); - drop(acceptor); - t!(TcpListener::bind(&addr)); - }); - } - - #[test] - fn tcp_clone_smoke() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move|| { - let mut s = t!(TcpStream::connect(&addr)); - let mut buf = [0, 0]; - assert_eq!(s.read(&mut buf).unwrap(), 1); - assert_eq!(buf[0], 1); - t!(s.write(&[2])); - }); - - let mut s1 = t!(acceptor.accept()).0; - let s2 = t!(s1.try_clone()); - - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - rx1.recv().unwrap(); - t!(s2.write(&[1])); - tx2.send(()).unwrap(); - }); - tx1.send(()).unwrap(); - let mut buf = [0, 0]; - assert_eq!(s1.read(&mut buf).unwrap(), 1); - rx2.recv().unwrap(); - }) - } - - #[test] - fn tcp_clone_two_read() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - let (tx1, rx) = channel(); - let tx2 = tx1.clone(); - - let _t = thread::spawn(move|| { - let mut s = t!(TcpStream::connect(&addr)); - t!(s.write(&[1])); - rx.recv().unwrap(); - t!(s.write(&[2])); - rx.recv().unwrap(); - }); - - let mut s1 = t!(acceptor.accept()).0; - let s2 = t!(s1.try_clone()); - - let (done, rx) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - let mut buf = [0, 0]; - t!(s2.read(&mut buf)); - tx2.send(()).unwrap(); - done.send(()).unwrap(); - }); - let mut buf = [0, 0]; - t!(s1.read(&mut buf)); - tx1.send(()).unwrap(); - - rx.recv().unwrap(); - }) - } - - #[test] - fn tcp_clone_two_write() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move|| { - let mut s = t!(TcpStream::connect(&addr)); - let mut buf = [0, 1]; - t!(s.read(&mut buf)); - t!(s.read(&mut buf)); - }); - - let mut s1 = t!(acceptor.accept()).0; - let s2 = t!(s1.try_clone()); - - let (done, rx) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - t!(s2.write(&[1])); - done.send(()).unwrap(); - }); - t!(s1.write(&[2])); - - rx.recv().unwrap(); - }) - } - - #[test] - fn shutdown_smoke() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let _t = thread::spawn(move|| { - let mut c = t!(a.accept()).0; - let mut b = [0]; - assert_eq!(c.read(&mut b).unwrap(), 0); - t!(c.write(&[1])); - }); - - let mut s = t!(TcpStream::connect(&addr)); - t!(s.shutdown(Shutdown::Write)); - assert!(s.write(&[1]).is_err()); - let mut b = [0, 0]; - assert_eq!(t!(s.read(&mut b)), 1); - assert_eq!(b[0], 1); - }) - } - - #[test] - fn close_readwrite_smoke() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let (tx, rx) = channel::<()>(); - let _t = thread::spawn(move|| { - let _s = t!(a.accept()); - let _ = rx.recv(); - }); - - let mut b = [0]; - let mut s = t!(TcpStream::connect(&addr)); - let mut s2 = t!(s.try_clone()); - - // closing should prevent reads/writes - t!(s.shutdown(Shutdown::Write)); - assert!(s.write(&[0]).is_err()); - t!(s.shutdown(Shutdown::Read)); - assert_eq!(s.read(&mut b).unwrap(), 0); - - // closing should affect previous handles - assert!(s2.write(&[0]).is_err()); - assert_eq!(s2.read(&mut b).unwrap(), 0); - - // closing should affect new handles - let mut s3 = t!(s.try_clone()); - assert!(s3.write(&[0]).is_err()); - assert_eq!(s3.read(&mut b).unwrap(), 0); - - // make sure these don't die - let _ = s2.shutdown(Shutdown::Read); - let _ = s2.shutdown(Shutdown::Write); - let _ = s3.shutdown(Shutdown::Read); - let _ = s3.shutdown(Shutdown::Write); - drop(tx); - }) - } - - #[test] - #[cfg(unix)] // test doesn't work on Windows, see #31657 - fn close_read_wakes_up() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let (tx1, rx) = channel::<()>(); - let _t = thread::spawn(move|| { - let _s = t!(a.accept()); - let _ = rx.recv(); - }); - - let s = t!(TcpStream::connect(&addr)); - let s2 = t!(s.try_clone()); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - assert_eq!(t!(s2.read(&mut [0])), 0); - tx.send(()).unwrap(); - }); - // this should wake up the child thread - t!(s.shutdown(Shutdown::Read)); - - // this test will never finish if the child doesn't wake up - rx.recv().unwrap(); - drop(tx1); - }) - } - - #[test] - fn clone_while_reading() { - each_ip(&mut |addr| { - let accept = t!(TcpListener::bind(&addr)); - - // Enqueue a thread to write to a socket - let (tx, rx) = channel(); - let (txdone, rxdone) = channel(); - let txdone2 = txdone.clone(); - let _t = thread::spawn(move|| { - let mut tcp = t!(TcpStream::connect(&addr)); - rx.recv().unwrap(); - t!(tcp.write(&[0])); - txdone2.send(()).unwrap(); - }); - - // Spawn off a reading clone - let tcp = t!(accept.accept()).0; - let tcp2 = t!(tcp.try_clone()); - let txdone3 = txdone.clone(); - let _t = thread::spawn(move|| { - let mut tcp2 = tcp2; - t!(tcp2.read(&mut [0])); - txdone3.send(()).unwrap(); - }); - - // Try to ensure that the reading clone is indeed reading - for _ in 0..50 { - thread::yield_now(); - } - - // clone the handle again while it's reading, then let it finish the - // read. - let _ = t!(tcp.try_clone()); - tx.send(()).unwrap(); - rxdone.recv().unwrap(); - rxdone.recv().unwrap(); - }) - } - - #[test] - fn clone_accept_smoke() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let a2 = t!(a.try_clone()); - - let _t = thread::spawn(move|| { - let _ = TcpStream::connect(&addr); - }); - let _t = thread::spawn(move|| { - let _ = TcpStream::connect(&addr); - }); - - t!(a.accept()); - t!(a2.accept()); - }) - } - - #[test] - fn clone_accept_concurrent() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let a2 = t!(a.try_clone()); - - let (tx, rx) = channel(); - let tx2 = tx.clone(); - - let _t = thread::spawn(move|| { - tx.send(t!(a.accept())).unwrap(); - }); - let _t = thread::spawn(move|| { - tx2.send(t!(a2.accept())).unwrap(); - }); - - let _t = thread::spawn(move|| { - let _ = TcpStream::connect(&addr); - }); - let _t = thread::spawn(move|| { - let _ = TcpStream::connect(&addr); - }); - - rx.recv().unwrap(); - rx.recv().unwrap(); - }) - } - - #[test] - fn debug() { - let name = if cfg!(windows) {"socket"} else {"fd"}; - let socket_addr = next_test_ip4(); - - let listener = t!(TcpListener::bind(&socket_addr)); - let listener_inner = listener.0.socket().as_inner(); - let compare = format!("TcpListener {{ addr: {:?}, {}: {:?} }}", - socket_addr, name, listener_inner); - assert_eq!(format!("{:?}", listener), compare); - - let stream = t!(TcpStream::connect(&("localhost", - socket_addr.port()))); - let stream_inner = stream.0.socket().as_inner(); - let compare = format!("TcpStream {{ addr: {:?}, \ - peer: {:?}, {}: {:?} }}", - stream.local_addr().unwrap(), - stream.peer_addr().unwrap(), - name, - stream_inner); - assert_eq!(format!("{:?}", stream), compare); - } - - // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code - // no longer has rounding errors. - #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] - #[test] - fn timeouts() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - let stream = t!(TcpStream::connect(&("localhost", addr.port()))); - let dur = Duration::new(15410, 0); - - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_read_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.read_timeout())); - - assert_eq!(None, t!(stream.write_timeout())); - - t!(stream.set_write_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.write_timeout())); - - t!(stream.set_read_timeout(None)); - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_write_timeout(None)); - assert_eq!(None, t!(stream.write_timeout())); - drop(listener); - } - - #[test] - fn test_read_timeout() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut buf = [0; 10]; - let start = Instant::now(); - let kind = stream.read(&mut buf).err().expect("expected error").kind(); - assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); - assert!(start.elapsed() > Duration::from_millis(400)); - drop(listener); - } - - #[test] - fn test_read_with_timeout() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut other_end = t!(listener.accept()).0; - t!(other_end.write_all(b"hello world")); - - let mut buf = [0; 11]; - t!(stream.read(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - - let start = Instant::now(); - let kind = stream.read(&mut buf).err().expect("expected error").kind(); - assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); - assert!(start.elapsed() > Duration::from_millis(400)); - drop(listener); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_timeout_zero_duration() { - let addr = next_test_ip4(); - - let listener = t!(TcpListener::bind(&addr)); - let stream = t!(TcpStream::connect(&addr)); - - let result = stream.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = stream.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - drop(listener); - } - - #[test] - fn nodelay() { - let addr = next_test_ip4(); - let _listener = t!(TcpListener::bind(&addr)); - - let stream = t!(TcpStream::connect(&("localhost", addr.port()))); - - assert_eq!(false, t!(stream.nodelay())); - t!(stream.set_nodelay(true)); - assert_eq!(true, t!(stream.nodelay())); - t!(stream.set_nodelay(false)); - assert_eq!(false, t!(stream.nodelay())); - } - - #[test] - fn ttl() { - let ttl = 100; - - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - t!(listener.set_ttl(ttl)); - assert_eq!(ttl, t!(listener.ttl())); - - let stream = t!(TcpStream::connect(&("localhost", addr.port()))); - - t!(stream.set_ttl(ttl)); - assert_eq!(ttl, t!(stream.ttl())); - } - - #[test] - fn set_nonblocking() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - t!(listener.set_nonblocking(true)); - t!(listener.set_nonblocking(false)); - - let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); - - t!(stream.set_nonblocking(false)); - t!(stream.set_nonblocking(true)); - - let mut buf = [0]; - match stream.read(&mut buf) { - Ok(_) => panic!("expected error"), - Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), - } - } - - #[test] - fn peek() { - each_ip(&mut |addr| { - let (txdone, rxdone) = channel(); - - let srv = t!(TcpListener::bind(&addr)); - let _t = thread::spawn(move|| { - let mut cl = t!(srv.accept()).0; - cl.write(&[1,3,3,7]).unwrap(); - t!(rxdone.recv()); - }); - - let mut c = t!(TcpStream::connect(&addr)); - let mut b = [0; 10]; - for _ in 1..3 { - let len = c.peek(&mut b).unwrap(); - assert_eq!(len, 4); - } - let len = c.read(&mut b).unwrap(); - assert_eq!(len, 4); - - t!(c.set_nonblocking(true)); - match c.peek(&mut b) { - Ok(_) => panic!("expected error"), - Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), - } - t!(txdone.send(())); - }) - } - - #[test] - fn connect_timeout_unroutable() { - // this IP is unroutable, so connections should always time out, - // provided the network is reachable to begin with. - let addr = "10.255.255.1:80".parse().unwrap(); - let e = TcpStream::connect_timeout(&addr, Duration::from_millis(250)).unwrap_err(); - assert!(e.kind() == io::ErrorKind::TimedOut || - e.kind() == io::ErrorKind::Other, - "bad error: {} {:?}", e, e.kind()); - } - - #[test] - fn connect_timeout_unbound() { - // bind and drop a socket to track down a "probably unassigned" port - let socket = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = socket.local_addr().unwrap(); - drop(socket); - - let timeout = Duration::from_secs(1); - let e = TcpStream::connect_timeout(&addr, timeout).unwrap_err(); - assert!(e.kind() == io::ErrorKind::ConnectionRefused || - e.kind() == io::ErrorKind::TimedOut || - e.kind() == io::ErrorKind::Other, - "bad error: {} {:?}", e, e.kind()); - } - - #[test] - fn connect_timeout_valid() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = listener.local_addr().unwrap(); - TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap(); - } -} diff --git a/ctr-std/src/net/test.rs b/ctr-std/src/net/test.rs deleted file mode 100644 index aec3d90..0000000 --- a/ctr-std/src/net/test.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(warnings)] // not used on emscripten - -use env; -use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs}; -use sync::atomic::{AtomicUsize, Ordering}; - -static PORT: AtomicUsize = AtomicUsize::new(0); - -pub fn next_test_ip4() -> SocketAddr { - let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port(); - SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port)) -} - -pub fn next_test_ip6() -> SocketAddr { - let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port(); - SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), - port, 0, 0)) -} - -pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr { - SocketAddr::V4(SocketAddrV4::new(a, p)) -} - -pub fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr { - SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0)) -} - -pub fn tsa(a: A) -> Result, String> { - match a.to_socket_addrs() { - Ok(a) => Ok(a.collect()), - Err(e) => Err(e.to_string()), - } -} - -// The bots run multiple builds at the same time, and these builds -// all want to use ports. This function figures out which workspace -// it is running in and assigns a port range based on it. -fn base_port() -> u16 { - let cwd = env::current_dir().unwrap(); - let dirs = ["32-opt", "32-nopt", - "musl-64-opt", "cross-opt", - "64-opt", "64-nopt", "64-opt-vg", "64-debug-opt", - "all-opt", "snap3", "dist"]; - dirs.iter().enumerate().find(|&(_, dir)| { - cwd.to_str().unwrap().contains(dir) - }).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600 -} diff --git a/ctr-std/src/net/udp.rs b/ctr-std/src/net/udp.rs deleted file mode 100644 index 0ebe328..0000000 --- a/ctr-std/src/net/udp.rs +++ /dev/null @@ -1,1163 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use fmt; -use io::{self, Error, ErrorKind}; -use net::{ToSocketAddrs, SocketAddr, Ipv4Addr, Ipv6Addr}; -use sys_common::net as net_imp; -use sys_common::{AsInner, FromInner, IntoInner}; -use time::Duration; - -/// A UDP socket. -/// -/// After creating a `UdpSocket` by [`bind`]ing it to a socket address, data can be -/// [sent to] and [received from] any other socket address. -/// -/// Although UDP is a connectionless protocol, this implementation provides an interface -/// to set an address where data should be sent and received from. After setting a remote -/// address with [`connect`], data can be sent to and received from that address with -/// [`send`] and [`recv`]. -/// -/// As stated in the User Datagram Protocol's specification in [IETF RFC 768], UDP is -/// an unordered, unreliable protocol; refer to [`TcpListener`] and [`TcpStream`] for TCP -/// primitives. -/// -/// [`bind`]: #method.bind -/// [`connect`]: #method.connect -/// [IETF RFC 768]: https://tools.ietf.org/html/rfc768 -/// [`recv`]: #method.recv -/// [received from]: #method.recv_from -/// [`send`]: #method.send -/// [sent to]: #method.send_to -/// [`TcpListener`]: ../../std/net/struct.TcpListener.html -/// [`TcpStream`]: ../../std/net/struct.TcpStream.html -/// -/// # Examples -/// -/// ```no_run -/// use std::net::UdpSocket; -/// -/// fn main() -> std::io::Result<()> { -/// { -/// let mut socket = UdpSocket::bind("127.0.0.1:34254")?; -/// -/// // Receives a single datagram message on the socket. If `buf` is too small to hold -/// // the message, it will be cut off. -/// let mut buf = [0; 10]; -/// let (amt, src) = socket.recv_from(&mut buf)?; -/// -/// // Redeclare `buf` as slice of the received data and send reverse data back to origin. -/// let buf = &mut buf[..amt]; -/// buf.reverse(); -/// socket.send_to(buf, &src)?; -/// } // the socket is closed here -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct UdpSocket(net_imp::UdpSocket); - -impl UdpSocket { - /// Creates a UDP socket from the given address. - /// - /// The address type can be any implementor of [`ToSocketAddrs`] trait. See - /// its documentation for concrete examples. - /// - /// If `addr` yields multiple addresses, `bind` will be attempted with - /// each of the addresses until one succeeds and returns the socket. If none - /// of the addresses succeed in creating a socket, the error returned from - /// the last attempt (the last address) is returned. - /// - /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html - /// - /// # Examples - /// - /// Create a UDP socket bound to `127.0.0.1:3400`: - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address"); - /// ``` - /// - /// Create a UDP socket bound to `127.0.0.1:3400`. If the socket cannot be - /// bound to that address, create a UDP socket bound to `127.0.0.1:3401`: - /// - /// ```no_run - /// use std::net::{SocketAddr, UdpSocket}; - /// - /// let addrs = [ - /// SocketAddr::from(([127, 0, 0, 1], 3400)), - /// SocketAddr::from(([127, 0, 0, 1], 3401)), - /// ]; - /// let socket = UdpSocket::bind(&addrs[..]).expect("couldn't bind to address"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn bind(addr: A) -> io::Result { - super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket) - } - - /// Receives a single datagram message on the socket. On success, returns the number - /// of bytes read and the origin. - /// - /// The function must be called with valid byte array `buf` of sufficient size to - /// hold the message bytes. If a message is too long to fit in the supplied buffer, - /// excess bytes may be discarded. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// let mut buf = [0; 10]; - /// let (number_of_bytes, src_addr) = socket.recv_from(&mut buf) - /// .expect("Didn't receive data"); - /// let filled_buf = &mut buf[..number_of_bytes]; - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.0.recv_from(buf) - } - - /// Receives a single datagram message on the socket, without removing it from the - /// queue. On success, returns the number of bytes read and the origin. - /// - /// The function must be called with valid byte array `buf` of sufficient size to - /// hold the message bytes. If a message is too long to fit in the supplied buffer, - /// excess bytes may be discarded. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. - /// - /// Do not use this function to implement busy waiting, instead use `libc::poll` to - /// synchronize IO events on one or more sockets. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// let mut buf = [0; 10]; - /// let (number_of_bytes, src_addr) = socket.peek_from(&mut buf) - /// .expect("Didn't receive data"); - /// let filled_buf = &mut buf[..number_of_bytes]; - /// ``` - #[stable(feature = "peek", since = "1.18.0")] - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.0.peek_from(buf) - } - - /// Sends data on the socket to the given address. On success, returns the - /// number of bytes written. - /// - /// Address type can be any implementor of [`ToSocketAddrs`] trait. See its - /// documentation for concrete examples. - /// - /// It is possible for `addr` to yield multiple addresses, but `send_to` - /// will only send data to the first address yielded by `addr`. - /// - /// This will return an error when the IP version of the local socket - /// does not match that returned from [`ToSocketAddrs`]. - /// - /// See for more details. - /// - /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.send_to(&[0; 10], "127.0.0.1:4242").expect("couldn't send data"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn send_to(&self, buf: &[u8], addr: A) - -> io::Result { - match addr.to_socket_addrs()?.next() { - Some(addr) => self.0.send_to(buf, &addr), - None => Err(Error::new(ErrorKind::InvalidInput, - "no addresses to send data to")), - } - } - - /// Returns the socket address that this socket was created from. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// assert_eq!(socket.local_addr().unwrap(), - /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 34254))); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn local_addr(&self) -> io::Result { - self.0.socket_addr() - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UdpSocket` is a reference to the same socket that this - /// object references. Both handles will read and write the same port, and - /// options set on one socket will be propagated to the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// let socket_clone = socket.try_clone().expect("couldn't clone the socket"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UdpSocket) - } - - /// Sets the read timeout to the timeout specified. - /// - /// If the value specified is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// # Platform-specific behavior - /// - /// Platforms may return a different error code whenever a read times out as - /// a result of setting this option. For example Unix typically returns an - /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// [`read`]: ../../std/io/trait.Read.html#tymethod.read - /// [`Duration`]: ../../std/time/struct.Duration.html - /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock - /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_read_timeout(None).expect("set_read_timeout call failed"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "socket_timeout", since = "1.4.0")] - pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { - self.0.set_read_timeout(dur) - } - - /// Sets the write timeout to the timeout specified. - /// - /// If the value specified is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// # Platform-specific behavior - /// - /// Platforms may return a different error code whenever a write times out - /// as a result of setting this option. For example Unix typically returns - /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// [`write`]: ../../std/io/trait.Write.html#tymethod.write - /// [`Duration`]: ../../std/time/struct.Duration.html - /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock - /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_write_timeout(None).expect("set_write_timeout call failed"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "socket_timeout", since = "1.4.0")] - pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { - self.0.set_write_timeout(dur) - } - - /// Returns the read timeout of this socket. - /// - /// If the timeout is [`None`], then [`read`] calls will block indefinitely. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`read`]: ../../std/io/trait.Read.html#tymethod.read - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_read_timeout(None).expect("set_read_timeout call failed"); - /// assert_eq!(socket.read_timeout().unwrap(), None); - /// ``` - #[stable(feature = "socket_timeout", since = "1.4.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.read_timeout() - } - - /// Returns the write timeout of this socket. - /// - /// If the timeout is [`None`], then [`write`] calls will block indefinitely. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`write`]: ../../std/io/trait.Write.html#tymethod.write - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_write_timeout(None).expect("set_write_timeout call failed"); - /// assert_eq!(socket.write_timeout().unwrap(), None); - /// ``` - #[stable(feature = "socket_timeout", since = "1.4.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.write_timeout() - } - - /// Sets the value of the `SO_BROADCAST` option for this socket. - /// - /// When enabled, this socket is allowed to send packets to a broadcast - /// address. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_broadcast(false).expect("set_broadcast call failed"); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { - self.0.set_broadcast(broadcast) - } - - /// Gets the value of the `SO_BROADCAST` option for this socket. - /// - /// For more information about this option, see - /// [`set_broadcast`][link]. - /// - /// [link]: #method.set_broadcast - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_broadcast(false).expect("set_broadcast call failed"); - /// assert_eq!(socket.broadcast().unwrap(), false); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn broadcast(&self) -> io::Result { - self.0.broadcast() - } - - /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. - /// - /// If enabled, multicast packets will be looped back to the local socket. - /// Note that this may not have any affect on IPv6 sockets. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed"); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { - self.0.set_multicast_loop_v4(multicast_loop_v4) - } - - /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket. - /// - /// For more information about this option, see - /// [`set_multicast_loop_v4`][link]. - /// - /// [link]: #method.set_multicast_loop_v4 - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed"); - /// assert_eq!(socket.multicast_loop_v4().unwrap(), false); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn multicast_loop_v4(&self) -> io::Result { - self.0.multicast_loop_v4() - } - - /// Sets the value of the `IP_MULTICAST_TTL` option for this socket. - /// - /// Indicates the time-to-live value of outgoing multicast packets for - /// this socket. The default value is 1 which means that multicast packets - /// don't leave the local network unless explicitly requested. - /// - /// Note that this may not have any affect on IPv6 sockets. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed"); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { - self.0.set_multicast_ttl_v4(multicast_ttl_v4) - } - - /// Gets the value of the `IP_MULTICAST_TTL` option for this socket. - /// - /// For more information about this option, see - /// [`set_multicast_ttl_v4`][link]. - /// - /// [link]: #method.set_multicast_ttl_v4 - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed"); - /// assert_eq!(socket.multicast_ttl_v4().unwrap(), 42); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn multicast_ttl_v4(&self) -> io::Result { - self.0.multicast_ttl_v4() - } - - /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. - /// - /// Controls whether this socket sees the multicast packets it sends itself. - /// Note that this may not have any affect on IPv4 sockets. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed"); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { - self.0.set_multicast_loop_v6(multicast_loop_v6) - } - - /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket. - /// - /// For more information about this option, see - /// [`set_multicast_loop_v6`][link]. - /// - /// [link]: #method.set_multicast_loop_v6 - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed"); - /// assert_eq!(socket.multicast_loop_v6().unwrap(), false); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn multicast_loop_v6(&self) -> io::Result { - self.0.multicast_loop_v6() - } - - /// Sets the value for the `IP_TTL` option on this socket. - /// - /// This value sets the time-to-live field that is used in every packet sent - /// from this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_ttl(42).expect("set_ttl call failed"); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - self.0.set_ttl(ttl) - } - - /// Gets the value of the `IP_TTL` option for this socket. - /// - /// For more information about this option, see [`set_ttl`][link]. - /// - /// [link]: #method.set_ttl - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.set_ttl(42).expect("set_ttl call failed"); - /// assert_eq!(socket.ttl().unwrap(), 42); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn ttl(&self) -> io::Result { - self.0.ttl() - } - - /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. - /// - /// This function specifies a new multicast group for this socket to join. - /// The address must be a valid multicast address, and `interface` is the - /// address of the local interface with which the system should join the - /// multicast group. If it's equal to `INADDR_ANY` then an appropriate - /// interface is chosen by the system. - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { - self.0.join_multicast_v4(multiaddr, interface) - } - - /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type. - /// - /// This function specifies a new multicast group for this socket to join. - /// The address must be a valid multicast address, and `interface` is the - /// index of the interface to join/leave (or 0 to indicate any interface). - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { - self.0.join_multicast_v6(multiaddr, interface) - } - - /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. - /// - /// For more information about this option, see - /// [`join_multicast_v4`][link]. - /// - /// [link]: #method.join_multicast_v4 - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { - self.0.leave_multicast_v4(multiaddr, interface) - } - - /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. - /// - /// For more information about this option, see - /// [`join_multicast_v6`][link]. - /// - /// [link]: #method.join_multicast_v6 - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { - self.0.leave_multicast_v6(multiaddr, interface) - } - - /// Get the value of the `SO_ERROR` option on this socket. - /// - /// This will retrieve the stored error in the underlying socket, clearing - /// the field in the process. This can be useful for checking errors between - /// calls. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// match socket.take_error() { - /// Ok(Some(error)) => println!("UdpSocket error: {:?}", error), - /// Ok(None) => println!("No error"), - /// Err(error) => println!("UdpSocket.take_error failed: {:?}", error), - /// } - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Connects this UDP socket to a remote address, allowing the `send` and - /// `recv` syscalls to be used to send data and also applies filters to only - /// receive data from the specified address. - /// - /// If `addr` yields multiple addresses, `connect` will be attempted with - /// each of the addresses until the underlying OS function returns no - /// error. Note that usually, a successful `connect` call does not specify - /// that there is a remote server listening on the port, rather, such an - /// error would only be detected after the first send. If the OS returns an - /// error for each of the specified addresses, the error returned from the - /// last connection attempt (the last address) is returned. - /// - /// # Examples - /// - /// Create a UDP socket bound to `127.0.0.1:3400` and connect the socket to - /// `127.0.0.1:8080`: - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address"); - /// socket.connect("127.0.0.1:8080").expect("connect function failed"); - /// ``` - /// - /// Unlike in the TCP case, passing an array of addresses to the `connect` - /// function of a UDP socket is not a useful thing to do: The OS will be - /// unable to determine whether something is listening on the remote - /// address without the application sending data. - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn connect(&self, addr: A) -> io::Result<()> { - super::each_addr(addr, |addr| self.0.connect(addr)) - } - - /// Sends data on the socket to the remote address to which it is connected. - /// - /// The [`connect`] method will connect this socket to a remote address. This - /// method will fail if the socket is not connected. - /// - /// [`connect`]: #method.connect - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.connect("127.0.0.1:8080").expect("connect function failed"); - /// socket.send(&[0, 1, 2]).expect("couldn't send message"); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn send(&self, buf: &[u8]) -> io::Result { - self.0.send(buf) - } - - /// Receives a single datagram message on the socket from the remote address to - /// which it is connected. On success, returns the number of bytes read. - /// - /// The function must be called with valid byte array `buf` of sufficient size to - /// hold the message bytes. If a message is too long to fit in the supplied buffer, - /// excess bytes may be discarded. - /// - /// The [`connect`] method will connect this socket to a remote address. This - /// method will fail if the socket is not connected. - /// - /// [`connect`]: #method.connect - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.connect("127.0.0.1:8080").expect("connect function failed"); - /// let mut buf = [0; 10]; - /// match socket.recv(&mut buf) { - /// Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]), - /// Err(e) => println!("recv function failed: {:?}", e), - /// } - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn recv(&self, buf: &mut [u8]) -> io::Result { - self.0.recv(buf) - } - - /// Receives single datagram on the socket from the remote address to which it is - /// connected, without removing the message from input queue. On success, returns - /// the number of bytes peeked. - /// - /// The function must be called with valid byte array `buf` of sufficient size to - /// hold the message bytes. If a message is too long to fit in the supplied buffer, - /// excess bytes may be discarded. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// Do not use this function to implement busy waiting, instead use `libc::poll` to - /// synchronize IO events on one or more sockets. - /// - /// The [`connect`] method will connect this socket to a remote address. This - /// method will fail if the socket is not connected. - /// - /// [`connect`]: #method.connect - /// - /// # Errors - /// - /// This method will fail if the socket is not connected. The `connect` method - /// will connect this socket to a remote address. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); - /// socket.connect("127.0.0.1:8080").expect("connect function failed"); - /// let mut buf = [0; 10]; - /// match socket.peek(&mut buf) { - /// Ok(received) => println!("received {} bytes", received), - /// Err(e) => println!("peek function failed: {:?}", e), - /// } - /// ``` - #[stable(feature = "peek", since = "1.18.0")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } - - /// Moves this UDP socket into or out of nonblocking mode. - /// - /// This will result in `recv`, `recv_from`, `send`, and `send_to` - /// operations becoming nonblocking, i.e. immediately returning from their - /// calls. If the IO operation is successful, `Ok` is returned and no - /// further action is required. If the IO operation could not be completed - /// and needs to be retried, an error with kind - /// [`io::ErrorKind::WouldBlock`] is returned. - /// - /// On Unix platforms, calling this method corresponds to calling `fcntl` - /// `FIONBIO`. On Windows calling this method corresponds to calling - /// `ioctlsocket` `FIONBIO`. - /// - /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock - /// - /// # Examples - /// - /// Create a UDP socket bound to `127.0.0.1:7878` and read bytes in - /// nonblocking mode: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// - /// let socket = UdpSocket::bind("127.0.0.1:7878").unwrap(); - /// socket.set_nonblocking(true).unwrap(); - /// - /// # fn wait_for_fd() { unimplemented!() } - /// let mut buf = [0; 10]; - /// let (num_bytes_read, _) = loop { - /// match socket.recv_from(&mut buf) { - /// Ok(n) => break n, - /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { - /// // wait until network socket is ready, typically implemented - /// // via platform-specific APIs such as epoll or IOCP - /// wait_for_fd(); - /// } - /// Err(e) => panic!("encountered IO error: {}", e), - /// } - /// }; - /// println!("bytes: {:?}", &buf[..num_bytes_read]); - /// ``` - #[stable(feature = "net2_mutators", since = "1.9.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } -} - -impl AsInner for UdpSocket { - fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 } -} - -impl FromInner for UdpSocket { - fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) } -} - -impl IntoInner for UdpSocket { - fn into_inner(self) -> net_imp::UdpSocket { self.0 } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for UdpSocket { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] -mod tests { - use io::ErrorKind; - use net::*; - use net::test::{next_test_ip4, next_test_ip6}; - use sync::mpsc::channel; - use sys_common::AsInner; - use time::{Instant, Duration}; - use thread; - - fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) { - f(next_test_ip4(), next_test_ip4()); - f(next_test_ip6(), next_test_ip6()); - } - - macro_rules! t { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), - } - } - } - - #[test] - fn bind_error() { - match UdpSocket::bind("1.1.1.1:9999") { - Ok(..) => panic!(), - Err(e) => { - assert_eq!(e.kind(), ErrorKind::AddrNotAvailable) - } - } - } - - #[test] - fn socket_smoke_test_ip4() { - each_ip(&mut |server_ip, client_ip| { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - - let _t = thread::spawn(move|| { - let client = t!(UdpSocket::bind(&client_ip)); - rx1.recv().unwrap(); - t!(client.send_to(&[99], &server_ip)); - tx2.send(()).unwrap(); - }); - - let server = t!(UdpSocket::bind(&server_ip)); - tx1.send(()).unwrap(); - let mut buf = [0]; - let (nread, src) = t!(server.recv_from(&mut buf)); - assert_eq!(nread, 1); - assert_eq!(buf[0], 99); - assert_eq!(src, client_ip); - rx2.recv().unwrap(); - }) - } - - #[test] - fn socket_name_ip4() { - each_ip(&mut |addr, _| { - let server = t!(UdpSocket::bind(&addr)); - assert_eq!(addr, t!(server.local_addr())); - }) - } - - #[test] - fn udp_clone_smoke() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); - - let _t = thread::spawn(move|| { - let mut buf = [0, 0]; - assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1)); - assert_eq!(buf[0], 1); - t!(sock2.send_to(&[2], &addr1)); - }); - - let sock3 = t!(sock1.try_clone()); - - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - rx1.recv().unwrap(); - t!(sock3.send_to(&[1], &addr2)); - tx2.send(()).unwrap(); - }); - tx1.send(()).unwrap(); - let mut buf = [0, 0]; - assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2)); - rx2.recv().unwrap(); - }) - } - - #[test] - fn udp_clone_two_read() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); - let (tx1, rx) = channel(); - let tx2 = tx1.clone(); - - let _t = thread::spawn(move|| { - t!(sock2.send_to(&[1], &addr1)); - rx.recv().unwrap(); - t!(sock2.send_to(&[2], &addr1)); - rx.recv().unwrap(); - }); - - let sock3 = t!(sock1.try_clone()); - - let (done, rx) = channel(); - let _t = thread::spawn(move|| { - let mut buf = [0, 0]; - t!(sock3.recv_from(&mut buf)); - tx2.send(()).unwrap(); - done.send(()).unwrap(); - }); - let mut buf = [0, 0]; - t!(sock1.recv_from(&mut buf)); - tx1.send(()).unwrap(); - - rx.recv().unwrap(); - }) - } - - #[test] - fn udp_clone_two_write() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); - - let (tx, rx) = channel(); - let (serv_tx, serv_rx) = channel(); - - let _t = thread::spawn(move|| { - let mut buf = [0, 1]; - rx.recv().unwrap(); - t!(sock2.recv_from(&mut buf)); - serv_tx.send(()).unwrap(); - }); - - let sock3 = t!(sock1.try_clone()); - - let (done, rx) = channel(); - let tx2 = tx.clone(); - let _t = thread::spawn(move|| { - match sock3.send_to(&[1], &addr2) { - Ok(..) => { let _ = tx2.send(()); } - Err(..) => {} - } - done.send(()).unwrap(); - }); - match sock1.send_to(&[2], &addr2) { - Ok(..) => { let _ = tx.send(()); } - Err(..) => {} - } - drop(tx); - - rx.recv().unwrap(); - serv_rx.recv().unwrap(); - }) - } - - #[test] - fn debug() { - let name = if cfg!(windows) {"socket"} else {"fd"}; - let socket_addr = next_test_ip4(); - - let udpsock = t!(UdpSocket::bind(&socket_addr)); - let udpsock_inner = udpsock.0.socket().as_inner(); - let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", - socket_addr, name, udpsock_inner); - assert_eq!(format!("{:?}", udpsock), compare); - } - - // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code - // no longer has rounding errors. - #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] - #[test] - fn timeouts() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - let dur = Duration::new(15410, 0); - - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_read_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.read_timeout())); - - assert_eq!(None, t!(stream.write_timeout())); - - t!(stream.set_write_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.write_timeout())); - - t!(stream.set_read_timeout(None)); - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_write_timeout(None)); - assert_eq!(None, t!(stream.write_timeout())); - } - - #[test] - fn test_read_timeout() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut buf = [0; 10]; - - let start = Instant::now(); - let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); - assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); - assert!(start.elapsed() > Duration::from_millis(400)); - } - - #[test] - fn test_read_with_timeout() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - t!(stream.send_to(b"hello world", &addr)); - - let mut buf = [0; 11]; - t!(stream.recv_from(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - - let start = Instant::now(); - let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); - assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); - assert!(start.elapsed() > Duration::from_millis(400)); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_timeout_zero_duration() { - let addr = next_test_ip4(); - - let socket = t!(UdpSocket::bind(&addr)); - - let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - } - - #[test] - fn connect_send_recv() { - let addr = next_test_ip4(); - - let socket = t!(UdpSocket::bind(&addr)); - t!(socket.connect(addr)); - - t!(socket.send(b"hello world")); - - let mut buf = [0; 11]; - t!(socket.recv(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - } - - #[test] - fn connect_send_peek_recv() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); - t!(socket.connect(addr)); - - t!(socket.send(b"hello world")); - - for _ in 1..3 { - let mut buf = [0; 11]; - let size = t!(socket.peek(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - } - - let mut buf = [0; 11]; - let size = t!(socket.recv(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - }) - } - - #[test] - fn peek_from() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); - t!(socket.send_to(b"hello world", &addr)); - - for _ in 1..3 { - let mut buf = [0; 11]; - let (size, _) = t!(socket.peek_from(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - } - - let mut buf = [0; 11]; - let (size, _) = t!(socket.recv_from(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - }) - } - - #[test] - fn ttl() { - let ttl = 100; - - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - - t!(stream.set_ttl(ttl)); - assert_eq!(ttl, t!(stream.ttl())); - } - - #[test] - fn set_nonblocking() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); - - t!(socket.set_nonblocking(true)); - t!(socket.set_nonblocking(false)); - - t!(socket.connect(addr)); - - t!(socket.set_nonblocking(false)); - t!(socket.set_nonblocking(true)); - - let mut buf = [0]; - match socket.recv(&mut buf) { - Ok(_) => panic!("expected error"), - Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), - } - }) - } -} diff --git a/ctr-std/src/num.rs b/ctr-std/src/num.rs deleted file mode 100644 index 3f90c1f..0000000 --- a/ctr-std/src/num.rs +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Additional functionality for numerics. -//! -//! This module provides some extra types that are useful when doing numerical -//! work. See the individual documentation for each piece for more information. - -#![stable(feature = "rust1", since = "1.0.0")] -#![allow(missing_docs)] - -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::num::Wrapping; - -#[stable(feature = "nonzero", since = "1.28.0")] -pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; - -#[cfg(test)] use fmt; -#[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; - -/// Helper function for testing numeric operations -#[cfg(test)] -pub fn test_num(ten: T, two: T) where - T: PartialEq - + Add + Sub - + Mul + Div - + Rem + fmt::Debug - + Copy -{ - assert_eq!(ten.add(two), ten + two); - assert_eq!(ten.sub(two), ten - two); - assert_eq!(ten.mul(two), ten * two); - assert_eq!(ten.div(two), ten / two); - assert_eq!(ten.rem(two), ten % two); -} - -#[cfg(test)] -mod tests { - use u8; - use u16; - use u32; - use u64; - use usize; - use ops::Mul; - - #[test] - fn test_saturating_add_uint() { - use usize::MAX; - assert_eq!(3_usize.saturating_add(5_usize), 8_usize); - assert_eq!(3_usize.saturating_add(MAX-1), MAX); - assert_eq!(MAX.saturating_add(MAX), MAX); - assert_eq!((MAX-2).saturating_add(1), MAX-1); - } - - #[test] - fn test_saturating_sub_uint() { - use usize::MAX; - assert_eq!(5_usize.saturating_sub(3_usize), 2_usize); - assert_eq!(3_usize.saturating_sub(5_usize), 0_usize); - assert_eq!(0_usize.saturating_sub(1_usize), 0_usize); - assert_eq!((MAX-1).saturating_sub(MAX), 0); - } - - #[test] - fn test_saturating_add_int() { - use isize::{MIN,MAX}; - assert_eq!(3i32.saturating_add(5), 8); - assert_eq!(3isize.saturating_add(MAX-1), MAX); - assert_eq!(MAX.saturating_add(MAX), MAX); - assert_eq!((MAX-2).saturating_add(1), MAX-1); - assert_eq!(3i32.saturating_add(-5), -2); - assert_eq!(MIN.saturating_add(-1), MIN); - assert_eq!((-2isize).saturating_add(-MAX), MIN); - } - - #[test] - fn test_saturating_sub_int() { - use isize::{MIN,MAX}; - assert_eq!(3i32.saturating_sub(5), -2); - assert_eq!(MIN.saturating_sub(1), MIN); - assert_eq!((-2isize).saturating_sub(MAX), MIN); - assert_eq!(3i32.saturating_sub(-5), 8); - assert_eq!(3isize.saturating_sub(-(MAX-1)), MAX); - assert_eq!(MAX.saturating_sub(-MAX), MAX); - assert_eq!((MAX-2).saturating_sub(-1), MAX-1); - } - - #[test] - fn test_checked_add() { - let five_less = usize::MAX - 5; - assert_eq!(five_less.checked_add(0), Some(usize::MAX - 5)); - assert_eq!(five_less.checked_add(1), Some(usize::MAX - 4)); - assert_eq!(five_less.checked_add(2), Some(usize::MAX - 3)); - assert_eq!(five_less.checked_add(3), Some(usize::MAX - 2)); - assert_eq!(five_less.checked_add(4), Some(usize::MAX - 1)); - assert_eq!(five_less.checked_add(5), Some(usize::MAX)); - assert_eq!(five_less.checked_add(6), None); - assert_eq!(five_less.checked_add(7), None); - } - - #[test] - fn test_checked_sub() { - assert_eq!(5_usize.checked_sub(0), Some(5)); - assert_eq!(5_usize.checked_sub(1), Some(4)); - assert_eq!(5_usize.checked_sub(2), Some(3)); - assert_eq!(5_usize.checked_sub(3), Some(2)); - assert_eq!(5_usize.checked_sub(4), Some(1)); - assert_eq!(5_usize.checked_sub(5), Some(0)); - assert_eq!(5_usize.checked_sub(6), None); - assert_eq!(5_usize.checked_sub(7), None); - } - - #[test] - fn test_checked_mul() { - let third = usize::MAX / 3; - assert_eq!(third.checked_mul(0), Some(0)); - assert_eq!(third.checked_mul(1), Some(third)); - assert_eq!(third.checked_mul(2), Some(third * 2)); - assert_eq!(third.checked_mul(3), Some(third * 3)); - assert_eq!(third.checked_mul(4), None); - } - - macro_rules! test_is_power_of_two { - ($test_name:ident, $T:ident) => ( - fn $test_name() { - #![test] - assert_eq!((0 as $T).is_power_of_two(), false); - assert_eq!((1 as $T).is_power_of_two(), true); - assert_eq!((2 as $T).is_power_of_two(), true); - assert_eq!((3 as $T).is_power_of_two(), false); - assert_eq!((4 as $T).is_power_of_two(), true); - assert_eq!((5 as $T).is_power_of_two(), false); - assert_eq!(($T::MAX / 2 + 1).is_power_of_two(), true); - } - ) - } - - test_is_power_of_two!{ test_is_power_of_two_u8, u8 } - test_is_power_of_two!{ test_is_power_of_two_u16, u16 } - test_is_power_of_two!{ test_is_power_of_two_u32, u32 } - test_is_power_of_two!{ test_is_power_of_two_u64, u64 } - test_is_power_of_two!{ test_is_power_of_two_uint, usize } - - macro_rules! test_next_power_of_two { - ($test_name:ident, $T:ident) => ( - fn $test_name() { - #![test] - assert_eq!((0 as $T).next_power_of_two(), 1); - let mut next_power = 1; - for i in 1 as $T..40 { - assert_eq!(i.next_power_of_two(), next_power); - if i == next_power { next_power *= 2 } - } - } - ) - } - - test_next_power_of_two! { test_next_power_of_two_u8, u8 } - test_next_power_of_two! { test_next_power_of_two_u16, u16 } - test_next_power_of_two! { test_next_power_of_two_u32, u32 } - test_next_power_of_two! { test_next_power_of_two_u64, u64 } - test_next_power_of_two! { test_next_power_of_two_uint, usize } - - macro_rules! test_checked_next_power_of_two { - ($test_name:ident, $T:ident) => ( - fn $test_name() { - #![test] - assert_eq!((0 as $T).checked_next_power_of_two(), Some(1)); - let smax = $T::MAX >> 1; - assert_eq!(smax.checked_next_power_of_two(), Some(smax+1)); - assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1)); - assert_eq!((smax + 2).checked_next_power_of_two(), None); - assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None); - assert_eq!($T::MAX.checked_next_power_of_two(), None); - let mut next_power = 1; - for i in 1 as $T..40 { - assert_eq!(i.checked_next_power_of_two(), Some(next_power)); - if i == next_power { next_power *= 2 } - } - } - ) - } - - test_checked_next_power_of_two! { test_checked_next_power_of_two_u8, u8 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_u16, u16 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_u32, u32 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_u64, u64 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_uint, usize } - - #[test] - fn test_pow() { - fn naive_pow + Copy>(one: T, base: T, exp: usize) -> T { - (0..exp).fold(one, |acc, _| acc * base) - } - macro_rules! assert_pow { - (($num:expr, $exp:expr) => $expected:expr) => {{ - let result = $num.pow($exp); - assert_eq!(result, $expected); - assert_eq!(result, naive_pow(1, $num, $exp)); - }} - } - assert_pow!((3u32, 0 ) => 1); - assert_pow!((5u32, 1 ) => 5); - assert_pow!((-4i32, 2 ) => 16); - assert_pow!((8u32, 3 ) => 512); - assert_pow!((2u64, 50) => 1125899906842624); - } - - #[test] - fn test_uint_to_str_overflow() { - let mut u8_val: u8 = 255; - assert_eq!(u8_val.to_string(), "255"); - - u8_val = u8_val.wrapping_add(1); - assert_eq!(u8_val.to_string(), "0"); - - let mut u16_val: u16 = 65_535; - assert_eq!(u16_val.to_string(), "65535"); - - u16_val = u16_val.wrapping_add(1); - assert_eq!(u16_val.to_string(), "0"); - - let mut u32_val: u32 = 4_294_967_295; - assert_eq!(u32_val.to_string(), "4294967295"); - - u32_val = u32_val.wrapping_add(1); - assert_eq!(u32_val.to_string(), "0"); - - let mut u64_val: u64 = 18_446_744_073_709_551_615; - assert_eq!(u64_val.to_string(), "18446744073709551615"); - - u64_val = u64_val.wrapping_add(1); - assert_eq!(u64_val.to_string(), "0"); - } - - fn from_str(t: &str) -> Option { - ::str::FromStr::from_str(t).ok() - } - - #[test] - fn test_uint_from_str_overflow() { - let mut u8_val: u8 = 255; - assert_eq!(from_str::("255"), Some(u8_val)); - assert_eq!(from_str::("256"), None); - - u8_val = u8_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u8_val)); - assert_eq!(from_str::("-1"), None); - - let mut u16_val: u16 = 65_535; - assert_eq!(from_str::("65535"), Some(u16_val)); - assert_eq!(from_str::("65536"), None); - - u16_val = u16_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u16_val)); - assert_eq!(from_str::("-1"), None); - - let mut u32_val: u32 = 4_294_967_295; - assert_eq!(from_str::("4294967295"), Some(u32_val)); - assert_eq!(from_str::("4294967296"), None); - - u32_val = u32_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u32_val)); - assert_eq!(from_str::("-1"), None); - - let mut u64_val: u64 = 18_446_744_073_709_551_615; - assert_eq!(from_str::("18446744073709551615"), Some(u64_val)); - assert_eq!(from_str::("18446744073709551616"), None); - - u64_val = u64_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u64_val)); - assert_eq!(from_str::("-1"), None); - } -} - - -#[cfg(test)] -mod bench { - extern crate test; - use self::test::Bencher; - - #[bench] - fn bench_pow_function(b: &mut Bencher) { - let v = (0..1024).collect::>(); - b.iter(|| {v.iter().fold(0u32, |old, new| old.pow(*new as u32));}); - } -} diff --git a/ctr-std/src/os/android/fs.rs b/ctr-std/src/os/android/fs.rs deleted file mode 100644 index 5899dc6..0000000 --- a/ctr-std/src/os/android/fs.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::android::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } -} - diff --git a/ctr-std/src/os/android/mod.rs b/ctr-std/src/os/android/mod.rs deleted file mode 100644 index 7cc3776..0000000 --- a/ctr-std/src/os/android/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Android-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/android/raw.rs b/ctr-std/src/os/android/raw.rs deleted file mode 100644 index 60ad8fc..0000000 --- a/ctr-std/src/os/android/raw.rs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Android-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use os::raw::c_long; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = c_long; - -#[doc(inline)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub use self::arch::{dev_t, mode_t, blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; - -#[cfg(any(target_arch = "arm", target_arch = "x86"))] -mod arch { - use os::raw::{c_uint, c_uchar, c_ulonglong, c_longlong, c_ulong}; - use os::unix::raw::{uid_t, gid_t}; - - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type dev_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type mode_t = u32; - - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type nlink_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: c_ulonglong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad0: [c_uchar; 4], - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __st_ino: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: c_uint, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: c_uint, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: uid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: gid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: c_ulonglong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad3: [c_uchar; 4], - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: c_longlong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: c_ulonglong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: c_ulonglong, - } - -} - - -#[cfg(target_arch = "aarch64")] -mod arch { - use os::raw::{c_uchar, c_ulong}; - use os::unix::raw::{uid_t, gid_t}; - - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type dev_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type mode_t = u32; - - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type nlink_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad0: [c_uchar; 4], - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __st_ino: ino_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: mode_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: nlink_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: uid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: gid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad3: [c_uchar; 4], - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: off_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: blksize_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: blkcnt_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: ino_t, - } -} - -#[cfg(target_arch = "x86_64")] -mod arch { - use os::raw::{c_uint, c_long, c_ulong}; - use os::unix::raw::{uid_t, gid_t}; - - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type dev_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type mode_t = u32; - - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type nlink_t = u32; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] - pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: ino_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: c_uint, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: uid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: gid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_ulong, - __unused: [c_long; 3], - } -} - diff --git a/ctr-std/src/os/bitrig/fs.rs b/ctr-std/src/os/bitrig/fs.rs deleted file mode 100644 index 24caf32..0000000 --- a/ctr-std/src/os/bitrig/fs.rs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::bitrig::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } -} - diff --git a/ctr-std/src/os/bitrig/mod.rs b/ctr-std/src/os/bitrig/mod.rs deleted file mode 100644 index fb58818..0000000 --- a/ctr-std/src/os/bitrig/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Bitrig-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/bitrig/raw.rs b/ctr-std/src/os/bitrig/raw.rs deleted file mode 100644 index 2895857..0000000 --- a/ctr-std/src/os/bitrig/raw.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Bitrig-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use os::raw::c_long; -use os::unix::raw::{uid_t, gid_t}; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: i64, -} diff --git a/ctr-std/src/os/dragonfly/fs.rs b/ctr-std/src/os/dragonfly/fs.rs deleted file mode 100644 index 6aea450..0000000 --- a/ctr-std/src/os/dragonfly/fs.rs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::dragonfly::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_lspare(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } -} - diff --git a/ctr-std/src/os/dragonfly/mod.rs b/ctr-std/src/os/dragonfly/mod.rs deleted file mode 100644 index 6455618..0000000 --- a/ctr-std/src/os/dragonfly/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Dragonfly-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/dragonfly/raw.rs b/ctr-std/src/os/dragonfly/raw.rs deleted file mode 100644 index 5da2540..0000000 --- a/ctr-std/src/os/dragonfly/raw.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Dragonfly-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use os::raw::c_long; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_lspare: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, -} diff --git a/ctr-std/src/os/emscripten/fs.rs b/ctr-std/src/os/emscripten/fs.rs deleted file mode 100644 index e0e197d..0000000 --- a/ctr-std/src/os/emscripten/fs.rs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::emscripten::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat64 - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } -} diff --git a/ctr-std/src/os/emscripten/mod.rs b/ctr-std/src/os/emscripten/mod.rs deleted file mode 100644 index 8ec44b9..0000000 --- a/ctr-std/src/os/emscripten/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Linux-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/emscripten/raw.rs b/ctr-std/src/os/emscripten/raw.rs deleted file mode 100644 index bcd85f8..0000000 --- a/ctr-std/src/os/emscripten/raw.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Emscripten-specific raw type definitions -//! This is basically exactly the same as the linux definitions, -//! except using the musl-specific stat64 structure in liblibc. - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use os::raw::{c_long, c_short, c_uint, c_ulong}; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = c_ulong; - -#[doc(inline)] -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad1: c_short, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __st_ino: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad2: c_uint, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, -} diff --git a/ctr-std/src/os/freebsd/fs.rs b/ctr-std/src/os/freebsd/fs.rs deleted file mode 100644 index 5f24cd6..0000000 --- a/ctr-std/src/os/freebsd/fs.rs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::freebsd::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_lspare(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } -} - diff --git a/ctr-std/src/os/freebsd/mod.rs b/ctr-std/src/os/freebsd/mod.rs deleted file mode 100644 index ce7b91e..0000000 --- a/ctr-std/src/os/freebsd/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! FreeBSD-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/freebsd/raw.rs b/ctr-std/src/os/freebsd/raw.rs deleted file mode 100644 index c755e5a..0000000 --- a/ctr-std/src/os/freebsd/raw.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! FreeBSD-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use os::raw::c_long; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_lspare: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, - #[cfg(target_arch = "x86")] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __unused: [u8; 8], -} diff --git a/ctr-std/src/os/fuchsia/fs.rs b/ctr-std/src/os/fuchsia/fs.rs deleted file mode 100644 index 1680257..0000000 --- a/ctr-std/src/os/fuchsia/fs.rs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use fs::Metadata; -use sys_common::AsInner; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } -} diff --git a/ctr-std/src/os/fuchsia/mod.rs b/ctr-std/src/os/fuchsia/mod.rs deleted file mode 100644 index 1ebcbba..0000000 --- a/ctr-std/src/os/fuchsia/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Fuchsia-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/fuchsia/raw.rs b/ctr-std/src/os/fuchsia/raw.rs deleted file mode 100644 index 5d01735..0000000 --- a/ctr-std/src/os/fuchsia/raw.rs +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Fuchsia-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use os::raw::c_ulong; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = c_ulong; - -#[doc(inline)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub use self::arch::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; - -#[cfg(any(target_arch = "x86", - target_arch = "le32", - target_arch = "powerpc", - target_arch = "arm"))] -mod arch { - use os::raw::{c_long, c_short, c_uint}; - - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad1: c_short, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __st_ino: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad2: c_uint, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - } -} - -#[cfg(target_arch = "mips")] -mod arch { - use os::raw::{c_long, c_ulong}; - - #[cfg(target_env = "musl")] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64; - #[cfg(not(target_env = "musl"))] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[cfg(target_env = "musl")] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[cfg(not(target_env = "musl"))] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[cfg(target_env = "musl")] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[cfg(not(target_env = "musl"))] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_pad1: [c_long; 3], - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_pad2: [c_long; 2], - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_pad5: [c_long; 14], - } -} - -#[cfg(target_arch = "mips64")] -mod arch { - pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; -} - -#[cfg(target_arch = "aarch64")] -mod arch { - use os::raw::{c_long, c_int}; - - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad1: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad2: c_int, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __unused: [c_int; 2], - } -} - -#[cfg(target_arch = "x86_64")] -mod arch { - use os::raw::{c_long, c_int}; - - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad0: c_int, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __unused: [c_long; 3], - } -} diff --git a/ctr-std/src/os/haiku/fs.rs b/ctr-std/src/os/haiku/fs.rs deleted file mode 100644 index 453136e..0000000 --- a/ctr-std/src/os/haiku/fs.rs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::haiku::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_crtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_crtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_crtime(&self) -> i64 { - self.as_inner().as_inner().st_crtime as i64 - } - fn st_crtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_crtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } -} diff --git a/ctr-std/src/os/haiku/mod.rs b/ctr-std/src/os/haiku/mod.rs deleted file mode 100644 index dd1675c..0000000 --- a/ctr-std/src/os/haiku/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Haiku-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/haiku/raw.rs b/ctr-std/src/os/haiku/raw.rs deleted file mode 100644 index 95353d9..0000000 --- a/ctr-std/src/os/haiku/raw.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Haiku-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -#![allow(deprecated)] - -use os::raw::{c_long}; -use os::unix::raw::{uid_t, gid_t}; - -// Use the direct definition of usize, instead of uintptr_t like in libc -#[stable(feature = "pthread_t", since = "1.8.0")] pub type pthread_t = usize; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = i32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = i32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = i64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = i32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = i64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: ino_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: mode_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: nlink_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: uid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: gid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: off_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: blksize_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_crtime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_crtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_type: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: blkcnt_t, -} diff --git a/ctr-std/src/os/hermit/fs.rs b/ctr-std/src/os/hermit/fs.rs deleted file mode 100644 index d2e7516..0000000 --- a/ctr-std/src/os/hermit/fs.rs +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::hermit::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned [`stat`] are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - /// - /// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let stat = meta.as_raw_stat(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - /// Returns the device ID on which this file resides. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_dev()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - /// Returns the inode number. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ino()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - /// Returns the file type and mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mode()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - /// Returns the number of hard links to file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_nlink()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - /// Returns the user ID of the file owner. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_uid()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - /// Returns the group ID of the file owner. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_gid()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - /// Returns the device ID that this file represents. Only relevant for special file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_rdev()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. - /// - /// The size of a symbolic link is the length of the pathname it contains, - /// without a terminating null byte. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_size()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - /// Returns the last access time. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_atime()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - /// Returns the last access time, nano seconds part. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_atime_nsec()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - /// Returns the last modification time. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mtime()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - /// Returns the last modification time, nano seconds part. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mtime_nsec()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - /// Returns the last status change time. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ctime()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - /// Returns the last status change time, nano seconds part. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ctime_nsec()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - /// Returns the "preferred" blocksize for efficient filesystem I/O. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_blksize()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - /// Returns the number of blocks allocated to the file, 512-byte units. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_blocks()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat64 - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } -} diff --git a/ctr-std/src/os/hermit/mod.rs b/ctr-std/src/os/hermit/mod.rs deleted file mode 100644 index fcb22cd..0000000 --- a/ctr-std/src/os/hermit/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! HermitCore-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/hermit/raw.rs b/ctr-std/src/os/hermit/raw.rs deleted file mode 100644 index 282afe0..0000000 --- a/ctr-std/src/os/hermit/raw.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! HermitCore-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] -#![allow(missing_debug_implementations)] - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub use libc::pthread_t; - -#[doc(inline)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub use libc::{dev_t, mode_t, off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; diff --git a/ctr-std/src/os/horizon/fs.rs b/ctr-std/src/os/horizon/fs.rs deleted file mode 100644 index 12e8719..0000000 --- a/ctr-std/src/os/horizon/fs.rs +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::horizon::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned [`stat`] are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - /// - /// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let stat = meta.as_raw_stat(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - /// Returns the device ID on which this file resides. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_dev()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - /// Returns the inode number. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ino()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - /// Returns the file type and mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mode()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - /// Returns the number of hard links to file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_nlink()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - /// Returns the user ID of the file owner. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_uid()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - /// Returns the group ID of the file owner. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_gid()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - /// Returns the device ID that this file represents. Only relevant for special file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_rdev()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. - /// - /// The size of a symbolic link is the length of the pathname it contains, - /// without a terminating null byte. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_size()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - /// Returns the last access time. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_atime()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - /// Returns the last access time, nano seconds part. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_atime_nsec()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - /// Returns the last modification time. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mtime()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - /// Returns the last modification time, nano seconds part. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mtime_nsec()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - /// Returns the last status change time. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ctime()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - /// Returns the last status change time, nano seconds part. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ctime_nsec()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - /// Returns the "preferred" blocksize for efficient filesystem I/O. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_blksize()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - /// Returns the number of blocks allocated to the file, 512-byte units. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_blocks()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - //self.as_inner().as_inner().st_atime_nsec as i64 - 0i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - //self.as_inner().as_inner().st_mtime_nsec as i64 - 0i64 - } - fn st_ctime(&self) -> i64 { - //self.as_inner().as_inner().st_ctime as i64 - 0i64 - } - fn st_ctime_nsec(&self) -> i64 { - //self.as_inner().as_inner().st_ctime_nsec as i64 - 0i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } -} diff --git a/ctr-std/src/os/horizon/mod.rs b/ctr-std/src/os/horizon/mod.rs deleted file mode 100644 index 8ec44b9..0000000 --- a/ctr-std/src/os/horizon/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Linux-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/horizon/raw.rs b/ctr-std/src/os/horizon/raw.rs deleted file mode 100644 index bb1830a..0000000 --- a/ctr-std/src/os/horizon/raw.rs +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Linux-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] -#![allow(missing_debug_implementations)] - -use os::raw::c_ulong; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = c_ulong; - -#[doc(inline)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub use self::arch::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; - -#[cfg(any(target_arch = "x86", - target_arch = "le32", - target_arch = "powerpc", - target_arch = "arm", - target_arch = "asmjs", - target_arch = "wasm32"))] -mod arch { - use os::raw::{c_long, c_short, c_uint}; - - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad1: c_short, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __st_ino: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad2: c_uint, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - } -} - -#[cfg(target_arch = "mips")] -mod arch { - use os::raw::{c_long, c_ulong}; - - #[cfg(target_env = "musl")] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64; - #[cfg(not(target_env = "musl"))] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[cfg(target_env = "musl")] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[cfg(not(target_env = "musl"))] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[cfg(target_env = "musl")] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[cfg(not(target_env = "musl"))] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_pad1: [c_long; 3], - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_pad2: [c_long; 2], - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_pad5: [c_long; 14], - } -} - -#[cfg(any(target_arch = "mips64", - target_arch = "s390x", - target_arch = "sparc64"))] -mod arch { - pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; -} - -#[cfg(target_arch = "aarch64")] -mod arch { - use os::raw::{c_long, c_int}; - - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad1: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad2: c_int, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __unused: [c_int; 2], - } -} - -#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64"))] -mod arch { - use os::raw::{c_long, c_int}; - - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad0: c_int, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __unused: [c_long; 3], - } -} diff --git a/ctr-std/src/os/ios/fs.rs b/ctr-std/src/os/ios/fs.rs deleted file mode 100644 index 296ce69..0000000 --- a/ctr-std/src/os/ios/fs.rs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::ios::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_lspare(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } -} - diff --git a/ctr-std/src/os/ios/mod.rs b/ctr-std/src/os/ios/mod.rs deleted file mode 100644 index 4cad233..0000000 --- a/ctr-std/src/os/ios/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! iOS-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/ios/raw.rs b/ctr-std/src/os/ios/raw.rs deleted file mode 100644 index 8b34a93..0000000 --- a/ctr-std/src/os/ios/raw.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! iOS-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use os::raw::c_long; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_lspare: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_qspare: [i64; 2], -} diff --git a/ctr-std/src/os/linux/fs.rs b/ctr-std/src/os/linux/fs.rs deleted file mode 100644 index 76fb10d..0000000 --- a/ctr-std/src/os/linux/fs.rs +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::linux::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned [`stat`] are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - /// - /// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let stat = meta.as_raw_stat(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - /// Returns the device ID on which this file resides. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_dev()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - /// Returns the inode number. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ino()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - /// Returns the file type and mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mode()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - /// Returns the number of hard links to file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_nlink()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - /// Returns the user ID of the file owner. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_uid()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - /// Returns the group ID of the file owner. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_gid()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - /// Returns the device ID that this file represents. Only relevant for special file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_rdev()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. - /// - /// The size of a symbolic link is the length of the pathname it contains, - /// without a terminating null byte. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_size()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - /// Returns the last access time. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_atime()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - /// Returns the last access time, nano seconds part. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_atime_nsec()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - /// Returns the last modification time. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mtime()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - /// Returns the last modification time, nano seconds part. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mtime_nsec()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - /// Returns the last status change time. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ctime()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - /// Returns the last status change time, nano seconds part. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ctime_nsec()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - /// Returns the "preferred" blocksize for efficient filesystem I/O. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_blksize()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - /// Returns the number of blocks allocated to the file, 512-byte units. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::io; - /// use std::os::linux::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_blocks()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat64 - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } -} diff --git a/ctr-std/src/os/linux/mod.rs b/ctr-std/src/os/linux/mod.rs deleted file mode 100644 index 8ec44b9..0000000 --- a/ctr-std/src/os/linux/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Linux-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/linux/raw.rs b/ctr-std/src/os/linux/raw.rs deleted file mode 100644 index bb1830a..0000000 --- a/ctr-std/src/os/linux/raw.rs +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Linux-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] -#![allow(missing_debug_implementations)] - -use os::raw::c_ulong; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = c_ulong; - -#[doc(inline)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub use self::arch::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; - -#[cfg(any(target_arch = "x86", - target_arch = "le32", - target_arch = "powerpc", - target_arch = "arm", - target_arch = "asmjs", - target_arch = "wasm32"))] -mod arch { - use os::raw::{c_long, c_short, c_uint}; - - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad1: c_short, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __st_ino: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad2: c_uint, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - } -} - -#[cfg(target_arch = "mips")] -mod arch { - use os::raw::{c_long, c_ulong}; - - #[cfg(target_env = "musl")] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64; - #[cfg(not(target_env = "musl"))] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[cfg(target_env = "musl")] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[cfg(not(target_env = "musl"))] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[cfg(target_env = "musl")] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[cfg(not(target_env = "musl"))] - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_pad1: [c_long; 3], - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: c_ulong, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_pad2: [c_long; 2], - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_pad5: [c_long; 14], - } -} - -#[cfg(any(target_arch = "mips64", - target_arch = "s390x", - target_arch = "sparc64"))] -mod arch { - pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; -} - -#[cfg(target_arch = "aarch64")] -mod arch { - use os::raw::{c_long, c_int}; - - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad1: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad2: c_int, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __unused: [c_int; 2], - } -} - -#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64"))] -mod arch { - use os::raw::{c_long, c_int}; - - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; - #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - - #[repr(C)] - #[derive(Clone)] - #[stable(feature = "raw_ext", since = "1.1.0")] - pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad0: c_int, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __unused: [c_long; 3], - } -} diff --git a/ctr-std/src/os/macos/fs.rs b/ctr-std/src/os/macos/fs.rs deleted file mode 100644 index 0b14c05..0000000 --- a/ctr-std/src/os/macos/fs.rs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::macos::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_lspare(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_qspare(&self) -> [u64; 2]; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } - fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 - } - fn st_qspare(&self) -> [u64; 2] { - let qspare = self.as_inner().as_inner().st_qspare; - [qspare[0] as u64, qspare[1] as u64] - } -} - diff --git a/ctr-std/src/os/macos/mod.rs b/ctr-std/src/os/macos/mod.rs deleted file mode 100644 index c9406f7..0000000 --- a/ctr-std/src/os/macos/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! macOS-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/macos/raw.rs b/ctr-std/src/os/macos/raw.rs deleted file mode 100644 index 8ffddf6..0000000 --- a/ctr-std/src/os/macos/raw.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! macOS-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use os::raw::c_long; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u16, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_lspare: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_qspare: [i64; 2], -} diff --git a/ctr-std/src/os/mod.rs b/ctr-std/src/os/mod.rs deleted file mode 100644 index ff4dd4f..0000000 --- a/ctr-std/src/os/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! OS-specific functionality. - -#![stable(feature = "os", since = "1.0.0")] -#![allow(missing_docs, bad_style, missing_debug_implementations)] - -cfg_if! { - if #[cfg(dox)] { - - // When documenting libstd we want to show unix/windows/linux modules as - // these are the "main modules" that are used across platforms. This - // should help show platform-specific functionality in a hopefully - // cross-platform way in the documentation - - #[stable(feature = "rust1", since = "1.0.0")] - pub use sys::unix_ext as unix; - - #[stable(feature = "rust1", since = "1.0.0")] - pub use sys::windows_ext as windows; - - #[doc(cfg(target_os = "linux"))] - pub mod linux; - - } else { - - // If we're not documenting libstd then we just expose everything as we - // otherwise would. - - #[cfg(target_os = "android")] pub mod android; - #[cfg(target_os = "bitrig")] pub mod bitrig; - #[cfg(target_os = "dragonfly")] pub mod dragonfly; - #[cfg(target_os = "freebsd")] pub mod freebsd; - #[cfg(target_os = "haiku")] pub mod haiku; - #[cfg(target_os = "ios")] pub mod ios; - #[cfg(target_os = "macos")] pub mod macos; - #[cfg(target_os = "netbsd")] pub mod netbsd; - #[cfg(target_os = "openbsd")] pub mod openbsd; - #[cfg(target_os = "solaris")] pub mod solaris; - #[cfg(target_os = "emscripten")] pub mod emscripten; - #[cfg(target_os = "fuchsia")] pub mod fuchsia; - #[cfg(target_os = "hermit")] pub mod hermit; - #[cfg(target_os = "horizon")] pub mod horizon; - - #[cfg(any(target_os = "redox", unix))] - #[stable(feature = "rust1", since = "1.0.0")] - pub use sys::ext as unix; - - #[cfg(windows)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use sys::ext as windows; - - #[cfg(any(target_os = "linux", target_os = "l4re"))] - pub mod linux; - - } -} - -pub mod raw; diff --git a/ctr-std/src/os/netbsd/fs.rs b/ctr-std/src/os/netbsd/fs.rs deleted file mode 100644 index e9cad33..0000000 --- a/ctr-std/src/os/netbsd/fs.rs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::netbsd::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atimensec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtimensec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctimensec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtimensec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } -} - diff --git a/ctr-std/src/os/netbsd/mod.rs b/ctr-std/src/os/netbsd/mod.rs deleted file mode 100644 index 06efbd8..0000000 --- a/ctr-std/src/os/netbsd/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! OpenBSD-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/netbsd/raw.rs b/ctr-std/src/os/netbsd/raw.rs deleted file mode 100644 index 9b2e037..0000000 --- a/ctr-std/src/os/netbsd/raw.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! NetBSD-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use os::raw::c_long; -use os::unix::raw::{uid_t, gid_t}; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: uid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: gid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - st_spare: [u32; 2], -} diff --git a/ctr-std/src/os/openbsd/fs.rs b/ctr-std/src/os/openbsd/fs.rs deleted file mode 100644 index 0f6b83b..0000000 --- a/ctr-std/src/os/openbsd/fs.rs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::openbsd::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } -} - diff --git a/ctr-std/src/os/openbsd/mod.rs b/ctr-std/src/os/openbsd/mod.rs deleted file mode 100644 index 06efbd8..0000000 --- a/ctr-std/src/os/openbsd/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! OpenBSD-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/openbsd/raw.rs b/ctr-std/src/os/openbsd/raw.rs deleted file mode 100644 index 6142f03..0000000 --- a/ctr-std/src/os/openbsd/raw.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! OpenBSD-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use os::raw::c_long; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, -} diff --git a/ctr-std/src/os/raw/char.md b/ctr-std/src/os/raw/char.md deleted file mode 100644 index 9a55767..0000000 --- a/ctr-std/src/os/raw/char.md +++ /dev/null @@ -1,11 +0,0 @@ -Equivalent to C's `char` type. - -[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. This type will always be either [`i8`] or [`u8`], as the type is defined as being one byte long. - -C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See [`CStr`] for more information. - -[C's `char` type]: https://en.wikipedia.org/wiki/C_data_types#Basic_types -[Rust's `char` type]: ../../primitive.char.html -[`CStr`]: ../../ffi/struct.CStr.html -[`i8`]: ../../primitive.i8.html -[`u8`]: ../../primitive.u8.html diff --git a/ctr-std/src/os/raw/double.md b/ctr-std/src/os/raw/double.md deleted file mode 100644 index 6818dad..0000000 --- a/ctr-std/src/os/raw/double.md +++ /dev/null @@ -1,7 +0,0 @@ -Equivalent to C's `double` type. - -This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard. - -[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754 -[`float`]: type.c_float.html -[`f64`]: ../../primitive.f64.html diff --git a/ctr-std/src/os/raw/float.md b/ctr-std/src/os/raw/float.md deleted file mode 100644 index 57d1071..0000000 --- a/ctr-std/src/os/raw/float.md +++ /dev/null @@ -1,6 +0,0 @@ -Equivalent to C's `float` type. - -This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all. - -[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754 -[`f32`]: ../../primitive.f32.html diff --git a/ctr-std/src/os/raw/int.md b/ctr-std/src/os/raw/int.md deleted file mode 100644 index a0d25fd..0000000 --- a/ctr-std/src/os/raw/int.md +++ /dev/null @@ -1,7 +0,0 @@ -Equivalent to C's `signed int` (`int`) type. - -This type will almost always be [`i32`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer that is at least the size of a [`short`]; some systems define it as an [`i16`], for example. - -[`short`]: type.c_short.html -[`i32`]: ../../primitive.i32.html -[`i16`]: ../../primitive.i16.html diff --git a/ctr-std/src/os/raw/long.md b/ctr-std/src/os/raw/long.md deleted file mode 100644 index c620b40..0000000 --- a/ctr-std/src/os/raw/long.md +++ /dev/null @@ -1,7 +0,0 @@ -Equivalent to C's `signed long` (`long`) type. - -This type will always be [`i32`] or [`i64`]. Most notably, many Linux-based systems assume an `i64`, but Windows assumes `i32`. The C standard technically only requires that this type be a signed integer that is at least 32 bits and at least the size of an [`int`], although in practice, no system would have a `long` that is neither an `i32` nor `i64`. - -[`int`]: type.c_int.html -[`i32`]: ../../primitive.i32.html -[`i64`]: ../../primitive.i64.html diff --git a/ctr-std/src/os/raw/longlong.md b/ctr-std/src/os/raw/longlong.md deleted file mode 100644 index ab3d643..0000000 --- a/ctr-std/src/os/raw/longlong.md +++ /dev/null @@ -1,7 +0,0 @@ -Equivalent to C's `signed long long` (`long long`) type. - -This type will almost always be [`i64`], but may differ on some systems. The C standard technically only requires that this type be a signed integer that is at least 64 bits and at least the size of a [`long`], although in practice, no system would have a `long long` that is not an `i64`, as most systems do not have a standardised [`i128`] type. - -[`long`]: type.c_int.html -[`i64`]: ../../primitive.i64.html -[`i128`]: ../../primitive.i128.html diff --git a/ctr-std/src/os/raw/mod.rs b/ctr-std/src/os/raw/mod.rs deleted file mode 100644 index dc33747..0000000 --- a/ctr-std/src/os/raw/mod.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Platform-specific types, as defined by C. -//! -//! Code that interacts via FFI will almost certainly be using the -//! base types provided by C, which aren't nearly as nicely defined -//! as Rust's primitive types. This module provides types which will -//! match those defined by C, so that code that interacts with C will -//! refer to the correct types. - -#![stable(feature = "raw_os", since = "1.1.0")] - -use fmt; - -#[doc(include = "os/raw/char.md")] -#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x")), - all(target_os = "android", any(target_arch = "aarch64", - target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all(target_os = "netbsd", any(target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc")), - all(target_os = "openbsd", target_arch = "aarch64"), - all(target_os = "fuchsia", target_arch = "aarch64")))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; -#[doc(include = "os/raw/char.md")] -#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x")), - all(target_os = "android", any(target_arch = "aarch64", - target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all(target_os = "netbsd", any(target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc")), - all(target_os = "openbsd", target_arch = "aarch64"), - all(target_os = "fuchsia", target_arch = "aarch64"))))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; -#[doc(include = "os/raw/schar.md")] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; -#[doc(include = "os/raw/uchar.md")] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8; -#[doc(include = "os/raw/short.md")] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16; -#[doc(include = "os/raw/ushort.md")] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16; -#[doc(include = "os/raw/int.md")] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32; -#[doc(include = "os/raw/uint.md")] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32; -#[doc(include = "os/raw/long.md")] -#[cfg(any(target_pointer_width = "32", windows))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32; -#[doc(include = "os/raw/ulong.md")] -#[cfg(any(target_pointer_width = "32", windows))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32; -#[doc(include = "os/raw/long.md")] -#[cfg(all(target_pointer_width = "64", not(windows)))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64; -#[doc(include = "os/raw/ulong.md")] -#[cfg(all(target_pointer_width = "64", not(windows)))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64; -#[doc(include = "os/raw/longlong.md")] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64; -#[doc(include = "os/raw/ulonglong.md")] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64; -#[doc(include = "os/raw/float.md")] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32; -#[doc(include = "os/raw/double.md")] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64; - -/// Equivalent to C's `void` type when used as a [pointer]. -/// -/// In essence, `*const c_void` is equivalent to C's `const void*` -/// and `*mut c_void` is equivalent to C's `void*`. That said, this is -/// *not* the same as C's `void` return type, which is Rust's `()` type. -/// -/// Ideally, this type would be equivalent to [`!`], but currently it may -/// be more ideal to use `c_void` for FFI purposes. -/// -/// [`!`]: ../../primitive.never.html -/// [pointer]: ../../primitive.pointer.html -// NB: For LLVM to recognize the void pointer type and by extension -// functions like malloc(), we need to have it represented as i8* in -// LLVM bitcode. The enum used here ensures this and prevents misuse -// of the "raw" type by only having private variants.. We need two -// variants, because the compiler complains about the repr attribute -// otherwise. -#[repr(u8)] -#[stable(feature = "raw_os", since = "1.1.0")] -pub enum c_void { - #[unstable(feature = "c_void_variant", reason = "should not have to exist", - issue = "0")] - #[doc(hidden)] __variant1, - #[unstable(feature = "c_void_variant", reason = "should not have to exist", - issue = "0")] - #[doc(hidden)] __variant2, -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for c_void { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("c_void") - } -} - -#[cfg(test)] -#[allow(unused_imports)] -mod tests { - use any::TypeId; - use libc; - use mem; - - macro_rules! ok { - ($($t:ident)*) => {$( - assert!(TypeId::of::() == TypeId::of::(), - "{} is wrong", stringify!($t)); - )*} - } - - #[test] - fn same() { - use os::raw; - ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong - c_longlong c_ulonglong c_float c_double); - } -} diff --git a/ctr-std/src/os/raw/schar.md b/ctr-std/src/os/raw/schar.md deleted file mode 100644 index 6aa8b12..0000000 --- a/ctr-std/src/os/raw/schar.md +++ /dev/null @@ -1,6 +0,0 @@ -Equivalent to C's `signed char` type. - -This type will always be [`i8`], but is included for completeness. It is defined as being a signed integer the same size as a C [`char`]. - -[`char`]: type.c_char.html -[`i8`]: ../../primitive.i8.html diff --git a/ctr-std/src/os/raw/short.md b/ctr-std/src/os/raw/short.md deleted file mode 100644 index be92c6c..0000000 --- a/ctr-std/src/os/raw/short.md +++ /dev/null @@ -1,6 +0,0 @@ -Equivalent to C's `signed short` (`short`) type. - -This type will almost always be [`i16`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer with at least 16 bits; some systems may define it as `i32`, for example. - -[`char`]: type.c_char.html -[`i16`]: ../../primitive.i16.html diff --git a/ctr-std/src/os/raw/uchar.md b/ctr-std/src/os/raw/uchar.md deleted file mode 100644 index b6ca711..0000000 --- a/ctr-std/src/os/raw/uchar.md +++ /dev/null @@ -1,6 +0,0 @@ -Equivalent to C's `unsigned char` type. - -This type will always be [`u8`], but is included for completeness. It is defined as being an unsigned integer the same size as a C [`char`]. - -[`char`]: type.c_char.html -[`u8`]: ../../primitive.u8.html diff --git a/ctr-std/src/os/raw/uint.md b/ctr-std/src/os/raw/uint.md deleted file mode 100644 index 6f7013a..0000000 --- a/ctr-std/src/os/raw/uint.md +++ /dev/null @@ -1,7 +0,0 @@ -Equivalent to C's `unsigned int` type. - -This type will almost always be [`u32`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as an [`int`]; some systems define it as a [`u16`], for example. - -[`int`]: type.c_int.html -[`u32`]: ../../primitive.u32.html -[`u16`]: ../../primitive.u16.html diff --git a/ctr-std/src/os/raw/ulong.md b/ctr-std/src/os/raw/ulong.md deleted file mode 100644 index c350395..0000000 --- a/ctr-std/src/os/raw/ulong.md +++ /dev/null @@ -1,7 +0,0 @@ -Equivalent to C's `unsigned long` type. - -This type will always be [`u32`] or [`u64`]. Most notably, many Linux-based systems assume an `u64`, but Windows assumes `u32`. The C standard technically only requires that this type be an unsigned integer with the size of a [`long`], although in practice, no system would have a `ulong` that is neither a `u32` nor `u64`. - -[`long`]: type.c_long.html -[`u32`]: ../../primitive.u32.html -[`u64`]: ../../primitive.u64.html diff --git a/ctr-std/src/os/raw/ulonglong.md b/ctr-std/src/os/raw/ulonglong.md deleted file mode 100644 index c41faf7..0000000 --- a/ctr-std/src/os/raw/ulonglong.md +++ /dev/null @@ -1,7 +0,0 @@ -Equivalent to C's `unsigned long long` type. - -This type will almost always be [`u64`], but may differ on some systems. The C standard technically only requires that this type be an unsigned integer with the size of a [`long long`], although in practice, no system would have a `long long` that is not a `u64`, as most systems do not have a standardised [`u128`] type. - -[`long long`]: type.c_longlong.html -[`u64`]: ../../primitive.u64.html -[`u128`]: ../../primitive.u128.html diff --git a/ctr-std/src/os/raw/ushort.md b/ctr-std/src/os/raw/ushort.md deleted file mode 100644 index d364abb..0000000 --- a/ctr-std/src/os/raw/ushort.md +++ /dev/null @@ -1,6 +0,0 @@ -Equivalent to C's `unsigned short` type. - -This type will almost always be [`u16`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as a [`short`]. - -[`short`]: type.c_short.html -[`u16`]: ../../primitive.u16.html diff --git a/ctr-std/src/os/solaris/fs.rs b/ctr-std/src/os/solaris/fs.rs deleted file mode 100644 index 19dce1b..0000000 --- a/ctr-std/src/os/solaris/fs.rs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use libc; - -use fs::Metadata; -use sys_common::AsInner; - -#[allow(deprecated)] -use os::solaris::raw; - -/// OS-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } -} diff --git a/ctr-std/src/os/solaris/mod.rs b/ctr-std/src/os/solaris/mod.rs deleted file mode 100644 index 1e01669..0000000 --- a/ctr-std/src/os/solaris/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Solaris-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/ctr-std/src/os/solaris/raw.rs b/ctr-std/src/os/solaris/raw.rs deleted file mode 100644 index 5a813c5..0000000 --- a/ctr-std/src/os/solaris/raw.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Solaris-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use os::raw::c_long; -use os::unix::raw::{uid_t, gid_t}; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = u32; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: ino_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: mode_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: nlink_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: uid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: gid_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: off_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: blksize_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: blkcnt_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub __unused: [u8; 16] -} diff --git a/ctr-std/src/panic.rs b/ctr-std/src/panic.rs deleted file mode 100644 index b8c1c4f..0000000 --- a/ctr-std/src/panic.rs +++ /dev/null @@ -1,426 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Panic support in the standard library. - -#![stable(feature = "std_panic", since = "1.9.0")] - -use any::Any; -use cell::UnsafeCell; -use fmt; -use future::Future; -use mem::PinMut; -use ops::{Deref, DerefMut}; -use panicking; -use ptr::{Unique, NonNull}; -use rc::Rc; -use sync::{Arc, Mutex, RwLock, atomic}; -use task::{self, Poll}; -use thread::Result; - -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub use panicking::{take_hook, set_hook}; - -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub use core::panic::{PanicInfo, Location}; - -/// A marker trait which represents "panic safe" types in Rust. -/// -/// This trait is implemented by default for many types and behaves similarly in -/// terms of inference of implementation to the [`Send`] and [`Sync`] traits. The -/// purpose of this trait is to encode what types are safe to cross a [`catch_unwind`] -/// boundary with no fear of unwind safety. -/// -/// [`Send`]: ../marker/trait.Send.html -/// [`Sync`]: ../marker/trait.Sync.html -/// [`catch_unwind`]: ./fn.catch_unwind.html -/// -/// ## What is unwind safety? -/// -/// In Rust a function can "return" early if it either panics or calls a -/// function which transitively panics. This sort of control flow is not always -/// anticipated, and has the possibility of causing subtle bugs through a -/// combination of two critical components: -/// -/// 1. A data structure is in a temporarily invalid state when the thread -/// panics. -/// 2. This broken invariant is then later observed. -/// -/// Typically in Rust, it is difficult to perform step (2) because catching a -/// panic involves either spawning a thread (which in turns makes it difficult -/// to later witness broken invariants) or using the `catch_unwind` function in this -/// module. Additionally, even if an invariant is witnessed, it typically isn't a -/// problem in Rust because there are no uninitialized values (like in C or C++). -/// -/// It is possible, however, for **logical** invariants to be broken in Rust, -/// which can end up causing behavioral bugs. Another key aspect of unwind safety -/// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to -/// memory unsafety. -/// -/// That was a bit of a whirlwind tour of unwind safety, but for more information -/// about unwind safety and how it applies to Rust, see an [associated RFC][rfc]. -/// -/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md -/// -/// ## What is `UnwindSafe`? -/// -/// Now that we've got an idea of what unwind safety is in Rust, it's also -/// important to understand what this trait represents. As mentioned above, one -/// way to witness broken invariants is through the `catch_unwind` function in this -/// module as it allows catching a panic and then re-using the environment of -/// the closure. -/// -/// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow -/// witnessing a broken invariant through the use of `catch_unwind` (catching a -/// panic). This trait is a marker trait, so it is automatically implemented for -/// many types, and it is also structurally composed (e.g. a struct is unwind -/// safe if all of its components are unwind safe). -/// -/// Note, however, that this is not an unsafe trait, so there is not a succinct -/// contract that this trait is providing. Instead it is intended as more of a -/// "speed bump" to alert users of `catch_unwind` that broken invariants may be -/// witnessed and may need to be accounted for. -/// -/// ## Who implements `UnwindSafe`? -/// -/// Types such as `&mut T` and `&RefCell` are examples which are **not** -/// unwind safe. The general idea is that any mutable state which can be shared -/// across `catch_unwind` is not unwind safe by default. This is because it is very -/// easy to witness a broken invariant outside of `catch_unwind` as the data is -/// simply accessed as usual. -/// -/// Types like `&Mutex`, however, are unwind safe because they implement -/// poisoning by default. They still allow witnessing a broken invariant, but -/// they already provide their own "speed bumps" to do so. -/// -/// ## When should `UnwindSafe` be used? -/// -/// It is not intended that most types or functions need to worry about this trait. -/// It is only used as a bound on the `catch_unwind` function and as mentioned -/// above, the lack of `unsafe` means it is mostly an advisory. The -/// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be -/// implemented for any closed over variables passed to `catch_unwind`. -/// -/// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html -#[stable(feature = "catch_unwind", since = "1.9.0")] -#[rustc_on_unimplemented( - message="the type `{Self}` may not be safely transferred across an unwind boundary", - label="`{Self}` may not be safely transferred across an unwind boundary", -)] -pub auto trait UnwindSafe {} - -/// A marker trait representing types where a shared reference is considered -/// unwind safe. -/// -/// This trait is namely not implemented by [`UnsafeCell`], the root of all -/// interior mutability. -/// -/// This is a "helper marker trait" used to provide impl blocks for the -/// [`UnwindSafe`] trait, for more information see that documentation. -/// -/// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html -/// [`UnwindSafe`]: ./trait.UnwindSafe.html -#[stable(feature = "catch_unwind", since = "1.9.0")] -#[rustc_on_unimplemented( - message="the type `{Self}` may contain interior mutability and a reference may not be safely \ - transferrable across a catch_unwind boundary", - label="`{Self}` may contain interior mutability and a reference may not be safely \ - transferrable across a catch_unwind boundary", -)] -pub auto trait RefUnwindSafe {} - -/// A simple wrapper around a type to assert that it is unwind safe. -/// -/// When using [`catch_unwind`] it may be the case that some of the closed over -/// variables are not unwind safe. For example if `&mut T` is captured the -/// compiler will generate a warning indicating that it is not unwind safe. It -/// may not be the case, however, that this is actually a problem due to the -/// specific usage of [`catch_unwind`] if unwind safety is specifically taken into -/// account. This wrapper struct is useful for a quick and lightweight -/// annotation that a variable is indeed unwind safe. -/// -/// [`catch_unwind`]: ./fn.catch_unwind.html -/// # Examples -/// -/// One way to use `AssertUnwindSafe` is to assert that the entire closure -/// itself is unwind safe, bypassing all checks for all variables: -/// -/// ``` -/// use std::panic::{self, AssertUnwindSafe}; -/// -/// let mut variable = 4; -/// -/// // This code will not compile because the closure captures `&mut variable` -/// // which is not considered unwind safe by default. -/// -/// // panic::catch_unwind(|| { -/// // variable += 3; -/// // }); -/// -/// // This, however, will compile due to the `AssertUnwindSafe` wrapper -/// let result = panic::catch_unwind(AssertUnwindSafe(|| { -/// variable += 3; -/// })); -/// // ... -/// ``` -/// -/// Wrapping the entire closure amounts to a blanket assertion that all captured -/// variables are unwind safe. This has the downside that if new captures are -/// added in the future, they will also be considered unwind safe. Therefore, -/// you may prefer to just wrap individual captures, as shown below. This is -/// more annotation, but it ensures that if a new capture is added which is not -/// unwind safe, you will get a compilation error at that time, which will -/// allow you to consider whether that new capture in fact represent a bug or -/// not. -/// -/// ``` -/// use std::panic::{self, AssertUnwindSafe}; -/// -/// let mut variable = 4; -/// let other_capture = 3; -/// -/// let result = { -/// let mut wrapper = AssertUnwindSafe(&mut variable); -/// panic::catch_unwind(move || { -/// **wrapper += other_capture; -/// }) -/// }; -/// // ... -/// ``` -#[stable(feature = "catch_unwind", since = "1.9.0")] -pub struct AssertUnwindSafe( - #[stable(feature = "catch_unwind", since = "1.9.0")] - pub T -); - -// Implementations of the `UnwindSafe` trait: -// -// * By default everything is unwind safe -// * pointers T contains mutability of some form are not unwind safe -// * Unique, an owning pointer, lifts an implementation -// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe -// * Our custom AssertUnwindSafe wrapper is indeed unwind safe - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<'a, T: ?Sized> !UnwindSafe for &'a mut T {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for &'a T {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for *const T {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for *mut T {} -#[unstable(feature = "ptr_internals", issue = "0")] -impl UnwindSafe for Unique {} -#[stable(feature = "nonnull", since = "1.25.0")] -impl UnwindSafe for NonNull {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for Mutex {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for RwLock {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for AssertUnwindSafe {} - -// not covered via the Shared impl above b/c the inner contents use -// Cell/AtomicUsize, but the usage here is unwind safe so we can lift the -// impl up one level to Arc/Rc itself -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for Rc {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for Arc {} - -// Pretty simple implementations for the `RefUnwindSafe` marker trait, -// basically just saying that `UnsafeCell` is the -// only thing which doesn't implement it (which then transitively applies to -// everything else). -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl !RefUnwindSafe for UnsafeCell {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl RefUnwindSafe for AssertUnwindSafe {} - -#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] -impl RefUnwindSafe for Mutex {} -#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] -impl RefUnwindSafe for RwLock {} - -#[cfg(target_has_atomic = "ptr")] -#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] -impl RefUnwindSafe for atomic::AtomicIsize {} -#[cfg(target_has_atomic = "8")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for atomic::AtomicI8 {} -#[cfg(target_has_atomic = "16")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for atomic::AtomicI16 {} -#[cfg(target_has_atomic = "32")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for atomic::AtomicI32 {} -#[cfg(target_has_atomic = "64")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for atomic::AtomicI64 {} - -#[cfg(target_has_atomic = "ptr")] -#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] -impl RefUnwindSafe for atomic::AtomicUsize {} -#[cfg(target_has_atomic = "8")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for atomic::AtomicU8 {} -#[cfg(target_has_atomic = "16")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for atomic::AtomicU16 {} -#[cfg(target_has_atomic = "32")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for atomic::AtomicU32 {} -#[cfg(target_has_atomic = "64")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for atomic::AtomicU64 {} - -#[cfg(target_has_atomic = "8")] -#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] -impl RefUnwindSafe for atomic::AtomicBool {} - -#[cfg(target_has_atomic = "ptr")] -#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] -impl RefUnwindSafe for atomic::AtomicPtr {} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl Deref for AssertUnwindSafe { - type Target = T; - - fn deref(&self) -> &T { - &self.0 - } -} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl DerefMut for AssertUnwindSafe { - fn deref_mut(&mut self) -> &mut T { - &mut self.0 - } -} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl R> FnOnce<()> for AssertUnwindSafe { - type Output = R; - - extern "rust-call" fn call_once(self, _args: ()) -> R { - (self.0)() - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for AssertUnwindSafe { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("AssertUnwindSafe") - .field(&self.0) - .finish() - } -} - -#[unstable(feature = "futures_api", issue = "50547")] -impl<'a, F: Future> Future for AssertUnwindSafe { - type Output = F::Output; - - fn poll(self: PinMut, cx: &mut task::Context) -> Poll { - let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; - pinned_field.poll(cx) - } -} - -/// Invokes a closure, capturing the cause of an unwinding panic if one occurs. -/// -/// This function will return `Ok` with the closure's result if the closure -/// does not panic, and will return `Err(cause)` if the closure panics. The -/// `cause` returned is the object with which panic was originally invoked. -/// -/// It is currently undefined behavior to unwind from Rust code into foreign -/// code, so this function is particularly useful when Rust is called from -/// another language (normally C). This can run arbitrary Rust code, capturing a -/// panic and allowing a graceful handling of the error. -/// -/// It is **not** recommended to use this function for a general try/catch -/// mechanism. The [`Result`] type is more appropriate to use for functions that -/// can fail on a regular basis. Additionally, this function is not guaranteed -/// to catch all panics, see the "Notes" section below. -/// -/// [`Result`]: ../result/enum.Result.html -/// -/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure -/// that all captured variables are safe to cross this boundary. The purpose of -/// this bound is to encode the concept of [exception safety][rfc] in the type -/// system. Most usage of this function should not need to worry about this -/// bound as programs are naturally unwind safe without `unsafe` code. If it -/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly -/// assert that the usage here is indeed unwind safe. -/// -/// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html -/// [`UnwindSafe`]: ./trait.UnwindSafe.html -/// -/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md -/// -/// # Notes -/// -/// Note that this function **may not catch all panics** in Rust. A panic in -/// Rust is not always implemented via unwinding, but can be implemented by -/// aborting the process as well. This function *only* catches unwinding panics, -/// not those that abort the process. -/// -/// # Examples -/// -/// ``` -/// use std::panic; -/// -/// let result = panic::catch_unwind(|| { -/// println!("hello!"); -/// }); -/// assert!(result.is_ok()); -/// -/// let result = panic::catch_unwind(|| { -/// panic!("oh no!"); -/// }); -/// assert!(result.is_err()); -/// ``` -#[stable(feature = "catch_unwind", since = "1.9.0")] -pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { - unsafe { - panicking::try(f) - } -} - -/// Triggers a panic without invoking the panic hook. -/// -/// This is designed to be used in conjunction with [`catch_unwind`] to, for -/// example, carry a panic across a layer of C code. -/// -/// [`catch_unwind`]: ./fn.catch_unwind.html -/// -/// # Notes -/// -/// Note that panics in Rust are not always implemented via unwinding, but they -/// may be implemented by aborting the process. If this function is called when -/// panics are implemented this way then this function will abort the process, -/// not trigger an unwind. -/// -/// # Examples -/// -/// ```should_panic -/// use std::panic; -/// -/// let result = panic::catch_unwind(|| { -/// panic!("oh no!"); -/// }); -/// -/// if let Err(err) = result { -/// panic::resume_unwind(err); -/// } -/// ``` -#[stable(feature = "resume_unwind", since = "1.9.0")] -pub fn resume_unwind(payload: Box) -> ! { - panicking::update_count_then_panic(payload) -} diff --git a/ctr-std/src/panicking.rs b/ctr-std/src/panicking.rs deleted file mode 100644 index c612604..0000000 --- a/ctr-std/src/panicking.rs +++ /dev/null @@ -1,550 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation of various bits and pieces of the `panic!` macro and -//! associated runtime pieces. -//! -//! Specifically, this module contains the implementation of: -//! -//! * Panic hooks -//! * Executing a panic up to doing the actual implementation -//! * Shims around "try" - -use core::panic::BoxMeUp; - -use io::prelude::*; - -use any::Any; -use cell::RefCell; -use core::panic::{PanicInfo, Location}; -use fmt; -use intrinsics; -use mem; -use ptr; -use raw; -use sys::stdio::{Stderr, stderr_prints_nothing}; -use sys_common::rwlock::RWLock; -use sys_common::thread_info; -use sys_common::util; -use thread; - -thread_local! { - pub static LOCAL_STDERR: RefCell>> = { - RefCell::new(None) - } -} - -// Binary interface to the panic runtime that the standard library depends on. -// -// The standard library is tagged with `#![needs_panic_runtime]` (introduced in -// RFC 1513) to indicate that it requires some other crate tagged with -// `#![panic_runtime]` to exist somewhere. Each panic runtime is intended to -// implement these symbols (with the same signatures) so we can get matched up -// to them. -// -// One day this may look a little less ad-hoc with the compiler helping out to -// hook up these functions, but it is not this day! -#[allow(improper_ctypes)] -extern { - fn __rust_maybe_catch_panic(f: fn(*mut u8), - data: *mut u8, - data_ptr: *mut usize, - vtable_ptr: *mut usize) -> u32; - #[unwind(allowed)] - fn __rust_start_panic(payload: usize) -> u32; -} - -#[derive(Copy, Clone)] -enum Hook { - Default, - Custom(*mut (dyn Fn(&PanicInfo) + 'static + Sync + Send)), -} - -static HOOK_LOCK: RWLock = RWLock::new(); -static mut HOOK: Hook = Hook::Default; - -/// Registers a custom panic hook, replacing any that was previously registered. -/// -/// The panic hook is invoked when a thread panics, but before the panic runtime -/// is invoked. As such, the hook will run with both the aborting and unwinding -/// runtimes. The default hook prints a message to standard error and generates -/// a backtrace if requested, but this behavior can be customized with the -/// `set_hook` and [`take_hook`] functions. -/// -/// [`take_hook`]: ./fn.take_hook.html -/// -/// The hook is provided with a `PanicInfo` struct which contains information -/// about the origin of the panic, including the payload passed to `panic!` and -/// the source code location from which the panic originated. -/// -/// The panic hook is a global resource. -/// -/// # Panics -/// -/// Panics if called from a panicking thread. -/// -/// # Examples -/// -/// The following will print "Custom panic hook": -/// -/// ```should_panic -/// use std::panic; -/// -/// panic::set_hook(Box::new(|_| { -/// println!("Custom panic hook"); -/// })); -/// -/// panic!("Normal panic"); -/// ``` -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn set_hook(hook: Box) { - if thread::panicking() { - panic!("cannot modify the panic hook from a panicking thread"); - } - - unsafe { - HOOK_LOCK.write(); - let old_hook = HOOK; - HOOK = Hook::Custom(Box::into_raw(hook)); - HOOK_LOCK.write_unlock(); - - if let Hook::Custom(ptr) = old_hook { - Box::from_raw(ptr); - } - } -} - -/// Unregisters the current panic hook, returning it. -/// -/// *See also the function [`set_hook`].* -/// -/// [`set_hook`]: ./fn.set_hook.html -/// -/// If no custom hook is registered, the default hook will be returned. -/// -/// # Panics -/// -/// Panics if called from a panicking thread. -/// -/// # Examples -/// -/// The following will print "Normal panic": -/// -/// ```should_panic -/// use std::panic; -/// -/// panic::set_hook(Box::new(|_| { -/// println!("Custom panic hook"); -/// })); -/// -/// let _ = panic::take_hook(); -/// -/// panic!("Normal panic"); -/// ``` -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn take_hook() -> Box { - if thread::panicking() { - panic!("cannot modify the panic hook from a panicking thread"); - } - - unsafe { - HOOK_LOCK.write(); - let hook = HOOK; - HOOK = Hook::Default; - HOOK_LOCK.write_unlock(); - - match hook { - Hook::Default => Box::new(default_hook), - Hook::Custom(ptr) => Box::from_raw(ptr), - } - } -} - -fn default_hook(info: &PanicInfo) { - #[cfg(feature = "backtrace")] - use sys_common::backtrace; - - // If this is a double panic, make sure that we print a backtrace - // for this panic. Otherwise only print it if logging is enabled. - #[cfg(feature = "backtrace")] - let log_backtrace = { - let panics = update_panic_count(0); - - if panics >= 2 { - Some(backtrace::PrintFormat::Full) - } else { - backtrace::log_enabled() - } - }; - - let location = info.location().unwrap(); // The current implementation always returns Some - - let msg = match info.payload().downcast_ref::<&'static str>() { - Some(s) => *s, - None => match info.payload().downcast_ref::() { - Some(s) => &s[..], - None => "Box", - } - }; - let mut err = Stderr::new().ok(); - let thread = thread_info::current_thread(); - let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); - - // 3DS-specific code begins here to display panics via the Error applet - use libctru::{errorInit, errorText, errorDisp, errorConf, ERROR_TEXT_WORD_WRAP, - CFG_LANGUAGE_EN, consoleDebugInit, debugDevice_SVC}; - - let error_text = format!("thread '{}' panicked at '{}', {}", name, msg, location); - - unsafe { - // Prepare error message for display - let mut error_conf: errorConf = mem::uninitialized(); - errorInit(&mut error_conf, - ERROR_TEXT_WORD_WRAP, - CFG_LANGUAGE_EN); - errorText(&mut error_conf, error_text.as_ptr() as *const ::libc::c_char); - - // Display the error - errorDisp(&mut error_conf); - } - - // Let's also write to stderr using the debug console. The output will be - // visible in Citra if a custom logging filter such as `Debug.Emulated:Debug` - // is enabled in the logging section of `~/.config/citra-emu/sdl2-config.ini` - unsafe { - consoleDebugInit(debugDevice_SVC); - } - - let write = |err: &mut dyn (::io::Write)| { - let _ = write!(err, "{}", error_text); - - #[cfg(feature = "backtrace")] - { - use sync::atomic::{AtomicBool, Ordering}; - - static FIRST_PANIC: AtomicBool = AtomicBool::new(true); - - if let Some(format) = log_backtrace { - let _ = backtrace::print(err, format); - } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) { - let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace."); - } - } - }; - - let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take()); - match (prev, err.as_mut()) { - (Some(mut stderr), _) => { - write(&mut *stderr); - let mut s = Some(stderr); - LOCAL_STDERR.with(|slot| { - *slot.borrow_mut() = s.take(); - }); - } - (None, Some(ref mut err)) => { write(err) } - _ => {} - } -} - - -#[cfg(not(test))] -#[doc(hidden)] -#[unstable(feature = "update_panic_count", issue = "0")] -pub fn update_panic_count(amt: isize) -> usize { - use cell::Cell; - thread_local! { static PANIC_COUNT: Cell = Cell::new(0) } - - PANIC_COUNT.with(|c| { - let next = (c.get() as isize + amt) as usize; - c.set(next); - return next - }) -} - -#[cfg(test)] -pub use realstd::rt::update_panic_count; - -/// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -pub unsafe fn try R>(f: F) -> Result> { - #[allow(unions_with_drop_fields)] - union Data { - f: F, - r: R, - } - - // We do some sketchy operations with ownership here for the sake of - // performance. We can only pass pointers down to - // `__rust_maybe_catch_panic` (can't pass objects by value), so we do all - // the ownership tracking here manually using a union. - // - // We go through a transition where: - // - // * First, we set the data to be the closure that we're going to call. - // * When we make the function call, the `do_call` function below, we take - // ownership of the function pointer. At this point the `Data` union is - // entirely uninitialized. - // * If the closure successfully returns, we write the return value into the - // data's return slot. Note that `ptr::write` is used as it's overwriting - // uninitialized data. - // * Finally, when we come back out of the `__rust_maybe_catch_panic` we're - // in one of two states: - // - // 1. The closure didn't panic, in which case the return value was - // filled in. We move it out of `data` and return it. - // 2. The closure panicked, in which case the return value wasn't - // filled in. In this case the entire `data` union is invalid, so - // there is no need to drop anything. - // - // Once we stack all that together we should have the "most efficient' - // method of calling a catch panic whilst juggling ownership. - let mut any_data = 0; - let mut any_vtable = 0; - let mut data = Data { - f, - }; - - let r = __rust_maybe_catch_panic(do_call::, - &mut data as *mut _ as *mut u8, - &mut any_data, - &mut any_vtable); - - return if r == 0 { - debug_assert!(update_panic_count(0) == 0); - Ok(data.r) - } else { - update_panic_count(-1); - debug_assert!(update_panic_count(0) == 0); - Err(mem::transmute(raw::TraitObject { - data: any_data as *mut _, - vtable: any_vtable as *mut _, - })) - }; - - fn do_call R, R>(data: *mut u8) { - unsafe { - let data = data as *mut Data; - let f = ptr::read(&mut (*data).f); - ptr::write(&mut (*data).r, f()); - } - } -} - -/// Determines whether the current thread is unwinding because of panic. -pub fn panicking() -> bool { - update_panic_count(0) != 0 -} - -/// Entry point of panic from the libcore crate. -#[cfg(not(test))] -#[panic_implementation] -#[unwind(allowed)] -pub fn rust_begin_panic(info: &PanicInfo) -> ! { - continue_panic_fmt(&info) -} - -/// The entry point for panicking with a formatted message. -/// -/// This is designed to reduce the amount of code required at the call -/// site as much as possible (so that `panic!()` has as low an impact -/// on (e.g.) the inlining of other functions as possible), by moving -/// the actual formatting into this shared place. -#[unstable(feature = "libstd_sys_internals", - reason = "used by the panic! macro", - issue = "0")] -#[inline(never)] #[cold] -pub fn begin_panic_fmt(msg: &fmt::Arguments, - file_line_col: &(&'static str, u32, u32)) -> ! { - let (file, line, col) = *file_line_col; - let info = PanicInfo::internal_constructor( - Some(msg), - Location::internal_constructor(file, line, col), - ); - continue_panic_fmt(&info) -} - -fn continue_panic_fmt(info: &PanicInfo) -> ! { - struct PanicPayload<'a> { - inner: &'a fmt::Arguments<'a>, - string: Option, - } - - impl<'a> PanicPayload<'a> { - fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { - PanicPayload { inner, string: None } - } - - fn fill(&mut self) -> &mut String { - use fmt::Write; - - let inner = self.inner; - self.string.get_or_insert_with(|| { - let mut s = String::new(); - drop(s.write_fmt(*inner)); - s - }) - } - } - - unsafe impl<'a> BoxMeUp for PanicPayload<'a> { - fn box_me_up(&mut self) -> *mut (dyn Any + Send) { - let contents = mem::replace(self.fill(), String::new()); - Box::into_raw(Box::new(contents)) - } - - fn get(&mut self) -> &(dyn Any + Send) { - self.fill() - } - } - - // We do two allocations here, unfortunately. But (a) they're - // required with the current scheme, and (b) we don't handle - // panic + OOM properly anyway (see comment in begin_panic - // below). - - let loc = info.location().unwrap(); // The current implementation always returns Some - let msg = info.message().unwrap(); // The current implementation always returns Some - let file_line_col = (loc.file(), loc.line(), loc.column()); - rust_panic_with_hook( - &mut PanicPayload::new(msg), - info.message(), - &file_line_col); -} - -/// This is the entry point of panicking for panic!() and assert!(). -#[unstable(feature = "libstd_sys_internals", - reason = "used by the panic! macro", - issue = "0")] -#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible -pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! { - // Note that this should be the only allocation performed in this code path. - // Currently this means that panic!() on OOM will invoke this code path, - // but then again we're not really ready for panic on OOM anyway. If - // we do start doing this, then we should propagate this allocation to - // be performed in the parent of this thread instead of the thread that's - // panicking. - - rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col); - - struct PanicPayload { - inner: Option, - } - - impl PanicPayload { - fn new(inner: A) -> PanicPayload { - PanicPayload { inner: Some(inner) } - } - } - - unsafe impl BoxMeUp for PanicPayload { - fn box_me_up(&mut self) -> *mut (dyn Any + Send) { - let data = match self.inner.take() { - Some(a) => Box::new(a) as Box, - None => Box::new(()), - }; - Box::into_raw(data) - } - - fn get(&mut self) -> &(dyn Any + Send) { - match self.inner { - Some(ref a) => a, - None => &(), - } - } - } -} - -/// Central point for dispatching panics. -/// -/// Executes the primary logic for a panic, including checking for recursive -/// panics, panic hooks, and finally dispatching to the panic runtime to either -/// abort or unwind. -fn rust_panic_with_hook(payload: &mut dyn BoxMeUp, - message: Option<&fmt::Arguments>, - file_line_col: &(&str, u32, u32)) -> ! { - let (file, line, col) = *file_line_col; - - let panics = update_panic_count(1); - - // If this is the third nested call (e.g. panics == 2, this is 0-indexed), - // the panic hook probably triggered the last panic, otherwise the - // double-panic check would have aborted the process. In this case abort the - // process real quickly as we don't want to try calling it again as it'll - // probably just panic again. - if panics > 2 { - util::dumb_print(format_args!("thread panicked while processing \ - panic. aborting.\n")); - unsafe { intrinsics::abort() } - } - - unsafe { - let mut info = PanicInfo::internal_constructor( - message, - Location::internal_constructor(file, line, col), - ); - HOOK_LOCK.read(); - match HOOK { - // Some platforms know that printing to stderr won't ever actually - // print anything, and if that's the case we can skip the default - // hook. - Hook::Default if stderr_prints_nothing() => {} - Hook::Default => { - info.set_payload(payload.get()); - default_hook(&info); - } - Hook::Custom(ptr) => { - info.set_payload(payload.get()); - (*ptr)(&info); - } - } - HOOK_LOCK.read_unlock(); - } - - if panics > 1 { - // If a thread panics while it's already unwinding then we - // have limited options. Currently our preference is to - // just abort. In the future we may consider resuming - // unwinding or otherwise exiting the thread cleanly. - util::dumb_print(format_args!("thread panicked while panicking. \ - aborting.\n")); - unsafe { intrinsics::abort() } - } - - rust_panic(payload) -} - -/// Shim around rust_panic. Called by resume_unwind. -pub fn update_count_then_panic(msg: Box) -> ! { - update_panic_count(1); - - struct RewrapBox(Box); - - unsafe impl BoxMeUp for RewrapBox { - fn box_me_up(&mut self) -> *mut (dyn Any + Send) { - Box::into_raw(mem::replace(&mut self.0, Box::new(()))) - } - - fn get(&mut self) -> &(dyn Any + Send) { - &*self.0 - } - } - - rust_panic(&mut RewrapBox(msg)) -} - -/// A private no-mangle function on which to slap yer breakpoints. -#[no_mangle] -#[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints -pub fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! { - let code = unsafe { - let obj = &mut msg as *mut &mut dyn BoxMeUp; - __rust_start_panic(obj as usize) - }; - rtabort!("failed to initiate panic, error {}", code) -} diff --git a/ctr-std/src/path.rs b/ctr-std/src/path.rs deleted file mode 100644 index ae7b632..0000000 --- a/ctr-std/src/path.rs +++ /dev/null @@ -1,4145 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Cross-platform path manipulation. -//! -//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`] -//! and [`str`]), for working with paths abstractly. These types are thin wrappers -//! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly -//! on strings according to the local platform's path syntax. -//! -//! Paths can be parsed into [`Component`]s by iterating over the structure -//! returned by the [`components`] method on [`Path`]. [`Component`]s roughly -//! correspond to the substrings between path separators (`/` or `\`). You can -//! reconstruct an equivalent path from components with the [`push`] method on -//! [`PathBuf`]; note that the paths may differ syntactically by the -//! normalization described in the documentation for the [`components`] method. -//! -//! ## Simple usage -//! -//! Path manipulation includes both parsing components from slices and building -//! new owned paths. -//! -//! To parse a path, you can create a [`Path`] slice from a [`str`] -//! slice and start asking questions: -//! -//! ``` -//! use std::path::Path; -//! use std::ffi::OsStr; -//! -//! let path = Path::new("/tmp/foo/bar.txt"); -//! -//! let parent = path.parent(); -//! assert_eq!(parent, Some(Path::new("/tmp/foo"))); -//! -//! let file_stem = path.file_stem(); -//! assert_eq!(file_stem, Some(OsStr::new("bar"))); -//! -//! let extension = path.extension(); -//! assert_eq!(extension, Some(OsStr::new("txt"))); -//! ``` -//! -//! To build or modify paths, use [`PathBuf`]: -//! -//! ``` -//! use std::path::PathBuf; -//! -//! // This way works... -//! let mut path = PathBuf::from("c:\\"); -//! -//! path.push("windows"); -//! path.push("system32"); -//! -//! path.set_extension("dll"); -//! -//! // ... but push is best used if you don't know everything up -//! // front. If you do, this way is better: -//! let path: PathBuf = ["c:\\", "windows", "system32.dll"].iter().collect(); -//! ``` -//! -//! [`Component`]: ../../std/path/enum.Component.html -//! [`components`]: ../../std/path/struct.Path.html#method.components -//! [`PathBuf`]: ../../std/path/struct.PathBuf.html -//! [`Path`]: ../../std/path/struct.Path.html -//! [`push`]: ../../std/path/struct.PathBuf.html#method.push -//! [`String`]: ../../std/string/struct.String.html -//! -//! [`str`]: ../../std/primitive.str.html -//! [`OsString`]: ../../std/ffi/struct.OsString.html -//! [`OsStr`]: ../../std/ffi/struct.OsStr.html - -#![stable(feature = "rust1", since = "1.0.0")] - -use borrow::{Borrow, Cow}; -use cmp; -use error::Error; -use fmt; -use fs; -use hash::{Hash, Hasher}; -use io; -use iter::{self, FusedIterator}; -use ops::{self, Deref}; -use rc::Rc; -use sync::Arc; - -use ffi::{OsStr, OsString}; - -use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; - -//////////////////////////////////////////////////////////////////////////////// -// GENERAL NOTES -//////////////////////////////////////////////////////////////////////////////// -// -// Parsing in this module is done by directly transmuting OsStr to [u8] slices, -// taking advantage of the fact that OsStr always encodes ASCII characters -// as-is. Eventually, this transmutation should be replaced by direct uses of -// OsStr APIs for parsing, but it will take a while for those to become -// available. - -//////////////////////////////////////////////////////////////////////////////// -// Windows Prefixes -//////////////////////////////////////////////////////////////////////////////// - -/// Windows path prefixes, e.g. `C:` or `\\server\share`. -/// -/// Windows uses a variety of path prefix styles, including references to drive -/// volumes (like `C:`), network shared folders (like `\\server\share`), and -/// others. In addition, some path prefixes are "verbatim" (i.e. prefixed with -/// `\\?\`), in which case `/` is *not* treated as a separator and essentially -/// no normalization is performed. -/// -/// # Examples -/// -/// ``` -/// use std::path::{Component, Path, Prefix}; -/// use std::path::Prefix::*; -/// use std::ffi::OsStr; -/// -/// fn get_path_prefix(s: &str) -> Prefix { -/// let path = Path::new(s); -/// match path.components().next().unwrap() { -/// Component::Prefix(prefix_component) => prefix_component.kind(), -/// _ => panic!(), -/// } -/// } -/// -/// # if cfg!(windows) { -/// assert_eq!(Verbatim(OsStr::new("pictures")), -/// get_path_prefix(r"\\?\pictures\kittens")); -/// assert_eq!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")), -/// get_path_prefix(r"\\?\UNC\server\share")); -/// assert_eq!(VerbatimDisk(b'C'), get_path_prefix(r"\\?\c:\")); -/// assert_eq!(DeviceNS(OsStr::new("BrainInterface")), -/// get_path_prefix(r"\\.\BrainInterface")); -/// assert_eq!(UNC(OsStr::new("server"), OsStr::new("share")), -/// get_path_prefix(r"\\server\share")); -/// assert_eq!(Disk(b'C'), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris")); -/// # } -/// ``` -#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] -#[stable(feature = "rust1", since = "1.0.0")] -pub enum Prefix<'a> { - /// Verbatim prefix, e.g. `\\?\cat_pics`. - /// - /// Verbatim prefixes consist of `\\?\` immediately followed by the given - /// component. - #[stable(feature = "rust1", since = "1.0.0")] - Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - - /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_, - /// e.g. `\\?\UNC\server\share`. - /// - /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the - /// server's hostname and a share name. - #[stable(feature = "rust1", since = "1.0.0")] - VerbatimUNC( - #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, - #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, - ), - - /// Verbatim disk prefix, e.g. `\\?\C:\`. - /// - /// Verbatim disk prefixes consist of `\\?\` immediately followed by the - /// drive letter and `:\`. - #[stable(feature = "rust1", since = "1.0.0")] - VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8), - - /// Device namespace prefix, e.g. `\\.\COM42`. - /// - /// Device namespace prefixes consist of `\\.\` immediately followed by the - /// device name. - #[stable(feature = "rust1", since = "1.0.0")] - DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - - /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g. - /// `\\server\share`. - /// - /// UNC prefixes consist of the server's hostname and a share name. - #[stable(feature = "rust1", since = "1.0.0")] - UNC( - #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, - #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, - ), - - /// Prefix `C:` for the given disk drive. - #[stable(feature = "rust1", since = "1.0.0")] - Disk(#[stable(feature = "rust1", since = "1.0.0")] u8), -} - -impl<'a> Prefix<'a> { - #[inline] - fn len(&self) -> usize { - use self::Prefix::*; - fn os_str_len(s: &OsStr) -> usize { - os_str_as_u8_slice(s).len() - } - match *self { - #[cfg(target_os = "horizon")] - Verbatim(x) => 1 + os_str_len(x), - #[cfg(not(target_os = "horizon"))] - Verbatim(x) => 1 + os_str_len(x), - VerbatimUNC(x, y) => { - 8 + os_str_len(x) + - if os_str_len(y) > 0 { - 1 + os_str_len(y) - } else { - 0 - } - }, - VerbatimDisk(_) => 6, - UNC(x, y) => { - 2 + os_str_len(x) + - if os_str_len(y) > 0 { - 1 + os_str_len(y) - } else { - 0 - } - }, - DeviceNS(x) => 4 + os_str_len(x), - Disk(_) => 2, - } - - } - - /// Determines if the prefix is verbatim, i.e. begins with `\\?\`. - /// - /// # Examples - /// - /// ``` - /// use std::path::Prefix::*; - /// use std::ffi::OsStr; - /// - /// assert!(Verbatim(OsStr::new("pictures")).is_verbatim()); - /// assert!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); - /// assert!(VerbatimDisk(b'C').is_verbatim()); - /// assert!(!DeviceNS(OsStr::new("BrainInterface")).is_verbatim()); - /// assert!(!UNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); - /// assert!(!Disk(b'C').is_verbatim()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_verbatim(&self) -> bool { - use self::Prefix::*; - match *self { - Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..) => true, - _ => false, - } - } - - #[inline] - fn is_drive(&self) -> bool { - match *self { - Prefix::Disk(_) => true, - _ => false, - } - } - - #[inline] - fn has_implicit_root(&self) -> bool { - !self.is_drive() - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Exposed parsing helpers -//////////////////////////////////////////////////////////////////////////////// - -/// Determines whether the character is one of the permitted path -/// separators for the current platform. -/// -/// # Examples -/// -/// ``` -/// use std::path; -/// -/// assert!(path::is_separator('/')); // '/' works for both Unix and Windows -/// assert!(!path::is_separator('❤')); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn is_separator(c: char) -> bool { - c.is_ascii() && is_sep_byte(c as u8) -} - -/// The primary separator of path components for the current platform. -/// -/// For example, `/` on Unix and `\` on Windows. -#[stable(feature = "rust1", since = "1.0.0")] -pub const MAIN_SEPARATOR: char = ::sys::path::MAIN_SEP; - -//////////////////////////////////////////////////////////////////////////////// -// Misc helpers -//////////////////////////////////////////////////////////////////////////////// - -// Iterate through `iter` while it matches `prefix`; return `None` if `prefix` -// is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving -// `iter` after having exhausted `prefix`. -fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option - where I: Iterator> + Clone, - J: Iterator>, -{ - loop { - let mut iter_next = iter.clone(); - match (iter_next.next(), prefix.next()) { - (Some(ref x), Some(ref y)) if x == y => (), - (Some(_), Some(_)) => return None, - (Some(_), None) => return Some(iter), - (None, None) => return Some(iter), - (None, Some(_)) => return None, - } - iter = iter_next; - } -} - -// See note at the top of this module to understand why these are used: -fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { - unsafe { &*(s as *const OsStr as *const [u8]) } -} -unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - &*(s as *const [u8] as *const OsStr) -} - -// Detect scheme on Redox -fn has_redox_scheme(s: &[u8]) -> bool { - cfg!(target_os = "redox") && s.split(|b| *b == b'/').next().unwrap_or(b"").contains(&b':') -} - -//////////////////////////////////////////////////////////////////////////////// -// Cross-platform, iterator-independent parsing -//////////////////////////////////////////////////////////////////////////////// - -/// Says whether the first byte after the prefix is a separator. -fn has_physical_root(s: &[u8], prefix: Option) -> bool { - let path = if let Some(p) = prefix { - &s[p.len()..] - } else { - s - }; - !path.is_empty() && is_sep_byte(path[0]) -} - -// basic workhorse for splitting stem and extension -fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { - unsafe { - if os_str_as_u8_slice(file) == b".." { - return (Some(file), None); - } - - // The unsafety here stems from converting between &OsStr and &[u8] - // and back. This is safe to do because (1) we only look at ASCII - // contents of the encoding and (2) new &OsStr values are produced - // only from ASCII-bounded slices of existing &OsStr values. - - let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.'); - let after = iter.next(); - let before = iter.next(); - if before == Some(b"") { - (Some(file), None) - } else { - (before.map(|s| u8_slice_as_os_str(s)), - after.map(|s| u8_slice_as_os_str(s))) - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// The core iterators -//////////////////////////////////////////////////////////////////////////////// - -/// Component parsing works by a double-ended state machine; the cursors at the -/// front and back of the path each keep track of what parts of the path have -/// been consumed so far. -/// -/// Going front to back, a path is made up of a prefix, a starting -/// directory component, and a body (of normal components) -#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] -enum State { - Prefix = 0, // c: - StartDir = 1, // / or . or nothing - Body = 2, // foo/bar/baz - Done = 3, -} - -/// A structure wrapping a Windows path prefix as well as its unparsed string -/// representation. -/// -/// In addition to the parsed [`Prefix`] information returned by [`kind`], -/// `PrefixComponent` also holds the raw and unparsed [`OsStr`] slice, -/// returned by [`as_os_str`]. -/// -/// Instances of this `struct` can be obtained by matching against the -/// [`Prefix` variant] on [`Component`]. -/// -/// Does not occur on Unix. -/// -/// # Examples -/// -/// ``` -/// # if cfg!(windows) { -/// use std::path::{Component, Path, Prefix}; -/// use std::ffi::OsStr; -/// -/// let path = Path::new(r"c:\you\later\"); -/// match path.components().next().unwrap() { -/// Component::Prefix(prefix_component) => { -/// assert_eq!(Prefix::Disk(b'C'), prefix_component.kind()); -/// assert_eq!(OsStr::new("c:"), prefix_component.as_os_str()); -/// } -/// _ => unreachable!(), -/// } -/// # } -/// ``` -/// -/// [`as_os_str`]: #method.as_os_str -/// [`Component`]: enum.Component.html -/// [`kind`]: #method.kind -/// [`OsStr`]: ../../std/ffi/struct.OsStr.html -/// [`Prefix` variant]: enum.Component.html#variant.Prefix -/// [`Prefix`]: enum.Prefix.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Copy, Clone, Eq, Debug)] -pub struct PrefixComponent<'a> { - /// The prefix as an unparsed `OsStr` slice. - raw: &'a OsStr, - - /// The parsed prefix data. - parsed: Prefix<'a>, -} - -impl<'a> PrefixComponent<'a> { - /// Returns the parsed prefix data. - /// - /// See [`Prefix`]'s documentation for more information on the different - /// kinds of prefixes. - /// - /// [`Prefix`]: enum.Prefix.html - #[stable(feature = "rust1", since = "1.0.0")] - pub fn kind(&self) -> Prefix<'a> { - self.parsed - } - - /// Returns the raw [`OsStr`] slice for this prefix. - /// - /// [`OsStr`]: ../../std/ffi/struct.OsStr.html - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_os_str(&self) -> &'a OsStr { - self.raw - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> cmp::PartialEq for PrefixComponent<'a> { - fn eq(&self, other: &PrefixComponent<'a>) -> bool { - cmp::PartialEq::eq(&self.parsed, &other.parsed) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> cmp::PartialOrd for PrefixComponent<'a> { - fn partial_cmp(&self, other: &PrefixComponent<'a>) -> Option { - cmp::PartialOrd::partial_cmp(&self.parsed, &other.parsed) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> cmp::Ord for PrefixComponent<'a> { - fn cmp(&self, other: &PrefixComponent<'a>) -> cmp::Ordering { - cmp::Ord::cmp(&self.parsed, &other.parsed) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Hash for PrefixComponent<'a> { - fn hash(&self, h: &mut H) { - self.parsed.hash(h); - } -} - -/// A single component of a path. -/// -/// A `Component` roughly corresponds to a substring between path separators -/// (`/` or `\`). -/// -/// This `enum` is created by iterating over [`Components`], which in turn is -/// created by the [`components`][`Path::components`] method on [`Path`]. -/// -/// # Examples -/// -/// ```rust -/// use std::path::{Component, Path}; -/// -/// let path = Path::new("/tmp/foo/bar.txt"); -/// let components = path.components().collect::>(); -/// assert_eq!(&components, &[ -/// Component::RootDir, -/// Component::Normal("tmp".as_ref()), -/// Component::Normal("foo".as_ref()), -/// Component::Normal("bar.txt".as_ref()), -/// ]); -/// ``` -/// -/// [`Components`]: struct.Components.html -/// [`Path`]: struct.Path.html -/// [`Path::components`]: struct.Path.html#method.components -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub enum Component<'a> { - /// A Windows path prefix, e.g. `C:` or `\\server\share`. - /// - /// There is a large variety of prefix types, see [`Prefix`]'s documentation - /// for more. - /// - /// Does not occur on Unix. - /// - /// [`Prefix`]: enum.Prefix.html - #[stable(feature = "rust1", since = "1.0.0")] - Prefix( - #[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a> - ), - - /// The root directory component, appears after any prefix and before anything else. - /// - /// It represents a separator that designates that a path starts from root. - #[stable(feature = "rust1", since = "1.0.0")] - RootDir, - - /// A reference to the current directory, i.e. `.`. - #[stable(feature = "rust1", since = "1.0.0")] - CurDir, - - /// A reference to the parent directory, i.e. `..`. - #[stable(feature = "rust1", since = "1.0.0")] - ParentDir, - - /// A normal component, e.g. `a` and `b` in `a/b`. - /// - /// This variant is the most common one, it represents references to files - /// or directories. - #[stable(feature = "rust1", since = "1.0.0")] - Normal(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), -} - -impl<'a> Component<'a> { - /// Extracts the underlying [`OsStr`] slice. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("./tmp/foo/bar.txt"); - /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect(); - /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]); - /// ``` - /// - /// [`OsStr`]: ../../std/ffi/struct.OsStr.html - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_os_str(self) -> &'a OsStr { - match self { - Component::Prefix(p) => p.as_os_str(), - Component::RootDir => OsStr::new(MAIN_SEP_STR), - Component::CurDir => OsStr::new("."), - Component::ParentDir => OsStr::new(".."), - Component::Normal(path) => path, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> AsRef for Component<'a> { - fn as_ref(&self) -> &OsStr { - self.as_os_str() - } -} - -#[stable(feature = "path_component_asref", since = "1.25.0")] -impl<'a> AsRef for Component<'a> { - fn as_ref(&self) -> &Path { - self.as_os_str().as_ref() - } -} - -/// An iterator over the [`Component`]s of a [`Path`]. -/// -/// This `struct` is created by the [`components`] method on [`Path`]. -/// See its documentation for more. -/// -/// # Examples -/// -/// ``` -/// use std::path::Path; -/// -/// let path = Path::new("/tmp/foo/bar.txt"); -/// -/// for component in path.components() { -/// println!("{:?}", component); -/// } -/// ``` -/// -/// [`Component`]: enum.Component.html -/// [`components`]: struct.Path.html#method.components -/// [`Path`]: struct.Path.html -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Components<'a> { - // The path left to parse components from - path: &'a [u8], - - // The prefix as it was originally parsed, if any - prefix: Option>, - - // true if path *physically* has a root separator; for most Windows - // prefixes, it may have a "logical" rootseparator for the purposes of - // normalization, e.g. \\server\share == \\server\share\. - has_physical_root: bool, - - // The iterator is double-ended, and these two states keep track of what has - // been produced from either end - front: State, - back: State, -} - -/// An iterator over the [`Component`]s of a [`Path`], as [`OsStr`] slices. -/// -/// This `struct` is created by the [`iter`] method on [`Path`]. -/// See its documentation for more. -/// -/// [`Component`]: enum.Component.html -/// [`iter`]: struct.Path.html#method.iter -/// [`OsStr`]: ../../std/ffi/struct.OsStr.html -/// [`Path`]: struct.Path.html -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a> { - inner: Components<'a>, -} - -#[stable(feature = "path_components_debug", since = "1.13.0")] -impl<'a> fmt::Debug for Components<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - struct DebugHelper<'a>(&'a Path); - - impl<'a> fmt::Debug for DebugHelper<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.0.components()) - .finish() - } - } - - f.debug_tuple("Components") - .field(&DebugHelper(self.as_path())) - .finish() - } -} - -impl<'a> Components<'a> { - // how long is the prefix, if any? - #[inline] - fn prefix_len(&self) -> usize { - self.prefix.as_ref().map(Prefix::len).unwrap_or(0) - } - - #[inline] - fn prefix_verbatim(&self) -> bool { - self.prefix.as_ref().map(Prefix::is_verbatim).unwrap_or(false) - } - - /// how much of the prefix is left from the point of view of iteration? - #[inline] - fn prefix_remaining(&self) -> usize { - if self.front == State::Prefix { - self.prefix_len() - } else { - 0 - } - } - - // Given the iteration so far, how much of the pre-State::Body path is left? - #[inline] - fn len_before_body(&self) -> usize { - let root = if self.front <= State::StartDir && self.has_physical_root { - 1 - } else { - 0 - }; - let cur_dir = if self.front <= State::StartDir && self.include_cur_dir() { - 1 - } else { - 0 - }; - self.prefix_remaining() + root + cur_dir - } - - // is the iteration complete? - #[inline] - fn finished(&self) -> bool { - self.front == State::Done || self.back == State::Done || self.front > self.back - } - - #[inline] - fn is_sep_byte(&self, b: u8) -> bool { - if self.prefix_verbatim() { - is_verbatim_sep(b) - } else { - is_sep_byte(b) - } - } - - /// Extracts a slice corresponding to the portion of the path remaining for iteration. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let mut components = Path::new("/tmp/foo/bar.txt").components(); - /// components.next(); - /// components.next(); - /// - /// assert_eq!(Path::new("foo/bar.txt"), components.as_path()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_path(&self) -> &'a Path { - let mut comps = self.clone(); - if comps.front == State::Body { - comps.trim_left(); - } - if comps.back == State::Body { - comps.trim_right(); - } - unsafe { Path::from_u8_slice(comps.path) } - } - - /// Is the *original* path rooted? - fn has_root(&self) -> bool { - if self.has_physical_root { - return true; - } - if let Some(p) = self.prefix { - if p.has_implicit_root() { - return true; - } - } - false - } - - /// Should the normalized path include a leading . ? - fn include_cur_dir(&self) -> bool { - if self.has_root() { - return false; - } - let mut iter = self.path[self.prefix_len()..].iter(); - match (iter.next(), iter.next()) { - (Some(&b'.'), None) => true, - (Some(&b'.'), Some(&b)) => self.is_sep_byte(b), - _ => false, - } - } - - // parse a given byte sequence into the corresponding path component - fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option> { - match comp { - b"." if self.prefix_verbatim() => Some(Component::CurDir), - b"." => None, // . components are normalized away, except at - // the beginning of a path, which is treated - // separately via `include_cur_dir` - b".." => Some(Component::ParentDir), - b"" => None, - _ => Some(Component::Normal(unsafe { u8_slice_as_os_str(comp) })), - } - } - - // parse a component from the left, saying how many bytes to consume to - // remove the component - fn parse_next_component(&self) -> (usize, Option>) { - debug_assert!(self.front == State::Body); - let (extra, comp) = match self.path.iter().position(|b| self.is_sep_byte(*b)) { - None => (0, self.path), - Some(i) => (1, &self.path[..i]), - }; - (comp.len() + extra, self.parse_single_component(comp)) - } - - // parse a component from the right, saying how many bytes to consume to - // remove the component - fn parse_next_component_back(&self) -> (usize, Option>) { - debug_assert!(self.back == State::Body); - let start = self.len_before_body(); - let (extra, comp) = match self.path[start..].iter().rposition(|b| self.is_sep_byte(*b)) { - None => (0, &self.path[start..]), - Some(i) => (1, &self.path[start + i + 1..]), - }; - (comp.len() + extra, self.parse_single_component(comp)) - } - - // trim away repeated separators (i.e. empty components) on the left - fn trim_left(&mut self) { - while !self.path.is_empty() { - let (size, comp) = self.parse_next_component(); - if comp.is_some() { - return; - } else { - self.path = &self.path[size..]; - } - } - } - - // trim away repeated separators (i.e. empty components) on the right - fn trim_right(&mut self) { - while self.path.len() > self.len_before_body() { - let (size, comp) = self.parse_next_component_back(); - if comp.is_some() { - return; - } else { - self.path = &self.path[..self.path.len() - size]; - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> AsRef for Components<'a> { - fn as_ref(&self) -> &Path { - self.as_path() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> AsRef for Components<'a> { - fn as_ref(&self) -> &OsStr { - self.as_path().as_os_str() - } -} - -#[stable(feature = "path_iter_debug", since = "1.13.0")] -impl<'a> fmt::Debug for Iter<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - struct DebugHelper<'a>(&'a Path); - - impl<'a> fmt::Debug for DebugHelper<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.0.iter()) - .finish() - } - } - - f.debug_tuple("Iter") - .field(&DebugHelper(self.as_path())) - .finish() - } -} - -impl<'a> Iter<'a> { - /// Extracts a slice corresponding to the portion of the path remaining for iteration. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let mut iter = Path::new("/tmp/foo/bar.txt").iter(); - /// iter.next(); - /// iter.next(); - /// - /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_path(&self) -> &'a Path { - self.inner.as_path() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> AsRef for Iter<'a> { - fn as_ref(&self) -> &Path { - self.as_path() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> AsRef for Iter<'a> { - fn as_ref(&self) -> &OsStr { - self.as_path().as_os_str() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for Iter<'a> { - type Item = &'a OsStr; - - fn next(&mut self) -> Option<&'a OsStr> { - self.inner.next().map(Component::as_os_str) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for Iter<'a> { - fn next_back(&mut self) -> Option<&'a OsStr> { - self.inner.next_back().map(Component::as_os_str) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a> FusedIterator for Iter<'a> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for Components<'a> { - type Item = Component<'a>; - - fn next(&mut self) -> Option> { - while !self.finished() { - match self.front { - State::Prefix if self.prefix_len() > 0 => { - self.front = State::StartDir; - debug_assert!(self.prefix_len() <= self.path.len()); - let raw = &self.path[..self.prefix_len()]; - self.path = &self.path[self.prefix_len()..]; - return Some(Component::Prefix(PrefixComponent { - raw: unsafe { u8_slice_as_os_str(raw) }, - parsed: self.prefix.unwrap(), - })); - } - State::Prefix => { - self.front = State::StartDir; - } - State::StartDir => { - self.front = State::Body; - if self.has_physical_root { - debug_assert!(!self.path.is_empty()); - self.path = &self.path[1..]; - return Some(Component::RootDir); - } else if let Some(p) = self.prefix { - if p.has_implicit_root() && !p.is_verbatim() { - return Some(Component::RootDir); - } - } else if self.include_cur_dir() { - debug_assert!(!self.path.is_empty()); - self.path = &self.path[1..]; - return Some(Component::CurDir); - } - } - State::Body if !self.path.is_empty() => { - let (size, comp) = self.parse_next_component(); - self.path = &self.path[size..]; - if comp.is_some() { - return comp; - } - } - State::Body => { - self.front = State::Done; - } - State::Done => unreachable!(), - } - } - None - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for Components<'a> { - fn next_back(&mut self) -> Option> { - while !self.finished() { - match self.back { - State::Body if self.path.len() > self.len_before_body() => { - let (size, comp) = self.parse_next_component_back(); - self.path = &self.path[..self.path.len() - size]; - if comp.is_some() { - return comp; - } - } - State::Body => { - self.back = State::StartDir; - } - State::StartDir => { - self.back = State::Prefix; - if self.has_physical_root { - self.path = &self.path[..self.path.len() - 1]; - return Some(Component::RootDir); - } else if let Some(p) = self.prefix { - if p.has_implicit_root() && !p.is_verbatim() { - return Some(Component::RootDir); - } - } else if self.include_cur_dir() { - self.path = &self.path[..self.path.len() - 1]; - return Some(Component::CurDir); - } - } - State::Prefix if self.prefix_len() > 0 => { - self.back = State::Done; - return Some(Component::Prefix(PrefixComponent { - raw: unsafe { u8_slice_as_os_str(self.path) }, - parsed: self.prefix.unwrap(), - })); - } - State::Prefix => { - self.back = State::Done; - return None; - } - State::Done => unreachable!(), - } - } - None - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a> FusedIterator for Components<'a> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> cmp::PartialEq for Components<'a> { - fn eq(&self, other: &Components<'a>) -> bool { - Iterator::eq(self.clone(), other.clone()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> cmp::Eq for Components<'a> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> cmp::PartialOrd for Components<'a> { - fn partial_cmp(&self, other: &Components<'a>) -> Option { - Iterator::partial_cmp(self.clone(), other.clone()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> cmp::Ord for Components<'a> { - fn cmp(&self, other: &Components<'a>) -> cmp::Ordering { - Iterator::cmp(self.clone(), other.clone()) - } -} - -/// An iterator over [`Path`] and its ancestors. -/// -/// This `struct` is created by the [`ancestors`] method on [`Path`]. -/// See its documentation for more. -/// -/// # Examples -/// -/// ``` -/// use std::path::Path; -/// -/// let path = Path::new("/foo/bar"); -/// -/// for ancestor in path.ancestors() { -/// println!("{}", ancestor.display()); -/// } -/// ``` -/// -/// [`ancestors`]: struct.Path.html#method.ancestors -/// [`Path`]: struct.Path.html -#[derive(Copy, Clone, Debug)] -#[stable(feature = "path_ancestors", since = "1.28.0")] -pub struct Ancestors<'a> { - next: Option<&'a Path>, -} - -#[stable(feature = "path_ancestors", since = "1.28.0")] -impl<'a> Iterator for Ancestors<'a> { - type Item = &'a Path; - - fn next(&mut self) -> Option { - let next = self.next; - self.next = next.and_then(Path::parent); - next - } -} - -#[stable(feature = "path_ancestors", since = "1.28.0")] -impl<'a> FusedIterator for Ancestors<'a> {} - -//////////////////////////////////////////////////////////////////////////////// -// Basic types and traits -//////////////////////////////////////////////////////////////////////////////// - -/// An owned, mutable path (akin to [`String`]). -/// -/// This type provides methods like [`push`] and [`set_extension`] that mutate -/// the path in place. It also implements [`Deref`] to [`Path`], meaning that -/// all methods on [`Path`] slices are available on `PathBuf` values as well. -/// -/// [`String`]: ../string/struct.String.html -/// [`Path`]: struct.Path.html -/// [`push`]: struct.PathBuf.html#method.push -/// [`set_extension`]: struct.PathBuf.html#method.set_extension -/// [`Deref`]: ../ops/trait.Deref.html -/// -/// More details about the overall approach can be found in -/// the [module documentation](index.html). -/// -/// # Examples -/// -/// You can use [`push`] to build up a `PathBuf` from -/// components: -/// -/// ``` -/// use std::path::PathBuf; -/// -/// let mut path = PathBuf::new(); -/// -/// path.push(r"C:\"); -/// path.push("windows"); -/// path.push("system32"); -/// -/// path.set_extension("dll"); -/// ``` -/// -/// However, [`push`] is best used for dynamic situations. This is a better way -/// to do this when you know all of the components ahead of time: -/// -/// ``` -/// use std::path::PathBuf; -/// -/// let path: PathBuf = [r"C:\", "windows", "system32.dll"].iter().collect(); -/// ``` -/// -/// We can still do better than this! Since these are all strings, we can use -/// `From::from`: -/// -/// ``` -/// use std::path::PathBuf; -/// -/// let path = PathBuf::from(r"C:\windows\system32.dll"); -/// ``` -/// -/// Which method works best depends on what kind of situation you're in. -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct PathBuf { - inner: OsString, -} - -impl PathBuf { - fn as_mut_vec(&mut self) -> &mut Vec { - unsafe { &mut *(self as *mut PathBuf as *mut Vec) } - } - - /// Allocates an empty `PathBuf`. - /// - /// # Examples - /// - /// ``` - /// use std::path::PathBuf; - /// - /// let path = PathBuf::new(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> PathBuf { - PathBuf { inner: OsString::new() } - } - - /// Coerces to a [`Path`] slice. - /// - /// [`Path`]: struct.Path.html - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let p = PathBuf::from("/test"); - /// assert_eq!(Path::new("/test"), p.as_path()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_path(&self) -> &Path { - self - } - - /// Extends `self` with `path`. - /// - /// If `path` is absolute, it replaces the current path. - /// - /// On Windows: - /// - /// * if `path` has a root but no prefix (e.g. `\windows`), it - /// replaces everything except for the prefix (if any) of `self`. - /// * if `path` has a prefix but no root, it replaces `self`. - /// - /// # Examples - /// - /// Pushing a relative path extends the existing path: - /// - /// ``` - /// use std::path::PathBuf; - /// - /// let mut path = PathBuf::from("/tmp"); - /// path.push("file.bk"); - /// assert_eq!(path, PathBuf::from("/tmp/file.bk")); - /// ``` - /// - /// Pushing an absolute path replaces the existing path: - /// - /// ``` - /// use std::path::PathBuf; - /// - /// let mut path = PathBuf::from("/tmp"); - /// path.push("/etc"); - /// assert_eq!(path, PathBuf::from("/etc")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn push>(&mut self, path: P) { - self._push(path.as_ref()) - } - - fn _push(&mut self, path: &Path) { - // in general, a separator is needed if the rightmost byte is not a separator - let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false); - - // in the special case of `C:` on Windows, do *not* add a separator - { - let comps = self.components(); - if comps.prefix_len() > 0 && comps.prefix_len() == comps.path.len() && - comps.prefix.unwrap().is_drive() { - need_sep = false - } - } - - // absolute `path` replaces `self` - if path.is_absolute() || path.prefix().is_some() { - self.as_mut_vec().truncate(0); - - // `path` has a root but no prefix, e.g. `\windows` (Windows only) - } else if path.has_root() { - let prefix_len = self.components().prefix_remaining(); - self.as_mut_vec().truncate(prefix_len); - - // `path` is a pure relative path - } else if need_sep { - self.inner.push(MAIN_SEP_STR); - } - - self.inner.push(path); - } - - /// Truncates `self` to [`self.parent`]. - /// - /// Returns `false` and does nothing if [`self.file_name`] is [`None`]. - /// Otherwise, returns `true`. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`self.parent`]: struct.PathBuf.html#method.parent - /// [`self.file_name`]: struct.PathBuf.html#method.file_name - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let mut p = PathBuf::from("/test/test.rs"); - /// - /// p.pop(); - /// assert_eq!(Path::new("/test"), p); - /// p.pop(); - /// assert_eq!(Path::new("/"), p); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn pop(&mut self) -> bool { - match self.parent().map(|p| p.as_u8_slice().len()) { - Some(len) => { - self.as_mut_vec().truncate(len); - true - } - None => false, - } - } - - /// Updates [`self.file_name`] to `file_name`. - /// - /// If [`self.file_name`] was [`None`], this is equivalent to pushing - /// `file_name`. - /// - /// Otherwise it is equivalent to calling [`pop`] and then pushing - /// `file_name`. The new path will be a sibling of the original path. - /// (That is, it will have the same parent.) - /// - /// [`self.file_name`]: struct.PathBuf.html#method.file_name - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`pop`]: struct.PathBuf.html#method.pop - /// - /// # Examples - /// - /// ``` - /// use std::path::PathBuf; - /// - /// let mut buf = PathBuf::from("/"); - /// assert!(buf.file_name() == None); - /// buf.set_file_name("bar"); - /// assert!(buf == PathBuf::from("/bar")); - /// assert!(buf.file_name().is_some()); - /// buf.set_file_name("baz.txt"); - /// assert!(buf == PathBuf::from("/baz.txt")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_file_name>(&mut self, file_name: S) { - self._set_file_name(file_name.as_ref()) - } - - fn _set_file_name(&mut self, file_name: &OsStr) { - if self.file_name().is_some() { - let popped = self.pop(); - debug_assert!(popped); - } - self.push(file_name); - } - - /// Updates [`self.extension`] to `extension`. - /// - /// Returns `false` and does nothing if [`self.file_name`] is [`None`], - /// returns `true` and updates the extension otherwise. - /// - /// If [`self.extension`] is [`None`], the extension is added; otherwise - /// it is replaced. - /// - /// [`self.file_name`]: struct.PathBuf.html#method.file_name - /// [`self.extension`]: struct.PathBuf.html#method.extension - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let mut p = PathBuf::from("/feel/the"); - /// - /// p.set_extension("force"); - /// assert_eq!(Path::new("/feel/the.force"), p.as_path()); - /// - /// p.set_extension("dark_side"); - /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_extension>(&mut self, extension: S) -> bool { - self._set_extension(extension.as_ref()) - } - - fn _set_extension(&mut self, extension: &OsStr) -> bool { - if self.file_name().is_none() { - return false; - } - - let mut stem = match self.file_stem() { - Some(stem) => stem.to_os_string(), - None => OsString::new(), - }; - - if !os_str_as_u8_slice(extension).is_empty() { - stem.push("."); - stem.push(extension); - } - self.set_file_name(&stem); - - true - } - - /// Consumes the `PathBuf`, yielding its internal [`OsString`] storage. - /// - /// [`OsString`]: ../ffi/struct.OsString.html - /// - /// # Examples - /// - /// ``` - /// use std::path::PathBuf; - /// - /// let p = PathBuf::from("/the/head"); - /// let os_str = p.into_os_string(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_os_string(self) -> OsString { - self.inner - } - - /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`]. - /// - /// [`Box`]: ../../std/boxed/struct.Box.html - /// [`Path`]: struct.Path.html - #[stable(feature = "into_boxed_path", since = "1.20.0")] - pub fn into_boxed_path(self) -> Box { - let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path; - unsafe { Box::from_raw(rw) } - } -} - -#[stable(feature = "box_from_path", since = "1.17.0")] -impl<'a> From<&'a Path> for Box { - fn from(path: &'a Path) -> Box { - let boxed: Box = path.inner.into(); - let rw = Box::into_raw(boxed) as *mut Path; - unsafe { Box::from_raw(rw) } - } -} - -#[stable(feature = "path_buf_from_box", since = "1.18.0")] -impl From> for PathBuf { - fn from(boxed: Box) -> PathBuf { - boxed.into_path_buf() - } -} - -#[stable(feature = "box_from_path_buf", since = "1.20.0")] -impl From for Box { - fn from(p: PathBuf) -> Box { - p.into_boxed_path() - } -} - -#[stable(feature = "more_box_slice_clone", since = "1.29.0")] -impl Clone for Box { - #[inline] - fn clone(&self) -> Self { - self.to_path_buf().into_boxed_path() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized + AsRef> From<&'a T> for PathBuf { - fn from(s: &'a T) -> PathBuf { - PathBuf::from(s.as_ref().to_os_string()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl From for PathBuf { - fn from(s: OsString) -> PathBuf { - PathBuf { inner: s } - } -} - -#[stable(feature = "from_path_buf_for_os_string", since = "1.14.0")] -impl From for OsString { - fn from(path_buf : PathBuf) -> OsString { - path_buf.inner - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl From for PathBuf { - fn from(s: String) -> PathBuf { - PathBuf::from(OsString::from(s)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl> iter::FromIterator

for PathBuf { - fn from_iter>(iter: I) -> PathBuf { - let mut buf = PathBuf::new(); - buf.extend(iter); - buf - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl> iter::Extend

for PathBuf { - fn extend>(&mut self, iter: I) { - for p in iter { - self.push(p.as_ref()) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for PathBuf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&**self, formatter) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::Deref for PathBuf { - type Target = Path; - - fn deref(&self) -> &Path { - Path::new(&self.inner) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Borrow for PathBuf { - fn borrow(&self) -> &Path { - self.deref() - } -} - -#[stable(feature = "default_for_pathbuf", since = "1.17.0")] -impl Default for PathBuf { - fn default() -> Self { - PathBuf::new() - } -} - -#[stable(feature = "cow_from_path", since = "1.6.0")] -impl<'a> From<&'a Path> for Cow<'a, Path> { - #[inline] - fn from(s: &'a Path) -> Cow<'a, Path> { - Cow::Borrowed(s) - } -} - -#[stable(feature = "cow_from_path", since = "1.6.0")] -impl<'a> From for Cow<'a, Path> { - #[inline] - fn from(s: PathBuf) -> Cow<'a, Path> { - Cow::Owned(s) - } -} - -#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")] -impl<'a> From<&'a PathBuf> for Cow<'a, Path> { - #[inline] - fn from(p: &'a PathBuf) -> Cow<'a, Path> { - Cow::Borrowed(p.as_path()) - } -} - -#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")] -impl<'a> From> for PathBuf { - #[inline] - fn from(p: Cow<'a, Path>) -> Self { - p.into_owned() - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl From for Arc { - #[inline] - fn from(s: PathBuf) -> Arc { - let arc: Arc = Arc::from(s.into_os_string()); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) } - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a Path> for Arc { - #[inline] - fn from(s: &Path) -> Arc { - let arc: Arc = Arc::from(s.as_os_str()); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) } - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl From for Rc { - #[inline] - fn from(s: PathBuf) -> Rc { - let rc: Rc = Rc::from(s.into_os_string()); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) } - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl<'a> From<&'a Path> for Rc { - #[inline] - fn from(s: &Path) -> Rc { - let rc: Rc = Rc::from(s.as_os_str()); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToOwned for Path { - type Owned = PathBuf; - fn to_owned(&self) -> PathBuf { - self.to_path_buf() - } - fn clone_into(&self, target: &mut PathBuf) { - self.inner.clone_into(&mut target.inner); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl cmp::PartialEq for PathBuf { - fn eq(&self, other: &PathBuf) -> bool { - self.components() == other.components() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for PathBuf { - fn hash(&self, h: &mut H) { - self.as_path().hash(h) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl cmp::Eq for PathBuf {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl cmp::PartialOrd for PathBuf { - fn partial_cmp(&self, other: &PathBuf) -> Option { - self.components().partial_cmp(other.components()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl cmp::Ord for PathBuf { - fn cmp(&self, other: &PathBuf) -> cmp::Ordering { - self.components().cmp(other.components()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for PathBuf { - fn as_ref(&self) -> &OsStr { - &self.inner[..] - } -} - -/// A slice of a path (akin to [`str`]). -/// -/// This type supports a number of operations for inspecting a path, including -/// breaking the path into its components (separated by `/` on Unix and by either -/// `/` or `\` on Windows), extracting the file name, determining whether the path -/// is absolute, and so on. -/// -/// This is an *unsized* type, meaning that it must always be used behind a -/// pointer like `&` or [`Box`]. For an owned version of this type, -/// see [`PathBuf`]. -/// -/// [`str`]: ../primitive.str.html -/// [`Box`]: ../boxed/struct.Box.html -/// [`PathBuf`]: struct.PathBuf.html -/// -/// More details about the overall approach can be found in -/// the [module documentation](index.html). -/// -/// # Examples -/// -/// ``` -/// use std::path::Path; -/// use std::ffi::OsStr; -/// -/// // Note: this example does work on Windows -/// let path = Path::new("./foo/bar.txt"); -/// -/// let parent = path.parent(); -/// assert_eq!(parent, Some(Path::new("./foo"))); -/// -/// let file_stem = path.file_stem(); -/// assert_eq!(file_stem, Some(OsStr::new("bar"))); -/// -/// let extension = path.extension(); -/// assert_eq!(extension, Some(OsStr::new("txt"))); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Path { - inner: OsStr, -} - -/// An error returned from [`Path::strip_prefix`][`strip_prefix`] if the prefix -/// was not found. -/// -/// This `struct` is created by the [`strip_prefix`] method on [`Path`]. -/// See its documentation for more. -/// -/// [`strip_prefix`]: struct.Path.html#method.strip_prefix -/// [`Path`]: struct.Path.html -#[derive(Debug, Clone, PartialEq, Eq)] -#[stable(since = "1.7.0", feature = "strip_prefix")] -pub struct StripPrefixError(()); - -impl Path { - // The following (private!) function allows construction of a path from a u8 - // slice, which is only safe when it is known to follow the OsStr encoding. - unsafe fn from_u8_slice(s: &[u8]) -> &Path { - Path::new(u8_slice_as_os_str(s)) - } - // The following (private!) function reveals the byte encoding used for OsStr. - fn as_u8_slice(&self) -> &[u8] { - os_str_as_u8_slice(&self.inner) - } - - /// Directly wraps a string slice as a `Path` slice. - /// - /// This is a cost-free conversion. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// Path::new("foo.txt"); - /// ``` - /// - /// You can create `Path`s from `String`s, or even other `Path`s: - /// - /// ``` - /// use std::path::Path; - /// - /// let string = String::from("foo.txt"); - /// let from_string = Path::new(&string); - /// let from_path = Path::new(&from_string); - /// assert_eq!(from_string, from_path); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new + ?Sized>(s: &S) -> &Path { - unsafe { &*(s.as_ref() as *const OsStr as *const Path) } - } - - /// Yields the underlying [`OsStr`] slice. - /// - /// [`OsStr`]: ../ffi/struct.OsStr.html - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let os_str = Path::new("foo.txt").as_os_str(); - /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_os_str(&self) -> &OsStr { - &self.inner - } - - /// Yields a [`&str`] slice if the `Path` is valid unicode. - /// - /// This conversion may entail doing a check for UTF-8 validity. - /// - /// [`&str`]: ../primitive.str.html - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("foo.txt"); - /// assert_eq!(path.to_str(), Some("foo.txt")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_str(&self) -> Option<&str> { - self.inner.to_str() - } - - /// Converts a `Path` to a [`Cow`]. - /// - /// Any non-Unicode sequences are replaced with - /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. - /// - /// [`Cow`]: ../borrow/enum.Cow.html - /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html - /// - /// # Examples - /// - /// Calling `to_string_lossy` on a `Path` with valid unicode: - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("foo.txt"); - /// assert_eq!(path.to_string_lossy(), "foo.txt"); - /// ``` - /// - /// Had `path` contained invalid unicode, the `to_string_lossy` call might - /// have returned `"fo�.txt"`. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_string_lossy(&self) -> Cow { - self.inner.to_string_lossy() - } - - /// Converts a `Path` to an owned [`PathBuf`]. - /// - /// [`PathBuf`]: struct.PathBuf.html - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path_buf = Path::new("foo.txt").to_path_buf(); - /// assert_eq!(path_buf, std::path::PathBuf::from("foo.txt")); - /// ``` - #[rustc_conversion_suggestion] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_path_buf(&self) -> PathBuf { - PathBuf::from(self.inner.to_os_string()) - } - - /// Returns `true` if the `Path` is absolute, i.e. if it is independent of - /// the current directory. - /// - /// * On Unix, a path is absolute if it starts with the root, so - /// `is_absolute` and [`has_root`] are equivalent. - /// - /// * On Windows, a path is absolute if it has a prefix and starts with the - /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// assert!(!Path::new("foo.txt").is_absolute()); - /// ``` - /// - /// [`has_root`]: #method.has_root - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - pub fn is_absolute(&self) -> bool { - if cfg!(target_os = "redox") { - // FIXME: Allow Redox prefixes - self.has_root() || has_redox_scheme(self.as_u8_slice()) - } else { - self.has_root() && (cfg!(unix) || self.prefix().is_some()) - } - } - - /// Returns `true` if the `Path` is relative, i.e. not absolute. - /// - /// See [`is_absolute`]'s documentation for more details. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// assert!(Path::new("foo.txt").is_relative()); - /// ``` - /// - /// [`is_absolute`]: #method.is_absolute - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_relative(&self) -> bool { - !self.is_absolute() - } - - fn prefix(&self) -> Option { - self.components().prefix - } - - /// Returns `true` if the `Path` has a root. - /// - /// * On Unix, a path has a root if it begins with `/`. - /// - /// * On Windows, a path has a root if it: - /// * has no prefix and begins with a separator, e.g. `\windows` - /// * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows` - /// * has any non-disk prefix, e.g. `\\server\share` - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// assert!(Path::new("/etc/passwd").has_root()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn has_root(&self) -> bool { - self.components().has_root() - } - - /// Returns the `Path` without its final component, if there is one. - /// - /// Returns [`None`] if the path terminates in a root or prefix. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("/foo/bar"); - /// let parent = path.parent().unwrap(); - /// assert_eq!(parent, Path::new("/foo")); - /// - /// let grand_parent = parent.parent().unwrap(); - /// assert_eq!(grand_parent, Path::new("/")); - /// assert_eq!(grand_parent.parent(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn parent(&self) -> Option<&Path> { - let mut comps = self.components(); - let comp = comps.next_back(); - comp.and_then(|p| { - match p { - Component::Normal(_) | - Component::CurDir | - Component::ParentDir => Some(comps.as_path()), - _ => None, - } - }) - } - - /// Produces an iterator over `Path` and its ancestors. - /// - /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero - /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`, - /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns - /// [`None`], the iterator will do likewise. The iterator will always yield at least one value, - /// namely `&self`. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let mut ancestors = Path::new("/foo/bar").ancestors(); - /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar"))); - /// assert_eq!(ancestors.next(), Some(Path::new("/foo"))); - /// assert_eq!(ancestors.next(), Some(Path::new("/"))); - /// assert_eq!(ancestors.next(), None); - /// ``` - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`parent`]: struct.Path.html#method.parent - #[stable(feature = "path_ancestors", since = "1.28.0")] - pub fn ancestors(&self) -> Ancestors { - Ancestors { - next: Some(&self), - } - } - - /// Returns the final component of the `Path`, if there is one. - /// - /// If the path is a normal file, this is the file name. If it's the path of a directory, this - /// is the directory name. - /// - /// Returns [`None`] if the path terminates in `..`. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// use std::ffi::OsStr; - /// - /// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name()); - /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name()); - /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name()); - /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name()); - /// assert_eq!(None, Path::new("foo.txt/..").file_name()); - /// assert_eq!(None, Path::new("/").file_name()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn file_name(&self) -> Option<&OsStr> { - self.components().next_back().and_then(|p| { - match p { - Component::Normal(p) => Some(p.as_ref()), - _ => None, - } - }) - } - - /// Returns a path that, when joined onto `base`, yields `self`. - /// - /// # Errors - /// - /// If `base` is not a prefix of `self` (i.e. [`starts_with`] - /// returns `false`), returns [`Err`]. - /// - /// [`starts_with`]: #method.starts_with - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let path = Path::new("/test/haha/foo.txt"); - /// - /// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt"))); - /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt"))); - /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt"))); - /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new(""))); - /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); - /// assert_eq!(path.strip_prefix("test").is_ok(), false); - /// assert_eq!(path.strip_prefix("/haha").is_ok(), false); - /// - /// let prefix = PathBuf::from("/test/"); - /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt"))); - /// ``` - #[stable(since = "1.7.0", feature = "path_strip_prefix")] - pub fn strip_prefix

(&self, base: P) - -> Result<&Path, StripPrefixError> - where P: AsRef - { - self._strip_prefix(base.as_ref()) - } - - fn _strip_prefix(&self, base: &Path) - -> Result<&Path, StripPrefixError> { - iter_after(self.components(), base.components()) - .map(|c| c.as_path()) - .ok_or(StripPrefixError(())) - } - - /// Determines whether `base` is a prefix of `self`. - /// - /// Only considers whole path components to match. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("/etc/passwd"); - /// - /// assert!(path.starts_with("/etc")); - /// assert!(path.starts_with("/etc/")); - /// assert!(path.starts_with("/etc/passwd")); - /// assert!(path.starts_with("/etc/passwd/")); - /// - /// assert!(!path.starts_with("/e")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn starts_with>(&self, base: P) -> bool { - self._starts_with(base.as_ref()) - } - - fn _starts_with(&self, base: &Path) -> bool { - iter_after(self.components(), base.components()).is_some() - } - - /// Determines whether `child` is a suffix of `self`. - /// - /// Only considers whole path components to match. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("/etc/passwd"); - /// - /// assert!(path.ends_with("passwd")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn ends_with>(&self, child: P) -> bool { - self._ends_with(child.as_ref()) - } - - fn _ends_with(&self, child: &Path) -> bool { - iter_after(self.components().rev(), child.components().rev()).is_some() - } - - /// Extracts the stem (non-extension) portion of [`self.file_name`]. - /// - /// [`self.file_name`]: struct.Path.html#method.file_name - /// - /// The stem is: - /// - /// * [`None`], if there is no file name; - /// * The entire file name if there is no embedded `.`; - /// * The entire file name if the file name begins with `.` and has no other `.`s within; - /// * Otherwise, the portion of the file name before the final `.` - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("foo.rs"); - /// - /// assert_eq!("foo", path.file_stem().unwrap()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn file_stem(&self) -> Option<&OsStr> { - self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after)) - } - - /// Extracts the extension of [`self.file_name`], if possible. - /// - /// The extension is: - /// - /// * [`None`], if there is no file name; - /// * [`None`], if there is no embedded `.`; - /// * [`None`], if the file name begins with `.` and has no other `.`s within; - /// * Otherwise, the portion of the file name after the final `.` - /// - /// [`self.file_name`]: struct.Path.html#method.file_name - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("foo.rs"); - /// - /// assert_eq!("rs", path.extension().unwrap()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn extension(&self) -> Option<&OsStr> { - self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after)) - } - - /// Creates an owned [`PathBuf`] with `path` adjoined to `self`. - /// - /// See [`PathBuf::push`] for more details on what it means to adjoin a path. - /// - /// [`PathBuf`]: struct.PathBuf.html - /// [`PathBuf::push`]: struct.PathBuf.html#method.push - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn join>(&self, path: P) -> PathBuf { - self._join(path.as_ref()) - } - - fn _join(&self, path: &Path) -> PathBuf { - let mut buf = self.to_path_buf(); - buf.push(path); - buf - } - - /// Creates an owned [`PathBuf`] like `self` but with the given file name. - /// - /// See [`PathBuf::set_file_name`] for more details. - /// - /// [`PathBuf`]: struct.PathBuf.html - /// [`PathBuf::set_file_name`]: struct.PathBuf.html#method.set_file_name - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let path = Path::new("/tmp/foo.txt"); - /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt")); - /// - /// let path = Path::new("/tmp"); - /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_file_name>(&self, file_name: S) -> PathBuf { - self._with_file_name(file_name.as_ref()) - } - - fn _with_file_name(&self, file_name: &OsStr) -> PathBuf { - let mut buf = self.to_path_buf(); - buf.set_file_name(file_name); - buf - } - - /// Creates an owned [`PathBuf`] like `self` but with the given extension. - /// - /// See [`PathBuf::set_extension`] for more details. - /// - /// [`PathBuf`]: struct.PathBuf.html - /// [`PathBuf::set_extension`]: struct.PathBuf.html#method.set_extension - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let path = Path::new("foo.rs"); - /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_extension>(&self, extension: S) -> PathBuf { - self._with_extension(extension.as_ref()) - } - - fn _with_extension(&self, extension: &OsStr) -> PathBuf { - let mut buf = self.to_path_buf(); - buf.set_extension(extension); - buf - } - - /// Produces an iterator over the [`Component`]s of the path. - /// - /// When parsing the path, there is a small amount of normalization: - /// - /// * Repeated separators are ignored, so `a/b` and `a//b` both have - /// `a` and `b` as components. - /// - /// * Occurrences of `.` are normalized away, except if they are at the - /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and - /// `a/b` all have `a` and `b` as components, but `./a/b` starts with - /// an additional [`CurDir`] component. - /// - /// Note that no other normalization takes place; in particular, `a/c` - /// and `a/b/../c` are distinct, to account for the possibility that `b` - /// is a symbolic link (so its parent isn't `a`). - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, Component}; - /// use std::ffi::OsStr; - /// - /// let mut components = Path::new("/tmp/foo.txt").components(); - /// - /// assert_eq!(components.next(), Some(Component::RootDir)); - /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("tmp")))); - /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt")))); - /// assert_eq!(components.next(), None) - /// ``` - /// - /// [`Component`]: enum.Component.html - /// [`CurDir`]: enum.Component.html#variant.CurDir - #[stable(feature = "rust1", since = "1.0.0")] - pub fn components(&self) -> Components { - let prefix = parse_prefix(self.as_os_str()); - Components { - path: self.as_u8_slice(), - prefix, - has_physical_root: has_physical_root(self.as_u8_slice(), prefix) || - has_redox_scheme(self.as_u8_slice()), - front: State::Prefix, - back: State::Body, - } - } - - /// Produces an iterator over the path's components viewed as [`OsStr`] - /// slices. - /// - /// For more information about the particulars of how the path is separated - /// into components, see [`components`]. - /// - /// [`components`]: #method.components - /// [`OsStr`]: ../ffi/struct.OsStr.html - /// - /// # Examples - /// - /// ``` - /// use std::path::{self, Path}; - /// use std::ffi::OsStr; - /// - /// let mut it = Path::new("/tmp/foo.txt").iter(); - /// assert_eq!(it.next(), Some(OsStr::new(&path::MAIN_SEPARATOR.to_string()))); - /// assert_eq!(it.next(), Some(OsStr::new("tmp"))); - /// assert_eq!(it.next(), Some(OsStr::new("foo.txt"))); - /// assert_eq!(it.next(), None) - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { - Iter { inner: self.components() } - } - - /// Returns an object that implements [`Display`] for safely printing paths - /// that may contain non-Unicode data. - /// - /// [`Display`]: ../fmt/trait.Display.html - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("/tmp/foo.rs"); - /// - /// println!("{}", path.display()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn display(&self) -> Display { - Display { path: self } - } - - /// Queries the file system to get information about a file, directory, etc. - /// - /// This function will traverse symbolic links to query information about the - /// destination file. - /// - /// This is an alias to [`fs::metadata`]. - /// - /// [`fs::metadata`]: ../fs/fn.metadata.html - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// - /// let path = Path::new("/Minas/tirith"); - /// let metadata = path.metadata().expect("metadata call failed"); - /// println!("{:?}", metadata.file_type()); - /// ``` - #[stable(feature = "path_ext", since = "1.5.0")] - pub fn metadata(&self) -> io::Result { - fs::metadata(self) - } - - /// Queries the metadata about a file without following symlinks. - /// - /// This is an alias to [`fs::symlink_metadata`]. - /// - /// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// - /// let path = Path::new("/Minas/tirith"); - /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed"); - /// println!("{:?}", metadata.file_type()); - /// ``` - #[stable(feature = "path_ext", since = "1.5.0")] - pub fn symlink_metadata(&self) -> io::Result { - fs::symlink_metadata(self) - } - - /// Returns the canonical, absolute form of the path with all intermediate - /// components normalized and symbolic links resolved. - /// - /// This is an alias to [`fs::canonicalize`]. - /// - /// [`fs::canonicalize`]: ../fs/fn.canonicalize.html - /// - /// # Examples - /// - /// ```no_run - /// use std::path::{Path, PathBuf}; - /// - /// let path = Path::new("/foo/test/../test/bar.rs"); - /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs")); - /// ``` - #[stable(feature = "path_ext", since = "1.5.0")] - pub fn canonicalize(&self) -> io::Result { - fs::canonicalize(self) - } - - /// Reads a symbolic link, returning the file that the link points to. - /// - /// This is an alias to [`fs::read_link`]. - /// - /// [`fs::read_link`]: ../fs/fn.read_link.html - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// - /// let path = Path::new("/laputa/sky_castle.rs"); - /// let path_link = path.read_link().expect("read_link call failed"); - /// ``` - #[stable(feature = "path_ext", since = "1.5.0")] - pub fn read_link(&self) -> io::Result { - fs::read_link(self) - } - - /// Returns an iterator over the entries within a directory. - /// - /// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. New - /// errors may be encountered after an iterator is initially constructed. - /// - /// This is an alias to [`fs::read_dir`]. - /// - /// [`io::Result`]: ../io/type.Result.html - /// [`DirEntry`]: ../fs/struct.DirEntry.html - /// [`fs::read_dir`]: ../fs/fn.read_dir.html - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// - /// let path = Path::new("/laputa"); - /// for entry in path.read_dir().expect("read_dir call failed") { - /// if let Ok(entry) = entry { - /// println!("{:?}", entry.path()); - /// } - /// } - /// ``` - #[stable(feature = "path_ext", since = "1.5.0")] - pub fn read_dir(&self) -> io::Result { - fs::read_dir(self) - } - - /// Returns whether the path points at an existing entity. - /// - /// This function will traverse symbolic links to query information about the - /// destination file. In case of broken symbolic links this will return `false`. - /// - /// If you cannot access the directory containing the file, e.g. because of a - /// permission error, this will return `false`. - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// assert_eq!(Path::new("does_not_exist.txt").exists(), false); - /// ``` - /// - /// # See Also - /// - /// This is a convenience function that coerces errors to false. If you want to - /// check errors, call [fs::metadata]. - /// - /// [fs::metadata]: ../../std/fs/fn.metadata.html - #[stable(feature = "path_ext", since = "1.5.0")] - pub fn exists(&self) -> bool { - fs::metadata(self).is_ok() - } - - /// Returns whether the path exists on disk and is pointing at a regular file. - /// - /// This function will traverse symbolic links to query information about the - /// destination file. In case of broken symbolic links this will return `false`. - /// - /// If you cannot access the directory containing the file, e.g. because of a - /// permission error, this will return `false`. - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// assert_eq!(Path::new("./is_a_directory/").is_file(), false); - /// assert_eq!(Path::new("a_file.txt").is_file(), true); - /// ``` - /// - /// # See Also - /// - /// This is a convenience function that coerces errors to false. If you want to - /// check errors, call [fs::metadata] and handle its Result. Then call - /// [fs::Metadata::is_file] if it was Ok. - /// - /// [fs::metadata]: ../../std/fs/fn.metadata.html - /// [fs::Metadata::is_file]: ../../std/fs/struct.Metadata.html#method.is_file - #[stable(feature = "path_ext", since = "1.5.0")] - pub fn is_file(&self) -> bool { - fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) - } - - /// Returns whether the path exists on disk and is pointing at a directory. - /// - /// This function will traverse symbolic links to query information about the - /// destination file. In case of broken symbolic links this will return `false`. - /// - /// If you cannot access the directory containing the file, e.g. because of a - /// permission error, this will return `false`. - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// assert_eq!(Path::new("./is_a_directory/").is_dir(), true); - /// assert_eq!(Path::new("a_file.txt").is_dir(), false); - /// ``` - /// - /// # See Also - /// - /// This is a convenience function that coerces errors to false. If you want to - /// check errors, call [fs::metadata] and handle its Result. Then call - /// [fs::Metadata::is_dir] if it was Ok. - /// - /// [fs::metadata]: ../../std/fs/fn.metadata.html - /// [fs::Metadata::is_dir]: ../../std/fs/struct.Metadata.html#method.is_dir - #[stable(feature = "path_ext", since = "1.5.0")] - pub fn is_dir(&self) -> bool { - fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) - } - - /// Converts a [`Box`][`Box`] into a [`PathBuf`] without copying or - /// allocating. - /// - /// [`Box`]: ../../std/boxed/struct.Box.html - /// [`PathBuf`]: struct.PathBuf.html - #[stable(feature = "into_boxed_path", since = "1.20.0")] - pub fn into_path_buf(self: Box) -> PathBuf { - let rw = Box::into_raw(self) as *mut OsStr; - let inner = unsafe { Box::from_raw(rw) }; - PathBuf { inner: OsString::from(inner) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for Path { - fn as_ref(&self) -> &OsStr { - &self.inner - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Path { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.inner, formatter) - } -} - -/// Helper struct for safely printing paths with [`format!`] and `{}`. -/// -/// A [`Path`] might contain non-Unicode data. This `struct` implements the -/// [`Display`] trait in a way that mitigates that. It is created by the -/// [`display`][`Path::display`] method on [`Path`]. -/// -/// # Examples -/// -/// ``` -/// use std::path::Path; -/// -/// let path = Path::new("/tmp/foo.rs"); -/// -/// println!("{}", path.display()); -/// ``` -/// -/// [`Display`]: ../../std/fmt/trait.Display.html -/// [`format!`]: ../../std/macro.format.html -/// [`Path`]: struct.Path.html -/// [`Path::display`]: struct.Path.html#method.display -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Display<'a> { - path: &'a Path, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> fmt::Debug for Display<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.path, f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> fmt::Display for Display<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.path.inner.display(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl cmp::PartialEq for Path { - fn eq(&self, other: &Path) -> bool { - self.components().eq(other.components()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Path { - fn hash(&self, h: &mut H) { - for component in self.components() { - component.hash(h); - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl cmp::Eq for Path {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl cmp::PartialOrd for Path { - fn partial_cmp(&self, other: &Path) -> Option { - self.components().partial_cmp(other.components()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl cmp::Ord for Path { - fn cmp(&self, other: &Path) -> cmp::Ordering { - self.components().cmp(other.components()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for Path { - fn as_ref(&self) -> &Path { - self - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for OsStr { - fn as_ref(&self) -> &Path { - Path::new(self) - } -} - -#[stable(feature = "cow_os_str_as_ref_path", since = "1.8.0")] -impl<'a> AsRef for Cow<'a, OsStr> { - fn as_ref(&self) -> &Path { - Path::new(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for OsString { - fn as_ref(&self) -> &Path { - Path::new(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for str { - fn as_ref(&self) -> &Path { - Path::new(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for String { - fn as_ref(&self) -> &Path { - Path::new(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for PathBuf { - fn as_ref(&self) -> &Path { - self - } -} - -#[stable(feature = "path_into_iter", since = "1.6.0")] -impl<'a> IntoIterator for &'a PathBuf { - type Item = &'a OsStr; - type IntoIter = Iter<'a>; - fn into_iter(self) -> Iter<'a> { self.iter() } -} - -#[stable(feature = "path_into_iter", since = "1.6.0")] -impl<'a> IntoIterator for &'a Path { - type Item = &'a OsStr; - type IntoIter = Iter<'a>; - fn into_iter(self) -> Iter<'a> { self.iter() } -} - -macro_rules! impl_cmp { - ($lhs:ty, $rhs: ty) => { - #[stable(feature = "partialeq_path", since = "1.6.0")] - impl<'a, 'b> PartialEq<$rhs> for $lhs { - #[inline] - fn eq(&self, other: &$rhs) -> bool { ::eq(self, other) } - } - - #[stable(feature = "partialeq_path", since = "1.6.0")] - impl<'a, 'b> PartialEq<$lhs> for $rhs { - #[inline] - fn eq(&self, other: &$lhs) -> bool { ::eq(self, other) } - } - - #[stable(feature = "cmp_path", since = "1.8.0")] - impl<'a, 'b> PartialOrd<$rhs> for $lhs { - #[inline] - fn partial_cmp(&self, other: &$rhs) -> Option { - ::partial_cmp(self, other) - } - } - - #[stable(feature = "cmp_path", since = "1.8.0")] - impl<'a, 'b> PartialOrd<$lhs> for $rhs { - #[inline] - fn partial_cmp(&self, other: &$lhs) -> Option { - ::partial_cmp(self, other) - } - } - } -} - -impl_cmp!(PathBuf, Path); -impl_cmp!(PathBuf, &'a Path); -impl_cmp!(Cow<'a, Path>, Path); -impl_cmp!(Cow<'a, Path>, &'b Path); -impl_cmp!(Cow<'a, Path>, PathBuf); - -macro_rules! impl_cmp_os_str { - ($lhs:ty, $rhs: ty) => { - #[stable(feature = "cmp_path", since = "1.8.0")] - impl<'a, 'b> PartialEq<$rhs> for $lhs { - #[inline] - fn eq(&self, other: &$rhs) -> bool { ::eq(self, other.as_ref()) } - } - - #[stable(feature = "cmp_path", since = "1.8.0")] - impl<'a, 'b> PartialEq<$lhs> for $rhs { - #[inline] - fn eq(&self, other: &$lhs) -> bool { ::eq(self.as_ref(), other) } - } - - #[stable(feature = "cmp_path", since = "1.8.0")] - impl<'a, 'b> PartialOrd<$rhs> for $lhs { - #[inline] - fn partial_cmp(&self, other: &$rhs) -> Option { - ::partial_cmp(self, other.as_ref()) - } - } - - #[stable(feature = "cmp_path", since = "1.8.0")] - impl<'a, 'b> PartialOrd<$lhs> for $rhs { - #[inline] - fn partial_cmp(&self, other: &$lhs) -> Option { - ::partial_cmp(self.as_ref(), other) - } - } - } -} - -impl_cmp_os_str!(PathBuf, OsStr); -impl_cmp_os_str!(PathBuf, &'a OsStr); -impl_cmp_os_str!(PathBuf, Cow<'a, OsStr>); -impl_cmp_os_str!(PathBuf, OsString); -impl_cmp_os_str!(Path, OsStr); -impl_cmp_os_str!(Path, &'a OsStr); -impl_cmp_os_str!(Path, Cow<'a, OsStr>); -impl_cmp_os_str!(Path, OsString); -impl_cmp_os_str!(&'a Path, OsStr); -impl_cmp_os_str!(&'a Path, Cow<'b, OsStr>); -impl_cmp_os_str!(&'a Path, OsString); -impl_cmp_os_str!(Cow<'a, Path>, OsStr); -impl_cmp_os_str!(Cow<'a, Path>, &'b OsStr); -impl_cmp_os_str!(Cow<'a, Path>, OsString); - -#[stable(since = "1.7.0", feature = "strip_prefix")] -impl fmt::Display for StripPrefixError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) - } -} - -#[stable(since = "1.7.0", feature = "strip_prefix")] -impl Error for StripPrefixError { - fn description(&self) -> &str { "prefix not found" } -} - -#[cfg(test)] -mod tests { - use super::*; - - use rc::Rc; - use sync::Arc; - - macro_rules! t( - ($path:expr, iter: $iter:expr) => ( - { - let path = Path::new($path); - - // Forward iteration - let comps = path.iter() - .map(|p| p.to_string_lossy().into_owned()) - .collect::>(); - let exp: &[&str] = &$iter; - let exps = exp.iter().map(|s| s.to_string()).collect::>(); - assert!(comps == exps, "iter: Expected {:?}, found {:?}", - exps, comps); - - // Reverse iteration - let comps = Path::new($path).iter().rev() - .map(|p| p.to_string_lossy().into_owned()) - .collect::>(); - let exps = exps.into_iter().rev().collect::>(); - assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}", - exps, comps); - } - ); - - ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => ( - { - let path = Path::new($path); - - let act_root = path.has_root(); - assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}", - $has_root, act_root); - - let act_abs = path.is_absolute(); - assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}", - $is_absolute, act_abs); - } - ); - - ($path:expr, parent: $parent:expr, file_name: $file:expr) => ( - { - let path = Path::new($path); - - let parent = path.parent().map(|p| p.to_str().unwrap()); - let exp_parent: Option<&str> = $parent; - assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}", - exp_parent, parent); - - let file = path.file_name().map(|p| p.to_str().unwrap()); - let exp_file: Option<&str> = $file; - assert!(file == exp_file, "file_name: Expected {:?}, found {:?}", - exp_file, file); - } - ); - - ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => ( - { - let path = Path::new($path); - - let stem = path.file_stem().map(|p| p.to_str().unwrap()); - let exp_stem: Option<&str> = $file_stem; - assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}", - exp_stem, stem); - - let ext = path.extension().map(|p| p.to_str().unwrap()); - let exp_ext: Option<&str> = $extension; - assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}", - exp_ext, ext); - } - ); - - ($path:expr, iter: $iter:expr, - has_root: $has_root:expr, is_absolute: $is_absolute:expr, - parent: $parent:expr, file_name: $file:expr, - file_stem: $file_stem:expr, extension: $extension:expr) => ( - { - t!($path, iter: $iter); - t!($path, has_root: $has_root, is_absolute: $is_absolute); - t!($path, parent: $parent, file_name: $file); - t!($path, file_stem: $file_stem, extension: $extension); - } - ); - ); - - #[test] - fn into() { - use borrow::Cow; - - let static_path = Path::new("/home/foo"); - let static_cow_path: Cow<'static, Path> = static_path.into(); - let pathbuf = PathBuf::from("/home/foo"); - - { - let path: &Path = &pathbuf; - let borrowed_cow_path: Cow = path.into(); - - assert_eq!(static_cow_path, borrowed_cow_path); - } - - let owned_cow_path: Cow<'static, Path> = pathbuf.into(); - - assert_eq!(static_cow_path, owned_cow_path); - } - - #[test] - #[cfg(unix)] - pub fn test_decompositions_unix() { - t!("", - iter: [], - has_root: false, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/", - iter: ["/"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("/foo", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/foo/", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("/foo/bar", - iter: ["/", "foo", "bar"], - has_root: true, - is_absolute: true, - parent: Some("/foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("///foo///", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("///foo///bar", - iter: ["/", "foo", "bar"], - has_root: true, - is_absolute: true, - parent: Some("///foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./.", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("/..", - iter: ["/", ".."], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("../", - iter: [".."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/.", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/..", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/./", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/./bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("foo/../", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/../bar", - iter: ["foo", "..", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo/.."), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./a", - iter: [".", "a"], - has_root: false, - is_absolute: false, - parent: Some("."), - file_name: Some("a"), - file_stem: Some("a"), - extension: None - ); - - t!(".", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("./", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("a/b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a//b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/./b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/b/c", - iter: ["a", "b", "c"], - has_root: false, - is_absolute: false, - parent: Some("a/b"), - file_name: Some("c"), - file_stem: Some("c"), - extension: None - ); - - t!(".foo", - iter: [".foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some(".foo"), - file_stem: Some(".foo"), - extension: None - ); - } - - #[test] - #[cfg(windows)] - pub fn test_decompositions_windows() { - t!("", - iter: [], - has_root: false, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/", - iter: ["\\"], - has_root: true, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\", - iter: ["\\"], - has_root: true, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("c:", - iter: ["c:"], - has_root: false, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("c:\\", - iter: ["c:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("c:/", - iter: ["c:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("/foo", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/foo/", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("/foo/bar", - iter: ["\\", "foo", "bar"], - has_root: true, - is_absolute: false, - parent: Some("/foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("///foo///", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("///foo///bar", - iter: ["\\", "foo", "bar"], - has_root: true, - is_absolute: false, - parent: Some("///foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./.", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("/..", - iter: ["\\", ".."], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("../", - iter: [".."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/.", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/..", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/./", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/./bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("foo/../", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/../bar", - iter: ["foo", "..", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo/.."), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./a", - iter: [".", "a"], - has_root: false, - is_absolute: false, - parent: Some("."), - file_name: Some("a"), - file_stem: Some("a"), - extension: None - ); - - t!(".", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("./", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("a/b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a//b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/./b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/b/c", - iter: ["a", "b", "c"], - has_root: false, - is_absolute: false, - parent: Some("a/b"), - file_name: Some("c"), - file_stem: Some("c"), - extension: None); - - t!("a\\b\\c", - iter: ["a", "b", "c"], - has_root: false, - is_absolute: false, - parent: Some("a\\b"), - file_name: Some("c"), - file_stem: Some("c"), - extension: None - ); - - t!("\\a", - iter: ["\\", "a"], - has_root: true, - is_absolute: false, - parent: Some("\\"), - file_name: Some("a"), - file_stem: Some("a"), - extension: None - ); - - t!("c:\\foo.txt", - iter: ["c:", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("c:\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\server\\share\\foo.txt", - iter: ["\\\\server\\share", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\server\\share\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\server\\share", - iter: ["\\\\server\\share", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\server", - iter: ["\\", "server"], - has_root: true, - is_absolute: false, - parent: Some("\\"), - file_name: Some("server"), - file_stem: Some("server"), - extension: None - ); - - t!("\\\\?\\bar\\foo.txt", - iter: ["\\\\?\\bar", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\bar\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\?\\bar", - iter: ["\\\\?\\bar"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\", - iter: ["\\\\?\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\UNC\\server\\share\\foo.txt", - iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\UNC\\server\\share\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\?\\UNC\\server", - iter: ["\\\\?\\UNC\\server"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\UNC\\", - iter: ["\\\\?\\UNC\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\C:\\foo.txt", - iter: ["\\\\?\\C:", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\C:\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - - t!("\\\\?\\C:\\", - iter: ["\\\\?\\C:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - - t!("\\\\?\\C:", - iter: ["\\\\?\\C:"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - - t!("\\\\?\\foo/bar", - iter: ["\\\\?\\foo/bar"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - - t!("\\\\?\\C:/foo", - iter: ["\\\\?\\C:/foo"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - - t!("\\\\.\\foo\\bar", - iter: ["\\\\.\\foo", "\\", "bar"], - has_root: true, - is_absolute: true, - parent: Some("\\\\.\\foo\\"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - - t!("\\\\.\\foo", - iter: ["\\\\.\\foo", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - - t!("\\\\.\\foo/bar", - iter: ["\\\\.\\foo/bar", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - - t!("\\\\.\\foo\\bar/baz", - iter: ["\\\\.\\foo", "\\", "bar", "baz"], - has_root: true, - is_absolute: true, - parent: Some("\\\\.\\foo\\bar"), - file_name: Some("baz"), - file_stem: Some("baz"), - extension: None - ); - - - t!("\\\\.\\", - iter: ["\\\\.\\", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\a\\b\\", - iter: ["\\\\?\\a", "\\", "b"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\a\\"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - } - - #[test] - pub fn test_stem_ext() { - t!("foo", - file_stem: Some("foo"), - extension: None - ); - - t!("foo.", - file_stem: Some("foo"), - extension: Some("") - ); - - t!(".foo", - file_stem: Some(".foo"), - extension: None - ); - - t!("foo.txt", - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("foo.bar.txt", - file_stem: Some("foo.bar"), - extension: Some("txt") - ); - - t!("foo.bar.", - file_stem: Some("foo.bar"), - extension: Some("") - ); - - t!(".", - file_stem: None, - extension: None - ); - - t!("..", - file_stem: None, - extension: None - ); - - t!("", - file_stem: None, - extension: None - ); - } - - #[test] - pub fn test_push() { - macro_rules! tp( - ($path:expr, $push:expr, $expected:expr) => ( { - let mut actual = PathBuf::from($path); - actual.push($push); - assert!(actual.to_str() == Some($expected), - "pushing {:?} onto {:?}: Expected {:?}, got {:?}", - $push, $path, $expected, actual.to_str().unwrap()); - }); - ); - - if cfg!(unix) { - tp!("", "foo", "foo"); - tp!("foo", "bar", "foo/bar"); - tp!("foo/", "bar", "foo/bar"); - tp!("foo//", "bar", "foo//bar"); - tp!("foo/.", "bar", "foo/./bar"); - tp!("foo./.", "bar", "foo././bar"); - tp!("foo", "", "foo/"); - tp!("foo", ".", "foo/."); - tp!("foo", "..", "foo/.."); - tp!("foo", "/", "/"); - tp!("/foo/bar", "/", "/"); - tp!("/foo/bar", "/baz", "/baz"); - tp!("/foo/bar", "./baz", "/foo/bar/./baz"); - } else { - tp!("", "foo", "foo"); - tp!("foo", "bar", r"foo\bar"); - tp!("foo/", "bar", r"foo/bar"); - tp!(r"foo\", "bar", r"foo\bar"); - tp!("foo//", "bar", r"foo//bar"); - tp!(r"foo\\", "bar", r"foo\\bar"); - tp!("foo/.", "bar", r"foo/.\bar"); - tp!("foo./.", "bar", r"foo./.\bar"); - tp!(r"foo\.", "bar", r"foo\.\bar"); - tp!(r"foo.\.", "bar", r"foo.\.\bar"); - tp!("foo", "", "foo\\"); - tp!("foo", ".", r"foo\."); - tp!("foo", "..", r"foo\.."); - tp!("foo", "/", "/"); - tp!("foo", r"\", r"\"); - tp!("/foo/bar", "/", "/"); - tp!(r"\foo\bar", r"\", r"\"); - tp!("/foo/bar", "/baz", "/baz"); - tp!("/foo/bar", r"\baz", r"\baz"); - tp!("/foo/bar", "./baz", r"/foo/bar\./baz"); - tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz"); - - tp!("c:\\", "windows", "c:\\windows"); - tp!("c:", "windows", "c:windows"); - - tp!("a\\b\\c", "d", "a\\b\\c\\d"); - tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d"); - tp!("a\\b", "c\\d", "a\\b\\c\\d"); - tp!("a\\b", "\\c\\d", "\\c\\d"); - tp!("a\\b", ".", "a\\b\\."); - tp!("a\\b", "..\\c", "a\\b\\..\\c"); - tp!("a\\b", "C:a.txt", "C:a.txt"); - tp!("a\\b", "C:\\a.txt", "C:\\a.txt"); - tp!("C:\\a", "C:\\b.txt", "C:\\b.txt"); - tp!("C:\\a\\b\\c", "C:d", "C:d"); - tp!("C:a\\b\\c", "C:d", "C:d"); - tp!("C:", r"a\b\c", r"C:a\b\c"); - tp!("C:", r"..\a", r"C:..\a"); - tp!("\\\\server\\share\\foo", - "bar", - "\\\\server\\share\\foo\\bar"); - tp!("\\\\server\\share\\foo", "C:baz", "C:baz"); - tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d"); - tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d"); - tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d"); - tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz"); - tp!("\\\\?\\UNC\\server\\share\\foo", - "bar", - "\\\\?\\UNC\\server\\share\\foo\\bar"); - tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a"); - tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a"); - - // Note: modified from old path API - tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo"); - - tp!("C:\\a", - "\\\\?\\UNC\\server\\share", - "\\\\?\\UNC\\server\\share"); - tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz"); - tp!("\\\\.\\foo\\bar", "C:a", "C:a"); - // again, not sure about the following, but I'm assuming \\.\ should be verbatim - tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar"); - - tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one - } - } - - #[test] - pub fn test_pop() { - macro_rules! tp( - ($path:expr, $expected:expr, $output:expr) => ( { - let mut actual = PathBuf::from($path); - let output = actual.pop(); - assert!(actual.to_str() == Some($expected) && output == $output, - "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}", - $path, $expected, $output, - actual.to_str().unwrap(), output); - }); - ); - - tp!("", "", false); - tp!("/", "/", false); - tp!("foo", "", true); - tp!(".", "", true); - tp!("/foo", "/", true); - tp!("/foo/bar", "/foo", true); - tp!("foo/bar", "foo", true); - tp!("foo/.", "", true); - tp!("foo//bar", "foo", true); - - if cfg!(windows) { - tp!("a\\b\\c", "a\\b", true); - tp!("\\a", "\\", true); - tp!("\\", "\\", false); - - tp!("C:\\a\\b", "C:\\a", true); - tp!("C:\\a", "C:\\", true); - tp!("C:\\", "C:\\", false); - tp!("C:a\\b", "C:a", true); - tp!("C:a", "C:", true); - tp!("C:", "C:", false); - tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true); - tp!("\\\\server\\share\\a", "\\\\server\\share\\", true); - tp!("\\\\server\\share", "\\\\server\\share", false); - tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true); - tp!("\\\\?\\a\\b", "\\\\?\\a\\", true); - tp!("\\\\?\\a", "\\\\?\\a", false); - tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true); - tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true); - tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false); - tp!("\\\\?\\UNC\\server\\share\\a\\b", - "\\\\?\\UNC\\server\\share\\a", - true); - tp!("\\\\?\\UNC\\server\\share\\a", - "\\\\?\\UNC\\server\\share\\", - true); - tp!("\\\\?\\UNC\\server\\share", - "\\\\?\\UNC\\server\\share", - false); - tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true); - tp!("\\\\.\\a\\b", "\\\\.\\a\\", true); - tp!("\\\\.\\a", "\\\\.\\a", false); - - tp!("\\\\?\\a\\b\\", "\\\\?\\a\\", true); - } - } - - #[test] - pub fn test_set_file_name() { - macro_rules! tfn( - ($path:expr, $file:expr, $expected:expr) => ( { - let mut p = PathBuf::from($path); - p.set_file_name($file); - assert!(p.to_str() == Some($expected), - "setting file name of {:?} to {:?}: Expected {:?}, got {:?}", - $path, $file, $expected, - p.to_str().unwrap()); - }); - ); - - tfn!("foo", "foo", "foo"); - tfn!("foo", "bar", "bar"); - tfn!("foo", "", ""); - tfn!("", "foo", "foo"); - if cfg!(unix) { - tfn!(".", "foo", "./foo"); - tfn!("foo/", "bar", "bar"); - tfn!("foo/.", "bar", "bar"); - tfn!("..", "foo", "../foo"); - tfn!("foo/..", "bar", "foo/../bar"); - tfn!("/", "foo", "/foo"); - } else { - tfn!(".", "foo", r".\foo"); - tfn!(r"foo\", "bar", r"bar"); - tfn!(r"foo\.", "bar", r"bar"); - tfn!("..", "foo", r"..\foo"); - tfn!(r"foo\..", "bar", r"foo\..\bar"); - tfn!(r"\", "foo", r"\foo"); - } - } - - #[test] - pub fn test_set_extension() { - macro_rules! tfe( - ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( { - let mut p = PathBuf::from($path); - let output = p.set_extension($ext); - assert!(p.to_str() == Some($expected) && output == $output, - "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}", - $path, $ext, $expected, $output, - p.to_str().unwrap(), output); - }); - ); - - tfe!("foo", "txt", "foo.txt", true); - tfe!("foo.bar", "txt", "foo.txt", true); - tfe!("foo.bar.baz", "txt", "foo.bar.txt", true); - tfe!(".test", "txt", ".test.txt", true); - tfe!("foo.txt", "", "foo", true); - tfe!("foo", "", "foo", true); - tfe!("", "foo", "", false); - tfe!(".", "foo", ".", false); - tfe!("foo/", "bar", "foo.bar", true); - tfe!("foo/.", "bar", "foo.bar", true); - tfe!("..", "foo", "..", false); - tfe!("foo/..", "bar", "foo/..", false); - tfe!("/", "foo", "/", false); - } - - #[test] - fn test_eq_receivers() { - use borrow::Cow; - - let borrowed: &Path = Path::new("foo/bar"); - let mut owned: PathBuf = PathBuf::new(); - owned.push("foo"); - owned.push("bar"); - let borrowed_cow: Cow = borrowed.into(); - let owned_cow: Cow = owned.clone().into(); - - macro_rules! t { - ($($current:expr),+) => { - $( - assert_eq!($current, borrowed); - assert_eq!($current, owned); - assert_eq!($current, borrowed_cow); - assert_eq!($current, owned_cow); - )+ - } - } - - t!(borrowed, owned, borrowed_cow, owned_cow); - } - - #[test] - pub fn test_compare() { - use hash::{Hash, Hasher}; - use collections::hash_map::DefaultHasher; - - fn hash(t: T) -> u64 { - let mut s = DefaultHasher::new(); - t.hash(&mut s); - s.finish() - } - - macro_rules! tc( - ($path1:expr, $path2:expr, eq: $eq:expr, - starts_with: $starts_with:expr, ends_with: $ends_with:expr, - relative_from: $relative_from:expr) => ({ - let path1 = Path::new($path1); - let path2 = Path::new($path2); - - let eq = path1 == path2; - assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}", - $path1, $path2, $eq, eq); - assert!($eq == (hash(path1) == hash(path2)), - "{:?} == {:?}, expected {:?}, got {} and {}", - $path1, $path2, $eq, hash(path1), hash(path2)); - - let starts_with = path1.starts_with(path2); - assert!(starts_with == $starts_with, - "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2, - $starts_with, starts_with); - - let ends_with = path1.ends_with(path2); - assert!(ends_with == $ends_with, - "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2, - $ends_with, ends_with); - - let relative_from = path1.strip_prefix(path2) - .map(|p| p.to_str().unwrap()) - .ok(); - let exp: Option<&str> = $relative_from; - assert!(relative_from == exp, - "{:?}.strip_prefix({:?}), expected {:?}, got {:?}", - $path1, $path2, exp, relative_from); - }); - ); - - tc!("", "", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo", "", - eq: false, - starts_with: true, - ends_with: true, - relative_from: Some("foo") - ); - - tc!("", "foo", - eq: false, - starts_with: false, - ends_with: false, - relative_from: None - ); - - tc!("foo", "foo", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo/", "foo", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo/bar", "foo", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("bar") - ); - - tc!("foo/bar/baz", "foo/bar", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("baz") - ); - - tc!("foo/bar", "foo/bar/baz", - eq: false, - starts_with: false, - ends_with: false, - relative_from: None - ); - - tc!("./foo/bar/", ".", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("foo/bar") - ); - - if cfg!(windows) { - tc!(r"C:\src\rust\cargo-test\test\Cargo.toml", - r"c:\src\rust\cargo-test\test", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("Cargo.toml") - ); - - tc!(r"c:\foo", r"C:\foo", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - } - } - - #[test] - fn test_components_debug() { - let path = Path::new("/tmp"); - - let mut components = path.components(); - - let expected = "Components([RootDir, Normal(\"tmp\")])"; - let actual = format!("{:?}", components); - assert_eq!(expected, actual); - - let _ = components.next().unwrap(); - let expected = "Components([Normal(\"tmp\")])"; - let actual = format!("{:?}", components); - assert_eq!(expected, actual); - - let _ = components.next().unwrap(); - let expected = "Components([])"; - let actual = format!("{:?}", components); - assert_eq!(expected, actual); - } - - #[cfg(unix)] - #[test] - fn test_iter_debug() { - let path = Path::new("/tmp"); - - let mut iter = path.iter(); - - let expected = "Iter([\"/\", \"tmp\"])"; - let actual = format!("{:?}", iter); - assert_eq!(expected, actual); - - let _ = iter.next().unwrap(); - let expected = "Iter([\"tmp\"])"; - let actual = format!("{:?}", iter); - assert_eq!(expected, actual); - - let _ = iter.next().unwrap(); - let expected = "Iter([])"; - let actual = format!("{:?}", iter); - assert_eq!(expected, actual); - } - - #[test] - fn into_boxed() { - let orig: &str = "some/sort/of/path"; - let path = Path::new(orig); - let boxed: Box = Box::from(path); - let path_buf = path.to_owned().into_boxed_path().into_path_buf(); - assert_eq!(path, &*boxed); - assert_eq!(&*boxed, &*path_buf); - assert_eq!(&*path_buf, path); - } - - #[test] - fn test_clone_into() { - let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious"); - let path = Path::new("short"); - path.clone_into(&mut path_buf); - assert_eq!(path, path_buf); - assert!(path_buf.into_os_string().capacity() >= 15); - } - - #[test] - fn display_format_flags() { - assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b"); - assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b"); - } - - #[test] - fn into_rc() { - let orig = "hello/world"; - let path = Path::new(orig); - let rc: Rc = Rc::from(path); - let arc: Arc = Arc::from(path); - - assert_eq!(&*rc, path); - assert_eq!(&*arc, path); - - let rc2: Rc = Rc::from(path.to_owned()); - let arc2: Arc = Arc::from(path.to_owned()); - - assert_eq!(&*rc2, path); - assert_eq!(&*arc2, path); - } -} diff --git a/ctr-std/src/prelude/mod.rs b/ctr-std/src/prelude/mod.rs deleted file mode 100644 index 919e033..0000000 --- a/ctr-std/src/prelude/mod.rs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The Rust Prelude. -//! -//! Rust comes with a variety of things in its standard library. However, if -//! you had to manually import every single thing that you used, it would be -//! very verbose. But importing a lot of things that a program never uses isn't -//! good either. A balance needs to be struck. -//! -//! The *prelude* is the list of things that Rust automatically imports into -//! every Rust program. It's kept as small as possible, and is focused on -//! things, particularly traits, which are used in almost every single Rust -//! program. -//! -//! On a technical level, Rust inserts -//! -//! ``` -//! # #[allow(unused_extern_crates)] -//! extern crate std; -//! ``` -//! -//! into the crate root of every crate, and -//! -//! ``` -//! # #[allow(unused_imports)] -//! use std::prelude::v1::*; -//! ``` -//! -//! into every module. -//! -//! # Other preludes -//! -//! Preludes can be seen as a pattern to make using multiple types more -//! convenient. As such, you'll find other preludes in the standard library, -//! such as [`std::io::prelude`]. Various libraries in the Rust ecosystem may -//! also define their own preludes. -//! -//! [`std::io::prelude`]: ../io/prelude/index.html -//! -//! The difference between 'the prelude' and these other preludes is that they -//! are not automatically `use`'d, and must be imported manually. This is still -//! easier than importing all of their constituent components. -//! -//! # Prelude contents -//! -//! The current version of the prelude (version 1) lives in -//! [`std::prelude::v1`], and re-exports the following. -//! -//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`]}. The marker -//! traits indicate fundamental properties of types. -//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various -//! operations for both destructors and overloading `()`. -//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly -//! dropping a value. -//! * [`std::boxed`]::[`Box`], a way to allocate values on the heap. -//! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines -//! [`to_owned`], the generic method for creating an owned type from a -//! borrowed type. -//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines -//! [`clone`][`Clone::clone`], the method for producing a copy of a value. -//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The -//! comparison traits, which implement the comparison operators and are often -//! seen in trait bounds. -//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}. Generic -//! conversions, used by savvy API authors to create overloaded methods. -//! * [`std::default`]::[`Default`], types that have default values. -//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`], -//! [`DoubleEndedIterator`], [`ExactSizeIterator`]}. Iterators of various -//! kinds. -//! * [`std::option`]::[`Option`]::{`self`, `Some`, `None`}. A type which -//! expresses the presence or absence of a value. This type is so commonly -//! used, its variants are also exported. -//! * [`std::result`]::[`Result`]::{`self`, `Ok`, `Err`}. A type for functions -//! that may succeed or fail. Like [`Option`], its variants are exported as -//! well. -//! * [`std::slice`]::[`SliceConcatExt`], a trait that exists for technical -//! reasons, but shouldn't have to exist. It provides a few useful methods on -//! slices. -//! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings. -//! * [`std::vec`]::[`Vec`](../vec/struct.Vec.html), a growable, heap-allocated -//! vector. -//! -//! [`AsMut`]: ../convert/trait.AsMut.html -//! [`AsRef`]: ../convert/trait.AsRef.html -//! [`Box`]: ../boxed/struct.Box.html -//! [`Clone`]: ../clone/trait.Clone.html -//! [`Copy`]: ../marker/trait.Copy.html -//! [`Default`]: ../default/trait.Default.html -//! [`DoubleEndedIterator`]: ../iter/trait.DoubleEndedIterator.html -//! [`Drop`]: ../ops/trait.Drop.html -//! [`Eq`]: ../cmp/trait.Eq.html -//! [`ExactSizeIterator`]: ../iter/trait.ExactSizeIterator.html -//! [`Extend`]: ../iter/trait.Extend.html -//! [`FnMut`]: ../ops/trait.FnMut.html -//! [`FnOnce`]: ../ops/trait.FnOnce.html -//! [`Fn`]: ../ops/trait.Fn.html -//! [`From`]: ../convert/trait.From.html -//! [`IntoIterator`]: ../iter/trait.IntoIterator.html -//! [`Into`]: ../convert/trait.Into.html -//! [`Iterator`]: ../iter/trait.Iterator.html -//! [`Option`]: ../option/enum.Option.html -//! [`Ord`]: ../cmp/trait.Ord.html -//! [`PartialEq`]: ../cmp/trait.PartialEq.html -//! [`PartialOrd`]: ../cmp/trait.PartialOrd.html -//! [`Result`]: ../result/enum.Result.html -//! [`Send`]: ../marker/trait.Send.html -//! [`Sized`]: ../marker/trait.Sized.html -//! [`SliceConcatExt`]: ../slice/trait.SliceConcatExt.html -//! [`String`]: ../string/struct.String.html -//! [`Sync`]: ../marker/trait.Sync.html -//! [`ToOwned`]: ../borrow/trait.ToOwned.html -//! [`ToString`]: ../string/trait.ToString.html -//! [`Vec`]: ../vec/struct.Vec.html -//! [`Clone::clone`]: ../clone/trait.Clone.html#tymethod.clone -//! [`mem::drop`]: ../mem/fn.drop.html -//! [`std::borrow`]: ../borrow/index.html -//! [`std::boxed`]: ../boxed/index.html -//! [`std::clone`]: ../clone/index.html -//! [`std::cmp`]: ../cmp/index.html -//! [`std::convert`]: ../convert/index.html -//! [`std::default`]: ../default/index.html -//! [`std::iter`]: ../iter/index.html -//! [`std::marker`]: ../marker/index.html -//! [`std::mem`]: ../mem/index.html -//! [`std::ops`]: ../ops/index.html -//! [`std::option`]: ../option/index.html -//! [`std::prelude::v1`]: v1/index.html -//! [`std::result`]: ../result/index.html -//! [`std::slice`]: ../slice/index.html -//! [`std::string`]: ../string/index.html -//! [`std::vec`]: ../vec/index.html -//! [`to_owned`]: ../borrow/trait.ToOwned.html#tymethod.to_owned -//! [book-closures]: ../../book/first-edition/closures.html -//! [book-dtor]: ../../book/first-edition/drop.html -//! [book-enums]: ../../book/first-edition/enums.html -//! [book-iter]: ../../book/first-edition/iterators.html - -#![stable(feature = "rust1", since = "1.0.0")] - -pub mod v1; diff --git a/ctr-std/src/prelude/v1.rs b/ctr-std/src/prelude/v1.rs deleted file mode 100644 index 53763da..0000000 --- a/ctr-std/src/prelude/v1.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The first version of the prelude of The Rust Standard Library. -//! -//! See the [module-level documentation](../index.html) for more. - - - -#![stable(feature = "rust1", since = "1.0.0")] - -// Re-exported core operators -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use marker::{Copy, Send, Sized, Sync}; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use ops::{Drop, Fn, FnMut, FnOnce}; - -// Re-exported functions -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use mem::drop; - -// Re-exported types and traits -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use clone::Clone; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use convert::{AsRef, AsMut, Into, From}; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use default::Default; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use iter::{Iterator, Extend, IntoIterator}; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use iter::{DoubleEndedIterator, ExactSizeIterator}; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use option::Option::{self, Some, None}; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use result::Result::{self, Ok, Err}; - - -// The file so far is equivalent to src/libcore/prelude/v1.rs, -// and below to src/liballoc/prelude.rs. -// Those files are duplicated rather than using glob imports -// because we want docs to show these re-exports as pointing to within `std`. - - -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use boxed::Box; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use borrow::ToOwned; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use slice::SliceConcatExt; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use string::{String, ToString}; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] -pub use vec::Vec; diff --git a/ctr-std/src/primitive_docs.rs b/ctr-std/src/primitive_docs.rs deleted file mode 100644 index 7074928..0000000 --- a/ctr-std/src/primitive_docs.rs +++ /dev/null @@ -1,1100 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[doc(primitive = "bool")] -#[doc(alias = "true")] -#[doc(alias = "false")] -// -/// The boolean type. -/// -/// The `bool` represents a value, which could only be either `true` or `false`. If you cast -/// a `bool` into an integer, `true` will be 1 and `false` will be 0. -/// -/// # Basic usage -/// -/// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc., -/// which allow us to perform boolean operations using `&`, `|` and `!`. -/// -/// [`if`] always demands a `bool` value. [`assert!`], being an important macro in testing, -/// checks whether an expression returns `true`. -/// -/// ``` -/// let bool_val = true & false | false; -/// assert!(!bool_val); -/// ``` -/// -/// [`assert!`]: macro.assert.html -/// [`if`]: ../book/first-edition/if.html -/// [`BitAnd`]: ops/trait.BitAnd.html -/// [`BitOr`]: ops/trait.BitOr.html -/// [`Not`]: ops/trait.Not.html -/// -/// # Examples -/// -/// A trivial example of the usage of `bool`, -/// -/// ``` -/// let praise_the_borrow_checker = true; -/// -/// // using the `if` conditional -/// if praise_the_borrow_checker { -/// println!("oh, yeah!"); -/// } else { -/// println!("what?!!"); -/// } -/// -/// // ... or, a match pattern -/// match praise_the_borrow_checker { -/// true => println!("keep praising!"), -/// false => println!("you should praise!"), -/// } -/// ``` -/// -/// Also, since `bool` implements the [`Copy`](marker/trait.Copy.html) trait, we don't -/// have to worry about the move semantics (just like the integer and float primitives). -/// -/// Now an example of `bool` cast to integer type: -/// -/// ``` -/// assert_eq!(true as i32, 1); -/// assert_eq!(false as i32, 0); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_bool { } - -#[doc(primitive = "never")] -#[doc(alias = "!")] -// -/// The `!` type, also called "never". -/// -/// `!` represents the type of computations which never resolve to any value at all. For example, -/// the [`exit`] function `fn exit(code: i32) -> !` exits the process without ever returning, and -/// so returns `!`. -/// -/// `break`, `continue` and `return` expressions also have type `!`. For example we are allowed to -/// write: -/// -/// ``` -/// #![feature(never_type)] -/// # fn foo() -> u32 { -/// let x: ! = { -/// return 123 -/// }; -/// # } -/// ``` -/// -/// Although the `let` is pointless here, it illustrates the meaning of `!`. Since `x` is never -/// assigned a value (because `return` returns from the entire function), `x` can be given type -/// `!`. We could also replace `return 123` with a `panic!` or a never-ending `loop` and this code -/// would still be valid. -/// -/// A more realistic usage of `!` is in this code: -/// -/// ``` -/// # fn get_a_number() -> Option { None } -/// # loop { -/// let num: u32 = match get_a_number() { -/// Some(num) => num, -/// None => break, -/// }; -/// # } -/// ``` -/// -/// Both match arms must produce values of type [`u32`], but since `break` never produces a value -/// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another -/// behaviour of the `!` type - expressions with type `!` will coerce into any other type. -/// -/// [`u32`]: primitive.str.html -/// [`exit`]: process/fn.exit.html -/// -/// # `!` and generics -/// -/// ## Infallible errors -/// -/// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`] -/// trait: -/// -/// ``` -/// trait FromStr: Sized { -/// type Err; -/// fn from_str(s: &str) -> Result; -/// } -/// ``` -/// -/// When implementing this trait for [`String`] we need to pick a type for [`Err`]. And since -/// converting a string into a string will never result in an error, the appropriate type is `!`. -/// (Currently the type actually used is an enum with no variants, though this is only because `!` -/// was added to Rust at a later date and it may change in the future). With an [`Err`] type of -/// `!`, if we have to call [`String::from_str`] for some reason the result will be a -/// [`Result`] which we can unpack like this: -/// -/// ```ignore (string-from-str-error-type-is-not-never-yet) -/// #[feature(exhaustive_patterns)] -/// // NOTE: This does not work today! -/// let Ok(s) = String::from_str("hello"); -/// ``` -/// -/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns` -/// feature is present this means we can exhaustively match on [`Result`] by just taking the -/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain -/// enum variants from generic types like `Result`. -/// -/// ## Infinite loops -/// -/// While [`Result`] is very useful for removing errors, `!` can also be used to remove -/// successes as well. If we think of [`Result`] as "if this function returns, it has not -/// errored," we get a very intuitive idea of [`Result`] as well: if the function returns, it -/// *has* errored. -/// -/// For example, consider the case of a simple web server, which can be simplified to: -/// -/// ```ignore (hypothetical-example) -/// loop { -/// let (client, request) = get_request().expect("disconnected"); -/// let response = request.process(); -/// response.send(client); -/// } -/// ``` -/// -/// Currently, this isn't ideal, because we simply panic whenever we fail to get a new connection. -/// Instead, we'd like to keep track of this error, like this: -/// -/// ```ignore (hypothetical-example) -/// loop { -/// match get_request() { -/// Err(err) => break err, -/// Ok((client, request)) => { -/// let response = request.process(); -/// response.send(client); -/// }, -/// } -/// } -/// ``` -/// -/// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it -/// might be intuitive to simply return the error, we might want to wrap it in a [`Result`] -/// instead: -/// -/// ```ignore (hypothetical-example) -/// fn server_loop() -> Result { -/// loop { -/// let (client, request) = get_request()?; -/// let response = request.process(); -/// response.send(client); -/// } -/// } -/// ``` -/// -/// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop -/// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok` -/// because `!` coerces to `Result` automatically. -/// -/// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str -/// [`Result`]: result/enum.Result.html -/// [`Result`]: result/enum.Result.html -/// [`Result`]: result/enum.Result.html -/// [`Ok`]: result/enum.Result.html#variant.Ok -/// [`String`]: string/struct.String.html -/// [`Err`]: result/enum.Result.html#variant.Err -/// [`FromStr`]: str/trait.FromStr.html -/// -/// # `!` and traits -/// -/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl` -/// which doesn't `panic!`. As is turns out, most traits can have an `impl` for `!`. Take [`Debug`] -/// for example: -/// -/// ``` -/// #![feature(never_type)] -/// # use std::fmt; -/// # trait Debug { -/// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result; -/// # } -/// impl Debug for ! { -/// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { -/// *self -/// } -/// } -/// ``` -/// -/// Once again we're using `!`'s ability to coerce into any other type, in this case -/// [`fmt::Result`]. Since this method takes a `&!` as an argument we know that it can never be -/// called (because there is no value of type `!` for it to be called with). Writing `*self` -/// essentially tells the compiler "We know that this code can never be run, so just treat the -/// entire function body has having type [`fmt::Result`]". This pattern can be used a lot when -/// implementing traits for `!`. Generally, any trait which only has methods which take a `self` -/// parameter should have such as impl. -/// -/// On the other hand, one trait which would not be appropriate to implement is [`Default`]: -/// -/// ``` -/// trait Default { -/// fn default() -> Self; -/// } -/// ``` -/// -/// Since `!` has no values, it has no default value either. It's true that we could write an -/// `impl` for this which simply panics, but the same is true for any type (we could `impl -/// Default` for (eg.) [`File`] by just making [`default()`] panic.) -/// -/// [`fmt::Result`]: fmt/type.Result.html -/// [`File`]: fs/struct.File.html -/// [`Debug`]: fmt/trait.Debug.html -/// [`Default`]: default/trait.Default.html -/// [`default()`]: default/trait.Default.html#tymethod.default -/// -mod prim_never { } - -#[doc(primitive = "char")] -// -/// A character type. -/// -/// The `char` type represents a single character. More specifically, since -/// 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode -/// scalar value]', which is similar to, but not the same as, a '[Unicode code -/// point]'. -/// -/// [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value -/// [Unicode code point]: http://www.unicode.org/glossary/#code_point -/// -/// This documentation describes a number of methods and trait implementations on the -/// `char` type. For technical reasons, there is additional, separate -/// documentation in [the `std::char` module](char/index.html) as well. -/// -/// # Representation -/// -/// `char` is always four bytes in size. This is a different representation than -/// a given character would have as part of a [`String`]. For example: -/// -/// ``` -/// let v = vec!['h', 'e', 'l', 'l', 'o']; -/// -/// // five elements times four bytes for each element -/// assert_eq!(20, v.len() * std::mem::size_of::()); -/// -/// let s = String::from("hello"); -/// -/// // five elements times one byte per element -/// assert_eq!(5, s.len() * std::mem::size_of::()); -/// ``` -/// -/// [`String`]: string/struct.String.html -/// -/// As always, remember that a human intuition for 'character' may not map to -/// Unicode's definitions. For example, despite looking similar, the 'é' -/// character is one Unicode code point while 'é' is two Unicode code points: -/// -/// ``` -/// let mut chars = "é".chars(); -/// // U+00e9: 'latin small letter e with acute' -/// assert_eq!(Some('\u{00e9}'), chars.next()); -/// assert_eq!(None, chars.next()); -/// -/// let mut chars = "é".chars(); -/// // U+0065: 'latin small letter e' -/// assert_eq!(Some('\u{0065}'), chars.next()); -/// // U+0301: 'combining acute accent' -/// assert_eq!(Some('\u{0301}'), chars.next()); -/// assert_eq!(None, chars.next()); -/// ``` -/// -/// This means that the contents of the first string above _will_ fit into a -/// `char` while the contents of the second string _will not_. Trying to create -/// a `char` literal with the contents of the second string gives an error: -/// -/// ```text -/// error: character literal may only contain one codepoint: 'é' -/// let c = 'é'; -/// ^^^^ -/// ``` -/// -/// Another implication of the 4-byte fixed size of a `char` is that -/// per-`char` processing can end up using a lot more memory: -/// -/// ``` -/// let s = String::from("love: ❤️"); -/// let v: Vec = s.chars().collect(); -/// -/// assert_eq!(12, s.len() * std::mem::size_of::()); -/// assert_eq!(32, v.len() * std::mem::size_of::()); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_char { } - -#[doc(primitive = "unit")] -// -/// The `()` type, sometimes called "unit" or "nil". -/// -/// The `()` type has exactly one value `()`, and is used when there -/// is no other meaningful value that could be returned. `()` is most -/// commonly seen implicitly: functions without a `-> ...` implicitly -/// have return type `()`, that is, these are equivalent: -/// -/// ```rust -/// fn long() -> () {} -/// -/// fn short() {} -/// ``` -/// -/// The semicolon `;` can be used to discard the result of an -/// expression at the end of a block, making the expression (and thus -/// the block) evaluate to `()`. For example, -/// -/// ```rust -/// fn returns_i64() -> i64 { -/// 1i64 -/// } -/// fn returns_unit() { -/// 1i64; -/// } -/// -/// let is_i64 = { -/// returns_i64() -/// }; -/// let is_unit = { -/// returns_i64(); -/// }; -/// ``` -/// -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_unit { } - -#[doc(primitive = "pointer")] -// -/// Raw, unsafe pointers, `*const T`, and `*mut T`. -/// -/// *[See also the `std::ptr` module](ptr/index.html).* -/// -/// Working with raw pointers in Rust is uncommon, -/// typically limited to a few patterns. -/// -/// Use the [`null`] and [`null_mut`] functions to create null pointers, and the -/// [`is_null`] method of the `*const T` and `*mut T` types to check for null. -/// The `*const T` and `*mut T` types also define the [`offset`] method, for -/// pointer math. -/// -/// # Common ways to create raw pointers -/// -/// ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`). -/// -/// ``` -/// let my_num: i32 = 10; -/// let my_num_ptr: *const i32 = &my_num; -/// let mut my_speed: i32 = 88; -/// let my_speed_ptr: *mut i32 = &mut my_speed; -/// ``` -/// -/// To get a pointer to a boxed value, dereference the box: -/// -/// ``` -/// let my_num: Box = Box::new(10); -/// let my_num_ptr: *const i32 = &*my_num; -/// let mut my_speed: Box = Box::new(88); -/// let my_speed_ptr: *mut i32 = &mut *my_speed; -/// ``` -/// -/// This does not take ownership of the original allocation -/// and requires no resource management later, -/// but you must not use the pointer after its lifetime. -/// -/// ## 2. Consume a box (`Box`). -/// -/// The [`into_raw`] function consumes a box and returns -/// the raw pointer. It doesn't destroy `T` or deallocate any memory. -/// -/// ``` -/// let my_speed: Box = Box::new(88); -/// let my_speed: *mut i32 = Box::into_raw(my_speed); -/// -/// // By taking ownership of the original `Box` though -/// // we are obligated to put it together later to be destroyed. -/// unsafe { -/// drop(Box::from_raw(my_speed)); -/// } -/// ``` -/// -/// Note that here the call to [`drop`] is for clarity - it indicates -/// that we are done with the given value and it should be destroyed. -/// -/// ## 3. Get it from C. -/// -/// ``` -/// # #![feature(libc)] -/// extern crate libc; -/// -/// use std::mem; -/// -/// fn main() { -/// unsafe { -/// let my_num: *mut i32 = libc::malloc(mem::size_of::()) as *mut i32; -/// if my_num.is_null() { -/// panic!("failed to allocate memory"); -/// } -/// libc::free(my_num as *mut libc::c_void); -/// } -/// } -/// ``` -/// -/// Usually you wouldn't literally use `malloc` and `free` from Rust, -/// but C APIs hand out a lot of pointers generally, so are a common source -/// of raw pointers in Rust. -/// -/// [`null`]: ../std/ptr/fn.null.html -/// [`null_mut`]: ../std/ptr/fn.null_mut.html -/// [`is_null`]: ../std/primitive.pointer.html#method.is_null -/// [`offset`]: ../std/primitive.pointer.html#method.offset -/// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw -/// [`drop`]: ../std/mem/fn.drop.html -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_pointer { } - -#[doc(primitive = "array")] -// -/// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and the -/// non-negative compile-time constant size, `N`. -/// -/// There are two syntactic forms for creating an array: -/// -/// * A list with each element, i.e. `[x, y, z]`. -/// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`. -/// The type of `x` must be [`Copy`][copy]. -/// -/// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if -/// the element type allows it: -/// -/// - [`Debug`][debug] -/// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`) -/// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord] -/// - [`Hash`][hash] -/// - [`AsRef`][asref], [`AsMut`][asmut] -/// - [`Borrow`][borrow], [`BorrowMut`][borrowmut] -/// - [`Default`][default] -/// -/// This limitation on the size `N` exists because Rust does not yet support -/// code that is generic over the size of an array type. `[Foo; 3]` and `[Bar; 3]` -/// are instances of same generic type `[T; 3]`, but `[Foo; 3]` and `[Foo; 5]` are -/// entirely different types. As a stopgap, trait implementations are -/// statically generated up to size 32. -/// -/// Arrays of *any* size are [`Copy`][copy] if the element type is [`Copy`][copy] -/// and [`Clone`][clone] if the element type is [`Clone`][clone]. This works -/// because [`Copy`][copy] and [`Clone`][clone] traits are specially known -/// to the compiler. -/// -/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on -/// an array. Indeed, this provides most of the API for working with arrays. -/// Slices have a dynamic size and do not coerce to arrays. -/// -/// There is no way to move elements out of an array. See [`mem::replace`][replace] -/// for an alternative. -/// -/// # Examples -/// -/// ``` -/// let mut array: [i32; 3] = [0; 3]; -/// -/// array[1] = 1; -/// array[2] = 2; -/// -/// assert_eq!([1, 2], &array[1..]); -/// -/// // This loop prints: 0 1 2 -/// for x in &array { -/// print!("{} ", x); -/// } -/// ``` -/// -/// An array itself is not iterable: -/// -/// ```compile_fail,E0277 -/// let array: [i32; 3] = [0; 3]; -/// -/// for x in array { } -/// // error: the trait bound `[i32; 3]: std::iter::Iterator` is not satisfied -/// ``` -/// -/// The solution is to coerce the array to a slice by calling a slice method: -/// -/// ``` -/// # let array: [i32; 3] = [0; 3]; -/// for x in array.iter() { } -/// ``` -/// -/// If the array has 32 or fewer elements (see above), you can also use the -/// array reference's [`IntoIterator`] implementation: -/// -/// ``` -/// # let array: [i32; 3] = [0; 3]; -/// for x in &array { } -/// ``` -/// -/// [slice]: primitive.slice.html -/// [copy]: marker/trait.Copy.html -/// [clone]: clone/trait.Clone.html -/// [debug]: fmt/trait.Debug.html -/// [intoiterator]: iter/trait.IntoIterator.html -/// [partialeq]: cmp/trait.PartialEq.html -/// [partialord]: cmp/trait.PartialOrd.html -/// [eq]: cmp/trait.Eq.html -/// [ord]: cmp/trait.Ord.html -/// [hash]: hash/trait.Hash.html -/// [asref]: convert/trait.AsRef.html -/// [asmut]: convert/trait.AsMut.html -/// [borrow]: borrow/trait.Borrow.html -/// [borrowmut]: borrow/trait.BorrowMut.html -/// [default]: default/trait.Default.html -/// [replace]: mem/fn.replace.html -/// [`IntoIterator`]: iter/trait.IntoIterator.html -/// -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_array { } - -#[doc(primitive = "slice")] -#[doc(alias = "[")] -#[doc(alias = "]")] -#[doc(alias = "[]")] -// -/// A dynamically-sized view into a contiguous sequence, `[T]`. -/// -/// *[See also the `std::slice` module](slice/index.html).* -/// -/// Slices are a view into a block of memory represented as a pointer and a -/// length. -/// -/// ``` -/// // slicing a Vec -/// let vec = vec![1, 2, 3]; -/// let int_slice = &vec[..]; -/// // coercing an array to a slice -/// let str_slice: &[&str] = &["one", "two", "three"]; -/// ``` -/// -/// Slices are either mutable or shared. The shared slice type is `&[T]`, -/// while the mutable slice type is `&mut [T]`, where `T` represents the element -/// type. For example, you can mutate the block of memory that a mutable slice -/// points to: -/// -/// ``` -/// let x = &mut [1, 2, 3]; -/// x[1] = 7; -/// assert_eq!(x, &[1, 7, 3]); -/// ``` -/// -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_slice { } - -#[doc(primitive = "str")] -// -/// String slices. -/// -/// *[See also the `std::str` module](str/index.html).* -/// -/// The `str` type, also called a 'string slice', is the most primitive string -/// type. It is usually seen in its borrowed form, `&str`. It is also the type -/// of string literals, `&'static str`. -/// -/// String slices are always valid UTF-8. -/// -/// # Examples -/// -/// String literals are string slices: -/// -/// ``` -/// let hello = "Hello, world!"; -/// -/// // with an explicit type annotation -/// let hello: &'static str = "Hello, world!"; -/// ``` -/// -/// They are `'static` because they're stored directly in the final binary, and -/// so will be valid for the `'static` duration. -/// -/// # Representation -/// -/// A `&str` is made up of two components: a pointer to some bytes, and a -/// length. You can look at these with the [`as_ptr`] and [`len`] methods: -/// -/// ``` -/// use std::slice; -/// use std::str; -/// -/// let story = "Once upon a time..."; -/// -/// let ptr = story.as_ptr(); -/// let len = story.len(); -/// -/// // story has nineteen bytes -/// assert_eq!(19, len); -/// -/// // We can re-build a str out of ptr and len. This is all unsafe because -/// // we are responsible for making sure the two components are valid: -/// let s = unsafe { -/// // First, we build a &[u8]... -/// let slice = slice::from_raw_parts(ptr, len); -/// -/// // ... and then convert that slice into a string slice -/// str::from_utf8(slice) -/// }; -/// -/// assert_eq!(s, Ok(story)); -/// ``` -/// -/// [`as_ptr`]: #method.as_ptr -/// [`len`]: #method.len -/// -/// Note: This example shows the internals of `&str`. `unsafe` should not be -/// used to get a string slice under normal circumstances. Use `as_slice` -/// instead. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_str { } - -#[doc(primitive = "tuple")] -#[doc(alias = "(")] -#[doc(alias = ")")] -#[doc(alias = "()")] -// -/// A finite heterogeneous sequence, `(T, U, ..)`. -/// -/// Let's cover each of those in turn: -/// -/// Tuples are *finite*. In other words, a tuple has a length. Here's a tuple -/// of length `3`: -/// -/// ``` -/// ("hello", 5, 'c'); -/// ``` -/// -/// 'Length' is also sometimes called 'arity' here; each tuple of a different -/// length is a different, distinct type. -/// -/// Tuples are *heterogeneous*. This means that each element of the tuple can -/// have a different type. In that tuple above, it has the type: -/// -/// ``` -/// # let _: -/// (&'static str, i32, char) -/// # = ("hello", 5, 'c'); -/// ``` -/// -/// Tuples are a *sequence*. This means that they can be accessed by position; -/// this is called 'tuple indexing', and it looks like this: -/// -/// ```rust -/// let tuple = ("hello", 5, 'c'); -/// -/// assert_eq!(tuple.0, "hello"); -/// assert_eq!(tuple.1, 5); -/// assert_eq!(tuple.2, 'c'); -/// ``` -/// -/// For more about tuples, see [the book](../book/first-edition/primitive-types.html#tuples). -/// -/// # Trait implementations -/// -/// If every type inside a tuple implements one of the following traits, then a -/// tuple itself also implements it. -/// -/// * [`Clone`] -/// * [`Copy`] -/// * [`PartialEq`] -/// * [`Eq`] -/// * [`PartialOrd`] -/// * [`Ord`] -/// * [`Debug`] -/// * [`Default`] -/// * [`Hash`] -/// -/// [`Clone`]: clone/trait.Clone.html -/// [`Copy`]: marker/trait.Copy.html -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// [`Eq`]: cmp/trait.Eq.html -/// [`PartialOrd`]: cmp/trait.PartialOrd.html -/// [`Ord`]: cmp/trait.Ord.html -/// [`Debug`]: fmt/trait.Debug.html -/// [`Default`]: default/trait.Default.html -/// [`Hash`]: hash/trait.Hash.html -/// -/// Due to a temporary restriction in Rust's type system, these traits are only -/// implemented on tuples of arity 12 or less. In the future, this may change. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let tuple = ("hello", 5, 'c'); -/// -/// assert_eq!(tuple.0, "hello"); -/// ``` -/// -/// Tuples are often used as a return type when you want to return more than -/// one value: -/// -/// ``` -/// fn calculate_point() -> (i32, i32) { -/// // Don't do a calculation, that's not the point of the example -/// (4, 5) -/// } -/// -/// let point = calculate_point(); -/// -/// assert_eq!(point.0, 4); -/// assert_eq!(point.1, 5); -/// -/// // Combining this with patterns can be nicer. -/// -/// let (x, y) = calculate_point(); -/// -/// assert_eq!(x, 4); -/// assert_eq!(y, 5); -/// ``` -/// -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_tuple { } - -#[doc(primitive = "f32")] -/// The 32-bit floating point type. -/// -/// *[See also the `std::f32` module](f32/index.html).* -/// -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_f32 { } - -#[doc(primitive = "f64")] -// -/// The 64-bit floating point type. -/// -/// *[See also the `std::f64` module](f64/index.html).* -/// -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_f64 { } - -#[doc(primitive = "i8")] -// -/// The 8-bit signed integer type. -/// -/// *[See also the `std::i8` module](i8/index.html).* -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_i8 { } - -#[doc(primitive = "i16")] -// -/// The 16-bit signed integer type. -/// -/// *[See also the `std::i16` module](i16/index.html).* -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_i16 { } - -#[doc(primitive = "i32")] -// -/// The 32-bit signed integer type. -/// -/// *[See also the `std::i32` module](i32/index.html).* -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_i32 { } - -#[doc(primitive = "i64")] -// -/// The 64-bit signed integer type. -/// -/// *[See also the `std::i64` module](i64/index.html).* -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_i64 { } - -#[doc(primitive = "i128")] -// -/// The 128-bit signed integer type. -/// -/// *[See also the `std::i128` module](i128/index.html).* -#[stable(feature = "i128", since="1.26.0")] -mod prim_i128 { } - -#[doc(primitive = "u8")] -// -/// The 8-bit unsigned integer type. -/// -/// *[See also the `std::u8` module](u8/index.html).* -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_u8 { } - -#[doc(primitive = "u16")] -// -/// The 16-bit unsigned integer type. -/// -/// *[See also the `std::u16` module](u16/index.html).* -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_u16 { } - -#[doc(primitive = "u32")] -// -/// The 32-bit unsigned integer type. -/// -/// *[See also the `std::u32` module](u32/index.html).* -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_u32 { } - -#[doc(primitive = "u64")] -// -/// The 64-bit unsigned integer type. -/// -/// *[See also the `std::u64` module](u64/index.html).* -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_u64 { } - -#[doc(primitive = "u128")] -// -/// The 128-bit unsigned integer type. -/// -/// *[See also the `std::u128` module](u128/index.html).* -#[stable(feature = "i128", since="1.26.0")] -mod prim_u128 { } - -#[doc(primitive = "isize")] -// -/// The pointer-sized signed integer type. -/// -/// *[See also the `std::isize` module](isize/index.html).* -/// -/// The size of this primitive is how many bytes it takes to reference any -/// location in memory. For example, on a 32 bit target, this is 4 bytes -/// and on a 64 bit target, this is 8 bytes. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_isize { } - -#[doc(primitive = "usize")] -// -/// The pointer-sized unsigned integer type. -/// -/// *[See also the `std::usize` module](usize/index.html).* -/// -/// The size of this primitive is how many bytes it takes to reference any -/// location in memory. For example, on a 32 bit target, this is 4 bytes -/// and on a 64 bit target, this is 8 bytes. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_usize { } - -#[doc(primitive = "reference")] -#[doc(alias = "&")] -// -/// References, both shared and mutable. -/// -/// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut` -/// operators on a value, or by using a `ref` or `ref mut` pattern. -/// -/// For those familiar with pointers, a reference is just a pointer that is assumed to not be null. -/// In fact, `Option<&T>` has the same memory representation as a nullable pointer, and can be -/// passed across FFI boundaries as such. -/// -/// In most cases, references can be used much like the original value. Field access, method -/// calling, and indexing work the same (save for mutability rules, of course). In addition, the -/// comparison operators transparently defer to the referent's implementation, allowing references -/// to be compared the same as owned values. -/// -/// References have a lifetime attached to them, which represents the scope for which the borrow is -/// valid. A lifetime is said to "outlive" another one if its representative scope is as long or -/// longer than the other. The `'static` lifetime is the longest lifetime, which represents the -/// total life of the program. For example, string literals have a `'static` lifetime because the -/// text data is embedded into the binary of the program, rather than in an allocation that needs -/// to be dynamically managed. -/// -/// `&mut T` references can be freely coerced into `&T` references with the same referent type, and -/// references with longer lifetimes can be freely coerced into references with shorter ones. -/// -/// For more information on how to use references, see [the book's section on "References and -/// Borrowing"][book-refs]. -/// -/// [book-refs]: ../book/second-edition/ch04-02-references-and-borrowing.html -/// -/// The following traits are implemented for all `&T`, regardless of the type of its referent: -/// -/// * [`Copy`] -/// * [`Clone`] \(Note that this will not defer to `T`'s `Clone` implementation if it exists!) -/// * [`Deref`] -/// * [`Borrow`] -/// * [`Pointer`] -/// -/// [`Copy`]: marker/trait.Copy.html -/// [`Clone`]: clone/trait.Clone.html -/// [`Deref`]: ops/trait.Deref.html -/// [`Borrow`]: borrow/trait.Borrow.html -/// [`Pointer`]: fmt/trait.Pointer.html -/// -/// `&mut T` references get all of the above except `Copy` and `Clone` (to prevent creating -/// multiple simultaneous mutable borrows), plus the following, regardless of the type of its -/// referent: -/// -/// * [`DerefMut`] -/// * [`BorrowMut`] -/// -/// [`DerefMut`]: ops/trait.DerefMut.html -/// [`BorrowMut`]: borrow/trait.BorrowMut.html -/// -/// The following traits are implemented on `&T` references if the underlying `T` also implements -/// that trait: -/// -/// * All the traits in [`std::fmt`] except [`Pointer`] and [`fmt::Write`] -/// * [`PartialOrd`] -/// * [`Ord`] -/// * [`PartialEq`] -/// * [`Eq`] -/// * [`AsRef`] -/// * [`Fn`] \(in addition, `&T` references get [`FnMut`] and [`FnOnce`] if `T: Fn`) -/// * [`Hash`] -/// * [`ToSocketAddrs`] -/// -/// [`std::fmt`]: fmt/index.html -/// [`fmt::Write`]: fmt/trait.Write.html -/// [`PartialOrd`]: cmp/trait.PartialOrd.html -/// [`Ord`]: cmp/trait.Ord.html -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// [`Eq`]: cmp/trait.Eq.html -/// [`AsRef`]: convert/trait.AsRef.html -/// [`Fn`]: ops/trait.Fn.html -/// [`FnMut`]: ops/trait.FnMut.html -/// [`FnOnce`]: ops/trait.FnOnce.html -/// [`Hash`]: hash/trait.Hash.html -/// [`ToSocketAddrs`]: net/trait.ToSocketAddrs.html -/// -/// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T` -/// implements that trait: -/// -/// * [`AsMut`] -/// * [`FnMut`] \(in addition, `&mut T` references get [`FnOnce`] if `T: FnMut`) -/// * [`fmt::Write`] -/// * [`Iterator`] -/// * [`DoubleEndedIterator`] -/// * [`ExactSizeIterator`] -/// * [`FusedIterator`] -/// * [`TrustedLen`] -/// * [`Send`] \(note that `&T` references only get `Send` if `T: Sync`) -/// * [`io::Write`] -/// * [`Read`] -/// * [`Seek`] -/// * [`BufRead`] -/// -/// [`AsMut`]: convert/trait.AsMut.html -/// [`Iterator`]: iter/trait.Iterator.html -/// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html -/// [`ExactSizeIterator`]: iter/trait.ExactSizeIterator.html -/// [`FusedIterator`]: iter/trait.FusedIterator.html -/// [`TrustedLen`]: iter/trait.TrustedLen.html -/// [`Send`]: marker/trait.Send.html -/// [`io::Write`]: io/trait.Write.html -/// [`Read`]: io/trait.Read.html -/// [`Seek`]: io/trait.Seek.html -/// [`BufRead`]: io/trait.BufRead.html -/// -/// Note that due to method call deref coercion, simply calling a trait method will act like they -/// work on references as well as they do on owned values! The implementations described here are -/// meant for generic contexts, where the final type `T` is a type parameter or otherwise not -/// locally known. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_ref { } - -#[doc(primitive = "fn")] -// -/// Function pointers, like `fn(usize) -> bool`. -/// -/// *See also the traits [`Fn`], [`FnMut`], and [`FnOnce`].* -/// -/// [`Fn`]: ops/trait.Fn.html -/// [`FnMut`]: ops/trait.FnMut.html -/// [`FnOnce`]: ops/trait.FnOnce.html -/// -/// Plain function pointers are obtained by casting either plain functions, or closures that don't -/// capture an environment: -/// -/// ``` -/// fn add_one(x: usize) -> usize { -/// x + 1 -/// } -/// -/// let ptr: fn(usize) -> usize = add_one; -/// assert_eq!(ptr(5), 6); -/// -/// let clos: fn(usize) -> usize = |x| x + 5; -/// assert_eq!(clos(5), 10); -/// ``` -/// -/// In addition to varying based on their signature, function pointers come in two flavors: safe -/// and unsafe. Plain `fn()` function pointers can only point to safe functions, -/// while `unsafe fn()` function pointers can point to safe or unsafe functions. -/// -/// ``` -/// fn add_one(x: usize) -> usize { -/// x + 1 -/// } -/// -/// unsafe fn add_one_unsafely(x: usize) -> usize { -/// x + 1 -/// } -/// -/// let safe_ptr: fn(usize) -> usize = add_one; -/// -/// //ERROR: mismatched types: expected normal fn, found unsafe fn -/// //let bad_ptr: fn(usize) -> usize = add_one_unsafely; -/// -/// let unsafe_ptr: unsafe fn(usize) -> usize = add_one_unsafely; -/// let really_safe_ptr: unsafe fn(usize) -> usize = add_one; -/// ``` -/// -/// On top of that, function pointers can vary based on what ABI they use. This is achieved by -/// adding the `extern` keyword to the type name, followed by the ABI in question. For example, -/// `fn()` is different from `extern "C" fn()`, which itself is different from `extern "stdcall" -/// fn()`, and so on for the various ABIs that Rust supports. Non-`extern` functions have an ABI -/// of `"Rust"`, and `extern` functions without an explicit ABI have an ABI of `"C"`. For more -/// information, see [the nomicon's section on foreign calling conventions][nomicon-abi]. -/// -/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions -/// -/// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them -/// to be called with a variable number of arguments. Normal rust functions, even those with an -/// `extern "ABI"`, cannot be variadic. For more information, see [the nomicon's section on -/// variadic functions][nomicon-variadic]. -/// -/// [nomicon-variadic]: ../nomicon/ffi.html#variadic-functions -/// -/// These markers can be combined, so `unsafe extern "stdcall" fn()` is a valid type. -/// -/// Like references in rust, function pointers are assumed to not be null, so if you want to pass a -/// function pointer over FFI and be able to accommodate null pointers, make your type -/// `Option` with your required signature. -/// -/// Function pointers implement the following traits: -/// -/// * [`Clone`] -/// * [`PartialEq`] -/// * [`Eq`] -/// * [`PartialOrd`] -/// * [`Ord`] -/// * [`Hash`] -/// * [`Pointer`] -/// * [`Debug`] -/// -/// [`Clone`]: clone/trait.Clone.html -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// [`Eq`]: cmp/trait.Eq.html -/// [`PartialOrd`]: cmp/trait.PartialOrd.html -/// [`Ord`]: cmp/trait.Ord.html -/// [`Hash`]: hash/trait.Hash.html -/// [`Pointer`]: fmt/trait.Pointer.html -/// [`Debug`]: fmt/trait.Debug.html -/// -/// Due to a temporary restriction in Rust's type system, these traits are only implemented on -/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this -/// may change. -/// -/// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe* -/// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits -/// are specially known to the compiler. -/// -/// [`Copy`]: marker/trait.Copy.html -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_fn { } diff --git a/ctr-std/src/process.rs b/ctr-std/src/process.rs deleted file mode 100644 index 9dd0767..0000000 --- a/ctr-std/src/process.rs +++ /dev/null @@ -1,1990 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A module for working with processes. -//! -//! This module is mostly concerned with spawning and interacting with child -//! processes, but it also provides [`abort`] and [`exit`] for terminating the -//! current process. -//! -//! # Spawning a process -//! -//! The [`Command`] struct is used to configure and spawn processes: -//! -//! ``` -//! use std::process::Command; -//! -//! let output = Command::new("echo") -//! .arg("Hello world") -//! .output() -//! .expect("Failed to execute command"); -//! -//! assert_eq!(b"Hello world\n", output.stdout.as_slice()); -//! ``` -//! -//! Several methods on [`Command`], such as [`spawn`] or [`output`], can be used -//! to spawn a process. In particular, [`output`] spawns the child process and -//! waits until the process terminates, while [`spawn`] will return a [`Child`] -//! that represents the spawned child process. -//! -//! # Handling I/O -//! -//! The [`stdout`], [`stdin`], and [`stderr`] of a child process can be -//! configured by passing an [`Stdio`] to the corresponding method on -//! [`Command`]. Once spawned, they can be accessed from the [`Child`]. For -//! example, piping output from one command into another command can be done -//! like so: -//! -//! ```no_run -//! use std::process::{Command, Stdio}; -//! -//! // stdout must be configured with `Stdio::piped` in order to use -//! // `echo_child.stdout` -//! let echo_child = Command::new("echo") -//! .arg("Oh no, a tpyo!") -//! .stdout(Stdio::piped()) -//! .spawn() -//! .expect("Failed to start echo process"); -//! -//! // Note that `echo_child` is moved here, but we won't be needing -//! // `echo_child` anymore -//! let echo_out = echo_child.stdout.expect("Failed to open echo stdout"); -//! -//! let mut sed_child = Command::new("sed") -//! .arg("s/tpyo/typo/") -//! .stdin(Stdio::from(echo_out)) -//! .stdout(Stdio::piped()) -//! .spawn() -//! .expect("Failed to start sed process"); -//! -//! let output = sed_child.wait_with_output().expect("Failed to wait on sed"); -//! assert_eq!(b"Oh no, a typo!\n", output.stdout.as_slice()); -//! ``` -//! -//! Note that [`ChildStderr`] and [`ChildStdout`] implement [`Read`] and -//! [`ChildStdin`] implements [`Write`]: -//! -//! ```no_run -//! use std::process::{Command, Stdio}; -//! use std::io::Write; -//! -//! let mut child = Command::new("/bin/cat") -//! .stdin(Stdio::piped()) -//! .stdout(Stdio::piped()) -//! .spawn() -//! .expect("failed to execute child"); -//! -//! { -//! // limited borrow of stdin -//! let stdin = child.stdin.as_mut().expect("failed to get stdin"); -//! stdin.write_all(b"test").expect("failed to write to stdin"); -//! } -//! -//! let output = child -//! .wait_with_output() -//! .expect("failed to wait on child"); -//! -//! assert_eq!(b"test", output.stdout.as_slice()); -//! ``` -//! -//! [`abort`]: fn.abort.html -//! [`exit`]: fn.exit.html -//! -//! [`Command`]: struct.Command.html -//! [`spawn`]: struct.Command.html#method.spawn -//! [`output`]: struct.Command.html#method.output -//! -//! [`Child`]: struct.Child.html -//! [`ChildStdin`]: struct.ChildStdin.html -//! [`ChildStdout`]: struct.ChildStdout.html -//! [`ChildStderr`]: struct.ChildStderr.html -//! [`Stdio`]: struct.Stdio.html -//! -//! [`stdout`]: struct.Command.html#method.stdout -//! [`stdin`]: struct.Command.html#method.stdin -//! [`stderr`]: struct.Command.html#method.stderr -//! -//! [`Write`]: ../io/trait.Write.html -//! [`Read`]: ../io/trait.Read.html - -#![stable(feature = "process", since = "1.0.0")] - -use io::prelude::*; - -use ffi::OsStr; -use fmt; -use fs; -use io::{self, Initializer}; -use path::Path; -use str; -use sys::pipe::{read2, AnonPipe}; -use sys::process as imp; -use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; - -/// Representation of a running or exited child process. -/// -/// This structure is used to represent and manage child processes. A child -/// process is created via the [`Command`] struct, which configures the -/// spawning process and can itself be constructed using a builder-style -/// interface. -/// -/// There is no implementation of [`Drop`] for child processes, -/// so if you do not ensure the `Child` has exited then it will continue to -/// run, even after the `Child` handle to the child process has gone out of -/// scope. -/// -/// Calling [`wait`](#method.wait) (or other functions that wrap around it) will make -/// the parent process wait until the child has actually exited before -/// continuing. -/// -/// # Examples -/// -/// ```should_panic -/// use std::process::Command; -/// -/// let mut child = Command::new("/bin/cat") -/// .arg("file.txt") -/// .spawn() -/// .expect("failed to execute child"); -/// -/// let ecode = child.wait() -/// .expect("failed to wait on child"); -/// -/// assert!(ecode.success()); -/// ``` -/// -/// [`Command`]: struct.Command.html -/// [`Drop`]: ../../core/ops/trait.Drop.html -/// [`wait`]: #method.wait -#[stable(feature = "process", since = "1.0.0")] -pub struct Child { - handle: imp::Process, - - /// The handle for writing to the child's standard input (stdin), if it has - /// been captured. - #[stable(feature = "process", since = "1.0.0")] - pub stdin: Option, - - /// The handle for reading from the child's standard output (stdout), if it - /// has been captured. - #[stable(feature = "process", since = "1.0.0")] - pub stdout: Option, - - /// The handle for reading from the child's standard error (stderr), if it - /// has been captured. - #[stable(feature = "process", since = "1.0.0")] - pub stderr: Option, -} - -impl AsInner for Child { - fn as_inner(&self) -> &imp::Process { &self.handle } -} - -impl FromInner<(imp::Process, imp::StdioPipes)> for Child { - fn from_inner((handle, io): (imp::Process, imp::StdioPipes)) -> Child { - Child { - handle, - stdin: io.stdin.map(ChildStdin::from_inner), - stdout: io.stdout.map(ChildStdout::from_inner), - stderr: io.stderr.map(ChildStderr::from_inner), - } - } -} - -impl IntoInner for Child { - fn into_inner(self) -> imp::Process { self.handle } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Child { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Child") - .field("stdin", &self.stdin) - .field("stdout", &self.stdout) - .field("stderr", &self.stderr) - .finish() - } -} - -/// A handle to a child process's standard input (stdin). -/// -/// This struct is used in the [`stdin`] field on [`Child`]. -/// -/// When an instance of `ChildStdin` is [dropped], the `ChildStdin`'s underlying -/// file handle will be closed. If the child process was blocked on input prior -/// to being dropped, it will become unblocked after dropping. -/// -/// [`Child`]: struct.Child.html -/// [`stdin`]: struct.Child.html#structfield.stdin -/// [dropped]: ../ops/trait.Drop.html -#[stable(feature = "process", since = "1.0.0")] -pub struct ChildStdin { - inner: AnonPipe -} - -#[stable(feature = "process", since = "1.0.0")] -impl Write for ChildStdin { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl AsInner for ChildStdin { - fn as_inner(&self) -> &AnonPipe { &self.inner } -} - -impl IntoInner for ChildStdin { - fn into_inner(self) -> AnonPipe { self.inner } -} - -impl FromInner for ChildStdin { - fn from_inner(pipe: AnonPipe) -> ChildStdin { - ChildStdin { inner: pipe } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ChildStdin { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("ChildStdin { .. }") - } -} - -/// A handle to a child process's standard output (stdout). -/// -/// This struct is used in the [`stdout`] field on [`Child`]. -/// -/// When an instance of `ChildStdout` is [dropped], the `ChildStdout`'s -/// underlying file handle will be closed. -/// -/// [`Child`]: struct.Child.html -/// [`stdout`]: struct.Child.html#structfield.stdout -/// [dropped]: ../ops/trait.Drop.html -#[stable(feature = "process", since = "1.0.0")] -pub struct ChildStdout { - inner: AnonPipe -} - -#[stable(feature = "process", since = "1.0.0")] -impl Read for ChildStdout { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -impl AsInner for ChildStdout { - fn as_inner(&self) -> &AnonPipe { &self.inner } -} - -impl IntoInner for ChildStdout { - fn into_inner(self) -> AnonPipe { self.inner } -} - -impl FromInner for ChildStdout { - fn from_inner(pipe: AnonPipe) -> ChildStdout { - ChildStdout { inner: pipe } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ChildStdout { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("ChildStdout { .. }") - } -} - -/// A handle to a child process's stderr. -/// -/// This struct is used in the [`stderr`] field on [`Child`]. -/// -/// When an instance of `ChildStderr` is [dropped], the `ChildStderr`'s -/// underlying file handle will be closed. -/// -/// [`Child`]: struct.Child.html -/// [`stderr`]: struct.Child.html#structfield.stderr -/// [dropped]: ../ops/trait.Drop.html -#[stable(feature = "process", since = "1.0.0")] -pub struct ChildStderr { - inner: AnonPipe -} - -#[stable(feature = "process", since = "1.0.0")] -impl Read for ChildStderr { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -impl AsInner for ChildStderr { - fn as_inner(&self) -> &AnonPipe { &self.inner } -} - -impl IntoInner for ChildStderr { - fn into_inner(self) -> AnonPipe { self.inner } -} - -impl FromInner for ChildStderr { - fn from_inner(pipe: AnonPipe) -> ChildStderr { - ChildStderr { inner: pipe } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ChildStderr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("ChildStderr { .. }") - } -} - -/// A process builder, providing fine-grained control -/// over how a new process should be spawned. -/// -/// A default configuration can be -/// generated using `Command::new(program)`, where `program` gives a path to the -/// program to be executed. Additional builder methods allow the configuration -/// to be changed (for example, by adding arguments) prior to spawning: -/// -/// ``` -/// use std::process::Command; -/// -/// let output = if cfg!(target_os = "windows") { -/// Command::new("cmd") -/// .args(&["/C", "echo hello"]) -/// .output() -/// .expect("failed to execute process") -/// } else { -/// Command::new("sh") -/// .arg("-c") -/// .arg("echo hello") -/// .output() -/// .expect("failed to execute process") -/// }; -/// -/// let hello = output.stdout; -/// ``` -/// -/// `Command` can be reused to spawn multiple processes. The builder methods -/// change the command without needing to immediately spawn the process. -/// -/// ```no_run -/// use std::process::Command; -/// -/// let mut echo_hello = Command::new("sh"); -/// echo_hello.arg("-c") -/// .arg("echo hello"); -/// let hello_1 = echo_hello.output().expect("failed to execute process"); -/// let hello_2 = echo_hello.output().expect("failed to execute process"); -/// ``` -/// -/// Similarly, you can call builder methods after spawning a process and then -/// spawn a new process with the modified settings. -/// -/// ```no_run -/// use std::process::Command; -/// -/// let mut list_dir = Command::new("ls"); -/// -/// // Execute `ls` in the current directory of the program. -/// list_dir.status().expect("process failed to execute"); -/// -/// println!(""); -/// -/// // Change `ls` to execute in the root directory. -/// list_dir.current_dir("/"); -/// -/// // And then execute `ls` again but in the root directory. -/// list_dir.status().expect("process failed to execute"); -/// ``` -#[stable(feature = "process", since = "1.0.0")] -pub struct Command { - inner: imp::Command, -} - -impl Command { - /// Constructs a new `Command` for launching the program at - /// path `program`, with the following default configuration: - /// - /// * No arguments to the program - /// * Inherit the current process's environment - /// * Inherit the current process's working directory - /// * Inherit stdin/stdout/stderr for `spawn` or `status`, but create pipes for `output` - /// - /// Builder methods are provided to change these defaults and - /// otherwise configure the process. - /// - /// If `program` is not an absolute path, the `PATH` will be searched in - /// an OS-defined way. - /// - /// The search path to be used may be controlled by setting the - /// `PATH` environment variable on the Command, - /// but this has some implementation limitations on Windows - /// (see ). - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("sh") - /// .spawn() - /// .expect("sh command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn new>(program: S) -> Command { - Command { inner: imp::Command::new(program.as_ref()) } - } - - /// Add an argument to pass to the program. - /// - /// Only one argument can be passed per use. So instead of: - /// - /// ```no_run - /// # std::process::Command::new("sh") - /// .arg("-C /path/to/repo") - /// # ; - /// ``` - /// - /// usage would be: - /// - /// ```no_run - /// # std::process::Command::new("sh") - /// .arg("-C") - /// .arg("/path/to/repo") - /// # ; - /// ``` - /// - /// To pass multiple arguments see [`args`]. - /// - /// [`args`]: #method.args - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .arg("-l") - /// .arg("-a") - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn arg>(&mut self, arg: S) -> &mut Command { - self.inner.arg(arg.as_ref()); - self - } - - /// Add multiple arguments to pass to the program. - /// - /// To pass a single argument see [`arg`]. - /// - /// [`arg`]: #method.arg - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .args(&["-l", "-a"]) - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn args(&mut self, args: I) -> &mut Command - where I: IntoIterator, S: AsRef - { - for arg in args { - self.arg(arg.as_ref()); - } - self - } - - /// Inserts or updates an environment variable mapping. - /// - /// Note that environment variable names are case-insensitive (but case-preserving) on Windows, - /// and case-sensitive on all other platforms. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .env("PATH", "/bin") - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn env(&mut self, key: K, val: V) -> &mut Command - where K: AsRef, V: AsRef - { - self.inner.env_mut().set(key.as_ref(), val.as_ref()); - self - } - - /// Add or update multiple environment variable mappings. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// use std::env; - /// use std::collections::HashMap; - /// - /// let filtered_env : HashMap = - /// env::vars().filter(|&(ref k, _)| - /// k == "TERM" || k == "TZ" || k == "LANG" || k == "PATH" - /// ).collect(); - /// - /// Command::new("printenv") - /// .stdin(Stdio::null()) - /// .stdout(Stdio::inherit()) - /// .env_clear() - /// .envs(&filtered_env) - /// .spawn() - /// .expect("printenv failed to start"); - /// ``` - #[stable(feature = "command_envs", since = "1.19.0")] - pub fn envs(&mut self, vars: I) -> &mut Command - where I: IntoIterator, K: AsRef, V: AsRef - { - for (ref key, ref val) in vars { - self.inner.env_mut().set(key.as_ref(), val.as_ref()); - } - self - } - - /// Removes an environment variable mapping. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .env_remove("PATH") - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn env_remove>(&mut self, key: K) -> &mut Command { - self.inner.env_mut().remove(key.as_ref()); - self - } - - /// Clears the entire environment map for the child process. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .env_clear() - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn env_clear(&mut self) -> &mut Command { - self.inner.env_mut().clear(); - self - } - - /// Sets the working directory for the child process. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .current_dir("/bin") - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn current_dir>(&mut self, dir: P) -> &mut Command { - self.inner.cwd(dir.as_ref().as_ref()); - self - } - - /// Configuration for the child process's standard input (stdin) handle. - /// - /// Defaults to [`inherit`] when used with `spawn` or `status`, and - /// defaults to [`piped`] when used with `output`. - /// - /// [`inherit`]: struct.Stdio.html#method.inherit - /// [`piped`]: struct.Stdio.html#method.piped - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// Command::new("ls") - /// .stdin(Stdio::null()) - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn stdin>(&mut self, cfg: T) -> &mut Command { - self.inner.stdin(cfg.into().0); - self - } - - /// Configuration for the child process's standard output (stdout) handle. - /// - /// Defaults to [`inherit`] when used with `spawn` or `status`, and - /// defaults to [`piped`] when used with `output`. - /// - /// [`inherit`]: struct.Stdio.html#method.inherit - /// [`piped`]: struct.Stdio.html#method.piped - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// Command::new("ls") - /// .stdout(Stdio::null()) - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn stdout>(&mut self, cfg: T) -> &mut Command { - self.inner.stdout(cfg.into().0); - self - } - - /// Configuration for the child process's standard error (stderr) handle. - /// - /// Defaults to [`inherit`] when used with `spawn` or `status`, and - /// defaults to [`piped`] when used with `output`. - /// - /// [`inherit`]: struct.Stdio.html#method.inherit - /// [`piped`]: struct.Stdio.html#method.piped - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// Command::new("ls") - /// .stderr(Stdio::null()) - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn stderr>(&mut self, cfg: T) -> &mut Command { - self.inner.stderr(cfg.into().0); - self - } - - /// Executes the command as a child process, returning a handle to it. - /// - /// By default, stdin, stdout and stderr are inherited from the parent. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn spawn(&mut self) -> io::Result { - self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner) - } - - /// Executes the command as a child process, waiting for it to finish and - /// collecting all of its output. - /// - /// By default, stdout and stderr are captured (and used to provide the - /// resulting output). Stdin is not inherited from the parent and any - /// attempt by the child process to read from the stdin stream will result - /// in the stream immediately closing. - /// - /// # Examples - /// - /// ```should_panic - /// use std::process::Command; - /// let output = Command::new("/bin/cat") - /// .arg("file.txt") - /// .output() - /// .expect("failed to execute process"); - /// - /// println!("status: {}", output.status); - /// println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - /// println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); - /// - /// assert!(output.status.success()); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn output(&mut self) -> io::Result { - self.inner.spawn(imp::Stdio::MakePipe, false).map(Child::from_inner) - .and_then(|p| p.wait_with_output()) - } - - /// Executes a command as a child process, waiting for it to finish and - /// collecting its exit status. - /// - /// By default, stdin, stdout and stderr are inherited from the parent. - /// - /// # Examples - /// - /// ```should_panic - /// use std::process::Command; - /// - /// let status = Command::new("/bin/cat") - /// .arg("file.txt") - /// .status() - /// .expect("failed to execute process"); - /// - /// println!("process exited with: {}", status); - /// - /// assert!(status.success()); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn status(&mut self) -> io::Result { - self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner) - .and_then(|mut p| p.wait()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Command { - /// Format the program and arguments of a Command for display. Any - /// non-utf8 data is lossily converted using the utf8 replacement - /// character. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.inner.fmt(f) - } -} - -impl AsInner for Command { - fn as_inner(&self) -> &imp::Command { &self.inner } -} - -impl AsInnerMut for Command { - fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner } -} - -/// The output of a finished process. -/// -/// This is returned in a Result by either the [`output`] method of a -/// [`Command`], or the [`wait_with_output`] method of a [`Child`] -/// process. -/// -/// [`Command`]: struct.Command.html -/// [`Child`]: struct.Child.html -/// [`output`]: struct.Command.html#method.output -/// [`wait_with_output`]: struct.Child.html#method.wait_with_output -#[derive(PartialEq, Eq, Clone)] -#[stable(feature = "process", since = "1.0.0")] -pub struct Output { - /// The status (exit code) of the process. - #[stable(feature = "process", since = "1.0.0")] - pub status: ExitStatus, - /// The data that the process wrote to stdout. - #[stable(feature = "process", since = "1.0.0")] - pub stdout: Vec, - /// The data that the process wrote to stderr. - #[stable(feature = "process", since = "1.0.0")] - pub stderr: Vec, -} - -// If either stderr or stdout are valid utf8 strings it prints the valid -// strings, otherwise it prints the byte sequence instead -#[stable(feature = "process_output_debug", since = "1.7.0")] -impl fmt::Debug for Output { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - - let stdout_utf8 = str::from_utf8(&self.stdout); - let stdout_debug: &dyn fmt::Debug = match stdout_utf8 { - Ok(ref str) => str, - Err(_) => &self.stdout - }; - - let stderr_utf8 = str::from_utf8(&self.stderr); - let stderr_debug: &dyn fmt::Debug = match stderr_utf8 { - Ok(ref str) => str, - Err(_) => &self.stderr - }; - - fmt.debug_struct("Output") - .field("status", &self.status) - .field("stdout", stdout_debug) - .field("stderr", stderr_debug) - .finish() - } -} - -/// Describes what to do with a standard I/O stream for a child process when -/// passed to the [`stdin`], [`stdout`], and [`stderr`] methods of [`Command`]. -/// -/// [`stdin`]: struct.Command.html#method.stdin -/// [`stdout`]: struct.Command.html#method.stdout -/// [`stderr`]: struct.Command.html#method.stderr -/// [`Command`]: struct.Command.html -#[stable(feature = "process", since = "1.0.0")] -pub struct Stdio(imp::Stdio); - -impl Stdio { - /// A new pipe should be arranged to connect the parent and child processes. - /// - /// # Examples - /// - /// With stdout: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// let output = Command::new("echo") - /// .arg("Hello, world!") - /// .stdout(Stdio::piped()) - /// .output() - /// .expect("Failed to execute command"); - /// - /// assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!\n"); - /// // Nothing echoed to console - /// ``` - /// - /// With stdin: - /// - /// ```no_run - /// use std::io::Write; - /// use std::process::{Command, Stdio}; - /// - /// let mut child = Command::new("rev") - /// .stdin(Stdio::piped()) - /// .stdout(Stdio::piped()) - /// .spawn() - /// .expect("Failed to spawn child process"); - /// - /// { - /// let mut stdin = child.stdin.as_mut().expect("Failed to open stdin"); - /// stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin"); - /// } - /// - /// let output = child.wait_with_output().expect("Failed to read stdout"); - /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH\n"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn piped() -> Stdio { Stdio(imp::Stdio::MakePipe) } - - /// The child inherits from the corresponding parent descriptor. - /// - /// # Examples - /// - /// With stdout: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// let output = Command::new("echo") - /// .arg("Hello, world!") - /// .stdout(Stdio::inherit()) - /// .output() - /// .expect("Failed to execute command"); - /// - /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); - /// // "Hello, world!" echoed to console - /// ``` - /// - /// With stdin: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// let output = Command::new("rev") - /// .stdin(Stdio::inherit()) - /// .stdout(Stdio::piped()) - /// .output() - /// .expect("Failed to execute command"); - /// - /// println!("You piped in the reverse of: {}", String::from_utf8_lossy(&output.stdout)); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) } - - /// This stream will be ignored. This is the equivalent of attaching the - /// stream to `/dev/null` - /// - /// # Examples - /// - /// With stdout: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// let output = Command::new("echo") - /// .arg("Hello, world!") - /// .stdout(Stdio::null()) - /// .output() - /// .expect("Failed to execute command"); - /// - /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); - /// // Nothing echoed to console - /// ``` - /// - /// With stdin: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// let output = Command::new("rev") - /// .stdin(Stdio::null()) - /// .stdout(Stdio::piped()) - /// .output() - /// .expect("Failed to execute command"); - /// - /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); - /// // Ignores any piped-in input - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn null() -> Stdio { Stdio(imp::Stdio::Null) } -} - -impl FromInner for Stdio { - fn from_inner(inner: imp::Stdio) -> Stdio { - Stdio(inner) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Stdio { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Stdio { .. }") - } -} - -#[stable(feature = "stdio_from", since = "1.20.0")] -impl From for Stdio { - fn from(child: ChildStdin) -> Stdio { - Stdio::from_inner(child.into_inner().into()) - } -} - -#[stable(feature = "stdio_from", since = "1.20.0")] -impl From for Stdio { - fn from(child: ChildStdout) -> Stdio { - Stdio::from_inner(child.into_inner().into()) - } -} - -#[stable(feature = "stdio_from", since = "1.20.0")] -impl From for Stdio { - fn from(child: ChildStderr) -> Stdio { - Stdio::from_inner(child.into_inner().into()) - } -} - -#[stable(feature = "stdio_from", since = "1.20.0")] -impl From for Stdio { - fn from(file: fs::File) -> Stdio { - Stdio::from_inner(file.into_inner().into()) - } -} - -/// Describes the result of a process after it has terminated. -/// -/// This `struct` is used to represent the exit status of a child process. -/// Child processes are created via the [`Command`] struct and their exit -/// status is exposed through the [`status`] method. -/// -/// [`Command`]: struct.Command.html -/// [`status`]: struct.Command.html#method.status -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[stable(feature = "process", since = "1.0.0")] -pub struct ExitStatus(imp::ExitStatus); - -impl ExitStatus { - /// Was termination successful? Signal termination is not considered a - /// success, and success is defined as a zero exit status. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::process::Command; - /// - /// let status = Command::new("mkdir") - /// .arg("projects") - /// .status() - /// .expect("failed to execute mkdir"); - /// - /// if status.success() { - /// println!("'projects/' directory created"); - /// } else { - /// println!("failed to create 'projects/' directory"); - /// } - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn success(&self) -> bool { - self.0.success() - } - - /// Returns the exit code of the process, if any. - /// - /// On Unix, this will return `None` if the process was terminated - /// by a signal; `std::os::unix` provides an extension trait for - /// extracting the signal and other details from the `ExitStatus`. - /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// let status = Command::new("mkdir") - /// .arg("projects") - /// .status() - /// .expect("failed to execute mkdir"); - /// - /// match status.code() { - /// Some(code) => println!("Exited with status code: {}", code), - /// None => println!("Process terminated by signal") - /// } - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn code(&self) -> Option { - self.0.code() - } -} - -impl AsInner for ExitStatus { - fn as_inner(&self) -> &imp::ExitStatus { &self.0 } -} - -impl FromInner for ExitStatus { - fn from_inner(s: imp::ExitStatus) -> ExitStatus { - ExitStatus(s) - } -} - -#[stable(feature = "process", since = "1.0.0")] -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -/// This type represents the status code a process can return to its -/// parent under normal termination. -/// -/// Numeric values used in this type don't have portable meanings, and -/// different platforms may mask different amounts of them. -/// -/// For the platform's canonical successful and unsuccessful codes, see -/// the [`SUCCESS`] and [`FAILURE`] associated items. -/// -/// [`SUCCESS`]: #associatedconstant.SUCCESS -/// [`FAILURE`]: #associatedconstant.FAILURE -/// -/// **Warning**: While various forms of this were discussed in [RFC #1937], -/// it was ultimately cut from that RFC, and thus this type is more subject -/// to change even than the usual unstable item churn. -/// -/// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937 -#[derive(Clone, Copy, Debug)] -#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] -pub struct ExitCode(pub u8); - -#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] -impl ExitCode { - /// The canonical ExitCode for successful termination on this platform. - /// - /// Note that a `()`-returning `main` implicitly results in a successful - /// termination, so there's no need to return this from `main` unless - /// you're also returning other possible codes. - #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] - pub const SUCCESS: ExitCode = ExitCode(0 as _); - - /// The canonical ExitCode for unsuccessful termination on this platform. - /// - /// If you're only returning this and `SUCCESS` from `main`, consider - /// instead returning `Err(_)` and `Ok(())` respectively, which will - /// return the same codes (but will also `eprintln!` the error). - #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] - pub const FAILURE: ExitCode = ExitCode(-1 as _); -} - -impl Child { - /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] - /// error is returned. - /// - /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function, - /// especially the [`Other`] kind might change to more specific kinds in the future. - /// - /// This is equivalent to sending a SIGKILL on Unix platforms. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// let mut command = Command::new("yes"); - /// if let Ok(mut child) = command.spawn() { - /// child.kill().expect("command wasn't running"); - /// } else { - /// println!("yes command didn't start"); - /// } - /// ``` - /// - /// [`ErrorKind`]: ../io/enum.ErrorKind.html - /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput - /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other - #[stable(feature = "process", since = "1.0.0")] - pub fn kill(&mut self) -> io::Result<()> { - self.handle.kill() - } - - /// Returns the OS-assigned process identifier associated with this child. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// let mut command = Command::new("ls"); - /// if let Ok(child) = command.spawn() { - /// println!("Child's id is {}", child.id()); - /// } else { - /// println!("ls command didn't start"); - /// } - /// ``` - #[stable(feature = "process_id", since = "1.3.0")] - pub fn id(&self) -> u32 { - self.handle.id() - } - - /// Waits for the child to exit completely, returning the status that it - /// exited with. This function will continue to have the same return value - /// after it has been called at least once. - /// - /// The stdin handle to the child process, if any, will be closed - /// before waiting. This helps avoid deadlock: it ensures that the - /// child does not block waiting for input from the parent, while - /// the parent waits for the child to exit. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// let mut command = Command::new("ls"); - /// if let Ok(mut child) = command.spawn() { - /// child.wait().expect("command wasn't running"); - /// println!("Child has finished its execution!"); - /// } else { - /// println!("ls command didn't start"); - /// } - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn wait(&mut self) -> io::Result { - drop(self.stdin.take()); - self.handle.wait().map(ExitStatus) - } - - /// Attempts to collect the exit status of the child if it has already - /// exited. - /// - /// This function will not block the calling thread and will only advisorily - /// check to see if the child process has exited or not. If the child has - /// exited then on Unix the process id is reaped. This function is - /// guaranteed to repeatedly return a successful exit status so long as the - /// child has already exited. - /// - /// If the child has exited, then `Ok(Some(status))` is returned. If the - /// exit status is not available at this time then `Ok(None)` is returned. - /// If an error occurs, then that error is returned. - /// - /// Note that unlike `wait`, this function will not attempt to drop stdin. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use std::process::Command; - /// - /// let mut child = Command::new("ls").spawn().unwrap(); - /// - /// match child.try_wait() { - /// Ok(Some(status)) => println!("exited with: {}", status), - /// Ok(None) => { - /// println!("status not ready yet, let's really wait"); - /// let res = child.wait(); - /// println!("result: {:?}", res); - /// } - /// Err(e) => println!("error attempting to wait: {}", e), - /// } - /// ``` - #[stable(feature = "process_try_wait", since = "1.18.0")] - pub fn try_wait(&mut self) -> io::Result> { - Ok(self.handle.try_wait()?.map(ExitStatus)) - } - - /// Simultaneously waits for the child to exit and collect all remaining - /// output on the stdout/stderr handles, returning an `Output` - /// instance. - /// - /// The stdin handle to the child process, if any, will be closed - /// before waiting. This helps avoid deadlock: it ensures that the - /// child does not block waiting for input from the parent, while - /// the parent waits for the child to exit. - /// - /// By default, stdin, stdout and stderr are inherited from the parent. - /// In order to capture the output into this `Result` it is - /// necessary to create new pipes between parent and child. Use - /// `stdout(Stdio::piped())` or `stderr(Stdio::piped())`, respectively. - /// - /// # Examples - /// - /// ```should_panic - /// use std::process::{Command, Stdio}; - /// - /// let child = Command::new("/bin/cat") - /// .arg("file.txt") - /// .stdout(Stdio::piped()) - /// .spawn() - /// .expect("failed to execute child"); - /// - /// let output = child - /// .wait_with_output() - /// .expect("failed to wait on child"); - /// - /// assert!(output.status.success()); - /// ``` - /// - #[stable(feature = "process", since = "1.0.0")] - pub fn wait_with_output(mut self) -> io::Result { - drop(self.stdin.take()); - - let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); - match (self.stdout.take(), self.stderr.take()) { - (None, None) => {} - (Some(mut out), None) => { - let res = out.read_to_end(&mut stdout); - res.unwrap(); - } - (None, Some(mut err)) => { - let res = err.read_to_end(&mut stderr); - res.unwrap(); - } - (Some(out), Some(err)) => { - let res = read2(out.inner, &mut stdout, err.inner, &mut stderr); - res.unwrap(); - } - } - - let status = self.wait()?; - Ok(Output { - status, - stdout, - stderr, - }) - } -} - -/// Terminates the current process with the specified exit code. -/// -/// This function will never return and will immediately terminate the current -/// process. The exit code is passed through to the underlying OS and will be -/// available for consumption by another process. -/// -/// Note that because this function never returns, and that it terminates the -/// process, no destructors on the current stack or any other thread's stack -/// will be run. If a clean shutdown is needed it is recommended to only call -/// this function at a known point where there are no more destructors left -/// to run. -/// -/// ## Platform-specific behavior -/// -/// **Unix**: On Unix-like platforms, it is unlikely that all 32 bits of `exit` -/// will be visible to a parent process inspecting the exit code. On most -/// Unix-like platforms, only the eight least-significant bits are considered. -/// -/// # Examples -/// -/// Due to this function’s behavior regarding destructors, a conventional way -/// to use the function is to extract the actual computation to another -/// function and compute the exit code from its return value: -/// -/// ``` -/// fn run_app() -> Result<(), ()> { -/// // Application logic here -/// Ok(()) -/// } -/// -/// fn main() { -/// ::std::process::exit(match run_app() { -/// Ok(_) => 0, -/// Err(err) => { -/// eprintln!("error: {:?}", err); -/// 1 -/// } -/// }); -/// } -/// ``` -/// -/// Due to [platform-specific behavior], the exit code for this example will be -/// `0` on Linux, but `256` on Windows: -/// -/// ```no_run -/// use std::process; -/// -/// process::exit(0x0100); -/// ``` -/// -/// [platform-specific behavior]: #platform-specific-behavior -#[stable(feature = "rust1", since = "1.0.0")] -pub fn exit(code: i32) -> ! { - ::sys_common::cleanup(); - ::sys::os::exit(code) -} - -/// Terminates the process in an abnormal fashion. -/// -/// The function will never return and will immediately terminate the current -/// process in a platform specific "abnormal" manner. -/// -/// Note that because this function never returns, and that it terminates the -/// process, no destructors on the current stack or any other thread's stack -/// will be run. -/// -/// This is in contrast to the default behaviour of [`panic!`] which unwinds -/// the current thread's stack and calls all destructors. -/// When `panic="abort"` is set, either as an argument to `rustc` or in a -/// crate's Cargo.toml, [`panic!`] and `abort` are similar. However, -/// [`panic!`] will still call the [panic hook] while `abort` will not. -/// -/// If a clean shutdown is needed it is recommended to only call -/// this function at a known point where there are no more destructors left -/// to run. -/// -/// # Examples -/// -/// ```no_run -/// use std::process; -/// -/// fn main() { -/// println!("aborting"); -/// -/// process::abort(); -/// -/// // execution never gets here -/// } -/// ``` -/// -/// The `abort` function terminates the process, so the destructor will not -/// get run on the example below: -/// -/// ```no_run -/// use std::process; -/// -/// struct HasDrop; -/// -/// impl Drop for HasDrop { -/// fn drop(&mut self) { -/// println!("This will never be printed!"); -/// } -/// } -/// -/// fn main() { -/// let _x = HasDrop; -/// process::abort(); -/// // the destructor implemented for HasDrop will never get run -/// } -/// ``` -/// -/// [`panic!`]: ../../std/macro.panic.html -/// [panic hook]: ../../std/panic/fn.set_hook.html -#[stable(feature = "process_abort", since = "1.17.0")] -pub fn abort() -> ! { - unsafe { ::sys::abort_internal() }; -} - -/// Returns the OS-assigned process identifier associated with this process. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ```no_run -/// use std::process; -/// -/// println!("My pid is {}", process::id()); -/// ``` -/// -/// -#[stable(feature = "getpid", since = "1.26.0")] -pub fn id() -> u32 { - ::sys::os::getpid() -} - -/// A trait for implementing arbitrary return types in the `main` function. -/// -/// The c-main function only supports to return integers as return type. -/// So, every type implementing the `Termination` trait has to be converted -/// to an integer. -/// -/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate -/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. -#[cfg_attr(not(test), lang = "termination")] -#[unstable(feature = "termination_trait_lib", issue = "43301")] -#[rustc_on_unimplemented( - message="`main` has invalid return type `{Self}`", - label="`main` can only return types that implement `{Termination}`")] -pub trait Termination { - /// Is called to get the representation of the value as status code. - /// This status code is returned to the operating system. - fn report(self) -> i32; -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for () { - #[inline] - fn report(self) -> i32 { ExitCode::SUCCESS.report() } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for Result<(), E> { - fn report(self) -> i32 { - match self { - Ok(()) => ().report(), - Err(err) => Err::(err).report(), - } - } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for ! { - fn report(self) -> i32 { self } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for Result { - fn report(self) -> i32 { - let Err(err) = self; - eprintln!("Error: {:?}", err); - ExitCode::FAILURE.report() - } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for ExitCode { - #[inline] - fn report(self) -> i32 { - self.0 as i32 - } -} - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] -mod tests { - use io::prelude::*; - - use io::ErrorKind; - use str; - use super::{Command, Output, Stdio}; - - // FIXME(#10380) these tests should not all be ignored on android. - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn smoke() { - let p = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 0"]).spawn() - } else { - Command::new("true").spawn() - }; - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.wait().unwrap().success()); - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn smoke_failure() { - match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() { - Ok(..) => panic!(), - Err(..) => {} - } - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn exit_reported_right() { - let p = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).spawn() - } else { - Command::new("false").spawn() - }; - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.wait().unwrap().code() == Some(1)); - drop(p.wait()); - } - - #[test] - #[cfg(unix)] - #[cfg_attr(target_os = "android", ignore)] - fn signal_reported_right() { - use os::unix::process::ExitStatusExt; - - let mut p = Command::new("/bin/sh") - .arg("-c").arg("read a") - .stdin(Stdio::piped()) - .spawn().unwrap(); - p.kill().unwrap(); - match p.wait().unwrap().signal() { - Some(9) => {}, - result => panic!("not terminated by signal 9 (instead, {:?})", - result), - } - } - - pub fn run_output(mut cmd: Command) -> String { - let p = cmd.spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.stdout.is_some()); - let mut ret = String::new(); - p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap(); - assert!(p.wait().unwrap().success()); - return ret; - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn stdout_works() { - if cfg!(target_os = "windows") { - let mut cmd = Command::new("cmd"); - cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped()); - assert_eq!(run_output(cmd), "foobar\r\n"); - } else { - let mut cmd = Command::new("echo"); - cmd.arg("foobar").stdout(Stdio::piped()); - assert_eq!(run_output(cmd), "foobar\n"); - } - } - - #[test] - #[cfg_attr(any(windows, target_os = "android"), ignore)] - fn set_current_dir_works() { - let mut cmd = Command::new("/bin/sh"); - cmd.arg("-c").arg("pwd") - .current_dir("/") - .stdout(Stdio::piped()); - assert_eq!(run_output(cmd), "/\n"); - } - - #[test] - #[cfg_attr(any(windows, target_os = "android"), ignore)] - fn stdin_works() { - let mut p = Command::new("/bin/sh") - .arg("-c").arg("read line; echo $line") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn().unwrap(); - p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap(); - drop(p.stdin.take()); - let mut out = String::new(); - p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap(); - assert!(p.wait().unwrap().success()); - assert_eq!(out, "foobar\n"); - } - - - #[test] - #[cfg_attr(target_os = "android", ignore)] - #[cfg(unix)] - fn uid_works() { - use os::unix::prelude::*; - use libc; - let mut p = Command::new("/bin/sh") - .arg("-c").arg("true") - .uid(unsafe { libc::getuid() }) - .gid(unsafe { libc::getgid() }) - .spawn().unwrap(); - assert!(p.wait().unwrap().success()); - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - #[cfg(unix)] - fn uid_to_root_fails() { - use os::unix::prelude::*; - use libc; - - // if we're already root, this isn't a valid test. Most of the bots run - // as non-root though (android is an exception). - if unsafe { libc::getuid() == 0 } { return } - assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err()); - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn test_process_status() { - let mut status = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap() - } else { - Command::new("false").status().unwrap() - }; - assert!(status.code() == Some(1)); - - status = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap() - } else { - Command::new("true").status().unwrap() - }; - assert!(status.success()); - } - - #[test] - fn test_process_output_fail_to_start() { - match Command::new("/no-binary-by-this-name-should-exist").output() { - Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound), - Ok(..) => panic!() - } - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn test_process_output_output() { - let Output {status, stdout, stderr} - = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap() - } else { - Command::new("echo").arg("hello").output().unwrap() - }; - let output_str = str::from_utf8(&stdout).unwrap(); - - assert!(status.success()); - assert_eq!(output_str.trim().to_string(), "hello"); - assert_eq!(stderr, Vec::new()); - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn test_process_output_error() { - let Output {status, stdout, stderr} - = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap() - } else { - Command::new("mkdir").arg("./").output().unwrap() - }; - - assert!(status.code() == Some(1)); - assert_eq!(stdout, Vec::new()); - assert!(!stderr.is_empty()); - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn test_finish_once() { - let mut prog = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() - } else { - Command::new("false").spawn().unwrap() - }; - assert!(prog.wait().unwrap().code() == Some(1)); - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn test_finish_twice() { - let mut prog = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() - } else { - Command::new("false").spawn().unwrap() - }; - assert!(prog.wait().unwrap().code() == Some(1)); - assert!(prog.wait().unwrap().code() == Some(1)); - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn test_wait_with_output_once() { - let prog = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap() - } else { - Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap() - }; - - let Output {status, stdout, stderr} = prog.wait_with_output().unwrap(); - let output_str = str::from_utf8(&stdout).unwrap(); - - assert!(status.success()); - assert_eq!(output_str.trim().to_string(), "hello"); - assert_eq!(stderr, Vec::new()); - } - - #[cfg(all(unix, not(target_os="android")))] - pub fn env_cmd() -> Command { - Command::new("env") - } - #[cfg(target_os="android")] - pub fn env_cmd() -> Command { - let mut cmd = Command::new("/system/bin/sh"); - cmd.arg("-c").arg("set"); - cmd - } - - #[cfg(windows)] - pub fn env_cmd() -> Command { - let mut cmd = Command::new("cmd"); - cmd.arg("/c").arg("set"); - cmd - } - - #[test] - fn test_inherit_env() { - use env; - - let result = env_cmd().output().unwrap(); - let output = String::from_utf8(result.stdout).unwrap(); - - for (ref k, ref v) in env::vars() { - // Don't check android RANDOM variable which seems to change - // whenever the shell runs, and our `env_cmd` is indeed running a - // shell which means it'll get a different RANDOM than we probably - // have. - // - // Also skip env vars with `-` in the name on android because, well, - // I'm not sure. It appears though that the `set` command above does - // not print env vars with `-` in the name, so we just skip them - // here as we won't find them in the output. Note that most env vars - // use `_` instead of `-`, but our build system sets a few env vars - // with `-` in the name. - if cfg!(target_os = "android") && - (*k == "RANDOM" || k.contains("-")) { - continue - } - - // Windows has hidden environment variables whose names start with - // equals signs (`=`). Those do not show up in the output of the - // `set` command. - assert!((cfg!(windows) && k.starts_with("=")) || - k.starts_with("DYLD") || - output.contains(&format!("{}={}", *k, *v)) || - output.contains(&format!("{}='{}'", *k, *v)), - "output doesn't contain `{}={}`\n{}", - k, v, output); - } - } - - #[test] - fn test_override_env() { - use env; - - // In some build environments (such as chrooted Nix builds), `env` can - // only be found in the explicitly-provided PATH env variable, not in - // default places such as /bin or /usr/bin. So we need to pass through - // PATH to our sub-process. - let mut cmd = env_cmd(); - cmd.env_clear().env("RUN_TEST_NEW_ENV", "123"); - if let Some(p) = env::var_os("PATH") { - cmd.env("PATH", &p); - } - let result = cmd.output().unwrap(); - let output = String::from_utf8_lossy(&result.stdout).to_string(); - - assert!(output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); - } - - #[test] - fn test_add_to_env() { - let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap(); - let output = String::from_utf8_lossy(&result.stdout).to_string(); - - assert!(output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); - } - - #[test] - fn test_capture_env_at_spawn() { - use env; - - let mut cmd = env_cmd(); - cmd.env("RUN_TEST_NEW_ENV1", "123"); - - // This variable will not be present if the environment has already - // been captured above. - env::set_var("RUN_TEST_NEW_ENV2", "456"); - let result = cmd.output().unwrap(); - env::remove_var("RUN_TEST_NEW_ENV2"); - - let output = String::from_utf8_lossy(&result.stdout).to_string(); - - assert!(output.contains("RUN_TEST_NEW_ENV1=123"), - "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}", output); - assert!(output.contains("RUN_TEST_NEW_ENV2=456"), - "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}", output); - } - - // Regression tests for #30858. - #[test] - fn test_interior_nul_in_progname_is_error() { - match Command::new("has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - fn test_interior_nul_in_arg_is_error() { - match Command::new("echo").arg("has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - fn test_interior_nul_in_args_is_error() { - match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - fn test_interior_nul_in_current_dir_is_error() { - match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - // Regression tests for #30862. - #[test] - fn test_interior_nul_in_env_key_is_error() { - match env_cmd().env("has-some-\0\0s-inside", "value").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - fn test_interior_nul_in_env_value_is_error() { - match env_cmd().env("key", "has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - /// Test that process creation flags work by debugging a process. - /// Other creation flags make it hard or impossible to detect - /// behavioral changes in the process. - #[test] - #[cfg(windows)] - fn test_creation_flags() { - use os::windows::process::CommandExt; - use sys::c::{BOOL, DWORD, INFINITE}; - #[repr(C, packed)] - struct DEBUG_EVENT { - pub event_code: DWORD, - pub process_id: DWORD, - pub thread_id: DWORD, - // This is a union in the real struct, but we don't - // need this data for the purposes of this test. - pub _junk: [u8; 164], - } - - extern "system" { - fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; - fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD, - dwContinueStatus: DWORD) -> BOOL; - } - - const DEBUG_PROCESS: DWORD = 1; - const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; - const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; - - let mut child = Command::new("cmd") - .creation_flags(DEBUG_PROCESS) - .stdin(Stdio::piped()).spawn().unwrap(); - child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); - let mut events = 0; - let mut event = DEBUG_EVENT { - event_code: 0, - process_id: 0, - thread_id: 0, - _junk: [0; 164], - }; - loop { - if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 { - panic!("WaitForDebugEvent failed!"); - } - events += 1; - - if event.event_code == EXIT_PROCESS_DEBUG_EVENT { - break; - } - - if unsafe { ContinueDebugEvent(event.process_id, - event.thread_id, - DBG_EXCEPTION_NOT_HANDLED) } == 0 { - panic!("ContinueDebugEvent failed!"); - } - } - assert!(events > 0); - } - - #[test] - fn test_command_implements_send() { - fn take_send_type(_: T) {} - take_send_type(Command::new("")) - } -} diff --git a/ctr-std/src/rt.rs b/ctr-std/src/rt.rs deleted file mode 100644 index fdaf2a8..0000000 --- a/ctr-std/src/rt.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Runtime services -//! -//! The `rt` module provides a narrow set of runtime services, -//! including the global heap (exported in `heap`) and unwinding and -//! backtrace support. The APIs in this module are highly unstable, -//! and should be considered as private implementation details for the -//! time being. - -#![unstable(feature = "rt", - reason = "this public module should not exist and is highly likely \ - to disappear", - issue = "0")] -#![doc(hidden)] - - -// Re-export some of our utilities which are expected by other crates. -pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count}; - -// To reduce the generated code of the new `lang_start`, this function is doing -// the real work. -#[cfg(not(test))] -fn lang_start_internal(main: &(dyn Fn() -> i32 + Sync + ::panic::RefUnwindSafe), - argc: isize, argv: *const *const u8) -> isize { - use panic; - use sys; - use sys_common; - use sys_common::thread_info; - use thread::Thread; - - sys::init(); - - unsafe { - let main_guard = sys::thread::guard::init(); - sys::stack_overflow::init(); - - // Next, set up the current Thread with the guard information we just - // created. Note that this isn't necessary in general for new threads, - // but we just do this to name the main thread and to give it correct - // info about the stack bounds. - let thread = Thread::new(Some("main".to_owned())); - thread_info::set(main_guard, thread); - - // Store our args if necessary in a squirreled away location - sys::args::init(argc, argv); - - // Let's run some code! - #[cfg(feature = "backtrace")] - let exit_code = panic::catch_unwind(|| { - ::sys_common::backtrace::__rust_begin_short_backtrace(move || main()) - }); - #[cfg(not(feature = "backtrace"))] - let exit_code = panic::catch_unwind(move || main()); - - sys_common::cleanup(); - exit_code.unwrap_or(101) as isize - } -} - -#[cfg(not(test))] -#[lang = "start"] -fn lang_start - (main: fn() -> T, argc: isize, argv: *const *const u8) -> isize -{ - lang_start_internal(&move || main().report(), argc, argv) -} diff --git a/ctr-std/src/sync/barrier.rs b/ctr-std/src/sync/barrier.rs deleted file mode 100644 index 273c7c1..0000000 --- a/ctr-std/src/sync/barrier.rs +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use fmt; -use sync::{Mutex, Condvar}; - -/// A barrier enables multiple threads to synchronize the beginning -/// of some computation. -/// -/// # Examples -/// -/// ``` -/// use std::sync::{Arc, Barrier}; -/// use std::thread; -/// -/// let mut handles = Vec::with_capacity(10); -/// let barrier = Arc::new(Barrier::new(10)); -/// for _ in 0..10 { -/// let c = barrier.clone(); -/// // The same messages will be printed together. -/// // You will NOT see any interleaving. -/// handles.push(thread::spawn(move|| { -/// println!("before wait"); -/// c.wait(); -/// println!("after wait"); -/// })); -/// } -/// // Wait for other threads to finish. -/// for handle in handles { -/// handle.join().unwrap(); -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Barrier { - lock: Mutex, - cvar: Condvar, - num_threads: usize, -} - -// The inner state of a double barrier -struct BarrierState { - count: usize, - generation_id: usize, -} - -/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`] -/// have rendezvoused. -/// -/// [`wait`]: struct.Barrier.html#method.wait -/// [`Barrier`]: struct.Barrier.html -/// -/// # Examples -/// -/// ``` -/// use std::sync::Barrier; -/// -/// let barrier = Barrier::new(1); -/// let barrier_wait_result = barrier.wait(); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BarrierWaitResult(bool); - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Barrier { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Barrier { .. }") - } -} - -impl Barrier { - /// Creates a new barrier that can block a given number of threads. - /// - /// A barrier will block `n`-1 threads which call [`wait`] and then wake up - /// all threads at once when the `n`th thread calls [`wait`]. - /// - /// [`wait`]: #method.wait - /// - /// # Examples - /// - /// ``` - /// use std::sync::Barrier; - /// - /// let barrier = Barrier::new(10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(n: usize) -> Barrier { - Barrier { - lock: Mutex::new(BarrierState { - count: 0, - generation_id: 0, - }), - cvar: Condvar::new(), - num_threads: n, - } - } - - /// Blocks the current thread until all threads have rendezvoused here. - /// - /// Barriers are re-usable after all threads have rendezvoused once, and can - /// be used continuously. - /// - /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that - /// returns `true` from [`is_leader`] when returning from this function, and - /// all other threads will receive a result that will return `false` from - /// [`is_leader`]. - /// - /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html - /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Barrier}; - /// use std::thread; - /// - /// let mut handles = Vec::with_capacity(10); - /// let barrier = Arc::new(Barrier::new(10)); - /// for _ in 0..10 { - /// let c = barrier.clone(); - /// // The same messages will be printed together. - /// // You will NOT see any interleaving. - /// handles.push(thread::spawn(move|| { - /// println!("before wait"); - /// c.wait(); - /// println!("after wait"); - /// })); - /// } - /// // Wait for other threads to finish. - /// for handle in handles { - /// handle.join().unwrap(); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn wait(&self) -> BarrierWaitResult { - let mut lock = self.lock.lock().unwrap(); - let local_gen = lock.generation_id; - lock.count += 1; - if lock.count < self.num_threads { - // We need a while loop to guard against spurious wakeups. - // http://en.wikipedia.org/wiki/Spurious_wakeup - while local_gen == lock.generation_id && - lock.count < self.num_threads { - lock = self.cvar.wait(lock).unwrap(); - } - BarrierWaitResult(false) - } else { - lock.count = 0; - lock.generation_id = lock.generation_id.wrapping_add(1); - self.cvar.notify_all(); - BarrierWaitResult(true) - } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for BarrierWaitResult { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("BarrierWaitResult") - .field("is_leader", &self.is_leader()) - .finish() - } -} - -impl BarrierWaitResult { - /// Returns whether this thread from [`wait`] is the "leader thread". - /// - /// Only one thread will have `true` returned from their result, all other - /// threads will have `false` returned. - /// - /// [`wait`]: struct.Barrier.html#method.wait - /// - /// # Examples - /// - /// ``` - /// use std::sync::Barrier; - /// - /// let barrier = Barrier::new(1); - /// let barrier_wait_result = barrier.wait(); - /// println!("{:?}", barrier_wait_result.is_leader()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_leader(&self) -> bool { self.0 } -} - -#[cfg(test)] -mod tests { - use sync::{Arc, Barrier}; - use sync::mpsc::{channel, TryRecvError}; - use thread; - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn test_barrier() { - const N: usize = 10; - - let barrier = Arc::new(Barrier::new(N)); - let (tx, rx) = channel(); - - for _ in 0..N - 1 { - let c = barrier.clone(); - let tx = tx.clone(); - thread::spawn(move|| { - tx.send(c.wait().is_leader()).unwrap(); - }); - } - - // At this point, all spawned threads should be blocked, - // so we shouldn't get anything from the port - assert!(match rx.try_recv() { - Err(TryRecvError::Empty) => true, - _ => false, - }); - - let mut leader_found = barrier.wait().is_leader(); - - // Now, the barrier is cleared and we should get data. - for _ in 0..N - 1 { - if rx.recv().unwrap() { - assert!(!leader_found); - leader_found = true; - } - } - assert!(leader_found); - } -} diff --git a/ctr-std/src/sync/condvar.rs b/ctr-std/src/sync/condvar.rs deleted file mode 100644 index 3014283..0000000 --- a/ctr-std/src/sync/condvar.rs +++ /dev/null @@ -1,839 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use fmt; -use sync::atomic::{AtomicUsize, Ordering}; -use sync::{mutex, MutexGuard, PoisonError}; -use sys_common::condvar as sys; -use sys_common::mutex as sys_mutex; -use sys_common::poison::{self, LockResult}; -use time::{Duration, Instant}; - -/// A type indicating whether a timed wait on a condition variable returned -/// due to a time out or not. -/// -/// It is returned by the [`wait_timeout`] method. -/// -/// [`wait_timeout`]: struct.Condvar.html#method.wait_timeout -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -#[stable(feature = "wait_timeout", since = "1.5.0")] -pub struct WaitTimeoutResult(bool); - -impl WaitTimeoutResult { - /// Returns whether the wait was known to have timed out. - /// - /// # Examples - /// - /// This example spawns a thread which will update the boolean value and - /// then wait 100 milliseconds before notifying the condvar. - /// - /// The main thread will wait with a timeout on the condvar and then leave - /// once the boolean has been updated and notified. - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// use std::time::Duration; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; - /// - /// // Let's wait 20 milliseconds before notifying the condvar. - /// thread::sleep(Duration::from_millis(20)); - /// - /// let mut started = lock.lock().unwrap(); - /// // We update the boolean value. - /// *started = true; - /// cvar.notify_one(); - /// }); - /// - /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; - /// let mut started = lock.lock().unwrap(); - /// loop { - /// // Let's put a timeout on the condvar's wait. - /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap(); - /// // 10 milliseconds have passed, or maybe the value changed! - /// started = result.0; - /// if *started == true { - /// // We received the notification and the value has been updated, we can leave. - /// break - /// } - /// } - /// ``` - #[stable(feature = "wait_timeout", since = "1.5.0")] - pub fn timed_out(&self) -> bool { - self.0 - } -} - -/// A Condition Variable -/// -/// Condition variables represent the ability to block a thread such that it -/// consumes no CPU time while waiting for an event to occur. Condition -/// variables are typically associated with a boolean predicate (a condition) -/// and a mutex. The predicate is always verified inside of the mutex before -/// determining that a thread must block. -/// -/// Functions in this module will block the current **thread** of execution and -/// are bindings to system-provided condition variables where possible. Note -/// that this module places one additional restriction over the system condition -/// variables: each condvar can be used with precisely one mutex at runtime. Any -/// attempt to use multiple mutexes on the same condition variable will result -/// in a runtime panic. If this is not desired, then the unsafe primitives in -/// `sys` do not have this restriction but may result in undefined behavior. -/// -/// # Examples -/// -/// ``` -/// use std::sync::{Arc, Mutex, Condvar}; -/// use std::thread; -/// -/// let pair = Arc::new((Mutex::new(false), Condvar::new())); -/// let pair2 = pair.clone(); -/// -/// // Inside of our lock, spawn a new thread, and then wait for it to start. -/// thread::spawn(move|| { -/// let &(ref lock, ref cvar) = &*pair2; -/// let mut started = lock.lock().unwrap(); -/// *started = true; -/// // We notify the condvar that the value has changed. -/// cvar.notify_one(); -/// }); -/// -/// // Wait for the thread to start up. -/// let &(ref lock, ref cvar) = &*pair; -/// let mut started = lock.lock().unwrap(); -/// while !*started { -/// started = cvar.wait(started).unwrap(); -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Condvar { - inner: Box, - mutex: AtomicUsize, -} - -impl Condvar { - /// Creates a new condition variable which is ready to be waited on and - /// notified. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Condvar; - /// - /// let condvar = Condvar::new(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> Condvar { - let mut c = Condvar { - inner: box sys::Condvar::new(), - mutex: AtomicUsize::new(0), - }; - unsafe { - c.inner.init(); - } - c - } - - /// Blocks the current thread until this condition variable receives a - /// notification. - /// - /// This function will atomically unlock the mutex specified (represented by - /// `guard`) and block the current thread. This means that any calls - /// to [`notify_one`] or [`notify_all`] which happen logically after the - /// mutex is unlocked are candidates to wake this thread up. When this - /// function call returns, the lock specified will have been re-acquired. - /// - /// Note that this function is susceptible to spurious wakeups. Condition - /// variables normally have a boolean predicate associated with them, and - /// the predicate must always be checked each time this function returns to - /// protect against spurious wakeups. - /// - /// # Errors - /// - /// This function will return an error if the mutex being waited on is - /// poisoned when this thread re-acquires the lock. For more information, - /// see information about [poisoning] on the [`Mutex`] type. - /// - /// # Panics - /// - /// This function will [`panic!`] if it is used with more than one mutex - /// over time. Each condition variable is dynamically bound to exactly one - /// mutex to ensure defined behavior across platforms. If this functionality - /// is not desired, then unsafe primitives in `sys` are provided. - /// - /// [`notify_one`]: #method.notify_one - /// [`notify_all`]: #method.notify_all - /// [poisoning]: ../sync/struct.Mutex.html#poisoning - /// [`Mutex`]: ../sync/struct.Mutex.html - /// [`panic!`]: ../../std/macro.panic.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; - /// let mut started = lock.lock().unwrap(); - /// *started = true; - /// // We notify the condvar that the value has changed. - /// cvar.notify_one(); - /// }); - /// - /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; - /// let mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. - /// while !*started { - /// started = cvar.wait(started).unwrap(); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) - -> LockResult> { - let poisoned = unsafe { - let lock = mutex::guard_lock(&guard); - self.verify(lock); - self.inner.wait(lock); - mutex::guard_poison(&guard).get() - }; - if poisoned { - Err(PoisonError::new(guard)) - } else { - Ok(guard) - } - } - - /// Blocks the current thread until this condition variable receives a - /// notification and the required condition is met. Spurious wakeups are - /// ignored and this function will only return once the condition has been - /// met. - /// - /// This function will atomically unlock the mutex specified (represented by - /// `guard`) and block the current thread. This means that any calls - /// to [`notify_one`] or [`notify_all`] which happen logically after the - /// mutex is unlocked are candidates to wake this thread up. When this - /// function call returns, the lock specified will have been re-acquired. - /// - /// # Errors - /// - /// This function will return an error if the mutex being waited on is - /// poisoned when this thread re-acquires the lock. For more information, - /// see information about [poisoning] on the [`Mutex`] type. - /// - /// [`notify_one`]: #method.notify_one - /// [`notify_all`]: #method.notify_all - /// [poisoning]: ../sync/struct.Mutex.html#poisoning - /// [`Mutex`]: ../sync/struct.Mutex.html - /// - /// # Examples - /// - /// ``` - /// #![feature(wait_until)] - /// - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; - /// let mut started = lock.lock().unwrap(); - /// *started = true; - /// // We notify the condvar that the value has changed. - /// cvar.notify_one(); - /// }); - /// - /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; - /// // As long as the value inside the `Mutex` is false, we wait. - /// let _guard = cvar.wait_until(lock.lock().unwrap(), |started| { *started }).unwrap(); - /// ``` - #[unstable(feature = "wait_until", issue = "47960")] - pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, - mut condition: F) - -> LockResult> - where F: FnMut(&mut T) -> bool { - while !condition(&mut *guard) { - guard = self.wait(guard)?; - } - Ok(guard) - } - - - /// Waits on this condition variable for a notification, timing out after a - /// specified duration. - /// - /// The semantics of this function are equivalent to [`wait`] - /// except that the thread will be blocked for roughly no longer - /// than `ms` milliseconds. This method should not be used for - /// precise timing due to anomalies such as preemption or platform - /// differences that may not cause the maximum amount of time - /// waited to be precisely `ms`. - /// - /// Note that the best effort is made to ensure that the time waited is - /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. - /// - /// The returned boolean is `false` only if the timeout is known - /// to have elapsed. - /// - /// Like [`wait`], the lock specified will be re-acquired when this function - /// returns, regardless of whether the timeout elapsed or not. - /// - /// [`wait`]: #method.wait - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; - /// let mut started = lock.lock().unwrap(); - /// *started = true; - /// // We notify the condvar that the value has changed. - /// cvar.notify_one(); - /// }); - /// - /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; - /// let mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. - /// loop { - /// let result = cvar.wait_timeout_ms(started, 10).unwrap(); - /// // 10 milliseconds have passed, or maybe the value changed! - /// started = result.0; - /// if *started == true { - /// // We received the notification and the value has been updated, we can leave. - /// break - /// } - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")] - pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32) - -> LockResult<(MutexGuard<'a, T>, bool)> { - let res = self.wait_timeout(guard, Duration::from_millis(ms as u64)); - poison::map_result(res, |(a, b)| { - (a, !b.timed_out()) - }) - } - - /// Waits on this condition variable for a notification, timing out after a - /// specified duration. - /// - /// The semantics of this function are equivalent to [`wait`] except that - /// the thread will be blocked for roughly no longer than `dur`. This - /// method should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum - /// amount of time waited to be precisely `dur`. - /// - /// Note that the best effort is made to ensure that the time waited is - /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. This function is susceptible to spurious wakeups. - /// Condition variables normally have a boolean predicate associated with - /// them, and the predicate must always be checked each time this function - /// returns to protect against spurious wakeups. Additionally, it is - /// typically desirable for the time-out to not exceed some duration in - /// spite of spurious wakes, thus the sleep-duration is decremented by the - /// amount slept. Alternatively, use the `wait_timeout_until` method - /// to wait until a condition is met with a total time-out regardless - /// of spurious wakes. - /// - /// The returned [`WaitTimeoutResult`] value indicates if the timeout is - /// known to have elapsed. - /// - /// Like [`wait`], the lock specified will be re-acquired when this function - /// returns, regardless of whether the timeout elapsed or not. - /// - /// [`wait`]: #method.wait - /// [`wait_timeout_until`]: #method.wait_timeout_until - /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// use std::time::Duration; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; - /// let mut started = lock.lock().unwrap(); - /// *started = true; - /// // We notify the condvar that the value has changed. - /// cvar.notify_one(); - /// }); - /// - /// // wait for the thread to start up - /// let &(ref lock, ref cvar) = &*pair; - /// let mut started = lock.lock().unwrap(); - /// // as long as the value inside the `Mutex` is false, we wait - /// loop { - /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap(); - /// // 10 milliseconds have passed, or maybe the value changed! - /// started = result.0; - /// if *started == true { - /// // We received the notification and the value has been updated, we can leave. - /// break - /// } - /// } - /// ``` - #[stable(feature = "wait_timeout", since = "1.5.0")] - pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, - dur: Duration) - -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> { - let (poisoned, result) = unsafe { - let lock = mutex::guard_lock(&guard); - self.verify(lock); - let success = self.inner.wait_timeout(lock, dur); - (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success)) - }; - if poisoned { - Err(PoisonError::new((guard, result))) - } else { - Ok((guard, result)) - } - } - - /// Waits on this condition variable for a notification, timing out after a - /// specified duration. Spurious wakes will not cause this function to - /// return. - /// - /// The semantics of this function are equivalent to [`wait_until`] except - /// that the thread will be blocked for roughly no longer than `dur`. This - /// method should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum - /// amount of time waited to be precisely `dur`. - /// - /// Note that the best effort is made to ensure that the time waited is - /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. - /// - /// The returned [`WaitTimeoutResult`] value indicates if the timeout is - /// known to have elapsed without the condition being met. - /// - /// Like [`wait_until`], the lock specified will be re-acquired when this - /// function returns, regardless of whether the timeout elapsed or not. - /// - /// [`wait_until`]: #method.wait_until - /// [`wait_timeout`]: #method.wait_timeout - /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html - /// - /// # Examples - /// - /// ``` - /// #![feature(wait_timeout_until)] - /// - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// use std::time::Duration; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; - /// let mut started = lock.lock().unwrap(); - /// *started = true; - /// // We notify the condvar that the value has changed. - /// cvar.notify_one(); - /// }); - /// - /// // wait for the thread to start up - /// let &(ref lock, ref cvar) = &*pair; - /// let result = cvar.wait_timeout_until( - /// lock.lock().unwrap(), - /// Duration::from_millis(100), - /// |&mut started| started, - /// ).unwrap(); - /// if result.1.timed_out() { - /// // timed-out without the condition ever evaluating to true. - /// } - /// // access the locked mutex via result.0 - /// ``` - #[unstable(feature = "wait_timeout_until", issue = "47960")] - pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, - dur: Duration, mut condition: F) - -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> - where F: FnMut(&mut T) -> bool { - let start = Instant::now(); - loop { - if condition(&mut *guard) { - return Ok((guard, WaitTimeoutResult(false))); - } - let timeout = match dur.checked_sub(start.elapsed()) { - Some(timeout) => timeout, - None => return Ok((guard, WaitTimeoutResult(true))), - }; - guard = self.wait_timeout(guard, timeout)?.0; - } - } - - /// Wakes up one blocked thread on this condvar. - /// - /// If there is a blocked thread on this condition variable, then it will - /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to - /// `notify_one` are not buffered in any way. - /// - /// To wake up all threads, see [`notify_all`]. - /// - /// [`wait`]: #method.wait - /// [`wait_timeout`]: #method.wait_timeout - /// [`notify_all`]: #method.notify_all - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; - /// let mut started = lock.lock().unwrap(); - /// *started = true; - /// // We notify the condvar that the value has changed. - /// cvar.notify_one(); - /// }); - /// - /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; - /// let mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. - /// while !*started { - /// started = cvar.wait(started).unwrap(); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn notify_one(&self) { - unsafe { self.inner.notify_one() } - } - - /// Wakes up all blocked threads on this condvar. - /// - /// This method will ensure that any current waiters on the condition - /// variable are awoken. Calls to `notify_all()` are not buffered in any - /// way. - /// - /// To wake up only one thread, see [`notify_one`]. - /// - /// [`notify_one`]: #method.notify_one - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; - /// let mut started = lock.lock().unwrap(); - /// *started = true; - /// // We notify the condvar that the value has changed. - /// cvar.notify_all(); - /// }); - /// - /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; - /// let mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. - /// while !*started { - /// started = cvar.wait(started).unwrap(); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn notify_all(&self) { - unsafe { self.inner.notify_all() } - } - - fn verify(&self, mutex: &sys_mutex::Mutex) { - let addr = mutex as *const _ as usize; - match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) { - // If we got out 0, then we have successfully bound the mutex to - // this cvar. - 0 => {} - - // If we get out a value that's the same as `addr`, then someone - // already beat us to the punch. - n if n == addr => {} - - // Anything else and we're using more than one mutex on this cvar, - // which is currently disallowed. - _ => panic!("attempted to use a condition variable with two \ - mutexes"), - } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Condvar { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Condvar { .. }") - } -} - -#[stable(feature = "condvar_default", since = "1.10.0")] -impl Default for Condvar { - /// Creates a `Condvar` which is ready to be waited on and notified. - fn default() -> Condvar { - Condvar::new() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Condvar { - fn drop(&mut self) { - unsafe { self.inner.destroy() } - } -} - -#[cfg(test)] -mod tests { - /// #![feature(wait_until)] - use sync::mpsc::channel; - use sync::{Condvar, Mutex, Arc}; - use sync::atomic::{AtomicBool, Ordering}; - use thread; - use time::Duration; - use u64; - - #[test] - fn smoke() { - let c = Condvar::new(); - c.notify_one(); - c.notify_all(); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn notify_one() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let g = m.lock().unwrap(); - let _t = thread::spawn(move|| { - let _g = m2.lock().unwrap(); - c2.notify_one(); - }); - let g = c.wait(g).unwrap(); - drop(g); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn notify_all() { - const N: usize = 10; - - let data = Arc::new((Mutex::new(0), Condvar::new())); - let (tx, rx) = channel(); - for _ in 0..N { - let data = data.clone(); - let tx = tx.clone(); - thread::spawn(move|| { - let &(ref lock, ref cond) = &*data; - let mut cnt = lock.lock().unwrap(); - *cnt += 1; - if *cnt == N { - tx.send(()).unwrap(); - } - while *cnt != 0 { - cnt = cond.wait(cnt).unwrap(); - } - tx.send(()).unwrap(); - }); - } - drop(tx); - - let &(ref lock, ref cond) = &*data; - rx.recv().unwrap(); - let mut cnt = lock.lock().unwrap(); - *cnt = 0; - cond.notify_all(); - drop(cnt); - - for _ in 0..N { - rx.recv().unwrap(); - } - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_until() { - let pair = Arc::new((Mutex::new(false), Condvar::new())); - let pair2 = pair.clone(); - - // Inside of our lock, spawn a new thread, and then wait for it to start. - thread::spawn(move|| { - let &(ref lock, ref cvar) = &*pair2; - let mut started = lock.lock().unwrap(); - *started = true; - // We notify the condvar that the value has changed. - cvar.notify_one(); - }); - - // Wait for the thread to start up. - let &(ref lock, ref cvar) = &*pair; - let guard = cvar.wait_until(lock.lock().unwrap(), |started| { - *started - }); - assert!(*guard.unwrap()); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_wait() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - loop { - let g = m.lock().unwrap(); - let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap(); - // spurious wakeups mean this isn't necessarily true - // so execute test again, if not timeout - if !no_timeout.timed_out() { - continue; - } - - break; - } - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_until_wait() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - let g = m.lock().unwrap(); - let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), |_| { false }).unwrap(); - // no spurious wakeups. ensure it timed-out - assert!(wait.timed_out()); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_until_instant_satisfy() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - let g = m.lock().unwrap(); - let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), |_| { true }).unwrap(); - // ensure it didn't time-out even if we were not given any time. - assert!(!wait.timed_out()); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_until_wake() { - let pair = Arc::new((Mutex::new(false), Condvar::new())); - let pair_copy = pair.clone(); - - let &(ref m, ref c) = &*pair; - let g = m.lock().unwrap(); - let _t = thread::spawn(move || { - let &(ref lock, ref cvar) = &*pair_copy; - let mut started = lock.lock().unwrap(); - thread::sleep(Duration::from_millis(1)); - *started = true; - cvar.notify_one(); - }); - let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |&mut notified| { - notified - }).unwrap(); - // ensure it didn't time-out even if we were not given any time. - assert!(!wait.timed_out()); - assert!(*g2); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_wake() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - loop { - let g = m.lock().unwrap(); - - let c2 = c.clone(); - let m2 = m.clone(); - - let notified = Arc::new(AtomicBool::new(false)); - let notified_copy = notified.clone(); - - let t = thread::spawn(move || { - let _g = m2.lock().unwrap(); - thread::sleep(Duration::from_millis(1)); - notified_copy.store(true, Ordering::SeqCst); - c2.notify_one(); - }); - let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap(); - assert!(!timeout_res.timed_out()); - // spurious wakeups mean this isn't necessarily true - // so execute test again, if not notified - if !notified.load(Ordering::SeqCst) { - t.join().unwrap(); - continue; - } - drop(g); - - t.join().unwrap(); - - break; - } - } - - #[test] - #[should_panic] - #[cfg_attr(target_os = "emscripten", ignore)] - fn two_mutexes() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock().unwrap(); - let _t = thread::spawn(move|| { - let _g = m2.lock().unwrap(); - c2.notify_one(); - }); - g = c.wait(g).unwrap(); - drop(g); - - let m = Mutex::new(()); - let _ = c.wait(m.lock().unwrap()).unwrap(); - } -} diff --git a/ctr-std/src/sync/mod.rs b/ctr-std/src/sync/mod.rs deleted file mode 100644 index e12ef8d..0000000 --- a/ctr-std/src/sync/mod.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Useful synchronization primitives. -//! -//! This module contains useful safe and unsafe synchronization primitives. -//! Most of the primitives in this module do not provide any sort of locking -//! and/or blocking at all, but rather provide the necessary tools to build -//! other types of concurrent primitives. - -#![stable(feature = "rust1", since = "1.0.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::sync::{Arc, Weak}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::sync::atomic; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::barrier::{Barrier, BarrierWaitResult}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::condvar::{Condvar, WaitTimeoutResult}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::mutex::{Mutex, MutexGuard}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::once::{Once, OnceState, ONCE_INIT}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use sys_common::poison::{PoisonError, TryLockError, TryLockResult, LockResult}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; - -pub mod mpsc; - -mod barrier; -mod condvar; -mod mutex; -mod once; -mod rwlock; diff --git a/ctr-std/src/sync/mpsc/blocking.rs b/ctr-std/src/sync/mpsc/blocking.rs deleted file mode 100644 index c08bd6d..0000000 --- a/ctr-std/src/sync/mpsc/blocking.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Generic support for building blocking abstractions. - -use thread::{self, Thread}; -use sync::atomic::{AtomicBool, Ordering}; -use sync::Arc; -use mem; -use time::Instant; - -struct Inner { - thread: Thread, - woken: AtomicBool, -} - -unsafe impl Send for Inner {} -unsafe impl Sync for Inner {} - -#[derive(Clone)] -pub struct SignalToken { - inner: Arc, -} - -pub struct WaitToken { - inner: Arc, -} - -impl !Send for WaitToken {} - -impl !Sync for WaitToken {} - -pub fn tokens() -> (WaitToken, SignalToken) { - let inner = Arc::new(Inner { - thread: thread::current(), - woken: AtomicBool::new(false), - }); - let wait_token = WaitToken { - inner: inner.clone(), - }; - let signal_token = SignalToken { - inner, - }; - (wait_token, signal_token) -} - -impl SignalToken { - pub fn signal(&self) -> bool { - let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst); - if wake { - self.inner.thread.unpark(); - } - wake - } - - /// Convert to an unsafe usize value. Useful for storing in a pipe's state - /// flag. - #[inline] - pub unsafe fn cast_to_usize(self) -> usize { - mem::transmute(self.inner) - } - - /// Convert from an unsafe usize value. Useful for retrieving a pipe's state - /// flag. - #[inline] - pub unsafe fn cast_from_usize(signal_ptr: usize) -> SignalToken { - SignalToken { inner: mem::transmute(signal_ptr) } - } -} - -impl WaitToken { - pub fn wait(self) { - while !self.inner.woken.load(Ordering::SeqCst) { - thread::park() - } - } - - /// Returns true if we wake up normally, false otherwise. - pub fn wait_max_until(self, end: Instant) -> bool { - while !self.inner.woken.load(Ordering::SeqCst) { - let now = Instant::now(); - if now >= end { - return false; - } - thread::park_timeout(end - now) - } - true - } -} diff --git a/ctr-std/src/sync/mpsc/cache_aligned.rs b/ctr-std/src/sync/mpsc/cache_aligned.rs deleted file mode 100644 index 5af0126..0000000 --- a/ctr-std/src/sync/mpsc/cache_aligned.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ops::{Deref, DerefMut}; - -#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(align(64))] -pub(super) struct Aligner; - -#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(super) struct CacheAligned(pub T, pub Aligner); - -impl Deref for CacheAligned { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for CacheAligned { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl CacheAligned { - pub(super) fn new(t: T) -> Self { - CacheAligned(t, Aligner) - } -} diff --git a/ctr-std/src/sync/mpsc/mod.rs b/ctr-std/src/sync/mpsc/mod.rs deleted file mode 100644 index 59cf741..0000000 --- a/ctr-std/src/sync/mpsc/mod.rs +++ /dev/null @@ -1,3130 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Multi-producer, single-consumer FIFO queue communication primitives. -//! -//! This module provides message-based communication over channels, concretely -//! defined among three types: -//! -//! * [`Sender`] -//! * [`SyncSender`] -//! * [`Receiver`] -//! -//! A [`Sender`] or [`SyncSender`] is used to send data to a [`Receiver`]. Both -//! senders are clone-able (multi-producer) such that many threads can send -//! simultaneously to one receiver (single-consumer). -//! -//! These channels come in two flavors: -//! -//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function -//! will return a `(Sender, Receiver)` tuple where all sends will be -//! **asynchronous** (they never block). The channel conceptually has an -//! infinite buffer. -//! -//! 2. A synchronous, bounded channel. The [`sync_channel`] function will -//! return a `(SyncSender, Receiver)` tuple where the storage for pending -//! messages is a pre-allocated buffer of a fixed size. All sends will be -//! **synchronous** by blocking until there is buffer space available. Note -//! that a bound of 0 is allowed, causing the channel to become a "rendezvous" -//! channel where each sender atomically hands off a message to a receiver. -//! -//! [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html -//! [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html -//! [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html -//! [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send -//! [`channel`]: ../../../std/sync/mpsc/fn.channel.html -//! [`sync_channel`]: ../../../std/sync/mpsc/fn.sync_channel.html -//! -//! ## Disconnection -//! -//! The send and receive operations on channels will all return a [`Result`] -//! indicating whether the operation succeeded or not. An unsuccessful operation -//! is normally indicative of the other half of a channel having "hung up" by -//! being dropped in its corresponding thread. -//! -//! Once half of a channel has been deallocated, most operations can no longer -//! continue to make progress, so [`Err`] will be returned. Many applications -//! will continue to [`unwrap`] the results returned from this module, -//! instigating a propagation of failure among threads if one unexpectedly dies. -//! -//! [`Result`]: ../../../std/result/enum.Result.html -//! [`Err`]: ../../../std/result/enum.Result.html#variant.Err -//! [`unwrap`]: ../../../std/result/enum.Result.html#method.unwrap -//! -//! # Examples -//! -//! Simple usage: -//! -//! ``` -//! use std::thread; -//! use std::sync::mpsc::channel; -//! -//! // Create a simple streaming channel -//! let (tx, rx) = channel(); -//! thread::spawn(move|| { -//! tx.send(10).unwrap(); -//! }); -//! assert_eq!(rx.recv().unwrap(), 10); -//! ``` -//! -//! Shared usage: -//! -//! ``` -//! use std::thread; -//! use std::sync::mpsc::channel; -//! -//! // Create a shared channel that can be sent along from many threads -//! // where tx is the sending half (tx for transmission), and rx is the receiving -//! // half (rx for receiving). -//! let (tx, rx) = channel(); -//! for i in 0..10 { -//! let tx = tx.clone(); -//! thread::spawn(move|| { -//! tx.send(i).unwrap(); -//! }); -//! } -//! -//! for _ in 0..10 { -//! let j = rx.recv().unwrap(); -//! assert!(0 <= j && j < 10); -//! } -//! ``` -//! -//! Propagating panics: -//! -//! ``` -//! use std::sync::mpsc::channel; -//! -//! // The call to recv() will return an error because the channel has already -//! // hung up (or been deallocated) -//! let (tx, rx) = channel::(); -//! drop(tx); -//! assert!(rx.recv().is_err()); -//! ``` -//! -//! Synchronous channels: -//! -//! ``` -//! use std::thread; -//! use std::sync::mpsc::sync_channel; -//! -//! let (tx, rx) = sync_channel::(0); -//! thread::spawn(move|| { -//! // This will wait for the parent thread to start receiving -//! tx.send(53).unwrap(); -//! }); -//! rx.recv().unwrap(); -//! ``` - -#![stable(feature = "rust1", since = "1.0.0")] - -// A description of how Rust's channel implementation works -// -// Channels are supposed to be the basic building block for all other -// concurrent primitives that are used in Rust. As a result, the channel type -// needs to be highly optimized, flexible, and broad enough for use everywhere. -// -// The choice of implementation of all channels is to be built on lock-free data -// structures. The channels themselves are then consequently also lock-free data -// structures. As always with lock-free code, this is a very "here be dragons" -// territory, especially because I'm unaware of any academic papers that have -// gone into great length about channels of these flavors. -// -// ## Flavors of channels -// -// From the perspective of a consumer of this library, there is only one flavor -// of channel. This channel can be used as a stream and cloned to allow multiple -// senders. Under the hood, however, there are actually three flavors of -// channels in play. -// -// * Flavor::Oneshots - these channels are highly optimized for the one-send use -// case. They contain as few atomics as possible and -// involve one and exactly one allocation. -// * Streams - these channels are optimized for the non-shared use case. They -// use a different concurrent queue that is more tailored for this -// use case. The initial allocation of this flavor of channel is not -// optimized. -// * Shared - this is the most general form of channel that this module offers, -// a channel with multiple senders. This type is as optimized as it -// can be, but the previous two types mentioned are much faster for -// their use-cases. -// -// ## Concurrent queues -// -// The basic idea of Rust's Sender/Receiver types is that send() never blocks, -// but recv() obviously blocks. This means that under the hood there must be -// some shared and concurrent queue holding all of the actual data. -// -// With two flavors of channels, two flavors of queues are also used. We have -// chosen to use queues from a well-known author that are abbreviated as SPSC -// and MPSC (single producer, single consumer and multiple producer, single -// consumer). SPSC queues are used for streams while MPSC queues are used for -// shared channels. -// -// ### SPSC optimizations -// -// The SPSC queue found online is essentially a linked list of nodes where one -// half of the nodes are the "queue of data" and the other half of nodes are a -// cache of unused nodes. The unused nodes are used such that an allocation is -// not required on every push() and a free doesn't need to happen on every -// pop(). -// -// As found online, however, the cache of nodes is of an infinite size. This -// means that if a channel at one point in its life had 50k items in the queue, -// then the queue will always have the capacity for 50k items. I believed that -// this was an unnecessary limitation of the implementation, so I have altered -// the queue to optionally have a bound on the cache size. -// -// By default, streams will have an unbounded SPSC queue with a small-ish cache -// size. The hope is that the cache is still large enough to have very fast -// send() operations while not too large such that millions of channels can -// coexist at once. -// -// ### MPSC optimizations -// -// Right now the MPSC queue has not been optimized. Like the SPSC queue, it uses -// a linked list under the hood to earn its unboundedness, but I have not put -// forth much effort into having a cache of nodes similar to the SPSC queue. -// -// For now, I believe that this is "ok" because shared channels are not the most -// common type, but soon we may wish to revisit this queue choice and determine -// another candidate for backend storage of shared channels. -// -// ## Overview of the Implementation -// -// Now that there's a little background on the concurrent queues used, it's -// worth going into much more detail about the channels themselves. The basic -// pseudocode for a send/recv are: -// -// -// send(t) recv() -// queue.push(t) return if queue.pop() -// if increment() == -1 deschedule { -// wakeup() if decrement() > 0 -// cancel_deschedule() -// } -// queue.pop() -// -// As mentioned before, there are no locks in this implementation, only atomic -// instructions are used. -// -// ### The internal atomic counter -// -// Every channel has a shared counter with each half to keep track of the size -// of the queue. This counter is used to abort descheduling by the receiver and -// to know when to wake up on the sending side. -// -// As seen in the pseudocode, senders will increment this count and receivers -// will decrement the count. The theory behind this is that if a sender sees a -// -1 count, it will wake up the receiver, and if the receiver sees a 1+ count, -// then it doesn't need to block. -// -// The recv() method has a beginning call to pop(), and if successful, it needs -// to decrement the count. It is a crucial implementation detail that this -// decrement does *not* happen to the shared counter. If this were the case, -// then it would be possible for the counter to be very negative when there were -// no receivers waiting, in which case the senders would have to determine when -// it was actually appropriate to wake up a receiver. -// -// Instead, the "steal count" is kept track of separately (not atomically -// because it's only used by receivers), and then the decrement() call when -// descheduling will lump in all of the recent steals into one large decrement. -// -// The implication of this is that if a sender sees a -1 count, then there's -// guaranteed to be a waiter waiting! -// -// ## Native Implementation -// -// A major goal of these channels is to work seamlessly on and off the runtime. -// All of the previous race conditions have been worded in terms of -// scheduler-isms (which is obviously not available without the runtime). -// -// For now, native usage of channels (off the runtime) will fall back onto -// mutexes/cond vars for descheduling/atomic decisions. The no-contention path -// is still entirely lock-free, the "deschedule" blocks above are surrounded by -// a mutex and the "wakeup" blocks involve grabbing a mutex and signaling on a -// condition variable. -// -// ## Select -// -// Being able to support selection over channels has greatly influenced this -// design, and not only does selection need to work inside the runtime, but also -// outside the runtime. -// -// The implementation is fairly straightforward. The goal of select() is not to -// return some data, but only to return which channel can receive data without -// blocking. The implementation is essentially the entire blocking procedure -// followed by an increment as soon as its woken up. The cancellation procedure -// involves an increment and swapping out of to_wake to acquire ownership of the -// thread to unblock. -// -// Sadly this current implementation requires multiple allocations, so I have -// seen the throughput of select() be much worse than it should be. I do not -// believe that there is anything fundamental that needs to change about these -// channels, however, in order to support a more efficient select(). -// -// # Conclusion -// -// And now that you've seen all the races that I found and attempted to fix, -// here's the code for you to find some more! - -use sync::Arc; -use error; -use fmt; -use mem; -use cell::UnsafeCell; -use time::{Duration, Instant}; - -#[unstable(feature = "mpsc_select", issue = "27800")] -pub use self::select::{Select, Handle}; -use self::select::StartResult; -use self::select::StartResult::*; -use self::blocking::SignalToken; - -mod blocking; -mod oneshot; -mod select; -mod shared; -mod stream; -mod sync; -mod mpsc_queue; -mod spsc_queue; - -mod cache_aligned; - -/// The receiving half of Rust's [`channel`][] (or [`sync_channel`]) type. -/// This half can only be owned by one thread. -/// -/// Messages sent to the channel can be retrieved using [`recv`]. -/// -/// [`channel`]: fn.channel.html -/// [`sync_channel`]: fn.sync_channel.html -/// [`recv`]: struct.Receiver.html#method.recv -/// -/// # Examples -/// -/// ```rust -/// use std::sync::mpsc::channel; -/// use std::thread; -/// use std::time::Duration; -/// -/// let (send, recv) = channel(); -/// -/// thread::spawn(move || { -/// send.send("Hello world!").unwrap(); -/// thread::sleep(Duration::from_secs(2)); // block for two seconds -/// send.send("Delayed for 2 seconds").unwrap(); -/// }); -/// -/// println!("{}", recv.recv().unwrap()); // Received immediately -/// println!("Waiting..."); -/// println!("{}", recv.recv().unwrap()); // Received after 2 seconds -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Receiver { - inner: UnsafeCell>, -} - -// The receiver port can be sent from place to place, so long as it -// is not used to receive non-sendable things. -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Receiver { } - -#[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for Receiver { } - -/// An iterator over messages on a [`Receiver`], created by [`iter`]. -/// -/// This iterator will block whenever [`next`] is called, -/// waiting for a new message, and [`None`] will be returned -/// when the corresponding channel has hung up. -/// -/// [`iter`]: struct.Receiver.html#method.iter -/// [`Receiver`]: struct.Receiver.html -/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next -/// [`None`]: ../../../std/option/enum.Option.html#variant.None -/// -/// # Examples -/// -/// ```rust -/// use std::sync::mpsc::channel; -/// use std::thread; -/// -/// let (send, recv) = channel(); -/// -/// thread::spawn(move || { -/// send.send(1u8).unwrap(); -/// send.send(2u8).unwrap(); -/// send.send(3u8).unwrap(); -/// }); -/// -/// for x in recv.iter() { -/// println!("Got: {}", x); -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct Iter<'a, T: 'a> { - rx: &'a Receiver -} - -/// An iterator that attempts to yield all pending values for a [`Receiver`], -/// created by [`try_iter`]. -/// -/// [`None`] will be returned when there are no pending values remaining or -/// if the corresponding channel has hung up. -/// -/// This iterator will never block the caller in order to wait for data to -/// become available. Instead, it will return [`None`]. -/// -/// [`Receiver`]: struct.Receiver.html -/// [`try_iter`]: struct.Receiver.html#method.try_iter -/// [`None`]: ../../../std/option/enum.Option.html#variant.None -/// -/// # Examples -/// -/// ```rust -/// use std::sync::mpsc::channel; -/// use std::thread; -/// use std::time::Duration; -/// -/// let (sender, receiver) = channel(); -/// -/// // Nothing is in the buffer yet -/// assert!(receiver.try_iter().next().is_none()); -/// println!("Nothing in the buffer..."); -/// -/// thread::spawn(move || { -/// sender.send(1).unwrap(); -/// sender.send(2).unwrap(); -/// sender.send(3).unwrap(); -/// }); -/// -/// println!("Going to sleep..."); -/// thread::sleep(Duration::from_secs(2)); // block for two seconds -/// -/// for x in receiver.try_iter() { -/// println!("Got: {}", x); -/// } -/// ``` -#[stable(feature = "receiver_try_iter", since = "1.15.0")] -#[derive(Debug)] -pub struct TryIter<'a, T: 'a> { - rx: &'a Receiver -} - -/// An owning iterator over messages on a [`Receiver`], -/// created by **Receiver::into_iter**. -/// -/// This iterator will block whenever [`next`] -/// is called, waiting for a new message, and [`None`] will be -/// returned if the corresponding channel has hung up. -/// -/// [`Receiver`]: struct.Receiver.html -/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next -/// [`None`]: ../../../std/option/enum.Option.html#variant.None -/// -/// # Examples -/// -/// ```rust -/// use std::sync::mpsc::channel; -/// use std::thread; -/// -/// let (send, recv) = channel(); -/// -/// thread::spawn(move || { -/// send.send(1u8).unwrap(); -/// send.send(2u8).unwrap(); -/// send.send(3u8).unwrap(); -/// }); -/// -/// for x in recv.into_iter() { -/// println!("Got: {}", x); -/// } -/// ``` -#[stable(feature = "receiver_into_iter", since = "1.1.0")] -#[derive(Debug)] -pub struct IntoIter { - rx: Receiver -} - -/// The sending-half of Rust's asynchronous [`channel`] type. This half can only be -/// owned by one thread, but it can be cloned to send to other threads. -/// -/// Messages can be sent through this channel with [`send`]. -/// -/// [`channel`]: fn.channel.html -/// [`send`]: struct.Sender.html#method.send -/// -/// # Examples -/// -/// ```rust -/// use std::sync::mpsc::channel; -/// use std::thread; -/// -/// let (sender, receiver) = channel(); -/// let sender2 = sender.clone(); -/// -/// // First thread owns sender -/// thread::spawn(move || { -/// sender.send(1).unwrap(); -/// }); -/// -/// // Second thread owns sender2 -/// thread::spawn(move || { -/// sender2.send(2).unwrap(); -/// }); -/// -/// let msg = receiver.recv().unwrap(); -/// let msg2 = receiver.recv().unwrap(); -/// -/// assert_eq!(3, msg + msg2); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Sender { - inner: UnsafeCell>, -} - -// The send port can be sent from place to place, so long as it -// is not used to send non-sendable things. -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Sender { } - -#[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for Sender { } - -/// The sending-half of Rust's synchronous [`sync_channel`] type. -/// -/// Messages can be sent through this channel with [`send`] or [`try_send`]. -/// -/// [`send`] will block if there is no space in the internal buffer. -/// -/// [`sync_channel`]: fn.sync_channel.html -/// [`send`]: struct.SyncSender.html#method.send -/// [`try_send`]: struct.SyncSender.html#method.try_send -/// -/// # Examples -/// -/// ```rust -/// use std::sync::mpsc::sync_channel; -/// use std::thread; -/// -/// // Create a sync_channel with buffer size 2 -/// let (sync_sender, receiver) = sync_channel(2); -/// let sync_sender2 = sync_sender.clone(); -/// -/// // First thread owns sync_sender -/// thread::spawn(move || { -/// sync_sender.send(1).unwrap(); -/// sync_sender.send(2).unwrap(); -/// }); -/// -/// // Second thread owns sync_sender2 -/// thread::spawn(move || { -/// sync_sender2.send(3).unwrap(); -/// // thread will now block since the buffer is full -/// println!("Thread unblocked!"); -/// }); -/// -/// let mut msg; -/// -/// msg = receiver.recv().unwrap(); -/// println!("message {} received", msg); -/// -/// // "Thread unblocked!" will be printed now -/// -/// msg = receiver.recv().unwrap(); -/// println!("message {} received", msg); -/// -/// msg = receiver.recv().unwrap(); -/// -/// println!("message {} received", msg); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SyncSender { - inner: Arc>, -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for SyncSender {} - -/// An error returned from the [`Sender::send`] or [`SyncSender::send`] -/// function on **channel**s. -/// -/// A **send** operation can only fail if the receiving end of a channel is -/// disconnected, implying that the data could never be received. The error -/// contains the data being sent as a payload so it can be recovered. -/// -/// [`Sender::send`]: struct.Sender.html#method.send -/// [`SyncSender::send`]: struct.SyncSender.html#method.send -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(PartialEq, Eq, Clone, Copy)] -pub struct SendError(#[stable(feature = "rust1", since = "1.0.0")] pub T); - -/// An error returned from the [`recv`] function on a [`Receiver`]. -/// -/// The [`recv`] operation can only fail if the sending half of a -/// [`channel`][`channel`] (or [`sync_channel`]) is disconnected, implying that no further -/// messages will ever be received. -/// -/// [`recv`]: struct.Receiver.html#method.recv -/// [`Receiver`]: struct.Receiver.html -/// [`channel`]: fn.channel.html -/// [`sync_channel`]: fn.sync_channel.html -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RecvError; - -/// This enumeration is the list of the possible reasons that [`try_recv`] could -/// not return data when called. This can occur with both a [`channel`] and -/// a [`sync_channel`]. -/// -/// [`try_recv`]: struct.Receiver.html#method.try_recv -/// [`channel`]: fn.channel.html -/// [`sync_channel`]: fn.sync_channel.html -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub enum TryRecvError { - /// This **channel** is currently empty, but the **Sender**(s) have not yet - /// disconnected, so data may yet become available. - #[stable(feature = "rust1", since = "1.0.0")] - Empty, - - /// The **channel**'s sending half has become disconnected, and there will - /// never be any more data received on it. - #[stable(feature = "rust1", since = "1.0.0")] - Disconnected, -} - -/// This enumeration is the list of possible errors that made [`recv_timeout`] -/// unable to return data when called. This can occur with both a [`channel`] and -/// a [`sync_channel`]. -/// -/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout -/// [`channel`]: fn.channel.html -/// [`sync_channel`]: fn.sync_channel.html -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] -pub enum RecvTimeoutError { - /// This **channel** is currently empty, but the **Sender**(s) have not yet - /// disconnected, so data may yet become available. - #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] - Timeout, - /// The **channel**'s sending half has become disconnected, and there will - /// never be any more data received on it. - #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] - Disconnected, -} - -/// This enumeration is the list of the possible error outcomes for the -/// [`try_send`] method. -/// -/// [`try_send`]: struct.SyncSender.html#method.try_send -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(PartialEq, Eq, Clone, Copy)] -pub enum TrySendError { - /// The data could not be sent on the [`sync_channel`] because it would require that - /// the callee block to send the data. - /// - /// If this is a buffered channel, then the buffer is full at this time. If - /// this is not a buffered channel, then there is no [`Receiver`] available to - /// acquire the data. - /// - /// [`sync_channel`]: fn.sync_channel.html - /// [`Receiver`]: struct.Receiver.html - #[stable(feature = "rust1", since = "1.0.0")] - Full(#[stable(feature = "rust1", since = "1.0.0")] T), - - /// This [`sync_channel`]'s receiving half has disconnected, so the data could not be - /// sent. The data is returned back to the callee in this case. - /// - /// [`sync_channel`]: fn.sync_channel.html - #[stable(feature = "rust1", since = "1.0.0")] - Disconnected(#[stable(feature = "rust1", since = "1.0.0")] T), -} - -enum Flavor { - Oneshot(Arc>), - Stream(Arc>), - Shared(Arc>), - Sync(Arc>), -} - -#[doc(hidden)] -trait UnsafeFlavor { - fn inner_unsafe(&self) -> &UnsafeCell>; - unsafe fn inner_mut(&self) -> &mut Flavor { - &mut *self.inner_unsafe().get() - } - unsafe fn inner(&self) -> &Flavor { - &*self.inner_unsafe().get() - } -} -impl UnsafeFlavor for Sender { - fn inner_unsafe(&self) -> &UnsafeCell> { - &self.inner - } -} -impl UnsafeFlavor for Receiver { - fn inner_unsafe(&self) -> &UnsafeCell> { - &self.inner - } -} - -/// Creates a new asynchronous channel, returning the sender/receiver halves. -/// All data sent on the [`Sender`] will become available on the [`Receiver`] in -/// the same order as it was sent, and no [`send`] will block the calling thread -/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will -/// block after its buffer limit is reached). [`recv`] will block until a message -/// is available. -/// -/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but -/// only one [`Receiver`] is supported. -/// -/// If the [`Receiver`] is disconnected while trying to [`send`] with the -/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, if the -/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will -/// return a [`RecvError`]. -/// -/// [`send`]: struct.Sender.html#method.send -/// [`recv`]: struct.Receiver.html#method.recv -/// [`Sender`]: struct.Sender.html -/// [`Receiver`]: struct.Receiver.html -/// [`sync_channel`]: fn.sync_channel.html -/// [`SendError`]: struct.SendError.html -/// [`RecvError`]: struct.RecvError.html -/// -/// # Examples -/// -/// ``` -/// use std::sync::mpsc::channel; -/// use std::thread; -/// -/// let (sender, receiver) = channel(); -/// -/// // Spawn off an expensive computation -/// thread::spawn(move|| { -/// # fn expensive_computation() {} -/// sender.send(expensive_computation()).unwrap(); -/// }); -/// -/// // Do some useful work for awhile -/// -/// // Let's see what that answer was -/// println!("{:?}", receiver.recv().unwrap()); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn channel() -> (Sender, Receiver) { - let a = Arc::new(oneshot::Packet::new()); - (Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a))) -} - -/// Creates a new synchronous, bounded channel. -/// All data sent on the [`SyncSender`] will become available on the [`Receiver`] -/// in the same order as it was sent. Like asynchronous [`channel`]s, the -/// [`Receiver`] will block until a message becomes available. `sync_channel` -/// differs greatly in the semantics of the sender, however. -/// -/// This channel has an internal buffer on which messages will be queued. -/// `bound` specifies the buffer size. When the internal buffer becomes full, -/// future sends will *block* waiting for the buffer to open up. Note that a -/// buffer size of 0 is valid, in which case this becomes "rendezvous channel" -/// where each [`send`] will not return until a [`recv`] is paired with it. -/// -/// The [`SyncSender`] can be cloned to [`send`] to the same channel multiple -/// times, but only one [`Receiver`] is supported. -/// -/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying -/// to [`send`] with the [`SyncSender`], the [`send`] method will return a -/// [`SendError`]. Similarly, If the [`SyncSender`] is disconnected while trying -/// to [`recv`], the [`recv`] method will return a [`RecvError`]. -/// -/// [`channel`]: fn.channel.html -/// [`send`]: struct.SyncSender.html#method.send -/// [`recv`]: struct.Receiver.html#method.recv -/// [`SyncSender`]: struct.SyncSender.html -/// [`Receiver`]: struct.Receiver.html -/// [`SendError`]: struct.SendError.html -/// [`RecvError`]: struct.RecvError.html -/// -/// # Examples -/// -/// ``` -/// use std::sync::mpsc::sync_channel; -/// use std::thread; -/// -/// let (sender, receiver) = sync_channel(1); -/// -/// // this returns immediately -/// sender.send(1).unwrap(); -/// -/// thread::spawn(move|| { -/// // this will block until the previous message has been received -/// sender.send(2).unwrap(); -/// }); -/// -/// assert_eq!(receiver.recv().unwrap(), 1); -/// assert_eq!(receiver.recv().unwrap(), 2); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { - let a = Arc::new(sync::Packet::new(bound)); - (SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a))) -} - -//////////////////////////////////////////////////////////////////////////////// -// Sender -//////////////////////////////////////////////////////////////////////////////// - -impl Sender { - fn new(inner: Flavor) -> Sender { - Sender { - inner: UnsafeCell::new(inner), - } - } - - /// Attempts to send a value on this channel, returning it back if it could - /// not be sent. - /// - /// A successful send occurs when it is determined that the other end of - /// the channel has not hung up already. An unsuccessful send would be one - /// where the corresponding receiver has already been deallocated. Note - /// that a return value of [`Err`] means that the data will never be - /// received, but a return value of [`Ok`] does *not* mean that the data - /// will be received. It is possible for the corresponding receiver to - /// hang up immediately after this function returns [`Ok`]. - /// - /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err - /// [`Ok`]: ../../../std/result/enum.Result.html#variant.Ok - /// - /// This method will never block the current thread. - /// - /// # Examples - /// - /// ``` - /// use std::sync::mpsc::channel; - /// - /// let (tx, rx) = channel(); - /// - /// // This send is always successful - /// tx.send(1).unwrap(); - /// - /// // This send will fail because the receiver is gone - /// drop(rx); - /// assert_eq!(tx.send(1).unwrap_err().0, 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn send(&self, t: T) -> Result<(), SendError> { - let (new_inner, ret) = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => { - if !p.sent() { - return p.send(t).map_err(SendError); - } else { - let a = Arc::new(stream::Packet::new()); - let rx = Receiver::new(Flavor::Stream(a.clone())); - match p.upgrade(rx) { - oneshot::UpSuccess => { - let ret = a.send(t); - (a, ret) - } - oneshot::UpDisconnected => (a, Err(t)), - oneshot::UpWoke(token) => { - // This send cannot panic because the thread is - // asleep (we're looking at it), so the receiver - // can't go away. - a.send(t).ok().unwrap(); - token.signal(); - (a, Ok(())) - } - } - } - } - Flavor::Stream(ref p) => return p.send(t).map_err(SendError), - Flavor::Shared(ref p) => return p.send(t).map_err(SendError), - Flavor::Sync(..) => unreachable!(), - }; - - unsafe { - let tmp = Sender::new(Flavor::Stream(new_inner)); - mem::swap(self.inner_mut(), tmp.inner_mut()); - } - ret.map_err(SendError) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Sender { - fn clone(&self) -> Sender { - let packet = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => { - let a = Arc::new(shared::Packet::new()); - { - let guard = a.postinit_lock(); - let rx = Receiver::new(Flavor::Shared(a.clone())); - let sleeper = match p.upgrade(rx) { - oneshot::UpSuccess | - oneshot::UpDisconnected => None, - oneshot::UpWoke(task) => Some(task), - }; - a.inherit_blocker(sleeper, guard); - } - a - } - Flavor::Stream(ref p) => { - let a = Arc::new(shared::Packet::new()); - { - let guard = a.postinit_lock(); - let rx = Receiver::new(Flavor::Shared(a.clone())); - let sleeper = match p.upgrade(rx) { - stream::UpSuccess | - stream::UpDisconnected => None, - stream::UpWoke(task) => Some(task), - }; - a.inherit_blocker(sleeper, guard); - } - a - } - Flavor::Shared(ref p) => { - p.clone_chan(); - return Sender::new(Flavor::Shared(p.clone())); - } - Flavor::Sync(..) => unreachable!(), - }; - - unsafe { - let tmp = Sender::new(Flavor::Shared(packet.clone())); - mem::swap(self.inner_mut(), tmp.inner_mut()); - } - Sender::new(Flavor::Shared(packet)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Sender { - fn drop(&mut self) { - match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => p.drop_chan(), - Flavor::Stream(ref p) => p.drop_chan(), - Flavor::Shared(ref p) => p.drop_chan(), - Flavor::Sync(..) => unreachable!(), - } - } -} - -#[stable(feature = "mpsc_debug", since = "1.8.0")] -impl fmt::Debug for Sender { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Sender").finish() - } -} - -//////////////////////////////////////////////////////////////////////////////// -// SyncSender -//////////////////////////////////////////////////////////////////////////////// - -impl SyncSender { - fn new(inner: Arc>) -> SyncSender { - SyncSender { inner: inner } - } - - /// Sends a value on this synchronous channel. - /// - /// This function will *block* until space in the internal buffer becomes - /// available or a receiver is available to hand off the message to. - /// - /// Note that a successful send does *not* guarantee that the receiver will - /// ever see the data if there is a buffer on this channel. Items may be - /// enqueued in the internal buffer for the receiver to receive at a later - /// time. If the buffer size is 0, however, the channel becomes a rendezvous - /// channel and it guarantees that the receiver has indeed received - /// the data if this function returns success. - /// - /// This function will never panic, but it may return [`Err`] if the - /// [`Receiver`] has disconnected and is no longer able to receive - /// information. - /// - /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err - /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html - /// - /// # Examples - /// - /// ```rust - /// use std::sync::mpsc::sync_channel; - /// use std::thread; - /// - /// // Create a rendezvous sync_channel with buffer size 0 - /// let (sync_sender, receiver) = sync_channel(0); - /// - /// thread::spawn(move || { - /// println!("sending message..."); - /// sync_sender.send(1).unwrap(); - /// // Thread is now blocked until the message is received - /// - /// println!("...message received!"); - /// }); - /// - /// let msg = receiver.recv().unwrap(); - /// assert_eq!(1, msg); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn send(&self, t: T) -> Result<(), SendError> { - self.inner.send(t).map_err(SendError) - } - - /// Attempts to send a value on this channel without blocking. - /// - /// This method differs from [`send`] by returning immediately if the - /// channel's buffer is full or no receiver is waiting to acquire some - /// data. Compared with [`send`], this function has two failure cases - /// instead of one (one for disconnection, one for a full buffer). - /// - /// See [`send`] for notes about guarantees of whether the - /// receiver has received the data or not if this function is successful. - /// - /// [`send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send - /// - /// # Examples - /// - /// ```rust - /// use std::sync::mpsc::sync_channel; - /// use std::thread; - /// - /// // Create a sync_channel with buffer size 1 - /// let (sync_sender, receiver) = sync_channel(1); - /// let sync_sender2 = sync_sender.clone(); - /// - /// // First thread owns sync_sender - /// thread::spawn(move || { - /// sync_sender.send(1).unwrap(); - /// sync_sender.send(2).unwrap(); - /// // Thread blocked - /// }); - /// - /// // Second thread owns sync_sender2 - /// thread::spawn(move || { - /// // This will return an error and send - /// // no message if the buffer is full - /// sync_sender2.try_send(3).is_err(); - /// }); - /// - /// let mut msg; - /// msg = receiver.recv().unwrap(); - /// println!("message {} received", msg); - /// - /// msg = receiver.recv().unwrap(); - /// println!("message {} received", msg); - /// - /// // Third message may have never been sent - /// match receiver.try_recv() { - /// Ok(msg) => println!("message {} received", msg), - /// Err(_) => println!("the third message was never sent"), - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_send(&self, t: T) -> Result<(), TrySendError> { - self.inner.try_send(t) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for SyncSender { - fn clone(&self) -> SyncSender { - self.inner.clone_chan(); - SyncSender::new(self.inner.clone()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Drop for SyncSender { - fn drop(&mut self) { - self.inner.drop_chan(); - } -} - -#[stable(feature = "mpsc_debug", since = "1.8.0")] -impl fmt::Debug for SyncSender { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SyncSender").finish() - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Receiver -//////////////////////////////////////////////////////////////////////////////// - -impl Receiver { - fn new(inner: Flavor) -> Receiver { - Receiver { inner: UnsafeCell::new(inner) } - } - - /// Attempts to return a pending value on this receiver without blocking. - /// - /// This method will never block the caller in order to wait for data to - /// become available. Instead, this will always return immediately with a - /// possible option of pending data on the channel. - /// - /// This is useful for a flavor of "optimistic check" before deciding to - /// block on a receiver. - /// - /// Compared with [`recv`], this function has two failure cases instead of one - /// (one for disconnection, one for an empty buffer). - /// - /// [`recv`]: struct.Receiver.html#method.recv - /// - /// # Examples - /// - /// ```rust - /// use std::sync::mpsc::{Receiver, channel}; - /// - /// let (_, receiver): (_, Receiver) = channel(); - /// - /// assert!(receiver.try_recv().is_err()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_recv(&self) -> Result { - loop { - let new_port = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => { - match p.try_recv() { - Ok(t) => return Ok(t), - Err(oneshot::Empty) => return Err(TryRecvError::Empty), - Err(oneshot::Disconnected) => { - return Err(TryRecvError::Disconnected) - } - Err(oneshot::Upgraded(rx)) => rx, - } - } - Flavor::Stream(ref p) => { - match p.try_recv() { - Ok(t) => return Ok(t), - Err(stream::Empty) => return Err(TryRecvError::Empty), - Err(stream::Disconnected) => { - return Err(TryRecvError::Disconnected) - } - Err(stream::Upgraded(rx)) => rx, - } - } - Flavor::Shared(ref p) => { - match p.try_recv() { - Ok(t) => return Ok(t), - Err(shared::Empty) => return Err(TryRecvError::Empty), - Err(shared::Disconnected) => { - return Err(TryRecvError::Disconnected) - } - } - } - Flavor::Sync(ref p) => { - match p.try_recv() { - Ok(t) => return Ok(t), - Err(sync::Empty) => return Err(TryRecvError::Empty), - Err(sync::Disconnected) => { - return Err(TryRecvError::Disconnected) - } - } - } - }; - unsafe { - mem::swap(self.inner_mut(), - new_port.inner_mut()); - } - } - } - - /// Attempts to wait for a value on this receiver, returning an error if the - /// corresponding channel has hung up. - /// - /// This function will always block the current thread if there is no data - /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this - /// receiver will wake up and return that message. - /// - /// If the corresponding [`Sender`] has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return [`Err`] to - /// indicate that no more messages can ever be received on this channel. - /// However, since channels are buffered, messages sent before the disconnect - /// will still be properly received. - /// - /// [`Sender`]: struct.Sender.html - /// [`SyncSender`]: struct.SyncSender.html - /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ``` - /// use std::sync::mpsc; - /// use std::thread; - /// - /// let (send, recv) = mpsc::channel(); - /// let handle = thread::spawn(move || { - /// send.send(1u8).unwrap(); - /// }); - /// - /// handle.join().unwrap(); - /// - /// assert_eq!(Ok(1), recv.recv()); - /// ``` - /// - /// Buffering behavior: - /// - /// ``` - /// use std::sync::mpsc; - /// use std::thread; - /// use std::sync::mpsc::RecvError; - /// - /// let (send, recv) = mpsc::channel(); - /// let handle = thread::spawn(move || { - /// send.send(1u8).unwrap(); - /// send.send(2).unwrap(); - /// send.send(3).unwrap(); - /// drop(send); - /// }); - /// - /// // wait for the thread to join so we ensure the sender is dropped - /// handle.join().unwrap(); - /// - /// assert_eq!(Ok(1), recv.recv()); - /// assert_eq!(Ok(2), recv.recv()); - /// assert_eq!(Ok(3), recv.recv()); - /// assert_eq!(Err(RecvError), recv.recv()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn recv(&self) -> Result { - loop { - let new_port = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => { - match p.recv(None) { - Ok(t) => return Ok(t), - Err(oneshot::Disconnected) => return Err(RecvError), - Err(oneshot::Upgraded(rx)) => rx, - Err(oneshot::Empty) => unreachable!(), - } - } - Flavor::Stream(ref p) => { - match p.recv(None) { - Ok(t) => return Ok(t), - Err(stream::Disconnected) => return Err(RecvError), - Err(stream::Upgraded(rx)) => rx, - Err(stream::Empty) => unreachable!(), - } - } - Flavor::Shared(ref p) => { - match p.recv(None) { - Ok(t) => return Ok(t), - Err(shared::Disconnected) => return Err(RecvError), - Err(shared::Empty) => unreachable!(), - } - } - Flavor::Sync(ref p) => return p.recv(None).map_err(|_| RecvError), - }; - unsafe { - mem::swap(self.inner_mut(), new_port.inner_mut()); - } - } - } - - /// Attempts to wait for a value on this receiver, returning an error if the - /// corresponding channel has hung up, or if it waits more than `timeout`. - /// - /// This function will always block the current thread if there is no data - /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this - /// receiver will wake up and return that message. - /// - /// If the corresponding [`Sender`] has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return [`Err`] to - /// indicate that no more messages can ever be received on this channel. - /// However, since channels are buffered, messages sent before the disconnect - /// will still be properly received. - /// - /// [`Sender`]: struct.Sender.html - /// [`SyncSender`]: struct.SyncSender.html - /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err - /// - /// # Known Issues - /// - /// There is currently a known issue (see [`#39364`]) that causes `recv_timeout` - /// to panic unexpectedly with the following example: - /// - /// ```no_run - /// use std::sync::mpsc::channel; - /// use std::thread; - /// use std::time::Duration; - /// - /// let (tx, rx) = channel::(); - /// - /// thread::spawn(move || { - /// let d = Duration::from_millis(10); - /// loop { - /// println!("recv"); - /// let _r = rx.recv_timeout(d); - /// } - /// }); - /// - /// thread::sleep(Duration::from_millis(100)); - /// let _c1 = tx.clone(); - /// - /// thread::sleep(Duration::from_secs(1)); - /// ``` - /// - /// [`#39364`]: https://github.com/rust-lang/rust/issues/39364 - /// - /// # Examples - /// - /// Successfully receiving value before encountering timeout: - /// - /// ```no_run - /// use std::thread; - /// use std::time::Duration; - /// use std::sync::mpsc; - /// - /// let (send, recv) = mpsc::channel(); - /// - /// thread::spawn(move || { - /// send.send('a').unwrap(); - /// }); - /// - /// assert_eq!( - /// recv.recv_timeout(Duration::from_millis(400)), - /// Ok('a') - /// ); - /// ``` - /// - /// Receiving an error upon reaching timeout: - /// - /// ```no_run - /// use std::thread; - /// use std::time::Duration; - /// use std::sync::mpsc; - /// - /// let (send, recv) = mpsc::channel(); - /// - /// thread::spawn(move || { - /// thread::sleep(Duration::from_millis(800)); - /// send.send('a').unwrap(); - /// }); - /// - /// assert_eq!( - /// recv.recv_timeout(Duration::from_millis(400)), - /// Err(mpsc::RecvTimeoutError::Timeout) - /// ); - /// ``` - #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] - pub fn recv_timeout(&self, timeout: Duration) -> Result { - // Do an optimistic try_recv to avoid the performance impact of - // Instant::now() in the full-channel case. - match self.try_recv() { - Ok(result) - => Ok(result), - Err(TryRecvError::Disconnected) - => Err(RecvTimeoutError::Disconnected), - Err(TryRecvError::Empty) - => self.recv_deadline(Instant::now() + timeout) - } - } - - /// Attempts to wait for a value on this receiver, returning an error if the - /// corresponding channel has hung up, or if `deadline` is reached. - /// - /// This function will always block the current thread if there is no data - /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this - /// receiver will wake up and return that message. - /// - /// If the corresponding [`Sender`] has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return [`Err`] to - /// indicate that no more messages can ever be received on this channel. - /// However, since channels are buffered, messages sent before the disconnect - /// will still be properly received. - /// - /// [`Sender`]: struct.Sender.html - /// [`SyncSender`]: struct.SyncSender.html - /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// Successfully receiving value before reaching deadline: - /// - /// ```no_run - /// #![feature(deadline_api)] - /// use std::thread; - /// use std::time::{Duration, Instant}; - /// use std::sync::mpsc; - /// - /// let (send, recv) = mpsc::channel(); - /// - /// thread::spawn(move || { - /// send.send('a').unwrap(); - /// }); - /// - /// assert_eq!( - /// recv.recv_deadline(Instant::now() + Duration::from_millis(400)), - /// Ok('a') - /// ); - /// ``` - /// - /// Receiving an error upon reaching deadline: - /// - /// ```no_run - /// #![feature(deadline_api)] - /// use std::thread; - /// use std::time::{Duration, Instant}; - /// use std::sync::mpsc; - /// - /// let (send, recv) = mpsc::channel(); - /// - /// thread::spawn(move || { - /// thread::sleep(Duration::from_millis(800)); - /// send.send('a').unwrap(); - /// }); - /// - /// assert_eq!( - /// recv.recv_deadline(Instant::now() + Duration::from_millis(400)), - /// Err(mpsc::RecvTimeoutError::Timeout) - /// ); - /// ``` - #[unstable(feature = "deadline_api", issue = "46316")] - pub fn recv_deadline(&self, deadline: Instant) -> Result { - use self::RecvTimeoutError::*; - - loop { - let port_or_empty = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => { - match p.recv(Some(deadline)) { - Ok(t) => return Ok(t), - Err(oneshot::Disconnected) => return Err(Disconnected), - Err(oneshot::Upgraded(rx)) => Some(rx), - Err(oneshot::Empty) => None, - } - } - Flavor::Stream(ref p) => { - match p.recv(Some(deadline)) { - Ok(t) => return Ok(t), - Err(stream::Disconnected) => return Err(Disconnected), - Err(stream::Upgraded(rx)) => Some(rx), - Err(stream::Empty) => None, - } - } - Flavor::Shared(ref p) => { - match p.recv(Some(deadline)) { - Ok(t) => return Ok(t), - Err(shared::Disconnected) => return Err(Disconnected), - Err(shared::Empty) => None, - } - } - Flavor::Sync(ref p) => { - match p.recv(Some(deadline)) { - Ok(t) => return Ok(t), - Err(sync::Disconnected) => return Err(Disconnected), - Err(sync::Empty) => None, - } - } - }; - - if let Some(new_port) = port_or_empty { - unsafe { - mem::swap(self.inner_mut(), new_port.inner_mut()); - } - } - - // If we're already passed the deadline, and we're here without - // data, return a timeout, else try again. - if Instant::now() >= deadline { - return Err(Timeout); - } - } - } - - /// Returns an iterator that will block waiting for messages, but never - /// [`panic!`]. It will return [`None`] when the channel has hung up. - /// - /// [`panic!`]: ../../../std/macro.panic.html - /// [`None`]: ../../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ```rust - /// use std::sync::mpsc::channel; - /// use std::thread; - /// - /// let (send, recv) = channel(); - /// - /// thread::spawn(move || { - /// send.send(1).unwrap(); - /// send.send(2).unwrap(); - /// send.send(3).unwrap(); - /// }); - /// - /// let mut iter = recv.iter(); - /// assert_eq!(iter.next(), Some(1)); - /// assert_eq!(iter.next(), Some(2)); - /// assert_eq!(iter.next(), Some(3)); - /// assert_eq!(iter.next(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { - Iter { rx: self } - } - - /// Returns an iterator that will attempt to yield all pending values. - /// It will return `None` if there are no more pending values or if the - /// channel has hung up. The iterator will never [`panic!`] or block the - /// user by waiting for values. - /// - /// [`panic!`]: ../../../std/macro.panic.html - /// - /// # Examples - /// - /// ```no_run - /// use std::sync::mpsc::channel; - /// use std::thread; - /// use std::time::Duration; - /// - /// let (sender, receiver) = channel(); - /// - /// // nothing is in the buffer yet - /// assert!(receiver.try_iter().next().is_none()); - /// - /// thread::spawn(move || { - /// thread::sleep(Duration::from_secs(1)); - /// sender.send(1).unwrap(); - /// sender.send(2).unwrap(); - /// sender.send(3).unwrap(); - /// }); - /// - /// // nothing is in the buffer yet - /// assert!(receiver.try_iter().next().is_none()); - /// - /// // block for two seconds - /// thread::sleep(Duration::from_secs(2)); - /// - /// let mut iter = receiver.try_iter(); - /// assert_eq!(iter.next(), Some(1)); - /// assert_eq!(iter.next(), Some(2)); - /// assert_eq!(iter.next(), Some(3)); - /// assert_eq!(iter.next(), None); - /// ``` - #[stable(feature = "receiver_try_iter", since = "1.15.0")] - pub fn try_iter(&self) -> TryIter { - TryIter { rx: self } - } - -} - -impl select::Packet for Receiver { - fn can_recv(&self) -> bool { - loop { - let new_port = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => { - match p.can_recv() { - Ok(ret) => return ret, - Err(upgrade) => upgrade, - } - } - Flavor::Stream(ref p) => { - match p.can_recv() { - Ok(ret) => return ret, - Err(upgrade) => upgrade, - } - } - Flavor::Shared(ref p) => return p.can_recv(), - Flavor::Sync(ref p) => return p.can_recv(), - }; - unsafe { - mem::swap(self.inner_mut(), - new_port.inner_mut()); - } - } - } - - fn start_selection(&self, mut token: SignalToken) -> StartResult { - loop { - let (t, new_port) = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => { - match p.start_selection(token) { - oneshot::SelSuccess => return Installed, - oneshot::SelCanceled => return Abort, - oneshot::SelUpgraded(t, rx) => (t, rx), - } - } - Flavor::Stream(ref p) => { - match p.start_selection(token) { - stream::SelSuccess => return Installed, - stream::SelCanceled => return Abort, - stream::SelUpgraded(t, rx) => (t, rx), - } - } - Flavor::Shared(ref p) => return p.start_selection(token), - Flavor::Sync(ref p) => return p.start_selection(token), - }; - token = t; - unsafe { - mem::swap(self.inner_mut(), new_port.inner_mut()); - } - } - } - - fn abort_selection(&self) -> bool { - let mut was_upgrade = false; - loop { - let result = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => p.abort_selection(), - Flavor::Stream(ref p) => p.abort_selection(was_upgrade), - Flavor::Shared(ref p) => return p.abort_selection(was_upgrade), - Flavor::Sync(ref p) => return p.abort_selection(), - }; - let new_port = match result { Ok(b) => return b, Err(p) => p }; - was_upgrade = true; - unsafe { - mem::swap(self.inner_mut(), - new_port.inner_mut()); - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Iter<'a, T> { - type Item = T; - - fn next(&mut self) -> Option { self.rx.recv().ok() } -} - -#[stable(feature = "receiver_try_iter", since = "1.15.0")] -impl<'a, T> Iterator for TryIter<'a, T> { - type Item = T; - - fn next(&mut self) -> Option { self.rx.try_recv().ok() } -} - -#[stable(feature = "receiver_into_iter", since = "1.1.0")] -impl<'a, T> IntoIterator for &'a Receiver { - type Item = T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { self.iter() } -} - -#[stable(feature = "receiver_into_iter", since = "1.1.0")] -impl Iterator for IntoIter { - type Item = T; - fn next(&mut self) -> Option { self.rx.recv().ok() } -} - -#[stable(feature = "receiver_into_iter", since = "1.1.0")] -impl IntoIterator for Receiver { - type Item = T; - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - IntoIter { rx: self } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Receiver { - fn drop(&mut self) { - match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => p.drop_port(), - Flavor::Stream(ref p) => p.drop_port(), - Flavor::Shared(ref p) => p.drop_port(), - Flavor::Sync(ref p) => p.drop_port(), - } - } -} - -#[stable(feature = "mpsc_debug", since = "1.8.0")] -impl fmt::Debug for Receiver { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Receiver").finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for SendError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "SendError(..)".fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for SendError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "sending on a closed channel".fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for SendError { - fn description(&self) -> &str { - "sending on a closed channel" - } - - fn cause(&self) -> Option<&dyn error::Error> { - None - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for TrySendError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - TrySendError::Full(..) => "Full(..)".fmt(f), - TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for TrySendError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - TrySendError::Full(..) => { - "sending on a full channel".fmt(f) - } - TrySendError::Disconnected(..) => { - "sending on a closed channel".fmt(f) - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for TrySendError { - - fn description(&self) -> &str { - match *self { - TrySendError::Full(..) => { - "sending on a full channel" - } - TrySendError::Disconnected(..) => { - "sending on a closed channel" - } - } - } - - fn cause(&self) -> Option<&dyn error::Error> { - None - } -} - -#[stable(feature = "mpsc_error_conversions", since = "1.24.0")] -impl From> for TrySendError { - fn from(err: SendError) -> TrySendError { - match err { - SendError(t) => TrySendError::Disconnected(t), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for RecvError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "receiving on a closed channel".fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for RecvError { - - fn description(&self) -> &str { - "receiving on a closed channel" - } - - fn cause(&self) -> Option<&dyn error::Error> { - None - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for TryRecvError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - TryRecvError::Empty => { - "receiving on an empty channel".fmt(f) - } - TryRecvError::Disconnected => { - "receiving on a closed channel".fmt(f) - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for TryRecvError { - - fn description(&self) -> &str { - match *self { - TryRecvError::Empty => { - "receiving on an empty channel" - } - TryRecvError::Disconnected => { - "receiving on a closed channel" - } - } - } - - fn cause(&self) -> Option<&dyn error::Error> { - None - } -} - -#[stable(feature = "mpsc_error_conversions", since = "1.24.0")] -impl From for TryRecvError { - fn from(err: RecvError) -> TryRecvError { - match err { - RecvError => TryRecvError::Disconnected, - } - } -} - -#[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")] -impl fmt::Display for RecvTimeoutError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - RecvTimeoutError::Timeout => { - "timed out waiting on channel".fmt(f) - } - RecvTimeoutError::Disconnected => { - "channel is empty and sending half is closed".fmt(f) - } - } - } -} - -#[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")] -impl error::Error for RecvTimeoutError { - fn description(&self) -> &str { - match *self { - RecvTimeoutError::Timeout => { - "timed out waiting on channel" - } - RecvTimeoutError::Disconnected => { - "channel is empty and sending half is closed" - } - } - } - - fn cause(&self) -> Option<&dyn error::Error> { - None - } -} - -#[stable(feature = "mpsc_error_conversions", since = "1.24.0")] -impl From for RecvTimeoutError { - fn from(err: RecvError) -> RecvTimeoutError { - match err { - RecvError => RecvTimeoutError::Disconnected, - } - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use env; - use super::*; - use thread; - use time::{Duration, Instant}; - - pub fn stress_factor() -> usize { - match env::var("RUST_TEST_STRESS") { - Ok(val) => val.parse().unwrap(), - Err(..) => 1, - } - } - - #[test] - fn smoke() { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn drop_full() { - let (tx, _rx) = channel::>(); - tx.send(box 1).unwrap(); - } - - #[test] - fn drop_full_shared() { - let (tx, _rx) = channel::>(); - drop(tx.clone()); - drop(tx.clone()); - tx.send(box 1).unwrap(); - } - - #[test] - fn smoke_shared() { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - let tx = tx.clone(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn smoke_threads() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move|| { - tx.send(1).unwrap(); - }); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn smoke_port_gone() { - let (tx, rx) = channel::(); - drop(rx); - assert!(tx.send(1).is_err()); - } - - #[test] - fn smoke_shared_port_gone() { - let (tx, rx) = channel::(); - drop(rx); - assert!(tx.send(1).is_err()) - } - - #[test] - fn smoke_shared_port_gone2() { - let (tx, rx) = channel::(); - drop(rx); - let tx2 = tx.clone(); - drop(tx); - assert!(tx2.send(1).is_err()); - } - - #[test] - fn port_gone_concurrent() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move|| { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() {} - } - - #[test] - fn port_gone_concurrent_shared() { - let (tx, rx) = channel::(); - let tx2 = tx.clone(); - let _t = thread::spawn(move|| { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() && tx2.send(1).is_ok() {} - } - - #[test] - fn smoke_chan_gone() { - let (tx, rx) = channel::(); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn smoke_chan_gone_shared() { - let (tx, rx) = channel::<()>(); - let tx2 = tx.clone(); - drop(tx); - drop(tx2); - assert!(rx.recv().is_err()); - } - - #[test] - fn chan_gone_concurrent() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move|| { - tx.send(1).unwrap(); - tx.send(1).unwrap(); - }); - while rx.recv().is_ok() {} - } - - #[test] - fn stress() { - let (tx, rx) = channel::(); - let t = thread::spawn(move|| { - for _ in 0..10000 { tx.send(1).unwrap(); } - }); - for _ in 0..10000 { - assert_eq!(rx.recv().unwrap(), 1); - } - t.join().ok().unwrap(); - } - - #[test] - fn stress_shared() { - const AMT: u32 = 10000; - const NTHREADS: u32 = 8; - let (tx, rx) = channel::(); - - let t = thread::spawn(move|| { - for _ in 0..AMT * NTHREADS { - assert_eq!(rx.recv().unwrap(), 1); - } - match rx.try_recv() { - Ok(..) => panic!(), - _ => {} - } - }); - - for _ in 0..NTHREADS { - let tx = tx.clone(); - thread::spawn(move|| { - for _ in 0..AMT { tx.send(1).unwrap(); } - }); - } - drop(tx); - t.join().ok().unwrap(); - } - - #[test] - fn send_from_outside_runtime() { - let (tx1, rx1) = channel::<()>(); - let (tx2, rx2) = channel::(); - let t1 = thread::spawn(move|| { - tx1.send(()).unwrap(); - for _ in 0..40 { - assert_eq!(rx2.recv().unwrap(), 1); - } - }); - rx1.recv().unwrap(); - let t2 = thread::spawn(move|| { - for _ in 0..40 { - tx2.send(1).unwrap(); - } - }); - t1.join().ok().unwrap(); - t2.join().ok().unwrap(); - } - - #[test] - fn recv_from_outside_runtime() { - let (tx, rx) = channel::(); - let t = thread::spawn(move|| { - for _ in 0..40 { - assert_eq!(rx.recv().unwrap(), 1); - } - }); - for _ in 0..40 { - tx.send(1).unwrap(); - } - t.join().ok().unwrap(); - } - - #[test] - fn no_runtime() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - let t1 = thread::spawn(move|| { - assert_eq!(rx1.recv().unwrap(), 1); - tx2.send(2).unwrap(); - }); - let t2 = thread::spawn(move|| { - tx1.send(1).unwrap(); - assert_eq!(rx2.recv().unwrap(), 2); - }); - t1.join().ok().unwrap(); - t2.join().ok().unwrap(); - } - - #[test] - fn oneshot_single_thread_close_port_first() { - // Simple test of closing without sending - let (_tx, rx) = channel::(); - drop(rx); - } - - #[test] - fn oneshot_single_thread_close_chan_first() { - // Simple test of closing without sending - let (tx, _rx) = channel::(); - drop(tx); - } - - #[test] - fn oneshot_single_thread_send_port_close() { - // Testing that the sender cleans up the payload if receiver is closed - let (tx, rx) = channel::>(); - drop(rx); - assert!(tx.send(box 0).is_err()); - } - - #[test] - fn oneshot_single_thread_recv_chan_close() { - // Receiving on a closed chan will panic - let res = thread::spawn(move|| { - let (tx, rx) = channel::(); - drop(tx); - rx.recv().unwrap(); - }).join(); - // What is our res? - assert!(res.is_err()); - } - - #[test] - fn oneshot_single_thread_send_then_recv() { - let (tx, rx) = channel::>(); - tx.send(box 10).unwrap(); - assert!(*rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_open() { - let (tx, rx) = channel::(); - assert!(tx.send(10).is_ok()); - assert!(rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_closed() { - let (tx, rx) = channel::(); - drop(rx); - assert!(tx.send(10).is_err()); - } - - #[test] - fn oneshot_single_thread_try_recv_open() { - let (tx, rx) = channel::(); - tx.send(10).unwrap(); - assert!(rx.recv() == Ok(10)); - } - - #[test] - fn oneshot_single_thread_try_recv_closed() { - let (tx, rx) = channel::(); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn oneshot_single_thread_peek_data() { - let (tx, rx) = channel::(); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - tx.send(10).unwrap(); - assert_eq!(rx.try_recv(), Ok(10)); - } - - #[test] - fn oneshot_single_thread_peek_close() { - let (tx, rx) = channel::(); - drop(tx); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - } - - #[test] - fn oneshot_single_thread_peek_open() { - let (_tx, rx) = channel::(); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - } - - #[test] - fn oneshot_multi_task_recv_then_send() { - let (tx, rx) = channel::>(); - let _t = thread::spawn(move|| { - assert!(*rx.recv().unwrap() == 10); - }); - - tx.send(box 10).unwrap(); - } - - #[test] - fn oneshot_multi_task_recv_then_close() { - let (tx, rx) = channel::>(); - let _t = thread::spawn(move|| { - drop(tx); - }); - let res = thread::spawn(move|| { - assert!(*rx.recv().unwrap() == 10); - }).join(); - assert!(res.is_err()); - } - - #[test] - fn oneshot_multi_thread_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move|| { - drop(rx); - }); - drop(tx); - } - } - - #[test] - fn oneshot_multi_thread_send_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move|| { - drop(rx); - }); - let _ = thread::spawn(move|| { - tx.send(1).unwrap(); - }).join(); - } - } - - #[test] - fn oneshot_multi_thread_recv_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::(); - thread::spawn(move|| { - let res = thread::spawn(move|| { - rx.recv().unwrap(); - }).join(); - assert!(res.is_err()); - }); - let _t = thread::spawn(move|| { - thread::spawn(move|| { - drop(tx); - }); - }); - } - } - - #[test] - fn oneshot_multi_thread_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::>(); - let _t = thread::spawn(move|| { - tx.send(box 10).unwrap(); - }); - assert!(*rx.recv().unwrap() == 10); - } - } - - #[test] - fn stream_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel(); - - send(tx, 0); - recv(rx, 0); - - fn send(tx: Sender>, i: i32) { - if i == 10 { return } - - thread::spawn(move|| { - tx.send(box i).unwrap(); - send(tx, i + 1); - }); - } - - fn recv(rx: Receiver>, i: i32) { - if i == 10 { return } - - thread::spawn(move|| { - assert!(*rx.recv().unwrap() == i); - recv(rx, i + 1); - }); - } - } - } - - #[test] - fn oneshot_single_thread_recv_timeout() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); - tx.send(()).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); - } - - #[test] - fn stress_recv_timeout_two_threads() { - let (tx, rx) = channel(); - let stress = stress_factor() + 100; - let timeout = Duration::from_millis(100); - - thread::spawn(move || { - for i in 0..stress { - if i % 2 == 0 { - thread::sleep(timeout * 2); - } - tx.send(1usize).unwrap(); - } - }); - - let mut recv_count = 0; - loop { - match rx.recv_timeout(timeout) { - Ok(n) => { - assert_eq!(n, 1usize); - recv_count += 1; - } - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, stress); - } - - #[test] - fn recv_timeout_upgrade() { - let (tx, rx) = channel::<()>(); - let timeout = Duration::from_millis(1); - let _tx_clone = tx.clone(); - - let start = Instant::now(); - assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout)); - assert!(Instant::now() >= start + timeout); - } - - #[test] - fn stress_recv_timeout_shared() { - let (tx, rx) = channel(); - let stress = stress_factor() + 100; - - for i in 0..stress { - let tx = tx.clone(); - thread::spawn(move || { - thread::sleep(Duration::from_millis(i as u64 * 10)); - tx.send(1usize).unwrap(); - }); - } - - drop(tx); - - let mut recv_count = 0; - loop { - match rx.recv_timeout(Duration::from_millis(10)) { - Ok(n) => { - assert_eq!(n, 1usize); - recv_count += 1; - } - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, stress); - } - - #[test] - fn recv_a_lot() { - // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = channel(); - for _ in 0..10000 { tx.send(()).unwrap(); } - for _ in 0..10000 { rx.recv().unwrap(); } - } - - #[test] - fn shared_recv_timeout() { - let (tx, rx) = channel(); - let total = 5; - for _ in 0..total { - let tx = tx.clone(); - thread::spawn(move|| { - tx.send(()).unwrap(); - }); - } - - for _ in 0..total { rx.recv().unwrap(); } - - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); - tx.send(()).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); - } - - #[test] - fn shared_chan_stress() { - let (tx, rx) = channel(); - let total = stress_factor() + 100; - for _ in 0..total { - let tx = tx.clone(); - thread::spawn(move|| { - tx.send(()).unwrap(); - }); - } - - for _ in 0..total { - rx.recv().unwrap(); - } - } - - #[test] - fn test_nested_recv_iter() { - let (tx, rx) = channel::(); - let (total_tx, total_rx) = channel::(); - - let _t = thread::spawn(move|| { - let mut acc = 0; - for x in rx.iter() { - acc += x; - } - total_tx.send(acc).unwrap(); - }); - - tx.send(3).unwrap(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - drop(tx); - assert_eq!(total_rx.recv().unwrap(), 6); - } - - #[test] - fn test_recv_iter_break() { - let (tx, rx) = channel::(); - let (count_tx, count_rx) = channel(); - - let _t = thread::spawn(move|| { - let mut count = 0; - for x in rx.iter() { - if count >= 3 { - break; - } else { - count += x; - } - } - count_tx.send(count).unwrap(); - }); - - tx.send(2).unwrap(); - tx.send(2).unwrap(); - tx.send(2).unwrap(); - let _ = tx.send(2); - drop(tx); - assert_eq!(count_rx.recv().unwrap(), 4); - } - - #[test] - fn test_recv_try_iter() { - let (request_tx, request_rx) = channel(); - let (response_tx, response_rx) = channel(); - - // Request `x`s until we have `6`. - let t = thread::spawn(move|| { - let mut count = 0; - loop { - for x in response_rx.try_iter() { - count += x; - if count == 6 { - return count; - } - } - request_tx.send(()).unwrap(); - } - }); - - for _ in request_rx.iter() { - if response_tx.send(2).is_err() { - break; - } - } - - assert_eq!(t.join().unwrap(), 6); - } - - #[test] - fn test_recv_into_iter_owned() { - let mut iter = { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - - rx.into_iter() - }; - assert_eq!(iter.next().unwrap(), 1); - assert_eq!(iter.next().unwrap(), 2); - assert_eq!(iter.next().is_none(), true); - } - - #[test] - fn test_recv_into_iter_borrowed() { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - drop(tx); - let mut iter = (&rx).into_iter(); - assert_eq!(iter.next().unwrap(), 1); - assert_eq!(iter.next().unwrap(), 2); - assert_eq!(iter.next().is_none(), true); - } - - #[test] - fn try_recv_states() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::<()>(); - let (tx3, rx3) = channel::<()>(); - let _t = thread::spawn(move|| { - rx2.recv().unwrap(); - tx1.send(1).unwrap(); - tx3.send(()).unwrap(); - rx2.recv().unwrap(); - drop(tx1); - tx3.send(()).unwrap(); - }); - - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Ok(1)); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); - } - - // This bug used to end up in a livelock inside of the Receiver destructor - // because the internal state of the Shared packet was corrupted - #[test] - fn destroy_upgraded_shared_port_when_sender_still_active() { - let (tx, rx) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - rx.recv().unwrap(); // wait on a oneshot - drop(rx); // destroy a shared - tx2.send(()).unwrap(); - }); - // make sure the other thread has gone to sleep - for _ in 0..5000 { thread::yield_now(); } - - // upgrade to a shared chan and send a message - let t = tx.clone(); - drop(tx); - t.send(()).unwrap(); - - // wait for the child thread to exit before we exit - rx2.recv().unwrap(); - } - - #[test] - fn issue_32114() { - let (tx, _) = channel(); - let _ = tx.send(123); - assert_eq!(tx.send(123), Err(SendError(123))); - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod sync_tests { - use env; - use thread; - use super::*; - use time::Duration; - - pub fn stress_factor() -> usize { - match env::var("RUST_TEST_STRESS") { - Ok(val) => val.parse().unwrap(), - Err(..) => 1, - } - } - - #[test] - fn smoke() { - let (tx, rx) = sync_channel::(1); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn drop_full() { - let (tx, _rx) = sync_channel::>(1); - tx.send(box 1).unwrap(); - } - - #[test] - fn smoke_shared() { - let (tx, rx) = sync_channel::(1); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - let tx = tx.clone(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn recv_timeout() { - let (tx, rx) = sync_channel::(1); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); - tx.send(1).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1)); - } - - #[test] - fn smoke_threads() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move|| { - tx.send(1).unwrap(); - }); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn smoke_port_gone() { - let (tx, rx) = sync_channel::(0); - drop(rx); - assert!(tx.send(1).is_err()); - } - - #[test] - fn smoke_shared_port_gone2() { - let (tx, rx) = sync_channel::(0); - drop(rx); - let tx2 = tx.clone(); - drop(tx); - assert!(tx2.send(1).is_err()); - } - - #[test] - fn port_gone_concurrent() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move|| { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() {} - } - - #[test] - fn port_gone_concurrent_shared() { - let (tx, rx) = sync_channel::(0); - let tx2 = tx.clone(); - let _t = thread::spawn(move|| { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() && tx2.send(1).is_ok() {} - } - - #[test] - fn smoke_chan_gone() { - let (tx, rx) = sync_channel::(0); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn smoke_chan_gone_shared() { - let (tx, rx) = sync_channel::<()>(0); - let tx2 = tx.clone(); - drop(tx); - drop(tx2); - assert!(rx.recv().is_err()); - } - - #[test] - fn chan_gone_concurrent() { - let (tx, rx) = sync_channel::(0); - thread::spawn(move|| { - tx.send(1).unwrap(); - tx.send(1).unwrap(); - }); - while rx.recv().is_ok() {} - } - - #[test] - fn stress() { - let (tx, rx) = sync_channel::(0); - thread::spawn(move|| { - for _ in 0..10000 { tx.send(1).unwrap(); } - }); - for _ in 0..10000 { - assert_eq!(rx.recv().unwrap(), 1); - } - } - - #[test] - fn stress_recv_timeout_two_threads() { - let (tx, rx) = sync_channel::(0); - - thread::spawn(move|| { - for _ in 0..10000 { tx.send(1).unwrap(); } - }); - - let mut recv_count = 0; - loop { - match rx.recv_timeout(Duration::from_millis(1)) { - Ok(v) => { - assert_eq!(v, 1); - recv_count += 1; - }, - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, 10000); - } - - #[test] - fn stress_recv_timeout_shared() { - const AMT: u32 = 1000; - const NTHREADS: u32 = 8; - let (tx, rx) = sync_channel::(0); - let (dtx, drx) = sync_channel::<()>(0); - - thread::spawn(move|| { - let mut recv_count = 0; - loop { - match rx.recv_timeout(Duration::from_millis(10)) { - Ok(v) => { - assert_eq!(v, 1); - recv_count += 1; - }, - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, AMT * NTHREADS); - assert!(rx.try_recv().is_err()); - - dtx.send(()).unwrap(); - }); - - for _ in 0..NTHREADS { - let tx = tx.clone(); - thread::spawn(move|| { - for _ in 0..AMT { tx.send(1).unwrap(); } - }); - } - - drop(tx); - - drx.recv().unwrap(); - } - - #[test] - fn stress_shared() { - const AMT: u32 = 1000; - const NTHREADS: u32 = 8; - let (tx, rx) = sync_channel::(0); - let (dtx, drx) = sync_channel::<()>(0); - - thread::spawn(move|| { - for _ in 0..AMT * NTHREADS { - assert_eq!(rx.recv().unwrap(), 1); - } - match rx.try_recv() { - Ok(..) => panic!(), - _ => {} - } - dtx.send(()).unwrap(); - }); - - for _ in 0..NTHREADS { - let tx = tx.clone(); - thread::spawn(move|| { - for _ in 0..AMT { tx.send(1).unwrap(); } - }); - } - drop(tx); - drx.recv().unwrap(); - } - - #[test] - fn oneshot_single_thread_close_port_first() { - // Simple test of closing without sending - let (_tx, rx) = sync_channel::(0); - drop(rx); - } - - #[test] - fn oneshot_single_thread_close_chan_first() { - // Simple test of closing without sending - let (tx, _rx) = sync_channel::(0); - drop(tx); - } - - #[test] - fn oneshot_single_thread_send_port_close() { - // Testing that the sender cleans up the payload if receiver is closed - let (tx, rx) = sync_channel::>(0); - drop(rx); - assert!(tx.send(box 0).is_err()); - } - - #[test] - fn oneshot_single_thread_recv_chan_close() { - // Receiving on a closed chan will panic - let res = thread::spawn(move|| { - let (tx, rx) = sync_channel::(0); - drop(tx); - rx.recv().unwrap(); - }).join(); - // What is our res? - assert!(res.is_err()); - } - - #[test] - fn oneshot_single_thread_send_then_recv() { - let (tx, rx) = sync_channel::>(1); - tx.send(box 10).unwrap(); - assert!(*rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_open() { - let (tx, rx) = sync_channel::(1); - assert_eq!(tx.try_send(10), Ok(())); - assert!(rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_closed() { - let (tx, rx) = sync_channel::(0); - drop(rx); - assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10))); - } - - #[test] - fn oneshot_single_thread_try_send_closed2() { - let (tx, _rx) = sync_channel::(0); - assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); - } - - #[test] - fn oneshot_single_thread_try_recv_open() { - let (tx, rx) = sync_channel::(1); - tx.send(10).unwrap(); - assert!(rx.recv() == Ok(10)); - } - - #[test] - fn oneshot_single_thread_try_recv_closed() { - let (tx, rx) = sync_channel::(0); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn oneshot_single_thread_try_recv_closed_with_data() { - let (tx, rx) = sync_channel::(1); - tx.send(10).unwrap(); - drop(tx); - assert_eq!(rx.try_recv(), Ok(10)); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - } - - #[test] - fn oneshot_single_thread_peek_data() { - let (tx, rx) = sync_channel::(1); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - tx.send(10).unwrap(); - assert_eq!(rx.try_recv(), Ok(10)); - } - - #[test] - fn oneshot_single_thread_peek_close() { - let (tx, rx) = sync_channel::(0); - drop(tx); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - } - - #[test] - fn oneshot_single_thread_peek_open() { - let (_tx, rx) = sync_channel::(0); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - } - - #[test] - fn oneshot_multi_task_recv_then_send() { - let (tx, rx) = sync_channel::>(0); - let _t = thread::spawn(move|| { - assert!(*rx.recv().unwrap() == 10); - }); - - tx.send(box 10).unwrap(); - } - - #[test] - fn oneshot_multi_task_recv_then_close() { - let (tx, rx) = sync_channel::>(0); - let _t = thread::spawn(move|| { - drop(tx); - }); - let res = thread::spawn(move|| { - assert!(*rx.recv().unwrap() == 10); - }).join(); - assert!(res.is_err()); - } - - #[test] - fn oneshot_multi_thread_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move|| { - drop(rx); - }); - drop(tx); - } - } - - #[test] - fn oneshot_multi_thread_send_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move|| { - drop(rx); - }); - let _ = thread::spawn(move || { - tx.send(1).unwrap(); - }).join(); - } - } - - #[test] - fn oneshot_multi_thread_recv_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move|| { - let res = thread::spawn(move|| { - rx.recv().unwrap(); - }).join(); - assert!(res.is_err()); - }); - let _t = thread::spawn(move|| { - thread::spawn(move|| { - drop(tx); - }); - }); - } - } - - #[test] - fn oneshot_multi_thread_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::>(0); - let _t = thread::spawn(move|| { - tx.send(box 10).unwrap(); - }); - assert!(*rx.recv().unwrap() == 10); - } - } - - #[test] - fn stream_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::>(0); - - send(tx, 0); - recv(rx, 0); - - fn send(tx: SyncSender>, i: i32) { - if i == 10 { return } - - thread::spawn(move|| { - tx.send(box i).unwrap(); - send(tx, i + 1); - }); - } - - fn recv(rx: Receiver>, i: i32) { - if i == 10 { return } - - thread::spawn(move|| { - assert!(*rx.recv().unwrap() == i); - recv(rx, i + 1); - }); - } - } - } - - #[test] - fn recv_a_lot() { - // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = sync_channel(10000); - for _ in 0..10000 { tx.send(()).unwrap(); } - for _ in 0..10000 { rx.recv().unwrap(); } - } - - #[test] - fn shared_chan_stress() { - let (tx, rx) = sync_channel(0); - let total = stress_factor() + 100; - for _ in 0..total { - let tx = tx.clone(); - thread::spawn(move|| { - tx.send(()).unwrap(); - }); - } - - for _ in 0..total { - rx.recv().unwrap(); - } - } - - #[test] - fn test_nested_recv_iter() { - let (tx, rx) = sync_channel::(0); - let (total_tx, total_rx) = sync_channel::(0); - - let _t = thread::spawn(move|| { - let mut acc = 0; - for x in rx.iter() { - acc += x; - } - total_tx.send(acc).unwrap(); - }); - - tx.send(3).unwrap(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - drop(tx); - assert_eq!(total_rx.recv().unwrap(), 6); - } - - #[test] - fn test_recv_iter_break() { - let (tx, rx) = sync_channel::(0); - let (count_tx, count_rx) = sync_channel(0); - - let _t = thread::spawn(move|| { - let mut count = 0; - for x in rx.iter() { - if count >= 3 { - break; - } else { - count += x; - } - } - count_tx.send(count).unwrap(); - }); - - tx.send(2).unwrap(); - tx.send(2).unwrap(); - tx.send(2).unwrap(); - let _ = tx.try_send(2); - drop(tx); - assert_eq!(count_rx.recv().unwrap(), 4); - } - - #[test] - fn try_recv_states() { - let (tx1, rx1) = sync_channel::(1); - let (tx2, rx2) = sync_channel::<()>(1); - let (tx3, rx3) = sync_channel::<()>(1); - let _t = thread::spawn(move|| { - rx2.recv().unwrap(); - tx1.send(1).unwrap(); - tx3.send(()).unwrap(); - rx2.recv().unwrap(); - drop(tx1); - tx3.send(()).unwrap(); - }); - - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Ok(1)); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); - } - - // This bug used to end up in a livelock inside of the Receiver destructor - // because the internal state of the Shared packet was corrupted - #[test] - fn destroy_upgraded_shared_port_when_sender_still_active() { - let (tx, rx) = sync_channel::<()>(0); - let (tx2, rx2) = sync_channel::<()>(0); - let _t = thread::spawn(move|| { - rx.recv().unwrap(); // wait on a oneshot - drop(rx); // destroy a shared - tx2.send(()).unwrap(); - }); - // make sure the other thread has gone to sleep - for _ in 0..5000 { thread::yield_now(); } - - // upgrade to a shared chan and send a message - let t = tx.clone(); - drop(tx); - t.send(()).unwrap(); - - // wait for the child thread to exit before we exit - rx2.recv().unwrap(); - } - - #[test] - fn send1() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move|| { rx.recv().unwrap(); }); - assert_eq!(tx.send(1), Ok(())); - } - - #[test] - fn send2() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move|| { drop(rx); }); - assert!(tx.send(1).is_err()); - } - - #[test] - fn send3() { - let (tx, rx) = sync_channel::(1); - assert_eq!(tx.send(1), Ok(())); - let _t =thread::spawn(move|| { drop(rx); }); - assert!(tx.send(1).is_err()); - } - - #[test] - fn send4() { - let (tx, rx) = sync_channel::(0); - let tx2 = tx.clone(); - let (done, donerx) = channel(); - let done2 = done.clone(); - let _t = thread::spawn(move|| { - assert!(tx.send(1).is_err()); - done.send(()).unwrap(); - }); - let _t = thread::spawn(move|| { - assert!(tx2.send(2).is_err()); - done2.send(()).unwrap(); - }); - drop(rx); - donerx.recv().unwrap(); - donerx.recv().unwrap(); - } - - #[test] - fn try_send1() { - let (tx, _rx) = sync_channel::(0); - assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); - } - - #[test] - fn try_send2() { - let (tx, _rx) = sync_channel::(1); - assert_eq!(tx.try_send(1), Ok(())); - assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); - } - - #[test] - fn try_send3() { - let (tx, rx) = sync_channel::(1); - assert_eq!(tx.try_send(1), Ok(())); - drop(rx); - assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1))); - } - - #[test] - fn issue_15761() { - fn repro() { - let (tx1, rx1) = sync_channel::<()>(3); - let (tx2, rx2) = sync_channel::<()>(3); - - let _t = thread::spawn(move|| { - rx1.recv().unwrap(); - tx2.try_send(()).unwrap(); - }); - - tx1.try_send(()).unwrap(); - rx2.recv().unwrap(); - } - - for _ in 0..100 { - repro() - } - } -} diff --git a/ctr-std/src/sync/mpsc/mpsc_queue.rs b/ctr-std/src/sync/mpsc/mpsc_queue.rs deleted file mode 100644 index df945ac..0000000 --- a/ctr-std/src/sync/mpsc/mpsc_queue.rs +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A mostly lock-free multi-producer, single consumer queue. -//! -//! This module contains an implementation of a concurrent MPSC queue. This -//! queue can be used to share data between threads, and is also used as the -//! building block of channels in rust. -//! -//! Note that the current implementation of this queue has a caveat of the `pop` -//! method, and see the method for more information about it. Due to this -//! caveat, this queue may not be appropriate for all use-cases. - -// http://www.1024cores.net/home/lock-free-algorithms -// /queues/non-intrusive-mpsc-node-based-queue - -pub use self::PopResult::*; - -use core::ptr; -use core::cell::UnsafeCell; -use boxed::Box; -use sync::atomic::{AtomicPtr, Ordering}; - -/// A result of the `pop` function. -pub enum PopResult { - /// Some data has been popped - Data(T), - /// The queue is empty - Empty, - /// The queue is in an inconsistent state. Popping data should succeed, but - /// some pushers have yet to make enough progress in order allow a pop to - /// succeed. It is recommended that a pop() occur "in the near future" in - /// order to see if the sender has made progress or not - Inconsistent, -} - -struct Node { - next: AtomicPtr>, - value: Option, -} - -/// The multi-producer single-consumer structure. This is not cloneable, but it -/// may be safely shared so long as it is guaranteed that there is only one -/// popper at a time (many pushers are allowed). -pub struct Queue { - head: AtomicPtr>, - tail: UnsafeCell<*mut Node>, -} - -unsafe impl Send for Queue { } -unsafe impl Sync for Queue { } - -impl Node { - unsafe fn new(v: Option) -> *mut Node { - Box::into_raw(box Node { - next: AtomicPtr::new(ptr::null_mut()), - value: v, - }) - } -} - -impl Queue { - /// Creates a new queue that is safe to share among multiple producers and - /// one consumer. - pub fn new() -> Queue { - let stub = unsafe { Node::new(None) }; - Queue { - head: AtomicPtr::new(stub), - tail: UnsafeCell::new(stub), - } - } - - /// Pushes a new value onto this queue. - pub fn push(&self, t: T) { - unsafe { - let n = Node::new(Some(t)); - let prev = self.head.swap(n, Ordering::AcqRel); - (*prev).next.store(n, Ordering::Release); - } - } - - /// Pops some data from this queue. - /// - /// Note that the current implementation means that this function cannot - /// return `Option`. It is possible for this queue to be in an - /// inconsistent state where many pushes have succeeded and completely - /// finished, but pops cannot return `Some(t)`. This inconsistent state - /// happens when a pusher is pre-empted at an inopportune moment. - /// - /// This inconsistent state means that this queue does indeed have data, but - /// it does not currently have access to it at this time. - pub fn pop(&self) -> PopResult { - unsafe { - let tail = *self.tail.get(); - let next = (*tail).next.load(Ordering::Acquire); - - if !next.is_null() { - *self.tail.get() = next; - assert!((*tail).value.is_none()); - assert!((*next).value.is_some()); - let ret = (*next).value.take().unwrap(); - let _: Box> = Box::from_raw(tail); - return Data(ret); - } - - if self.head.load(Ordering::Acquire) == tail {Empty} else {Inconsistent} - } - } -} - -impl Drop for Queue { - fn drop(&mut self) { - unsafe { - let mut cur = *self.tail.get(); - while !cur.is_null() { - let next = (*cur).next.load(Ordering::Relaxed); - let _: Box> = Box::from_raw(cur); - cur = next; - } - } - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use sync::mpsc::channel; - use super::{Queue, Data, Empty, Inconsistent}; - use sync::Arc; - use thread; - - #[test] - fn test_full() { - let q: Queue> = Queue::new(); - q.push(box 1); - q.push(box 2); - } - - #[test] - fn test() { - let nthreads = 8; - let nmsgs = 1000; - let q = Queue::new(); - match q.pop() { - Empty => {} - Inconsistent | Data(..) => panic!() - } - let (tx, rx) = channel(); - let q = Arc::new(q); - - for _ in 0..nthreads { - let tx = tx.clone(); - let q = q.clone(); - thread::spawn(move|| { - for i in 0..nmsgs { - q.push(i); - } - tx.send(()).unwrap(); - }); - } - - let mut i = 0; - while i < nthreads * nmsgs { - match q.pop() { - Empty | Inconsistent => {}, - Data(_) => { i += 1 } - } - } - drop(tx); - for _ in 0..nthreads { - rx.recv().unwrap(); - } - } -} diff --git a/ctr-std/src/sync/mpsc/oneshot.rs b/ctr-std/src/sync/mpsc/oneshot.rs deleted file mode 100644 index b8e50c9..0000000 --- a/ctr-std/src/sync/mpsc/oneshot.rs +++ /dev/null @@ -1,396 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Oneshot channels/ports -/// -/// This is the initial flavor of channels/ports used for comm module. This is -/// an optimization for the one-use case of a channel. The major optimization of -/// this type is to have one and exactly one allocation when the chan/port pair -/// is created. -/// -/// Another possible optimization would be to not use an Arc box because -/// in theory we know when the shared packet can be deallocated (no real need -/// for the atomic reference counting), but I was having trouble how to destroy -/// the data early in a drop of a Port. -/// -/// # Implementation -/// -/// Oneshots are implemented around one atomic usize variable. This variable -/// indicates both the state of the port/chan but also contains any threads -/// blocked on the port. All atomic operations happen on this one word. -/// -/// In order to upgrade a oneshot channel, an upgrade is considered a disconnect -/// on behalf of the channel side of things (it can be mentally thought of as -/// consuming the port). This upgrade is then also stored in the shared packet. -/// The one caveat to consider is that when a port sees a disconnected channel -/// it must check for data because there is no "data plus upgrade" state. - -pub use self::Failure::*; -pub use self::UpgradeResult::*; -pub use self::SelectionResult::*; -use self::MyUpgrade::*; - -use sync::mpsc::Receiver; -use sync::mpsc::blocking::{self, SignalToken}; -use cell::UnsafeCell; -use ptr; -use sync::atomic::{AtomicUsize, Ordering}; -use time::Instant; - -// Various states you can find a port in. -const EMPTY: usize = 0; // initial state: no data, no blocked receiver -const DATA: usize = 1; // data ready for receiver to take -const DISCONNECTED: usize = 2; // channel is disconnected OR upgraded -// Any other value represents a pointer to a SignalToken value. The -// protocol ensures that when the state moves *to* a pointer, -// ownership of the token is given to the packet, and when the state -// moves *from* a pointer, ownership of the token is transferred to -// whoever changed the state. - -pub struct Packet { - // Internal state of the chan/port pair (stores the blocked thread as well) - state: AtomicUsize, - // One-shot data slot location - data: UnsafeCell>, - // when used for the second time, a oneshot channel must be upgraded, and - // this contains the slot for the upgrade - upgrade: UnsafeCell>, -} - -pub enum Failure { - Empty, - Disconnected, - Upgraded(Receiver), -} - -pub enum UpgradeResult { - UpSuccess, - UpDisconnected, - UpWoke(SignalToken), -} - -pub enum SelectionResult { - SelCanceled, - SelUpgraded(SignalToken, Receiver), - SelSuccess, -} - -enum MyUpgrade { - NothingSent, - SendUsed, - GoUp(Receiver), -} - -impl Packet { - pub fn new() -> Packet { - Packet { - data: UnsafeCell::new(None), - upgrade: UnsafeCell::new(NothingSent), - state: AtomicUsize::new(EMPTY), - } - } - - pub fn send(&self, t: T) -> Result<(), T> { - unsafe { - // Sanity check - match *self.upgrade.get() { - NothingSent => {} - _ => panic!("sending on a oneshot that's already sent on "), - } - assert!((*self.data.get()).is_none()); - ptr::write(self.data.get(), Some(t)); - ptr::write(self.upgrade.get(), SendUsed); - - match self.state.swap(DATA, Ordering::SeqCst) { - // Sent the data, no one was waiting - EMPTY => Ok(()), - - // Couldn't send the data, the port hung up first. Return the data - // back up the stack. - DISCONNECTED => { - self.state.swap(DISCONNECTED, Ordering::SeqCst); - ptr::write(self.upgrade.get(), NothingSent); - Err((&mut *self.data.get()).take().unwrap()) - } - - // Not possible, these are one-use channels - DATA => unreachable!(), - - // There is a thread waiting on the other end. We leave the 'DATA' - // state inside so it'll pick it up on the other end. - ptr => { - SignalToken::cast_from_usize(ptr).signal(); - Ok(()) - } - } - } - } - - // Just tests whether this channel has been sent on or not, this is only - // safe to use from the sender. - pub fn sent(&self) -> bool { - unsafe { - match *self.upgrade.get() { - NothingSent => false, - _ => true, - } - } - } - - pub fn recv(&self, deadline: Option) -> Result> { - // Attempt to not block the thread (it's a little expensive). If it looks - // like we're not empty, then immediately go through to `try_recv`. - if self.state.load(Ordering::SeqCst) == EMPTY { - let (wait_token, signal_token) = blocking::tokens(); - let ptr = unsafe { signal_token.cast_to_usize() }; - - // race with senders to enter the blocking state - if self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) == EMPTY { - if let Some(deadline) = deadline { - let timed_out = !wait_token.wait_max_until(deadline); - // Try to reset the state - if timed_out { - self.abort_selection().map_err(Upgraded)?; - } - } else { - wait_token.wait(); - debug_assert!(self.state.load(Ordering::SeqCst) != EMPTY); - } - } else { - // drop the signal token, since we never blocked - drop(unsafe { SignalToken::cast_from_usize(ptr) }); - } - } - - self.try_recv() - } - - pub fn try_recv(&self) -> Result> { - unsafe { - match self.state.load(Ordering::SeqCst) { - EMPTY => Err(Empty), - - // We saw some data on the channel, but the channel can be used - // again to send us an upgrade. As a result, we need to re-insert - // into the channel that there's no data available (otherwise we'll - // just see DATA next time). This is done as a cmpxchg because if - // the state changes under our feet we'd rather just see that state - // change. - DATA => { - self.state.compare_and_swap(DATA, EMPTY, Ordering::SeqCst); - match (&mut *self.data.get()).take() { - Some(data) => Ok(data), - None => unreachable!(), - } - } - - // There's no guarantee that we receive before an upgrade happens, - // and an upgrade flags the channel as disconnected, so when we see - // this we first need to check if there's data available and *then* - // we go through and process the upgrade. - DISCONNECTED => { - match (&mut *self.data.get()).take() { - Some(data) => Ok(data), - None => { - match ptr::replace(self.upgrade.get(), SendUsed) { - SendUsed | NothingSent => Err(Disconnected), - GoUp(upgrade) => Err(Upgraded(upgrade)) - } - } - } - } - - // We are the sole receiver; there cannot be a blocking - // receiver already. - _ => unreachable!() - } - } - } - - // Returns whether the upgrade was completed. If the upgrade wasn't - // completed, then the port couldn't get sent to the other half (it will - // never receive it). - pub fn upgrade(&self, up: Receiver) -> UpgradeResult { - unsafe { - let prev = match *self.upgrade.get() { - NothingSent => NothingSent, - SendUsed => SendUsed, - _ => panic!("upgrading again"), - }; - ptr::write(self.upgrade.get(), GoUp(up)); - - match self.state.swap(DISCONNECTED, Ordering::SeqCst) { - // If the channel is empty or has data on it, then we're good to go. - // Senders will check the data before the upgrade (in case we - // plastered over the DATA state). - DATA | EMPTY => UpSuccess, - - // If the other end is already disconnected, then we failed the - // upgrade. Be sure to trash the port we were given. - DISCONNECTED => { ptr::replace(self.upgrade.get(), prev); UpDisconnected } - - // If someone's waiting, we gotta wake them up - ptr => UpWoke(SignalToken::cast_from_usize(ptr)) - } - } - } - - pub fn drop_chan(&self) { - match self.state.swap(DISCONNECTED, Ordering::SeqCst) { - DATA | DISCONNECTED | EMPTY => {} - - // If someone's waiting, we gotta wake them up - ptr => unsafe { - SignalToken::cast_from_usize(ptr).signal(); - } - } - } - - pub fn drop_port(&self) { - match self.state.swap(DISCONNECTED, Ordering::SeqCst) { - // An empty channel has nothing to do, and a remotely disconnected - // channel also has nothing to do b/c we're about to run the drop - // glue - DISCONNECTED | EMPTY => {} - - // There's data on the channel, so make sure we destroy it promptly. - // This is why not using an arc is a little difficult (need the box - // to stay valid while we take the data). - DATA => unsafe { (&mut *self.data.get()).take().unwrap(); }, - - // We're the only ones that can block on this port - _ => unreachable!() - } - } - - //////////////////////////////////////////////////////////////////////////// - // select implementation - //////////////////////////////////////////////////////////////////////////// - - // If Ok, the value is whether this port has data, if Err, then the upgraded - // port needs to be checked instead of this one. - pub fn can_recv(&self) -> Result> { - unsafe { - match self.state.load(Ordering::SeqCst) { - EMPTY => Ok(false), // Welp, we tried - DATA => Ok(true), // we have some un-acquired data - DISCONNECTED if (*self.data.get()).is_some() => Ok(true), // we have data - DISCONNECTED => { - match ptr::replace(self.upgrade.get(), SendUsed) { - // The other end sent us an upgrade, so we need to - // propagate upwards whether the upgrade can receive - // data - GoUp(upgrade) => Err(upgrade), - - // If the other end disconnected without sending an - // upgrade, then we have data to receive (the channel is - // disconnected). - up => { ptr::write(self.upgrade.get(), up); Ok(true) } - } - } - _ => unreachable!(), // we're the "one blocker" - } - } - } - - // Attempts to start selection on this port. This can either succeed, fail - // because there is data, or fail because there is an upgrade pending. - pub fn start_selection(&self, token: SignalToken) -> SelectionResult { - unsafe { - let ptr = token.cast_to_usize(); - match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) { - EMPTY => SelSuccess, - DATA => { - drop(SignalToken::cast_from_usize(ptr)); - SelCanceled - } - DISCONNECTED if (*self.data.get()).is_some() => { - drop(SignalToken::cast_from_usize(ptr)); - SelCanceled - } - DISCONNECTED => { - match ptr::replace(self.upgrade.get(), SendUsed) { - // The other end sent us an upgrade, so we need to - // propagate upwards whether the upgrade can receive - // data - GoUp(upgrade) => { - SelUpgraded(SignalToken::cast_from_usize(ptr), upgrade) - } - - // If the other end disconnected without sending an - // upgrade, then we have data to receive (the channel is - // disconnected). - up => { - ptr::write(self.upgrade.get(), up); - drop(SignalToken::cast_from_usize(ptr)); - SelCanceled - } - } - } - _ => unreachable!(), // we're the "one blocker" - } - } - } - - // Remove a previous selecting thread from this port. This ensures that the - // blocked thread will no longer be visible to any other threads. - // - // The return value indicates whether there's data on this port. - pub fn abort_selection(&self) -> Result> { - let state = match self.state.load(Ordering::SeqCst) { - // Each of these states means that no further activity will happen - // with regard to abortion selection - s @ EMPTY | - s @ DATA | - s @ DISCONNECTED => s, - - // If we've got a blocked thread, then use an atomic to gain ownership - // of it (may fail) - ptr => self.state.compare_and_swap(ptr, EMPTY, Ordering::SeqCst) - }; - - // Now that we've got ownership of our state, figure out what to do - // about it. - match state { - EMPTY => unreachable!(), - // our thread used for select was stolen - DATA => Ok(true), - - // If the other end has hung up, then we have complete ownership - // of the port. First, check if there was data waiting for us. This - // is possible if the other end sent something and then hung up. - // - // We then need to check to see if there was an upgrade requested, - // and if so, the upgraded port needs to have its selection aborted. - DISCONNECTED => unsafe { - if (*self.data.get()).is_some() { - Ok(true) - } else { - match ptr::replace(self.upgrade.get(), SendUsed) { - GoUp(port) => Err(port), - _ => Ok(true), - } - } - }, - - // We woke ourselves up from select. - ptr => unsafe { - drop(SignalToken::cast_from_usize(ptr)); - Ok(false) - } - } - } -} - -impl Drop for Packet { - fn drop(&mut self) { - assert_eq!(self.state.load(Ordering::SeqCst), DISCONNECTED); - } -} diff --git a/ctr-std/src/sync/mpsc/select.rs b/ctr-std/src/sync/mpsc/select.rs deleted file mode 100644 index a7a284c..0000000 --- a/ctr-std/src/sync/mpsc/select.rs +++ /dev/null @@ -1,779 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Selection over an array of receivers -//! -//! This module contains the implementation machinery necessary for selecting -//! over a number of receivers. One large goal of this module is to provide an -//! efficient interface to selecting over any receiver of any type. -//! -//! This is achieved through an architecture of a "receiver set" in which -//! receivers are added to a set and then the entire set is waited on at once. -//! The set can be waited on multiple times to prevent re-adding each receiver -//! to the set. -//! -//! Usage of this module is currently encouraged to go through the use of the -//! `select!` macro. This macro allows naturally binding of variables to the -//! received values of receivers in a much more natural syntax then usage of the -//! `Select` structure directly. -//! -//! # Examples -//! -//! ```rust -//! #![feature(mpsc_select)] -//! -//! use std::sync::mpsc::channel; -//! -//! let (tx1, rx1) = channel(); -//! let (tx2, rx2) = channel(); -//! -//! tx1.send(1).unwrap(); -//! tx2.send(2).unwrap(); -//! -//! select! { -//! val = rx1.recv() => { -//! assert_eq!(val.unwrap(), 1); -//! }, -//! val = rx2.recv() => { -//! assert_eq!(val.unwrap(), 2); -//! } -//! } -//! ``` - -#![allow(dead_code)] -#![unstable(feature = "mpsc_select", - reason = "This implementation, while likely sufficient, is unsafe and \ - likely to be error prone. At some point in the future this \ - module will likely be replaced, and it is currently \ - unknown how much API breakage that will cause. The ability \ - to select over a number of channels will remain forever, \ - but no guarantees beyond this are being made", - issue = "27800")] - - -use fmt; - -use core::cell::{Cell, UnsafeCell}; -use core::marker; -use core::ptr; -use core::usize; - -use sync::mpsc::{Receiver, RecvError}; -use sync::mpsc::blocking::{self, SignalToken}; - -/// The "receiver set" of the select interface. This structure is used to manage -/// a set of receivers which are being selected over. -pub struct Select { - inner: UnsafeCell, - next_id: Cell, -} - -struct SelectInner { - head: *mut Handle<'static, ()>, - tail: *mut Handle<'static, ()>, -} - -impl !marker::Send for Select {} - -/// A handle to a receiver which is currently a member of a `Select` set of -/// receivers. This handle is used to keep the receiver in the set as well as -/// interact with the underlying receiver. -pub struct Handle<'rx, T:Send+'rx> { - /// The ID of this handle, used to compare against the return value of - /// `Select::wait()` - id: usize, - selector: *mut SelectInner, - next: *mut Handle<'static, ()>, - prev: *mut Handle<'static, ()>, - added: bool, - packet: &'rx (dyn Packet+'rx), - - // due to our fun transmutes, we be sure to place this at the end. (nothing - // previous relies on T) - rx: &'rx Receiver, -} - -struct Packets { cur: *mut Handle<'static, ()> } - -#[doc(hidden)] -#[derive(PartialEq, Eq)] -pub enum StartResult { - Installed, - Abort, -} - -#[doc(hidden)] -pub trait Packet { - fn can_recv(&self) -> bool; - fn start_selection(&self, token: SignalToken) -> StartResult; - fn abort_selection(&self) -> bool; -} - -impl Select { - /// Creates a new selection structure. This set is initially empty. - /// - /// Usage of this struct directly can sometimes be burdensome, and usage is much easier through - /// the `select!` macro. - /// - /// # Examples - /// - /// ``` - /// #![feature(mpsc_select)] - /// - /// use std::sync::mpsc::Select; - /// - /// let select = Select::new(); - /// ``` - pub fn new() -> Select { - Select { - inner: UnsafeCell::new(SelectInner { - head: ptr::null_mut(), - tail: ptr::null_mut(), - }), - next_id: Cell::new(1), - } - } - - /// Creates a new handle into this receiver set for a new receiver. Note - /// that this does *not* add the receiver to the receiver set, for that you - /// must call the `add` method on the handle itself. - pub fn handle<'a, T: Send>(&'a self, rx: &'a Receiver) -> Handle<'a, T> { - let id = self.next_id.get(); - self.next_id.set(id + 1); - Handle { - id, - selector: self.inner.get(), - next: ptr::null_mut(), - prev: ptr::null_mut(), - added: false, - rx, - packet: rx, - } - } - - /// Waits for an event on this receiver set. The returned value is *not* an - /// index, but rather an id. This id can be queried against any active - /// `Handle` structures (each one has an `id` method). The handle with - /// the matching `id` will have some sort of event available on it. The - /// event could either be that data is available or the corresponding - /// channel has been closed. - pub fn wait(&self) -> usize { - self.wait2(true) - } - - /// Helper method for skipping the preflight checks during testing - fn wait2(&self, do_preflight_checks: bool) -> usize { - // Note that this is currently an inefficient implementation. We in - // theory have knowledge about all receivers in the set ahead of time, - // so this method shouldn't really have to iterate over all of them yet - // again. The idea with this "receiver set" interface is to get the - // interface right this time around, and later this implementation can - // be optimized. - // - // This implementation can be summarized by: - // - // fn select(receivers) { - // if any receiver ready { return ready index } - // deschedule { - // block on all receivers - // } - // unblock on all receivers - // return ready index - // } - // - // Most notably, the iterations over all of the receivers shouldn't be - // necessary. - unsafe { - // Stage 1: preflight checks. Look for any packets ready to receive - if do_preflight_checks { - for handle in self.iter() { - if (*handle).packet.can_recv() { - return (*handle).id(); - } - } - } - - // Stage 2: begin the blocking process - // - // Create a number of signal tokens, and install each one - // sequentially until one fails. If one fails, then abort the - // selection on the already-installed tokens. - let (wait_token, signal_token) = blocking::tokens(); - for (i, handle) in self.iter().enumerate() { - match (*handle).packet.start_selection(signal_token.clone()) { - StartResult::Installed => {} - StartResult::Abort => { - // Go back and abort the already-begun selections - for handle in self.iter().take(i) { - (*handle).packet.abort_selection(); - } - return (*handle).id; - } - } - } - - // Stage 3: no messages available, actually block - wait_token.wait(); - - // Stage 4: there *must* be message available; find it. - // - // Abort the selection process on each receiver. If the abort - // process returns `true`, then that means that the receiver is - // ready to receive some data. Note that this also means that the - // receiver may have yet to have fully read the `to_wake` field and - // woken us up (although the wakeup is guaranteed to fail). - // - // This situation happens in the window of where a sender invokes - // increment(), sees -1, and then decides to wake up the thread. After - // all this is done, the sending thread will set `selecting` to - // `false`. Until this is done, we cannot return. If we were to - // return, then a sender could wake up a receiver which has gone - // back to sleep after this call to `select`. - // - // Note that it is a "fairly small window" in which an increment() - // views that it should wake a thread up until the `selecting` bit - // is set to false. For now, the implementation currently just spins - // in a yield loop. This is very distasteful, but this - // implementation is already nowhere near what it should ideally be. - // A rewrite should focus on avoiding a yield loop, and for now this - // implementation is tying us over to a more efficient "don't - // iterate over everything every time" implementation. - let mut ready_id = usize::MAX; - for handle in self.iter() { - if (*handle).packet.abort_selection() { - ready_id = (*handle).id; - } - } - - // We must have found a ready receiver - assert!(ready_id != usize::MAX); - return ready_id; - } - } - - fn iter(&self) -> Packets { Packets { cur: unsafe { &*self.inner.get() }.head } } -} - -impl<'rx, T: Send> Handle<'rx, T> { - /// Retrieves the id of this handle. - #[inline] - pub fn id(&self) -> usize { self.id } - - /// Blocks to receive a value on the underlying receiver, returning `Some` on - /// success or `None` if the channel disconnects. This function has the same - /// semantics as `Receiver.recv` - pub fn recv(&mut self) -> Result { self.rx.recv() } - - /// Adds this handle to the receiver set that the handle was created from. This - /// method can be called multiple times, but it has no effect if `add` was - /// called previously. - /// - /// This method is unsafe because it requires that the `Handle` is not moved - /// while it is added to the `Select` set. - pub unsafe fn add(&mut self) { - if self.added { return } - let selector = &mut *self.selector; - let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>; - - if selector.head.is_null() { - selector.head = me; - selector.tail = me; - } else { - (*me).prev = selector.tail; - assert!((*me).next.is_null()); - (*selector.tail).next = me; - selector.tail = me; - } - self.added = true; - } - - /// Removes this handle from the `Select` set. This method is unsafe because - /// it has no guarantee that the `Handle` was not moved since `add` was - /// called. - pub unsafe fn remove(&mut self) { - if !self.added { return } - - let selector = &mut *self.selector; - let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>; - - if self.prev.is_null() { - assert_eq!(selector.head, me); - selector.head = self.next; - } else { - (*self.prev).next = self.next; - } - if self.next.is_null() { - assert_eq!(selector.tail, me); - selector.tail = self.prev; - } else { - (*self.next).prev = self.prev; - } - - self.next = ptr::null_mut(); - self.prev = ptr::null_mut(); - - self.added = false; - } -} - -impl Drop for Select { - fn drop(&mut self) { - unsafe { - assert!((&*self.inner.get()).head.is_null()); - assert!((&*self.inner.get()).tail.is_null()); - } - } -} - -impl<'rx, T: Send> Drop for Handle<'rx, T> { - fn drop(&mut self) { - unsafe { self.remove() } - } -} - -impl Iterator for Packets { - type Item = *mut Handle<'static, ()>; - - fn next(&mut self) -> Option<*mut Handle<'static, ()>> { - if self.cur.is_null() { - None - } else { - let ret = Some(self.cur); - unsafe { self.cur = (*self.cur).next; } - ret - } - } -} - -impl fmt::Debug for Select { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Select").finish() - } -} - -impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Handle").finish() - } -} - -#[allow(unused_imports)] -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use thread; - use sync::mpsc::*; - - // Don't use the libstd version so we can pull in the right Select structure - // (std::comm points at the wrong one) - macro_rules! select { - ( - $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ - ) => ({ - let sel = Select::new(); - $( let mut $rx = sel.handle(&$rx); )+ - unsafe { - $( $rx.add(); )+ - } - let ret = sel.wait(); - $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+ - { unreachable!() } - }) - } - - #[test] - fn smoke() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - tx1.send(1).unwrap(); - select! { - foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); }, - _bar = rx2.recv() => { panic!() } - } - tx2.send(2).unwrap(); - select! { - _foo = rx1.recv() => { panic!() }, - bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) } - } - drop(tx1); - select! { - foo = rx1.recv() => { assert!(foo.is_err()); }, - _bar = rx2.recv() => { panic!() } - } - drop(tx2); - select! { - bar = rx2.recv() => { assert!(bar.is_err()); } - } - } - - #[test] - fn smoke2() { - let (_tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (_tx3, rx3) = channel::(); - let (_tx4, rx4) = channel::(); - let (tx5, rx5) = channel::(); - tx5.send(4).unwrap(); - select! { - _foo = rx1.recv() => { panic!("1") }, - _foo = rx2.recv() => { panic!("2") }, - _foo = rx3.recv() => { panic!("3") }, - _foo = rx4.recv() => { panic!("4") }, - foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); } - } - } - - #[test] - fn closed() { - let (_tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - drop(tx2); - - select! { - _a1 = rx1.recv() => { panic!() }, - a2 = rx2.recv() => { assert!(a2.is_err()); } - } - } - - #[test] - fn unblocks() { - let (tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (tx3, rx3) = channel::(); - - let _t = thread::spawn(move|| { - for _ in 0..20 { thread::yield_now(); } - tx1.send(1).unwrap(); - rx3.recv().unwrap(); - for _ in 0..20 { thread::yield_now(); } - }); - - select! { - a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, - _b = rx2.recv() => { panic!() } - } - tx3.send(1).unwrap(); - select! { - a = rx1.recv() => { assert!(a.is_err()) }, - _b = rx2.recv() => { panic!() } - } - } - - #[test] - fn both_ready() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - for _ in 0..20 { thread::yield_now(); } - tx1.send(1).unwrap(); - tx2.send(2).unwrap(); - rx3.recv().unwrap(); - }); - - select! { - a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, - a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } - } - select! { - a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, - a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } - } - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty)); - tx3.send(()).unwrap(); - } - - #[test] - fn stress() { - const AMT: i32 = 10000; - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - for i in 0..AMT { - if i % 2 == 0 { - tx1.send(i).unwrap(); - } else { - tx2.send(i).unwrap(); - } - rx3.recv().unwrap(); - } - }); - - for i in 0..AMT { - select! { - i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); }, - i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); } - } - tx3.send(()).unwrap(); - } - } - - #[allow(unused_must_use)] - #[test] - fn cloning() { - let (tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - rx3.recv().unwrap(); - tx1.clone(); - assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); - tx1.send(2).unwrap(); - rx3.recv().unwrap(); - }); - - tx3.send(()).unwrap(); - select! { - _i1 = rx1.recv() => {}, - _i2 = rx2.recv() => panic!() - } - tx3.send(()).unwrap(); - } - - #[allow(unused_must_use)] - #[test] - fn cloning2() { - let (tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - rx3.recv().unwrap(); - tx1.clone(); - assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); - tx1.send(2).unwrap(); - rx3.recv().unwrap(); - }); - - tx3.send(()).unwrap(); - select! { - _i1 = rx1.recv() => {}, - _i2 = rx2.recv() => panic!() - } - tx3.send(()).unwrap(); - } - - #[test] - fn cloning3() { - let (tx1, rx1) = channel::<()>(); - let (tx2, rx2) = channel::<()>(); - let (tx3, rx3) = channel::<()>(); - let _t = thread::spawn(move|| { - let s = Select::new(); - let mut h1 = s.handle(&rx1); - let mut h2 = s.handle(&rx2); - unsafe { h2.add(); } - unsafe { h1.add(); } - assert_eq!(s.wait(), h2.id); - tx3.send(()).unwrap(); - }); - - for _ in 0..1000 { thread::yield_now(); } - drop(tx1.clone()); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - } - - #[test] - fn preflight1() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - select! { - _n = rx.recv() => {} - } - } - - #[test] - fn preflight2() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - tx.send(()).unwrap(); - select! { - _n = rx.recv() => {} - } - } - - #[test] - fn preflight3() { - let (tx, rx) = channel(); - drop(tx.clone()); - tx.send(()).unwrap(); - select! { - _n = rx.recv() => {} - } - } - - #[test] - fn preflight4() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id); - } - - #[test] - fn preflight5() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - tx.send(()).unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id); - } - - #[test] - fn preflight6() { - let (tx, rx) = channel(); - drop(tx.clone()); - tx.send(()).unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id); - } - - #[test] - fn preflight7() { - let (tx, rx) = channel::<()>(); - drop(tx); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id); - } - - #[test] - fn preflight8() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - drop(tx); - rx.recv().unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id); - } - - #[test] - fn preflight9() { - let (tx, rx) = channel(); - drop(tx.clone()); - tx.send(()).unwrap(); - drop(tx); - rx.recv().unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id); - } - - #[test] - fn oneshot_data_waiting() { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - select! { - _n = rx1.recv() => {} - } - tx2.send(()).unwrap(); - }); - - for _ in 0..100 { thread::yield_now() } - tx1.send(()).unwrap(); - rx2.recv().unwrap(); - } - - #[test] - fn stream_data_waiting() { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - tx1.send(()).unwrap(); - tx1.send(()).unwrap(); - rx1.recv().unwrap(); - rx1.recv().unwrap(); - let _t = thread::spawn(move|| { - select! { - _n = rx1.recv() => {} - } - tx2.send(()).unwrap(); - }); - - for _ in 0..100 { thread::yield_now() } - tx1.send(()).unwrap(); - rx2.recv().unwrap(); - } - - #[test] - fn shared_data_waiting() { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - drop(tx1.clone()); - tx1.send(()).unwrap(); - rx1.recv().unwrap(); - let _t = thread::spawn(move|| { - select! { - _n = rx1.recv() => {} - } - tx2.send(()).unwrap(); - }); - - for _ in 0..100 { thread::yield_now() } - tx1.send(()).unwrap(); - rx2.recv().unwrap(); - } - - #[test] - fn sync1() { - let (tx, rx) = sync_channel::(1); - tx.send(1).unwrap(); - select! { - n = rx.recv() => { assert_eq!(n.unwrap(), 1); } - } - } - - #[test] - fn sync2() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move|| { - for _ in 0..100 { thread::yield_now() } - tx.send(1).unwrap(); - }); - select! { - n = rx.recv() => { assert_eq!(n.unwrap(), 1); } - } - } - - #[test] - fn sync3() { - let (tx1, rx1) = sync_channel::(0); - let (tx2, rx2): (Sender, Receiver) = channel(); - let _t = thread::spawn(move|| { tx1.send(1).unwrap(); }); - let _t = thread::spawn(move|| { tx2.send(2).unwrap(); }); - select! { - n = rx1.recv() => { - let n = n.unwrap(); - assert_eq!(n, 1); - assert_eq!(rx2.recv().unwrap(), 2); - }, - n = rx2.recv() => { - let n = n.unwrap(); - assert_eq!(n, 2); - assert_eq!(rx1.recv().unwrap(), 1); - } - } - } -} diff --git a/ctr-std/src/sync/mpsc/shared.rs b/ctr-std/src/sync/mpsc/shared.rs deleted file mode 100644 index f9e0290..0000000 --- a/ctr-std/src/sync/mpsc/shared.rs +++ /dev/null @@ -1,506 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Shared channels -/// -/// This is the flavor of channels which are not necessarily optimized for any -/// particular use case, but are the most general in how they are used. Shared -/// channels are cloneable allowing for multiple senders. -/// -/// High level implementation details can be found in the comment of the parent -/// module. You'll also note that the implementation of the shared and stream -/// channels are quite similar, and this is no coincidence! - -pub use self::Failure::*; - -use core::cmp; -use core::intrinsics::abort; -use core::isize; - -use cell::UnsafeCell; -use ptr; -use sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering}; -use sync::mpsc::blocking::{self, SignalToken}; -use sync::mpsc::mpsc_queue as mpsc; -use sync::mpsc::select::StartResult::*; -use sync::mpsc::select::StartResult; -use sync::{Mutex, MutexGuard}; -use thread; -use time::Instant; - -const DISCONNECTED: isize = isize::MIN; -const FUDGE: isize = 1024; -const MAX_REFCOUNT: usize = (isize::MAX) as usize; -#[cfg(test)] -const MAX_STEALS: isize = 5; -#[cfg(not(test))] -const MAX_STEALS: isize = 1 << 20; - -pub struct Packet { - queue: mpsc::Queue, - cnt: AtomicIsize, // How many items are on this channel - steals: UnsafeCell, // How many times has a port received without blocking? - to_wake: AtomicUsize, // SignalToken for wake up - - // The number of channels which are currently using this packet. - channels: AtomicUsize, - - // See the discussion in Port::drop and the channel send methods for what - // these are used for - port_dropped: AtomicBool, - sender_drain: AtomicIsize, - - // this lock protects various portions of this implementation during - // select() - select_lock: Mutex<()>, -} - -pub enum Failure { - Empty, - Disconnected, -} - -impl Packet { - // Creation of a packet *must* be followed by a call to postinit_lock - // and later by inherit_blocker - pub fn new() -> Packet { - Packet { - queue: mpsc::Queue::new(), - cnt: AtomicIsize::new(0), - steals: UnsafeCell::new(0), - to_wake: AtomicUsize::new(0), - channels: AtomicUsize::new(2), - port_dropped: AtomicBool::new(false), - sender_drain: AtomicIsize::new(0), - select_lock: Mutex::new(()), - } - } - - // This function should be used after newly created Packet - // was wrapped with an Arc - // In other case mutex data will be duplicated while cloning - // and that could cause problems on platforms where it is - // represented by opaque data structure - pub fn postinit_lock(&self) -> MutexGuard<()> { - self.select_lock.lock().unwrap() - } - - // This function is used at the creation of a shared packet to inherit a - // previously blocked thread. This is done to prevent spurious wakeups of - // threads in select(). - // - // This can only be called at channel-creation time - pub fn inherit_blocker(&self, - token: Option, - guard: MutexGuard<()>) { - token.map(|token| { - assert_eq!(self.cnt.load(Ordering::SeqCst), 0); - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); - self.to_wake.store(unsafe { token.cast_to_usize() }, Ordering::SeqCst); - self.cnt.store(-1, Ordering::SeqCst); - - // This store is a little sketchy. What's happening here is that - // we're transferring a blocker from a oneshot or stream channel to - // this shared channel. In doing so, we never spuriously wake them - // up and rather only wake them up at the appropriate time. This - // implementation of shared channels assumes that any blocking - // recv() will undo the increment of steals performed in try_recv() - // once the recv is complete. This thread that we're inheriting, - // however, is not in the middle of recv. Hence, the first time we - // wake them up, they're going to wake up from their old port, move - // on to the upgraded port, and then call the block recv() function. - // - // When calling this function, they'll find there's data immediately - // available, counting it as a steal. This in fact wasn't a steal - // because we appropriately blocked them waiting for data. - // - // To offset this bad increment, we initially set the steal count to - // -1. You'll find some special code in abort_selection() as well to - // ensure that this -1 steal count doesn't escape too far. - unsafe { *self.steals.get() = -1; } - }); - - // When the shared packet is constructed, we grabbed this lock. The - // purpose of this lock is to ensure that abort_selection() doesn't - // interfere with this method. After we unlock this lock, we're - // signifying that we're done modifying self.cnt and self.to_wake and - // the port is ready for the world to continue using it. - drop(guard); - } - - pub fn send(&self, t: T) -> Result<(), T> { - // See Port::drop for what's going on - if self.port_dropped.load(Ordering::SeqCst) { return Err(t) } - - // Note that the multiple sender case is a little trickier - // semantically than the single sender case. The logic for - // incrementing is "add and if disconnected store disconnected". - // This could end up leading some senders to believe that there - // wasn't a disconnect if in fact there was a disconnect. This means - // that while one thread is attempting to re-store the disconnected - // states, other threads could walk through merrily incrementing - // this very-negative disconnected count. To prevent senders from - // spuriously attempting to send when the channels is actually - // disconnected, the count has a ranged check here. - // - // This is also done for another reason. Remember that the return - // value of this function is: - // - // `true` == the data *may* be received, this essentially has no - // meaning - // `false` == the data will *never* be received, this has a lot of - // meaning - // - // In the SPSC case, we have a check of 'queue.is_empty()' to see - // whether the data was actually received, but this same condition - // means nothing in a multi-producer context. As a result, this - // preflight check serves as the definitive "this will never be - // received". Once we get beyond this check, we have permanently - // entered the realm of "this may be received" - if self.cnt.load(Ordering::SeqCst) < DISCONNECTED + FUDGE { - return Err(t) - } - - self.queue.push(t); - match self.cnt.fetch_add(1, Ordering::SeqCst) { - -1 => { - self.take_to_wake().signal(); - } - - // In this case, we have possibly failed to send our data, and - // we need to consider re-popping the data in order to fully - // destroy it. We must arbitrate among the multiple senders, - // however, because the queues that we're using are - // single-consumer queues. In order to do this, all exiting - // pushers will use an atomic count in order to count those - // flowing through. Pushers who see 0 are required to drain as - // much as possible, and then can only exit when they are the - // only pusher (otherwise they must try again). - n if n < DISCONNECTED + FUDGE => { - // see the comment in 'try' for a shared channel for why this - // window of "not disconnected" is ok. - self.cnt.store(DISCONNECTED, Ordering::SeqCst); - - if self.sender_drain.fetch_add(1, Ordering::SeqCst) == 0 { - loop { - // drain the queue, for info on the thread yield see the - // discussion in try_recv - loop { - match self.queue.pop() { - mpsc::Data(..) => {} - mpsc::Empty => break, - mpsc::Inconsistent => thread::yield_now(), - } - } - // maybe we're done, if we're not the last ones - // here, then we need to go try again. - if self.sender_drain.fetch_sub(1, Ordering::SeqCst) == 1 { - break - } - } - - // At this point, there may still be data on the queue, - // but only if the count hasn't been incremented and - // some other sender hasn't finished pushing data just - // yet. That sender in question will drain its own data. - } - } - - // Can't make any assumptions about this case like in the SPSC case. - _ => {} - } - - Ok(()) - } - - pub fn recv(&self, deadline: Option) -> Result { - // This code is essentially the exact same as that found in the stream - // case (see stream.rs) - match self.try_recv() { - Err(Empty) => {} - data => return data, - } - - let (wait_token, signal_token) = blocking::tokens(); - if self.decrement(signal_token) == Installed { - if let Some(deadline) = deadline { - let timed_out = !wait_token.wait_max_until(deadline); - if timed_out { - self.abort_selection(false); - } - } else { - wait_token.wait(); - } - } - - match self.try_recv() { - data @ Ok(..) => unsafe { *self.steals.get() -= 1; data }, - data => data, - } - } - - // Essentially the exact same thing as the stream decrement function. - // Returns true if blocking should proceed. - fn decrement(&self, token: SignalToken) -> StartResult { - unsafe { - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); - let ptr = token.cast_to_usize(); - self.to_wake.store(ptr, Ordering::SeqCst); - - let steals = ptr::replace(self.steals.get(), 0); - - match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) { - DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); } - // If we factor in our steals and notice that the channel has no - // data, we successfully sleep - n => { - assert!(n >= 0); - if n - steals <= 0 { return Installed } - } - } - - self.to_wake.store(0, Ordering::SeqCst); - drop(SignalToken::cast_from_usize(ptr)); - Abort - } - } - - pub fn try_recv(&self) -> Result { - let ret = match self.queue.pop() { - mpsc::Data(t) => Some(t), - mpsc::Empty => None, - - // This is a bit of an interesting case. The channel is reported as - // having data available, but our pop() has failed due to the queue - // being in an inconsistent state. This means that there is some - // pusher somewhere which has yet to complete, but we are guaranteed - // that a pop will eventually succeed. In this case, we spin in a - // yield loop because the remote sender should finish their enqueue - // operation "very quickly". - // - // Avoiding this yield loop would require a different queue - // abstraction which provides the guarantee that after M pushes have - // succeeded, at least M pops will succeed. The current queues - // guarantee that if there are N active pushes, you can pop N times - // once all N have finished. - mpsc::Inconsistent => { - let data; - loop { - thread::yield_now(); - match self.queue.pop() { - mpsc::Data(t) => { data = t; break } - mpsc::Empty => panic!("inconsistent => empty"), - mpsc::Inconsistent => {} - } - } - Some(data) - } - }; - match ret { - // See the discussion in the stream implementation for why we - // might decrement steals. - Some(data) => unsafe { - if *self.steals.get() > MAX_STEALS { - match self.cnt.swap(0, Ordering::SeqCst) { - DISCONNECTED => { - self.cnt.store(DISCONNECTED, Ordering::SeqCst); - } - n => { - let m = cmp::min(n, *self.steals.get()); - *self.steals.get() -= m; - self.bump(n - m); - } - } - assert!(*self.steals.get() >= 0); - } - *self.steals.get() += 1; - Ok(data) - }, - - // See the discussion in the stream implementation for why we try - // again. - None => { - match self.cnt.load(Ordering::SeqCst) { - n if n != DISCONNECTED => Err(Empty), - _ => { - match self.queue.pop() { - mpsc::Data(t) => Ok(t), - mpsc::Empty => Err(Disconnected), - // with no senders, an inconsistency is impossible. - mpsc::Inconsistent => unreachable!(), - } - } - } - } - } - } - - // Prepares this shared packet for a channel clone, essentially just bumping - // a refcount. - pub fn clone_chan(&self) { - let old_count = self.channels.fetch_add(1, Ordering::SeqCst); - - // See comments on Arc::clone() on why we do this (for `mem::forget`). - if old_count > MAX_REFCOUNT { - unsafe { - abort(); - } - } - } - - // Decrement the reference count on a channel. This is called whenever a - // Chan is dropped and may end up waking up a receiver. It's the receiver's - // responsibility on the other end to figure out that we've disconnected. - pub fn drop_chan(&self) { - match self.channels.fetch_sub(1, Ordering::SeqCst) { - 1 => {} - n if n > 1 => return, - n => panic!("bad number of channels left {}", n), - } - - match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) { - -1 => { self.take_to_wake().signal(); } - DISCONNECTED => {} - n => { assert!(n >= 0); } - } - } - - // See the long discussion inside of stream.rs for why the queue is drained, - // and why it is done in this fashion. - pub fn drop_port(&self) { - self.port_dropped.store(true, Ordering::SeqCst); - let mut steals = unsafe { *self.steals.get() }; - while { - let cnt = self.cnt.compare_and_swap(steals, DISCONNECTED, Ordering::SeqCst); - cnt != DISCONNECTED && cnt != steals - } { - // See the discussion in 'try_recv' for why we yield - // control of this thread. - loop { - match self.queue.pop() { - mpsc::Data(..) => { steals += 1; } - mpsc::Empty | mpsc::Inconsistent => break, - } - } - } - } - - // Consumes ownership of the 'to_wake' field. - fn take_to_wake(&self) -> SignalToken { - let ptr = self.to_wake.load(Ordering::SeqCst); - self.to_wake.store(0, Ordering::SeqCst); - assert!(ptr != 0); - unsafe { SignalToken::cast_from_usize(ptr) } - } - - //////////////////////////////////////////////////////////////////////////// - // select implementation - //////////////////////////////////////////////////////////////////////////// - - // Helper function for select, tests whether this port can receive without - // blocking (obviously not an atomic decision). - // - // This is different than the stream version because there's no need to peek - // at the queue, we can just look at the local count. - pub fn can_recv(&self) -> bool { - let cnt = self.cnt.load(Ordering::SeqCst); - cnt == DISCONNECTED || cnt - unsafe { *self.steals.get() } > 0 - } - - // increment the count on the channel (used for selection) - fn bump(&self, amt: isize) -> isize { - match self.cnt.fetch_add(amt, Ordering::SeqCst) { - DISCONNECTED => { - self.cnt.store(DISCONNECTED, Ordering::SeqCst); - DISCONNECTED - } - n => n - } - } - - // Inserts the signal token for selection on this port, returning true if - // blocking should proceed. - // - // The code here is the same as in stream.rs, except that it doesn't need to - // peek at the channel to see if an upgrade is pending. - pub fn start_selection(&self, token: SignalToken) -> StartResult { - match self.decrement(token) { - Installed => Installed, - Abort => { - let prev = self.bump(1); - assert!(prev == DISCONNECTED || prev >= 0); - Abort - } - } - } - - // Cancels a previous thread waiting on this port, returning whether there's - // data on the port. - // - // This is similar to the stream implementation (hence fewer comments), but - // uses a different value for the "steals" variable. - pub fn abort_selection(&self, _was_upgrade: bool) -> bool { - // Before we do anything else, we bounce on this lock. The reason for - // doing this is to ensure that any upgrade-in-progress is gone and - // done with. Without this bounce, we can race with inherit_blocker - // about looking at and dealing with to_wake. Once we have acquired the - // lock, we are guaranteed that inherit_blocker is done. - { - let _guard = self.select_lock.lock().unwrap(); - } - - // Like the stream implementation, we want to make sure that the count - // on the channel goes non-negative. We don't know how negative the - // stream currently is, so instead of using a steal value of 1, we load - // the channel count and figure out what we should do to make it - // positive. - let steals = { - let cnt = self.cnt.load(Ordering::SeqCst); - if cnt < 0 && cnt != DISCONNECTED {-cnt} else {0} - }; - let prev = self.bump(steals + 1); - - if prev == DISCONNECTED { - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); - true - } else { - let cur = prev + steals + 1; - assert!(cur >= 0); - if prev < 0 { - drop(self.take_to_wake()); - } else { - while self.to_wake.load(Ordering::SeqCst) != 0 { - thread::yield_now(); - } - } - unsafe { - // if the number of steals is -1, it was the pre-emptive -1 steal - // count from when we inherited a blocker. This is fine because - // we're just going to overwrite it with a real value. - let old = self.steals.get(); - assert!(*old == 0 || *old == -1); - *old = steals; - prev >= 0 - } - } - } -} - -impl Drop for Packet { - fn drop(&mut self) { - // Note that this load is not only an assert for correctness about - // disconnection, but also a proper fence before the read of - // `to_wake`, so this assert cannot be removed with also removing - // the `to_wake` assert. - assert_eq!(self.cnt.load(Ordering::SeqCst), DISCONNECTED); - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); - assert_eq!(self.channels.load(Ordering::SeqCst), 0); - } -} diff --git a/ctr-std/src/sync/mpsc/spsc_queue.rs b/ctr-std/src/sync/mpsc/spsc_queue.rs deleted file mode 100644 index 9482f69..0000000 --- a/ctr-std/src/sync/mpsc/spsc_queue.rs +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A single-producer single-consumer concurrent queue -//! -//! This module contains the implementation of an SPSC queue which can be used -//! concurrently between two threads. This data structure is safe to use and -//! enforces the semantics that there is one pusher and one popper. - -// http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue - -use boxed::Box; -use core::ptr; -use core::cell::UnsafeCell; - -use sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; - -use super::cache_aligned::CacheAligned; - -// Node within the linked list queue of messages to send -struct Node { - // FIXME: this could be an uninitialized T if we're careful enough, and - // that would reduce memory usage (and be a bit faster). - // is it worth it? - value: Option, // nullable for re-use of nodes - cached: bool, // This node goes into the node cache - next: AtomicPtr>, // next node in the queue -} - -/// The single-producer single-consumer queue. This structure is not cloneable, -/// but it can be safely shared in an Arc if it is guaranteed that there -/// is only one popper and one pusher touching the queue at any one point in -/// time. -pub struct Queue { - // consumer fields - consumer: CacheAligned>, - - // producer fields - producer: CacheAligned>, -} - -struct Consumer { - tail: UnsafeCell<*mut Node>, // where to pop from - tail_prev: AtomicPtr>, // where to pop from - cache_bound: usize, // maximum cache size - cached_nodes: AtomicUsize, // number of nodes marked as cachable - addition: Addition, -} - -struct Producer { - head: UnsafeCell<*mut Node>, // where to push to - first: UnsafeCell<*mut Node>, // where to get new nodes from - tail_copy: UnsafeCell<*mut Node>, // between first/tail - addition: Addition, -} - -unsafe impl Send for Queue { } - -unsafe impl Sync for Queue { } - -impl Node { - fn new() -> *mut Node { - Box::into_raw(box Node { - value: None, - cached: false, - next: AtomicPtr::new(ptr::null_mut::>()), - }) - } -} - -impl Queue { - - /// Creates a new queue. With given additional elements in the producer and - /// consumer portions of the queue. - /// - /// Due to the performance implications of cache-contention, - /// we wish to keep fields used mainly by the producer on a separate cache - /// line than those used by the consumer. - /// Since cache lines are usually 64 bytes, it is unreasonably expensive to - /// allocate one for small fields, so we allow users to insert additional - /// fields into the cache lines already allocated by this for the producer - /// and consumer. - /// - /// This is unsafe as the type system doesn't enforce a single - /// consumer-producer relationship. It also allows the consumer to `pop` - /// items while there is a `peek` active due to all methods having a - /// non-mutable receiver. - /// - /// # Arguments - /// - /// * `bound` - This queue implementation is implemented with a linked - /// list, and this means that a push is always a malloc. In - /// order to amortize this cost, an internal cache of nodes is - /// maintained to prevent a malloc from always being - /// necessary. This bound is the limit on the size of the - /// cache (if desired). If the value is 0, then the cache has - /// no bound. Otherwise, the cache will never grow larger than - /// `bound` (although the queue itself could be much larger. - pub unsafe fn with_additions( - bound: usize, - producer_addition: ProducerAddition, - consumer_addition: ConsumerAddition, - ) -> Self { - let n1 = Node::new(); - let n2 = Node::new(); - (*n1).next.store(n2, Ordering::Relaxed); - Queue { - consumer: CacheAligned::new(Consumer { - tail: UnsafeCell::new(n2), - tail_prev: AtomicPtr::new(n1), - cache_bound: bound, - cached_nodes: AtomicUsize::new(0), - addition: consumer_addition - }), - producer: CacheAligned::new(Producer { - head: UnsafeCell::new(n2), - first: UnsafeCell::new(n1), - tail_copy: UnsafeCell::new(n1), - addition: producer_addition - }), - } - } - - /// Pushes a new value onto this queue. Note that to use this function - /// safely, it must be externally guaranteed that there is only one pusher. - pub fn push(&self, t: T) { - unsafe { - // Acquire a node (which either uses a cached one or allocates a new - // one), and then append this to the 'head' node. - let n = self.alloc(); - assert!((*n).value.is_none()); - (*n).value = Some(t); - (*n).next.store(ptr::null_mut(), Ordering::Relaxed); - (**self.producer.head.get()).next.store(n, Ordering::Release); - *(&self.producer.head).get() = n; - } - } - - unsafe fn alloc(&self) -> *mut Node { - // First try to see if we can consume the 'first' node for our uses. - if *self.producer.first.get() != *self.producer.tail_copy.get() { - let ret = *self.producer.first.get(); - *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed); - return ret; - } - // If the above fails, then update our copy of the tail and try - // again. - *self.producer.0.tail_copy.get() = - self.consumer.tail_prev.load(Ordering::Acquire); - if *self.producer.first.get() != *self.producer.tail_copy.get() { - let ret = *self.producer.first.get(); - *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed); - return ret; - } - // If all of that fails, then we have to allocate a new node - // (there's nothing in the node cache). - Node::new() - } - - /// Attempts to pop a value from this queue. Remember that to use this type - /// safely you must ensure that there is only one popper at a time. - pub fn pop(&self) -> Option { - unsafe { - // The `tail` node is not actually a used node, but rather a - // sentinel from where we should start popping from. Hence, look at - // tail's next field and see if we can use it. If we do a pop, then - // the current tail node is a candidate for going into the cache. - let tail = *self.consumer.tail.get(); - let next = (*tail).next.load(Ordering::Acquire); - if next.is_null() { return None } - assert!((*next).value.is_some()); - let ret = (*next).value.take(); - - *self.consumer.0.tail.get() = next; - if self.consumer.cache_bound == 0 { - self.consumer.tail_prev.store(tail, Ordering::Release); - } else { - let cached_nodes = self.consumer.cached_nodes.load(Ordering::Relaxed); - if cached_nodes < self.consumer.cache_bound && !(*tail).cached { - self.consumer.cached_nodes.store(cached_nodes, Ordering::Relaxed); - (*tail).cached = true; - } - - if (*tail).cached { - self.consumer.tail_prev.store(tail, Ordering::Release); - } else { - (*self.consumer.tail_prev.load(Ordering::Relaxed)) - .next.store(next, Ordering::Relaxed); - // We have successfully erased all references to 'tail', so - // now we can safely drop it. - let _: Box> = Box::from_raw(tail); - } - } - ret - } - } - - /// Attempts to peek at the head of the queue, returning `None` if the queue - /// has no data currently - /// - /// # Warning - /// The reference returned is invalid if it is not used before the consumer - /// pops the value off the queue. If the producer then pushes another value - /// onto the queue, it will overwrite the value pointed to by the reference. - pub fn peek(&self) -> Option<&mut T> { - // This is essentially the same as above with all the popping bits - // stripped out. - unsafe { - let tail = *self.consumer.tail.get(); - let next = (*tail).next.load(Ordering::Acquire); - if next.is_null() { None } else { (*next).value.as_mut() } - } - } - - pub fn producer_addition(&self) -> &ProducerAddition { - &self.producer.addition - } - - pub fn consumer_addition(&self) -> &ConsumerAddition { - &self.consumer.addition - } -} - -impl Drop for Queue { - fn drop(&mut self) { - unsafe { - let mut cur = *self.producer.first.get(); - while !cur.is_null() { - let next = (*cur).next.load(Ordering::Relaxed); - let _n: Box> = Box::from_raw(cur); - cur = next; - } - } - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use sync::Arc; - use super::Queue; - use thread; - use sync::mpsc::channel; - - #[test] - fn smoke() { - unsafe { - let queue = Queue::with_additions(0, (), ()); - queue.push(1); - queue.push(2); - assert_eq!(queue.pop(), Some(1)); - assert_eq!(queue.pop(), Some(2)); - assert_eq!(queue.pop(), None); - queue.push(3); - queue.push(4); - assert_eq!(queue.pop(), Some(3)); - assert_eq!(queue.pop(), Some(4)); - assert_eq!(queue.pop(), None); - } - } - - #[test] - fn peek() { - unsafe { - let queue = Queue::with_additions(0, (), ()); - queue.push(vec![1]); - - // Ensure the borrowchecker works - match queue.peek() { - Some(vec) => { - assert_eq!(&*vec, &[1]); - }, - None => unreachable!() - } - - match queue.pop() { - Some(vec) => { - assert_eq!(&*vec, &[1]); - }, - None => unreachable!() - } - } - } - - #[test] - fn drop_full() { - unsafe { - let q: Queue> = Queue::with_additions(0, (), ()); - q.push(box 1); - q.push(box 2); - } - } - - #[test] - fn smoke_bound() { - unsafe { - let q = Queue::with_additions(0, (), ()); - q.push(1); - q.push(2); - assert_eq!(q.pop(), Some(1)); - assert_eq!(q.pop(), Some(2)); - assert_eq!(q.pop(), None); - q.push(3); - q.push(4); - assert_eq!(q.pop(), Some(3)); - assert_eq!(q.pop(), Some(4)); - assert_eq!(q.pop(), None); - } - } - - #[test] - fn stress() { - unsafe { - stress_bound(0); - stress_bound(1); - } - - unsafe fn stress_bound(bound: usize) { - let q = Arc::new(Queue::with_additions(bound, (), ())); - - let (tx, rx) = channel(); - let q2 = q.clone(); - let _t = thread::spawn(move|| { - for _ in 0..100000 { - loop { - match q2.pop() { - Some(1) => break, - Some(_) => panic!(), - None => {} - } - } - } - tx.send(()).unwrap(); - }); - for _ in 0..100000 { - q.push(1); - } - rx.recv().unwrap(); - } - } -} diff --git a/ctr-std/src/sync/mpsc/stream.rs b/ctr-std/src/sync/mpsc/stream.rs deleted file mode 100644 index d1515eb..0000000 --- a/ctr-std/src/sync/mpsc/stream.rs +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Stream channels -/// -/// This is the flavor of channels which are optimized for one sender and one -/// receiver. The sender will be upgraded to a shared channel if the channel is -/// cloned. -/// -/// High level implementation details can be found in the comment of the parent -/// module. - -pub use self::Failure::*; -pub use self::UpgradeResult::*; -pub use self::SelectionResult::*; -use self::Message::*; - -use cell::UnsafeCell; -use core::cmp; -use core::isize; -use ptr; -use thread; -use time::Instant; - -use sync::atomic::{AtomicIsize, AtomicUsize, Ordering, AtomicBool}; -use sync::mpsc::Receiver; -use sync::mpsc::blocking::{self, SignalToken}; -use sync::mpsc::spsc_queue as spsc; - -const DISCONNECTED: isize = isize::MIN; -#[cfg(test)] -const MAX_STEALS: isize = 5; -#[cfg(not(test))] -const MAX_STEALS: isize = 1 << 20; - -pub struct Packet { - // internal queue for all messages - queue: spsc::Queue, ProducerAddition, ConsumerAddition>, -} - -struct ProducerAddition { - cnt: AtomicIsize, // How many items are on this channel - to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up - - port_dropped: AtomicBool, // flag if the channel has been destroyed. -} - -struct ConsumerAddition { - steals: UnsafeCell, // How many times has a port received without blocking? -} - - -pub enum Failure { - Empty, - Disconnected, - Upgraded(Receiver), -} - -pub enum UpgradeResult { - UpSuccess, - UpDisconnected, - UpWoke(SignalToken), -} - -pub enum SelectionResult { - SelSuccess, - SelCanceled, - SelUpgraded(SignalToken, Receiver), -} - -// Any message could contain an "upgrade request" to a new shared port, so the -// internal queue it's a queue of T, but rather Message -enum Message { - Data(T), - GoUp(Receiver), -} - -impl Packet { - pub fn new() -> Packet { - Packet { - queue: unsafe { spsc::Queue::with_additions( - 128, - ProducerAddition { - cnt: AtomicIsize::new(0), - to_wake: AtomicUsize::new(0), - - port_dropped: AtomicBool::new(false), - }, - ConsumerAddition { - steals: UnsafeCell::new(0), - } - )}, - } - } - - pub fn send(&self, t: T) -> Result<(), T> { - // If the other port has deterministically gone away, then definitely - // must return the data back up the stack. Otherwise, the data is - // considered as being sent. - if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) { return Err(t) } - - match self.do_send(Data(t)) { - UpSuccess | UpDisconnected => {}, - UpWoke(token) => { token.signal(); } - } - Ok(()) - } - - pub fn upgrade(&self, up: Receiver) -> UpgradeResult { - // If the port has gone away, then there's no need to proceed any - // further. - if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) { - return UpDisconnected - } - - self.do_send(GoUp(up)) - } - - fn do_send(&self, t: Message) -> UpgradeResult { - self.queue.push(t); - match self.queue.producer_addition().cnt.fetch_add(1, Ordering::SeqCst) { - // As described in the mod's doc comment, -1 == wakeup - -1 => UpWoke(self.take_to_wake()), - // As as described before, SPSC queues must be >= -2 - -2 => UpSuccess, - - // Be sure to preserve the disconnected state, and the return value - // in this case is going to be whether our data was received or not. - // This manifests itself on whether we have an empty queue or not. - // - // Primarily, are required to drain the queue here because the port - // will never remove this data. We can only have at most one item to - // drain (the port drains the rest). - DISCONNECTED => { - self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst); - let first = self.queue.pop(); - let second = self.queue.pop(); - assert!(second.is_none()); - - match first { - Some(..) => UpSuccess, // we failed to send the data - None => UpDisconnected, // we successfully sent data - } - } - - // Otherwise we just sent some data on a non-waiting queue, so just - // make sure the world is sane and carry on! - n => { assert!(n >= 0); UpSuccess } - } - } - - // Consumes ownership of the 'to_wake' field. - fn take_to_wake(&self) -> SignalToken { - let ptr = self.queue.producer_addition().to_wake.load(Ordering::SeqCst); - self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst); - assert!(ptr != 0); - unsafe { SignalToken::cast_from_usize(ptr) } - } - - // Decrements the count on the channel for a sleeper, returning the sleeper - // back if it shouldn't sleep. Note that this is the location where we take - // steals into account. - fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> { - assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); - let ptr = unsafe { token.cast_to_usize() }; - self.queue.producer_addition().to_wake.store(ptr, Ordering::SeqCst); - - let steals = unsafe { ptr::replace(self.queue.consumer_addition().steals.get(), 0) }; - - match self.queue.producer_addition().cnt.fetch_sub(1 + steals, Ordering::SeqCst) { - DISCONNECTED => { - self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst); - } - // If we factor in our steals and notice that the channel has no - // data, we successfully sleep - n => { - assert!(n >= 0); - if n - steals <= 0 { return Ok(()) } - } - } - - self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst); - Err(unsafe { SignalToken::cast_from_usize(ptr) }) - } - - pub fn recv(&self, deadline: Option) -> Result> { - // Optimistic preflight check (scheduling is expensive). - match self.try_recv() { - Err(Empty) => {} - data => return data, - } - - // Welp, our channel has no data. Deschedule the current thread and - // initiate the blocking protocol. - let (wait_token, signal_token) = blocking::tokens(); - if self.decrement(signal_token).is_ok() { - if let Some(deadline) = deadline { - let timed_out = !wait_token.wait_max_until(deadline); - if timed_out { - self.abort_selection(/* was_upgrade = */ false).map_err(Upgraded)?; - } - } else { - wait_token.wait(); - } - } - - match self.try_recv() { - // Messages which actually popped from the queue shouldn't count as - // a steal, so offset the decrement here (we already have our - // "steal" factored into the channel count above). - data @ Ok(..) | - data @ Err(Upgraded(..)) => unsafe { - *self.queue.consumer_addition().steals.get() -= 1; - data - }, - - data => data, - } - } - - pub fn try_recv(&self) -> Result> { - match self.queue.pop() { - // If we stole some data, record to that effect (this will be - // factored into cnt later on). - // - // Note that we don't allow steals to grow without bound in order to - // prevent eventual overflow of either steals or cnt as an overflow - // would have catastrophic results. Sometimes, steals > cnt, but - // other times cnt > steals, so we don't know the relation between - // steals and cnt. This code path is executed only rarely, so we do - // a pretty slow operation, of swapping 0 into cnt, taking steals - // down as much as possible (without going negative), and then - // adding back in whatever we couldn't factor into steals. - Some(data) => unsafe { - if *self.queue.consumer_addition().steals.get() > MAX_STEALS { - match self.queue.producer_addition().cnt.swap(0, Ordering::SeqCst) { - DISCONNECTED => { - self.queue.producer_addition().cnt.store( - DISCONNECTED, Ordering::SeqCst); - } - n => { - let m = cmp::min(n, *self.queue.consumer_addition().steals.get()); - *self.queue.consumer_addition().steals.get() -= m; - self.bump(n - m); - } - } - assert!(*self.queue.consumer_addition().steals.get() >= 0); - } - *self.queue.consumer_addition().steals.get() += 1; - match data { - Data(t) => Ok(t), - GoUp(up) => Err(Upgraded(up)), - } - }, - - None => { - match self.queue.producer_addition().cnt.load(Ordering::SeqCst) { - n if n != DISCONNECTED => Err(Empty), - - // This is a little bit of a tricky case. We failed to pop - // data above, and then we have viewed that the channel is - // disconnected. In this window more data could have been - // sent on the channel. It doesn't really make sense to - // return that the channel is disconnected when there's - // actually data on it, so be extra sure there's no data by - // popping one more time. - // - // We can ignore steals because the other end is - // disconnected and we'll never need to really factor in our - // steals again. - _ => { - match self.queue.pop() { - Some(Data(t)) => Ok(t), - Some(GoUp(up)) => Err(Upgraded(up)), - None => Err(Disconnected), - } - } - } - } - } - } - - pub fn drop_chan(&self) { - // Dropping a channel is pretty simple, we just flag it as disconnected - // and then wakeup a blocker if there is one. - match self.queue.producer_addition().cnt.swap(DISCONNECTED, Ordering::SeqCst) { - -1 => { self.take_to_wake().signal(); } - DISCONNECTED => {} - n => { assert!(n >= 0); } - } - } - - pub fn drop_port(&self) { - // Dropping a port seems like a fairly trivial thing. In theory all we - // need to do is flag that we're disconnected and then everything else - // can take over (we don't have anyone to wake up). - // - // The catch for Ports is that we want to drop the entire contents of - // the queue. There are multiple reasons for having this property, the - // largest of which is that if another chan is waiting in this channel - // (but not received yet), then waiting on that port will cause a - // deadlock. - // - // So if we accept that we must now destroy the entire contents of the - // queue, this code may make a bit more sense. The tricky part is that - // we can't let any in-flight sends go un-dropped, we have to make sure - // *everything* is dropped and nothing new will come onto the channel. - - // The first thing we do is set a flag saying that we're done for. All - // sends are gated on this flag, so we're immediately guaranteed that - // there are a bounded number of active sends that we'll have to deal - // with. - self.queue.producer_addition().port_dropped.store(true, Ordering::SeqCst); - - // Now that we're guaranteed to deal with a bounded number of senders, - // we need to drain the queue. This draining process happens atomically - // with respect to the "count" of the channel. If the count is nonzero - // (with steals taken into account), then there must be data on the - // channel. In this case we drain everything and then try again. We will - // continue to fail while active senders send data while we're dropping - // data, but eventually we're guaranteed to break out of this loop - // (because there is a bounded number of senders). - let mut steals = unsafe { *self.queue.consumer_addition().steals.get() }; - while { - let cnt = self.queue.producer_addition().cnt.compare_and_swap( - steals, DISCONNECTED, Ordering::SeqCst); - cnt != DISCONNECTED && cnt != steals - } { - while let Some(_) = self.queue.pop() { steals += 1; } - } - - // At this point in time, we have gated all future senders from sending, - // and we have flagged the channel as being disconnected. The senders - // still have some responsibility, however, because some sends may not - // complete until after we flag the disconnection. There are more - // details in the sending methods that see DISCONNECTED - } - - //////////////////////////////////////////////////////////////////////////// - // select implementation - //////////////////////////////////////////////////////////////////////////// - - // Tests to see whether this port can receive without blocking. If Ok is - // returned, then that's the answer. If Err is returned, then the returned - // port needs to be queried instead (an upgrade happened) - pub fn can_recv(&self) -> Result> { - // We peek at the queue to see if there's anything on it, and we use - // this return value to determine if we should pop from the queue and - // upgrade this channel immediately. If it looks like we've got an - // upgrade pending, then go through the whole recv rigamarole to update - // the internal state. - match self.queue.peek() { - Some(&mut GoUp(..)) => { - match self.recv(None) { - Err(Upgraded(port)) => Err(port), - _ => unreachable!(), - } - } - Some(..) => Ok(true), - None => Ok(false) - } - } - - // increment the count on the channel (used for selection) - fn bump(&self, amt: isize) -> isize { - match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) { - DISCONNECTED => { - self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst); - DISCONNECTED - } - n => n - } - } - - // Attempts to start selecting on this port. Like a oneshot, this can fail - // immediately because of an upgrade. - pub fn start_selection(&self, token: SignalToken) -> SelectionResult { - match self.decrement(token) { - Ok(()) => SelSuccess, - Err(token) => { - let ret = match self.queue.peek() { - Some(&mut GoUp(..)) => { - match self.queue.pop() { - Some(GoUp(port)) => SelUpgraded(token, port), - _ => unreachable!(), - } - } - Some(..) => SelCanceled, - None => SelCanceled, - }; - // Undo our decrement above, and we should be guaranteed that the - // previous value is positive because we're not going to sleep - let prev = self.bump(1); - assert!(prev == DISCONNECTED || prev >= 0); - ret - } - } - } - - // Removes a previous thread from being blocked in this port - pub fn abort_selection(&self, - was_upgrade: bool) -> Result> { - // If we're aborting selection after upgrading from a oneshot, then - // we're guarantee that no one is waiting. The only way that we could - // have seen the upgrade is if data was actually sent on the channel - // half again. For us, this means that there is guaranteed to be data on - // this channel. Furthermore, we're guaranteed that there was no - // start_selection previously, so there's no need to modify `self.cnt` - // at all. - // - // Hence, because of these invariants, we immediately return `Ok(true)`. - // Note that the data may not actually be sent on the channel just yet. - // The other end could have flagged the upgrade but not sent data to - // this end. This is fine because we know it's a small bounded windows - // of time until the data is actually sent. - if was_upgrade { - assert_eq!(unsafe { *self.queue.consumer_addition().steals.get() }, 0); - assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); - return Ok(true) - } - - // We want to make sure that the count on the channel goes non-negative, - // and in the stream case we can have at most one steal, so just assume - // that we had one steal. - let steals = 1; - let prev = self.bump(steals + 1); - - // If we were previously disconnected, then we know for sure that there - // is no thread in to_wake, so just keep going - let has_data = if prev == DISCONNECTED { - assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); - true // there is data, that data is that we're disconnected - } else { - let cur = prev + steals + 1; - assert!(cur >= 0); - - // If the previous count was negative, then we just made things go - // positive, hence we passed the -1 boundary and we're responsible - // for removing the to_wake() field and trashing it. - // - // If the previous count was positive then we're in a tougher - // situation. A possible race is that a sender just incremented - // through -1 (meaning it's going to try to wake a thread up), but it - // hasn't yet read the to_wake. In order to prevent a future recv() - // from waking up too early (this sender picking up the plastered - // over to_wake), we spin loop here waiting for to_wake to be 0. - // Note that this entire select() implementation needs an overhaul, - // and this is *not* the worst part of it, so this is not done as a - // final solution but rather out of necessity for now to get - // something working. - if prev < 0 { - drop(self.take_to_wake()); - } else { - while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != 0 { - thread::yield_now(); - } - } - unsafe { - assert_eq!(*self.queue.consumer_addition().steals.get(), 0); - *self.queue.consumer_addition().steals.get() = steals; - } - - // if we were previously positive, then there's surely data to - // receive - prev >= 0 - }; - - // Now that we've determined that this queue "has data", we peek at the - // queue to see if the data is an upgrade or not. If it's an upgrade, - // then we need to destroy this port and abort selection on the - // upgraded port. - if has_data { - match self.queue.peek() { - Some(&mut GoUp(..)) => { - match self.queue.pop() { - Some(GoUp(port)) => Err(port), - _ => unreachable!(), - } - } - _ => Ok(true), - } - } else { - Ok(false) - } - } -} - -impl Drop for Packet { - fn drop(&mut self) { - // Note that this load is not only an assert for correctness about - // disconnection, but also a proper fence before the read of - // `to_wake`, so this assert cannot be removed with also removing - // the `to_wake` assert. - assert_eq!(self.queue.producer_addition().cnt.load(Ordering::SeqCst), DISCONNECTED); - assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); - } -} diff --git a/ctr-std/src/sync/mpsc/sync.rs b/ctr-std/src/sync/mpsc/sync.rs deleted file mode 100644 index 90f12c8..0000000 --- a/ctr-std/src/sync/mpsc/sync.rs +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Synchronous channels/ports -/// -/// This channel implementation differs significantly from the asynchronous -/// implementations found next to it (oneshot/stream/share). This is an -/// implementation of a synchronous, bounded buffer channel. -/// -/// Each channel is created with some amount of backing buffer, and sends will -/// *block* until buffer space becomes available. A buffer size of 0 is valid, -/// which means that every successful send is paired with a successful recv. -/// -/// This flavor of channels defines a new `send_opt` method for channels which -/// is the method by which a message is sent but the thread does not panic if it -/// cannot be delivered. -/// -/// Another major difference is that send() will *always* return back the data -/// if it couldn't be sent. This is because it is deterministically known when -/// the data is received and when it is not received. -/// -/// Implementation-wise, it can all be summed up with "use a mutex plus some -/// logic". The mutex used here is an OS native mutex, meaning that no user code -/// is run inside of the mutex (to prevent context switching). This -/// implementation shares almost all code for the buffered and unbuffered cases -/// of a synchronous channel. There are a few branches for the unbuffered case, -/// but they're mostly just relevant to blocking senders. - -pub use self::Failure::*; -use self::Blocker::*; - -use core::intrinsics::abort; -use core::isize; -use core::mem; -use core::ptr; - -use sync::atomic::{Ordering, AtomicUsize}; -use sync::mpsc::blocking::{self, WaitToken, SignalToken}; -use sync::mpsc::select::StartResult::{self, Installed, Abort}; -use sync::{Mutex, MutexGuard}; -use time::Instant; - -const MAX_REFCOUNT: usize = (isize::MAX) as usize; - -pub struct Packet { - /// Only field outside of the mutex. Just done for kicks, but mainly because - /// the other shared channel already had the code implemented - channels: AtomicUsize, - - lock: Mutex>, -} - -unsafe impl Send for Packet { } - -unsafe impl Sync for Packet { } - -struct State { - disconnected: bool, // Is the channel disconnected yet? - queue: Queue, // queue of senders waiting to send data - blocker: Blocker, // currently blocked thread on this channel - buf: Buffer, // storage for buffered messages - cap: usize, // capacity of this channel - - /// A curious flag used to indicate whether a sender failed or succeeded in - /// blocking. This is used to transmit information back to the thread that it - /// must dequeue its message from the buffer because it was not received. - /// This is only relevant in the 0-buffer case. This obviously cannot be - /// safely constructed, but it's guaranteed to always have a valid pointer - /// value. - canceled: Option<&'static mut bool>, -} - -unsafe impl Send for State {} - -/// Possible flavors of threads who can be blocked on this channel. -enum Blocker { - BlockedSender(SignalToken), - BlockedReceiver(SignalToken), - NoneBlocked -} - -/// Simple queue for threading threads together. Nodes are stack-allocated, so -/// this structure is not safe at all -struct Queue { - head: *mut Node, - tail: *mut Node, -} - -struct Node { - token: Option, - next: *mut Node, -} - -unsafe impl Send for Node {} - -/// A simple ring-buffer -struct Buffer { - buf: Vec>, - start: usize, - size: usize, -} - -#[derive(Debug)] -pub enum Failure { - Empty, - Disconnected, -} - -/// Atomically blocks the current thread, placing it into `slot`, unlocking `lock` -/// in the meantime. This re-locks the mutex upon returning. -fn wait<'a, 'b, T>(lock: &'a Mutex>, - mut guard: MutexGuard<'b, State>, - f: fn(SignalToken) -> Blocker) - -> MutexGuard<'a, State> -{ - let (wait_token, signal_token) = blocking::tokens(); - match mem::replace(&mut guard.blocker, f(signal_token)) { - NoneBlocked => {} - _ => unreachable!(), - } - drop(guard); // unlock - wait_token.wait(); // block - lock.lock().unwrap() // relock -} - -/// Same as wait, but waiting at most until `deadline`. -fn wait_timeout_receiver<'a, 'b, T>(lock: &'a Mutex>, - deadline: Instant, - mut guard: MutexGuard<'b, State>, - success: &mut bool) - -> MutexGuard<'a, State> -{ - let (wait_token, signal_token) = blocking::tokens(); - match mem::replace(&mut guard.blocker, BlockedReceiver(signal_token)) { - NoneBlocked => {} - _ => unreachable!(), - } - drop(guard); // unlock - *success = wait_token.wait_max_until(deadline); // block - let mut new_guard = lock.lock().unwrap(); // relock - if !*success { - abort_selection(&mut new_guard); - } - new_guard -} - -fn abort_selection<'a, T>(guard: &mut MutexGuard<'a , State>) -> bool { - match mem::replace(&mut guard.blocker, NoneBlocked) { - NoneBlocked => true, - BlockedSender(token) => { - guard.blocker = BlockedSender(token); - true - } - BlockedReceiver(token) => { drop(token); false } - } -} - -/// Wakes up a thread, dropping the lock at the correct time -fn wakeup(token: SignalToken, guard: MutexGuard>) { - // We need to be careful to wake up the waiting thread *outside* of the mutex - // in case it incurs a context switch. - drop(guard); - token.signal(); -} - -impl Packet { - pub fn new(cap: usize) -> Packet { - Packet { - channels: AtomicUsize::new(1), - lock: Mutex::new(State { - disconnected: false, - blocker: NoneBlocked, - cap, - canceled: None, - queue: Queue { - head: ptr::null_mut(), - tail: ptr::null_mut(), - }, - buf: Buffer { - buf: (0..cap + if cap == 0 {1} else {0}).map(|_| None).collect(), - start: 0, - size: 0, - }, - }), - } - } - - // wait until a send slot is available, returning locked access to - // the channel state. - fn acquire_send_slot(&self) -> MutexGuard> { - let mut node = Node { token: None, next: ptr::null_mut() }; - loop { - let mut guard = self.lock.lock().unwrap(); - // are we ready to go? - if guard.disconnected || guard.buf.size() < guard.buf.cap() { - return guard; - } - // no room; actually block - let wait_token = guard.queue.enqueue(&mut node); - drop(guard); - wait_token.wait(); - } - } - - pub fn send(&self, t: T) -> Result<(), T> { - let mut guard = self.acquire_send_slot(); - if guard.disconnected { return Err(t) } - guard.buf.enqueue(t); - - match mem::replace(&mut guard.blocker, NoneBlocked) { - // if our capacity is 0, then we need to wait for a receiver to be - // available to take our data. After waiting, we check again to make - // sure the port didn't go away in the meantime. If it did, we need - // to hand back our data. - NoneBlocked if guard.cap == 0 => { - let mut canceled = false; - assert!(guard.canceled.is_none()); - guard.canceled = Some(unsafe { mem::transmute(&mut canceled) }); - let mut guard = wait(&self.lock, guard, BlockedSender); - if canceled {Err(guard.buf.dequeue())} else {Ok(())} - } - - // success, we buffered some data - NoneBlocked => Ok(()), - - // success, someone's about to receive our buffered data. - BlockedReceiver(token) => { wakeup(token, guard); Ok(()) } - - BlockedSender(..) => panic!("lolwut"), - } - } - - pub fn try_send(&self, t: T) -> Result<(), super::TrySendError> { - let mut guard = self.lock.lock().unwrap(); - if guard.disconnected { - Err(super::TrySendError::Disconnected(t)) - } else if guard.buf.size() == guard.buf.cap() { - Err(super::TrySendError::Full(t)) - } else if guard.cap == 0 { - // With capacity 0, even though we have buffer space we can't - // transfer the data unless there's a receiver waiting. - match mem::replace(&mut guard.blocker, NoneBlocked) { - NoneBlocked => Err(super::TrySendError::Full(t)), - BlockedSender(..) => unreachable!(), - BlockedReceiver(token) => { - guard.buf.enqueue(t); - wakeup(token, guard); - Ok(()) - } - } - } else { - // If the buffer has some space and the capacity isn't 0, then we - // just enqueue the data for later retrieval, ensuring to wake up - // any blocked receiver if there is one. - assert!(guard.buf.size() < guard.buf.cap()); - guard.buf.enqueue(t); - match mem::replace(&mut guard.blocker, NoneBlocked) { - BlockedReceiver(token) => wakeup(token, guard), - NoneBlocked => {} - BlockedSender(..) => unreachable!(), - } - Ok(()) - } - } - - // Receives a message from this channel - // - // When reading this, remember that there can only ever be one receiver at - // time. - pub fn recv(&self, deadline: Option) -> Result { - let mut guard = self.lock.lock().unwrap(); - - let mut woke_up_after_waiting = false; - // Wait for the buffer to have something in it. No need for a - // while loop because we're the only receiver. - if !guard.disconnected && guard.buf.size() == 0 { - if let Some(deadline) = deadline { - guard = wait_timeout_receiver(&self.lock, - deadline, - guard, - &mut woke_up_after_waiting); - } else { - guard = wait(&self.lock, guard, BlockedReceiver); - woke_up_after_waiting = true; - } - } - - // NB: Channel could be disconnected while waiting, so the order of - // these conditionals is important. - if guard.disconnected && guard.buf.size() == 0 { - return Err(Disconnected); - } - - // Pick up the data, wake up our neighbors, and carry on - assert!(guard.buf.size() > 0 || (deadline.is_some() && !woke_up_after_waiting)); - - if guard.buf.size() == 0 { return Err(Empty); } - - let ret = guard.buf.dequeue(); - self.wakeup_senders(woke_up_after_waiting, guard); - Ok(ret) - } - - pub fn try_recv(&self) -> Result { - let mut guard = self.lock.lock().unwrap(); - - // Easy cases first - if guard.disconnected && guard.buf.size() == 0 { return Err(Disconnected) } - if guard.buf.size() == 0 { return Err(Empty) } - - // Be sure to wake up neighbors - let ret = Ok(guard.buf.dequeue()); - self.wakeup_senders(false, guard); - ret - } - - // Wake up pending senders after some data has been received - // - // * `waited` - flag if the receiver blocked to receive some data, or if it - // just picked up some data on the way out - // * `guard` - the lock guard that is held over this channel's lock - fn wakeup_senders(&self, waited: bool, mut guard: MutexGuard>) { - let pending_sender1: Option = guard.queue.dequeue(); - - // If this is a no-buffer channel (cap == 0), then if we didn't wait we - // need to ACK the sender. If we waited, then the sender waking us up - // was already the ACK. - let pending_sender2 = if guard.cap == 0 && !waited { - match mem::replace(&mut guard.blocker, NoneBlocked) { - NoneBlocked => None, - BlockedReceiver(..) => unreachable!(), - BlockedSender(token) => { - guard.canceled.take(); - Some(token) - } - } - } else { - None - }; - mem::drop(guard); - - // only outside of the lock do we wake up the pending threads - pending_sender1.map(|t| t.signal()); - pending_sender2.map(|t| t.signal()); - } - - // Prepares this shared packet for a channel clone, essentially just bumping - // a refcount. - pub fn clone_chan(&self) { - let old_count = self.channels.fetch_add(1, Ordering::SeqCst); - - // See comments on Arc::clone() on why we do this (for `mem::forget`). - if old_count > MAX_REFCOUNT { - unsafe { - abort(); - } - } - } - - pub fn drop_chan(&self) { - // Only flag the channel as disconnected if we're the last channel - match self.channels.fetch_sub(1, Ordering::SeqCst) { - 1 => {} - _ => return - } - - // Not much to do other than wake up a receiver if one's there - let mut guard = self.lock.lock().unwrap(); - if guard.disconnected { return } - guard.disconnected = true; - match mem::replace(&mut guard.blocker, NoneBlocked) { - NoneBlocked => {} - BlockedSender(..) => unreachable!(), - BlockedReceiver(token) => wakeup(token, guard), - } - } - - pub fn drop_port(&self) { - let mut guard = self.lock.lock().unwrap(); - - if guard.disconnected { return } - guard.disconnected = true; - - // If the capacity is 0, then the sender may want its data back after - // we're disconnected. Otherwise it's now our responsibility to destroy - // the buffered data. As with many other portions of this code, this - // needs to be careful to destroy the data *outside* of the lock to - // prevent deadlock. - let _data = if guard.cap != 0 { - mem::replace(&mut guard.buf.buf, Vec::new()) - } else { - Vec::new() - }; - let mut queue = mem::replace(&mut guard.queue, Queue { - head: ptr::null_mut(), - tail: ptr::null_mut(), - }); - - let waiter = match mem::replace(&mut guard.blocker, NoneBlocked) { - NoneBlocked => None, - BlockedSender(token) => { - *guard.canceled.take().unwrap() = true; - Some(token) - } - BlockedReceiver(..) => unreachable!(), - }; - mem::drop(guard); - - while let Some(token) = queue.dequeue() { token.signal(); } - waiter.map(|t| t.signal()); - } - - //////////////////////////////////////////////////////////////////////////// - // select implementation - //////////////////////////////////////////////////////////////////////////// - - // If Ok, the value is whether this port has data, if Err, then the upgraded - // port needs to be checked instead of this one. - pub fn can_recv(&self) -> bool { - let guard = self.lock.lock().unwrap(); - guard.disconnected || guard.buf.size() > 0 - } - - // Attempts to start selection on this port. This can either succeed or fail - // because there is data waiting. - pub fn start_selection(&self, token: SignalToken) -> StartResult { - let mut guard = self.lock.lock().unwrap(); - if guard.disconnected || guard.buf.size() > 0 { - Abort - } else { - match mem::replace(&mut guard.blocker, BlockedReceiver(token)) { - NoneBlocked => {} - BlockedSender(..) => unreachable!(), - BlockedReceiver(..) => unreachable!(), - } - Installed - } - } - - // Remove a previous selecting thread from this port. This ensures that the - // blocked thread will no longer be visible to any other threads. - // - // The return value indicates whether there's data on this port. - pub fn abort_selection(&self) -> bool { - let mut guard = self.lock.lock().unwrap(); - abort_selection(&mut guard) - } -} - -impl Drop for Packet { - fn drop(&mut self) { - assert_eq!(self.channels.load(Ordering::SeqCst), 0); - let mut guard = self.lock.lock().unwrap(); - assert!(guard.queue.dequeue().is_none()); - assert!(guard.canceled.is_none()); - } -} - - -//////////////////////////////////////////////////////////////////////////////// -// Buffer, a simple ring buffer backed by Vec -//////////////////////////////////////////////////////////////////////////////// - -impl Buffer { - fn enqueue(&mut self, t: T) { - let pos = (self.start + self.size) % self.buf.len(); - self.size += 1; - let prev = mem::replace(&mut self.buf[pos], Some(t)); - assert!(prev.is_none()); - } - - fn dequeue(&mut self) -> T { - let start = self.start; - self.size -= 1; - self.start = (self.start + 1) % self.buf.len(); - let result = &mut self.buf[start]; - result.take().unwrap() - } - - fn size(&self) -> usize { self.size } - fn cap(&self) -> usize { self.buf.len() } -} - -//////////////////////////////////////////////////////////////////////////////// -// Queue, a simple queue to enqueue threads with (stack-allocated nodes) -//////////////////////////////////////////////////////////////////////////////// - -impl Queue { - fn enqueue(&mut self, node: &mut Node) -> WaitToken { - let (wait_token, signal_token) = blocking::tokens(); - node.token = Some(signal_token); - node.next = ptr::null_mut(); - - if self.tail.is_null() { - self.head = node as *mut Node; - self.tail = node as *mut Node; - } else { - unsafe { - (*self.tail).next = node as *mut Node; - self.tail = node as *mut Node; - } - } - - wait_token - } - - fn dequeue(&mut self) -> Option { - if self.head.is_null() { - return None - } - let node = self.head; - self.head = unsafe { (*node).next }; - if self.head.is_null() { - self.tail = ptr::null_mut(); - } - unsafe { - (*node).next = ptr::null_mut(); - Some((*node).token.take().unwrap()) - } - } -} diff --git a/ctr-std/src/sync/mutex.rs b/ctr-std/src/sync/mutex.rs deleted file mode 100644 index e5a4106..0000000 --- a/ctr-std/src/sync/mutex.rs +++ /dev/null @@ -1,716 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use fmt; -use mem; -use ops::{Deref, DerefMut}; -use ptr; -use sys_common::mutex as sys; -use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; - -/// A mutual exclusion primitive useful for protecting shared data -/// -/// This mutex will block threads waiting for the lock to become available. The -/// mutex can also be statically initialized or created via a [`new`] -/// constructor. Each mutex has a type parameter which represents the data that -/// it is protecting. The data can only be accessed through the RAII guards -/// returned from [`lock`] and [`try_lock`], which guarantees that the data is only -/// ever accessed when the mutex is locked. -/// -/// # Poisoning -/// -/// The mutexes in this module implement a strategy called "poisoning" where a -/// mutex is considered poisoned whenever a thread panics while holding the -/// mutex. Once a mutex is poisoned, all other threads are unable to access the -/// data by default as it is likely tainted (some invariant is not being -/// upheld). -/// -/// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a -/// [`Result`] which indicates whether a mutex has been poisoned or not. Most -/// usage of a mutex will simply [`unwrap()`] these results, propagating panics -/// among threads to ensure that a possibly invalid invariant is not witnessed. -/// -/// A poisoned mutex, however, does not prevent all access to the underlying -/// data. The [`PoisonError`] type has an [`into_inner`] method which will return -/// the guard that would have otherwise been returned on a successful lock. This -/// allows access to the data, despite the lock being poisoned. -/// -/// [`new`]: #method.new -/// [`lock`]: #method.lock -/// [`try_lock`]: #method.try_lock -/// [`Result`]: ../../std/result/enum.Result.html -/// [`unwrap()`]: ../../std/result/enum.Result.html#method.unwrap -/// [`PoisonError`]: ../../std/sync/struct.PoisonError.html -/// [`into_inner`]: ../../std/sync/struct.PoisonError.html#method.into_inner -/// -/// # Examples -/// -/// ``` -/// use std::sync::{Arc, Mutex}; -/// use std::thread; -/// use std::sync::mpsc::channel; -/// -/// const N: usize = 10; -/// -/// // Spawn a few threads to increment a shared variable (non-atomically), and -/// // let the main thread know once all increments are done. -/// // -/// // Here we're using an Arc to share memory among threads, and the data inside -/// // the Arc is protected with a mutex. -/// let data = Arc::new(Mutex::new(0)); -/// -/// let (tx, rx) = channel(); -/// for _ in 0..N { -/// let (data, tx) = (data.clone(), tx.clone()); -/// thread::spawn(move || { -/// // The shared state can only be accessed once the lock is held. -/// // Our non-atomic increment is safe because we're the only thread -/// // which can access the shared state when the lock is held. -/// // -/// // We unwrap() the return value to assert that we are not expecting -/// // threads to ever fail while holding the lock. -/// let mut data = data.lock().unwrap(); -/// *data += 1; -/// if *data == N { -/// tx.send(()).unwrap(); -/// } -/// // the lock is unlocked here when `data` goes out of scope. -/// }); -/// } -/// -/// rx.recv().unwrap(); -/// ``` -/// -/// To recover from a poisoned mutex: -/// -/// ``` -/// use std::sync::{Arc, Mutex}; -/// use std::thread; -/// -/// let lock = Arc::new(Mutex::new(0_u32)); -/// let lock2 = lock.clone(); -/// -/// let _ = thread::spawn(move || -> () { -/// // This thread will acquire the mutex first, unwrapping the result of -/// // `lock` because the lock has not been poisoned. -/// let _guard = lock2.lock().unwrap(); -/// -/// // This panic while holding the lock (`_guard` is in scope) will poison -/// // the mutex. -/// panic!(); -/// }).join(); -/// -/// // The lock is poisoned by this point, but the returned result can be -/// // pattern matched on to return the underlying guard on both branches. -/// let mut guard = match lock.lock() { -/// Ok(guard) => guard, -/// Err(poisoned) => poisoned.into_inner(), -/// }; -/// -/// *guard += 1; -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Mutex { - // Note that this mutex is in a *box*, not inlined into the struct itself. - // Once a native mutex has been used once, its address can never change (it - // can't be moved). This mutex type can be safely moved at any time, so to - // ensure that the native mutex is used correctly we box the inner mutex to - // give it a constant address. - inner: Box, - poison: poison::Flag, - data: UnsafeCell, -} - -// these are the only places where `T: Send` matters; all other -// functionality works fine on a single thread. -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Mutex { } -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for Mutex { } - -/// An RAII implementation of a "scoped lock" of a mutex. When this structure is -/// dropped (falls out of scope), the lock will be unlocked. -/// -/// The data protected by the mutex can be accessed through this guard via its -/// [`Deref`] and [`DerefMut`] implementations. -/// -/// This structure is created by the [`lock`] and [`try_lock`] methods on -/// [`Mutex`]. -/// -/// [`Deref`]: ../../std/ops/trait.Deref.html -/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html -/// [`lock`]: struct.Mutex.html#method.lock -/// [`try_lock`]: struct.Mutex.html#method.try_lock -/// [`Mutex`]: struct.Mutex.html -#[must_use = "if unused the Mutex will immediately unlock"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct MutexGuard<'a, T: ?Sized + 'a> { - // funny underscores due to how Deref/DerefMut currently work (they - // disregard field privacy). - __lock: &'a Mutex, - __poison: poison::Guard, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> !Send for MutexGuard<'a, T> { } -#[stable(feature = "mutexguard", since = "1.19.0")] -unsafe impl<'a, T: ?Sized + Sync> Sync for MutexGuard<'a, T> { } - -impl Mutex { - /// Creates a new mutex in an unlocked state ready for use. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Mutex; - /// - /// let mutex = Mutex::new(0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(t: T) -> Mutex { - let mut m = Mutex { - inner: box sys::Mutex::new(), - poison: poison::Flag::new(), - data: UnsafeCell::new(t), - }; - unsafe { - m.inner.init(); - } - m - } -} - -impl Mutex { - /// Acquires a mutex, blocking the current thread until it is able to do so. - /// - /// This function will block the local thread until it is available to acquire - /// the mutex. Upon returning, the thread is the only thread with the lock - /// held. An RAII guard is returned to allow scoped unlock of the lock. When - /// the guard goes out of scope, the mutex will be unlocked. - /// - /// The exact behavior on locking a mutex in the thread which already holds - /// the lock is left unspecified. However, this function will not return on - /// the second call (it might panic or deadlock, for example). - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return an error once the mutex is acquired. - /// - /// # Panics - /// - /// This function might panic when called if the lock is already held by - /// the current thread. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex}; - /// use std::thread; - /// - /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); - /// - /// thread::spawn(move || { - /// *c_mutex.lock().unwrap() = 10; - /// }).join().expect("thread::spawn failed"); - /// assert_eq!(*mutex.lock().unwrap(), 10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> LockResult> { - unsafe { - self.inner.raw_lock(); - MutexGuard::new(self) - } - } - - /// Attempts to acquire this lock. - /// - /// If the lock could not be acquired at this time, then [`Err`] is returned. - /// Otherwise, an RAII guard is returned. The lock will be unlocked when the - /// guard is dropped. - /// - /// This function does not block. - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return failure if the mutex would otherwise be - /// acquired. - /// - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex}; - /// use std::thread; - /// - /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); - /// - /// thread::spawn(move || { - /// let mut lock = c_mutex.try_lock(); - /// if let Ok(ref mut mutex) = lock { - /// **mutex = 10; - /// } else { - /// println!("try_lock failed"); - /// } - /// }).join().expect("thread::spawn failed"); - /// assert_eq!(*mutex.lock().unwrap(), 10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_lock(&self) -> TryLockResult> { - unsafe { - if self.inner.try_lock() { - Ok(MutexGuard::new(self)?) - } else { - Err(TryLockError::WouldBlock) - } - } - } - - /// Determines whether the mutex is poisoned. - /// - /// If another thread is active, the mutex can still become poisoned at any - /// time. You should not trust a `false` value for program correctness - /// without additional synchronization. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex}; - /// use std::thread; - /// - /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); - /// - /// let _ = thread::spawn(move || { - /// let _lock = c_mutex.lock().unwrap(); - /// panic!(); // the mutex gets poisoned - /// }).join(); - /// assert_eq!(mutex.is_poisoned(), true); - /// ``` - #[inline] - #[stable(feature = "sync_poison", since = "1.2.0")] - pub fn is_poisoned(&self) -> bool { - self.poison.get() - } - - /// Consumes this mutex, returning the underlying data. - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return an error instead. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Mutex; - /// - /// let mutex = Mutex::new(0); - /// assert_eq!(mutex.into_inner().unwrap(), 0); - /// ``` - #[stable(feature = "mutex_into_inner", since = "1.6.0")] - pub fn into_inner(self) -> LockResult where T: Sized { - // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner mutex. - // - // To get the inner value, we'd like to call `data.into_inner()`, - // but because `Mutex` impl-s `Drop`, we can't move out of it, so - // we'll have to destructure it manually instead. - unsafe { - // Like `let Mutex { inner, poison, data } = self`. - let (inner, poison, data) = { - let Mutex { ref inner, ref poison, ref data } = self; - (ptr::read(inner), ptr::read(poison), ptr::read(data)) - }; - mem::forget(self); - inner.destroy(); // Keep in sync with the `Drop` impl. - drop(inner); - - poison::map_result(poison.borrow(), |_| data.into_inner()) - } - } - - /// Returns a mutable reference to the underlying data. - /// - /// Since this call borrows the `Mutex` mutably, no actual locking needs to - /// take place---the mutable borrow statically guarantees no locks exist. - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return an error instead. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Mutex; - /// - /// let mut mutex = Mutex::new(0); - /// *mutex.get_mut().unwrap() = 10; - /// assert_eq!(*mutex.lock().unwrap(), 10); - /// ``` - #[stable(feature = "mutex_get_mut", since = "1.6.0")] - pub fn get_mut(&mut self) -> LockResult<&mut T> { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner mutex. - let data = unsafe { &mut *self.data.get() }; - poison::map_result(self.poison.borrow(), |_| data ) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex { - fn drop(&mut self) { - // This is actually safe b/c we know that there is no further usage of - // this mutex (it's up to the user to arrange for a mutex to get - // dropped, that's not our job) - // - // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`. - unsafe { self.inner.destroy() } - } -} - -#[stable(feature = "mutex_from", since = "1.24.0")] -impl From for Mutex { - /// Creates a new mutex in an unlocked state ready for use. - /// This is equivalent to [`Mutex::new`]. - /// - /// [`Mutex::new`]: #method.new - fn from(t: T) -> Self { - Mutex::new(t) - } -} - -#[stable(feature = "mutex_default", since = "1.10.0")] -impl Default for Mutex { - /// Creates a `Mutex`, with the `Default` value for T. - fn default() -> Mutex { - Mutex::new(Default::default()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Mutex { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.try_lock() { - Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(), - Err(TryLockError::Poisoned(err)) => { - f.debug_struct("Mutex").field("data", &&**err.get_ref()).finish() - }, - Err(TryLockError::WouldBlock) => { - struct LockedPlaceholder; - impl fmt::Debug for LockedPlaceholder { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } - } - - f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish() - } - } - } -} - -impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { - unsafe fn new(lock: &'mutex Mutex) -> LockResult> { - poison::map_result(lock.poison.borrow(), |guard| { - MutexGuard { - __lock: lock, - __poison: guard, - } - }) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.__lock.data.get() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.__lock.data.get() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { - #[inline] - fn drop(&mut self) { - unsafe { - self.__lock.poison.done(&self.__poison); - self.__lock.inner.raw_unlock(); - } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("MutexGuard") - .field("lock", &self.__lock) - .finish() - } -} - -#[stable(feature = "std_guard_impls", since = "1.20.0")] -impl<'a, T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (**self).fmt(f) - } -} - -pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { - &guard.__lock.inner -} - -pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { - &guard.__lock.poison -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use sync::mpsc::channel; - use sync::{Arc, Mutex, Condvar}; - use sync::atomic::{AtomicUsize, Ordering}; - use thread; - - struct Packet(Arc<(Mutex, Condvar)>); - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - #[test] - fn smoke() { - let m = Mutex::new(()); - drop(m.lock().unwrap()); - drop(m.lock().unwrap()); - } - - #[test] - fn lots_and_lots() { - const J: u32 = 1000; - const K: u32 = 3; - - let m = Arc::new(Mutex::new(0)); - - fn inc(m: &Mutex) { - for _ in 0..J { - *m.lock().unwrap() += 1; - } - } - - let (tx, rx) = channel(); - for _ in 0..K { - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); }); - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); }); - } - - drop(tx); - for _ in 0..2 * K { - rx.recv().unwrap(); - } - assert_eq!(*m.lock().unwrap(), J * K * 2); - } - - #[test] - fn try_lock() { - let m = Mutex::new(()); - *m.try_lock().unwrap() = (); - } - - #[test] - fn test_into_inner() { - let m = Mutex::new(NonCopy(10)); - assert_eq!(m.into_inner().unwrap(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = Mutex::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner().unwrap(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_into_inner_poison() { - let m = Arc::new(Mutex::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.lock().unwrap(); - panic!("test panic in inner thread to poison mutex"); - }).join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().into_inner() { - Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), - Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x), - } - } - - #[test] - fn test_get_mut() { - let mut m = Mutex::new(NonCopy(10)); - *m.get_mut().unwrap() = NonCopy(20); - assert_eq!(m.into_inner().unwrap(), NonCopy(20)); - } - - #[test] - fn test_get_mut_poison() { - let m = Arc::new(Mutex::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.lock().unwrap(); - panic!("test panic in inner thread to poison mutex"); - }).join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().get_mut() { - Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), - Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x), - } - } - - #[test] - fn test_mutex_arc_condvar() { - let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); - let packet2 = Packet(packet.0.clone()); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - // wait until parent gets in - rx.recv().unwrap(); - let &(ref lock, ref cvar) = &*packet2.0; - let mut lock = lock.lock().unwrap(); - *lock = true; - cvar.notify_one(); - }); - - let &(ref lock, ref cvar) = &*packet.0; - let mut lock = lock.lock().unwrap(); - tx.send(()).unwrap(); - assert!(!*lock); - while !*lock { - lock = cvar.wait(lock).unwrap(); - } - } - - #[test] - fn test_arc_condvar_poison() { - let packet = Packet(Arc::new((Mutex::new(1), Condvar::new()))); - let packet2 = Packet(packet.0.clone()); - let (tx, rx) = channel(); - - let _t = thread::spawn(move || -> () { - rx.recv().unwrap(); - let &(ref lock, ref cvar) = &*packet2.0; - let _g = lock.lock().unwrap(); - cvar.notify_one(); - // Parent should fail when it wakes up. - panic!(); - }); - - let &(ref lock, ref cvar) = &*packet.0; - let mut lock = lock.lock().unwrap(); - tx.send(()).unwrap(); - while *lock == 1 { - match cvar.wait(lock) { - Ok(l) => { - lock = l; - assert_eq!(*lock, 1); - } - Err(..) => break, - } - } - } - - #[test] - fn test_mutex_arc_poison() { - let arc = Arc::new(Mutex::new(1)); - assert!(!arc.is_poisoned()); - let arc2 = arc.clone(); - let _ = thread::spawn(move|| { - let lock = arc2.lock().unwrap(); - assert_eq!(*lock, 2); - }).join(); - assert!(arc.lock().is_err()); - assert!(arc.is_poisoned()); - } - - #[test] - fn test_mutex_arc_nested() { - // Tests nested mutexes and access - // to underlying data. - let arc = Arc::new(Mutex::new(1)); - let arc2 = Arc::new(Mutex::new(arc)); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let lock = arc2.lock().unwrap(); - let lock2 = lock.lock().unwrap(); - assert_eq!(*lock2, 1); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_mutex_arc_access_in_unwind() { - let arc = Arc::new(Mutex::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move|| -> () { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - *self.i.lock().unwrap() += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }).join(); - let lock = arc.lock().unwrap(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_mutex_unsized() { - let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); - { - let b = &mut *mutex.lock().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*mutex.lock().unwrap(), comp); - } -} diff --git a/ctr-std/src/sync/once.rs b/ctr-std/src/sync/once.rs deleted file mode 100644 index f6cb8be..0000000 --- a/ctr-std/src/sync/once.rs +++ /dev/null @@ -1,596 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A "once initialization" primitive -//! -//! This primitive is meant to be used to run one-time initialization. An -//! example use case would be for initializing an FFI library. - -// A "once" is a relatively simple primitive, and it's also typically provided -// by the OS as well (see `pthread_once` or `InitOnceExecuteOnce`). The OS -// primitives, however, tend to have surprising restrictions, such as the Unix -// one doesn't allow an argument to be passed to the function. -// -// As a result, we end up implementing it ourselves in the standard library. -// This also gives us the opportunity to optimize the implementation a bit which -// should help the fast path on call sites. Consequently, let's explain how this -// primitive works now! -// -// So to recap, the guarantees of a Once are that it will call the -// initialization closure at most once, and it will never return until the one -// that's running has finished running. This means that we need some form of -// blocking here while the custom callback is running at the very least. -// Additionally, we add on the restriction of **poisoning**. Whenever an -// initialization closure panics, the Once enters a "poisoned" state which means -// that all future calls will immediately panic as well. -// -// So to implement this, one might first reach for a `Mutex`, but those cannot -// be put into a `static`. It also gets a lot harder with poisoning to figure -// out when the mutex needs to be deallocated because it's not after the closure -// finishes, but after the first successful closure finishes. -// -// All in all, this is instead implemented with atomics and lock-free -// operations! Whee! Each `Once` has one word of atomic state, and this state is -// CAS'd on to determine what to do. There are four possible state of a `Once`: -// -// * Incomplete - no initialization has run yet, and no thread is currently -// using the Once. -// * Poisoned - some thread has previously attempted to initialize the Once, but -// it panicked, so the Once is now poisoned. There are no other -// threads currently accessing this Once. -// * Running - some thread is currently attempting to run initialization. It may -// succeed, so all future threads need to wait for it to finish. -// Note that this state is accompanied with a payload, described -// below. -// * Complete - initialization has completed and all future calls should finish -// immediately. -// -// With 4 states we need 2 bits to encode this, and we use the remaining bits -// in the word we have allocated as a queue of threads waiting for the thread -// responsible for entering the RUNNING state. This queue is just a linked list -// of Waiter nodes which is monotonically increasing in size. Each node is -// allocated on the stack, and whenever the running closure finishes it will -// consume the entire queue and notify all waiters they should try again. -// -// You'll find a few more details in the implementation, but that's the gist of -// it! - -use fmt; -use marker; -use ptr; -use sync::atomic::{AtomicUsize, AtomicBool, Ordering}; -use thread::{self, Thread}; - -/// A synchronization primitive which can be used to run a one-time global -/// initialization. Useful for one-time initialization for FFI or related -/// functionality. This type can only be constructed with the [`ONCE_INIT`] -/// value or the equivalent [`Once::new`] constructor. -/// -/// [`ONCE_INIT`]: constant.ONCE_INIT.html -/// [`Once::new`]: struct.Once.html#method.new -/// -/// # Examples -/// -/// ``` -/// use std::sync::Once; -/// -/// static START: Once = Once::new(); -/// -/// START.call_once(|| { -/// // run initialization here -/// }); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Once { - // This `state` word is actually an encoded version of just a pointer to a - // `Waiter`, so we add the `PhantomData` appropriately. - state: AtomicUsize, - _marker: marker::PhantomData<*mut Waiter>, -} - -// The `PhantomData` of a raw pointer removes these two auto traits, but we -// enforce both below in the implementation so this should be safe to add. -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for Once {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Once {} - -/// State yielded to [`call_once_force`]’s closure parameter. The state can be -/// used to query the poison status of the [`Once`]. -/// -/// [`call_once_force`]: struct.Once.html#method.call_once_force -/// [`Once`]: struct.Once.html -#[unstable(feature = "once_poison", issue = "33577")] -#[derive(Debug)] -pub struct OnceState { - poisoned: bool, -} - -/// Initialization value for static [`Once`] values. -/// -/// [`Once`]: struct.Once.html -/// -/// # Examples -/// -/// ``` -/// use std::sync::{Once, ONCE_INIT}; -/// -/// static START: Once = ONCE_INIT; -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub const ONCE_INIT: Once = Once::new(); - -// Four states that a Once can be in, encoded into the lower bits of `state` in -// the Once structure. -const INCOMPLETE: usize = 0x0; -const POISONED: usize = 0x1; -const RUNNING: usize = 0x2; -const COMPLETE: usize = 0x3; - -// Mask to learn about the state. All other bits are the queue of waiters if -// this is in the RUNNING state. -const STATE_MASK: usize = 0x3; - -// Representation of a node in the linked list of waiters in the RUNNING state. -struct Waiter { - thread: Option, - signaled: AtomicBool, - next: *mut Waiter, -} - -// Helper struct used to clean up after a closure call with a `Drop` -// implementation to also run on panic. -struct Finish<'a> { - panicked: bool, - me: &'a Once, -} - -impl Once { - /// Creates a new `Once` value. - #[stable(feature = "once_new", since = "1.2.0")] - pub const fn new() -> Once { - Once { - state: AtomicUsize::new(INCOMPLETE), - _marker: marker::PhantomData, - } - } - - /// Performs an initialization routine once and only once. The given closure - /// will be executed if this is the first time `call_once` has been called, - /// and otherwise the routine will *not* be invoked. - /// - /// This method will block the calling thread if another initialization - /// routine is currently running. - /// - /// When this function returns, it is guaranteed that some initialization - /// has run and completed (it may not be the closure specified). It is also - /// guaranteed that any memory writes performed by the executed closure can - /// be reliably observed by other threads at this point (there is a - /// happens-before relation between the closure and code executing after the - /// return). - /// - /// If the given closure recusively invokes `call_once` on the same `Once` - /// instance the exact behavior is not specified, allowed outcomes are - /// a panic or a deadlock. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Once; - /// - /// static mut VAL: usize = 0; - /// static INIT: Once = Once::new(); - /// - /// // Accessing a `static mut` is unsafe much of the time, but if we do so - /// // in a synchronized fashion (e.g. write once or read all) then we're - /// // good to go! - /// // - /// // This function will only call `expensive_computation` once, and will - /// // otherwise always return the value returned from the first invocation. - /// fn get_cached_val() -> usize { - /// unsafe { - /// INIT.call_once(|| { - /// VAL = expensive_computation(); - /// }); - /// VAL - /// } - /// } - /// - /// fn expensive_computation() -> usize { - /// // ... - /// # 2 - /// } - /// ``` - /// - /// # Panics - /// - /// The closure `f` will only be executed once if this is called - /// concurrently amongst many threads. If that closure panics, however, then - /// it will *poison* this `Once` instance, causing all future invocations of - /// `call_once` to also panic. - /// - /// This is similar to [poisoning with mutexes][poison]. - /// - /// [poison]: struct.Mutex.html#poisoning - #[stable(feature = "rust1", since = "1.0.0")] - pub fn call_once(&self, f: F) where F: FnOnce() { - // Fast path, just see if we've completed initialization. - // An `Acquire` load is enough because that makes all the initialization - // operations visible to us. The cold path uses SeqCst consistently - // because the performance difference really does not matter there, - // and SeqCst minimizes the chances of something going wrong. - if self.state.load(Ordering::Acquire) == COMPLETE { - return - } - - let mut f = Some(f); - self.call_inner(false, &mut |_| f.take().unwrap()()); - } - - /// Performs the same function as [`call_once`] except ignores poisoning. - /// - /// Unlike [`call_once`], if this `Once` has been poisoned (i.e. a previous - /// call to `call_once` or `call_once_force` caused a panic), calling - /// `call_once_force` will still invoke the closure `f` and will _not_ - /// result in an immediate panic. If `f` panics, the `Once` will remain - /// in a poison state. If `f` does _not_ panic, the `Once` will no - /// longer be in a poison state and all future calls to `call_once` or - /// `call_one_force` will no-op. - /// - /// The closure `f` is yielded a [`OnceState`] structure which can be used - /// to query the poison status of the `Once`. - /// - /// [`call_once`]: struct.Once.html#method.call_once - /// [`OnceState`]: struct.OnceState.html - /// - /// # Examples - /// - /// ``` - /// #![feature(once_poison)] - /// - /// use std::sync::Once; - /// use std::thread; - /// - /// static INIT: Once = Once::new(); - /// - /// // poison the once - /// let handle = thread::spawn(|| { - /// INIT.call_once(|| panic!()); - /// }); - /// assert!(handle.join().is_err()); - /// - /// // poisoning propagates - /// let handle = thread::spawn(|| { - /// INIT.call_once(|| {}); - /// }); - /// assert!(handle.join().is_err()); - /// - /// // call_once_force will still run and reset the poisoned state - /// INIT.call_once_force(|state| { - /// assert!(state.poisoned()); - /// }); - /// - /// // once any success happens, we stop propagating the poison - /// INIT.call_once(|| {}); - /// ``` - #[unstable(feature = "once_poison", issue = "33577")] - pub fn call_once_force(&self, f: F) where F: FnOnce(&OnceState) { - // same as above, just with a different parameter to `call_inner`. - // An `Acquire` load is enough because that makes all the initialization - // operations visible to us. The cold path uses SeqCst consistently - // because the performance difference really does not matter there, - // and SeqCst minimizes the chances of something going wrong. - if self.state.load(Ordering::Acquire) == COMPLETE { - return - } - - let mut f = Some(f); - self.call_inner(true, &mut |p| { - f.take().unwrap()(&OnceState { poisoned: p }) - }); - } - - // This is a non-generic function to reduce the monomorphization cost of - // using `call_once` (this isn't exactly a trivial or small implementation). - // - // Additionally, this is tagged with `#[cold]` as it should indeed be cold - // and it helps let LLVM know that calls to this function should be off the - // fast path. Essentially, this should help generate more straight line code - // in LLVM. - // - // Finally, this takes an `FnMut` instead of a `FnOnce` because there's - // currently no way to take an `FnOnce` and call it via virtual dispatch - // without some allocation overhead. - #[cold] - fn call_inner(&self, - ignore_poisoning: bool, - init: &mut dyn FnMut(bool)) { - let mut state = self.state.load(Ordering::SeqCst); - - 'outer: loop { - match state { - // If we're complete, then there's nothing to do, we just - // jettison out as we shouldn't run the closure. - COMPLETE => return, - - // If we're poisoned and we're not in a mode to ignore - // poisoning, then we panic here to propagate the poison. - POISONED if !ignore_poisoning => { - panic!("Once instance has previously been poisoned"); - } - - // Otherwise if we see a poisoned or otherwise incomplete state - // we will attempt to move ourselves into the RUNNING state. If - // we succeed, then the queue of waiters starts at null (all 0 - // bits). - POISONED | - INCOMPLETE => { - let old = self.state.compare_and_swap(state, RUNNING, - Ordering::SeqCst); - if old != state { - state = old; - continue - } - - // Run the initialization routine, letting it know if we're - // poisoned or not. The `Finish` struct is then dropped, and - // the `Drop` implementation here is responsible for waking - // up other waiters both in the normal return and panicking - // case. - let mut complete = Finish { - panicked: true, - me: self, - }; - init(state == POISONED); - complete.panicked = false; - return - } - - // All other values we find should correspond to the RUNNING - // state with an encoded waiter list in the more significant - // bits. We attempt to enqueue ourselves by moving us to the - // head of the list and bail out if we ever see a state that's - // not RUNNING. - _ => { - assert!(state & STATE_MASK == RUNNING); - let mut node = Waiter { - thread: Some(thread::current()), - signaled: AtomicBool::new(false), - next: ptr::null_mut(), - }; - let me = &mut node as *mut Waiter as usize; - assert!(me & STATE_MASK == 0); - - while state & STATE_MASK == RUNNING { - node.next = (state & !STATE_MASK) as *mut Waiter; - let old = self.state.compare_and_swap(state, - me | RUNNING, - Ordering::SeqCst); - if old != state { - state = old; - continue - } - - // Once we've enqueued ourselves, wait in a loop. - // Afterwards reload the state and continue with what we - // were doing from before. - while !node.signaled.load(Ordering::SeqCst) { - thread::park(); - } - state = self.state.load(Ordering::SeqCst); - continue 'outer - } - } - } - } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Once { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Once { .. }") - } -} - -impl<'a> Drop for Finish<'a> { - fn drop(&mut self) { - // Swap out our state with however we finished. We should only ever see - // an old state which was RUNNING. - let queue = if self.panicked { - self.me.state.swap(POISONED, Ordering::SeqCst) - } else { - self.me.state.swap(COMPLETE, Ordering::SeqCst) - }; - assert_eq!(queue & STATE_MASK, RUNNING); - - // Decode the RUNNING to a list of waiters, then walk that entire list - // and wake them up. Note that it is crucial that after we store `true` - // in the node it can be free'd! As a result we load the `thread` to - // signal ahead of time and then unpark it after the store. - unsafe { - let mut queue = (queue & !STATE_MASK) as *mut Waiter; - while !queue.is_null() { - let next = (*queue).next; - let thread = (*queue).thread.take().unwrap(); - (*queue).signaled.store(true, Ordering::SeqCst); - thread.unpark(); - queue = next; - } - } - } -} - -impl OnceState { - /// Returns whether the associated [`Once`] was poisoned prior to the - /// invocation of the closure passed to [`call_once_force`]. - /// - /// [`call_once_force`]: struct.Once.html#method.call_once_force - /// [`Once`]: struct.Once.html - /// - /// # Examples - /// - /// A poisoned `Once`: - /// - /// ``` - /// #![feature(once_poison)] - /// - /// use std::sync::Once; - /// use std::thread; - /// - /// static INIT: Once = Once::new(); - /// - /// // poison the once - /// let handle = thread::spawn(|| { - /// INIT.call_once(|| panic!()); - /// }); - /// assert!(handle.join().is_err()); - /// - /// INIT.call_once_force(|state| { - /// assert!(state.poisoned()); - /// }); - /// ``` - /// - /// An unpoisoned `Once`: - /// - /// ``` - /// #![feature(once_poison)] - /// - /// use std::sync::Once; - /// - /// static INIT: Once = Once::new(); - /// - /// INIT.call_once_force(|state| { - /// assert!(!state.poisoned()); - /// }); - #[unstable(feature = "once_poison", issue = "33577")] - pub fn poisoned(&self) -> bool { - self.poisoned - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use panic; - use sync::mpsc::channel; - use thread; - use super::Once; - - #[test] - fn smoke_once() { - static O: Once = Once::new(); - let mut a = 0; - O.call_once(|| a += 1); - assert_eq!(a, 1); - O.call_once(|| a += 1); - assert_eq!(a, 1); - } - - #[test] - fn stampede_once() { - static O: Once = Once::new(); - static mut RUN: bool = false; - - let (tx, rx) = channel(); - for _ in 0..10 { - let tx = tx.clone(); - thread::spawn(move|| { - for _ in 0..4 { thread::yield_now() } - unsafe { - O.call_once(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - tx.send(()).unwrap(); - }); - } - - unsafe { - O.call_once(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - - for _ in 0..10 { - rx.recv().unwrap(); - } - } - - #[test] - fn poison_bad() { - static O: Once = Once::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.call_once(|| panic!()); - }); - assert!(t.is_err()); - - // poisoning propagates - let t = panic::catch_unwind(|| { - O.call_once(|| {}); - }); - assert!(t.is_err()); - - // we can subvert poisoning, however - let mut called = false; - O.call_once_force(|p| { - called = true; - assert!(p.poisoned()) - }); - assert!(called); - - // once any success happens, we stop propagating the poison - O.call_once(|| {}); - } - - #[test] - fn wait_for_force_to_finish() { - static O: Once = Once::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.call_once(|| panic!()); - }); - assert!(t.is_err()); - - // make sure someone's waiting inside the once via a force - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let t1 = thread::spawn(move || { - O.call_once_force(|p| { - assert!(p.poisoned()); - tx1.send(()).unwrap(); - rx2.recv().unwrap(); - }); - }); - - rx1.recv().unwrap(); - - // put another waiter on the once - let t2 = thread::spawn(|| { - let mut called = false; - O.call_once(|| { - called = true; - }); - assert!(!called); - }); - - tx2.send(()).unwrap(); - - assert!(t1.join().is_ok()); - assert!(t2.join().is_ok()); - - } -} diff --git a/ctr-std/src/sync/rwlock.rs b/ctr-std/src/sync/rwlock.rs deleted file mode 100644 index e3db60c..0000000 --- a/ctr-std/src/sync/rwlock.rs +++ /dev/null @@ -1,808 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use fmt; -use mem; -use ops::{Deref, DerefMut}; -use ptr; -use sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; -use sys_common::rwlock as sys; - -/// A reader-writer lock -/// -/// This type of lock allows a number of readers or at most one writer at any -/// point in time. The write portion of this lock typically allows modification -/// of the underlying data (exclusive access) and the read portion of this lock -/// typically allows for read-only access (shared access). -/// -/// In comparison, a [`Mutex`] does not distinguish between readers or writers -/// that acquire the lock, therefore blocking any threads waiting for the lock to -/// become available. An `RwLock` will allow any number of readers to acquire the -/// lock as long as a writer is not holding the lock. -/// -/// The priority policy of the lock is dependent on the underlying operating -/// system's implementation, and this type does not guarantee that any -/// particular policy will be used. -/// -/// The type parameter `T` represents the data that this lock protects. It is -/// required that `T` satisfies [`Send`] to be shared across threads and -/// [`Sync`] to allow concurrent access through readers. The RAII guards -/// returned from the locking methods implement [`Deref`][] (and [`DerefMut`] -/// for the `write` methods) to allow access to the content of the lock. -/// -/// # Poisoning -/// -/// An `RwLock`, like [`Mutex`], will become poisoned on a panic. Note, however, -/// that an `RwLock` may only be poisoned if a panic occurs while it is locked -/// exclusively (write mode). If a panic occurs in any reader, then the lock -/// will not be poisoned. -/// -/// # Examples -/// -/// ``` -/// use std::sync::RwLock; -/// -/// let lock = RwLock::new(5); -/// -/// // many reader locks can be held at once -/// { -/// let r1 = lock.read().unwrap(); -/// let r2 = lock.read().unwrap(); -/// assert_eq!(*r1, 5); -/// assert_eq!(*r2, 5); -/// } // read locks are dropped at this point -/// -/// // only one write lock may be held, however -/// { -/// let mut w = lock.write().unwrap(); -/// *w += 1; -/// assert_eq!(*w, 6); -/// } // write lock is dropped here -/// ``` -/// -/// [`Deref`]: ../../std/ops/trait.Deref.html -/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html -/// [`Send`]: ../../std/marker/trait.Send.html -/// [`Sync`]: ../../std/marker/trait.Sync.html -/// [`Mutex`]: struct.Mutex.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RwLock { - inner: Box, - poison: poison::Flag, - data: UnsafeCell, -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for RwLock {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for RwLock {} - -/// RAII structure used to release the shared read access of a lock when -/// dropped. -/// -/// This structure is created by the [`read`] and [`try_read`] methods on -/// [`RwLock`]. -/// -/// [`read`]: struct.RwLock.html#method.read -/// [`try_read`]: struct.RwLock.html#method.try_read -/// [`RwLock`]: struct.RwLock.html -#[must_use = "if unused the RwLock will immediately unlock"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { - __lock: &'a RwLock, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> !Send for RwLockReadGuard<'a, T> {} - -#[stable(feature = "rwlock_guard_sync", since = "1.23.0")] -unsafe impl<'a, T: ?Sized + Sync> Sync for RwLockReadGuard<'a, T> {} - -/// RAII structure used to release the exclusive write access of a lock when -/// dropped. -/// -/// This structure is created by the [`write`] and [`try_write`] methods -/// on [`RwLock`]. -/// -/// [`write`]: struct.RwLock.html#method.write -/// [`try_write`]: struct.RwLock.html#method.try_write -/// [`RwLock`]: struct.RwLock.html -#[must_use = "if unused the RwLock will immediately unlock"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { - __lock: &'a RwLock, - __poison: poison::Guard, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> !Send for RwLockWriteGuard<'a, T> {} - -#[stable(feature = "rwlock_guard_sync", since = "1.23.0")] -unsafe impl<'a, T: ?Sized + Sync> Sync for RwLockWriteGuard<'a, T> {} - -impl RwLock { - /// Creates a new instance of an `RwLock` which is unlocked. - /// - /// # Examples - /// - /// ``` - /// use std::sync::RwLock; - /// - /// let lock = RwLock::new(5); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(t: T) -> RwLock { - RwLock { - inner: box sys::RWLock::new(), - poison: poison::Flag::new(), - data: UnsafeCell::new(t), - } - } -} - -impl RwLock { - /// Locks this rwlock with shared read access, blocking the current thread - /// until it can be acquired. - /// - /// The calling thread will be blocked until there are no more writers which - /// hold the lock. There may be other readers currently inside the lock when - /// this method returns. This method does not provide any guarantees with - /// respect to the ordering of whether contentious readers or writers will - /// acquire the lock first. - /// - /// Returns an RAII guard which will release this thread's shared access - /// once it is dropped. - /// - /// # Errors - /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. - /// The failure will occur immediately after the lock has been acquired. - /// - /// # Panics - /// - /// This function might panic when called if the lock is already held by the current thread. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, RwLock}; - /// use std::thread; - /// - /// let lock = Arc::new(RwLock::new(1)); - /// let c_lock = lock.clone(); - /// - /// let n = lock.read().unwrap(); - /// assert_eq!(*n, 1); - /// - /// thread::spawn(move || { - /// let r = c_lock.read(); - /// assert!(r.is_ok()); - /// }).join().unwrap(); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn read(&self) -> LockResult> { - unsafe { - self.inner.read(); - RwLockReadGuard::new(self) - } - } - - /// Attempts to acquire this rwlock with shared read access. - /// - /// If the access could not be granted at this time, then `Err` is returned. - /// Otherwise, an RAII guard is returned which will release the shared access - /// when it is dropped. - /// - /// This function does not block. - /// - /// This function does not provide any guarantees with respect to the ordering - /// of whether contentious readers or writers will acquire the lock first. - /// - /// # Errors - /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. An - /// error will only be returned if the lock would have otherwise been - /// acquired. - /// - /// # Examples - /// - /// ``` - /// use std::sync::RwLock; - /// - /// let lock = RwLock::new(1); - /// - /// match lock.try_read() { - /// Ok(n) => assert_eq!(*n, 1), - /// Err(_) => unreachable!(), - /// }; - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_read(&self) -> TryLockResult> { - unsafe { - if self.inner.try_read() { - Ok(RwLockReadGuard::new(self)?) - } else { - Err(TryLockError::WouldBlock) - } - } - } - - /// Locks this rwlock with exclusive write access, blocking the current - /// thread until it can be acquired. - /// - /// This function will not return while other writers or other readers - /// currently have access to the lock. - /// - /// Returns an RAII guard which will drop the write access of this rwlock - /// when dropped. - /// - /// # Errors - /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. - /// An error will be returned when the lock is acquired. - /// - /// # Panics - /// - /// This function might panic when called if the lock is already held by the current thread. - /// - /// # Examples - /// - /// ``` - /// use std::sync::RwLock; - /// - /// let lock = RwLock::new(1); - /// - /// let mut n = lock.write().unwrap(); - /// *n = 2; - /// - /// assert!(lock.try_read().is_err()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn write(&self) -> LockResult> { - unsafe { - self.inner.write(); - RwLockWriteGuard::new(self) - } - } - - /// Attempts to lock this rwlock with exclusive write access. - /// - /// If the lock could not be acquired at this time, then `Err` is returned. - /// Otherwise, an RAII guard is returned which will release the lock when - /// it is dropped. - /// - /// This function does not block. - /// - /// This function does not provide any guarantees with respect to the ordering - /// of whether contentious readers or writers will acquire the lock first. - /// - /// # Errors - /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. An - /// error will only be returned if the lock would have otherwise been - /// acquired. - /// - /// # Examples - /// - /// ``` - /// use std::sync::RwLock; - /// - /// let lock = RwLock::new(1); - /// - /// let n = lock.read().unwrap(); - /// assert_eq!(*n, 1); - /// - /// assert!(lock.try_write().is_err()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn try_write(&self) -> TryLockResult> { - unsafe { - if self.inner.try_write() { - Ok(RwLockWriteGuard::new(self)?) - } else { - Err(TryLockError::WouldBlock) - } - } - } - - /// Determines whether the lock is poisoned. - /// - /// If another thread is active, the lock can still become poisoned at any - /// time. You should not trust a `false` value for program correctness - /// without additional synchronization. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, RwLock}; - /// use std::thread; - /// - /// let lock = Arc::new(RwLock::new(0)); - /// let c_lock = lock.clone(); - /// - /// let _ = thread::spawn(move || { - /// let _lock = c_lock.write().unwrap(); - /// panic!(); // the lock gets poisoned - /// }).join(); - /// assert_eq!(lock.is_poisoned(), true); - /// ``` - #[inline] - #[stable(feature = "sync_poison", since = "1.2.0")] - pub fn is_poisoned(&self) -> bool { - self.poison.get() - } - - /// Consumes this `RwLock`, returning the underlying data. - /// - /// # Errors - /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. An - /// error will only be returned if the lock would have otherwise been - /// acquired. - /// - /// # Examples - /// - /// ``` - /// use std::sync::RwLock; - /// - /// let lock = RwLock::new(String::new()); - /// { - /// let mut s = lock.write().unwrap(); - /// *s = "modified".to_owned(); - /// } - /// assert_eq!(lock.into_inner().unwrap(), "modified"); - /// ``` - #[stable(feature = "rwlock_into_inner", since = "1.6.0")] - pub fn into_inner(self) -> LockResult where T: Sized { - // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner lock. - // - // To get the inner value, we'd like to call `data.into_inner()`, - // but because `RwLock` impl-s `Drop`, we can't move out of it, so - // we'll have to destructure it manually instead. - unsafe { - // Like `let RwLock { inner, poison, data } = self`. - let (inner, poison, data) = { - let RwLock { ref inner, ref poison, ref data } = self; - (ptr::read(inner), ptr::read(poison), ptr::read(data)) - }; - mem::forget(self); - inner.destroy(); // Keep in sync with the `Drop` impl. - drop(inner); - - poison::map_result(poison.borrow(), |_| data.into_inner()) - } - } - - /// Returns a mutable reference to the underlying data. - /// - /// Since this call borrows the `RwLock` mutably, no actual locking needs to - /// take place---the mutable borrow statically guarantees no locks exist. - /// - /// # Errors - /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. An - /// error will only be returned if the lock would have otherwise been - /// acquired. - /// - /// # Examples - /// - /// ``` - /// use std::sync::RwLock; - /// - /// let mut lock = RwLock::new(0); - /// *lock.get_mut().unwrap() = 10; - /// assert_eq!(*lock.read().unwrap(), 10); - /// ``` - #[stable(feature = "rwlock_get_mut", since = "1.6.0")] - pub fn get_mut(&mut self) -> LockResult<&mut T> { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner lock. - let data = unsafe { &mut *self.data.get() }; - poison::map_result(self.poison.borrow(), |_| data) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock { - fn drop(&mut self) { - // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`. - unsafe { self.inner.destroy() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for RwLock { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.try_read() { - Ok(guard) => f.debug_struct("RwLock").field("data", &&*guard).finish(), - Err(TryLockError::Poisoned(err)) => { - f.debug_struct("RwLock").field("data", &&**err.get_ref()).finish() - }, - Err(TryLockError::WouldBlock) => { - struct LockedPlaceholder; - impl fmt::Debug for LockedPlaceholder { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } - } - - f.debug_struct("RwLock").field("data", &LockedPlaceholder).finish() - } - } - } -} - -#[stable(feature = "rw_lock_default", since = "1.10.0")] -impl Default for RwLock { - /// Creates a new `RwLock`, with the `Default` value for T. - fn default() -> RwLock { - RwLock::new(Default::default()) - } -} - -#[stable(feature = "rw_lock_from", since = "1.24.0")] -impl From for RwLock { - /// Creates a new instance of an `RwLock` which is unlocked. - /// This is equivalent to [`RwLock::new`]. - /// - /// [`RwLock::new`]: #method.new - fn from(t: T) -> Self { - RwLock::new(t) - } -} - -impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { - unsafe fn new(lock: &'rwlock RwLock) - -> LockResult> { - poison::map_result(lock.poison.borrow(), |_| { - RwLockReadGuard { - __lock: lock, - } - }) - } -} - -impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { - unsafe fn new(lock: &'rwlock RwLock) - -> LockResult> { - poison::map_result(lock.poison.borrow(), |guard| { - RwLockWriteGuard { - __lock: lock, - __poison: guard, - } - }) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, T: fmt::Debug> fmt::Debug for RwLockReadGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("RwLockReadGuard") - .field("lock", &self.__lock) - .finish() - } -} - -#[stable(feature = "std_guard_impls", since = "1.20.0")] -impl<'a, T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (**self).fmt(f) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<'a, T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("RwLockWriteGuard") - .field("lock", &self.__lock) - .finish() - } -} - -#[stable(feature = "std_guard_impls", since = "1.20.0")] -impl<'a, T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (**self).fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.__lock.data.get() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.__lock.data.get() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'rwlock, T: ?Sized> DerefMut for RwLockWriteGuard<'rwlock, T> { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.__lock.data.get() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> { - fn drop(&mut self) { - unsafe { self.__lock.inner.read_unlock(); } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> { - fn drop(&mut self) { - self.__lock.poison.done(&self.__poison); - unsafe { self.__lock.inner.write_unlock(); } - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use rand::{self, Rng}; - use sync::mpsc::channel; - use thread; - use sync::{Arc, RwLock, TryLockError}; - use sync::atomic::{AtomicUsize, Ordering}; - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - #[test] - fn smoke() { - let l = RwLock::new(()); - drop(l.read().unwrap()); - drop(l.write().unwrap()); - drop((l.read().unwrap(), l.read().unwrap())); - drop(l.write().unwrap()); - } - - #[test] - fn frob() { - const N: u32 = 10; - const M: usize = 1000; - - let r = Arc::new(RwLock::new(())); - - let (tx, rx) = channel::<()>(); - for _ in 0..N { - let tx = tx.clone(); - let r = r.clone(); - thread::spawn(move || { - let mut rng = rand::thread_rng(); - for _ in 0..M { - if rng.gen_weighted_bool(N) { - drop(r.write().unwrap()); - } else { - drop(r.read().unwrap()); - } - } - drop(tx); - }); - } - drop(tx); - let _ = rx.recv(); - } - - #[test] - fn test_rw_arc_poison_wr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write().unwrap(); - panic!(); - }).join(); - assert!(arc.read().is_err()); - } - - #[test] - fn test_rw_arc_poison_ww() { - let arc = Arc::new(RwLock::new(1)); - assert!(!arc.is_poisoned()); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write().unwrap(); - panic!(); - }).join(); - assert!(arc.write().is_err()); - assert!(arc.is_poisoned()); - } - - #[test] - fn test_rw_arc_no_poison_rr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read().unwrap(); - panic!(); - }).join(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 1); - } - #[test] - fn test_rw_arc_no_poison_rw() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read().unwrap(); - panic!() - }).join(); - let lock = arc.write().unwrap(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_rw_arc() { - let arc = Arc::new(RwLock::new(0)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - - thread::spawn(move || { - let mut lock = arc2.write().unwrap(); - for _ in 0..10 { - let tmp = *lock; - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; - } - tx.send(()).unwrap(); - }); - - // Readers try to catch the writer in the act - let mut children = Vec::new(); - for _ in 0..5 { - let arc3 = arc.clone(); - children.push(thread::spawn(move || { - let lock = arc3.read().unwrap(); - assert!(*lock >= 0); - })); - } - - // Wait for children to pass their asserts - for r in children { - assert!(r.join().is_ok()); - } - - // Wait for writer to finish - rx.recv().unwrap(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 10); - } - - #[test] - fn test_rw_arc_access_in_unwind() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || -> () { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - let mut lock = self.i.write().unwrap(); - *lock += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }).join(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_rwlock_unsized() { - let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); - { - let b = &mut *rw.write().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*rw.read().unwrap(), comp); - } - - #[test] - fn test_rwlock_try_write() { - let lock = RwLock::new(0isize); - let read_guard = lock.read().unwrap(); - - let write_result = lock.try_write(); - match write_result { - Err(TryLockError::WouldBlock) => (), - Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"), - Err(_) => assert!(false, "unexpected error"), - } - - drop(read_guard); - } - - #[test] - fn test_into_inner() { - let m = RwLock::new(NonCopy(10)); - assert_eq!(m.into_inner().unwrap(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = RwLock::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner().unwrap(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_into_inner_poison() { - let m = Arc::new(RwLock::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.write().unwrap(); - panic!("test panic in inner thread to poison RwLock"); - }).join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().into_inner() { - Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), - Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x), - } - } - - #[test] - fn test_get_mut() { - let mut m = RwLock::new(NonCopy(10)); - *m.get_mut().unwrap() = NonCopy(20); - assert_eq!(m.into_inner().unwrap(), NonCopy(20)); - } - - #[test] - fn test_get_mut_poison() { - let m = Arc::new(RwLock::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.write().unwrap(); - panic!("test panic in inner thread to poison RwLock"); - }).join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().get_mut() { - Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), - Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x), - } - } -} diff --git a/ctr-std/src/sys/cloudabi/abi/bitflags.rs b/ctr-std/src/sys/cloudabi/abi/bitflags.rs deleted file mode 100644 index f764cc1..0000000 --- a/ctr-std/src/sys/cloudabi/abi/bitflags.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2018 Nuxi (https://nuxi.nl/) and contributors. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. - -// Appease Rust's tidy. -// ignore-license - -#[cfg(feature = "bitflags")] -#[macro_use] -extern crate bitflags; - -// Minimal implementation of bitflags! in case we can't depend on the bitflags -// crate. Only implements `bits()` and a `from_bits_truncate()` that doesn't -// actually truncate. -#[cfg(not(feature = "bitflags"))] -macro_rules! bitflags { - ( - $(#[$attr:meta])* - pub struct $name:ident: $type:ty { - $($(#[$const_attr:meta])* const $const:ident = $val:expr;)* - } - ) => { - $(#[$attr])* - #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] - pub struct $name { bits: $type } - impl $name { - $($(#[$const_attr])* pub const $const: $name = $name{ bits: $val };)* - pub fn bits(&self) -> $type { self.bits } - pub fn from_bits_truncate(bits: $type) -> Self { $name{ bits } } - } - } -} diff --git a/ctr-std/src/sys/cloudabi/abi/cloudabi.rs b/ctr-std/src/sys/cloudabi/abi/cloudabi.rs deleted file mode 100644 index cd9a5ad..0000000 --- a/ctr-std/src/sys/cloudabi/abi/cloudabi.rs +++ /dev/null @@ -1,2847 +0,0 @@ -// Copyright (c) 2016-2017 Nuxi (https://nuxi.nl/) and contributors. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. -// -// This file is automatically generated. Do not edit. -// -// Source: https://github.com/NuxiNL/cloudabi - -// Appease Rust's tidy. -// ignore-license -// ignore-tidy-linelength - -//! **PLEASE NOTE: This entire crate including this -//! documentation is automatically generated from -//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt)** -//! -//! # Nuxi CloudABI -//! -//! CloudABI is what you get if you take POSIX, add capability-based -//! security, and remove everything that's incompatible with that. The -//! result is a minimal ABI consisting of only 49 syscalls. -//! -//! CloudABI doesn't have its own kernel, but instead is implemented in existing -//! kernels: FreeBSD has CloudABI support for x86-64 and arm64, and [a patch-set -//! for NetBSD](https://github.com/NuxiNL/netbsd) and [a patch-set for -//! Linux](https://github.com/NuxiNL/linux) are available as well. This means that -//! CloudABI binaries can be executed on different operating systems, without any -//! modification. -//! -//! ## Capability-Based Security -//! -//! Capability-based security means that processes can only perform -//! actions that have no global impact. Processes cannot open files by -//! their absolute path, cannot open network connections, and cannot -//! observe global system state such as the process table. -//! -//! The capabilities of a process are fully determined by its set of open -//! file descriptors (fds). For example, files can only be opened if the -//! process already has a file descriptor to a directory the file is in. -//! -//! Unlike in POSIX, where processes are normally started with file -//! descriptors 0, 1, and 2 reserved for standard input, output, and -//! error, CloudABI does not reserve any file descriptor numbers for -//! specific purposes. -//! -//! In CloudABI, a process depends on its parent process to launch it with -//! the right set of resources, since the process will not be able to open -//! any new resources. For example, a simple static web server would need -//! to be started with a file descriptor to a [TCP -//! listener](https://github.com/NuxiNL/flower), and a file descriptor to -//! the directory for which to serve files. The web server will then be -//! unable to do anything other than reading files in that directory, and -//! process incoming network connections. -//! -//! So, unknown CloudABI binaries can safely be executed without the need -//! for containers, virtual machines, or other sandboxing technologies. -//! -//! Watch [Ed Schouten's Talk at -//! 32C3](https://www.youtube.com/watch?v=3N29vrPoDv8) for more -//! information about what capability-based security for UNIX means. -//! -//! ## Cloudlibc -//! -//! [Cloudlibc](https://github.com/NuxiNL/cloudlibc) is an implementation -//! of the C standard library, without all CloudABI-incompatible -//! functions. For example, Cloudlibc does not have `printf`, but does -//! have `fprintf`. It does not have `open`, but does have `openat`. -//! -//! ## CloudABI-Ports -//! -//! [CloudABI-Ports](https://github.com/NuxiNL/cloudabi-ports) is a -//! collection of ports of commonly used libraries and applications to -//! CloudABI. It contains software such as `zlib`, `libpng`, `boost`, -//! `memcached`, and much more. The software is patched to not depend on -//! any global state, such as files in `/etc` or `/dev`, using `open()`, -//! etc. -//! -//! ## Using CloudABI -//! -//! Instructions for using CloudABI (including kernel modules/patches, -//! toolchain, and ports) are available for several operating systems: -//! -//! - [Arch Linux](https://nuxi.nl/cloudabi/archlinux/) -//! - [Debian, Ubuntu, and other Debian derivatives](https://nuxi.nl/cloudabi/debian/) -//! - [FreeBSD, PC-BSD and DragonFly BSD](https://nuxi.nl/cloudabi/freebsd/) -//! - [Mac OS X](https://nuxi.nl/cloudabi/mac/) -//! - [NetBSD](https://nuxi.nl/cloudabi/netbsd/) -//! -//! ## Specification of the ABI -//! -//! The entire ABI is specified in a a file called -//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt), -//! from which all -//! [headers](https://github.com/NuxiNL/cloudabi/tree/master/headers) -//! and documentation (including the one you're reading now) is generated. - -#![no_std] -#![allow(non_camel_case_types)] - -include!("bitflags.rs"); - -/// File or memory access pattern advisory information. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum advice { - /// The application expects that it will not access the - /// specified data in the near future. - DONTNEED = 1, - /// The application expects to access the specified data - /// once and then not reuse it thereafter. - NOREUSE = 2, - /// The application has no advice to give on its behavior - /// with respect to the specified data. - NORMAL = 3, - /// The application expects to access the specified data - /// in a random order. - RANDOM = 4, - /// The application expects to access the specified data - /// sequentially from lower offsets to higher offsets. - SEQUENTIAL = 5, - /// The application expects to access the specified data - /// in the near future. - WILLNEED = 6, -} - -/// Enumeration describing the kind of value stored in [`auxv`](struct.auxv.html). -#[repr(u32)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum auxtype { - /// Base address of the binary argument data provided to - /// [`proc_exec()`](fn.proc_exec.html). - ARGDATA = 256, - /// Length of the binary argument data provided to - /// [`proc_exec()`](fn.proc_exec.html). - ARGDATALEN = 257, - /// Base address at which the executable is placed in - /// memory. - BASE = 7, - /// Base address of a buffer of random data that may be - /// used for non-cryptographic purposes, for example as a - /// canary for stack smashing protection. - CANARY = 258, - /// Length of a buffer of random data that may be used - /// for non-cryptographic purposes, for example as a - /// canary for stack smashing protection. - CANARYLEN = 259, - /// Number of CPUs that the system this process is running - /// on has. - NCPUS = 260, - /// Terminator of the auxiliary vector. - NULL = 0, - /// Smallest memory object size for which individual - /// memory protection controls can be configured. - PAGESZ = 6, - /// Address of the first ELF program header of the - /// executable. - PHDR = 3, - /// Number of ELF program headers of the executable. - PHNUM = 4, - /// Identifier of the process. - /// - /// This environment does not provide any simple numerical - /// process identifiers, for the reason that these are not - /// useful in distributed contexts. Instead, processes are - /// identified by a UUID. - /// - /// This record should point to sixteen bytes of binary - /// data, containing a version 4 UUID (fully random). - PID = 263, - /// Address of the ELF header of the vDSO. - /// - /// The vDSO is a shared library that is mapped in the - /// address space of the process. It provides entry points - /// for every system call supported by the environment, - /// all having a corresponding symbol that is prefixed - /// with `cloudabi_sys_`. System calls should be invoked - /// through these entry points. - /// - /// The first advantage of letting processes call into a - /// vDSO to perform system calls instead of raising - /// hardware traps is that it allows for easy emulation of - /// executables on top of existing operating systems. The - /// second advantage is that in cases where an operating - /// system provides native support for CloudABI executables, - /// it may still implement partial userspace - /// implementations of these system calls to improve - /// performance (e.g., [`clock_time_get()`](fn.clock_time_get.html)). It also provides - /// a more dynamic way of adding, removing or replacing - /// system calls. - SYSINFO_EHDR = 262, - /// Thread ID of the initial thread of the process. - TID = 261, -} - -/// Identifiers for clocks. -#[repr(u32)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum clockid { - /// The system-wide monotonic clock, which is defined as a - /// clock measuring real time, whose value cannot be - /// adjusted and which cannot have negative clock jumps. - /// - /// The epoch of this clock is undefined. The absolute - /// time value of this clock therefore has no meaning. - MONOTONIC = 1, - /// The CPU-time clock associated with the current - /// process. - PROCESS_CPUTIME_ID = 2, - /// The system-wide clock measuring real time. Time value - /// zero corresponds with 1970-01-01T00:00:00Z. - REALTIME = 3, - /// The CPU-time clock associated with the current thread. - THREAD_CPUTIME_ID = 4, -} - -/// A userspace condition variable. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct condvar(pub u32); -/// The condition variable is in its initial state. There -/// are no threads waiting to be woken up. If the -/// condition variable has any other value, the kernel -/// must be called to wake up any sleeping threads. -pub const CONDVAR_HAS_NO_WAITERS: condvar = condvar(0); - -/// Identifier for a device containing a file system. Can be used -/// in combination with [`inode`](struct.inode.html) to uniquely identify a file on the -/// local system. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct device(pub u64); - -/// A reference to the offset of a directory entry. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct dircookie(pub u64); -/// Permanent reference to the first directory entry -/// within a directory. -pub const DIRCOOKIE_START: dircookie = dircookie(0); - -/// Error codes returned by system calls. -/// -/// Not all of these error codes are returned by the system calls -/// provided by this environment, but are either used in userspace -/// exclusively or merely provided for alignment with POSIX. -#[repr(u16)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum errno { - /// No error occurred. System call completed successfully. - SUCCESS = 0, - /// Argument list too long. - TOOBIG = 1, - /// Permission denied. - ACCES = 2, - /// Address in use. - ADDRINUSE = 3, - /// Address not available. - ADDRNOTAVAIL = 4, - /// Address family not supported. - AFNOSUPPORT = 5, - /// Resource unavailable, or operation would block. - AGAIN = 6, - /// Connection already in progress. - ALREADY = 7, - /// Bad file descriptor. - BADF = 8, - /// Bad message. - BADMSG = 9, - /// Device or resource busy. - BUSY = 10, - /// Operation canceled. - CANCELED = 11, - /// No child processes. - CHILD = 12, - /// Connection aborted. - CONNABORTED = 13, - /// Connection refused. - CONNREFUSED = 14, - /// Connection reset. - CONNRESET = 15, - /// Resource deadlock would occur. - DEADLK = 16, - /// Destination address required. - DESTADDRREQ = 17, - /// Mathematics argument out of domain of function. - DOM = 18, - /// Reserved. - DQUOT = 19, - /// File exists. - EXIST = 20, - /// Bad address. - FAULT = 21, - /// File too large. - FBIG = 22, - /// Host is unreachable. - HOSTUNREACH = 23, - /// Identifier removed. - IDRM = 24, - /// Illegal byte sequence. - ILSEQ = 25, - /// Operation in progress. - INPROGRESS = 26, - /// Interrupted function. - INTR = 27, - /// Invalid argument. - INVAL = 28, - /// I/O error. - IO = 29, - /// Socket is connected. - ISCONN = 30, - /// Is a directory. - ISDIR = 31, - /// Too many levels of symbolic links. - LOOP = 32, - /// File descriptor value too large. - MFILE = 33, - /// Too many links. - MLINK = 34, - /// Message too large. - MSGSIZE = 35, - /// Reserved. - MULTIHOP = 36, - /// Filename too long. - NAMETOOLONG = 37, - /// Network is down. - NETDOWN = 38, - /// Connection aborted by network. - NETRESET = 39, - /// Network unreachable. - NETUNREACH = 40, - /// Too many files open in system. - NFILE = 41, - /// No buffer space available. - NOBUFS = 42, - /// No such device. - NODEV = 43, - /// No such file or directory. - NOENT = 44, - /// Executable file format error. - NOEXEC = 45, - /// No locks available. - NOLCK = 46, - /// Reserved. - NOLINK = 47, - /// Not enough space. - NOMEM = 48, - /// No message of the desired type. - NOMSG = 49, - /// Protocol not available. - NOPROTOOPT = 50, - /// No space left on device. - NOSPC = 51, - /// Function not supported. - NOSYS = 52, - /// The socket is not connected. - NOTCONN = 53, - /// Not a directory or a symbolic link to a directory. - NOTDIR = 54, - /// Directory not empty. - NOTEMPTY = 55, - /// State not recoverable. - NOTRECOVERABLE = 56, - /// Not a socket. - NOTSOCK = 57, - /// Not supported, or operation not supported on socket. - NOTSUP = 58, - /// Inappropriate I/O control operation. - NOTTY = 59, - /// No such device or address. - NXIO = 60, - /// Value too large to be stored in data type. - OVERFLOW = 61, - /// Previous owner died. - OWNERDEAD = 62, - /// Operation not permitted. - PERM = 63, - /// Broken pipe. - PIPE = 64, - /// Protocol error. - PROTO = 65, - /// Protocol not supported. - PROTONOSUPPORT = 66, - /// Protocol wrong type for socket. - PROTOTYPE = 67, - /// Result too large. - RANGE = 68, - /// Read-only file system. - ROFS = 69, - /// Invalid seek. - SPIPE = 70, - /// No such process. - SRCH = 71, - /// Reserved. - STALE = 72, - /// Connection timed out. - TIMEDOUT = 73, - /// Text file busy. - TXTBSY = 74, - /// Cross-device link. - XDEV = 75, - /// Extension: Capabilities insufficient. - NOTCAPABLE = 76, -} - -bitflags! { - /// The state of the file descriptor subscribed to with - /// [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - #[repr(C)] - pub struct eventrwflags: u16 { - /// The peer of this socket has closed or disconnected. - const HANGUP = 0x0001; - } -} - -/// Type of a subscription to an event or its occurrence. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum eventtype { - /// The time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id) - /// has reached timestamp [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout). - CLOCK = 1, - /// Condition variable [`subscription.union.condvar.condvar`](struct.subscription_condvar.html#structfield.condvar) has - /// been woken up and [`subscription.union.condvar.lock`](struct.subscription_condvar.html#structfield.lock) has been - /// acquired for writing. - CONDVAR = 2, - /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has - /// data available for reading. This event always triggers - /// for regular files. - FD_READ = 3, - /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has - /// capacity available for writing. This event always - /// triggers for regular files. - FD_WRITE = 4, - /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for - /// reading. - LOCK_RDLOCK = 5, - /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for - /// writing. - LOCK_WRLOCK = 6, - /// The process associated with process descriptor - /// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated. - PROC_TERMINATE = 7, -} - -/// Exit code generated by a process when exiting. -pub type exitcode = u32; - -/// A file descriptor number. -/// -/// Unlike on POSIX-compliant systems, none of the file descriptor -/// numbers are reserved for a purpose (e.g., stdin, stdout, -/// stderr). Operating systems are not required to allocate new -/// file descriptors in ascending order. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct fd(pub u32); -/// Returned to the child process by [`proc_fork()`](fn.proc_fork.html). -pub const PROCESS_CHILD: fd = fd(0xffffffff); -/// Passed to [`mem_map()`](fn.mem_map.html) when creating a mapping to -/// anonymous memory. -pub const MAP_ANON_FD : fd = fd(0xffffffff); - -bitflags! { - /// File descriptor flags. - #[repr(C)] - pub struct fdflags: u16 { - /// Append mode: Data written to the file is always - /// appended to the file's end. - const APPEND = 0x0001; - /// Write according to synchronized I/O data integrity - /// completion. Only the data stored in the file is - /// synchronized. - const DSYNC = 0x0002; - /// Non-blocking mode. - const NONBLOCK = 0x0004; - /// Synchronized read I/O operations. - const RSYNC = 0x0008; - /// Write according to synchronized I/O file integrity - /// completion. In addition to synchronizing the data - /// stored in the file, the system may also synchronously - /// update the file's metadata. - const SYNC = 0x0010; - } -} - -bitflags! { - /// Which file descriptor attributes to adjust. - #[repr(C)] - pub struct fdsflags: u16 { - /// Adjust the file descriptor flags stored in - /// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags). - const FLAGS = 0x0001; - /// Restrict the rights of the file descriptor to the - /// rights stored in [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and - /// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting). - const RIGHTS = 0x0002; - } -} - -/// Relative offset within a file. -pub type filedelta = i64; - -/// Non-negative file size or length of a region within a file. -pub type filesize = u64; - -/// The type of a file descriptor or file. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum filetype { - /// The type of the file descriptor or file is unknown or - /// is different from any of the other types specified. - UNKNOWN = 0, - /// The file descriptor or file refers to a block device - /// inode. - BLOCK_DEVICE = 16, - /// The file descriptor or file refers to a character - /// device inode. - CHARACTER_DEVICE = 17, - /// The file descriptor or file refers to a directory - /// inode. - DIRECTORY = 32, - /// The file descriptor refers to a process handle. - PROCESS = 80, - /// The file descriptor or file refers to a regular file - /// inode. - REGULAR_FILE = 96, - /// The file descriptor refers to a shared memory object. - SHARED_MEMORY = 112, - /// The file descriptor or file refers to a datagram - /// socket. - SOCKET_DGRAM = 128, - /// The file descriptor or file refers to a byte-stream - /// socket. - SOCKET_STREAM = 130, - /// The file refers to a symbolic link inode. - SYMBOLIC_LINK = 144, -} - -bitflags! { - /// Which file attributes to adjust. - #[repr(C)] - pub struct fsflags: u16 { - /// Adjust the last data access timestamp to the value - /// stored in [`filestat.st_atim`](struct.filestat.html#structfield.st_atim). - const ATIM = 0x0001; - /// Adjust the last data access timestamp to the time - /// of clock [`REALTIME`](enum.clockid.html#variant.REALTIME). - const ATIM_NOW = 0x0002; - /// Adjust the last data modification timestamp to the - /// value stored in [`filestat.st_mtim`](struct.filestat.html#structfield.st_mtim). - const MTIM = 0x0004; - /// Adjust the last data modification timestamp to the - /// time of clock [`REALTIME`](enum.clockid.html#variant.REALTIME). - const MTIM_NOW = 0x0008; - /// Truncate or extend the file to the size stored in - /// [`filestat.st_size`](struct.filestat.html#structfield.st_size). - const SIZE = 0x0010; - } -} - -/// File serial number that is unique within its file system. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct inode(pub u64); - -/// Number of hard links to an inode. -pub type linkcount = u32; - -/// A userspace read-recursive readers-writer lock, similar to a -/// Linux futex or a FreeBSD umtx. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct lock(pub u32); -/// Value indicating that the lock is in its initial -/// unlocked state. -pub const LOCK_UNLOCKED : lock = lock(0x00000000); -/// Bitmask indicating that the lock is write-locked. If -/// set, the lower 30 bits of the lock contain the -/// identifier of the thread that owns the write lock. -/// Otherwise, the lower 30 bits of the lock contain the -/// number of acquired read locks. -pub const LOCK_WRLOCKED : lock = lock(0x40000000); -/// Bitmask indicating that the lock is either read locked -/// or write locked, and that one or more threads have -/// their execution suspended, waiting to acquire the -/// lock. The last owner of the lock must call the -/// kernel to unlock. -/// -/// When the lock is acquired for reading and this bit is -/// set, it means that one or more threads are attempting -/// to acquire this lock for writing. In that case, other -/// threads should only acquire additional read locks if -/// suspending execution would cause a deadlock. It is -/// preferred to suspend execution, as this prevents -/// starvation of writers. -pub const LOCK_KERNEL_MANAGED: lock = lock(0x80000000); -/// Value indicating that the lock is in an incorrect -/// state. A lock cannot be in its initial unlocked state, -/// while also managed by the kernel. -pub const LOCK_BOGUS : lock = lock(0x80000000); - -bitflags! { - /// Flags determining the method of how paths are resolved. - #[repr(C)] - pub struct lookupflags: u32 { - /// As long as the resolved path corresponds to a symbolic - /// link, it is expanded. - const SYMLINK_FOLLOW = 0x00000001; - } -} - -bitflags! { - /// Memory mapping flags. - #[repr(C)] - pub struct mflags: u8 { - /// Instead of mapping the contents of the file provided, - /// create a mapping to anonymous memory. The file - /// descriptor argument must be set to [`MAP_ANON_FD`](constant.MAP_ANON_FD.html), - /// and the offset must be set to zero. - const ANON = 0x01; - /// Require that the mapping is performed at the base - /// address provided. - const FIXED = 0x02; - /// Changes are private. - const PRIVATE = 0x04; - /// Changes are shared. - const SHARED = 0x08; - } -} - -bitflags! { - /// Memory page protection options. - /// - /// This implementation enforces the `W^X` property: Pages cannot be - /// mapped for execution while also mapped for writing. - #[repr(C)] - pub struct mprot: u8 { - /// Page can be executed. - const EXEC = 0x01; - /// Page can be written. - const WRITE = 0x02; - /// Page can be read. - const READ = 0x04; - } -} - -bitflags! { - /// Methods of synchronizing memory with physical storage. - #[repr(C)] - pub struct msflags: u8 { - /// Perform asynchronous writes. - const ASYNC = 0x01; - /// Invalidate cached data. - const INVALIDATE = 0x02; - /// Perform synchronous writes. - const SYNC = 0x04; - } -} - -/// Specifies the number of threads sleeping on a condition -/// variable that should be woken up. -pub type nthreads = u32; - -bitflags! { - /// Open flags used by [`file_open()`](fn.file_open.html). - #[repr(C)] - pub struct oflags: u16 { - /// Create file if it does not exist. - const CREAT = 0x0001; - /// Fail if not a directory. - const DIRECTORY = 0x0002; - /// Fail if file already exists. - const EXCL = 0x0004; - /// Truncate file to size 0. - const TRUNC = 0x0008; - } -} - -bitflags! { - /// Flags provided to [`sock_recv()`](fn.sock_recv.html). - #[repr(C)] - pub struct riflags: u16 { - /// Returns the message without removing it from the - /// socket's receive queue. - const PEEK = 0x0004; - /// On byte-stream sockets, block until the full amount - /// of data can be returned. - const WAITALL = 0x0010; - } -} - -bitflags! { - /// File descriptor rights, determining which actions may be - /// performed. - #[repr(C)] - pub struct rights: u64 { - /// The right to invoke [`fd_datasync()`](fn.fd_datasync.html). - /// - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to - /// invoke [`file_open()`](fn.file_open.html) with [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC). - const FD_DATASYNC = 0x0000000000000001; - /// The right to invoke [`fd_read()`](fn.fd_read.html) and [`sock_recv()`](fn.sock_recv.html). - /// - /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to - /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option - /// [`READ`](struct.mprot.html#associatedconstant.READ). - /// - /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to invoke - /// [`fd_pread()`](fn.fd_pread.html). - const FD_READ = 0x0000000000000002; - /// The right to invoke [`fd_seek()`](fn.fd_seek.html). This flag implies - /// [`FD_TELL`](struct.rights.html#associatedconstant.FD_TELL). - const FD_SEEK = 0x0000000000000004; - /// The right to invoke [`fd_stat_put()`](fn.fd_stat_put.html) with - /// [`FLAGS`](struct.fdsflags.html#associatedconstant.FLAGS). - const FD_STAT_PUT_FLAGS = 0x0000000000000008; - /// The right to invoke [`fd_sync()`](fn.fd_sync.html). - /// - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to - /// invoke [`file_open()`](fn.file_open.html) with [`RSYNC`](struct.fdflags.html#associatedconstant.RSYNC) and - /// [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC). - const FD_SYNC = 0x0000000000000010; - /// The right to invoke [`fd_seek()`](fn.fd_seek.html) in such a way that the - /// file offset remains unaltered (i.e., [`CUR`](enum.whence.html#variant.CUR) with - /// offset zero). - const FD_TELL = 0x0000000000000020; - /// The right to invoke [`fd_write()`](fn.fd_write.html) and [`sock_send()`](fn.sock_send.html). - /// - /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to - /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option - /// [`WRITE`](struct.mprot.html#associatedconstant.WRITE). - /// - /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to - /// invoke [`fd_pwrite()`](fn.fd_pwrite.html). - const FD_WRITE = 0x0000000000000040; - /// The right to invoke [`file_advise()`](fn.file_advise.html). - const FILE_ADVISE = 0x0000000000000080; - /// The right to invoke [`file_allocate()`](fn.file_allocate.html). - const FILE_ALLOCATE = 0x0000000000000100; - /// The right to invoke [`file_create()`](fn.file_create.html) with - /// [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY). - const FILE_CREATE_DIRECTORY = 0x0000000000000200; - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, the right to invoke - /// [`file_open()`](fn.file_open.html) with [`CREAT`](struct.oflags.html#associatedconstant.CREAT). - const FILE_CREATE_FILE = 0x0000000000000400; - /// The right to invoke [`file_link()`](fn.file_link.html) with the file - /// descriptor as the source directory. - const FILE_LINK_SOURCE = 0x0000000000001000; - /// The right to invoke [`file_link()`](fn.file_link.html) with the file - /// descriptor as the target directory. - const FILE_LINK_TARGET = 0x0000000000002000; - /// The right to invoke [`file_open()`](fn.file_open.html). - const FILE_OPEN = 0x0000000000004000; - /// The right to invoke [`file_readdir()`](fn.file_readdir.html). - const FILE_READDIR = 0x0000000000008000; - /// The right to invoke [`file_readlink()`](fn.file_readlink.html). - const FILE_READLINK = 0x0000000000010000; - /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file - /// descriptor as the source directory. - const FILE_RENAME_SOURCE = 0x0000000000020000; - /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file - /// descriptor as the target directory. - const FILE_RENAME_TARGET = 0x0000000000040000; - /// The right to invoke [`file_stat_fget()`](fn.file_stat_fget.html). - const FILE_STAT_FGET = 0x0000000000080000; - /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with - /// [`SIZE`](struct.fsflags.html#associatedconstant.SIZE). - /// - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to - /// invoke [`file_open()`](fn.file_open.html) with [`TRUNC`](struct.oflags.html#associatedconstant.TRUNC). - const FILE_STAT_FPUT_SIZE = 0x0000000000100000; - /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with - /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM), - /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW). - const FILE_STAT_FPUT_TIMES = 0x0000000000200000; - /// The right to invoke [`file_stat_get()`](fn.file_stat_get.html). - const FILE_STAT_GET = 0x0000000000400000; - /// The right to invoke [`file_stat_put()`](fn.file_stat_put.html) with - /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM), - /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW). - const FILE_STAT_PUT_TIMES = 0x0000000000800000; - /// The right to invoke [`file_symlink()`](fn.file_symlink.html). - const FILE_SYMLINK = 0x0000000001000000; - /// The right to invoke [`file_unlink()`](fn.file_unlink.html). - const FILE_UNLINK = 0x0000000002000000; - /// The right to invoke [`mem_map()`](fn.mem_map.html) with [`mprot`](struct.mprot.html) set to - /// zero. - const MEM_MAP = 0x0000000004000000; - /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, the right to invoke - /// [`mem_map()`](fn.mem_map.html) with [`EXEC`](struct.mprot.html#associatedconstant.EXEC). - const MEM_MAP_EXEC = 0x0000000008000000; - /// If [`FD_READ`](struct.rights.html#associatedconstant.FD_READ) is set, includes the right to - /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_READ`](enum.eventtype.html#variant.FD_READ). - /// - /// If [`FD_WRITE`](struct.rights.html#associatedconstant.FD_WRITE) is set, includes the right to - /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - const POLL_FD_READWRITE = 0x0000000010000000; - /// The right to invoke [`poll()`](fn.poll.html) to subscribe to - /// [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). - const POLL_PROC_TERMINATE = 0x0000000040000000; - /// The right to invoke [`proc_exec()`](fn.proc_exec.html). - const PROC_EXEC = 0x0000000100000000; - /// The right to invoke [`sock_shutdown()`](fn.sock_shutdown.html). - const SOCK_SHUTDOWN = 0x0000008000000000; - } -} - -bitflags! { - /// Flags returned by [`sock_recv()`](fn.sock_recv.html). - #[repr(C)] - pub struct roflags: u16 { - /// Returned by [`sock_recv()`](fn.sock_recv.html): List of file descriptors - /// has been truncated. - const FDS_TRUNCATED = 0x0001; - /// Returned by [`sock_recv()`](fn.sock_recv.html): Message data has been - /// truncated. - const DATA_TRUNCATED = 0x0008; - } -} - -/// Indicates whether an object is stored in private or shared -/// memory. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum scope { - /// The object is stored in private memory. - PRIVATE = 4, - /// The object is stored in shared memory. - SHARED = 8, -} - -bitflags! { - /// Which channels on a socket need to be shut down. - #[repr(C)] - pub struct sdflags: u8 { - /// Disables further receive operations. - const RD = 0x01; - /// Disables further send operations. - const WR = 0x02; - } -} - -bitflags! { - /// Flags provided to [`sock_send()`](fn.sock_send.html). As there are currently no flags - /// defined, it must be set to zero. - #[repr(C)] - pub struct siflags: u16 { - const DEFAULT = 0; - } -} - -/// Signal condition. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum signal { - /// Process abort signal. - /// - /// Action: Terminates the process. - ABRT = 1, - /// Alarm clock. - /// - /// Action: Terminates the process. - ALRM = 2, - /// Access to an undefined portion of a memory object. - /// - /// Action: Terminates the process. - BUS = 3, - /// Child process terminated, stopped, or continued. - /// - /// Action: Ignored. - CHLD = 4, - /// Continue executing, if stopped. - /// - /// Action: Continues executing, if stopped. - CONT = 5, - /// Erroneous arithmetic operation. - /// - /// Action: Terminates the process. - FPE = 6, - /// Hangup. - /// - /// Action: Terminates the process. - HUP = 7, - /// Illegal instruction. - /// - /// Action: Terminates the process. - ILL = 8, - /// Terminate interrupt signal. - /// - /// Action: Terminates the process. - INT = 9, - /// Kill. - /// - /// Action: Terminates the process. - KILL = 10, - /// Write on a pipe with no one to read it. - /// - /// Action: Ignored. - PIPE = 11, - /// Terminal quit signal. - /// - /// Action: Terminates the process. - QUIT = 12, - /// Invalid memory reference. - /// - /// Action: Terminates the process. - SEGV = 13, - /// Stop executing. - /// - /// Action: Stops executing. - STOP = 14, - /// Bad system call. - /// - /// Action: Terminates the process. - SYS = 15, - /// Termination signal. - /// - /// Action: Terminates the process. - TERM = 16, - /// Trace/breakpoint trap. - /// - /// Action: Terminates the process. - TRAP = 17, - /// Terminal stop signal. - /// - /// Action: Stops executing. - TSTP = 18, - /// Background process attempting read. - /// - /// Action: Stops executing. - TTIN = 19, - /// Background process attempting write. - /// - /// Action: Stops executing. - TTOU = 20, - /// High bandwidth data is available at a socket. - /// - /// Action: Ignored. - URG = 21, - /// User-defined signal 1. - /// - /// Action: Terminates the process. - USR1 = 22, - /// User-defined signal 2. - /// - /// Action: Terminates the process. - USR2 = 23, - /// Virtual timer expired. - /// - /// Action: Terminates the process. - VTALRM = 24, - /// CPU time limit exceeded. - /// - /// Action: Terminates the process. - XCPU = 25, - /// File size limit exceeded. - /// - /// Action: Terminates the process. - XFSZ = 26, -} - -bitflags! { - /// Flags determining how the timestamp provided in - /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) should be interpreted. - #[repr(C)] - pub struct subclockflags: u16 { - /// If set, treat the timestamp provided in - /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) as an absolute timestamp - /// of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id). - /// - /// If clear, treat the timestamp provided in - /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) relative to the current - /// time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id). - const ABSTIME = 0x0001; - } -} - -bitflags! { - /// Flags influencing the method of polling for read or writing on - /// a file descriptor. - #[repr(C)] - pub struct subrwflags: u16 { - /// Deprecated. Must be set by callers and ignored by - /// implementations. - const POLL = 0x0001; - } -} - -/// Unique system-local identifier of a thread. This identifier is -/// only valid during the lifetime of the thread. -/// -/// Threads must be aware of their thread identifier, as it is -/// written it into locks when acquiring them for writing. It is -/// not advised to use these identifiers for any other purpose. -/// -/// As the thread identifier is also stored in [`lock`](struct.lock.html) when -/// [`LOCK_WRLOCKED`](constant.LOCK_WRLOCKED.html) is set, the top two bits of the thread -/// must always be set to zero. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct tid(pub u32); - -/// Timestamp in nanoseconds. -pub type timestamp = u64; - -bitflags! { - /// Specifies whether files are unlinked or directories are - /// removed. - #[repr(C)] - pub struct ulflags: u8 { - /// If set, removes a directory. Otherwise, unlinks any - /// non-directory file. - const REMOVEDIR = 0x01; - } -} - -/// User-provided value that can be attached to objects that is -/// retained when extracted from the kernel. -pub type userdata = u64; - -/// Relative to which position the offset of the file descriptor -/// should be set. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum whence { - /// Seek relative to current position. - CUR = 1, - /// Seek relative to end-of-file. - END = 2, - /// Seek relative to start-of-file. - SET = 3, -} - -/// Auxiliary vector entry. -/// -/// The auxiliary vector is a list of key-value pairs that is -/// provided to the process on startup. Unlike structures, it is -/// extensible, as it is possible to add new records later on. -/// The auxiliary vector is always terminated by an entry having -/// type [`NULL`](enum.auxtype.html#variant.NULL). -/// -/// The auxiliary vector is part of the x86-64 ABI, but is used by -/// this environment on all architectures. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct auxv { - /// The type of the auxiliary vector entry. - pub a_type: auxtype, - pub union: auxv_union -} -/// A union inside `auxv`. -#[repr(C)] -#[derive(Copy, Clone)] -pub union auxv_union { - /// Used when `a_type` is [`ARGDATALEN`](enum.auxtype.html#variant.ARGDATALEN), [`CANARYLEN`](enum.auxtype.html#variant.CANARYLEN), [`NCPUS`](enum.auxtype.html#variant.NCPUS), [`PAGESZ`](enum.auxtype.html#variant.PAGESZ), [`PHNUM`](enum.auxtype.html#variant.PHNUM), or [`TID`](enum.auxtype.html#variant.TID). -/// A numerical value. - pub a_val: usize, - /// Used when `a_type` is [`ARGDATA`](enum.auxtype.html#variant.ARGDATA), [`BASE`](enum.auxtype.html#variant.BASE), [`CANARY`](enum.auxtype.html#variant.CANARY), [`PHDR`](enum.auxtype.html#variant.PHDR), [`PID`](enum.auxtype.html#variant.PID), or [`SYSINFO_EHDR`](enum.auxtype.html#variant.SYSINFO_EHDR). -/// A pointer value. - pub a_ptr: *mut (), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn auxv_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: auxv = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.a_type as *const _ as usize - base, 0); - assert_eq!(&obj.union.a_val as *const _ as usize - base, 4); - assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 4); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn auxv_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 16); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: auxv = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.a_type as *const _ as usize - base, 0); - assert_eq!(&obj.union.a_val as *const _ as usize - base, 8); - assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 8); - } -} - -/// A region of memory for scatter/gather writes. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct ciovec { - /// The address and length of the buffer to be written. - pub buf: (*const (), usize), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn ciovec_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: ciovec = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 4); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn ciovec_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 16); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: ciovec = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 8); - } -} - -/// A directory entry. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct dirent { - /// The offset of the next directory entry stored in this - /// directory. - pub d_next: dircookie, - /// The serial number of the file referred to by this - /// directory entry. - pub d_ino: inode, - /// The length of the name of the directory entry. - pub d_namlen: u32, - /// The type of the file referred to by this directory - /// entry. - pub d_type: filetype, -} -#[test] -fn dirent_layout_test() { - assert_eq!(::core::mem::size_of::(), 24); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: dirent = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.d_next as *const _ as usize - base, 0); - assert_eq!(&obj.d_ino as *const _ as usize - base, 8); - assert_eq!(&obj.d_namlen as *const _ as usize - base, 16); - assert_eq!(&obj.d_type as *const _ as usize - base, 20); - } -} - -/// An event that occurred. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct event { - /// User-provided value that got attached to - /// [`subscription.userdata`](struct.subscription.html#structfield.userdata). - pub userdata: userdata, - /// If non-zero, an error that occurred while processing - /// the subscription request. - pub error: errno, - /// The type of the event that occurred. - pub type_: eventtype, - pub union: event_union -} -/// A union inside `event`. -#[repr(C)] -#[derive(Copy, Clone)] -pub union event_union { - /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - pub fd_readwrite: event_fd_readwrite, - /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). - pub proc_terminate: event_proc_terminate, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct event_fd_readwrite { - /// The number of bytes available - /// for reading or writing. - pub nbytes: filesize, - /// Obsolete. - pub unused: [u8; 4], - /// The state of the file - /// descriptor. - pub flags: eventrwflags, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct event_proc_terminate { - /// Obsolete. - pub unused: [u8; 4], - /// If zero, the process has - /// exited. - /// Otherwise, the signal - /// condition causing it to - /// terminated. - pub signal: signal, - /// If exited, the exit code of - /// the process. - pub exitcode: exitcode, -} -#[test] -fn event_layout_test() { - assert_eq!(::core::mem::size_of::(), 32); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: event = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.userdata as *const _ as usize - base, 0); - assert_eq!(&obj.error as *const _ as usize - base, 8); - assert_eq!(&obj.type_ as *const _ as usize - base, 10); - assert_eq!(&obj.union.fd_readwrite.nbytes as *const _ as usize - base, 16); - assert_eq!(&obj.union.fd_readwrite.unused as *const _ as usize - base, 24); - assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 28); - assert_eq!(&obj.union.proc_terminate.unused as *const _ as usize - base, 16); - assert_eq!(&obj.union.proc_terminate.signal as *const _ as usize - base, 20); - assert_eq!(&obj.union.proc_terminate.exitcode as *const _ as usize - base, 24); - } -} - -/// File descriptor attributes. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct fdstat { - /// File type. - pub fs_filetype: filetype, - /// File descriptor flags. - pub fs_flags: fdflags, - /// Rights that apply to this file descriptor. - pub fs_rights_base: rights, - /// Maximum set of rights that can be installed on new - /// file descriptors that are created through this file - /// descriptor, e.g., through [`file_open()`](fn.file_open.html). - pub fs_rights_inheriting: rights, -} -#[test] -fn fdstat_layout_test() { - assert_eq!(::core::mem::size_of::(), 24); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: fdstat = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.fs_filetype as *const _ as usize - base, 0); - assert_eq!(&obj.fs_flags as *const _ as usize - base, 2); - assert_eq!(&obj.fs_rights_base as *const _ as usize - base, 8); - assert_eq!(&obj.fs_rights_inheriting as *const _ as usize - base, 16); - } -} - -/// File attributes. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct filestat { - /// Device ID of device containing the file. - pub st_dev: device, - /// File serial number. - pub st_ino: inode, - /// File type. - pub st_filetype: filetype, - /// Number of hard links to the file. - pub st_nlink: linkcount, - /// For regular files, the file size in bytes. For - /// symbolic links, the length in bytes of the pathname - /// contained in the symbolic link. - pub st_size: filesize, - /// Last data access timestamp. - pub st_atim: timestamp, - /// Last data modification timestamp. - pub st_mtim: timestamp, - /// Last file status change timestamp. - pub st_ctim: timestamp, -} -#[test] -fn filestat_layout_test() { - assert_eq!(::core::mem::size_of::(), 56); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: filestat = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.st_dev as *const _ as usize - base, 0); - assert_eq!(&obj.st_ino as *const _ as usize - base, 8); - assert_eq!(&obj.st_filetype as *const _ as usize - base, 16); - assert_eq!(&obj.st_nlink as *const _ as usize - base, 20); - assert_eq!(&obj.st_size as *const _ as usize - base, 24); - assert_eq!(&obj.st_atim as *const _ as usize - base, 32); - assert_eq!(&obj.st_mtim as *const _ as usize - base, 40); - assert_eq!(&obj.st_ctim as *const _ as usize - base, 48); - } -} - -/// A region of memory for scatter/gather reads. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct iovec { - /// The address and length of the buffer to be filled. - pub buf: (*mut (), usize), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn iovec_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: iovec = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 4); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn iovec_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 16); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: iovec = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 8); - } -} - -/// Path lookup properties. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct lookup { - /// The working directory at which the resolution of the - /// path starts. - pub fd: fd, - /// Flags determining the method of how the path is - /// resolved. - pub flags: lookupflags, -} -#[test] -fn lookup_layout_test() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: lookup = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.fd as *const _ as usize - base, 0); - assert_eq!(&obj.flags as *const _ as usize - base, 4); - } -} - -/// Entry point for a process (`_start`). -/// -/// **auxv**: -/// The auxiliary vector. See [`auxv`](struct.auxv.html). -pub type processentry = unsafe extern "C" fn( - auxv: *const auxv, -) -> (); - -/// Arguments of [`sock_recv()`](fn.sock_recv.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct recv_in { - /// List of scatter/gather vectors where message data - /// should be stored. - pub ri_data: (*const iovec, usize), - /// Buffer where numbers of incoming file descriptors - /// should be stored. - pub ri_fds: (*mut fd, usize), - /// Message flags. - pub ri_flags: riflags, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn recv_in_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 20); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: recv_in = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 4); - assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 8); - assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 12); - assert_eq!(&obj.ri_flags as *const _ as usize - base, 16); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn recv_in_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 40); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: recv_in = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 8); - assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 16); - assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 24); - assert_eq!(&obj.ri_flags as *const _ as usize - base, 32); - } -} - -/// Results of [`sock_recv()`](fn.sock_recv.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct recv_out { - /// Number of bytes stored in [`recv_in.ri_data`](struct.recv_in.html#structfield.ri_data). - pub ro_datalen: usize, - /// Number of file descriptors stored in [`recv_in.ri_fds`](struct.recv_in.html#structfield.ri_fds). - pub ro_fdslen: usize, - /// Fields that were used by previous implementations. - pub ro_unused: [u8; 40], - /// Message flags. - pub ro_flags: roflags, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn recv_out_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 52); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: recv_out = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0); - assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 4); - assert_eq!(&obj.ro_unused as *const _ as usize - base, 8); - assert_eq!(&obj.ro_flags as *const _ as usize - base, 48); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn recv_out_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 64); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: recv_out = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0); - assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 8); - assert_eq!(&obj.ro_unused as *const _ as usize - base, 16); - assert_eq!(&obj.ro_flags as *const _ as usize - base, 56); - } -} - -/// Arguments of [`sock_send()`](fn.sock_send.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct send_in { - /// List of scatter/gather vectors where message data - /// should be retrieved. - pub si_data: (*const ciovec, usize), - /// File descriptors that need to be attached to the - /// message. - pub si_fds: (*const fd, usize), - /// Message flags. - pub si_flags: siflags, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn send_in_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 20); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: send_in = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.si_data.1 as *const _ as usize - base, 4); - assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 8); - assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 12); - assert_eq!(&obj.si_flags as *const _ as usize - base, 16); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn send_in_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 40); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: send_in = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.si_data.1 as *const _ as usize - base, 8); - assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 16); - assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 24); - assert_eq!(&obj.si_flags as *const _ as usize - base, 32); - } -} - -/// Results of [`sock_send()`](fn.sock_send.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct send_out { - /// Number of bytes transmitted. - pub so_datalen: usize, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn send_out_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 4); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: send_out = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.so_datalen as *const _ as usize - base, 0); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn send_out_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: send_out = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.so_datalen as *const _ as usize - base, 0); - } -} - -/// Subscription to an event. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription { - /// User-provided value that is attached to the - /// subscription in the kernel and returned through - /// [`event.userdata`](struct.event.html#structfield.userdata). - pub userdata: userdata, - /// Used by previous implementations. Ignored. - pub unused: u16, - /// The type of the event to which to subscribe. - /// - /// Currently, [`CONDVAR`](enum.eventtype.html#variant.CONDVAR), - /// [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK), and [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK) - /// must be provided as the first subscription and may - /// only be followed by up to one other subscription, - /// having type [`CLOCK`](enum.eventtype.html#variant.CLOCK). - pub type_: eventtype, - pub union: subscription_union -} -/// A union inside `subscription`. -#[repr(C)] -#[derive(Copy, Clone)] -pub union subscription_union { - /// Used when `type_` is [`CLOCK`](enum.eventtype.html#variant.CLOCK). - pub clock: subscription_clock, - /// Used when `type_` is [`CONDVAR`](enum.eventtype.html#variant.CONDVAR). - pub condvar: subscription_condvar, - /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - pub fd_readwrite: subscription_fd_readwrite, - /// Used when `type_` is [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK) or [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK). - pub lock: subscription_lock, - /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). - pub proc_terminate: subscription_proc_terminate, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_clock { - /// The user-defined unique - /// identifier of the clock. - pub identifier: userdata, - /// The clock against which the - /// timestamp should be compared. - pub clock_id: clockid, - /// The absolute or relative - /// timestamp. - pub timeout: timestamp, - /// The amount of time that the - /// kernel may wait additionally - /// to coalesce with other events. - pub precision: timestamp, - /// Flags specifying whether the - /// timeout is absolute or - /// relative. - pub flags: subclockflags, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_condvar { - /// The condition variable on - /// which to wait to be woken up. - pub condvar: *mut condvar, - /// The lock that will be - /// released while waiting. - /// - /// The lock will be reacquired - /// for writing when the condition - /// variable triggers. - pub lock: *mut lock, - /// Whether the condition variable - /// is stored in private or shared - /// memory. - pub condvar_scope: scope, - /// Whether the lock is stored in - /// private or shared memory. - pub lock_scope: scope, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_fd_readwrite { - /// The file descriptor on which - /// to wait for it to become ready - /// for reading or writing. - pub fd: fd, - /// Under which conditions to - /// trigger. - pub flags: subrwflags, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_lock { - /// The lock that will be acquired - /// for reading or writing. - pub lock: *mut lock, - /// Whether the lock is stored in - /// private or shared memory. - pub lock_scope: scope, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_proc_terminate { - /// The process descriptor on - /// which to wait for process - /// termination. - pub fd: fd, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn subscription_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 56); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: subscription = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.userdata as *const _ as usize - base, 0); - assert_eq!(&obj.unused as *const _ as usize - base, 8); - assert_eq!(&obj.type_ as *const _ as usize - base, 10); - assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16); - assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24); - assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32); - assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40); - assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48); - assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16); - assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 20); - assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 24); - assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 25); - assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16); - assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20); - assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16); - assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 20); - assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn subscription_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 56); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: subscription = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.userdata as *const _ as usize - base, 0); - assert_eq!(&obj.unused as *const _ as usize - base, 8); - assert_eq!(&obj.type_ as *const _ as usize - base, 10); - assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16); - assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24); - assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32); - assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40); - assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48); - assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16); - assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 24); - assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 32); - assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 33); - assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16); - assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20); - assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16); - assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 24); - assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16); - } -} - -/// The Thread Control Block (TCB). -/// -/// After a thread begins execution (at program startup or when -/// created through [`thread_create()`](fn.thread_create.html)), the CPU's registers -/// controlling Thread-Local Storage (TLS) will already be -/// initialized. They will point to an area only containing the -/// TCB. -/// -/// If the thread needs space for storing thread-specific -/// variables, the thread may allocate a larger area and adjust -/// the CPU's registers to point to that area instead. However, it -/// does need to make sure that the TCB is copied over to the new -/// TLS area. -/// -/// The purpose of the TCB is that it allows light-weight -/// emulators to store information related to individual threads. -/// For example, it may be used to store a copy of the CPU -/// registers prior emulation, so that TLS for the host system -/// can be restored if needed. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct tcb { - /// Pointer that may be freely assigned by the system. Its - /// value cannot be interpreted by the application. - pub parent: *mut (), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn tcb_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 4); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: tcb = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.parent as *const _ as usize - base, 0); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn tcb_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: tcb = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.parent as *const _ as usize - base, 0); - } -} - -/// Entry point for additionally created threads. -/// -/// **tid**: -/// Thread ID of the current thread. -/// -/// **aux**: -/// Copy of the value stored in -/// [`threadattr.argument`](struct.threadattr.html#structfield.argument). -pub type threadentry = unsafe extern "C" fn( - tid: tid, - aux: *mut (), -) -> (); - -/// Attributes for thread creation. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct threadattr { - /// Initial program counter value. - pub entry_point: threadentry, - /// Region allocated to serve as stack space. - pub stack: (*mut (), usize), - /// Argument to be forwarded to the entry point function. - pub argument: *mut (), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn threadattr_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 16); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: threadattr = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.entry_point as *const _ as usize - base, 0); - assert_eq!(&obj.stack.0 as *const _ as usize - base, 4); - assert_eq!(&obj.stack.1 as *const _ as usize - base, 8); - assert_eq!(&obj.argument as *const _ as usize - base, 12); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn threadattr_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 32); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: threadattr = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.entry_point as *const _ as usize - base, 0); - assert_eq!(&obj.stack.0 as *const _ as usize - base, 8); - assert_eq!(&obj.stack.1 as *const _ as usize - base, 16); - assert_eq!(&obj.argument as *const _ as usize - base, 24); - } -} - -/// The table with pointers to all syscall implementations. -#[allow(improper_ctypes)] -extern "C" { - fn cloudabi_sys_clock_res_get(_: clockid, _: *mut timestamp) -> errno; - fn cloudabi_sys_clock_time_get(_: clockid, _: timestamp, _: *mut timestamp) -> errno; - fn cloudabi_sys_condvar_signal(_: *mut condvar, _: scope, _: nthreads) -> errno; - fn cloudabi_sys_fd_close(_: fd) -> errno; - fn cloudabi_sys_fd_create1(_: filetype, _: *mut fd) -> errno; - fn cloudabi_sys_fd_create2(_: filetype, _: *mut fd, _: *mut fd) -> errno; - fn cloudabi_sys_fd_datasync(_: fd) -> errno; - fn cloudabi_sys_fd_dup(_: fd, _: *mut fd) -> errno; - fn cloudabi_sys_fd_pread(_: fd, _: *const iovec, _: usize, _: filesize, _: *mut usize) -> errno; - fn cloudabi_sys_fd_pwrite(_: fd, _: *const ciovec, _: usize, _: filesize, _: *mut usize) -> errno; - fn cloudabi_sys_fd_read(_: fd, _: *const iovec, _: usize, _: *mut usize) -> errno; - fn cloudabi_sys_fd_replace(_: fd, _: fd) -> errno; - fn cloudabi_sys_fd_seek(_: fd, _: filedelta, _: whence, _: *mut filesize) -> errno; - fn cloudabi_sys_fd_stat_get(_: fd, _: *mut fdstat) -> errno; - fn cloudabi_sys_fd_stat_put(_: fd, _: *const fdstat, _: fdsflags) -> errno; - fn cloudabi_sys_fd_sync(_: fd) -> errno; - fn cloudabi_sys_fd_write(_: fd, _: *const ciovec, _: usize, _: *mut usize) -> errno; - fn cloudabi_sys_file_advise(_: fd, _: filesize, _: filesize, _: advice) -> errno; - fn cloudabi_sys_file_allocate(_: fd, _: filesize, _: filesize) -> errno; - fn cloudabi_sys_file_create(_: fd, _: *const u8, _: usize, _: filetype) -> errno; - fn cloudabi_sys_file_link(_: lookup, _: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno; - fn cloudabi_sys_file_open(_: lookup, _: *const u8, _: usize, _: oflags, _: *const fdstat, _: *mut fd) -> errno; - fn cloudabi_sys_file_readdir(_: fd, _: *mut (), _: usize, _: dircookie, _: *mut usize) -> errno; - fn cloudabi_sys_file_readlink(_: fd, _: *const u8, _: usize, _: *mut u8, _: usize, _: *mut usize) -> errno; - fn cloudabi_sys_file_rename(_: fd, _: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno; - fn cloudabi_sys_file_stat_fget(_: fd, _: *mut filestat) -> errno; - fn cloudabi_sys_file_stat_fput(_: fd, _: *const filestat, _: fsflags) -> errno; - fn cloudabi_sys_file_stat_get(_: lookup, _: *const u8, _: usize, _: *mut filestat) -> errno; - fn cloudabi_sys_file_stat_put(_: lookup, _: *const u8, _: usize, _: *const filestat, _: fsflags) -> errno; - fn cloudabi_sys_file_symlink(_: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno; - fn cloudabi_sys_file_unlink(_: fd, _: *const u8, _: usize, _: ulflags) -> errno; - fn cloudabi_sys_lock_unlock(_: *mut lock, _: scope) -> errno; - fn cloudabi_sys_mem_advise(_: *mut (), _: usize, _: advice) -> errno; - fn cloudabi_sys_mem_map(_: *mut (), _: usize, _: mprot, _: mflags, _: fd, _: filesize, _: *mut *mut ()) -> errno; - fn cloudabi_sys_mem_protect(_: *mut (), _: usize, _: mprot) -> errno; - fn cloudabi_sys_mem_sync(_: *mut (), _: usize, _: msflags) -> errno; - fn cloudabi_sys_mem_unmap(_: *mut (), _: usize) -> errno; - fn cloudabi_sys_poll(_: *const subscription, _: *mut event, _: usize, _: *mut usize) -> errno; - fn cloudabi_sys_proc_exec(_: fd, _: *const (), _: usize, _: *const fd, _: usize) -> errno; - fn cloudabi_sys_proc_exit(_: exitcode) -> !; - fn cloudabi_sys_proc_fork(_: *mut fd, _: *mut tid) -> errno; - fn cloudabi_sys_proc_raise(_: signal) -> errno; - fn cloudabi_sys_random_get(_: *mut (), _: usize) -> errno; - fn cloudabi_sys_sock_recv(_: fd, _: *const recv_in, _: *mut recv_out) -> errno; - fn cloudabi_sys_sock_send(_: fd, _: *const send_in, _: *mut send_out) -> errno; - fn cloudabi_sys_sock_shutdown(_: fd, _: sdflags) -> errno; - fn cloudabi_sys_thread_create(_: *mut threadattr, _: *mut tid) -> errno; - fn cloudabi_sys_thread_exit(_: *mut lock, _: scope) -> !; - fn cloudabi_sys_thread_yield() -> errno; -} - -/// Obtains the resolution of a clock. -/// -/// ## Parameters -/// -/// **clock_id**: -/// The clock for which the resolution needs to be -/// returned. -/// -/// **resolution**: -/// The resolution of the clock. -#[inline] -pub unsafe fn clock_res_get(clock_id_: clockid, resolution_: &mut timestamp) -> errno { - cloudabi_sys_clock_res_get(clock_id_, resolution_) -} - -/// Obtains the time value of a clock. -/// -/// ## Parameters -/// -/// **clock_id**: -/// The clock for which the time needs to be -/// returned. -/// -/// **precision**: -/// The maximum lag (exclusive) that the returned -/// time value may have, compared to its actual -/// value. -/// -/// **time**: -/// The time value of the clock. -#[inline] -pub unsafe fn clock_time_get(clock_id_: clockid, precision_: timestamp, time_: &mut timestamp) -> errno { - cloudabi_sys_clock_time_get(clock_id_, precision_, time_) -} - -/// Wakes up threads waiting on a userspace condition variable. -/// -/// If an invocation of this system call causes all waiting -/// threads to be woken up, the value of the condition variable -/// is set to [`CONDVAR_HAS_NO_WAITERS`](constant.CONDVAR_HAS_NO_WAITERS.html). As long as the condition -/// variable is set to this value, it is not needed to invoke this -/// system call. -/// -/// ## Parameters -/// -/// **condvar**: -/// The userspace condition variable that has -/// waiting threads. -/// -/// **scope**: -/// Whether the condition variable is stored in -/// private or shared memory. -/// -/// **nwaiters**: -/// The number of threads that need to be woken -/// up. If it exceeds the number of waiting -/// threads, all threads are woken up. -#[inline] -pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: nthreads) -> errno { - cloudabi_sys_condvar_signal(condvar_, scope_, nwaiters_) -} - -/// Closes a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor that needs to be closed. -#[inline] -pub unsafe fn fd_close(fd_: fd) -> errno { - cloudabi_sys_fd_close(fd_) -} - -/// Creates a file descriptor. -/// -/// ## Parameters -/// -/// **type**: -/// Possible values: -/// -/// - [`SHARED_MEMORY`](enum.filetype.html#variant.SHARED_MEMORY): -/// Creates an anonymous shared memory -/// object. -/// -/// **fd**: -/// The file descriptor that has been created. -#[inline] -pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno { - cloudabi_sys_fd_create1(type_, fd_) -} - -/// Creates a pair of file descriptors. -/// -/// ## Parameters -/// -/// **type**: -/// Possible values: -/// -/// - [`SOCKET_DGRAM`](enum.filetype.html#variant.SOCKET_DGRAM): -/// Creates a UNIX datagram socket pair. -/// - [`SOCKET_STREAM`](enum.filetype.html#variant.SOCKET_STREAM): -/// Creates a UNIX byte-stream socket -/// pair. -/// -/// **fd1**: -/// The first file descriptor of the pair. -/// -/// **fd2**: -/// The second file descriptor of the pair. -#[inline] -pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno { - cloudabi_sys_fd_create2(type_, fd1_, fd2_) -} - -/// Synchronizes the data of a file to disk. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor of the file whose data -/// needs to be synchronized to disk. -#[inline] -pub unsafe fn fd_datasync(fd_: fd) -> errno { - cloudabi_sys_fd_datasync(fd_) -} - -/// Duplicates a file descriptor. -/// -/// ## Parameters -/// -/// **from**: -/// The file descriptor that needs to be -/// duplicated. -/// -/// **fd**: -/// The new file descriptor. -#[inline] -pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno { - cloudabi_sys_fd_dup(from_, fd_) -} - -/// Reads from a file descriptor, without using and updating the -/// file descriptor's offset. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor from which data should be -/// read. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be stored. -/// -/// **offset**: -/// The offset within the file at which reading -/// should start. -/// -/// **nread**: -/// The number of bytes read. -#[inline] -pub unsafe fn fd_pread(fd_: fd, iovs_: &[iovec], offset_: filesize, nread_: &mut usize) -> errno { - cloudabi_sys_fd_pread(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nread_) -} - -/// Writes to a file descriptor, without using and updating the -/// file descriptor's offset. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor to which data should be -/// written. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be retrieved. -/// -/// **offset**: -/// The offset within the file at which writing -/// should start. -/// -/// **nwritten**: -/// The number of bytes written. -#[inline] -pub unsafe fn fd_pwrite(fd_: fd, iovs_: &[ciovec], offset_: filesize, nwritten_: &mut usize) -> errno { - cloudabi_sys_fd_pwrite(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nwritten_) -} - -/// Reads from a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor from which data should be -/// read. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be stored. -/// -/// **nread**: -/// The number of bytes read. -#[inline] -pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno { - cloudabi_sys_fd_read(fd_, iovs_.as_ptr(), iovs_.len(), nread_) -} - -/// Atomically replaces a file descriptor by a copy of another -/// file descriptor. -/// -/// Due to the strong focus on thread safety, this environment -/// does not provide a mechanism to duplicate a file descriptor to -/// an arbitrary number, like dup2(). This would be prone to race -/// conditions, as an actual file descriptor with the same number -/// could be allocated by a different thread at the same time. -/// -/// This system call provides a way to atomically replace file -/// descriptors, which would disappear if dup2() were to be -/// removed entirely. -/// -/// ## Parameters -/// -/// **from**: -/// The file descriptor that needs to be copied. -/// -/// **to**: -/// The file descriptor that needs to be -/// overwritten. -#[inline] -pub unsafe fn fd_replace(from_: fd, to_: fd) -> errno { - cloudabi_sys_fd_replace(from_, to_) -} - -/// Moves the offset of the file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose offset has to be -/// moved. -/// -/// **offset**: -/// The number of bytes to move. -/// -/// **whence**: -/// Relative to which position the move should -/// take place. -/// -/// **newoffset**: -/// The new offset of the file descriptor, -/// relative to the start of the file. -#[inline] -pub unsafe fn fd_seek(fd_: fd, offset_: filedelta, whence_: whence, newoffset_: &mut filesize) -> errno { - cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_) -} - -/// Gets attributes of a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be obtained. -/// -/// **buf**: -/// The buffer where the file descriptor's -/// attributes are stored. -#[inline] -pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno { - cloudabi_sys_fd_stat_get(fd_, buf_) -} - -/// Adjusts attributes of a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be adjusted. -/// -/// **buf**: -/// The desired values of the file descriptor -/// attributes that are adjusted. -/// -/// **flags**: -/// A bitmask indicating which attributes have to -/// be adjusted. -#[inline] -pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> errno { - cloudabi_sys_fd_stat_put(fd_, buf_, flags_) -} - -/// Synchronizes the data and metadata of a file to disk. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor of the file whose data -/// and metadata needs to be synchronized to disk. -#[inline] -pub unsafe fn fd_sync(fd_: fd) -> errno { - cloudabi_sys_fd_sync(fd_) -} - -/// Writes to a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor to which data should be -/// written. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be retrieved. -/// -/// **nwritten**: -/// The number of bytes written. -#[inline] -pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errno { - cloudabi_sys_fd_write(fd_, iovs_.as_ptr(), iovs_.len(), nwritten_) -} - -/// Provides file advisory information on a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor for which to provide file -/// advisory information. -/// -/// **offset**: -/// The offset within the file to which the -/// advisory applies. -/// -/// **len**: -/// The length of the region to which the advisory -/// applies. -/// -/// **advice**: -/// The advice. -#[inline] -pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: advice) -> errno { - cloudabi_sys_file_advise(fd_, offset_, len_, advice_) -} - -/// Forces the allocation of space in a file. -/// -/// ## Parameters -/// -/// **fd**: -/// The file in which the space should be -/// allocated. -/// -/// **offset**: -/// The offset at which the allocation should -/// start. -/// -/// **len**: -/// The length of the area that is allocated. -#[inline] -pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno { - cloudabi_sys_file_allocate(fd_, offset_, len_) -} - -/// Creates a file of a specified type. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the file to be created starts. -/// -/// **path**: -/// The path at which the file should be created. -/// -/// **type**: -/// Possible values: -/// -/// - [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY): -/// Creates a directory. -#[inline] -pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno { - cloudabi_sys_file_create(fd_, path_.as_ptr(), path_.len(), type_) -} - -/// Creates a hard link. -/// -/// ## Parameters -/// -/// **fd1**: -/// The working directory at which the resolution -/// of the source path starts. -/// -/// **path1**: -/// The source path of the file that should be -/// hard linked. -/// -/// **fd2**: -/// The working directory at which the resolution -/// of the destination path starts. -/// -/// **path2**: -/// The destination path at which the hard link -/// should be created. -#[inline] -pub unsafe fn file_link(fd1_: lookup, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno { - cloudabi_sys_file_link(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len()) -} - -/// Opens a file. -/// -/// ## Parameters -/// -/// **dirfd**: -/// The working directory at which the resolution -/// of the file to be opened starts. -/// -/// **path**: -/// The path of the file that should be opened. -/// -/// **oflags**: -/// The method at which the file should be opened. -/// -/// **fds**: -/// [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and -/// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting) specify the -/// initial rights of the newly created file -/// descriptor. The operating system is allowed to -/// return a file descriptor with fewer rights -/// than specified, if and only if those rights do -/// not apply to the type of file being opened. -/// -/// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags) specifies the initial flags -/// of the file descriptor. -/// -/// [`fdstat.fs_filetype`](struct.fdstat.html#structfield.fs_filetype) is ignored. -/// -/// **fd**: -/// The file descriptor of the file that has been -/// opened. -#[inline] -pub unsafe fn file_open(dirfd_: lookup, path_: &[u8], oflags_: oflags, fds_: *const fdstat, fd_: &mut fd) -> errno { - cloudabi_sys_file_open(dirfd_, path_.as_ptr(), path_.len(), oflags_, fds_, fd_) -} - -/// Reads directory entries from a directory. -/// -/// When successful, the contents of the output buffer consist of -/// a sequence of directory entries. Each directory entry consists -/// of a [`dirent`](struct.dirent.html) object, followed by [`dirent.d_namlen`](struct.dirent.html#structfield.d_namlen) bytes -/// holding the name of the directory entry. -/// -/// This system call fills the output buffer as much as possible, -/// potentially truncating the last directory entry. This allows -/// the caller to grow its read buffer size in case it's too small -/// to fit a single large directory entry, or skip the oversized -/// directory entry. -/// -/// ## Parameters -/// -/// **fd**: -/// The directory from which to read the directory -/// entries. -/// -/// **buf**: -/// The buffer where directory entries are stored. -/// -/// **cookie**: -/// The location within the directory to start -/// reading. -/// -/// **bufused**: -/// The number of bytes stored in the read buffer. -/// If less than the size of the read buffer, the -/// end of the directory has been reached. -#[inline] -pub unsafe fn file_readdir(fd_: fd, buf_: &mut [u8], cookie_: dircookie, bufused_: &mut usize) -> errno { - cloudabi_sys_file_readdir(fd_, buf_.as_mut_ptr() as *mut (), buf_.len(), cookie_, bufused_) -} - -/// Reads the contents of a symbolic link. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path of the symbolic starts. -/// -/// **path**: -/// The path of the symbolic link whose contents -/// should be read. -/// -/// **buf**: -/// The buffer where the contents of the symbolic -/// link should be stored. -/// -/// **bufused**: -/// The number of bytes placed in the buffer. -#[inline] -pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &mut usize) -> errno { - cloudabi_sys_file_readlink(fd_, path_.as_ptr(), path_.len(), buf_.as_mut_ptr(), buf_.len(), bufused_) -} - -/// Renames a file. -/// -/// ## Parameters -/// -/// **fd1**: -/// The working directory at which the resolution -/// of the source path starts. -/// -/// **path1**: -/// The source path of the file that should be -/// renamed. -/// -/// **fd2**: -/// The working directory at which the resolution -/// of the destination path starts. -/// -/// **path2**: -/// The destination path to which the file should -/// be renamed. -#[inline] -pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno { - cloudabi_sys_file_rename(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len()) -} - -/// Gets attributes of a file by file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be obtained. -/// -/// **buf**: -/// The buffer where the file's attributes are -/// stored. -#[inline] -pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno { - cloudabi_sys_file_stat_fget(fd_, buf_) -} - -/// Adjusts attributes of a file by file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be adjusted. -/// -/// **buf**: -/// The desired values of the file attributes that -/// are adjusted. -/// -/// **flags**: -/// A bitmask indicating which attributes have to -/// be adjusted. -#[inline] -pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) -> errno { - cloudabi_sys_file_stat_fput(fd_, buf_, flags_) -} - -/// Gets attributes of a file by path. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path whose attributes have to be -/// obtained starts. -/// -/// **path**: -/// The path of the file whose attributes have to -/// be obtained. -/// -/// **buf**: -/// The buffer where the file's attributes are -/// stored. -#[inline] -pub unsafe fn file_stat_get(fd_: lookup, path_: &[u8], buf_: *mut filestat) -> errno { - cloudabi_sys_file_stat_get(fd_, path_.as_ptr(), path_.len(), buf_) -} - -/// Adjusts attributes of a file by path. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path whose attributes have to be -/// adjusted starts. -/// -/// **path**: -/// The path of the file whose attributes have to -/// be adjusted. -/// -/// **buf**: -/// The desired values of the file attributes that -/// are adjusted. -/// -/// **flags**: -/// A bitmask indicating which attributes have to -/// be adjusted. -#[inline] -pub unsafe fn file_stat_put(fd_: lookup, path_: &[u8], buf_: *const filestat, flags_: fsflags) -> errno { - cloudabi_sys_file_stat_put(fd_, path_.as_ptr(), path_.len(), buf_, flags_) -} - -/// Creates a symbolic link. -/// -/// ## Parameters -/// -/// **path1**: -/// The contents of the symbolic link. -/// -/// **fd**: -/// The working directory at which the resolution -/// of the destination path starts. -/// -/// **path2**: -/// The destination path at which the symbolic -/// link should be created. -#[inline] -pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno { - cloudabi_sys_file_symlink(path1_.as_ptr(), path1_.len(), fd_, path2_.as_ptr(), path2_.len()) -} - -/// Unlinks a file, or removes a directory. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path starts. -/// -/// **path**: -/// The path that needs to be unlinked or removed. -/// -/// **flags**: -/// Possible values: -/// -/// - [`REMOVEDIR`](struct.ulflags.html#associatedconstant.REMOVEDIR): -/// If set, attempt to remove a directory. -/// Otherwise, unlink a file. -#[inline] -pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno { - cloudabi_sys_file_unlink(fd_, path_.as_ptr(), path_.len(), flags_) -} - -/// Unlocks a write-locked userspace lock. -/// -/// If a userspace lock is unlocked while having its -/// [`LOCK_KERNEL_MANAGED`](constant.LOCK_KERNEL_MANAGED.html) flag set, the lock cannot be unlocked in -/// userspace directly. This system call needs to be performed -/// instead, so that any waiting threads can be woken up. -/// -/// To prevent spurious invocations of this system call, the lock -/// must be locked for writing. This prevents other threads from -/// acquiring additional read locks while the system call is in -/// progress. If the lock is acquired for reading, it must first -/// be upgraded to a write lock. -/// -/// ## Parameters -/// -/// **lock**: -/// The userspace lock that is locked for writing -/// by the calling thread. -/// -/// **scope**: -/// Whether the lock is stored in private or -/// shared memory. -#[inline] -pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno { - cloudabi_sys_lock_unlock(lock_, scope_) -} - -/// Provides memory advisory information on a region of memory. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages for which to provide memory advisory -/// information. -/// -/// **advice**: -/// The advice. -#[inline] -pub unsafe fn mem_advise(mapping_: &mut [u8], advice_: advice) -> errno { - cloudabi_sys_mem_advise(mapping_.as_mut_ptr() as *mut (), mapping_.len(), advice_) -} - -/// Creates a memory mapping, making the contents of a file -/// accessible through memory. -/// -/// ## Parameters -/// -/// **addr**: -/// If [`FIXED`](struct.mflags.html#associatedconstant.FIXED) is set, specifies to which -/// address the file region is mapped. Otherwise, -/// the mapping is performed at an unused -/// location. -/// -/// **len**: -/// The length of the memory mapping to be -/// created. -/// -/// **prot**: -/// Initial memory protection options for the -/// memory mapping. -/// -/// **flags**: -/// Memory mapping flags. -/// -/// **fd**: -/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be -/// [`MAP_ANON_FD`](constant.MAP_ANON_FD.html). Otherwise, this argument -/// specifies the file whose contents need to be -/// mapped. -/// -/// **off**: -/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be -/// zero. Otherwise, this argument specifies the -/// offset within the file at which the mapping -/// starts. -/// -/// **mem**: -/// The starting address of the memory mapping. -#[inline] -pub unsafe fn mem_map(addr_: *mut (), len_: usize, prot_: mprot, flags_: mflags, fd_: fd, off_: filesize, mem_: &mut *mut ()) -> errno { - cloudabi_sys_mem_map(addr_, len_, prot_, flags_, fd_, off_, mem_) -} - -/// Change the protection of a memory mapping. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages that need their protection changed. -/// -/// **prot**: -/// New protection options. -#[inline] -pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno { - cloudabi_sys_mem_protect(mapping_.as_mut_ptr() as *mut (), mapping_.len(), prot_) -} - -/// Synchronize a region of memory with its physical storage. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages that need to be synchronized. -/// -/// **flags**: -/// The method of synchronization. -#[inline] -pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno { - cloudabi_sys_mem_sync(mapping_.as_mut_ptr() as *mut (), mapping_.len(), flags_) -} - -/// Unmaps a region of memory. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages that needs to be unmapped. -#[inline] -pub unsafe fn mem_unmap(mapping_: &mut [u8]) -> errno { - cloudabi_sys_mem_unmap(mapping_.as_mut_ptr() as *mut (), mapping_.len()) -} - -/// Concurrently polls for the occurrence of a set of events. -/// -/// ## Parameters -/// -/// **in**: -/// The events to which to subscribe. -/// -/// **out**: -/// The events that have occurred. -/// -/// **nsubscriptions**: -/// Both the number of subscriptions and events. -/// -/// **nevents**: -/// The number of events stored. -#[inline] -pub unsafe fn poll(in_: *const subscription, out_: *mut event, nsubscriptions_: usize, nevents_: &mut usize) -> errno { - cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_) -} - -/// Replaces the process by a new executable. -/// -/// Process execution in CloudABI differs from POSIX in two ways: -/// handling of arguments and inheritance of file descriptors. -/// -/// CloudABI does not use string command line arguments. Instead, -/// a buffer with binary data is copied into the address space of -/// the new executable. The kernel does not enforce any specific -/// structure to this data, although CloudABI's C library uses it -/// to store a tree structure that is semantically identical to -/// YAML. -/// -/// Due to the strong focus on thread safety, file descriptors -/// aren't inherited through close-on-exec flags. An explicit -/// list of file descriptors that need to be retained needs to be -/// provided. After execution, file descriptors are placed in the -/// order in which they are stored in the array. This not only -/// makes the execution process deterministic. It also prevents -/// potential information disclosures about the layout of the -/// original process. -/// -/// ## Parameters -/// -/// **fd**: -/// A file descriptor of the new executable. -/// -/// **data**: -/// Binary argument data that is passed on to the -/// new executable. -/// -/// **fds**: -/// The layout of the file descriptor table after -/// execution. -#[inline] -pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno { - cloudabi_sys_proc_exec(fd_, data_.as_ptr() as *const (), data_.len(), fds_.as_ptr(), fds_.len()) -} - -/// Terminates the process normally. -/// -/// ## Parameters -/// -/// **rval**: -/// The exit code returned by the process. The -/// exit code can be obtained by other processes -/// through [`event.union.proc_terminate.exitcode`](struct.event_proc_terminate.html#structfield.exitcode). -#[inline] -pub unsafe fn proc_exit(rval_: exitcode) -> ! { - cloudabi_sys_proc_exit(rval_) -} - -/// Forks the process of the calling thread. -/// -/// After forking, a new process shall be created, having only a -/// copy of the calling thread. The parent process will obtain a -/// process descriptor. When closed, the child process is -/// automatically signaled with [`KILL`](enum.signal.html#variant.KILL). -/// -/// ## Parameters -/// -/// **fd**: -/// In the parent process: the file descriptor -/// number of the process descriptor. -/// -/// In the child process: [`PROCESS_CHILD`](constant.PROCESS_CHILD.html). -/// -/// **tid**: -/// In the parent process: undefined. -/// -/// In the child process: the thread ID of the -/// initial thread of the child process. -#[inline] -pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno { - cloudabi_sys_proc_fork(fd_, tid_) -} - -/// Sends a signal to the process of the calling thread. -/// -/// ## Parameters -/// -/// **sig**: -/// The signal condition that should be triggered. -/// If the signal causes the process to terminate, -/// its condition can be obtained by other -/// processes through -/// [`event.union.proc_terminate.signal`](struct.event_proc_terminate.html#structfield.signal). -#[inline] -pub unsafe fn proc_raise(sig_: signal) -> errno { - cloudabi_sys_proc_raise(sig_) -} - -/// Obtains random data from the kernel random number generator. -/// -/// As this interface is not guaranteed to be fast, it is advised -/// that the random data obtained through this system call is used -/// as the seed for a userspace pseudo-random number generator. -/// -/// ## Parameters -/// -/// **buf**: -/// The buffer that needs to be filled with random -/// data. -#[inline] -pub unsafe fn random_get(buf_: &mut [u8]) -> errno { - cloudabi_sys_random_get(buf_.as_mut_ptr() as *mut (), buf_.len()) -} - -/// Receives a message on a socket. -/// -/// ## Parameters -/// -/// **sock**: -/// The socket on which a message should be -/// received. -/// -/// **in**: -/// Input parameters. -/// -/// **out**: -/// Output parameters. -#[inline] -pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) -> errno { - cloudabi_sys_sock_recv(sock_, in_, out_) -} - -/// Sends a message on a socket. -/// -/// ## Parameters -/// -/// **sock**: -/// The socket on which a message should be sent. -/// -/// **in**: -/// Input parameters. -/// -/// **out**: -/// Output parameters. -#[inline] -pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) -> errno { - cloudabi_sys_sock_send(sock_, in_, out_) -} - -/// Shuts down socket send and receive channels. -/// -/// ## Parameters -/// -/// **sock**: -/// The socket that needs its channels shut down. -/// -/// **how**: -/// Which channels on the socket need to be shut -/// down. -#[inline] -pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno { - cloudabi_sys_sock_shutdown(sock_, how_) -} - -/// Creates a new thread within the current process. -/// -/// ## Parameters -/// -/// **attr**: -/// The desired attributes of the new thread. -/// -/// **tid**: -/// The thread ID of the new thread. -#[inline] -pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno { - cloudabi_sys_thread_create(attr_, tid_) -} - -/// Terminates the calling thread. -/// -/// This system call can also unlock a single userspace lock -/// after termination, which can be used to implement thread -/// joining. -/// -/// ## Parameters -/// -/// **lock**: -/// Userspace lock that is locked for writing by -/// the calling thread. -/// -/// **scope**: -/// Whether the lock is stored in private or -/// shared memory. -#[inline] -pub unsafe fn thread_exit(lock_: *mut lock, scope_: scope) -> ! { - cloudabi_sys_thread_exit(lock_, scope_) -} - -/// Temporarily yields execution of the calling thread. -#[inline] -pub unsafe fn thread_yield() -> errno { - cloudabi_sys_thread_yield() -} diff --git a/ctr-std/src/sys/cloudabi/abi/mod.rs b/ctr-std/src/sys/cloudabi/abi/mod.rs deleted file mode 100644 index 81a4d29..0000000 --- a/ctr-std/src/sys/cloudabi/abi/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(warnings)] -mod cloudabi; -pub use self::cloudabi::*; diff --git a/ctr-std/src/sys/cloudabi/args.rs b/ctr-std/src/sys/cloudabi/args.rs deleted file mode 100644 index 7b62cc6..0000000 --- a/ctr-std/src/sys/cloudabi/args.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use sys::cloudabi::shims::args::*; - -#[allow(dead_code)] -pub fn init(_: isize, _: *const *const u8) {} - -#[allow(dead_code)] -pub fn cleanup() {} diff --git a/ctr-std/src/sys/cloudabi/backtrace.rs b/ctr-std/src/sys/cloudabi/backtrace.rs deleted file mode 100644 index 2c43b59..0000000 --- a/ctr-std/src/sys/cloudabi/backtrace.rs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use error::Error; -use ffi::CStr; -use intrinsics; -use io; -use libc; -use sys_common::backtrace::Frame; -use unwind as uw; - -pub struct BacktraceContext; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl ::fmt::Display for UnwindError { - fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { - let mut cx = Context { idx: 0, frames }; - let result_unwind = - unsafe { uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context as *mut libc::c_void) }; - // See libunwind:src/unwind/Backtrace.c for the return values. - // No, there is no doc. - match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => Err(io::Error::new( - io::ErrorKind::Other, - UnwindError(result_unwind), - )), - } -} - -extern "C" fn trace_fn( - ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void, -) -> uw::_Unwind_Reason_Code { - let cx = unsafe { &mut *(arg as *mut Context) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - let mut ip_before_insn = 0; - let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; - } - - let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) }; - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} - -pub fn foreach_symbol_fileline(_: Frame, _: F, _: &BacktraceContext) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()>, -{ - // No way to obtain this information on CloudABI. - Ok(false) -} - -pub fn resolve_symname(frame: Frame, callback: F, _: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()>, -{ - unsafe { - let mut info: Dl_info = intrinsics::init(); - let symname = - if dladdr(frame.exact_position as *mut _, &mut info) == 0 || info.dli_sname.is_null() { - None - } else { - CStr::from_ptr(info.dli_sname).to_str().ok() - }; - callback(symname) - } -} - -#[repr(C)] -struct Dl_info { - dli_fname: *const libc::c_char, - dli_fbase: *mut libc::c_void, - dli_sname: *const libc::c_char, - dli_saddr: *mut libc::c_void, -} - -extern "C" { - fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; -} diff --git a/ctr-std/src/sys/cloudabi/condvar.rs b/ctr-std/src/sys/cloudabi/condvar.rs deleted file mode 100644 index c05c837..0000000 --- a/ctr-std/src/sys/cloudabi/condvar.rs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use mem; -use sync::atomic::{AtomicU32, Ordering}; -use sys::cloudabi::abi; -use sys::mutex::{self, Mutex}; -use sys::time::dur2intervals; -use time::Duration; - -extern "C" { - #[thread_local] - static __pthread_thread_id: abi::tid; -} - -pub struct Condvar { - condvar: UnsafeCell, -} - -unsafe impl Send for Condvar {} -unsafe impl Sync for Condvar {} - -impl Condvar { - pub const fn new() -> Condvar { - Condvar { - condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)), - } - } - - pub unsafe fn init(&mut self) {} - - pub unsafe fn notify_one(&self) { - let condvar = self.condvar.get(); - if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { - let ret = abi::condvar_signal(condvar as *mut abi::condvar, abi::scope::PRIVATE, 1); - assert_eq!( - ret, - abi::errno::SUCCESS, - "Failed to signal on condition variable" - ); - } - } - - pub unsafe fn notify_all(&self) { - let condvar = self.condvar.get(); - if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { - let ret = abi::condvar_signal( - condvar as *mut abi::condvar, - abi::scope::PRIVATE, - abi::nthreads::max_value(), - ); - assert_eq!( - ret, - abi::errno::SUCCESS, - "Failed to broadcast on condition variable" - ); - } - } - - pub unsafe fn wait(&self, mutex: &Mutex) { - let mutex = mutex::raw(mutex); - assert_eq!( - (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "This lock is not write-locked by this thread" - ); - - // Call into the kernel to wait on the condition variable. - let condvar = self.condvar.get(); - let subscription = abi::subscription { - type_: abi::eventtype::CONDVAR, - union: abi::subscription_union { - condvar: abi::subscription_condvar { - condvar: condvar as *mut abi::condvar, - condvar_scope: abi::scope::PRIVATE, - lock: mutex as *mut abi::lock, - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event: abi::event = mem::uninitialized(); - let mut nevents: usize = mem::uninitialized(); - let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); - assert_eq!( - ret, - abi::errno::SUCCESS, - "Failed to wait on condition variable" - ); - assert_eq!( - event.error, - abi::errno::SUCCESS, - "Failed to wait on condition variable" - ); - } - - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let mutex = mutex::raw(mutex); - assert_eq!( - (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "This lock is not write-locked by this thread" - ); - - // Call into the kernel to wait on the condition variable. - let condvar = self.condvar.get(); - let subscriptions = [ - abi::subscription { - type_: abi::eventtype::CONDVAR, - union: abi::subscription_union { - condvar: abi::subscription_condvar { - condvar: condvar as *mut abi::condvar, - condvar_scope: abi::scope::PRIVATE, - lock: mutex as *mut abi::lock, - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }, - abi::subscription { - type_: abi::eventtype::CLOCK, - union: abi::subscription_union { - clock: abi::subscription_clock { - clock_id: abi::clockid::MONOTONIC, - timeout: dur2intervals(&dur), - ..mem::zeroed() - }, - }, - ..mem::zeroed() - }, - ]; - let mut events: [abi::event; 2] = mem::uninitialized(); - let mut nevents: usize = mem::uninitialized(); - let ret = abi::poll(subscriptions.as_ptr(), events.as_mut_ptr(), 2, &mut nevents); - assert_eq!( - ret, - abi::errno::SUCCESS, - "Failed to wait on condition variable" - ); - for i in 0..nevents { - assert_eq!( - events[i].error, - abi::errno::SUCCESS, - "Failed to wait on condition variable" - ); - if events[i].type_ == abi::eventtype::CONDVAR { - return true; - } - } - false - } - - pub unsafe fn destroy(&self) { - let condvar = self.condvar.get(); - assert_eq!( - (*condvar).load(Ordering::Relaxed), - abi::CONDVAR_HAS_NO_WAITERS.0, - "Attempted to destroy a condition variable with blocked threads" - ); - } -} diff --git a/ctr-std/src/sys/cloudabi/mod.rs b/ctr-std/src/sys/cloudabi/mod.rs deleted file mode 100644 index 9e943c1..0000000 --- a/ctr-std/src/sys/cloudabi/mod.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use libc; -use mem; - -pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; -#[path = "../unix/cmath.rs"] -pub mod cmath; -pub mod condvar; -#[path = "../unix/memchr.rs"] -pub mod memchr; -pub mod mutex; -pub mod os; -#[path = "../unix/os_str.rs"] -pub mod os_str; -pub mod rwlock; -pub mod stack_overflow; -pub mod stdio; -pub mod thread; -#[path = "../unix/thread_local.rs"] -pub mod thread_local; -pub mod time; - -mod abi; - -mod shims; -pub use self::shims::*; - -#[allow(dead_code)] -pub fn init() {} - -pub fn decode_error_kind(errno: i32) -> io::ErrorKind { - match errno { - x if x == abi::errno::ACCES as i32 => io::ErrorKind::PermissionDenied, - x if x == abi::errno::ADDRINUSE as i32 => io::ErrorKind::AddrInUse, - x if x == abi::errno::ADDRNOTAVAIL as i32 => io::ErrorKind::AddrNotAvailable, - x if x == abi::errno::AGAIN as i32 => io::ErrorKind::WouldBlock, - x if x == abi::errno::CONNABORTED as i32 => io::ErrorKind::ConnectionAborted, - x if x == abi::errno::CONNREFUSED as i32 => io::ErrorKind::ConnectionRefused, - x if x == abi::errno::CONNRESET as i32 => io::ErrorKind::ConnectionReset, - x if x == abi::errno::EXIST as i32 => io::ErrorKind::AlreadyExists, - x if x == abi::errno::INTR as i32 => io::ErrorKind::Interrupted, - x if x == abi::errno::INVAL as i32 => io::ErrorKind::InvalidInput, - x if x == abi::errno::NOENT as i32 => io::ErrorKind::NotFound, - x if x == abi::errno::NOTCONN as i32 => io::ErrorKind::NotConnected, - x if x == abi::errno::PERM as i32 => io::ErrorKind::PermissionDenied, - x if x == abi::errno::PIPE as i32 => io::ErrorKind::BrokenPipe, - x if x == abi::errno::TIMEDOUT as i32 => io::ErrorKind::TimedOut, - _ => io::ErrorKind::Other, - } -} - -pub unsafe fn abort_internal() -> ! { - ::core::intrinsics::abort(); -} - -pub use libc::strlen; - -pub fn hashmap_random_keys() -> (u64, u64) { - unsafe { - let mut v = mem::uninitialized(); - libc::arc4random_buf(&mut v as *mut _ as *mut libc::c_void, mem::size_of_val(&v)); - v - } -} diff --git a/ctr-std/src/sys/cloudabi/mutex.rs b/ctr-std/src/sys/cloudabi/mutex.rs deleted file mode 100644 index d4ba6bc..0000000 --- a/ctr-std/src/sys/cloudabi/mutex.rs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use mem; -use sync::atomic::{AtomicU32, Ordering}; -use sys::cloudabi::abi; -use sys::rwlock::{self, RWLock}; - -extern "C" { - #[thread_local] - static __pthread_thread_id: abi::tid; -} - -// Implement Mutex using an RWLock. This doesn't introduce any -// performance overhead in this environment, as the operations would be -// implemented identically. -pub struct Mutex(RWLock); - -pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 { - rwlock::raw(&m.0) -} - -impl Mutex { - pub const fn new() -> Mutex { - Mutex(RWLock::new()) - } - - pub unsafe fn init(&mut self) { - // This function should normally reinitialize the mutex after - // moving it to a different memory address. This implementation - // does not require adjustments after moving. - } - - pub unsafe fn try_lock(&self) -> bool { - self.0.try_write() - } - - pub unsafe fn lock(&self) { - self.0.write() - } - - pub unsafe fn unlock(&self) { - self.0.write_unlock() - } - - pub unsafe fn destroy(&self) { - self.0.destroy() - } -} - -pub struct ReentrantMutex { - lock: UnsafeCell, - recursion: UnsafeCell, -} - -impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { - mem::uninitialized() - } - - pub unsafe fn init(&mut self) { - self.lock = UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)); - self.recursion = UnsafeCell::new(0); - } - - pub unsafe fn try_lock(&self) -> bool { - // Attempt to acquire the lock. - let lock = self.lock.get(); - let recursion = self.recursion.get(); - if let Err(old) = (*lock).compare_exchange( - abi::LOCK_UNLOCKED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - Ordering::Acquire, - Ordering::Relaxed, - ) { - // If we fail to acquire the lock, it may be the case - // that we've already acquired it and may need to recurse. - if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 { - *recursion += 1; - true - } else { - false - } - } else { - // Success. - assert_eq!(*recursion, 0, "Mutex has invalid recursion count"); - true - } - } - - pub unsafe fn lock(&self) { - if !self.try_lock() { - // Call into the kernel to acquire a write lock. - let lock = self.lock.get(); - let subscription = abi::subscription { - type_: abi::eventtype::LOCK_WRLOCK, - union: abi::subscription_union { - lock: abi::subscription_lock { - lock: lock as *mut abi::lock, - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event: abi::event = mem::uninitialized(); - let mut nevents: usize = mem::uninitialized(); - let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex"); - assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex"); - } - } - - pub unsafe fn unlock(&self) { - let lock = self.lock.get(); - let recursion = self.recursion.get(); - assert_eq!( - (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "This mutex is locked by a different thread" - ); - - if *recursion > 0 { - *recursion -= 1; - } else if !(*lock) - .compare_exchange( - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - abi::LOCK_UNLOCKED.0, - Ordering::Release, - Ordering::Relaxed, - ) - .is_ok() - { - // Lock is managed by kernelspace. Call into the kernel - // to unblock waiting threads. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex"); - } - } - - pub unsafe fn destroy(&self) { - let lock = self.lock.get(); - let recursion = self.recursion.get(); - assert_eq!( - (*lock).load(Ordering::Relaxed), - abi::LOCK_UNLOCKED.0, - "Attempted to destroy locked mutex" - ); - assert_eq!(*recursion, 0, "Recursion counter invalid"); - } -} diff --git a/ctr-std/src/sys/cloudabi/os.rs b/ctr-std/src/sys/cloudabi/os.rs deleted file mode 100644 index 7e506b8..0000000 --- a/ctr-std/src/sys/cloudabi/os.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::CStr; -use libc::{self, c_int}; -use str; - -pub use sys::cloudabi::shims::os::*; - -pub fn errno() -> i32 { - extern "C" { - #[thread_local] - static errno: c_int; - } - - unsafe { errno as i32 } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(errno: i32) -> String { - // cloudlibc's strerror() is guaranteed to be thread-safe. There is - // thus no need to use strerror_r(). - str::from_utf8(unsafe { CStr::from_ptr(libc::strerror(errno)) }.to_bytes()) - .unwrap() - .to_owned() -} - -pub fn exit(code: i32) -> ! { - unsafe { libc::exit(code as c_int) } -} diff --git a/ctr-std/src/sys/cloudabi/rwlock.rs b/ctr-std/src/sys/cloudabi/rwlock.rs deleted file mode 100644 index 8539aec..0000000 --- a/ctr-std/src/sys/cloudabi/rwlock.rs +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use mem; -use sync::atomic::{AtomicU32, Ordering}; -use sys::cloudabi::abi; - -extern "C" { - #[thread_local] - static __pthread_thread_id: abi::tid; -} - -#[thread_local] -static mut RDLOCKS_ACQUIRED: u32 = 0; - -pub struct RWLock { - lock: UnsafeCell, -} - -pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 { - r.lock.get() -} - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { - lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)), - } - } - - pub unsafe fn try_read(&self) -> bool { - let lock = self.lock.get(); - let mut old = abi::LOCK_UNLOCKED.0; - while let Err(cur) = - (*lock).compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed) - { - if (cur & abi::LOCK_WRLOCKED.0) != 0 { - // Another thread already has a write lock. - assert_ne!( - old & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "Attempted to acquire a read lock while holding a write lock" - ); - return false; - } else if (old & abi::LOCK_KERNEL_MANAGED.0) != 0 && RDLOCKS_ACQUIRED == 0 { - // Lock has threads waiting for the lock. Only acquire - // the lock if we have already acquired read locks. In - // that case, it is justified to acquire this lock to - // prevent a deadlock. - return false; - } - old = cur; - } - - RDLOCKS_ACQUIRED += 1; - true - } - - pub unsafe fn read(&self) { - if !self.try_read() { - // Call into the kernel to acquire a read lock. - let lock = self.lock.get(); - let subscription = abi::subscription { - type_: abi::eventtype::LOCK_RDLOCK, - union: abi::subscription_union { - lock: abi::subscription_lock { - lock: lock as *mut abi::lock, - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event: abi::event = mem::uninitialized(); - let mut nevents: usize = mem::uninitialized(); - let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire read lock"); - assert_eq!( - event.error, - abi::errno::SUCCESS, - "Failed to acquire read lock" - ); - - RDLOCKS_ACQUIRED += 1; - } - } - - pub unsafe fn read_unlock(&self) { - // Perform a read unlock. We can do this in userspace, except when - // other threads are blocked and we are performing the last unlock. - // In that case, call into the kernel. - // - // Other threads may attempt to increment the read lock count, - // meaning that the call into the kernel could be spurious. To - // prevent this from happening, upgrade to a write lock first. This - // allows us to call into the kernel, having the guarantee that the - // lock value will not change in the meantime. - assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count"); - let mut old = 1; - loop { - let lock = self.lock.get(); - if old == 1 | abi::LOCK_KERNEL_MANAGED.0 { - // Last read lock while threads are waiting. Attempt to upgrade - // to a write lock before calling into the kernel to unlock. - if let Err(cur) = (*lock).compare_exchange_weak( - old, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0, - Ordering::Acquire, - Ordering::Relaxed, - ) { - old = cur; - } else { - // Call into the kernel to unlock. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); - break; - } - } else { - // No threads waiting or not the last read lock. Just decrement - // the read lock count. - assert_ne!( - old & !abi::LOCK_KERNEL_MANAGED.0, - 0, - "This rwlock is not locked" - ); - assert_eq!( - old & abi::LOCK_WRLOCKED.0, - 0, - "Attempted to read-unlock a write-locked rwlock" - ); - if let Err(cur) = (*lock).compare_exchange_weak( - old, - old - 1, - Ordering::Acquire, - Ordering::Relaxed, - ) { - old = cur; - } else { - break; - } - } - } - - RDLOCKS_ACQUIRED -= 1; - } - - pub unsafe fn try_write(&self) -> bool { - // Attempt to acquire the lock. - let lock = self.lock.get(); - if let Err(old) = (*lock).compare_exchange( - abi::LOCK_UNLOCKED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - Ordering::Acquire, - Ordering::Relaxed, - ) { - // Failure. Crash upon recursive acquisition. - assert_ne!( - old & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "Attempted to recursive write-lock a rwlock", - ); - false - } else { - // Success. - true - } - } - - pub unsafe fn write(&self) { - if !self.try_write() { - // Call into the kernel to acquire a write lock. - let lock = self.lock.get(); - let subscription = abi::subscription { - type_: abi::eventtype::LOCK_WRLOCK, - union: abi::subscription_union { - lock: abi::subscription_lock { - lock: lock as *mut abi::lock, - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event: abi::event = mem::uninitialized(); - let mut nevents: usize = mem::uninitialized(); - let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire write lock"); - assert_eq!( - event.error, - abi::errno::SUCCESS, - "Failed to acquire write lock" - ); - } - } - - pub unsafe fn write_unlock(&self) { - let lock = self.lock.get(); - assert_eq!( - (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "This rwlock is not write-locked by this thread" - ); - - if !(*lock) - .compare_exchange( - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - abi::LOCK_UNLOCKED.0, - Ordering::Release, - Ordering::Relaxed, - ) - .is_ok() - { - // Lock is managed by kernelspace. Call into the kernel - // to unblock waiting threads. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); - } - } - - pub unsafe fn destroy(&self) { - let lock = self.lock.get(); - assert_eq!( - (*lock).load(Ordering::Relaxed), - abi::LOCK_UNLOCKED.0, - "Attempted to destroy locked rwlock" - ); - } -} diff --git a/ctr-std/src/sys/cloudabi/shims/args.rs b/ctr-std/src/sys/cloudabi/shims/args.rs deleted file mode 100644 index 1b5785a..0000000 --- a/ctr-std/src/sys/cloudabi/shims/args.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::OsString; - -pub struct Args(()); - -impl Args { - pub fn inner_debug(&self) -> &[OsString] { - &[] - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - None - } - fn size_hint(&self) -> (usize, Option) { - (0, Some(0)) - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - 0 - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - None - } -} - -pub fn args() -> Args { - Args(()) -} diff --git a/ctr-std/src/sys/cloudabi/shims/env.rs b/ctr-std/src/sys/cloudabi/shims/env.rs deleted file mode 100644 index 31777aa..0000000 --- a/ctr-std/src/sys/cloudabi/shims/env.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub mod os { - pub const FAMILY: &'static str = "cloudabi"; - pub const OS: &'static str = "cloudabi"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} diff --git a/ctr-std/src/sys/cloudabi/shims/fs.rs b/ctr-std/src/sys/cloudabi/shims/fs.rs deleted file mode 100644 index d3da0fb..0000000 --- a/ctr-std/src/sys/cloudabi/shims/fs.rs +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::OsString; -use fmt; -use hash::{Hash, Hasher}; -use io::{self, SeekFrom}; -use path::{Path, PathBuf}; -use sys::time::SystemTime; -use sys::{unsupported, Void}; - -pub struct File(Void); - -pub struct FileAttr(Void); - -pub struct ReadDir(Void); - -pub struct DirEntry(Void); - -#[derive(Clone, Debug)] -pub struct OpenOptions {} - -pub struct FilePermissions(Void); - -pub struct FileType(Void); - -#[derive(Debug)] -pub struct DirBuilder {} - -impl FileAttr { - pub fn size(&self) -> u64 { - match self.0 {} - } - - pub fn perm(&self) -> FilePermissions { - match self.0 {} - } - - pub fn file_type(&self) -> FileType { - match self.0 {} - } - - pub fn modified(&self) -> io::Result { - match self.0 {} - } - - pub fn accessed(&self) -> io::Result { - match self.0 {} - } - - pub fn created(&self) -> io::Result { - match self.0 {} - } -} - -impl Clone for FileAttr { - fn clone(&self) -> FileAttr { - match self.0 {} - } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - match self.0 {} - } - - pub fn set_readonly(&mut self, _readonly: bool) { - match self.0 {} - } -} - -impl Clone for FilePermissions { - fn clone(&self) -> FilePermissions { - match self.0 {} - } -} - -impl PartialEq for FilePermissions { - fn eq(&self, _other: &FilePermissions) -> bool { - match self.0 {} - } -} - -impl Eq for FilePermissions {} - -impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -impl FileType { - pub fn is_dir(&self) -> bool { - match self.0 {} - } - - pub fn is_file(&self) -> bool { - match self.0 {} - } - - pub fn is_symlink(&self) -> bool { - match self.0 {} - } -} - -impl Clone for FileType { - fn clone(&self) -> FileType { - match self.0 {} - } -} - -impl Copy for FileType {} - -impl PartialEq for FileType { - fn eq(&self, _other: &FileType) -> bool { - match self.0 {} - } -} - -impl Eq for FileType {} - -impl Hash for FileType { - fn hash(&self, _h: &mut H) { - match self.0 {} - } -} - -impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - match self.0 {} - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - match self.0 {} - } - - pub fn file_name(&self) -> OsString { - match self.0 {} - } - - pub fn metadata(&self) -> io::Result { - match self.0 {} - } - - pub fn file_type(&self) -> io::Result { - match self.0 {} - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions {} - } - - pub fn read(&mut self, _read: bool) {} - pub fn write(&mut self, _write: bool) {} - pub fn append(&mut self, _append: bool) {} - pub fn truncate(&mut self, _truncate: bool) {} - pub fn create(&mut self, _create: bool) {} - pub fn create_new(&mut self, _create_new: bool) {} -} - -impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { - unsupported() - } - - pub fn file_attr(&self) -> io::Result { - match self.0 {} - } - - pub fn fsync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn datasync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn truncate(&self, _size: u64) -> io::Result<()> { - match self.0 {} - } - - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn flush(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder {} - } - - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() - } -} - -impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -pub fn readdir(_p: &Path) -> io::Result { - unsupported() -} - -pub fn unlink(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { - unsupported() -} - -pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { - match perm.0 {} -} - -pub fn rmdir(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - unsupported() -} - -pub fn readlink(_p: &Path) -> io::Result { - unsupported() -} - -pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn stat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn lstat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn canonicalize(_p: &Path) -> io::Result { - unsupported() -} - -pub fn copy(_from: &Path, _to: &Path) -> io::Result { - unsupported() -} diff --git a/ctr-std/src/sys/cloudabi/shims/mod.rs b/ctr-std/src/sys/cloudabi/shims/mod.rs deleted file mode 100644 index 407c2b9..0000000 --- a/ctr-std/src/sys/cloudabi/shims/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; - -pub mod args; -pub mod env; -pub mod fs; -pub mod net; -#[path = "../../unix/path.rs"] -pub mod path; -pub mod pipe; -pub mod process; -pub mod os; - -// This enum is used as the storage for a bunch of types which can't actually exist. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub enum Void {} - -pub fn unsupported() -> io::Result { - Err(io::Error::new( - io::ErrorKind::Other, - "This function is not available on CloudABI.", - )) -} diff --git a/ctr-std/src/sys/cloudabi/shims/net.rs b/ctr-std/src/sys/cloudabi/shims/net.rs deleted file mode 100644 index 93eaf6a..0000000 --- a/ctr-std/src/sys/cloudabi/shims/net.rs +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use fmt; -use io; -use net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; -use time::Duration; -use sys::{unsupported, Void}; - -pub extern crate libc as netc; - -pub struct TcpStream(Void); - -impl TcpStream { - pub fn connect(_: &SocketAddr) -> io::Result { - unsupported() - } - - pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { - unsupported() - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn read_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn write_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn write(&self, _: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn peer_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn socket_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn nodelay(&self) -> io::Result { - match self.0 {} - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn ttl(&self) -> io::Result { - match self.0 {} - } - - pub fn take_error(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} - } -} - -impl fmt::Debug for TcpStream { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -pub struct TcpListener(Void); - -impl TcpListener { - pub fn bind(_: &SocketAddr) -> io::Result { - unsupported() - } - - pub fn socket_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn ttl(&self) -> io::Result { - match self.0 {} - } - - pub fn set_only_v6(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn only_v6(&self) -> io::Result { - match self.0 {} - } - - pub fn take_error(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} - } -} - -impl fmt::Debug for TcpListener { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -pub struct UdpSocket(Void); - -impl UdpSocket { - pub fn bind(_: &SocketAddr) -> io::Result { - unsupported() - } - - pub fn socket_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - match self.0 {} - } - - pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - match self.0 {} - } - - pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn read_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn write_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_broadcast(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn broadcast(&self) -> io::Result { - match self.0 {} - } - - pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn multicast_loop_v4(&self) -> io::Result { - match self.0 {} - } - - pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - match self.0 {} - } - - pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn multicast_loop_v6(&self) -> io::Result { - match self.0 {} - } - - pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - match self.0 {} - } - - pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - match self.0 {} - } - - pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn ttl(&self) -> io::Result { - match self.0 {} - } - - pub fn take_error(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn recv(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn send(&self, _: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn connect(&self, _: &SocketAddr) -> io::Result<()> { - match self.0 {} - } -} - -impl fmt::Debug for UdpSocket { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -pub struct LookupHost(Void); - -impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option { - match self.0 {} - } -} - -pub fn lookup_host(_: &str) -> io::Result { - unsupported() -} diff --git a/ctr-std/src/sys/cloudabi/shims/os.rs b/ctr-std/src/sys/cloudabi/shims/os.rs deleted file mode 100644 index 1e355d9..0000000 --- a/ctr-std/src/sys/cloudabi/shims/os.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use error::Error as StdError; -use ffi::{OsStr, OsString}; -use fmt; -use io; -use iter; -use path::{self, PathBuf}; -use sys::{unsupported, Void}; - -pub fn getcwd() -> io::Result { - unsupported() -} - -pub fn chdir(_: &path::Path) -> io::Result<()> { - unsupported() -} - -pub type Env = iter::Empty<(OsString, OsString)>; - -pub fn env() -> Env { - iter::empty() -} - -pub fn getenv(_: &OsStr) -> io::Result> { - Ok(None) -} - -pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - unsupported() -} - -pub fn unsetenv(_: &OsStr) -> io::Result<()> { - unsupported() -} - -pub struct SplitPaths<'a>(&'a Void); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - match *self.0 {} - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "not supported on CloudABI yet".fmt(f) - } -} - -impl StdError for JoinPathsError { - fn description(&self) -> &str { - "not supported on CloudABI yet" - } -} - -pub fn home_dir() -> Option { - None -} - -pub fn temp_dir() -> PathBuf { - PathBuf::from("/tmp") -} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub fn getpid() -> u32 { - 1 -} diff --git a/ctr-std/src/sys/cloudabi/shims/pipe.rs b/ctr-std/src/sys/cloudabi/shims/pipe.rs deleted file mode 100644 index 77a9cd6..0000000 --- a/ctr-std/src/sys/cloudabi/shims/pipe.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use sys::Void; - -pub struct AnonPipe(Void); - -impl AnonPipe { - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -pub fn read2(p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} diff --git a/ctr-std/src/sys/cloudabi/shims/process.rs b/ctr-std/src/sys/cloudabi/shims/process.rs deleted file mode 100644 index fcd40c1..0000000 --- a/ctr-std/src/sys/cloudabi/shims/process.rs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::OsStr; -use fmt; -use io; -use sys::fs::File; -use sys::pipe::AnonPipe; -use sys::{unsupported, Void}; -use sys_common::process::{CommandEnv, DefaultEnvKey}; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - env: CommandEnv, -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, -} - -impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { - env: Default::default(), - } - } - - pub fn arg(&mut self, _arg: &OsStr) {} - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, _dir: &OsStr) {} - - pub fn stdin(&mut self, _stdin: Stdio) {} - - pub fn stdout(&mut self, _stdout: Stdio) {} - - pub fn stderr(&mut self, _stderr: Stdio) {} - - pub fn spawn( - &mut self, - _default: Stdio, - _needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - file.diverge() - } -} - -impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - Ok(()) - } -} - -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } -} - -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - match self.0 {} - } -} - -impl Copy for ExitStatus {} - -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { - match self.0 {} - } -} - -impl Eq for ExitStatus {} - -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(bool); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(false); - pub const FAILURE: ExitCode = ExitCode(true); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} diff --git a/ctr-std/src/sys/cloudabi/stack_overflow.rs b/ctr-std/src/sys/cloudabi/stack_overflow.rs deleted file mode 100644 index 5c0b1e5..0000000 --- a/ctr-std/src/sys/cloudabi/stack_overflow.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg_attr(test, allow(dead_code))] - -pub struct Handler; - -impl Handler { - pub unsafe fn new() -> Handler { - Handler - } -} - -pub unsafe fn init() {} - -pub unsafe fn cleanup() {} diff --git a/ctr-std/src/sys/cloudabi/stdio.rs b/ctr-std/src/sys/cloudabi/stdio.rs deleted file mode 100644 index 1d7344f..0000000 --- a/ctr-std/src/sys/cloudabi/stdio.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use sys::cloudabi::abi; - -pub struct Stdin(()); -pub struct Stdout(()); -pub struct Stderr(()); - -impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin(())) - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - Ok(0) - } -} - -impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout(())) - } - - pub fn write(&self, _: &[u8]) -> io::Result { - Err(io::Error::new( - io::ErrorKind::BrokenPipe, - "Stdout is not connected to any output in this environment", - )) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr(())) - } - - pub fn write(&self, _: &[u8]) -> io::Result { - Err(io::Error::new( - io::ErrorKind::BrokenPipe, - "Stderr is not connected to any output in this environment", - )) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -// FIXME: right now this raw stderr handle is used in a few places because -// std::io::stderr_raw isn't exposed, but once that's exposed this impl -// should go away -impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result { - Stderr::write(self, data) - } - - fn flush(&mut self) -> io::Result<()> { - Stderr::flush(self) - } -} - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(abi::errno::BADF as i32) -} - -pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; - -pub fn stderr_prints_nothing() -> bool { - false -} diff --git a/ctr-std/src/sys/cloudabi/thread.rs b/ctr-std/src/sys/cloudabi/thread.rs deleted file mode 100644 index 8cca47e..0000000 --- a/ctr-std/src/sys/cloudabi/thread.rs +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use boxed::FnBox; -use cmp; -use ffi::CStr; -use io; -use libc; -use mem; -use ptr; -use sys::cloudabi::abi; -use sys::time::dur2intervals; -use sys_common::thread::*; -use time::Duration; - -pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; - -pub struct Thread { - id: libc::pthread_t, -} - -// CloudABI has pthread_t as a pointer in which case we still want -// a thread to be Send/Sync -unsafe impl Send for Thread {} -unsafe impl Sync for Thread {} - -impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box) -> io::Result { - let p = box p; - let mut native: libc::pthread_t = mem::zeroed(); - let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); - - let stack_size = cmp::max(stack, min_stack_size(&attr)); - assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); - - let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _); - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); - - return if ret != 0 { - Err(io::Error::from_raw_os_error(ret)) - } else { - mem::forget(p); // ownership passed to pthread_create - Ok(Thread { id: native }) - }; - - extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { - unsafe { - start_thread(main as *mut u8); - } - ptr::null_mut() - } - } - - pub fn yield_now() { - let ret = unsafe { abi::thread_yield() }; - debug_assert_eq!(ret, abi::errno::SUCCESS); - } - - pub fn set_name(_name: &CStr) { - // CloudABI has no way to set a thread name. - } - - pub fn sleep(dur: Duration) { - unsafe { - let subscription = abi::subscription { - type_: abi::eventtype::CLOCK, - union: abi::subscription_union { - clock: abi::subscription_clock { - clock_id: abi::clockid::MONOTONIC, - timeout: dur2intervals(&dur), - ..mem::zeroed() - }, - }, - ..mem::zeroed() - }; - let mut event: abi::event = mem::uninitialized(); - let mut nevents: usize = mem::uninitialized(); - let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); - assert_eq!(ret, abi::errno::SUCCESS); - assert_eq!(event.error, abi::errno::SUCCESS); - } - } - - pub fn join(self) { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - assert!( - ret == 0, - "failed to join thread: {}", - io::Error::from_raw_os_error(ret) - ); - } - } -} - -impl Drop for Thread { - fn drop(&mut self) { - let ret = unsafe { libc::pthread_detach(self.id) }; - debug_assert_eq!(ret, 0); - } -} - -#[cfg_attr(test, allow(dead_code))] -pub mod guard { - pub type Guard = !; - pub unsafe fn current() -> Option { - None - } - pub unsafe fn init() -> Option { - None - } - pub unsafe fn deinit() {} -} - -fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { - libc::PTHREAD_STACK_MIN -} diff --git a/ctr-std/src/sys/cloudabi/time.rs b/ctr-std/src/sys/cloudabi/time.rs deleted file mode 100644 index ee12731..0000000 --- a/ctr-std/src/sys/cloudabi/time.rs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use mem; -use sys::cloudabi::abi; -use time::Duration; - -const NSEC_PER_SEC: abi::timestamp = 1_000_000_000; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant { - t: abi::timestamp, -} - -pub fn dur2intervals(dur: &Duration) -> abi::timestamp { - dur.as_secs() - .checked_mul(NSEC_PER_SEC) - .and_then(|nanos| nanos.checked_add(dur.subsec_nanos() as abi::timestamp)) - .expect("overflow converting duration to nanoseconds") -} - -impl Instant { - pub fn now() -> Instant { - unsafe { - let mut t = mem::uninitialized(); - let ret = abi::clock_time_get(abi::clockid::MONOTONIC, 0, &mut t); - assert_eq!(ret, abi::errno::SUCCESS); - Instant { t: t } - } - } - - pub fn sub_instant(&self, other: &Instant) -> Duration { - let diff = self.t - .checked_sub(other.t) - .expect("second instant is later than self"); - Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32) - } - - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant { - t: self.t - .checked_add(dur2intervals(other)) - .expect("overflow when adding duration to instant"), - } - } - - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant { - t: self.t - .checked_sub(dur2intervals(other)) - .expect("overflow when subtracting duration from instant"), - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct SystemTime { - t: abi::timestamp, -} - -impl SystemTime { - pub fn now() -> SystemTime { - unsafe { - let mut t = mem::uninitialized(); - let ret = abi::clock_time_get(abi::clockid::REALTIME, 0, &mut t); - assert_eq!(ret, abi::errno::SUCCESS); - SystemTime { t: t } - } - } - - pub fn sub_time(&self, other: &SystemTime) -> Result { - if self.t >= other.t { - let diff = self.t - other.t; - Ok(Duration::new( - diff / NSEC_PER_SEC, - (diff % NSEC_PER_SEC) as u32, - )) - } else { - let diff = other.t - self.t; - Err(Duration::new( - diff / NSEC_PER_SEC, - (diff % NSEC_PER_SEC) as u32, - )) - } - } - - pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime { - t: self.t - .checked_add(dur2intervals(other)) - .expect("overflow when adding duration to instant"), - } - } - - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - SystemTime { - t: self.t - .checked_sub(dur2intervals(other)) - .expect("overflow when subtracting duration from instant"), - } - } -} - -pub const UNIX_EPOCH: SystemTime = SystemTime { t: 0 }; diff --git a/ctr-std/src/sys/horizon/android.rs b/ctr-std/src/sys/horizon/android.rs deleted file mode 100644 index 1043672..0000000 --- a/ctr-std/src/sys/horizon/android.rs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Android ABI-compatibility module -//! -//! The ABI of Android has changed quite a bit over time, and libstd attempts to -//! be both forwards and backwards compatible as much as possible. We want to -//! always work with the most recent version of Android, but we also want to -//! work with older versions of Android for whenever projects need to. -//! -//! Our current minimum supported Android version is `android-9`, e.g. Android -//! with API level 9. We then in theory want to work on that and all future -//! versions of Android! -//! -//! Some of the detection here is done at runtime via `dlopen` and -//! introspection. Other times no detection is performed at all and we just -//! provide a fallback implementation as some versions of Android we support -//! don't have the function. -//! -//! You'll find more details below about why each compatibility shim is needed. - -#![cfg(target_os = "android")] - -use libc::{c_int, c_void, sighandler_t, size_t, ssize_t}; -use libc::{ftruncate, pread, pwrite}; - -use io; -use super::{cvt, cvt_r}; - -// The `log2` and `log2f` functions apparently appeared in android-18, or at -// least you can see they're not present in the android-17 header [1] and they -// are present in android-18 [2]. -// -// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms -// /android-17/arch-arm/usr/include/math.h -// [2]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms -// /android-18/arch-arm/usr/include/math.h -// -// Note that these shims are likely less precise than directly calling `log2`, -// but hopefully that should be enough for now... -// -// Note that mathematically, for any arbitrary `y`: -// -// log_2(x) = log_y(x) / log_y(2) -// = log_y(x) / (1 / log_2(y)) -// = log_y(x) * log_2(y) -// -// Hence because `ln` (log_e) is available on all Android we just choose `y = e` -// and get: -// -// log_2(x) = ln(x) * log_2(e) - -#[cfg(not(test))] -pub fn log2f32(f: f32) -> f32 { - f.ln() * ::f32::consts::LOG2_E -} - -#[cfg(not(test))] -pub fn log2f64(f: f64) -> f64 { - f.ln() * ::f64::consts::LOG2_E -} - -// Back in the day [1] the `signal` function was just an inline wrapper -// around `bsd_signal`, but starting in API level android-20 the `signal` -// symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was -// removed [3]. -// -// Basically this means that if we want to be binary compatible with multiple -// Android releases (oldest being 9 and newest being 21) then we need to check -// for both symbols and not actually link against either. -// -// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms -// /android-18/arch-arm/usr/include/signal.h -// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental -// /platforms/android-20/arch-arm -// /usr/include/signal.h -// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms -// /android-21/arch-arm/usr/include/signal.h -pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t { - weak!(fn signal(c_int, sighandler_t) -> sighandler_t); - weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t); - - let f = signal.get().or_else(|| bsd_signal.get()); - let f = f.expect("neither `signal` nor `bsd_signal` symbols found"); - f(signum, handler) -} - -// The `ftruncate64` symbol apparently appeared in android-12, so we do some -// dynamic detection to see if we can figure out whether `ftruncate64` exists. -// -// If it doesn't we just fall back to `ftruncate`, generating an error for -// too-large values. -#[cfg(target_pointer_width = "32")] -pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { - weak!(fn ftruncate64(c_int, i64) -> c_int); - - unsafe { - match ftruncate64.get() { - Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()), - None => { - if size > i32::max_value() as u64 { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot truncate >2GB")) - } else { - cvt_r(|| ftruncate(fd, size as i32)).map(|_| ()) - } - } - } - } -} - -#[cfg(target_pointer_width = "64")] -pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { - unsafe { - cvt_r(|| ftruncate(fd, size as i64)).map(|_| ()) - } -} - -#[cfg(target_pointer_width = "32")] -pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64) - -> io::Result -{ - use convert::TryInto; - weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t); - pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| { - if let Ok(o) = offset.try_into() { - cvt(pread(fd, buf, count, o)) - } else { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot pread >2GB")) - } - }) -} - -#[cfg(target_pointer_width = "32")] -pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64) - -> io::Result -{ - use convert::TryInto; - weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t); - pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| { - if let Ok(o) = offset.try_into() { - cvt(pwrite(fd, buf, count, o)) - } else { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot pwrite >2GB")) - } - }) -} - -#[cfg(target_pointer_width = "64")] -pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64) - -> io::Result -{ - cvt(pread(fd, buf, count, offset)) -} - -#[cfg(target_pointer_width = "64")] -pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64) - -> io::Result -{ - cvt(pwrite(fd, buf, count, offset)) -} diff --git a/ctr-std/src/sys/horizon/args.rs b/ctr-std/src/sys/horizon/args.rs deleted file mode 100644 index 84d0c85..0000000 --- a/ctr-std/src/sys/horizon/args.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::OsString; -use marker::PhantomData; -use vec; - -pub unsafe fn init(_argc: isize, _argv: *const *const u8) { - // Currently null because we haven't implemented args yet -} - -pub unsafe fn cleanup() { -} - -pub fn args() -> Args { - return Args { - iter: Vec::new().into_iter(), - _dont_send_or_sync_me: PhantomData, - } -} - -pub struct Args { - iter: vec::IntoIter, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Args { - pub fn inner_debug(&self) -> &[OsString] { - self.iter.as_slice() - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } -} diff --git a/ctr-std/src/sys/horizon/backtrace/mod.rs b/ctr-std/src/sys/horizon/backtrace/mod.rs deleted file mode 100644 index b5bf20c..0000000 --- a/ctr-std/src/sys/horizon/backtrace/mod.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Backtrace support built on libgcc with some extra OS-specific support -/// -/// Some methods of getting a backtrace: -/// -/// * The backtrace() functions on unix. It turns out this doesn't work very -/// well for green threads on macOS, and the address to symbol portion of it -/// suffers problems that are described below. -/// -/// * Using libunwind. This is more difficult than it sounds because libunwind -/// isn't installed everywhere by default. It's also a bit of a hefty library, -/// so possibly not the best option. When testing, libunwind was excellent at -/// getting both accurate backtraces and accurate symbols across platforms. -/// This route was not chosen in favor of the next option, however. -/// -/// * We're already using libgcc_s for exceptions in rust (triggering thread -/// unwinding and running destructors on the stack), and it turns out that it -/// conveniently comes with a function that also gives us a backtrace. All of -/// these functions look like _Unwind_*, but it's not quite the full -/// repertoire of the libunwind API. Due to it already being in use, this was -/// the chosen route of getting a backtrace. -/// -/// After choosing libgcc_s for backtraces, the sad part is that it will only -/// give us a stack trace of instruction pointers. Thankfully these instruction -/// pointers are accurate (they work for green and native threads), but it's -/// then up to us again to figure out how to translate these addresses to -/// symbols. As with before, we have a few options. Before, that, a little bit -/// of an interlude about symbols. This is my very limited knowledge about -/// symbol tables, and this information is likely slightly wrong, but the -/// general idea should be correct. -/// -/// When talking about symbols, it's helpful to know a few things about where -/// symbols are located. Some symbols are located in the dynamic symbol table -/// of the executable which in theory means that they're available for dynamic -/// linking and lookup. Other symbols end up only in the local symbol table of -/// the file. This loosely corresponds to pub and priv functions in Rust. -/// -/// Armed with this knowledge, we know that our solution for address to symbol -/// translation will need to consult both the local and dynamic symbol tables. -/// With that in mind, here's our options of translating an address to -/// a symbol. -/// -/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() -/// behind the scenes to translate, and this is why backtrace() was not used. -/// Conveniently, this method works fantastically on macOS. It appears dladdr() -/// uses magic to consult the local symbol table, or we're putting everything -/// in the dynamic symbol table anyway. Regardless, for macOS, this is the -/// method used for translation. It's provided by the system and easy to do.o -/// -/// Sadly, all other systems have a dladdr() implementation that does not -/// consult the local symbol table. This means that most functions are blank -/// because they don't have symbols. This means that we need another solution. -/// -/// * Use unw_get_proc_name(). This is part of the libunwind api (not the -/// libgcc_s version of the libunwind api), but involves taking a dependency -/// to libunwind. We may pursue this route in the future if we bundle -/// libunwind, but libunwind was unwieldy enough that it was not chosen at -/// this time to provide this functionality. -/// -/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a -/// semi-reasonable solution. The stdlib already knows how to spawn processes, -/// so in theory it could invoke readelf, parse the output, and consult the -/// local/dynamic symbol tables from there. This ended up not getting chosen -/// due to the craziness of the idea plus the advent of the next option. -/// -/// * Use `libbacktrace`. It turns out that this is a small library bundled in -/// the gcc repository which provides backtrace and symbol translation -/// functionality. All we really need from it is the backtrace functionality, -/// and we only really need this on everything that's not macOS, so this is the -/// chosen route for now. -/// -/// In summary, the current situation uses libgcc_s to get a trace of stack -/// pointers, and we use dladdr() or libbacktrace to translate these addresses -/// to symbols. This is a bit of a hokey implementation as-is, but it works for -/// all unix platforms we support right now, so it at least gets the job done. - -pub use self::tracing::unwind_backtrace; -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; - -// tracing impls: -mod tracing; -// symbol resolvers: -mod printing; - -#[cfg(not(target_os = "emscripten"))] -pub mod gnu { - use io; - use fs; - use libc::c_char; - - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - use env; - use os::unix::ffi::OsStrExt; - - let filename = env::current_exe()?; - let file = fs::File::open(&filename)?; - let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter() - .map(|&x| x as c_char).collect(); - filename_cstr.push(0); // Null terminate - Ok((filename_cstr, file)) - } -} - -pub struct BacktraceContext; diff --git a/ctr-std/src/sys/horizon/backtrace/printing/dladdr.rs b/ctr-std/src/sys/horizon/backtrace/printing/dladdr.rs deleted file mode 100644 index bc56fd6..0000000 --- a/ctr-std/src/sys/horizon/backtrace/printing/dladdr.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use intrinsics; -use ffi::CStr; -use libc; -use sys::backtrace::BacktraceContext; -use sys_common::backtrace::Frame; - -pub fn resolve_symname(frame: Frame, - callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - unsafe { - let mut info: Dl_info = intrinsics::init(); - let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 || - info.dli_sname.is_null() { - None - } else { - CStr::from_ptr(info.dli_sname).to_str().ok() - }; - callback(symname) - } -} - -#[repr(C)] -struct Dl_info { - dli_fname: *const libc::c_char, - dli_fbase: *mut libc::c_void, - dli_sname: *const libc::c_char, - dli_saddr: *mut libc::c_void, -} - -extern { - fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; -} diff --git a/ctr-std/src/sys/horizon/backtrace/printing/mod.rs b/ctr-std/src/sys/horizon/backtrace/printing/mod.rs deleted file mode 100644 index caa6071..0000000 --- a/ctr-std/src/sys/horizon/backtrace/printing/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2014-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -mod dladdr; - -use sys::backtrace::BacktraceContext; -use sys_common::backtrace::Frame; -use io; - -#[cfg(target_os = "emscripten")] -pub use self::dladdr::resolve_symname; - -#[cfg(target_os = "emscripten")] -pub fn foreach_symbol_fileline(_: Frame, _: F, _: &BacktraceContext) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()> -{ - Ok(false) -} - -#[cfg(not(target_os = "emscripten"))] -pub use sys_common::gnu::libbacktrace::foreach_symbol_fileline; - -#[cfg(not(target_os = "emscripten"))] -pub fn resolve_symname(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()> -{ - ::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| { - if symname.is_some() { - callback(symname) - } else { - dladdr::resolve_symname(frame, callback, bc) - } - }, bc) -} diff --git a/ctr-std/src/sys/horizon/backtrace/tracing/backtrace_fn.rs b/ctr-std/src/sys/horizon/backtrace/tracing/backtrace_fn.rs deleted file mode 100644 index 6293eeb..0000000 --- a/ctr-std/src/sys/horizon/backtrace/tracing/backtrace_fn.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// As always - iOS on arm uses SjLj exceptions and -/// _Unwind_Backtrace is even not available there. Still, -/// backtraces could be extracted using a backtrace function, -/// which thanks god is public -/// -/// As mentioned in a huge comment block in `super::super`, backtrace -/// doesn't play well with green threads, so while it is extremely nice and -/// simple to use it should be used only on iOS devices as the only viable -/// option. - -use io; -use libc; -use sys::backtrace::BacktraceContext; -use sys_common::backtrace::Frame; - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - const FRAME_LEN: usize = 100; - assert!(FRAME_LEN >= frames.len()); - let mut raw_frames = [::ptr::null_mut(); FRAME_LEN]; - let nb_frames = unsafe { - backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int) - } as usize; - for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) { - *to = Frame { - exact_position: *from as *mut u8, - symbol_addr: *from as *mut u8, - inline_context: 0, - }; - } - Ok((nb_frames as usize, BacktraceContext)) -} - -extern { - fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int; -} diff --git a/ctr-std/src/sys/horizon/backtrace/tracing/gcc_s.rs b/ctr-std/src/sys/horizon/backtrace/tracing/gcc_s.rs deleted file mode 100644 index 1b92fc0..0000000 --- a/ctr-std/src/sys/horizon/backtrace/tracing/gcc_s.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use error::Error; -use io; -use libc; -use sys::backtrace::BacktraceContext; -use sys_common::backtrace::Frame; - -use unwind as uw; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl ::fmt::Display for UnwindError { - fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - let mut cx = Context { - idx: 0, - frames, - }; - let result_unwind = unsafe { - uw::_Unwind_Backtrace(trace_fn, - &mut cx as *mut Context - as *mut libc::c_void) - }; - // See libunwind:src/unwind/Backtrace.c for the return values. - // No, there is no doc. - match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => { - Err(io::Error::new(io::ErrorKind::Other, - UnwindError(result_unwind))) - } - } -} - -extern fn trace_fn(ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { - let cx = unsafe { &mut *(arg as *mut Context) }; - let mut ip_before_insn = 0; - let mut ip = unsafe { - uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void - }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; - } - - // dladdr() on osx gets whiny when we use FindEnclosingFunction, and - // it appears to work fine without it, so we only use - // FindEnclosingFunction on non-osx platforms. In doing so, we get a - // slightly more accurate stack trace in the process. - // - // This is often because panic involves the last instruction of a - // function being "call std::rt::begin_unwind", with no ret - // instructions after it. This means that the return instruction - // pointer points *outside* of the calling function, and by - // unwinding it we go back to the original function. - let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { - ip - } else { - unsafe { uw::_Unwind_FindEnclosingFunction(ip) } - }; - - if cx.idx < cx.frames.len() { - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - } - - uw::_URC_NO_REASON -} diff --git a/ctr-std/src/sys/horizon/backtrace/tracing/mod.rs b/ctr-std/src/sys/horizon/backtrace/tracing/mod.rs deleted file mode 100644 index c9c8e26..0000000 --- a/ctr-std/src/sys/horizon/backtrace/tracing/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::imp::*; - -#[cfg(not(all(target_os = "ios", target_arch = "arm")))] -#[path = "gcc_s.rs"] -mod imp; -#[cfg(all(target_os = "ios", target_arch = "arm"))] -#[path = "backtrace_fn.rs"] -mod imp; diff --git a/ctr-std/src/sys/horizon/cmath.rs b/ctr-std/src/sys/horizon/cmath.rs deleted file mode 100644 index 2bc9665..0000000 --- a/ctr-std/src/sys/horizon/cmath.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg(not(test))] - -use libc::{c_float, c_double}; - -#[link_name = "m"] -extern { - pub fn acos(n: c_double) -> c_double; - pub fn acosf(n: c_float) -> c_float; - pub fn asin(n: c_double) -> c_double; - pub fn asinf(n: c_float) -> c_float; - pub fn atan(n: c_double) -> c_double; - pub fn atan2(a: c_double, b: c_double) -> c_double; - pub fn atan2f(a: c_float, b: c_float) -> c_float; - pub fn atanf(n: c_float) -> c_float; - pub fn cbrt(n: c_double) -> c_double; - pub fn cbrtf(n: c_float) -> c_float; - pub fn cosh(n: c_double) -> c_double; - pub fn coshf(n: c_float) -> c_float; - pub fn expm1(n: c_double) -> c_double; - pub fn expm1f(n: c_float) -> c_float; - pub fn fdim(a: c_double, b: c_double) -> c_double; - pub fn fdimf(a: c_float, b: c_float) -> c_float; - pub fn hypot(x: c_double, y: c_double) -> c_double; - pub fn hypotf(x: c_float, y: c_float) -> c_float; - pub fn log1p(n: c_double) -> c_double; - pub fn log1pf(n: c_float) -> c_float; - pub fn sinh(n: c_double) -> c_double; - pub fn sinhf(n: c_float) -> c_float; - pub fn tan(n: c_double) -> c_double; - pub fn tanf(n: c_float) -> c_float; - pub fn tanh(n: c_double) -> c_double; - pub fn tanhf(n: c_float) -> c_float; -} diff --git a/ctr-std/src/sys/horizon/condvar.rs b/ctr-std/src/sys/horizon/condvar.rs deleted file mode 100644 index f6cb49d..0000000 --- a/ctr-std/src/sys/horizon/condvar.rs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// *Implementation adapted from `/sys/redox/condvar.rs` - -use cell::UnsafeCell; -use intrinsics::atomic_cxchg; -use ptr; -use time::Duration; - -use sys::mutex::{self, Mutex}; - -pub struct Condvar { - lock: UnsafeCell<*mut ::libctru::LightLock>, -} - -unsafe impl Send for Condvar {} -unsafe impl Sync for Condvar {} - -impl Condvar { - pub const fn new() -> Condvar { - Condvar { - lock: UnsafeCell::new(ptr::null_mut()), - } - } - - #[inline] - pub unsafe fn init(&self) { - *self.lock.get() = ptr::null_mut(); - } - - #[inline] - pub fn notify_one(&self) { - unsafe { - let arbiter = ::libctru::__sync_get_arbiter(); - - ::libctru::svcArbitrateAddress(arbiter, - *self.lock.get() as u32, - ::libctru::ARBITRATION_SIGNAL, - 1, - 0); - } - } - - #[inline] - pub fn notify_all(&self) { - unsafe { - let lock = self.lock.get(); - - if *lock == ptr::null_mut() { - return; - } - - let arbiter = ::libctru::__sync_get_arbiter(); - - ::libctru::svcArbitrateAddress(arbiter, - *self.lock.get() as u32, - ::libctru::ARBITRATION_SIGNAL, - -1, - 0); - } - } - - #[inline] - pub fn wait(&self, mutex: &Mutex) { - unsafe { - let lock = self.lock.get(); - - if *lock != mutex::raw(mutex) as *mut i32 { - if *lock != ptr::null_mut() { - panic!("Condvar used with more than one Mutex"); - } - - atomic_cxchg(lock as *mut usize, 0, mutex::raw(mutex) as usize); - } - - mutex.unlock(); - - let arbiter = ::libctru::__sync_get_arbiter(); - - ::libctru::svcArbitrateAddress(arbiter, - *self.lock.get() as u32, - ::libctru::ARBITRATION_WAIT_IF_LESS_THAN, - 2, - 0); - - mutex.lock(); - } - } - - #[inline] - pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - use time::Instant; - - unsafe { - let lock = self.lock.get(); - - if *lock != mutex::raw(mutex) as *mut i32 { - if *lock != ptr::null_mut() { - panic!("Condvar used with more than one Mutex"); - } - - atomic_cxchg(lock as *mut usize, 0, mutex::raw(mutex) as usize); - } - - let now = Instant::now(); - - let nanos = dur.as_secs() - .saturating_mul(1_000_000_000) - .saturating_add(dur.subsec_nanos() as u64); - - mutex.unlock(); - - let arbiter = ::libctru::__sync_get_arbiter(); - - ::libctru::svcArbitrateAddress(arbiter, - *self.lock.get() as u32, - ::libctru::ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, - 2, - nanos as i64); - - mutex.lock(); - - now.elapsed() < dur - } - } - - #[inline] - pub unsafe fn destroy(&self) { - *self.lock.get() = ptr::null_mut(); - } -} \ No newline at end of file diff --git a/ctr-std/src/sys/horizon/env.rs b/ctr-std/src/sys/horizon/env.rs deleted file mode 100644 index 5e2fe38..0000000 --- a/ctr-std/src/sys/horizon/env.rs +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[cfg(target_os = "horizon")] -pub mod os { - pub const FAMILY: &'static str = "nintendo"; - pub const OS: &'static str = "horizon"; - pub const DLL_PREFIX: &'static str = ""; - pub const DLL_SUFFIX: &'static str = ".cro"; - pub const DLL_EXTENSION: &'static str = ".cro"; - pub const EXE_SUFFIX: &'static str = ".3dsx"; - pub const EXE_EXTENSION: &'static str = "3dsx"; -} - -#[cfg(target_os = "linux")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "linux"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "macos")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "macos"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".dylib"; - pub const DLL_EXTENSION: &'static str = "dylib"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "ios")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "ios"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".dylib"; - pub const DLL_EXTENSION: &'static str = "dylib"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "freebsd")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "freebsd"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "dragonfly")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "dragonfly"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "bitrig")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "bitrig"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "netbsd")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "netbsd"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "openbsd")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "openbsd"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "android")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "android"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "solaris")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "solaris"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "haiku")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "haiku"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "emscripten"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ".js"; - pub const EXE_EXTENSION: &'static str = "js"; -} - -#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "emscripten"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ".js"; - pub const EXE_EXTENSION: &'static str = "js"; -} - -#[cfg(target_os = "fuchsia")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "fuchsia"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "l4re")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "l4re"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} diff --git a/ctr-std/src/sys/horizon/ext/ffi.rs b/ctr-std/src/sys/horizon/ext/ffi.rs deleted file mode 100644 index 8347145..0000000 --- a/ctr-std/src/sys/horizon/ext/ffi.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific extension to the primitives in the `std::ffi` module - -#![stable(feature = "rust1", since = "1.0.0")] - -use ffi::{OsStr, OsString}; -use mem; -use sys::os_str::Buf; -use sys_common::{FromInner, IntoInner, AsInner}; - -/// Unix-specific extensions to [`OsString`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStringExt { - /// Creates an [`OsString`] from a byte vector. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// use std::os::unix::ffi::OsStringExt; - /// - /// let bytes = b"foo".to_vec(); - /// let os_string = OsString::from_vec(bytes); - /// assert_eq!(os_string.to_str(), Some("foo")); - /// ``` - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html - #[stable(feature = "rust1", since = "1.0.0")] - fn from_vec(vec: Vec) -> Self; - - /// Yields the underlying byte vector of this [`OsString`]. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// use std::os::unix::ffi::OsStringExt; - /// - /// let mut os_string = OsString::new(); - /// os_string.push("foo"); - /// let bytes = os_string.into_vec(); - /// assert_eq!(bytes, b"foo"); - /// ``` - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html - #[stable(feature = "rust1", since = "1.0.0")] - fn into_vec(self) -> Vec; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStringExt for OsString { - fn from_vec(vec: Vec) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec { - self.into_inner().inner - } -} - -/// Unix-specific extensions to [`OsStr`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStrExt { - #[stable(feature = "rust1", since = "1.0.0")] - /// Creates an [`OsStr`] from a byte slice. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// use std::os::unix::ffi::OsStrExt; - /// - /// let bytes = b"foo"; - /// let os_str = OsStr::from_bytes(bytes); - /// assert_eq!(os_str.to_str(), Some("foo")); - /// ``` - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html - fn from_bytes(slice: &[u8]) -> &Self; - - /// Gets the underlying byte view of the [`OsStr`] slice. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// use std::os::unix::ffi::OsStrExt; - /// - /// let mut os_str = OsStr::new("foo"); - /// let bytes = os_str.as_bytes(); - /// assert_eq!(bytes, b"foo"); - /// ``` - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html - #[stable(feature = "rust1", since = "1.0.0")] - fn as_bytes(&self) -> &[u8]; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } -} diff --git a/ctr-std/src/sys/horizon/ext/fs.rs b/ctr-std/src/sys/horizon/ext/fs.rs deleted file mode 100644 index 29f2542..0000000 --- a/ctr-std/src/sys/horizon/ext/fs.rs +++ /dev/null @@ -1,736 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific extensions to primitives in the `std::fs` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use fs::{self, Permissions, OpenOptions}; -use io; -use libc; -use path::Path; -use sys; -use sys_common::{FromInner, AsInner, AsInnerMut}; -use sys::platform::fs::MetadataExt as UnixMetadataExt; - -/// Unix-specific extensions to [`File`]. -/// -/// [`File`]: ../../../../std/fs/struct.File.html -#[stable(feature = "file_offset", since = "1.15.0")] -pub trait FileExt { - /// Reads a number of bytes starting from a given offset. - /// - /// Returns the number of bytes read. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// Note that similar to [`File::read`], it is not an error to return with a - /// short read. - /// - /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs::File; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let mut buf = [0u8; 8]; - /// let file = File::open("foo.txt")?; - /// - /// // We now read 8 bytes from the offset 10. - /// let num_bytes_read = file.read_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", num_bytes_read, buf); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result; - - /// Writes a number of bytes starting from a given offset. - /// - /// Returns the number of bytes written. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// When writing beyond the end of the file, the file is appropriately - /// extended and the intermediate bytes are initialized with the value 0. - /// - /// Note that similar to [`File::write`], it is not an error to return a - /// short write. - /// - /// [`File::write`]: ../../../../std/fs/struct.File.html#write.v - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let file = File::open("foo.txt")?; - /// - /// // We now write at the offset 10. - /// file.write_at(b"sushi", 10)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn write_at(&self, buf: &[u8], offset: u64) -> io::Result; -} - -#[stable(feature = "file_offset", since = "1.15.0")] -impl FileExt for fs::File { - fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - self.as_inner().read_at(buf, offset) - } - fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - self.as_inner().write_at(buf, offset) - } -} - -/// Unix-specific extensions to [`fs::Permissions`]. -/// -/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait PermissionsExt { - /// Returns the underlying raw `st_mode` bits that contain the standard - /// Unix permissions for this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let permissions = metadata.permissions(); - /// - /// println!("permissions: {}", permissions.mode()); - /// Ok(()) } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&self) -> u32; - - /// Sets the underlying raw bits for this set of permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); - /// - /// permissions.set_mode(0o644); // Read/write for owner and read for others. - /// assert_eq!(permissions.mode(), 0o644); - /// Ok(()) } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn set_mode(&mut self, mode: u32); - - /// Creates a new instance of `Permissions` from the given set of Unix - /// permission bits. - /// - /// # Examples - /// - /// ``` - /// use std::fs::Permissions; - /// use std::os::unix::fs::PermissionsExt; - /// - /// // Read/write for owner and read for others. - /// let permissions = Permissions::from_mode(0o644); - /// assert_eq!(permissions.mode(), 0o644); - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn from_mode(mode: u32) -> Self; -} - -#[stable(feature = "fs_ext", since = "1.1.0")] -impl PermissionsExt for Permissions { - fn mode(&self) -> u32 { - self.as_inner().mode() - } - - fn set_mode(&mut self, mode: u32) { - *self = Permissions::from_inner(FromInner::from_inner(mode)); - } - - fn from_mode(mode: u32) -> Permissions { - Permissions::from_inner(FromInner::from_inner(mode)) - } -} - -/// Unix-specific extensions to [`fs::OpenOptions`]. -/// -/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait OpenOptionsExt { - /// Sets the mode bits that a new file will be created with. - /// - /// If a new file is created as part of a `File::open_opts` call then this - /// specified `mode` will be used as the permission bits for the new file. - /// If no `mode` is set, the default of `0o666` will be used. - /// The operating system masks out bits with the systems `umask`, to produce - /// the final permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// use std::os::unix::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.mode(0o644); // Give read/write for owner and read for others. - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&mut self, mode: u32) -> &mut Self; - - /// Pass custom flags to the `flags` argument of `open`. - /// - /// The bits that define the access mode are masked out with `O_ACCMODE`, to - /// ensure they do not interfere with the access mode set by Rusts options. - /// - /// Custom flags can only set flags, not remove flags set by Rusts options. - /// This options overwrites any previously set custom flags. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(libc)] - /// extern crate libc; - /// use std::fs::OpenOptions; - /// use std::os::unix::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.write(true); - /// if cfg!(unix) { - /// options.custom_flags(libc::O_NOFOLLOW); - /// } - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn custom_flags(&mut self, flags: i32) -> &mut Self; -} - -#[stable(feature = "fs_ext", since = "1.1.0")] -impl OpenOptionsExt for OpenOptions { - fn mode(&mut self, mode: u32) -> &mut OpenOptions { - self.as_inner_mut().mode(mode); self - } - - fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { - self.as_inner_mut().custom_flags(flags); self - } -} - -/// Unix-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Returns the ID of the device containing the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let dev_id = meta.dev(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn dev(&self) -> u64; - /// Returns the inode number. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let inode = meta.ino(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ino(&self) -> u64; - /// Returns the rights applied to this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let mode = meta.mode(); - /// let user_has_write_access = mode & 0o200; - /// let user_has_read_write_access = mode & 0o600; - /// let group_has_read_access = mode & 0o040; - /// let others_have_exec_access = mode & 0o001; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mode(&self) -> u32; - /// Returns the number of hard links pointing to this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nb_hard_links = meta.nlink(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn nlink(&self) -> u64; - /// Returns the user ID of the owner of this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let user_id = meta.uid(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn uid(&self) -> u32; - /// Returns the group ID of the owner of this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let group_id = meta.gid(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn gid(&self) -> u32; - /// Returns the device ID of this file (if it is a special one). - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let device_id = meta.rdev(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn rdev(&self) -> u64; - /// Returns the total size of this file in bytes. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let file_size = meta.size(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn size(&self) -> u64; - /// Returns the time of the last access to the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_access_time = meta.atime(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn atime(&self) -> i64; - /// Returns the time of the last access to the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_access_time = meta.atime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn atime_nsec(&self) -> i64; - /// Returns the time of the last modification of the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_modification_time = meta.mtime(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mtime(&self) -> i64; - /// Returns the time of the last modification of the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_modification_time = meta.mtime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mtime_nsec(&self) -> i64; - /// Returns the time of the last status change of the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_status_change_time = meta.ctime(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ctime(&self) -> i64; - /// Returns the time of the last status change of the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_status_change_time = meta.ctime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ctime_nsec(&self) -> i64; - /// Returns the blocksize for filesystem I/O. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let blocksize = meta.blksize(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blksize(&self) -> u64; - /// Returns the number of blocks allocated to the file, in 512-byte units. - /// - /// Please note that this may be smaller than `st_size / 512` when the file has holes. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let blocks = meta.blocks(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blocks(&self) -> u64; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for fs::Metadata { - fn dev(&self) -> u64 { self.st_dev() } - fn ino(&self) -> u64 { self.st_ino() } - fn mode(&self) -> u32 { self.st_mode() } - fn nlink(&self) -> u64 { self.st_nlink() } - fn uid(&self) -> u32 { self.st_uid() } - fn gid(&self) -> u32 { self.st_gid() } - fn rdev(&self) -> u64 { self.st_rdev() } - fn size(&self) -> u64 { self.st_size() } - fn atime(&self) -> i64 { self.st_atime() } - fn atime_nsec(&self) -> i64 { self.st_atime_nsec() } - fn mtime(&self) -> i64 { self.st_mtime() } - fn mtime_nsec(&self) -> i64 { self.st_mtime_nsec() } - fn ctime(&self) -> i64 { self.st_ctime() } - fn ctime_nsec(&self) -> i64 { self.st_ctime_nsec() } - fn blksize(&self) -> u64 { self.st_blksize() } - fn blocks(&self) -> u64 { self.st_blocks() } -} - -/// Unix-specific extensions for [`FileType`]. -/// -/// Adds support for special Unix file types such as block/character devices, -/// pipes, and sockets. -/// -/// [`FileType`]: ../../../../std/fs/struct.FileType.html -#[stable(feature = "file_type_ext", since = "1.5.0")] -pub trait FileTypeExt { - /// Returns whether this file type is a block device. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("block_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_block_device()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_block_device(&self) -> bool; - /// Returns whether this file type is a char device. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("char_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_char_device()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_char_device(&self) -> bool; - /// Returns whether this file type is a fifo. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("fifo_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_fifo()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_fifo(&self) -> bool; - /// Returns whether this file type is a socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("unix.socket")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_socket()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_socket(&self) -> bool; -} - -#[stable(feature = "file_type_ext", since = "1.5.0")] -impl FileTypeExt for fs::FileType { - fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) } - fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) } - fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) } - fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) } -} - -/// Unix-specific extension methods for [`fs::DirEntry`]. -/// -/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html -#[stable(feature = "dir_entry_ext", since = "1.1.0")] -pub trait DirEntryExt { - /// Returns the underlying `d_ino` field in the contained `dirent` - /// structure. - /// - /// # Examples - /// - /// ``` - /// use std::fs; - /// use std::os::unix::fs::DirEntryExt; - /// - /// if let Ok(entries) = fs::read_dir(".") { - /// for entry in entries { - /// if let Ok(entry) = entry { - /// // Here, `entry` is a `DirEntry`. - /// println!("{:?}: {}", entry.file_name(), entry.ino()); - /// } - /// } - /// } - /// ``` - #[stable(feature = "dir_entry_ext", since = "1.1.0")] - fn ino(&self) -> u64; -} - -#[stable(feature = "dir_entry_ext", since = "1.1.0")] -impl DirEntryExt for fs::DirEntry { - fn ino(&self) -> u64 { 0u64 } -} - -/// Creates a new symbolic link on the filesystem. -/// -/// The `dst` path will be a symbolic link pointing to the `src` path. -/// -/// # Note -/// -/// On Windows, you must specify whether a symbolic link points to a file -/// or directory. Use `os::windows::fs::symlink_file` to create a -/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a -/// symbolic link to a directory. Additionally, the process must have -/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a -/// symbolic link. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::symlink("a.txt", "b.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> -{ - sys::fs::symlink(src.as_ref(), dst.as_ref()) -} - -/// Unix-specific extensions to [`fs::DirBuilder`]. -/// -/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html -#[stable(feature = "dir_builder", since = "1.6.0")] -pub trait DirBuilderExt { - /// Sets the mode to create new directories with. This option defaults to - /// 0o777. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::DirBuilder; - /// use std::os::unix::fs::DirBuilderExt; - /// - /// let mut builder = DirBuilder::new(); - /// builder.mode(0o755); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - fn mode(&mut self, mode: u32) -> &mut Self; -} - -#[stable(feature = "dir_builder", since = "1.6.0")] -impl DirBuilderExt for fs::DirBuilder { - fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { - self.as_inner_mut().set_mode(mode); - self - } -} diff --git a/ctr-std/src/sys/horizon/ext/io.rs b/ctr-std/src/sys/horizon/ext/io.rs deleted file mode 100644 index c9fe359..0000000 --- a/ctr-std/src/sys/horizon/ext/io.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific extensions to general I/O primitives - -#![stable(feature = "rust1", since = "1.0.0")] - -use fs; -use os::raw; -use sys; -use io; -use sys_common::{AsInner, FromInner, IntoInner}; -use libc; - -/// Raw file descriptors. -#[stable(feature = "rust1", since = "1.0.0")] -pub type RawFd = raw::c_int; - -/// A trait to extract the raw unix file descriptor from an underlying -/// object. -/// -/// This is only available on unix platforms and must be imported in order -/// to call the method. Windows platforms have a corresponding `AsRawHandle` -/// and `AsRawSocket` set of traits. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsRawFd { - /// Extracts the raw file descriptor. - /// - /// This method does **not** pass ownership of the raw file descriptor - /// to the caller. The descriptor is only guaranteed to be valid while - /// the original object has not yet been destroyed. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_fd(&self) -> RawFd; -} - -/// A trait to express the ability to construct an object from a raw file -/// descriptor. -#[stable(feature = "from_raw_os", since = "1.1.0")] -pub trait FromRawFd { - /// Constructs a new instance of `Self` from the given raw file - /// descriptor. - /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - #[stable(feature = "from_raw_os", since = "1.1.0")] - unsafe fn from_raw_fd(fd: RawFd) -> Self; -} - -/// A trait to express the ability to consume an object and acquire ownership of -/// its raw file descriptor. -#[stable(feature = "into_raw_os", since = "1.4.0")] -pub trait IntoRawFd { - /// Consumes this object, returning the raw underlying file descriptor. - /// - /// This function **transfers ownership** of the underlying file descriptor - /// to the caller. Callers are then the unique owners of the file descriptor - /// and must close the descriptor once it's no longer needed. - #[stable(feature = "into_raw_os", since = "1.4.0")] - fn into_raw_fd(self) -> RawFd; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for fs::File { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for fs::File { - unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs::File::from_inner(fd)) - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for fs::File { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdin { - fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdout { - fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stderr { - fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO } -} diff --git a/ctr-std/src/sys/horizon/ext/mod.rs b/ctr-std/src/sys/horizon/ext/mod.rs deleted file mode 100644 index 49d2a31..0000000 --- a/ctr-std/src/sys/horizon/ext/mod.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Experimental extensions to `std` for Unix platforms. -//! -//! Provides access to platform-level information on Unix platforms, and -//! exposes Unix-specific functions that would otherwise be inappropriate as -//! part of the core `std` library. -//! -//! It exposes more ways to deal with platform-specific strings (`OsStr`, -//! `OsString`), allows to set permissions more granularly, extract low-level -//! file descriptors from files and sockets, and has platform-specific helpers -//! for spawning processes. -//! -//! # Examples -//! -//! ```no_run -//! use std::fs::File; -//! use std::os::unix::prelude::*; -//! -//! fn main() { -//! let f = File::create("foo.txt").unwrap(); -//! let fd = f.as_raw_fd(); -//! -//! // use fd with native unix bindings -//! } -//! ``` - -#![stable(feature = "rust1", since = "1.0.0")] -#![doc(cfg(unix))] - -pub mod io; -pub mod ffi; -pub mod fs; -pub mod raw; - -/// A prelude for conveniently writing platform-specific code. -/// -/// Includes all extension traits, and some important type definitions. -#[stable(feature = "rust1", since = "1.0.0")] -pub mod prelude { - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::fs::DirEntryExt; - #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")] - pub use super::fs::FileExt; -} diff --git a/ctr-std/src/sys/horizon/ext/raw.rs b/ctr-std/src/sys/horizon/ext/raw.rs deleted file mode 100644 index 7972990..0000000 --- a/ctr-std/src/sys/horizon/ext/raw.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific primitives available on all unix platforms - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type uid_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type gid_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type pid_t = i32; - -#[doc(inline)] -#[stable(feature = "pthread_t", since = "1.8.0")] -pub use sys::platform::raw::pthread_t; -#[doc(inline)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub use sys::platform::raw::{dev_t, ino_t, mode_t, nlink_t, off_t, blksize_t}; -#[doc(inline)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub use sys::platform::raw::{blkcnt_t, time_t}; diff --git a/ctr-std/src/sys/horizon/fast_thread_local.rs b/ctr-std/src/sys/horizon/fast_thread_local.rs deleted file mode 100644 index 6cdbe5d..0000000 --- a/ctr-std/src/sys/horizon/fast_thread_local.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg(target_thread_local)] -#![unstable(feature = "thread_local_internals", issue = "0")] - -// Since what appears to be glibc 2.18 this symbol has been shipped which -// GCC and clang both use to invoke destructors in thread_local globals, so -// let's do the same! -// -// Note, however, that we run on lots older linuxes, as well as cross -// compiling from a newer linux to an older linux, so we also have a -// fallback implementation to use as well. -// -// Due to rust-lang/rust#18804, make sure this is not generic! -#[cfg(target_os = "linux")] -pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - use libc; - use mem; - use sys_common::thread_local::register_dtor_fallback; - - extern { - #[linkage = "extern_weak"] - static __dso_handle: *mut u8; - #[linkage = "extern_weak"] - static __cxa_thread_atexit_impl: *const libc::c_void; - } - if !__cxa_thread_atexit_impl.is_null() { - type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), - arg: *mut u8, - dso_handle: *mut u8) -> libc::c_int; - mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) - (dtor, t, &__dso_handle as *const _ as *mut _); - return - } - register_dtor_fallback(t, dtor); -} - -// macOS's analog of the above linux function is this _tlv_atexit function. -// The disassembly of thread_local globals in C++ (at least produced by -// clang) will have this show up in the output. -#[cfg(target_os = "macos")] -pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - extern { - fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), - arg: *mut u8); - } - _tlv_atexit(dtor, t); -} - -// Just use the thread_local fallback implementation, at least until there's -// a more direct implementation. -#[cfg(target_os = "fuchsia")] -pub use sys_common::thread_local::register_dtor_fallback as register_dtor; - -pub fn requires_move_before_drop() -> bool { - // The macOS implementation of TLS apparently had an odd aspect to it - // where the pointer we have may be overwritten while this destructor - // is running. Specifically if a TLS destructor re-accesses TLS it may - // trigger a re-initialization of all TLS variables, paving over at - // least some destroyed ones with initial values. - // - // This means that if we drop a TLS value in place on macOS that we could - // revert the value to its original state halfway through the - // destructor, which would be bad! - // - // Hence, we use `ptr::read` on macOS (to move to a "safe" location) - // instead of drop_in_place. - cfg!(target_os = "macos") -} diff --git a/ctr-std/src/sys/horizon/fd.rs b/ctr-std/src/sys/horizon/fd.rs deleted file mode 100644 index 8925e72..0000000 --- a/ctr-std/src/sys/horizon/fd.rs +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(reason = "not public", issue = "0", feature = "fd")] - -use cmp; -use io::{self, Read}; -use libc::{self, c_int, c_void, ssize_t}; -use mem; -use sync::atomic::{AtomicBool, Ordering}; -use sys::cvt; -use sys_common::AsInner; - -#[derive(Debug)] -pub struct FileDesc { - fd: c_int, -} - -fn max_len() -> usize { - // The maximum read limit on most posix-like systems is `SSIZE_MAX`, - // with the man page quoting that if the count of bytes to read is - // greater than `SSIZE_MAX` the result is "unspecified". - // - // On macOS, however, apparently the 64-bit libc is either buggy or - // intentionally showing odd behavior by rejecting any read with a size - // larger than or equal to INT_MAX. To handle both of these the read - // size is capped on both platforms. - if cfg!(target_os = "macos") { - ::max_value() as usize - 1 - } else { - ::max_value() as usize - } -} - -impl FileDesc { - pub fn new(fd: c_int) -> FileDesc { - FileDesc { fd: fd } - } - - pub fn raw(&self) -> c_int { self.fd } - - /// Extracts the actual filedescriptor without closing it. - pub fn into_raw(self) -> c_int { - let fd = self.fd; - mem::forget(self); - fd - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - let ret = cvt(unsafe { - libc::read(self.fd, - buf.as_mut_ptr() as *mut c_void, - cmp::min(buf.len(), max_len())) - })?; - Ok(ret as usize) - } - - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - let mut me = self; - (&mut me).read_to_end(buf) - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - #[cfg(target_os = "android")] - use super::android::cvt_pread64; - - #[cfg(target_os = "emscripten")] - unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) - -> io::Result - { - use convert::TryInto; - use libc::pread64; - // pread64 on emscripten actually takes a 32 bit offset - if let Ok(o) = offset.try_into() { - cvt(pread64(fd, buf, count, o)) - } else { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot pread >2GB")) - } - } - - #[cfg(not(any(target_os = "android", target_os = "emscripten")))] - unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) - -> io::Result - { - #[cfg(target_os = "linux")] - use libc::pread64; - #[cfg(not(target_os = "linux"))] - use libc::pread as pread64; - cvt(pread64(fd, buf, count, offset)) - } - - unsafe { - cvt_pread64(self.fd, - buf.as_mut_ptr() as *mut c_void, - cmp::min(buf.len(), max_len()), - offset as i64) - .map(|n| n as usize) - } - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - let ret = cvt(unsafe { - libc::write(self.fd, - buf.as_ptr() as *const c_void, - cmp::min(buf.len(), max_len())) - })?; - Ok(ret as usize) - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - #[cfg(target_os = "android")] - use super::android::cvt_pwrite64; - - #[cfg(target_os = "emscripten")] - unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) - -> io::Result - { - use convert::TryInto; - use libc::pwrite64; - // pwrite64 on emscripten actually takes a 32 bit offset - if let Ok(o) = offset.try_into() { - cvt(pwrite64(fd, buf, count, o)) - } else { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot pwrite >2GB")) - } - } - - #[cfg(not(any(target_os = "android", target_os = "emscripten")))] - unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) - -> io::Result - { - #[cfg(target_os = "linux")] - use libc::pwrite64; - #[cfg(not(target_os = "linux"))] - use libc::pwrite as pwrite64; - cvt(pwrite64(fd, buf, count, offset)) - } - - unsafe { - cvt_pwrite64(self.fd, - buf.as_ptr() as *const c_void, - cmp::min(buf.len(), max_len()), - offset as i64) - .map(|n| n as usize) - } - } - - // We don't have fork/exec on the 3DS, so this shouldn't need to do anything - #[cfg(target_os = "horizon")] - pub fn set_cloexec(&self) -> io::Result<()> { - Ok(()) - } - - #[cfg(target_os = "linux")] - pub fn get_cloexec(&self) -> io::Result { - unsafe { - Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) - } - } - - #[cfg(target_os = "linux")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - unsafe { - let v = nonblocking as c_int; - cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?; - Ok(()) - } - } - - #[cfg(not(target_os = "linux"))] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - unsafe { - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?; - let new = if nonblocking { - previous | libc::O_NONBLOCK - } else { - previous & !libc::O_NONBLOCK - }; - if new != previous { - cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?; - } - Ok(()) - } - } - - pub fn duplicate(&self) -> io::Result { - // We want to atomically duplicate this file descriptor and set the - // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This - // flag, however, isn't supported on older Linux kernels (earlier than - // 2.6.24). - // - // To detect this and ensure that CLOEXEC is still set, we - // follow a strategy similar to musl [1] where if passing - // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not - // supported (the third parameter, 0, is always valid), so we stop - // trying that. - // - // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to - // resolve so we at least compile this. - // - // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963 - #[cfg(any(target_os = "android", target_os = "haiku"))] - use libc::F_DUPFD as F_DUPFD_CLOEXEC; - #[cfg(not(any(target_os = "android", target_os="haiku")))] - use libc::F_DUPFD_CLOEXEC; - - let make_filedesc = |fd| { - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - Ok(fd) - }; - static TRY_CLOEXEC: AtomicBool = - AtomicBool::new(!cfg!(target_os = "android")); - let fd = self.raw(); - if TRY_CLOEXEC.load(Ordering::Relaxed) { - match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) { - // We *still* call the `set_cloexec` method as apparently some - // linux kernel at some point stopped setting CLOEXEC even - // though it reported doing so on F_DUPFD_CLOEXEC. - Ok(fd) => { - return Ok(if cfg!(target_os = "linux") { - make_filedesc(fd)? - } else { - FileDesc::new(fd) - }) - } - Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => { - TRY_CLOEXEC.store(false, Ordering::Relaxed); - } - Err(e) => return Err(e), - } - } - cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc) - } -} - -impl<'a> Read for &'a FileDesc { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (**self).read(buf) - } -} - -impl AsInner for FileDesc { - fn as_inner(&self) -> &c_int { &self.fd } -} - -impl Drop for FileDesc { - fn drop(&mut self) { - // Note that errors are ignored when closing a file descriptor. The - // reason for this is that if an error occurs we don't actually know if - // the file descriptor was closed or not, and if we retried (for - // something like EINTR), we might close another valid file descriptor - // (opened after we closed ours. - let _ = unsafe { libc::close(self.fd) }; - } -} diff --git a/ctr-std/src/sys/horizon/fs.rs b/ctr-std/src/sys/horizon/fs.rs deleted file mode 100644 index f370d9c..0000000 --- a/ctr-std/src/sys/horizon/fs.rs +++ /dev/null @@ -1,928 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use os::unix::prelude::*; - -use ffi::{CString, CStr, OsString, OsStr}; -use fmt; -use io::{self, Error, ErrorKind, SeekFrom}; -use libc::{self, c_int, mode_t}; -use mem; -use path::{Path, PathBuf}; -use ptr; -use sync::Arc; -use sys::fd::FileDesc; -use sys::time::SystemTime; -use sys::{cvt, cvt_r}; -use sys_common::{AsInner, FromInner}; - -#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))] -use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64}; -#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] -use libc::{fstatat, dirfd}; -#[cfg(target_os = "android")] -use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek64, - dirent as dirent64, open as open64}; -#[cfg(not(any(target_os = "linux", - target_os = "emscripten", - target_os = "l4re", - target_os = "android")))] -use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t, - ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64}; -#[cfg(not(any(target_os = "linux", - target_os = "emscripten", - target_os = "solaris", - target_os = "l4re", - target_os = "fuchsia")))] -use libc::{readdir_r as readdir64_r}; - -pub struct File(FileDesc); - -#[derive(Clone)] -pub struct FileAttr { - stat: stat64, -} - -// all DirEntry's will have a reference to this struct -struct InnerReadDir { - dirp: Dir, - root: PathBuf, -} - -#[derive(Clone)] -pub struct ReadDir(Arc); - -struct Dir(*mut libc::DIR); - -unsafe impl Send for Dir {} -unsafe impl Sync for Dir {} - -pub struct DirEntry { - entry: dirent64, - dir: ReadDir, - // We need to store an owned copy of the entry name - // on Solaris and Fuchsia because a) it uses a zero-length - // array to store the name, b) its lifetime between readdir - // calls is not guaranteed. - #[cfg(any(target_os = "solaris", target_os = "fuchsia"))] - name: Box<[u8]> -} - -#[derive(Clone, Debug)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - custom_flags: i32, - mode: mode_t, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct FilePermissions { mode: mode_t } - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct FileType { mode: mode_t } - -#[derive(Debug)] -pub struct DirBuilder { mode: mode_t } - -impl FileAttr { - pub fn size(&self) -> u64 { self.stat.st_size as u64 } - pub fn perm(&self) -> FilePermissions { - FilePermissions { mode: (self.stat.st_mode as mode_t) } - } - - pub fn file_type(&self) -> FileType { - FileType { mode: self.stat.st_mode as mode_t } - } -} - -#[cfg(target_os = "netbsd")] -impl FileAttr { - pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, - tv_nsec: self.stat.st_mtimensec as libc::c_long, - })) - } - - pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, - tv_nsec: self.stat.st_atimensec as libc::c_long, - })) - } - - pub fn created(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_birthtime as libc::time_t, - tv_nsec: self.stat.st_birthtimensec as libc::c_long, - })) - } -} - -#[cfg(not(target_os = "netbsd"))] -impl FileAttr { - pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, - tv_nsec: 0 as _, - })) - } - - pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, - tv_nsec: 0 as _, - })) - } - - #[cfg(any(target_os = "bitrig", - target_os = "freebsd", - target_os = "openbsd", - target_os = "macos", - target_os = "ios"))] - pub fn created(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_birthtime as libc::time_t, - tv_nsec: self.stat.st_birthtime_nsec as libc::c_long, - })) - } - - #[cfg(not(any(target_os = "bitrig", - target_os = "freebsd", - target_os = "openbsd", - target_os = "macos", - target_os = "ios")))] - pub fn created(&self) -> io::Result { - Err(io::Error::new(io::ErrorKind::Other, - "creation time is not available on this platform \ - currently")) - } -} - -impl AsInner for FileAttr { - fn as_inner(&self) -> &stat64 { &self.stat } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - // check if any class (owner, group, others) has write permission - self.mode & 0o222 == 0 - } - - pub fn set_readonly(&mut self, readonly: bool) { - if readonly { - // remove write permission for all classes; equivalent to `chmod a-w ` - self.mode &= !0o222; - } else { - // add write permission for all classes; equivalent to `chmod a+w ` - self.mode |= 0o222; - } - } - pub fn mode(&self) -> u32 { self.mode as u32 } -} - -impl FileType { - pub fn is_dir(&self) -> bool { self.is(libc::S_IFDIR) } - pub fn is_file(&self) -> bool { self.is(libc::S_IFREG) } - pub fn is_symlink(&self) -> bool { self.is(libc::S_IFLNK) } - - pub fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode } -} - -impl FromInner for FilePermissions { - fn from_inner(mode: u32) -> FilePermissions { - FilePermissions { mode: mode as mode_t } - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. - // Thus the result will be e g 'ReadDir("/home")' - fmt::Debug::fmt(&*self.0.root, f) - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - - #[cfg(any(target_os = "solaris", target_os = "fuchsia"))] - fn next(&mut self) -> Option> { - unsafe { - loop { - // Although readdir_r(3) would be a correct function to use here because - // of the thread safety, on Illumos and Fuchsia the readdir(3C) function - // is safe to use in threaded applications and it is generally preferred - // over the readdir_r(3C) function. - super::os::set_errno(0); - let entry_ptr = libc::readdir(self.0.dirp.0); - if entry_ptr.is_null() { - // NULL can mean either the end is reached or an error occurred. - // So we had to clear errno beforehand to check for an error now. - return match super::os::errno() { - 0 => None, - e => Some(Err(Error::from_raw_os_error(e))), - } - } - - let name = (*entry_ptr).d_name.as_ptr() as *const u8; - let namelen = libc::strlen(name) as usize; - - let ret = DirEntry { - entry: *entry_ptr, - name: ::slice::from_raw_parts(name as *const u8, - namelen as usize).to_owned().into_boxed_slice(), - dir: self.clone() - }; - if ret.name_bytes() != b"." && ret.name_bytes() != b".." { - return Some(Ok(ret)) - } - } - } - } - - #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))] - fn next(&mut self) -> Option> { - unsafe { - let mut ret = DirEntry { - entry: mem::zeroed(), - dir: self.clone(), - }; - let mut entry_ptr = ptr::null_mut(); - loop { - if readdir64_r(self.0.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { - return Some(Err(Error::last_os_error())) - } - if entry_ptr.is_null() { - return None - } - if ret.name_bytes() != b"." && ret.name_bytes() != b".." { - return Some(Ok(ret)) - } - } - } - } -} - -impl Drop for Dir { - fn drop(&mut self) { - let r = unsafe { libc::closedir(self.0) }; - debug_assert_eq!(r, 0); - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - self.dir.0.root.join(OsStr::from_bytes(self.name_bytes())) - } - - pub fn file_name(&self) -> OsString { - OsStr::from_bytes(self.name_bytes()).to_os_string() - } - - #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] - pub fn metadata(&self) -> io::Result { - let fd = cvt(unsafe {dirfd(self.dir.0.dirp.0)})?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { - fstatat(fd, - self.entry.d_name.as_ptr() as *const u8, - &mut stat as *mut _ as *mut _, - libc::AT_SYMLINK_NOFOLLOW) - })?; - Ok(FileAttr { stat: stat }) - } - - #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))] - pub fn metadata(&self) -> io::Result { - lstat(&self.path()) - } - - #[cfg(any(target_os = "solaris", target_os = "haiku"))] - pub fn file_type(&self) -> io::Result { - lstat(&self.path()).map(|m| m.file_type()) - } - - #[cfg(not(any(target_os = "solaris", target_os = "haiku")))] - pub fn file_type(&self) -> io::Result { - match self.entry.d_type { - libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), - libc::DT_FIFO => Ok(FileType { mode: libc::S_IFIFO }), - libc::DT_LNK => Ok(FileType { mode: libc::S_IFLNK }), - libc::DT_REG => Ok(FileType { mode: libc::S_IFREG }), - libc::DT_SOCK => Ok(FileType { mode: libc::S_IFSOCK }), - libc::DT_DIR => Ok(FileType { mode: libc::S_IFDIR }), - libc::DT_BLK => Ok(FileType { mode: libc::S_IFBLK }), - _ => lstat(&self.path()).map(|m| m.file_type()), - } - } - - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "linux", - target_os = "emscripten", - target_os = "android", - target_os = "solaris", - target_os = "haiku", - target_os = "l4re", - target_os = "fuchsia"))] - pub fn ino(&self) -> u64 { - self.entry.d_ino as u64 - } - - #[cfg(any(target_os = "freebsd", - target_os = "openbsd", - target_os = "bitrig", - target_os = "netbsd", - target_os = "dragonfly"))] - pub fn ino(&self) -> u64 { - self.entry.d_fileno as u64 - } - - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig"))] - fn name_bytes(&self) -> &[u8] { - unsafe { - ::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8 as *const u8, - self.entry.d_namlen as usize) - } - } - #[cfg(any(target_os = "android", - target_os = "linux", - target_os = "emscripten", - target_os = "l4re", - target_os = "haiku", - target_os = "horizon"))] - fn name_bytes(&self) -> &[u8] { - unsafe { - CStr::from_ptr(self.entry.d_name.as_ptr() as *const i8).to_bytes() - } - } - #[cfg(any(target_os = "solaris", - target_os = "fuchsia"))] - fn name_bytes(&self) -> &[u8] { - &*self.name - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - custom_flags: 0, - mode: 0o666, - } - } - - pub fn read(&mut self, read: bool) { self.read = read; } - pub fn write(&mut self, write: bool) { self.write = write; } - pub fn append(&mut self, append: bool) { self.append = append; } - pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; } - pub fn create(&mut self, create: bool) { self.create = create; } - pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; } - - pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; } - pub fn mode(&mut self, mode: u32) { self.mode = mode as mode_t; } - - fn get_access_mode(&self) -> io::Result { - match (self.read, self.write, self.append) { - (true, false, false) => Ok(libc::O_RDONLY), - (false, true, false) => Ok(libc::O_WRONLY), - (true, true, false) => Ok(libc::O_RDWR), - (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND), - (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND), - (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)), - } - } - - fn get_creation_mode(&self) -> io::Result { - match (self.write, self.append) { - (true, false) => {} - (false, false) => - if self.truncate || self.create || self.create_new { - return Err(Error::from_raw_os_error(libc::EINVAL)); - }, - (_, true) => - if self.truncate && !self.create_new { - return Err(Error::from_raw_os_error(libc::EINVAL)); - }, - } - - Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => 0, - (true, false, false) => libc::O_CREAT, - (false, true, false) => libc::O_TRUNC, - (true, true, false) => libc::O_CREAT | libc::O_TRUNC, - (_, _, true) => libc::O_CREAT | libc::O_EXCL, - }) - } -} - -impl File { - pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let path = cstr(path)?; - File::open_c(&path, opts) - } - - pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result { - let flags = libc::O_CLOEXEC | - opts.get_access_mode()? | - opts.get_creation_mode()? | - (opts.custom_flags as c_int & !libc::O_ACCMODE); - let fd = cvt_r(|| unsafe { - open64(path.as_ptr() as *const u8, flags, opts.mode as c_int) - })?; - let fd = FileDesc::new(fd); - - // Currently the standard library supports Linux 2.6.18 which did not - // have the O_CLOEXEC flag (passed above). If we're running on an older - // Linux kernel then the flag is just ignored by the OS. After we open - // the first file, we check whether it has CLOEXEC set. If it doesn't, - // we will explicitly ask for a CLOEXEC fd for every further file we - // open, if it does, we will skip that step. - // - // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc - // that we support, so we only do this on Linux currently. - #[cfg(target_os = "linux")] - fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> { - use sync::atomic::{AtomicUsize, Ordering}; - - const OPEN_CLOEXEC_UNKNOWN: usize = 0; - const OPEN_CLOEXEC_SUPPORTED: usize = 1; - const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2; - static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN); - - let need_to_set; - match OPEN_CLOEXEC.load(Ordering::Relaxed) { - OPEN_CLOEXEC_UNKNOWN => { - need_to_set = !fd.get_cloexec()?; - OPEN_CLOEXEC.store(if need_to_set { - OPEN_CLOEXEC_NOTSUPPORTED - } else { - OPEN_CLOEXEC_SUPPORTED - }, Ordering::Relaxed); - }, - OPEN_CLOEXEC_SUPPORTED => need_to_set = false, - OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true, - _ => unreachable!(), - } - if need_to_set { - fd.set_cloexec()?; - } - Ok(()) - } - - #[cfg(not(target_os = "linux"))] - fn ensure_cloexec(_: &FileDesc) -> io::Result<()> { - Ok(()) - } - - ensure_cloexec(&fd)?; - Ok(File(fd)) - } - - pub fn file_attr(&self) -> io::Result { - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { - fstat64(self.0.raw(), &mut stat) - })?; - Ok(FileAttr { stat: stat }) - } - - pub fn fsync(&self) -> io::Result<()> { - cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?; - Ok(()) - } - - pub fn datasync(&self) -> io::Result<()> { - cvt_r(|| unsafe { os_datasync(self.0.raw()) })?; - return Ok(()); - - #[cfg(any(target_os = "macos", target_os = "ios"))] - unsafe fn os_datasync(fd: c_int) -> c_int { - libc::fcntl(fd, libc::F_FULLFSYNC) - } - #[cfg(target_os = "linux")] - unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) } - #[cfg(not(any(target_os = "macos", - target_os = "ios", - target_os = "linux")))] - unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) } - } - - pub fn truncate(&self, size: u64) -> io::Result<()> { - #[cfg(target_os = "android")] - return ::sys::android::ftruncate64(self.0.raw(), size); - - #[cfg(not(target_os = "android"))] - return cvt_r(|| unsafe { - ftruncate64(self.0.raw(), size as off64_t) - }).map(|_| ()); - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - self.0.read_at(buf, offset) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - self.0.write_at(buf, offset) - } - - pub fn flush(&self) -> io::Result<()> { Ok(()) } - - pub fn seek(&self, pos: SeekFrom) -> io::Result { - let (whence, pos) = match pos { - // Casting to `i64` is fine, too large values will end up as - // negative which will cause an error in `lseek64`. - SeekFrom::Start(off) => (libc::SEEK_SET, off as i64), - SeekFrom::End(off) => (libc::SEEK_END, off), - SeekFrom::Current(off) => (libc::SEEK_CUR, off), - }; - #[cfg(target_os = "emscripten")] - let pos = pos as i32; - let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?; - Ok(n as u64) - } - - pub fn duplicate(&self) -> io::Result { - self.0.duplicate().map(File) - } - - pub fn fd(&self) -> &FileDesc { &self.0 } - - pub fn into_fd(self) -> FileDesc { self.0 } - - pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { - cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?; - Ok(()) - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder { mode: 0o777 } - } - - pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::mkdir(p.as_ptr() as *const u8, self.mode) })?; - Ok(()) - } - - pub fn set_mode(&mut self, mode: u32) { - self.mode = mode as mode_t; - } -} - -fn cstr(path: &Path) -> io::Result { - Ok(CString::new(path.as_os_str().as_bytes())?) -} - -impl FromInner for File { - fn from_inner(fd: c_int) -> File { - File(FileDesc::new(fd)) - } -} - -impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - #[cfg(target_os = "linux")] - fn get_path(fd: c_int) -> Option { - let mut p = PathBuf::from("/proc/self/fd"); - p.push(&fd.to_string()); - readlink(&p).ok() - } - - #[cfg(target_os = "macos")] - fn get_path(fd: c_int) -> Option { - // FIXME: The use of PATH_MAX is generally not encouraged, but it - // is inevitable in this case because macOS defines `fcntl` with - // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no - // alternatives. If a better method is invented, it should be used - // instead. - let mut buf = vec![0;libc::PATH_MAX as usize]; - let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr() as *const u8) }; - if n == -1 { - return None; - } - let l = buf.iter().position(|&c| c == 0).unwrap(); - buf.truncate(l as usize); - buf.shrink_to_fit(); - Some(PathBuf::from(OsString::from_vec(buf))) - } - - #[cfg(not(any(target_os = "linux", target_os = "macos")))] - fn get_path(_fd: c_int) -> Option { - // FIXME(#24570): implement this for other Unix platforms - None - } - - #[cfg(any(target_os = "linux", target_os = "macos"))] - fn get_mode(fd: c_int) -> Option<(bool, bool)> { - let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; - if mode == -1 { - return None; - } - match mode & libc::O_ACCMODE { - libc::O_RDONLY => Some((true, false)), - libc::O_RDWR => Some((true, true)), - libc::O_WRONLY => Some((false, true)), - _ => None - } - } - - #[cfg(not(any(target_os = "linux", target_os = "macos")))] - fn get_mode(_fd: c_int) -> Option<(bool, bool)> { - // FIXME(#24570): implement this for other Unix platforms - None - } - - let fd = self.0.raw(); - let mut b = f.debug_struct("File"); - b.field("fd", &fd); - if let Some(path) = get_path(fd) { - b.field("path", &path); - } - if let Some((read, write)) = get_mode(fd) { - b.field("read", &read).field("write", &write); - } - b.finish() - } -} - -pub fn readdir(p: &Path) -> io::Result { - let root = p.to_path_buf(); - let p = cstr(p)?; - unsafe { - let ptr = libc::opendir(p.as_ptr() as *const u8); - if ptr.is_null() { - Err(Error::last_os_error()) - } else { - let inner = InnerReadDir { dirp: Dir(ptr), root }; - Ok(ReadDir(Arc::new(inner))) - } - } -} - -pub fn unlink(p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::unlink(p.as_ptr() as *const u8) })?; - Ok(()) -} - -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = cstr(old)?; - let new = cstr(new)?; - cvt(unsafe { libc::rename(old.as_ptr() as *const u8, new.as_ptr() as *const u8) })?; - Ok(()) -} - -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = cstr(p)?; - cvt_r(|| unsafe { libc::chmod(p.as_ptr() as *const u8, perm.mode) })?; - Ok(()) -} - -pub fn rmdir(p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::rmdir(p.as_ptr() as *const u8) })?; - Ok(()) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { - unlink(path) - } else { - remove_dir_all_recursive(path) - } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - -pub fn readlink(p: &Path) -> io::Result { - let c_path = cstr(p)?; - let p = c_path.as_ptr() as *const u8; - - let mut buf = Vec::with_capacity(256); - - loop { - let buf_read = cvt(unsafe { - libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) - })? as usize; - - unsafe { buf.set_len(buf_read); } - - if buf_read != buf.capacity() { - buf.shrink_to_fit(); - - return Ok(PathBuf::from(OsString::from_vec(buf))); - } - - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. The length is guaranteed to be - // the same as the capacity due to the if statement above. - buf.reserve(1); - } -} - -pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; - cvt(unsafe { libc::symlink(src.as_ptr() as *const u8, dst.as_ptr() as *const u8) })?; - Ok(()) -} - -pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; - cvt(unsafe { libc::link(src.as_ptr() as *const u8, dst.as_ptr() as *const u8) })?; - Ok(()) -} - -pub fn stat(p: &Path) -> io::Result { - let p = cstr(p)?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { - stat64(p.as_ptr() as *const u8, &mut stat as *mut _ as *mut _) - })?; - Ok(FileAttr { stat: stat }) -} - -pub fn lstat(p: &Path) -> io::Result { - let p = cstr(p)?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { - lstat64(p.as_ptr() as *const u8, &mut stat as *mut _ as *mut _) - })?; - Ok(FileAttr { stat: stat }) -} - -pub fn canonicalize(p: &Path) -> io::Result { - let path = CString::new(p.as_os_str().as_bytes())?; - let buf; - unsafe { - let r = libc::realpath(path.as_ptr() as *const u8, ptr::null_mut()); - if r.is_null() { - return Err(io::Error::last_os_error()) - } - buf = CStr::from_ptr(r as *const i8).to_bytes().to_vec(); - libc::free(r as *mut _); - } - Ok(PathBuf::from(OsString::from_vec(buf))) -} - -#[cfg(not(any(target_os = "linux", target_os = "android")))] -pub fn copy(from: &Path, to: &Path) -> io::Result { - use fs::File; - if !from.is_file() { - return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing regular file")) - } - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let perm = reader.metadata()?.permissions(); - - let ret = io::copy(&mut reader, &mut writer)?; - writer.set_permissions(perm)?; - Ok(ret) -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -pub fn copy(from: &Path, to: &Path) -> io::Result { - use cmp; - use fs::File; - use sync::atomic::{AtomicBool, Ordering}; - - // Kernel prior to 4.5 don't have copy_file_range - // We store the availability in a global to avoid unneccessary syscalls - static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true); - - unsafe fn copy_file_range( - fd_in: libc::c_int, - off_in: *mut libc::loff_t, - fd_out: libc::c_int, - off_out: *mut libc::loff_t, - len: libc::size_t, - flags: libc::c_uint, - ) -> libc::c_long { - libc::syscall( - libc::SYS_copy_file_range, - fd_in, - off_in, - fd_out, - off_out, - len, - flags, - ) - } - - if !from.is_file() { - return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing regular file")) - } - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let (perm, len) = { - let metadata = reader.metadata()?; - (metadata.permissions(), metadata.size()) - }; - - let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); - let mut written = 0u64; - while written < len { - let copy_result = if has_copy_file_range { - let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize; - let copy_result = unsafe { - // We actually don't have to adjust the offsets, - // because copy_file_range adjusts the file offset automatically - cvt(copy_file_range(reader.as_raw_fd(), - ptr::null_mut(), - writer.as_raw_fd(), - ptr::null_mut(), - bytes_to_copy, - 0) - ) - }; - if let Err(ref copy_err) = copy_result { - match copy_err.raw_os_error() { - Some(libc::ENOSYS) | Some(libc::EPERM) => { - HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); - } - _ => {} - } - } - copy_result - } else { - Err(io::Error::from_raw_os_error(libc::ENOSYS)) - }; - match copy_result { - Ok(ret) => written += ret as u64, - Err(err) => { - match err.raw_os_error() { - Some(os_err) if os_err == libc::ENOSYS - || os_err == libc::EXDEV - || os_err == libc::EPERM => { - // Try fallback io::copy if either: - // - Kernel version is < 4.5 (ENOSYS) - // - Files are mounted on different fs (EXDEV) - // - copy_file_range is disallowed, for example by seccomp (EPERM) - assert_eq!(written, 0); - let ret = io::copy(&mut reader, &mut writer)?; - writer.set_permissions(perm)?; - return Ok(ret) - }, - _ => return Err(err), - } - } - } - } - writer.set_permissions(perm)?; - Ok(written) -} diff --git a/ctr-std/src/sys/horizon/l4re.rs b/ctr-std/src/sys/horizon/l4re.rs deleted file mode 100644 index 2121848..0000000 --- a/ctr-std/src/sys/horizon/l4re.rs +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright 2016-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -macro_rules! unimpl { - () => (return Err(io::Error::new(io::ErrorKind::Other, "No networking available on L4Re."));) -} - -pub mod net { - #![allow(warnings)] - use fmt; - use io; - use libc; - use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; - use sys_common::{AsInner, FromInner, IntoInner}; - use sys::fd::FileDesc; - use time::Duration; - - - pub extern crate libc as netc; - - pub struct Socket(FileDesc); - impl Socket { - pub fn new(_: &SocketAddr, _: libc::c_int) -> io::Result { - unimpl!(); - } - - pub fn new_raw(_: libc::c_int, _: libc::c_int) -> io::Result { - unimpl!(); - } - - pub fn new_pair(_: libc::c_int, _: libc::c_int) -> io::Result<(Socket, Socket)> { - unimpl!(); - } - - pub fn connect_timeout(&self, _: &SocketAddr, _: Duration) -> io::Result<()> { - unimpl!(); - } - - pub fn accept(&self, _: *mut libc::sockaddr, _: *mut libc::socklen_t) - -> io::Result { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn write(&self, _: &[u8]) -> io::Result { - unimpl!(); - } - - pub fn set_timeout(&self, _: Option, _: libc::c_int) -> io::Result<()> { - unimpl!(); - } - - pub fn timeout(&self, _: libc::c_int) -> io::Result> { - unimpl!(); - } - - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - unimpl!(); - } - - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn nodelay(&self) -> io::Result { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - } - - impl AsInner for Socket { - fn as_inner(&self) -> &libc::c_int { self.0.as_inner() } - } - - impl FromInner for Socket { - fn from_inner(fd: libc::c_int) -> Socket { Socket(FileDesc::new(fd)) } - } - - impl IntoInner for Socket { - fn into_inner(self) -> libc::c_int { self.0.into_raw() } - } - - pub struct TcpStream { - inner: Socket, - } - - impl TcpStream { - pub fn connect(_: &SocketAddr) -> io::Result { - unimpl!(); - } - - pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { - unimpl!(); - } - - pub fn socket(&self) -> &Socket { &self.inner } - - pub fn into_socket(self) -> Socket { self.inner } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn read_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn write_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn write(&self, _: &[u8]) -> io::Result { - unimpl!(); - } - - pub fn peer_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn socket_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn nodelay(&self) -> io::Result { - unimpl!(); - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn ttl(&self) -> io::Result { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - } - - impl FromInner for TcpStream { - fn from_inner(socket: Socket) -> TcpStream { - TcpStream { inner: socket } - } - } - - impl fmt::Debug for TcpStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "No networking support available on L4Re") - } - } - - pub struct TcpListener { - inner: Socket, - } - - impl TcpListener { - pub fn bind(_: &SocketAddr) -> io::Result { - unimpl!(); - } - - pub fn socket(&self) -> &Socket { &self.inner } - - pub fn into_socket(self) -> Socket { self.inner } - - pub fn socket_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn ttl(&self) -> io::Result { - unimpl!(); - } - - pub fn set_only_v6(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn only_v6(&self) -> io::Result { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - } - - impl FromInner for TcpListener { - fn from_inner(socket: Socket) -> TcpListener { - TcpListener { inner: socket } - } - } - - impl fmt::Debug for TcpListener { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "No networking support available on L4Re.") - } - } - - pub struct UdpSocket { - inner: Socket, - } - - impl UdpSocket { - pub fn bind(_: &SocketAddr) -> io::Result { - unimpl!(); - } - - pub fn socket(&self) -> &Socket { &self.inner } - - pub fn into_socket(self) -> Socket { self.inner } - - pub fn socket_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn read_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn write_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_broadcast(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn broadcast(&self) -> io::Result { - unimpl!(); - } - - pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn multicast_loop_v4(&self) -> io::Result { - unimpl!(); - } - - pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - unimpl!(); - } - - pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn multicast_loop_v6(&self) -> io::Result { - unimpl!(); - } - - pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) - -> io::Result<()> { - unimpl!(); - } - - pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) - -> io::Result<()> { - unimpl!(); - } - - pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) - -> io::Result<()> { - unimpl!(); - } - - pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) - -> io::Result<()> { - unimpl!(); - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn ttl(&self) -> io::Result { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn recv(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn send(&self, _: &[u8]) -> io::Result { - unimpl!(); - } - - pub fn connect(&self, _: &SocketAddr) -> io::Result<()> { - unimpl!(); - } - } - - impl FromInner for UdpSocket { - fn from_inner(socket: Socket) -> UdpSocket { - UdpSocket { inner: socket } - } - } - - impl fmt::Debug for UdpSocket { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "No networking support on L4Re available.") - } - } - - pub struct LookupHost { - original: *mut libc::addrinfo, - cur: *mut libc::addrinfo, - } - - impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option { - None - } - } - - unsafe impl Sync for LookupHost {} - unsafe impl Send for LookupHost {} - - pub fn lookup_host(_: &str) -> io::Result { - unimpl!(); - } -} - diff --git a/ctr-std/src/sys/horizon/memchr.rs b/ctr-std/src/sys/horizon/memchr.rs deleted file mode 100644 index f49adc2..0000000 --- a/ctr-std/src/sys/horizon/memchr.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// Original implementation taken from rust-memchr -// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch - -pub fn memchr(needle: u8, haystack: &[u8]) -> Option { - use libc; - - let p = unsafe { - libc::memchr( - haystack.as_ptr() as *const libc::c_void, - needle as libc::c_int, - haystack.len()) - }; - if p.is_null() { - None - } else { - Some(p as usize - (haystack.as_ptr() as usize)) - } -} - -pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { - - #[cfg(target_os = "linux")] - fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option { - use libc; - - // GNU's memrchr() will - unlike memchr() - error if haystack is empty. - if haystack.is_empty() {return None} - let p = unsafe { - libc::memrchr( - haystack.as_ptr() as *const libc::c_void, - needle as libc::c_int, - haystack.len()) - }; - if p.is_null() { - None - } else { - Some(p as usize - (haystack.as_ptr() as usize)) - } - } - - #[cfg(not(target_os = "linux"))] - fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option { - ::core::slice::memchr::memrchr(needle, haystack) - } - - memrchr_specific(needle, haystack) -} diff --git a/ctr-std/src/sys/horizon/mod.rs b/ctr-std/src/sys/horizon/mod.rs deleted file mode 100644 index efbe0bb..0000000 --- a/ctr-std/src/sys/horizon/mod.rs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(missing_docs, bad_style)] - -use io::{self, ErrorKind}; -use libc; - -#[cfg(any(dox, target_os = "linux"))] pub use os::linux as platform; - -#[cfg(all(not(dox), target_os = "android"))] pub use os::android as platform; -#[cfg(all(not(dox), target_os = "bitrig"))] pub use os::bitrig as platform; -#[cfg(all(not(dox), target_os = "dragonfly"))] pub use os::dragonfly as platform; -#[cfg(all(not(dox), target_os = "freebsd"))] pub use os::freebsd as platform; -#[cfg(all(not(dox), target_os = "haiku"))] pub use os::haiku as platform; -#[cfg(all(not(dox), target_os = "ios"))] pub use os::ios as platform; -#[cfg(all(not(dox), target_os = "macos"))] pub use os::macos as platform; -#[cfg(all(not(dox), target_os = "netbsd"))] pub use os::netbsd as platform; -#[cfg(all(not(dox), target_os = "openbsd"))] pub use os::openbsd as platform; -#[cfg(all(not(dox), target_os = "solaris"))] pub use os::solaris as platform; -#[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform; -#[cfg(all(not(dox), target_os = "fuchsia"))] pub use os::fuchsia as platform; -#[cfg(all(not(dox), target_os = "l4re"))] pub use os::linux as platform; -#[cfg(all(not(dox), target_os = "horizon"))] pub use os::horizon as platform; - -pub use self::rand::hashmap_random_keys; -pub use libc::strlen; - -#[macro_use] -pub mod weak; - -pub mod args; -pub mod android; -#[cfg(feature = "backtrace")] -pub mod backtrace; -pub mod cmath; -pub mod condvar; -pub mod env; -pub mod ext; -pub mod fast_thread_local; -pub mod fd; -pub mod fs; -pub mod memchr; -pub mod mutex; -#[cfg(not(target_os = "l4re"))] -pub mod net; -#[cfg(target_os = "l4re")] -mod l4re; -#[cfg(target_os = "l4re")] -pub use self::l4re::net; -pub mod os; -pub mod os_str; -pub mod path; -pub mod pipe; -pub mod process; -pub mod rand; -pub mod rwlock; -pub mod stack_overflow; -pub mod thread; -pub mod thread_local; -pub mod time; -pub mod stdio; - -#[cfg(not(test))] -pub fn init() { - // By default, some platforms will send a *signal* when an EPIPE error - // would otherwise be delivered. This runtime doesn't install a SIGPIPE - // handler, causing it to kill the program, which isn't exactly what we - // want! - // - // Hence, we set SIGPIPE to ignore when the program starts up in order - // to prevent this problem. - unsafe { - reset_sigpipe(); - } - - #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] - unsafe fn reset_sigpipe() { - assert!(signal(0 as _, libc::SIG_IGN) != libc::SIG_ERR); - } - #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))] - unsafe fn reset_sigpipe() {} -} - -#[cfg(target_os = "android")] -pub use sys::android::signal; -#[cfg(not(target_os = "android"))] -pub use libc::signal; - -pub fn unsupported() -> io::Result { - Err(unsupported_err()) -} - -pub fn unsupported_err() -> io::Error { - io::Error::new(io::ErrorKind::Other, - "operation not supported on 3DS yet") -} - -#[derive(Copy,Clone)] -pub enum Void {} - -pub fn decode_error_kind(errno: i32) -> ErrorKind { - match errno as libc::c_int { - libc::ECONNREFUSED => ErrorKind::ConnectionRefused, - libc::ECONNRESET => ErrorKind::ConnectionReset, - libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied, - libc::EPIPE => ErrorKind::BrokenPipe, - libc::ENOTCONN => ErrorKind::NotConnected, - libc::ECONNABORTED => ErrorKind::ConnectionAborted, - libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, - libc::EADDRINUSE => ErrorKind::AddrInUse, - libc::ENOENT => ErrorKind::NotFound, - libc::EINTR => ErrorKind::Interrupted, - libc::EINVAL => ErrorKind::InvalidInput, - libc::ETIMEDOUT => ErrorKind::TimedOut, - libc::EEXIST => ErrorKind::AlreadyExists, - - // These two constants can have the same value on some systems, - // but different values on others, so we can't use a match - // clause - x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => - ErrorKind::WouldBlock, - - _ => ErrorKind::Other, - } -} - -#[doc(hidden)] -pub trait IsMinusOne { - fn is_minus_one(&self) -> bool; -} - -macro_rules! impl_is_minus_one { - ($($t:ident)*) => ($(impl IsMinusOne for $t { - fn is_minus_one(&self) -> bool { - *self == -1 - } - })*) -} - -impl_is_minus_one! { i8 i16 i32 i64 isize } - -pub fn cvt(t: T) -> io::Result { - if t.is_minus_one() { - Err(io::Error::last_os_error()) - } else { - Ok(t) - } -} - -pub fn cvt_r(mut f: F) -> io::Result - where T: IsMinusOne, - F: FnMut() -> T -{ - loop { - match cvt(f()) { - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - other => return other, - } - } -} - -// On Unix-like platforms, libc::abort will unregister signal handlers -// including the SIGABRT handler, preventing the abort from being blocked, and -// fclose streams, with the side effect of flushing them so libc bufferred -// output will be printed. Additionally the shell will generally print a more -// understandable error message like "Abort trap" rather than "Illegal -// instruction" that intrinsics::abort would cause, as intrinsics::abort is -// implemented as an illegal instruction. -pub unsafe fn abort_internal() -> ! { - ::libc::abort() -} diff --git a/ctr-std/src/sys/horizon/mutex.rs b/ctr-std/src/sys/horizon/mutex.rs deleted file mode 100644 index 95c74a4..0000000 --- a/ctr-std/src/sys/horizon/mutex.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use mem; - -pub struct Mutex { - inner: UnsafeCell<::libctru::LightLock>, -} - -#[inline] -pub unsafe fn raw(m: &Mutex) -> *mut ::libctru::LightLock { - m.inner.get() -} - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} - -impl Mutex { - pub const fn new() -> Mutex { - Mutex { inner: UnsafeCell::new(0) } - } - - #[inline] - pub unsafe fn init(&mut self) { - ::libctru::LightLock_Init(self.inner.get()); - } - - #[inline] - pub unsafe fn lock(&self) { - ::libctru::LightLock_Lock(self.inner.get()); - } - - #[inline] - pub unsafe fn unlock(&self) { - ::libctru::LightLock_Unlock(self.inner.get()); - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - match ::libctru::LightLock_TryLock(self.inner.get()) { - 0 => false, - _ => true, - } - } - - #[inline] - pub unsafe fn destroy(&self) { - } -} - -pub struct ReentrantMutex { inner: UnsafeCell<::libctru::RecursiveLock> } - -unsafe impl Send for ReentrantMutex {} -unsafe impl Sync for ReentrantMutex {} - -impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: mem::uninitialized() } - } - - pub unsafe fn init(&mut self) { - ::libctru::RecursiveLock_Init(self.inner.get()); - } - - pub unsafe fn lock(&self) { - ::libctru::RecursiveLock_Lock(self.inner.get()); - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - match ::libctru::RecursiveLock_TryLock(self.inner.get()) { - 0 => false, - _ => true, - } - } - - pub unsafe fn unlock(&self) { - ::libctru::RecursiveLock_Unlock(self.inner.get()); - } - - pub unsafe fn destroy(&self) {} -} diff --git a/ctr-std/src/sys/horizon/net.rs b/ctr-std/src/sys/horizon/net.rs deleted file mode 100644 index 14c58eb..0000000 --- a/ctr-std/src/sys/horizon/net.rs +++ /dev/null @@ -1,429 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] - -use ffi::CStr; -use io; -use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, MSG_PEEK}; -use mem; -use net::{SocketAddr, Shutdown}; -use str; -use sys::fd::FileDesc; -use sys_common::{AsInner, FromInner, IntoInner}; -use sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; -use time::{Duration, Instant}; -use cmp; - -pub use sys::{cvt, cvt_r}; -pub extern crate libc as netc; - -pub type wrlen_t = size_t; - -// See below for the usage of SOCK_CLOEXEC, but this constant is only defined on -// Linux currently (e.g. support doesn't exist on other platforms). In order to -// get name resolution to work and things to compile we just define a dummy -// SOCK_CLOEXEC here for other platforms. Note that the dummy constant isn't -// actually ever used (the blocks below are wrapped in `if cfg!` as well. -#[cfg(target_os = "linux")] -use libc::SOCK_CLOEXEC; -#[cfg(not(target_os = "linux"))] -const SOCK_CLOEXEC: c_int = 0; - -// Another conditional contant for name resolution: Macos et iOS use -// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket. -// Other platforms do otherwise. -#[cfg(target_vendor = "apple")] -use libc::SO_NOSIGPIPE; -#[cfg(not(target_vendor = "apple"))] -const SO_NOSIGPIPE: c_int = 0; - -const EAI_SYSTEM: c_int = 0; - -pub struct Socket(FileDesc); - -pub fn init() {} - -pub fn cvt_gai(err: c_int) -> io::Result<()> { - if err == 0 { - return Ok(()) - } - - // We may need to trigger a glibc workaround. See on_resolver_failure() for details. - on_resolver_failure(); - - if err == EAI_SYSTEM { - return Err(io::Error::last_os_error()) - } - - let detail = unsafe { - str::from_utf8(CStr::from_ptr(libc::gai_strerror(err) as *const i8).to_bytes()).unwrap() - .to_owned() - }; - Err(io::Error::new(io::ErrorKind::Other, - &format!("failed to lookup address information: {}", - detail)[..])) -} - -impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => libc::AF_INET, - SocketAddr::V6(..) => libc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { - unsafe { - // On linux we first attempt to pass the SOCK_CLOEXEC flag to - // atomically create the socket and set it as CLOEXEC. Support for - // this option, however, was added in 2.6.27, and we still support - // 2.6.18 as a kernel, so if the returned error is EINVAL we - // fallthrough to the fallback. - if cfg!(target_os = "linux") { - match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) { - Ok(fd) => return Ok(Socket(FileDesc::new(fd))), - Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} - Err(e) => return Err(e), - } - } - - let fd = cvt(libc::socket(fam, ty, 0))?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - let socket = Socket(fd); - if cfg!(target_vendor = "apple") { - setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?; - } - Ok(socket) - } - } - - pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> { - unsafe { - let mut fds = [0, 0]; - - // Like above, see if we can set cloexec atomically - if cfg!(target_os = "linux") { - match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) { - Ok(_) => { - return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1])))); - } - Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}, - Err(e) => return Err(e), - } - } - - cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?; - let a = FileDesc::new(fds[0]); - let b = FileDesc::new(fds[1]); - a.set_cloexec()?; - b.set_cloexec()?; - Ok((Socket(a), Socket(b))) - } - } - - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = unsafe { - let (addrp, len) = addr.into_inner(); - cvt(libc::connect(self.0.raw(), addrp, len)) - }; - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS :( - Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} - Err(e) => return Err(e), - } - - let mut pollfd = libc::pollfd { - fd: self.0.raw(), - // supposed to be `libc::POLLOUT`, but the value in the `libc` crate is currently - // incorrect for the 3DS - events: 0x10, - revents: 0, - }; - - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout")); - } - - let start = Instant::now(); - - loop { - let elapsed = start.elapsed(); - if elapsed >= timeout { - return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")); - } - - let timeout = timeout - elapsed; - let mut timeout = timeout.as_secs() - .saturating_mul(1_000) - .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); - if timeout == 0 { - timeout = 1; - } - - let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int; - - match unsafe { libc::poll(&mut pollfd, 1, timeout) } { - -1 => { - let err = io::Error::last_os_error(); - if err.kind() != io::ErrorKind::Interrupted { - return Err(err); - } - } - 0 => {} - _ => { - // `libc::POLLHUP` should be 0x4, but the constant is currently defined - // incorrectly for 3DS. So we just specifiy it manually for now. - if pollfd.revents & 0x4 != 0 { - let e = self.take_error()? - .unwrap_or_else(|| { - io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") - }); - return Err(e); - } - - return Ok(()); - } - } - } - } - - pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) - -> io::Result { - // Unfortunately the only known way right now to accept a socket and - // atomically set the CLOEXEC flag is to use the `accept4` syscall on - // Linux. This was added in 2.6.28, however, and because we support - // 2.6.18 we must detect this support dynamically. - if cfg!(target_os = "linux") { - weak! { - fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int - } - if let Some(accept) = accept4.get() { - let res = cvt_r(|| unsafe { - accept(self.0.raw(), storage, len, SOCK_CLOEXEC) - }); - match res { - Ok(fd) => return Ok(Socket(FileDesc::new(fd))), - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} - Err(e) => return Err(e), - } - } - } - - let fd = cvt_r(|| unsafe { - libc::accept(self.0.raw(), storage, len) - })?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - Ok(Socket(fd)) - } - - pub fn duplicate(&self) -> io::Result { - self.0.duplicate().map(Socket) - } - - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { - let ret = cvt(unsafe { - libc::recv(self.0.raw(), - buf.as_mut_ptr() as *mut c_void, - buf.len(), - flags) - })?; - Ok(ret as usize) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, 0) - } - - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, MSG_PEEK) - } - - fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int) - -> io::Result<(usize, SocketAddr)> { - let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t; - - let n = cvt(unsafe { - libc::recvfrom(self.0.raw(), - buf.as_mut_ptr() as *mut c_void, - buf.len(), - flags, - &mut storage as *mut _ as *mut _, - &mut addrlen) - })?; - Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) - } - - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, 0) - } - - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, MSG_PEEK) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn set_timeout(&self, dur: Option, kind: libc::c_int) -> io::Result<()> { - let timeout = match dur { - Some(dur) => { - if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout")); - } - - let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { - libc::time_t::max_value() - } else { - dur.as_secs() as libc::time_t - }; - let mut timeout = libc::timeval { - tv_sec: secs, - tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, - }; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } - timeout - } - None => { - libc::timeval { - tv_sec: 0, - tv_usec: 0, - } - } - }; - setsockopt(self, libc::SOL_SOCKET, kind, timeout) - } - - pub fn timeout(&self, kind: libc::c_int) -> io::Result> { - let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?; - if raw.tv_sec == 0 && raw.tv_usec == 0 { - Ok(None) - } else { - let sec = raw.tv_sec as u64; - let nsec = (raw.tv_usec as u32) * 1000; - Ok(Some(Duration::new(sec, nsec))) - } - } - - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - let how = match how { - Shutdown::Write => libc::SHUT_WR, - Shutdown::Read => libc::SHUT_RD, - Shutdown::Both => libc::SHUT_RDWR, - }; - cvt(unsafe { libc::shutdown(self.0.raw(), how) })?; - Ok(()) - } - - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) - } - - pub fn nodelay(&self) -> io::Result { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?; - Ok(raw != 0) - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; - if raw == 0 { - Ok(None) - } else { - Ok(Some(io::Error::from_raw_os_error(raw as i32))) - } - } -} - -impl AsInner for Socket { - fn as_inner(&self) -> &c_int { self.0.as_inner() } -} - -impl FromInner for Socket { - fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) } -} - -impl IntoInner for Socket { - fn into_inner(self) -> c_int { self.0.into_raw() } -} - -// In versions of glibc prior to 2.26, there's a bug where the DNS resolver -// will cache the contents of /etc/resolv.conf, so changes to that file on disk -// can be ignored by a long-running program. That can break DNS lookups on e.g. -// laptops where the network comes and goes. See -// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some -// distros including Debian have patched glibc to fix this for a long time. -// -// A workaround for this bug is to call the res_init libc function, to clear -// the cached configs. Unfortunately, while we believe glibc's implementation -// of res_init is thread-safe, we know that other implementations are not -// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could -// try to synchronize its res_init calls with a Mutex, but that wouldn't -// protect programs that call into libc in other ways. So instead of calling -// res_init unconditionally, we call it only when we detect we're linking -// against glibc version < 2.26. (That is, when we both know its needed and -// believe it's thread-safe). -#[cfg(target_env = "gnu")] -fn on_resolver_failure() { - use sys; - - // If the version fails to parse, we treat it the same as "not glibc". - if let Some(version) = sys::os::glibc_version() { - if version < (2, 26) { - unsafe { libc::res_init() }; - } - } -} - -#[cfg(not(target_env = "gnu"))] -fn on_resolver_failure() {} - -#[cfg(all(test, taget_env = "gnu"))] -mod test { - use super::*; - - #[test] - fn test_res_init() { - // This mostly just tests that the weak linkage doesn't panic wildly... - res_init_if_glibc_before_2_26().unwrap(); - } - - #[test] - fn test_parse_glibc_version() { - let cases = [ - ("0.0", Some((0, 0))), - ("01.+2", Some((1, 2))), - ("3.4.5.six", Some((3, 4))), - ("1", None), - ("1.-2", None), - ("1.foo", None), - ("foo.1", None), - ]; - for &(version_str, parsed) in cases.iter() { - assert_eq!(parsed, parse_glibc_version(version_str)); - } - } -} diff --git a/ctr-std/src/sys/horizon/os.rs b/ctr-std/src/sys/horizon/os.rs deleted file mode 100644 index a26e007..0000000 --- a/ctr-std/src/sys/horizon/os.rs +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use error::Error as StdError; -use ffi::{CString, CStr, OsString, OsStr}; -use fmt; -use io; -use iter; -use libc::{self, c_int, c_char}; -use path::{self, PathBuf}; -use slice; -use str; -use sys::{unsupported, Void}; -use sys::horizon::ext::ffi::{OsStrExt, OsStringExt}; - -const TMPBUF_SZ: usize = 128; - -extern "C" { - fn __errno() -> *mut c_int; -} - -/// Returns the platform-specific value of errno -pub fn errno() -> i32 { - unsafe { - (*__errno()) as i32 - } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(errno: i32) -> String { - extern { - #[cfg_attr(any(target_os = "linux", target_env = "newlib"), - link_name = "__xpg_strerror_r")] - fn strerror_r(errnum: c_int, buf: *mut c_char, - buflen: libc::size_t) -> c_int; - } - - let mut buf = [0 as c_char; TMPBUF_SZ]; - - let p = buf.as_mut_ptr(); - unsafe { - if strerror_r(errno as c_int, p, buf.len()) < 0 { - panic!("strerror_r failure"); - } - - let p = p as *const _; - str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() - } -} - -pub fn getcwd() -> io::Result { - let mut buf = Vec::with_capacity(512); - loop { - unsafe { - let ptr = buf.as_mut_ptr() as *mut libc::c_char; - if !libc::getcwd(ptr, buf.capacity()).is_null() { - let len = CStr::from_ptr(buf.as_ptr() as *const i8).to_bytes().len(); - buf.set_len(len); - buf.shrink_to_fit(); - return Ok(PathBuf::from(OsString::from_vec(buf))); - } else { - let error = io::Error::last_os_error(); - if error.raw_os_error() != Some(libc::ERANGE) { - return Err(error); - } - } - - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. - let cap = buf.capacity(); - buf.set_len(cap); - buf.reserve(1); - } - } -} - -pub fn chdir(p: &path::Path) -> io::Result<()> { - let p: &OsStr = p.as_ref(); - let p = CString::new(p.as_bytes())?; - unsafe { - match libc::chdir(p.as_ptr() as *const u8) == (0 as c_int) { - true => Ok(()), - false => Err(io::Error::last_os_error()), - } - } -} - -pub struct SplitPaths<'a> { - iter: iter::Map bool>, - fn(&'a [u8]) -> PathBuf>, -} - -pub fn split_paths(unparsed: &OsStr) -> SplitPaths { - fn bytes_to_path(b: &[u8]) -> PathBuf { - PathBuf::from(::from_bytes(b)) - } - fn is_colon(b: &u8) -> bool { *b == b':' } - let unparsed = unparsed.as_bytes(); - SplitPaths { - iter: unparsed.split(is_colon as fn(&u8) -> bool) - .map(bytes_to_path as fn(&[u8]) -> PathBuf) - } -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { self.iter.next() } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(paths: I) -> Result - where I: Iterator, T: AsRef -{ - let mut joined = Vec::new(); - let sep = b':'; - - for (i, path) in paths.enumerate() { - let path = path.as_ref().as_bytes(); - if i > 0 { joined.push(sep) } - if path.contains(&sep) { - return Err(JoinPathsError) - } - joined.extend_from_slice(path); - } - Ok(OsStringExt::from_vec(joined)) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "path segment contains separator `:`".fmt(f) - } -} - -impl StdError for JoinPathsError { - fn description(&self) -> &str { "failed to join paths" } -} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub struct Env(Void); - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - match self.0 {} - } -} - -pub fn env() -> Env { - panic!("not supported on 3DS yet") -} - -pub fn getenv(_k: &OsStr) -> io::Result> { - return Ok(None) -} - -pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> { - unsupported() -} - -pub fn unsetenv(_n: &OsStr) -> io::Result<()> { - unsupported() -} - -pub fn temp_dir() -> PathBuf { - PathBuf::from("/tmp") -} - -pub fn home_dir() -> Option { - None -} - -pub fn exit(code: i32) -> ! { - unsafe { libc::exit(code as c_int) } -} - -pub fn getpid() -> u32 { - panic!("no pids on 3DS") -} \ No newline at end of file diff --git a/ctr-std/src/sys/horizon/os_str.rs b/ctr-std/src/sys/horizon/os_str.rs deleted file mode 100644 index 01c0fb8..0000000 --- a/ctr-std/src/sys/horizon/os_str.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// The underlying OsString/OsStr implementation on Unix systems: just -/// a `Vec`/`[u8]`. - -use borrow::Cow; -use fmt; -use str; -use mem; -use rc::Rc; -use sync::Arc; -use sys_common::{AsInner, IntoInner}; -use sys_common::bytestring::debug_fmt_bytestring; -use core::str::lossy::Utf8Lossy; - -#[derive(Clone, Hash)] -pub struct Buf { - pub inner: Vec -} - -pub struct Slice { - pub inner: [u8] -} - -impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - debug_fmt_bytestring(&self.inner, formatter) - } -} - -impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) - } -} - -impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) - } -} - -impl IntoInner> for Buf { - fn into_inner(self) -> Vec { - self.inner - } -} - -impl AsInner<[u8]> for Buf { - fn as_inner(&self) -> &[u8] { - &self.inner - } -} - - -impl Buf { - pub fn from_string(s: String) -> Buf { - Buf { inner: s.into_bytes() } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Buf { - Buf { - inner: Vec::with_capacity(capacity) - } - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear() - } - - #[inline] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - pub fn as_slice(&self) -> &Slice { - unsafe { mem::transmute(&*self.inner) } - } - - pub fn into_string(self) -> Result { - String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) - } - - pub fn push_slice(&mut self, s: &Slice) { - self.inner.extend_from_slice(&s.inner) - } - - #[inline] - pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.inner.into_boxed_slice()) } - } - - #[inline] - pub fn from_box(boxed: Box) -> Buf { - let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Buf { inner: inner.into_vec() } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - self.as_slice().into_arc() - } - - #[inline] - pub fn into_rc(&self) -> Rc { - self.as_slice().into_rc() - } -} - -impl Slice { - fn from_u8_slice(s: &[u8]) -> &Slice { - unsafe { mem::transmute(s) } - } - - pub fn from_str(s: &str) -> &Slice { - Slice::from_u8_slice(s.as_bytes()) - } - - pub fn to_str(&self) -> Option<&str> { - str::from_utf8(&self.inner).ok() - } - - pub fn to_string_lossy(&self) -> Cow { - String::from_utf8_lossy(&self.inner) - } - - pub fn to_owned(&self) -> Buf { - Buf { inner: self.inner.to_vec() } - } - - #[inline] - pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.inner.into(); - unsafe { mem::transmute(boxed) } - } - - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.inner); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.inner); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } - } -} diff --git a/ctr-std/src/sys/horizon/path.rs b/ctr-std/src/sys/horizon/path.rs deleted file mode 100644 index bf9af7a..0000000 --- a/ctr-std/src/sys/horizon/path.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use path::Prefix; -use ffi::OsStr; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option { - None -} - -pub const MAIN_SEP_STR: &'static str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/ctr-std/src/sys/horizon/pipe.rs b/ctr-std/src/sys/horizon/pipe.rs deleted file mode 100644 index 0c121ae..0000000 --- a/ctr-std/src/sys/horizon/pipe.rs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] - -use io; -use libc::{self, c_int}; -use mem; -use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; -use sys::fd::FileDesc; -use sys::{cvt, cvt_r}; - -//////////////////////////////////////////////////////////////////////////////// -// Anonymous pipes -//////////////////////////////////////////////////////////////////////////////// - -pub struct AnonPipe(FileDesc); - -pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - weak! { fn pipe2(*mut c_int, c_int) -> c_int } - static INVALID: AtomicBool = ATOMIC_BOOL_INIT; - - let mut fds = [0; 2]; - - // Unfortunately the only known way right now to create atomically set the - // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in - // 2.6.27, however, and because we support 2.6.18 we must detect this - // support dynamically. - if cfg!(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd")) && - !INVALID.load(Ordering::SeqCst) - { - - if let Some(pipe) = pipe2.get() { - // Note that despite calling a glibc function here we may still - // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to - // emulate on older kernels, so if you happen to be running on - // an older kernel you may see `pipe2` as a symbol but still not - // see the syscall. - match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { - Ok(_) => { - return Ok((AnonPipe(FileDesc::new(fds[0])), - AnonPipe(FileDesc::new(fds[1])))); - } - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => { - INVALID.store(true, Ordering::SeqCst); - } - Err(e) => return Err(e), - } - } - } - cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; - - let fd0 = FileDesc::new(fds[0]); - let fd1 = FileDesc::new(fds[1]); - fd0.set_cloexec()?; - fd1.set_cloexec()?; - Ok((AnonPipe(fd0), AnonPipe(fd1))) -} - -impl AnonPipe { - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn fd(&self) -> &FileDesc { &self.0 } - pub fn into_fd(self) -> FileDesc { self.0 } - - pub fn diverge(&self) -> ! { - panic!() - } -} - -pub fn read2(p1: AnonPipe, - v1: &mut Vec, - p2: AnonPipe, - v2: &mut Vec) -> io::Result<()> { - - // Set both pipes into nonblocking mode as we're gonna be reading from both - // in the `select` loop below, and we wouldn't want one to block the other! - let p1 = p1.into_fd(); - let p2 = p2.into_fd(); - p1.set_nonblocking(true)?; - p2.set_nonblocking(true)?; - - let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; - fds[0].fd = p1.raw(); - fds[0].events = libc::POLLIN; - fds[1].fd = p2.raw(); - fds[1].events = libc::POLLIN; - loop { - // wait for either pipe to become readable using `poll` - cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; - - if fds[0].revents != 0 && read(&p1, v1)? { - p2.set_nonblocking(false)?; - return p2.read_to_end(v2).map(|_| ()); - } - if fds[1].revents != 0 && read(&p2, v2)? { - p1.set_nonblocking(false)?; - return p1.read_to_end(v1).map(|_| ()); - } - } - - // Read as much as we can from each pipe, ignoring EWOULDBLOCK or - // EAGAIN. If we hit EOF, then this will happen because the underlying - // reader will return Ok(0), in which case we'll see `Ok` ourselves. In - // this case we flip the other fd back into blocking mode and read - // whatever's leftover on that file descriptor. - fn read(fd: &FileDesc, dst: &mut Vec) -> Result { - match fd.read_to_end(dst) { - Ok(_) => Ok(true), - Err(e) => { - if e.raw_os_error() == Some(libc::EWOULDBLOCK) || - e.raw_os_error() == Some(libc::EAGAIN) { - Ok(false) - } else { - Err(e) - } - } - } - } -} diff --git a/ctr-std/src/sys/horizon/process.rs b/ctr-std/src/sys/horizon/process.rs deleted file mode 100644 index 15b0e31..0000000 --- a/ctr-std/src/sys/horizon/process.rs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::OsStr; -use fmt; -use io; -use sys::fs::File; -use sys::pipe::AnonPipe; -use sys::{unsupported, Void}; -use sys_common::process::{CommandEnv, DefaultEnvKey}; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - env: CommandEnv -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, -} - -impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { - env: Default::default() - } - } - - pub fn arg(&mut self, _arg: &OsStr) { - } - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, _dir: &OsStr) { - } - - pub fn stdin(&mut self, _stdin: Stdio) { - } - - pub fn stdout(&mut self, _stdout: Stdio) { - } - - pub fn stderr(&mut self, _stderr: Stdio) { - } - - pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool) - -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(_file: File) -> Stdio { - //file.diverge() - unimplemented!() - } -} - -impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - Ok(()) - } -} - -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } -} - -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - match self.0 {} - } -} - -impl Copy for ExitStatus {} - -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { - match self.0 {} - } -} - -impl Eq for ExitStatus { -} - -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} \ No newline at end of file diff --git a/ctr-std/src/sys/horizon/rand.rs b/ctr-std/src/sys/horizon/rand.rs deleted file mode 100644 index 3ae694a..0000000 --- a/ctr-std/src/sys/horizon/rand.rs +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use mem; -use slice; - -pub fn hashmap_random_keys() -> (u64, u64) { - let mut v = (0, 0); - unsafe { - let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, - mem::size_of_val(&v)); - imp::fill_bytes(view); - } - return v -} - -#[cfg(target_os = "horizon")] -mod imp { - use libctru; - - pub fn fill_bytes(v: &mut [u8]) { - unsafe { - // Initializing and de-initializing the sslC subsystem every time - // we initialize a hashmap is pretty dumb, but I can't think of a - // better method at the moment. - // - // lazy_static won't work because - // destructors (for closing the subsystem on exit) won't run. - // - // Perhaps overriding __appInit() and __appExit() will work, - // but that's an experiment for another time. - libctru::sslcInit(0); - libctru::sslcGenerateRandomData(v.as_ptr() as _, v.len() as u32); - libctru::sslcExit(); - } - } -} - -#[cfg(all(unix, - not(target_os = "ios"), - not(target_os = "openbsd"), - not(target_os = "freebsd"), - not(target_os = "fuchsia"), - not(target_os = "horizon") - ))] -mod imp { - use fs::File; - use io::Read; - use libc; - use sys::os::errno; - - #[cfg(any(target_os = "linux", target_os = "android"))] - fn getrandom(buf: &mut [u8]) -> libc::c_long { - unsafe { - libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK) - } - } - - #[cfg(not(any(target_os = "linux", target_os = "android")))] - fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } - - fn getrandom_fill_bytes(v: &mut [u8]) -> bool { - let mut read = 0; - while read < v.len() { - let result = getrandom(&mut v[read..]); - if result == -1 { - let err = errno() as libc::c_int; - if err == libc::EINTR { - continue; - } else if err == libc::EAGAIN { - return false - } else { - panic!("unexpected getrandom error: {}", err); - } - } else { - read += result as usize; - } - } - - return true - } - - #[cfg(any(target_os = "linux", target_os = "android"))] - fn is_getrandom_available() -> bool { - use io; - use sync::atomic::{AtomicBool, Ordering}; - use sync::Once; - - static CHECKER: Once = Once::new(); - static AVAILABLE: AtomicBool = AtomicBool::new(false); - - CHECKER.call_once(|| { - let mut buf: [u8; 0] = []; - let result = getrandom(&mut buf); - let available = if result == -1 { - let err = io::Error::last_os_error().raw_os_error(); - err != Some(libc::ENOSYS) - } else { - true - }; - AVAILABLE.store(available, Ordering::Relaxed); - }); - - AVAILABLE.load(Ordering::Relaxed) - } - - #[cfg(not(any(target_os = "linux", target_os = "android")))] - fn is_getrandom_available() -> bool { false } - - pub fn fill_bytes(v: &mut [u8]) { - // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN, - // meaning it would have blocked because the non-blocking pool (urandom) - // has not initialized in the kernel yet due to a lack of entropy the - // fallback we do here is to avoid blocking applications which could - // depend on this call without ever knowing they do and don't have a - // work around. The PRNG of /dev/urandom will still be used but not - // over a completely full entropy pool - if is_getrandom_available() && getrandom_fill_bytes(v) { - return - } - - let mut file = File::open("/dev/urandom") - .expect("failed to open /dev/urandom"); - file.read_exact(v).expect("failed to read /dev/urandom"); - } -} - -#[cfg(target_os = "openbsd")] -mod imp { - use libc; - use sys::os::errno; - - pub fn fill_bytes(v: &mut [u8]) { - // getentropy(2) permits a maximum buffer size of 256 bytes - for s in v.chunks_mut(256) { - let ret = unsafe { - libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) - }; - if ret == -1 { - panic!("unexpected getentropy error: {}", errno()); - } - } - } -} - -#[cfg(target_os = "ios")] -mod imp { - use io; - use libc::{c_int, size_t}; - use ptr; - - enum SecRandom {} - - #[allow(non_upper_case_globals)] - const kSecRandomDefault: *const SecRandom = ptr::null(); - - extern { - fn SecRandomCopyBytes(rnd: *const SecRandom, - count: size_t, - bytes: *mut u8) -> c_int; - } - - pub fn fill_bytes(v: &mut [u8]) { - let ret = unsafe { - SecRandomCopyBytes(kSecRandomDefault, - v.len(), - v.as_mut_ptr()) - }; - if ret == -1 { - panic!("couldn't generate random bytes: {}", - io::Error::last_os_error()); - } - } -} - -#[cfg(target_os = "freebsd")] -mod imp { - use libc; - use ptr; - - pub fn fill_bytes(v: &mut [u8]) { - let mib = [libc::CTL_KERN, libc::KERN_ARND]; - // kern.arandom permits a maximum buffer size of 256 bytes - for s in v.chunks_mut(256) { - let mut s_len = s.len(); - let ret = unsafe { - libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, - s.as_mut_ptr() as *mut _, &mut s_len, - ptr::null(), 0) - }; - if ret == -1 || s_len != s.len() { - panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})", - ret, s.len(), s_len); - } - } - } -} - -#[cfg(target_os = "fuchsia")] -mod imp { - #[link(name = "zircon")] - extern { - fn zx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32; - } - - fn getrandom(buf: &mut [u8]) -> Result { - unsafe { - let mut actual = 0; - let status = zx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual); - if status == 0 { - Ok(actual) - } else { - Err(status) - } - } - } - - pub fn fill_bytes(v: &mut [u8]) { - let mut buf = v; - while !buf.is_empty() { - let ret = getrandom(buf); - match ret { - Err(err) => { - panic!("kernel zx_cprng_draw call failed! (returned {}, buf.len() {})", - err, buf.len()) - } - Ok(actual) => { - let move_buf = buf; - buf = &mut move_buf[(actual as usize)..]; - } - } - } - } -} diff --git a/ctr-std/src/sys/horizon/rwlock.rs b/ctr-std/src/sys/horizon/rwlock.rs deleted file mode 100644 index 4a802e9..0000000 --- a/ctr-std/src/sys/horizon/rwlock.rs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use super::mutex::Mutex; -use super::condvar::Condvar; - -// A simple read-preferring RWLock implementation that I found on wikipedia <.< -pub struct RWLock { - mutex: Mutex, - cvar: Condvar, - reader_count: UnsafeCell, - writer_active: UnsafeCell, -} - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { - mutex: Mutex::new(), - cvar: Condvar::new(), - reader_count: UnsafeCell::new(0), - writer_active: UnsafeCell::new(false), - } - } - - #[inline] - pub unsafe fn read(&self) { - self.mutex.lock(); - - while *self.writer_active.get() { - self.cvar.wait(&self.mutex); - } - - assert!(*self.reader_count.get() != u32::max_value()); - *self.reader_count.get() += 1; - - self.mutex.unlock(); - } - - #[inline] - pub unsafe fn try_read(&self) -> bool { - if !self.mutex.try_lock() { - return false - } - - while *self.writer_active.get() { - self.cvar.wait(&self.mutex); - } - - assert!(*self.reader_count.get() != u32::max_value()); - *self.reader_count.get() += 1; - - self.mutex.unlock(); - true - } - - #[inline] - pub unsafe fn write(&self) { - self.mutex.lock(); - - while *self.writer_active.get() || *self.reader_count.get() > 0 { - self.cvar.wait(&self.mutex); - } - - *self.writer_active.get() = true; - - self.mutex.unlock(); - } - - #[inline] - pub unsafe fn try_write(&self) -> bool { - if !self.mutex.try_lock() { - return false; - } - - while *self.writer_active.get() || *self.reader_count.get() > 0 { - self.cvar.wait(&self.mutex); - } - - *self.writer_active.get() = true; - - self.mutex.unlock(); - true - } - - #[inline] - pub unsafe fn read_unlock(&self) { - self.mutex.lock(); - - *self.reader_count.get() -= 1; - - if *self.reader_count.get() == 0 { - self.cvar.notify_one() - } - - self.mutex.unlock(); - } - - #[inline] - pub unsafe fn write_unlock(&self) { - self.mutex.lock(); - - *self.writer_active.get() = false; - - self.cvar.notify_all(); - - self.mutex.unlock(); - } - - #[inline] - pub unsafe fn destroy(&self) { - self.mutex.destroy(); - self.cvar.destroy(); - *self.reader_count.get() = 0; - *self.writer_active.get() = false; - } -} diff --git a/ctr-std/src/sys/horizon/stack_overflow.rs b/ctr-std/src/sys/horizon/stack_overflow.rs deleted file mode 100644 index 40453f9..0000000 --- a/ctr-std/src/sys/horizon/stack_overflow.rs +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg_attr(test, allow(dead_code))] - -use libc; -use self::imp::{make_handler, drop_handler}; - -pub use self::imp::cleanup; -pub use self::imp::init; - -pub struct Handler { - _data: *mut libc::c_void -} - -impl Handler { - pub unsafe fn new() -> Handler { - make_handler() - } -} - -impl Drop for Handler { - fn drop(&mut self) { - unsafe { - drop_handler(self); - } - } -} - -#[cfg(any(target_os = "linux", - target_os = "macos", - target_os = "bitrig", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "solaris", - all(target_os = "netbsd", not(target_vendor = "rumprun")), - target_os = "openbsd"))] -mod imp { - use super::Handler; - use mem; - use ptr; - use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE}; - use libc::{sigaction, SIGBUS, SIG_DFL, - SA_SIGINFO, SA_ONSTACK, sighandler_t}; - use libc; - use libc::{mmap, munmap}; - use libc::{SIGSEGV, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON}; - use libc::MAP_FAILED; - - use sys_common::thread_info; - - - #[cfg(any(target_os = "linux", target_os = "android"))] - unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize { - #[repr(C)] - struct siginfo_t { - a: [libc::c_int; 3], // si_signo, si_errno, si_code - si_addr: *mut libc::c_void, - } - - (*(info as *const siginfo_t)).si_addr as usize - } - - #[cfg(not(any(target_os = "linux", target_os = "android")))] - unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize { - (*info).si_addr as usize - } - - // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages - // (unmapped pages) at the end of every thread's stack, so if a thread ends - // up running into the guard page it'll trigger this handler. We want to - // detect these cases and print out a helpful error saying that the stack - // has overflowed. All other signals, however, should go back to what they - // were originally supposed to do. - // - // This handler currently exists purely to print an informative message - // whenever a thread overflows its stack. We then abort to exit and - // indicate a crash, but to avoid a misleading SIGSEGV that might lead - // users to believe that unsafe code has accessed an invalid pointer; the - // SIGSEGV encountered when overflowing the stack is expected and - // well-defined. - // - // If this is not a stack overflow, the handler un-registers itself and - // then returns (to allow the original signal to be delivered again). - // Returning from this kind of signal handler is technically not defined - // to work when reading the POSIX spec strictly, but in practice it turns - // out many large systems and all implementations allow returning from a - // signal handler to work. For a more detailed explanation see the - // comments on #26458. - unsafe extern fn signal_handler(signum: libc::c_int, - info: *mut libc::siginfo_t, - _data: *mut libc::c_void) { - use sys_common::util::report_overflow; - - let guard = thread_info::stack_guard().unwrap_or(0..0); - let addr = siginfo_si_addr(info); - - // If the faulting address is within the guard page, then we print a - // message saying so and abort. - if guard.start <= addr && addr < guard.end { - report_overflow(); - rtabort!("stack overflow"); - } else { - // Unregister ourselves by reverting back to the default behavior. - let mut action: sigaction = mem::zeroed(); - action.sa_sigaction = SIG_DFL; - sigaction(signum, &action, ptr::null_mut()); - - // See comment above for why this function returns. - } - } - - static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut(); - - pub unsafe fn init() { - let mut action: sigaction = mem::zeroed(); - action.sa_flags = SA_SIGINFO | SA_ONSTACK; - action.sa_sigaction = signal_handler as sighandler_t; - sigaction(SIGSEGV, &action, ptr::null_mut()); - sigaction(SIGBUS, &action, ptr::null_mut()); - - let handler = make_handler(); - MAIN_ALTSTACK = handler._data; - mem::forget(handler); - } - - pub unsafe fn cleanup() { - Handler { _data: MAIN_ALTSTACK }; - } - - unsafe fn get_stackp() -> *mut libc::c_void { - let stackp = mmap(ptr::null_mut(), - SIGSTKSZ, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, - -1, - 0); - if stackp == MAP_FAILED { - panic!("failed to allocate an alternative stack"); - } - stackp - } - - #[cfg(any(target_os = "linux", - target_os = "macos", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - unsafe fn get_stack() -> libc::stack_t { - libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ } - } - - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly"))] - unsafe fn get_stack() -> libc::stack_t { - libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ } - } - - pub unsafe fn make_handler() -> Handler { - let mut stack = mem::zeroed(); - sigaltstack(ptr::null(), &mut stack); - // Configure alternate signal stack, if one is not already set. - if stack.ss_flags & SS_DISABLE != 0 { - stack = get_stack(); - sigaltstack(&stack, ptr::null_mut()); - Handler { _data: stack.ss_sp as *mut libc::c_void } - } else { - Handler { _data: ptr::null_mut() } - } - } - - pub unsafe fn drop_handler(handler: &mut Handler) { - if !handler._data.is_null() { - let stack = libc::stack_t { - ss_sp: ptr::null_mut(), - ss_flags: SS_DISABLE, - // Workaround for bug in macOS implementation of sigaltstack - // UNIX2003 which returns ENOMEM when disabling a stack while - // passing ss_size smaller than MINSIGSTKSZ. According to POSIX - // both ss_sp and ss_size should be ignored in this case. - ss_size: SIGSTKSZ, - }; - sigaltstack(&stack, ptr::null_mut()); - munmap(handler._data, SIGSTKSZ); - } - } -} - -#[cfg(not(any(target_os = "linux", - target_os = "macos", - target_os = "bitrig", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "solaris", - all(target_os = "netbsd", not(target_vendor = "rumprun")), - target_os = "openbsd")))] -mod imp { - use ptr; - - pub unsafe fn init() { - } - - pub unsafe fn cleanup() { - } - - pub unsafe fn make_handler() -> super::Handler { - super::Handler { _data: ptr::null_mut() } - } - - pub unsafe fn drop_handler(_handler: &mut super::Handler) { - } -} diff --git a/ctr-std/src/sys/horizon/stdio.rs b/ctr-std/src/sys/horizon/stdio.rs deleted file mode 100644 index 87ba2ae..0000000 --- a/ctr-std/src/sys/horizon/stdio.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use libc; -use sys::fd::FileDesc; - -pub struct Stdin(()); -pub struct Stdout(()); -pub struct Stderr(()); - -impl Stdin { - pub fn new() -> io::Result { Ok(Stdin(())) } - - pub fn read(&self, data: &mut [u8]) -> io::Result { - let fd = FileDesc::new(libc::STDIN_FILENO); - let ret = fd.read(data); - fd.into_raw(); - ret - } -} - -impl Stdout { - pub fn new() -> io::Result { Ok(Stdout(())) } - - pub fn write(&self, data: &[u8]) -> io::Result { - let fd = FileDesc::new(libc::STDOUT_FILENO); - let ret = fd.write(data); - fd.into_raw(); - ret - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub fn new() -> io::Result { Ok(Stderr(())) } - - pub fn write(&self, data: &[u8]) -> io::Result { - let fd = FileDesc::new(libc::STDERR_FILENO); - let ret = fd.write(data); - fd.into_raw(); - ret - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -// FIXME: right now this raw stderr handle is used in a few places because -// std::io::stderr_raw isn't exposed, but once that's exposed this impl -// should go away -impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result { - Stderr::write(self, data) - } - - fn flush(&mut self) -> io::Result<()> { - Stderr::flush(self) - } -} - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(libc::EBADF as i32) -} - -pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; - -pub fn stderr_prints_nothing() -> bool { - false -} diff --git a/ctr-std/src/sys/horizon/thread.rs b/ctr-std/src/sys/horizon/thread.rs deleted file mode 100644 index 694f85a..0000000 --- a/ctr-std/src/sys/horizon/thread.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use alloc_crate::boxed::FnBox; -use libc; -use cmp; -use ffi::CStr; -use io; -use mem; -use ptr; -use sys_common::thread::start_thread; -use time::Duration; - -use libctru::Thread as ThreadHandle; - -pub struct Thread { - handle: ThreadHandle, -} - -unsafe impl Send for Thread {} -unsafe impl Sync for Thread {} - -pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; - - -impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box) -> io::Result { - let p = box p; - let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE); - - let mut priority = 0; - ::libctru::svcGetThreadPriority(&mut priority, 0xFFFF8000); - - let handle = ::libctru::threadCreate(Some(thread_func), &*p as *const _ as *mut _, - stack_size, priority, -2, false); - - return if handle == ptr::null_mut() { - Err(io::Error::from_raw_os_error(libc::EAGAIN)) - } else { - mem::forget(p); // ownership passed to the new thread - Ok(Thread { handle: handle }) - }; - - extern "C" fn thread_func(start: *mut libc::c_void) { - unsafe { start_thread(start as *mut u8) } - } - } - - pub fn yield_now() { - unsafe { - ::libctru::svcSleepThread(0) - } - } - - pub fn set_name(_name: &CStr) { - // threads aren't named in libctru - } - - pub fn sleep(dur: Duration) { - unsafe { - let nanos = dur.as_secs() - .saturating_mul(1_000_000_000) - .saturating_add(dur.subsec_nanos() as u64); - ::libctru::svcSleepThread(nanos as i64) - } - } - - pub fn join(self) { - unsafe { - let ret = ::libctru::threadJoin(self.handle, u64::max_value()); - ::libctru::threadFree(self.handle); - mem::forget(self); - debug_assert_eq!(ret, 0); - } - } - - #[allow(dead_code)] - pub fn id(&self) -> ThreadHandle { - self.handle - } - - #[allow(dead_code)] - pub fn into_id(self) -> ThreadHandle { - let handle = self.handle; - mem::forget(self); - handle - } -} - -impl Drop for Thread { - fn drop(&mut self) { - unsafe { ::libctru::threadDetach(self.handle) } - } -} - -pub mod guard { - pub unsafe fn current() -> Option { None } - pub unsafe fn init() -> Option { None } -} diff --git a/ctr-std/src/sys/horizon/thread_local.rs b/ctr-std/src/sys/horizon/thread_local.rs deleted file mode 100644 index 7c9c1fc..0000000 --- a/ctr-std/src/sys/horizon/thread_local.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] // not used on all platforms - -use collections::BTreeMap; -use ptr; -use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - -pub type Key = usize; - -type Dtor = unsafe extern fn(*mut u8); - -static NEXT_KEY: AtomicUsize = ATOMIC_USIZE_INIT; - -static mut KEYS: *mut BTreeMap> = ptr::null_mut(); - -#[thread_local] -static mut LOCALS: *mut BTreeMap = ptr::null_mut(); - -unsafe fn keys() -> &'static mut BTreeMap> { - if KEYS == ptr::null_mut() { - KEYS = Box::into_raw(Box::new(BTreeMap::new())); - } - &mut *KEYS -} - -unsafe fn locals() -> &'static mut BTreeMap { - if LOCALS == ptr::null_mut() { - LOCALS = Box::into_raw(Box::new(BTreeMap::new())); - } - &mut *LOCALS -} - -#[inline] -pub unsafe fn create(dtor: Option) -> Key { - let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst); - keys().insert(key, dtor); - key -} - -#[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - if let Some(&entry) = locals().get(&key) { - entry - } else { - ptr::null_mut() - } -} - -#[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - locals().insert(key, value); -} - -#[inline] -pub unsafe fn destroy(key: Key) { - keys().remove(&key); -} - -#[inline] -pub fn requires_synchronized_create() -> bool { - false -} \ No newline at end of file diff --git a/ctr-std/src/sys/horizon/time.rs b/ctr-std/src/sys/horizon/time.rs deleted file mode 100644 index aa66cf1..0000000 --- a/ctr-std/src/sys/horizon/time.rs +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cmp::Ordering; -use libc; -use time::Duration; -use core::hash::{Hash, Hasher}; - -pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; - -const NSEC_PER_SEC: u64 = 1_000_000_000; - -#[derive(Copy, Clone)] -struct Timespec { - t: libc::timespec, -} - -impl Timespec { - fn sub_timespec(&self, other: &Timespec) -> Result { - if self >= other { - Ok(if self.t.tv_nsec >= other.t.tv_nsec { - Duration::new((self.t.tv_sec - other.t.tv_sec) as u64, - (self.t.tv_nsec - other.t.tv_nsec) as u32) - } else { - Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64, - self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - - other.t.tv_nsec as u32) - }) - } else { - match other.sub_timespec(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } - } - - fn add_duration(&self, other: &Duration) -> Timespec { - let secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64); - let mut secs = secs.expect("overflow when adding duration to time"); - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; - if nsec >= NSEC_PER_SEC as u32 { - nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1).expect("overflow when adding \ - duration to time"); - } - Timespec { - t: libc::timespec { - tv_sec: secs as libc::time_t, - tv_nsec: nsec as libc::c_long, - }, - } - } - - fn sub_duration(&self, other: &Duration) -> Timespec { - let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64); - let mut secs = secs.expect("overflow when subtracting duration \ - from time"); - - // Similar to above, nanos can't overflow. - let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; - if nsec < 0 { - nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1).expect("overflow when subtracting \ - duration from time"); - } - Timespec { - t: libc::timespec { - tv_sec: secs as libc::time_t, - tv_nsec: nsec as libc::c_long, - }, - } - } -} - -impl PartialEq for Timespec { - fn eq(&self, other: &Timespec) -> bool { - self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec - } -} - -impl Eq for Timespec {} - -impl PartialOrd for Timespec { - fn partial_cmp(&self, other: &Timespec) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Timespec { - fn cmp(&self, other: &Timespec) -> Ordering { - let me = (self.t.tv_sec, self.t.tv_nsec); - let other = (other.t.tv_sec, other.t.tv_nsec); - me.cmp(&other) - } -} - -impl Hash for Timespec { - fn hash(&self, state: &mut H) { - self.t.tv_sec.hash(state); - self.t.tv_nsec.hash(state); - } -} - -mod inner { - use fmt; - use libc; - use sync::Once; - use sys::cvt; - use sys_common::mul_div_u64; - use time::Duration; - - use super::NSEC_PER_SEC; - use super::Timespec; - - use libctru; - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] - pub struct Instant { - t: u64 - } - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct SystemTime { - t: Timespec, - } - - pub const UNIX_EPOCH: SystemTime = SystemTime { - t: Timespec { - t: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, - }, - }; - - impl Instant { - pub fn now() -> Instant { - Instant { t: ctr_absolute_time() } - } - - pub fn sub_instant(&self, other: &Instant) -> Duration { - let info = info(); - let diff = self.t.checked_sub(other.t) - .expect("second instant is later than self"); - let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64); - Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32) - } - - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant { - t: self.t.checked_add(dur2intervals(other)) - .expect("overflow when adding duration to instant"), - } - } - - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant { - t: self.t.checked_sub(dur2intervals(other)) - .expect("overflow when adding duration to instant"), - } - } - } - - // The initial system tick after which all Instants occur - static mut TICK: u64 = 0; - - // A source of monotonic time based on ticks of the 3DS CPU. Returns the - // number of system ticks elapsed since an arbitrary point in the past - fn ctr_absolute_time() -> u64 { - let first_tick = get_first_tick(); - let current_tick = get_system_tick(); - current_tick - first_tick - } - - // The first time this function is called, it generates and returns the - // initial system tick used to create Instants - // - // subsequent calls to this function return the previously generated - // tick value - fn get_first_tick() -> u64 { - static ONCE: Once = Once::new(); - unsafe { - ONCE.call_once(|| { - TICK = get_system_tick(); - }); - TICK - } - } - - // Gets the current system tick - #[inline] - fn get_system_tick() -> u64 { - unsafe { libctru::svcGetSystemTick() } - } - - // A struct representing the clock speed of the 3DS - struct CtrClockInfo { - numer: u32, - denom: u32, - } - - // Initializes the CtrClockInfo struct - // - // Note that svcGetSystemTick always runs at 268MHz (268,111,856Hz), even - // on a New 3DS running in 804MHz mode - // - // See https://www.3dbrew.org/wiki/Hardware#Common_hardware - fn info() -> &'static CtrClockInfo { - static INFO: CtrClockInfo = CtrClockInfo { - numer: 1_000_000_000, - denom: 268_111_856, - }; - &INFO - } - - fn dur2intervals(dur: &Duration) -> u64 { - let info = info(); - let nanos = dur.as_secs().checked_mul(NSEC_PER_SEC).and_then(|nanos| { - nanos.checked_add(dur.subsec_nanos() as u64) - }).expect("overflow converting duration to nanoseconds"); - mul_div_u64(nanos, info.denom as u64, info.numer as u64) - } - - impl SystemTime { - pub fn now() -> SystemTime { - use ptr; - - let mut s = libc::timeval { - tv_sec: 0, - tv_usec: 0, - }; - cvt(unsafe { - libc::gettimeofday(&mut s, ptr::null_mut()) - }).unwrap(); - return SystemTime::from(s) - } - - pub fn sub_time(&self, other: &SystemTime) - -> Result { - self.t.sub_timespec(&other.t) - } - - pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime { t: self.t.add_duration(other) } - } - - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - SystemTime { t: self.t.sub_duration(other) } - } - } - - impl From for SystemTime { - fn from(t: libc::timeval) -> SystemTime { - SystemTime::from(libc::timespec { - tv_sec: t.tv_sec, - tv_nsec: (t.tv_usec * 1000) as libc::c_long, - }) - } - } - - impl From for SystemTime { - fn from(t: libc::timespec) -> SystemTime { - SystemTime { t: Timespec { t: t } } - } - } - - impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SystemTime") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } - } -} \ No newline at end of file diff --git a/ctr-std/src/sys/horizon/weak.rs b/ctr-std/src/sys/horizon/weak.rs deleted file mode 100644 index aa6394c..0000000 --- a/ctr-std/src/sys/horizon/weak.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Support for "weak linkage" to symbols on Unix -//! -//! Some I/O operations we do in libstd require newer versions of OSes but we -//! need to maintain binary compatibility with older releases for now. In order -//! to use the new functionality when available we use this module for -//! detection. -//! -//! One option to use here is weak linkage, but that is unfortunately only -//! really workable on Linux. Hence, use dlsym to get the symbol value at -//! runtime. This is also done for compatibility with older versions of glibc, -//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that -//! we've been dynamically linked to the library the symbol comes from, but that -//! is currently always the case for things like libpthread/libc. -//! -//! A long time ago this used weak linkage for the __pthread_get_minstack -//! symbol, but that caused Debian to detect an unnecessarily strict versioned -//! dependency on libc6 (#23628). - -use libc; - -use ffi::CString; -use marker; -use mem; -use sync::atomic::{AtomicUsize, Ordering}; - -macro_rules! weak { - (fn $name:ident($($t:ty),*) -> $ret:ty) => ( - static $name: ::sys::weak::Weak $ret> = - ::sys::weak::Weak::new(stringify!($name)); - ) -} - -pub struct Weak { - name: &'static str, - addr: AtomicUsize, - _marker: marker::PhantomData, -} - -impl Weak { - pub const fn new(name: &'static str) -> Weak { - Weak { - name, - addr: AtomicUsize::new(1), - _marker: marker::PhantomData, - } - } - - pub fn get(&self) -> Option<&F> { - assert_eq!(mem::size_of::(), mem::size_of::()); - unsafe { - if self.addr.load(Ordering::SeqCst) == 1 { - self.addr.store(fetch(self.name), Ordering::SeqCst); - } - if self.addr.load(Ordering::SeqCst) == 0 { - None - } else { - mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr) - } - } - } -} - -unsafe fn fetch(name: &str) -> usize { - let name = match CString::new(name) { - Ok(cstr) => cstr, - Err(..) => return 0, - }; - libc::dlsym(0 as _, name.as_ptr() as *const u8) as usize -} diff --git a/ctr-std/src/sys/mod.rs b/ctr-std/src/sys/mod.rs deleted file mode 100644 index 9aa6662..0000000 --- a/ctr-std/src/sys/mod.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Platform-dependent platform abstraction -//! -//! The `std::sys` module is the abstracted interface through which -//! `std` talks to the underlying operating system. It has different -//! implementations for different operating system families, today -//! just Unix and Windows, and initial support for Redox. -//! -//! The centralization of platform-specific code in this module is -//! enforced by the "platform abstraction layer" tidy script in -//! `tools/tidy/src/pal.rs`. -//! -//! This module is closely related to the platform-independent system -//! integration code in `std::sys_common`. See that module's -//! documentation for details. -//! -//! In the future it would be desirable for the independent -//! implementations of this module to be extracted to their own crates -//! that `std` can link to, thus enabling their implementation -//! out-of-tree via crate replacement. Though due to the complex -//! inter-dependencies within `std` that will be a challenging goal to -//! achieve. - -#![allow(missing_debug_implementations)] - -cfg_if! { - if #[cfg(target_os = "horizon")] { - mod horizon; - pub use self::horizon::*; - } else if #[cfg(unix)] { - mod unix; - pub use self::unix::*; - } else if #[cfg(windows)] { - mod windows; - pub use self::windows::*; - } else if #[cfg(target_os = "cloudabi")] { - mod cloudabi; - pub use self::cloudabi::*; - } else if #[cfg(target_os = "redox")] { - mod redox; - pub use self::redox::*; - } else if #[cfg(target_arch = "wasm32")] { - mod wasm; - pub use self::wasm::*; - } else { - compile_error!("libstd doesn't compile for this platform yet"); - } -} - -// Import essential modules from both platforms when documenting. These are -// then later used in the `std::os` module when documenting, for example, -// Windows when we're compiling for Linux. - -#[cfg(dox)] -cfg_if! { - if #[cfg(any(unix, target_os = "redox"))] { - // On unix we'll document what's already available - pub use self::ext as unix_ext; - } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] { - // On CloudABI and wasm right now the module below doesn't compile - // (missing things in `libc` which is empty) so just omit everything - // with an empty module - #[unstable(issue = "0", feature = "std_internals")] - #[allow(missing_docs)] - pub mod unix_ext {} - } else { - // On other platforms like Windows document the bare bones of unix - use os::linux as platform; - #[path = "unix/ext/mod.rs"] - pub mod unix_ext; - } -} - -#[cfg(dox)] -cfg_if! { - if #[cfg(windows)] { - // On windows we'll just be documenting what's already available - #[allow(missing_docs)] - pub use self::ext as windows_ext; - } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] { - // On CloudABI and wasm right now the shim below doesn't compile, so - // just omit it - #[unstable(issue = "0", feature = "std_internals")] - #[allow(missing_docs)] - pub mod windows_ext {} - } else { - // On all other platforms (aka linux/osx/etc) then pull in a "minimal" - // amount of windows goop which ends up compiling - #[macro_use] - #[path = "windows/compat.rs"] - mod compat; - - #[path = "windows/c.rs"] - mod c; - - #[path = "windows/ext/mod.rs"] - pub mod windows_ext; - } -} diff --git a/ctr-std/src/sys/redox/args.rs b/ctr-std/src/sys/redox/args.rs deleted file mode 100644 index 556ed77..0000000 --- a/ctr-std/src/sys/redox/args.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Global initialization and retrieval of command line arguments. -//! -//! On some platforms these are stored during runtime startup, -//! and on some they are retrieved from the system on demand. - -#![allow(dead_code)] // runtime init functions not used during testing - -use ffi::OsString; -use marker::PhantomData; -use vec; - -/// One-time global initialization. -pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } - -/// One-time global cleanup. -pub unsafe fn cleanup() { imp::cleanup() } - -/// Returns the command line arguments -pub fn args() -> Args { - imp::args() -} - -pub struct Args { - iter: vec::IntoIter, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Args { - pub fn inner_debug(&self) -> &[OsString] { - self.iter.as_slice() - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { self.iter.next() } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { self.iter.len() } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { self.iter.next_back() } -} - -mod imp { - use os::unix::prelude::*; - use mem; - use ffi::{CStr, OsString}; - use marker::PhantomData; - use libc; - use super::Args; - - use sys_common::mutex::Mutex; - - static mut GLOBAL_ARGS_PTR: usize = 0; - static LOCK: Mutex = Mutex::new(); - - pub unsafe fn init(argc: isize, argv: *const *const u8) { - let args = (0..argc).map(|i| { - CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec() - }).collect(); - - let _guard = LOCK.lock(); - let ptr = get_global_ptr(); - assert!((*ptr).is_none()); - (*ptr) = Some(box args); - } - - pub unsafe fn cleanup() { - let _guard = LOCK.lock(); - *get_global_ptr() = None; - } - - pub fn args() -> Args { - let bytes = clone().unwrap_or(Vec::new()); - let v: Vec = bytes.into_iter().map(|v| { - OsStringExt::from_vec(v) - }).collect(); - Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData } - } - - fn clone() -> Option>> { - unsafe { - let _guard = LOCK.lock(); - let ptr = get_global_ptr(); - (*ptr).as_ref().map(|s| (**s).clone()) - } - } - - unsafe fn get_global_ptr() -> *mut Option>>> { - mem::transmute(&GLOBAL_ARGS_PTR) - } - -} diff --git a/ctr-std/src/sys/redox/backtrace/mod.rs b/ctr-std/src/sys/redox/backtrace/mod.rs deleted file mode 100644 index 40b957d..0000000 --- a/ctr-std/src/sys/redox/backtrace/mod.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// See sys/unix/backtrace/mod.rs for an explanation of the method used here. - -pub use self::tracing::unwind_backtrace; -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; - -// tracing impls: -mod tracing; -// symbol resolvers: -mod printing; - -pub mod gnu { - use io; - use fs; - use libc::c_char; - use vec::Vec; - use ffi::OsStr; - use os::unix::ffi::OsStrExt; - use io::Read; - - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - let mut exefile = fs::File::open("sys:exe")?; - let mut exename = Vec::new(); - exefile.read_to_end(&mut exename)?; - if exename.last() == Some(&b'\n') { - exename.pop(); - } - let file = fs::File::open(OsStr::from_bytes(&exename))?; - Ok((exename.into_iter().map(|c| c as c_char).collect(), file)) - } -} - -pub struct BacktraceContext; diff --git a/ctr-std/src/sys/redox/backtrace/printing.rs b/ctr-std/src/sys/redox/backtrace/printing.rs deleted file mode 100644 index 3e937db..0000000 --- a/ctr-std/src/sys/redox/backtrace/printing.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; diff --git a/ctr-std/src/sys/redox/backtrace/tracing.rs b/ctr-std/src/sys/redox/backtrace/tracing.rs deleted file mode 100644 index c0414b7..0000000 --- a/ctr-std/src/sys/redox/backtrace/tracing.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use error::Error; -use io; -use libc; -use sys::backtrace::BacktraceContext; -use sys_common::backtrace::Frame; - -use unwind as uw; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl ::fmt::Display for UnwindError { - fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - let mut cx = Context { - idx: 0, - frames: frames, - }; - let result_unwind = unsafe { - uw::_Unwind_Backtrace(trace_fn, - &mut cx as *mut Context - as *mut libc::c_void) - }; - // See libunwind:src/unwind/Backtrace.c for the return values. - // No, there is no doc. - match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => { - Err(io::Error::new(io::ErrorKind::Other, - UnwindError(result_unwind))) - } - } -} - -extern fn trace_fn(ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { - let cx = unsafe { &mut *(arg as *mut Context) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - let mut ip_before_insn = 0; - let mut ip = unsafe { - uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void - }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; - } - - // dladdr() on osx gets whiny when we use FindEnclosingFunction, and - // it appears to work fine without it, so we only use - // FindEnclosingFunction on non-osx platforms. In doing so, we get a - // slightly more accurate stack trace in the process. - // - // This is often because panic involves the last instruction of a - // function being "call std::rt::begin_unwind", with no ret - // instructions after it. This means that the return instruction - // pointer points *outside* of the calling function, and by - // unwinding it we go back to the original function. - let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { - ip - } else { - unsafe { uw::_Unwind_FindEnclosingFunction(ip) } - }; - - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} diff --git a/ctr-std/src/sys/redox/cmath.rs b/ctr-std/src/sys/redox/cmath.rs deleted file mode 100644 index 2bc9665..0000000 --- a/ctr-std/src/sys/redox/cmath.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg(not(test))] - -use libc::{c_float, c_double}; - -#[link_name = "m"] -extern { - pub fn acos(n: c_double) -> c_double; - pub fn acosf(n: c_float) -> c_float; - pub fn asin(n: c_double) -> c_double; - pub fn asinf(n: c_float) -> c_float; - pub fn atan(n: c_double) -> c_double; - pub fn atan2(a: c_double, b: c_double) -> c_double; - pub fn atan2f(a: c_float, b: c_float) -> c_float; - pub fn atanf(n: c_float) -> c_float; - pub fn cbrt(n: c_double) -> c_double; - pub fn cbrtf(n: c_float) -> c_float; - pub fn cosh(n: c_double) -> c_double; - pub fn coshf(n: c_float) -> c_float; - pub fn expm1(n: c_double) -> c_double; - pub fn expm1f(n: c_float) -> c_float; - pub fn fdim(a: c_double, b: c_double) -> c_double; - pub fn fdimf(a: c_float, b: c_float) -> c_float; - pub fn hypot(x: c_double, y: c_double) -> c_double; - pub fn hypotf(x: c_float, y: c_float) -> c_float; - pub fn log1p(n: c_double) -> c_double; - pub fn log1pf(n: c_float) -> c_float; - pub fn sinh(n: c_double) -> c_double; - pub fn sinhf(n: c_float) -> c_float; - pub fn tan(n: c_double) -> c_double; - pub fn tanf(n: c_float) -> c_float; - pub fn tanh(n: c_double) -> c_double; - pub fn tanhf(n: c_float) -> c_float; -} diff --git a/ctr-std/src/sys/redox/condvar.rs b/ctr-std/src/sys/redox/condvar.rs deleted file mode 100644 index 2a611ed..0000000 --- a/ctr-std/src/sys/redox/condvar.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use intrinsics::{atomic_cxchg, atomic_load, atomic_xadd, atomic_xchg}; -use ptr; -use time::Duration; - -use sys::mutex::{mutex_unlock, Mutex}; -use sys::syscall::{futex, TimeSpec, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE}; - -pub struct Condvar { - lock: UnsafeCell<*mut i32>, - seq: UnsafeCell -} - -impl Condvar { - pub const fn new() -> Condvar { - Condvar { - lock: UnsafeCell::new(ptr::null_mut()), - seq: UnsafeCell::new(0) - } - } - - #[inline] - pub unsafe fn init(&self) { - *self.lock.get() = ptr::null_mut(); - *self.seq.get() = 0; - } - - #[inline] - pub fn notify_one(&self) { - unsafe { - let seq = self.seq.get(); - - atomic_xadd(seq, 1); - - let _ = futex(seq, FUTEX_WAKE, 1, 0, ptr::null_mut()); - } - } - - #[inline] - pub fn notify_all(&self) { - unsafe { - let lock = self.lock.get(); - let seq = self.seq.get(); - - if *lock == ptr::null_mut() { - return; - } - - atomic_xadd(seq, 1); - - let _ = futex(seq, FUTEX_REQUEUE, 1, ::usize::MAX, *lock); - } - } - - #[inline] - unsafe fn wait_inner(&self, mutex: &Mutex, timeout_ptr: *const TimeSpec) -> bool { - let lock = self.lock.get(); - let seq = self.seq.get(); - - if *lock != mutex.lock.get() { - if *lock != ptr::null_mut() { - panic!("Condvar used with more than one Mutex"); - } - - atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize); - } - - mutex_unlock(*lock); - - let seq_before = atomic_load(seq); - - let _ = futex(seq, FUTEX_WAIT, seq_before, timeout_ptr as usize, ptr::null_mut()); - - let seq_after = atomic_load(seq); - - while atomic_xchg(*lock, 2) != 0 { - let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut()); - } - - seq_before != seq_after - } - - #[inline] - pub fn wait(&self, mutex: &Mutex) { - unsafe { - assert!(self.wait_inner(mutex, ptr::null())); - } - } - - #[inline] - pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - unsafe { - let timeout = TimeSpec { - tv_sec: dur.as_secs() as i64, - tv_nsec: dur.subsec_nanos() as i32 - }; - - self.wait_inner(mutex, &timeout as *const TimeSpec) - } - } - - #[inline] - pub unsafe fn destroy(&self) { - *self.lock.get() = ptr::null_mut(); - *self.seq.get() = 0; - } -} - -unsafe impl Send for Condvar {} - -unsafe impl Sync for Condvar {} diff --git a/ctr-std/src/sys/redox/env.rs b/ctr-std/src/sys/redox/env.rs deleted file mode 100644 index 669b752..0000000 --- a/ctr-std/src/sys/redox/env.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub mod os { - pub const FAMILY: &'static str = "redox"; - pub const OS: &'static str = "redox"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} diff --git a/ctr-std/src/sys/redox/ext/ffi.rs b/ctr-std/src/sys/redox/ext/ffi.rs deleted file mode 100644 index cd88c8f..0000000 --- a/ctr-std/src/sys/redox/ext/ffi.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Redox-specific extension to the primitives in the `std::ffi` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use ffi::{OsStr, OsString}; -use mem; -use sys::os_str::Buf; -use sys_common::{FromInner, IntoInner, AsInner}; - -/// Redox-specific extensions to [`OsString`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStringExt { - /// Creates an `OsString` from a byte vector. - #[stable(feature = "rust1", since = "1.0.0")] - fn from_vec(vec: Vec) -> Self; - - /// Yields the underlying byte vector of this `OsString`. - #[stable(feature = "rust1", since = "1.0.0")] - fn into_vec(self) -> Vec; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStringExt for OsString { - fn from_vec(vec: Vec) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec { - self.into_inner().inner - } -} - -/// Redox-specific extensions to [`OsStr`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStrExt { - #[stable(feature = "rust1", since = "1.0.0")] - fn from_bytes(slice: &[u8]) -> &Self; - - /// Gets the underlying byte view of the `OsStr` slice. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_bytes(&self) -> &[u8]; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } -} diff --git a/ctr-std/src/sys/redox/ext/fs.rs b/ctr-std/src/sys/redox/ext/fs.rs deleted file mode 100644 index c1dba6e..0000000 --- a/ctr-std/src/sys/redox/ext/fs.rs +++ /dev/null @@ -1,349 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Redox-specific extensions to primitives in the `std::fs` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use fs::{self, Permissions, OpenOptions}; -use io; -use path::Path; -use sys; -use sys_common::{FromInner, AsInner, AsInnerMut}; - -/// Redox-specific extensions to [`fs::Permissions`]. -/// -/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait PermissionsExt { - /// Returns the underlying raw `mode_t` bits that are the standard Redox - /// permissions for this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::redox::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let permissions = metadata.permissions(); - /// - /// println!("permissions: {}", permissions.mode()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&self) -> u32; - - /// Sets the underlying raw bits for this set of permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::redox::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); - /// - /// permissions.set_mode(0o644); // Read/write for owner and read for others. - /// assert_eq!(permissions.mode(), 0o644); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn set_mode(&mut self, mode: u32); - - /// Creates a new instance of `Permissions` from the given set of Redox - /// permission bits. - /// - /// # Examples - /// - /// ``` - /// use std::fs::Permissions; - /// use std::os::redox::fs::PermissionsExt; - /// - /// // Read/write for owner and read for others. - /// let permissions = Permissions::from_mode(0o644); - /// assert_eq!(permissions.mode(), 0o644); - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn from_mode(mode: u32) -> Self; -} - -#[stable(feature = "fs_ext", since = "1.1.0")] -impl PermissionsExt for Permissions { - fn mode(&self) -> u32 { - self.as_inner().mode() - } - - fn set_mode(&mut self, mode: u32) { - *self = Permissions::from_inner(FromInner::from_inner(mode)); - } - - fn from_mode(mode: u32) -> Permissions { - Permissions::from_inner(FromInner::from_inner(mode)) - } -} - -/// Redox-specific extensions to [`fs::OpenOptions`]. -/// -/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait OpenOptionsExt { - /// Sets the mode bits that a new file will be created with. - /// - /// If a new file is created as part of a `File::open_opts` call then this - /// specified `mode` will be used as the permission bits for the new file. - /// If no `mode` is set, the default of `0o666` will be used. - /// The operating system masks out bits with the systems `umask`, to produce - /// the final permissions. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(libc)] - /// extern crate libc; - /// use std::fs::OpenOptions; - /// use std::os::redox::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.mode(0o644); // Give read/write for owner and read for others. - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&mut self, mode: u32) -> &mut Self; - - /// Pass custom flags to the `flags` argument of `open`. - /// - /// The bits that define the access mode are masked out with `O_ACCMODE`, to - /// ensure they do not interfere with the access mode set by Rusts options. - /// - /// Custom flags can only set flags, not remove flags set by Rusts options. - /// This options overwrites any previously set custom flags. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(libc)] - /// extern crate libc; - /// use std::fs::OpenOptions; - /// use std::os::redox::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.write(true); - /// if cfg!(target_os = "redox") { - /// options.custom_flags(libc::O_NOFOLLOW); - /// } - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn custom_flags(&mut self, flags: i32) -> &mut Self; -} - -#[stable(feature = "fs_ext", since = "1.1.0")] -impl OpenOptionsExt for OpenOptions { - fn mode(&mut self, mode: u32) -> &mut OpenOptions { - self.as_inner_mut().mode(mode); self - } - - fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { - self.as_inner_mut().custom_flags(flags); self - } -} - -/// Redox-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn dev(&self) -> u64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ino(&self) -> u64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mode(&self) -> u32; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn nlink(&self) -> u64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn uid(&self) -> u32; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn gid(&self) -> u32; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn size(&self) -> u64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn atime(&self) -> i64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mtime(&self) -> i64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ctime(&self) -> i64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blksize(&self) -> u64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blocks(&self) -> u64; -} - -// Hm, why are there casts here to the returned type, shouldn't the types always -// be the same? Right you are! Turns out, however, on android at least the types -// in the raw `stat` structure are not the same as the types being returned. Who -// knew! -// -// As a result to make sure this compiles for all platforms we do the manual -// casts and rely on manual lowering to `stat` if the raw type is desired. -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for fs::Metadata { - fn dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } -} - -/// Redox-specific extensions for [`FileType`]. -/// -/// Adds support for special Unix file types such as block/character devices, -/// pipes, and sockets. -/// -/// [`FileType`]: ../../../../std/fs/struct.FileType.html -#[stable(feature = "file_type_ext", since = "1.5.0")] -pub trait FileTypeExt { - /// Returns whether this file type is a block device. - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_block_device(&self) -> bool; - /// Returns whether this file type is a char device. - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_char_device(&self) -> bool; - /// Returns whether this file type is a fifo. - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_fifo(&self) -> bool; - /// Returns whether this file type is a socket. - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_socket(&self) -> bool; -} - -#[stable(feature = "file_type_ext", since = "1.5.0")] -impl FileTypeExt for fs::FileType { - fn is_block_device(&self) -> bool { false /*FIXME: Implement block device mode*/ } - fn is_char_device(&self) -> bool { false /*FIXME: Implement char device mode*/ } - fn is_fifo(&self) -> bool { false /*FIXME: Implement fifo mode*/ } - fn is_socket(&self) -> bool { false /*FIXME: Implement socket mode*/ } -} - -/// Creates a new symbolic link on the filesystem. -/// -/// The `dst` path will be a symbolic link pointing to the `src` path. -/// -/// # Note -/// -/// On Windows, you must specify whether a symbolic link points to a file -/// or directory. Use `os::windows::fs::symlink_file` to create a -/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a -/// symbolic link to a directory. Additionally, the process must have -/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a -/// symbolic link. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::redox::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::symlink("a.txt", "b.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> -{ - sys::fs::symlink(src.as_ref(), dst.as_ref()) -} - -/// Redox-specific extensions to [`fs::DirBuilder`]. -/// -/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html -#[stable(feature = "dir_builder", since = "1.6.0")] -pub trait DirBuilderExt { - /// Sets the mode to create new directories with. This option defaults to - /// 0o777. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::DirBuilder; - /// use std::os::redox::fs::DirBuilderExt; - /// - /// let mut builder = DirBuilder::new(); - /// builder.mode(0o755); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - fn mode(&mut self, mode: u32) -> &mut Self; -} - -#[stable(feature = "dir_builder", since = "1.6.0")] -impl DirBuilderExt for fs::DirBuilder { - fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { - self.as_inner_mut().set_mode(mode); - self - } -} diff --git a/ctr-std/src/sys/redox/ext/io.rs b/ctr-std/src/sys/redox/ext/io.rs deleted file mode 100644 index c4d9956..0000000 --- a/ctr-std/src/sys/redox/ext/io.rs +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific extensions to general I/O primitives - -#![stable(feature = "rust1", since = "1.0.0")] - -use fs; -use net; -use sys; -use io; -use sys_common::{self, AsInner, FromInner, IntoInner}; - -/// Raw file descriptors. -#[stable(feature = "rust1", since = "1.0.0")] -pub type RawFd = usize; - -/// A trait to extract the raw unix file descriptor from an underlying -/// object. -/// -/// This is only available on unix platforms and must be imported in order -/// to call the method. Windows platforms have a corresponding `AsRawHandle` -/// and `AsRawSocket` set of traits. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsRawFd { - /// Extracts the raw file descriptor. - /// - /// This method does **not** pass ownership of the raw file descriptor - /// to the caller. The descriptor is only guaranteed to be valid while - /// the original object has not yet been destroyed. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_fd(&self) -> RawFd; -} - -/// A trait to express the ability to construct an object from a raw file -/// descriptor. -#[stable(feature = "from_raw_os", since = "1.1.0")] -pub trait FromRawFd { - /// Constructs a new instances of `Self` from the given raw file - /// descriptor. - /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - #[stable(feature = "from_raw_os", since = "1.1.0")] - unsafe fn from_raw_fd(fd: RawFd) -> Self; -} - -/// A trait to express the ability to consume an object and acquire ownership of -/// its raw file descriptor. -#[stable(feature = "into_raw_os", since = "1.4.0")] -pub trait IntoRawFd { - /// Consumes this object, returning the raw underlying file descriptor. - /// - /// This function **transfers ownership** of the underlying file descriptor - /// to the caller. Callers are then the unique owners of the file descriptor - /// and must close the descriptor once it's no longer needed. - #[stable(feature = "into_raw_os", since = "1.4.0")] - fn into_raw_fd(self) -> RawFd; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for fs::File { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for fs::File { - unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs::File::from_inner(fd)) - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for fs::File { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().as_inner().fd().raw() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().as_inner().fd().raw() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().as_inner().fd().raw() - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdin { - fn as_raw_fd(&self) -> RawFd { 0 } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdout { - fn as_raw_fd(&self) -> RawFd { 1 } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stderr { - fn as_raw_fd(&self) -> RawFd { 2 } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let file = sys::fs::File::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(file)) - } -} -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let file = sys::fs::File::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(file)) - } -} -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let file = sys::fs::File::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(file)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_inner().into_fd().into_raw() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_inner().into_fd().into_raw() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_inner().into_fd().into_raw() - } -} diff --git a/ctr-std/src/sys/redox/ext/mod.rs b/ctr-std/src/sys/redox/ext/mod.rs deleted file mode 100644 index cb2c75a..0000000 --- a/ctr-std/src/sys/redox/ext/mod.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Experimental extensions to `std` for Unix platforms. -//! -//! For now, this module is limited to extracting file descriptors, -//! but its functionality will grow over time. -//! -//! # Examples -//! -//! ```no_run -//! use std::fs::File; -//! use std::os::unix::prelude::*; -//! -//! fn main() { -//! let f = File::create("foo.txt").unwrap(); -//! let fd = f.as_raw_fd(); -//! -//! // use fd with native unix bindings -//! } -//! ``` - -#![stable(feature = "rust1", since = "1.0.0")] -#![doc(cfg(target_os = "redox"))] - -pub mod ffi; -pub mod fs; -pub mod io; -pub mod net; -pub mod process; -pub mod thread; - -/// A prelude for conveniently writing platform-specific code. -/// -/// Includes all extension traits, and some important type definitions. -#[stable(feature = "rust1", since = "1.0.0")] -pub mod prelude { - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::fs::{FileTypeExt, PermissionsExt, OpenOptionsExt, MetadataExt}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::thread::JoinHandleExt; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::process::{CommandExt, ExitStatusExt}; -} diff --git a/ctr-std/src/sys/redox/ext/net.rs b/ctr-std/src/sys/redox/ext/net.rs deleted file mode 100644 index 2ab7770..0000000 --- a/ctr-std/src/sys/redox/ext/net.rs +++ /dev/null @@ -1,769 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "unix_socket_redox", since = "1.29")] - -//! Unix-specific networking functionality - -use fmt; -use io::{self, Error, ErrorKind, Initializer}; -use net::Shutdown; -use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; -use path::Path; -use time::Duration; -use sys::{cvt, fd::FileDesc, syscall}; - -/// An address associated with a Unix socket. -/// -/// # Examples -/// -/// ``` -/// use std::os::unix::net::UnixListener; -/// -/// let socket = match UnixListener::bind("/tmp/sock") { -/// Ok(sock) => sock, -/// Err(e) => { -/// println!("Couldn't bind: {:?}", e); -/// return -/// } -/// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); -/// ``` -#[derive(Clone)] -#[stable(feature = "unix_socket_redox", since = "1.29")] -pub struct SocketAddr(()); - -impl SocketAddr { - /// Returns the contents of this address if it is a `pathname` address. - /// - /// # Examples - /// - /// With a pathname: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// use std::path::Path; - /// - /// let socket = UnixListener::bind("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); - /// ``` - /// - /// Without a pathname: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), None); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn as_pathname(&self) -> Option<&Path> { - None - } - - /// Returns true if and only if the address is unnamed. - /// - /// # Examples - /// - /// A named address: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let socket = UnixListener::bind("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), false); - /// ``` - /// - /// An unnamed address: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), true); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn is_unnamed(&self) -> bool { - false - } -} -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "SocketAddr") - } -} - -/// A Unix stream socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixStream; -/// use std::io::prelude::*; -/// -/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); -/// stream.write_all(b"hello world").unwrap(); -/// let mut response = String::new(); -/// stream.read_to_string(&mut response).unwrap(); -/// println!("{}", response); -/// ``` -#[stable(feature = "unix_socket_redox", since = "1.29")] -pub struct UnixStream(FileDesc); - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixStream"); - builder.field("fd", &self.0.raw()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixStream { - /// Connects to the socket named by `path`. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = match UnixStream::connect("/tmp/sock") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn connect>(path: P) -> io::Result { - if let Some(s) = path.as_ref().to_str() { - cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) - .map(FileDesc::new) - .map(UnixStream) - } else { - Err(Error::new( - ErrorKind::Other, - "UnixStream::connect: non-utf8 paths not supported on redox" - )) - } - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixStream`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let (sock1, sock2) = match UnixStream::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't create a pair of sockets: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) - .map(FileDesc::new)?; - let client = server.duplicate_path(b"connect")?; - let stream = server.duplicate_path(b"listen")?; - Ok((UnixStream(client), UnixStream(stream))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixStream` is a reference to the same stream that this - /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propagated to the other - /// stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixStream) - } - - /// Returns the socket address of the local half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn local_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) - } - - /// Returns the socket address of the remote half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn peer_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn read_timeout(&self) -> io::Result> { - Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn write_timeout(&self) -> io::Result> { - Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns None. - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn take_error(&self) -> io::Result> { - Ok(None) - } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::net::Shutdown; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) - } -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl io::Read for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - io::Read::read(&mut &*self, buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl io::Write for UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - io::Write::write(&mut &*self, buf) - } - - fn flush(&mut self) -> io::Result<()> { - io::Write::flush(&mut &*self) - } -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - self.0.raw() - } -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(FileDesc::new(fd)) - } -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw() - } -} - -/// A structure representing a Unix domain socket server. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); -/// -/// // accept connections and process them, spawning a new thread for each one -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// /* connection succeeded */ -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// /* connection failed */ -/// break; -/// } -/// } -/// } -/// ``` -#[stable(feature = "unix_socket_redox", since = "1.29")] -pub struct UnixListener(FileDesc); - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixListener"); - builder.field("fd", &self.0.raw()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - builder.finish() - } -} - -impl UnixListener { - /// Creates a new `UnixListener` bound to the specified socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = match UnixListener::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn bind>(path: P) -> io::Result { - if let Some(s) = path.as_ref().to_str() { - cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) - .map(FileDesc::new) - .map(UnixListener) - } else { - Err(Error::new( - ErrorKind::Other, - "UnixListener::bind: non-utf8 paths not supported on redox" - )) - } - } - - /// Accepts a new incoming connection to this listener. - /// - /// This function will block the calling thread until a new Unix connection - /// is established. When established, the corresponding [`UnixStream`] and - /// the remote peer's address will be returned. - /// - /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), - /// } - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixListener` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one listener will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let listener_copy = listener.try_clone().expect("try_clone failed"); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixListener) - } - - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let addr = listener.local_addr().expect("Couldn't get local address"); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn local_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/tmp/sock").unwrap(); - /// - /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns None. - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn take_error(&self) -> io::Result> { - Ok(None) - } - - /// Returns an iterator over incoming connections. - /// - /// The iterator will never return [`None`] and will also not yield the - /// peer's [`SocketAddr`] structure. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`SocketAddr`]: struct.SocketAddr.html - /// - /// # Examples - /// - /// ```no_run - /// use std::thread; - /// use std::os::unix::net::{UnixStream, UnixListener}; - /// - /// fn handle_client(stream: UnixStream) { - /// // ... - /// } - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// thread::spawn(|| handle_client(stream)); - /// } - /// Err(err) => { - /// break; - /// } - /// } - /// } - /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] - pub fn incoming<'a>(&'a self) -> Incoming<'a> { - Incoming { listener: self } - } -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - self.0.raw() - } -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(FileDesc::new(fd)) - } -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw() - } -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl<'a> IntoIterator for &'a UnixListener { - type Item = io::Result; - type IntoIter = Incoming<'a>; - - fn into_iter(self) -> Incoming<'a> { - self.incoming() - } -} - -/// An iterator over incoming connections to a [`UnixListener`]. -/// -/// It will never return [`None`]. -/// -/// [`None`]: ../../../../std/option/enum.Option.html#variant.None -/// [`UnixListener`]: struct.UnixListener.html -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); -/// -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// break; -/// } -/// } -/// } -/// ``` -#[derive(Debug)] -#[stable(feature = "unix_socket_redox", since = "1.29")] -pub struct Incoming<'a> { - listener: &'a UnixListener, -} - -#[stable(feature = "unix_socket_redox", since = "1.29")] -impl<'a> Iterator for Incoming<'a> { - type Item = io::Result; - - fn next(&mut self) -> Option> { - Some(self.listener.accept().map(|s| s.0)) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::max_value(), None) - } -} diff --git a/ctr-std/src/sys/redox/ext/process.rs b/ctr-std/src/sys/redox/ext/process.rs deleted file mode 100644 index cfb6d5f..0000000 --- a/ctr-std/src/sys/redox/ext/process.rs +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Redox-specific extensions to primitives in the `std::process` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use io; -use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd}; -use process; -use sys; -use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; - -/// Redox-specific extensions to the [`process::Command`] builder, -/// -/// [`process::Command`]: ../../../../std/process/struct.Command.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait CommandExt { - /// Sets the child process's user id. This translates to a - /// `setuid` call in the child process. Failure in the `setuid` - /// call will cause the spawn to fail. - #[stable(feature = "rust1", since = "1.0.0")] - fn uid(&mut self, id: u32) -> &mut process::Command; - - /// Similar to `uid`, but sets the group id of the child process. This has - /// the same semantics as the `uid` field. - #[stable(feature = "rust1", since = "1.0.0")] - fn gid(&mut self, id: u32) -> &mut process::Command; - - /// Schedules a closure to be run just before the `exec` function is - /// invoked. - /// - /// The closure is allowed to return an I/O error whose OS error code will - /// be communicated back to the parent and returned as an error from when - /// the spawn was requested. - /// - /// Multiple closures can be registered and they will be called in order of - /// their registration. If a closure returns `Err` then no further closures - /// will be called and the spawn operation will immediately return with a - /// failure. - /// - /// # Notes - /// - /// This closure will be run in the context of the child process after a - /// `fork`. This primarily means that any modifications made to memory on - /// behalf of this closure will **not** be visible to the parent process. - /// This is often a very constrained environment where normal operations - /// like `malloc` or acquiring a mutex are not guaranteed to work (due to - /// other threads perhaps still running when the `fork` was run). - /// - /// When this closure is run, aspects such as the stdio file descriptors and - /// working directory have successfully been changed, so output to these - /// locations may not appear where intended. - #[stable(feature = "process_exec", since = "1.15.0")] - fn before_exec(&mut self, f: F) -> &mut process::Command - where F: FnMut() -> io::Result<()> + Send + Sync + 'static; - - /// Performs all the required setup by this `Command`, followed by calling - /// the `execvp` syscall. - /// - /// On success this function will not return, and otherwise it will return - /// an error indicating why the exec (or another part of the setup of the - /// `Command`) failed. - /// - /// This function, unlike `spawn`, will **not** `fork` the process to create - /// a new child. Like spawn, however, the default behavior for the stdio - /// descriptors will be to inherited from the current process. - /// - /// # Notes - /// - /// The process may be in a "broken state" if this function returns in - /// error. For example the working directory, environment variables, signal - /// handling settings, various user/group information, or aspects of stdio - /// file descriptors may have changed. If a "transactional spawn" is - /// required to gracefully handle errors it is recommended to use the - /// cross-platform `spawn` instead. - #[stable(feature = "process_exec2", since = "1.9.0")] - fn exec(&mut self) -> io::Error; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl CommandExt for process::Command { - fn uid(&mut self, id: u32) -> &mut process::Command { - self.as_inner_mut().uid(id); - self - } - - fn gid(&mut self, id: u32) -> &mut process::Command { - self.as_inner_mut().gid(id); - self - } - - fn before_exec(&mut self, f: F) -> &mut process::Command - where F: FnMut() -> io::Result<()> + Send + Sync + 'static - { - self.as_inner_mut().before_exec(Box::new(f)); - self - } - - fn exec(&mut self) -> io::Error { - self.as_inner_mut().exec(sys::process::Stdio::Inherit) - } -} - -/// Redox-specific extensions to [`process::ExitStatus`]. -/// -/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait ExitStatusExt { - /// Creates a new `ExitStatus` from the raw underlying `i32` return value of - /// a process. - #[stable(feature = "exit_status_from", since = "1.12.0")] - fn from_raw(raw: i32) -> Self; - - /// If the process was terminated by a signal, returns that signal. - #[stable(feature = "rust1", since = "1.0.0")] - fn signal(&self) -> Option; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExitStatusExt for process::ExitStatus { - fn from_raw(raw: i32) -> Self { - process::ExitStatus::from_inner(From::from(raw)) - } - - fn signal(&self) -> Option { - self.as_inner().signal() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl FromRawFd for process::Stdio { - unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { - let fd = sys::fd::FileDesc::new(fd); - let io = sys::process::Stdio::Fd(fd); - process::Stdio::from_inner(io) - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStdin { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStdout { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStderr { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStdin { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStdout { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStderr { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} diff --git a/ctr-std/src/sys/redox/ext/thread.rs b/ctr-std/src/sys/redox/ext/thread.rs deleted file mode 100644 index 71ff0d4..0000000 --- a/ctr-std/src/sys/redox/ext/thread.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Redox-specific extensions to primitives in the `std::thread` module. - -#![stable(feature = "thread_extensions", since = "1.9.0")] - -use sys_common::{AsInner, IntoInner}; -use thread::JoinHandle; - -#[stable(feature = "thread_extensions", since = "1.9.0")] -#[allow(deprecated)] -pub type RawPthread = usize; - -/// Redox-specific extensions to [`thread::JoinHandle`]. -/// -/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html -#[stable(feature = "thread_extensions", since = "1.9.0")] -pub trait JoinHandleExt { - /// Extracts the raw pthread_t without taking ownership - #[stable(feature = "thread_extensions", since = "1.9.0")] - fn as_pthread_t(&self) -> RawPthread; - - /// Consumes the thread, returning the raw pthread_t - /// - /// This function **transfers ownership** of the underlying pthread_t to - /// the caller. Callers are then the unique owners of the pthread_t and - /// must either detach or join the pthread_t once it's no longer needed. - #[stable(feature = "thread_extensions", since = "1.9.0")] - fn into_pthread_t(self) -> RawPthread; -} - -#[stable(feature = "thread_extensions", since = "1.9.0")] -impl JoinHandleExt for JoinHandle { - fn as_pthread_t(&self) -> RawPthread { - self.as_inner().id() as RawPthread - } - - fn into_pthread_t(self) -> RawPthread { - self.into_inner().into_id() as RawPthread - } -} diff --git a/ctr-std/src/sys/redox/fast_thread_local.rs b/ctr-std/src/sys/redox/fast_thread_local.rs deleted file mode 100644 index 6a007e9..0000000 --- a/ctr-std/src/sys/redox/fast_thread_local.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg(target_thread_local)] -#![unstable(feature = "thread_local_internals", issue = "0")] - -use cell::{Cell, UnsafeCell}; -use mem; -use ptr; - - -pub struct Key { - inner: UnsafeCell>, - - // Metadata to keep track of the state of the destructor. Remember that - // these variables are thread-local, not global. - dtor_registered: Cell, - dtor_running: Cell, -} - -unsafe impl ::marker::Sync for Key { } - -impl Key { - pub const fn new() -> Key { - Key { - inner: UnsafeCell::new(None), - dtor_registered: Cell::new(false), - dtor_running: Cell::new(false) - } - } - - pub fn get(&'static self) -> Option<&'static UnsafeCell>> { - unsafe { - if mem::needs_drop::() && self.dtor_running.get() { - return None - } - self.register_dtor(); - } - Some(&self.inner) - } - - unsafe fn register_dtor(&self) { - if !mem::needs_drop::() || self.dtor_registered.get() { - return - } - - register_dtor(self as *const _ as *mut u8, - destroy_value::); - self.dtor_registered.set(true); - } -} - -pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - // The fallback implementation uses a vanilla OS-based TLS key to track - // the list of destructors that need to be run for this thread. The key - // then has its own destructor which runs all the other destructors. - // - // The destructor for DTORS is a little special in that it has a `while` - // loop to continuously drain the list of registered destructors. It - // *should* be the case that this loop always terminates because we - // provide the guarantee that a TLS key cannot be set after it is - // flagged for destruction. - use sys_common::thread_local as os; - - static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors)); - type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; - if DTORS.get().is_null() { - let v: Box = box Vec::new(); - DTORS.set(Box::into_raw(v) as *mut u8); - } - let list: &mut List = &mut *(DTORS.get() as *mut List); - list.push((t, dtor)); - - unsafe extern fn run_dtors(mut ptr: *mut u8) { - while !ptr.is_null() { - let list: Box = Box::from_raw(ptr as *mut List); - for (ptr, dtor) in list.into_iter() { - dtor(ptr); - } - ptr = DTORS.get(); - DTORS.set(ptr::null_mut()); - } - } -} - -pub unsafe extern fn destroy_value(ptr: *mut u8) { - let ptr = ptr as *mut Key; - // Right before we run the user destructor be sure to flag the - // destructor as running for this thread so calls to `get` will return - // `None`. - (*ptr).dtor_running.set(true); - - // The macOS implementation of TLS apparently had an odd aspect to it - // where the pointer we have may be overwritten while this destructor - // is running. Specifically if a TLS destructor re-accesses TLS it may - // trigger a re-initialization of all TLS variables, paving over at - // least some destroyed ones with initial values. - // - // This means that if we drop a TLS value in place on macOS that we could - // revert the value to its original state halfway through the - // destructor, which would be bad! - // - // Hence, we use `ptr::read` on macOS (to move to a "safe" location) - // instead of drop_in_place. - if cfg!(target_os = "macos") { - ptr::read((*ptr).inner.get()); - } else { - ptr::drop_in_place((*ptr).inner.get()); - } -} - -pub fn requires_move_before_drop() -> bool { - false -} diff --git a/ctr-std/src/sys/redox/fd.rs b/ctr-std/src/sys/redox/fd.rs deleted file mode 100644 index e04e279..0000000 --- a/ctr-std/src/sys/redox/fd.rs +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(reason = "not public", issue = "0", feature = "fd")] - -use io::{self, Read}; -use mem; -use sys::{cvt, syscall}; -use sys_common::AsInner; - -pub struct FileDesc { - fd: usize, -} - -impl FileDesc { - pub fn new(fd: usize) -> FileDesc { - FileDesc { fd: fd } - } - - pub fn raw(&self) -> usize { self.fd } - - /// Extracts the actual filedescriptor without closing it. - pub fn into_raw(self) -> usize { - let fd = self.fd; - mem::forget(self); - fd - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - cvt(syscall::read(self.fd, buf)) - } - - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - let mut me = self; - (&mut me).read_to_end(buf) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - cvt(syscall::write(self.fd, buf)) - } - - pub fn duplicate(&self) -> io::Result { - self.duplicate_path(&[]) - } - pub fn duplicate_path(&self, path: &[u8]) -> io::Result { - let new_fd = cvt(syscall::dup(self.fd, path))?; - Ok(FileDesc::new(new_fd)) - } - - pub fn nonblocking(&self) -> io::Result { - let flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?; - Ok(flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK) - } - - pub fn set_cloexec(&self) -> io::Result<()> { - let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFD, 0))?; - flags |= syscall::O_CLOEXEC; - cvt(syscall::fcntl(self.fd, syscall::F_SETFD, flags)).and(Ok(())) - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?; - if nonblocking { - flags |= syscall::O_NONBLOCK; - } else { - flags &= !syscall::O_NONBLOCK; - } - cvt(syscall::fcntl(self.fd, syscall::F_SETFL, flags)).and(Ok(())) - } -} - -impl<'a> Read for &'a FileDesc { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (**self).read(buf) - } -} - -impl AsInner for FileDesc { - fn as_inner(&self) -> &usize { &self.fd } -} - -impl Drop for FileDesc { - fn drop(&mut self) { - // Note that errors are ignored when closing a file descriptor. The - // reason for this is that if an error occurs we don't actually know if - // the file descriptor was closed or not, and if we retried (for - // something like EINTR), we might close another valid file descriptor - // (opened after we closed ours. - let _ = syscall::close(self.fd); - } -} diff --git a/ctr-std/src/sys/redox/fs.rs b/ctr-std/src/sys/redox/fs.rs deleted file mode 100644 index 2e22161..0000000 --- a/ctr-std/src/sys/redox/fs.rs +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use os::unix::prelude::*; - -use ffi::{OsString, OsStr}; -use fmt; -use io::{self, Error, ErrorKind, SeekFrom}; -use path::{Path, PathBuf}; -use sync::Arc; -use sys::fd::FileDesc; -use sys::time::SystemTime; -use sys::{cvt, syscall}; -use sys_common::{AsInner, FromInner}; - -pub struct File(FileDesc); - -#[derive(Clone)] -pub struct FileAttr { - stat: syscall::Stat, -} - -pub struct ReadDir { - data: Vec, - i: usize, - root: Arc, -} - -struct Dir(FileDesc); - -unsafe impl Send for Dir {} -unsafe impl Sync for Dir {} - -pub struct DirEntry { - root: Arc, - name: Box<[u8]> -} - -#[derive(Clone, Debug)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - custom_flags: i32, - mode: u16, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct FilePermissions { mode: u16 } - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct FileType { mode: u16 } - -#[derive(Debug)] -pub struct DirBuilder { mode: u16 } - -impl FileAttr { - pub fn size(&self) -> u64 { self.stat.st_size as u64 } - pub fn perm(&self) -> FilePermissions { - FilePermissions { mode: (self.stat.st_mode as u16) & 0o777 } - } - - pub fn file_type(&self) -> FileType { - FileType { mode: self.stat.st_mode as u16 } - } -} - -impl FileAttr { - pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(syscall::TimeSpec { - tv_sec: self.stat.st_mtime as i64, - tv_nsec: self.stat.st_mtime_nsec as i32, - })) - } - - pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(syscall::TimeSpec { - tv_sec: self.stat.st_atime as i64, - tv_nsec: self.stat.st_atime_nsec as i32, - })) - } - - pub fn created(&self) -> io::Result { - Ok(SystemTime::from(syscall::TimeSpec { - tv_sec: self.stat.st_ctime as i64, - tv_nsec: self.stat.st_ctime_nsec as i32, - })) - } -} - -impl AsInner for FileAttr { - fn as_inner(&self) -> &syscall::Stat { &self.stat } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 } - pub fn set_readonly(&mut self, readonly: bool) { - if readonly { - self.mode &= !0o222; - } else { - self.mode |= 0o222; - } - } - pub fn mode(&self) -> u32 { self.mode as u32 } -} - -impl FileType { - pub fn is_dir(&self) -> bool { self.is(syscall::MODE_DIR) } - pub fn is_file(&self) -> bool { self.is(syscall::MODE_FILE) } - pub fn is_symlink(&self) -> bool { self.is(syscall::MODE_SYMLINK) } - - pub fn is(&self, mode: u16) -> bool { - self.mode & syscall::MODE_TYPE == mode - } -} - -impl FromInner for FilePermissions { - fn from_inner(mode: u32) -> FilePermissions { - FilePermissions { mode: mode as u16 } - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. - // Thus the result will be e g 'ReadDir("/home")' - fmt::Debug::fmt(&*self.root, f) - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - loop { - let start = self.i; - let mut i = self.i; - while i < self.data.len() { - self.i += 1; - if self.data[i] == b'\n' { - break; - } - i += 1; - } - if start < self.i { - let ret = DirEntry { - name: self.data[start .. i].to_owned().into_boxed_slice(), - root: self.root.clone() - }; - if ret.name_bytes() != b"." && ret.name_bytes() != b".." { - return Some(Ok(ret)) - } - } else { - return None; - } - } - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - self.root.join(OsStr::from_bytes(self.name_bytes())) - } - - pub fn file_name(&self) -> OsString { - OsStr::from_bytes(self.name_bytes()).to_os_string() - } - - pub fn metadata(&self) -> io::Result { - lstat(&self.path()) - } - - pub fn file_type(&self) -> io::Result { - lstat(&self.path()).map(|m| m.file_type()) - } - - fn name_bytes(&self) -> &[u8] { - &*self.name - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - custom_flags: 0, - mode: 0o666, - } - } - - pub fn read(&mut self, read: bool) { self.read = read; } - pub fn write(&mut self, write: bool) { self.write = write; } - pub fn append(&mut self, append: bool) { self.append = append; } - pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; } - pub fn create(&mut self, create: bool) { self.create = create; } - pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; } - - pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; } - pub fn mode(&mut self, mode: u32) { self.mode = mode as u16; } - - fn get_access_mode(&self) -> io::Result { - match (self.read, self.write, self.append) { - (true, false, false) => Ok(syscall::O_RDONLY), - (false, true, false) => Ok(syscall::O_WRONLY), - (true, true, false) => Ok(syscall::O_RDWR), - (false, _, true) => Ok(syscall::O_WRONLY | syscall::O_APPEND), - (true, _, true) => Ok(syscall::O_RDWR | syscall::O_APPEND), - (false, false, false) => Err(Error::from_raw_os_error(syscall::EINVAL)), - } - } - - fn get_creation_mode(&self) -> io::Result { - match (self.write, self.append) { - (true, false) => {} - (false, false) => - if self.truncate || self.create || self.create_new { - return Err(Error::from_raw_os_error(syscall::EINVAL)); - }, - (_, true) => - if self.truncate && !self.create_new { - return Err(Error::from_raw_os_error(syscall::EINVAL)); - }, - } - - Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => 0, - (true, false, false) => syscall::O_CREAT, - (false, true, false) => syscall::O_TRUNC, - (true, true, false) => syscall::O_CREAT | syscall::O_TRUNC, - (_, _, true) => syscall::O_CREAT | syscall::O_EXCL, - }) - } -} - -impl File { - pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let flags = syscall::O_CLOEXEC | - opts.get_access_mode()? as usize | - opts.get_creation_mode()? as usize | - (opts.custom_flags as usize & !syscall::O_ACCMODE); - let fd = cvt(syscall::open(path.to_str().unwrap(), flags | opts.mode as usize))?; - Ok(File(FileDesc::new(fd))) - } - - pub fn file_attr(&self) -> io::Result { - let mut stat = syscall::Stat::default(); - cvt(syscall::fstat(self.0.raw(), &mut stat))?; - Ok(FileAttr { stat: stat }) - } - - pub fn fsync(&self) -> io::Result<()> { - cvt(syscall::fsync(self.0.raw()))?; - Ok(()) - } - - pub fn datasync(&self) -> io::Result<()> { - self.fsync() - } - - pub fn truncate(&self, size: u64) -> io::Result<()> { - cvt(syscall::ftruncate(self.0.raw(), size as usize))?; - Ok(()) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn flush(&self) -> io::Result<()> { Ok(()) } - - pub fn seek(&self, pos: SeekFrom) -> io::Result { - let (whence, pos) = match pos { - // Casting to `i64` is fine, too large values will end up as - // negative which will cause an error in `lseek64`. - SeekFrom::Start(off) => (syscall::SEEK_SET, off as i64), - SeekFrom::End(off) => (syscall::SEEK_END, off), - SeekFrom::Current(off) => (syscall::SEEK_CUR, off), - }; - let n = cvt(syscall::lseek(self.0.raw(), pos as isize, whence))?; - Ok(n as u64) - } - - pub fn duplicate(&self) -> io::Result { - self.0.duplicate().map(File) - } - - pub fn dup(&self, buf: &[u8]) -> io::Result { - let fd = cvt(syscall::dup(*self.fd().as_inner() as usize, buf))?; - Ok(File(FileDesc::new(fd))) - } - - pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { - set_perm(&self.path()?, perm) - } - - pub fn path(&self) -> io::Result { - let mut buf: [u8; 4096] = [0; 4096]; - let count = cvt(syscall::fpath(*self.fd().as_inner() as usize, &mut buf))?; - Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) })) - } - - pub fn fd(&self) -> &FileDesc { &self.0 } - - pub fn into_fd(self) -> FileDesc { self.0 } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder { mode: 0o777 } - } - - pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let flags = syscall::O_CREAT | syscall::O_CLOEXEC | syscall::O_DIRECTORY | syscall::O_EXCL; - let fd = cvt(syscall::open(p.to_str().unwrap(), flags | (self.mode as usize & 0o777)))?; - let _ = syscall::close(fd); - Ok(()) - } - - pub fn set_mode(&mut self, mode: u32) { - self.mode = mode as u16; - } -} - -impl FromInner for File { - fn from_inner(fd: usize) -> File { - File(FileDesc::new(fd)) - } -} - -impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut b = f.debug_struct("File"); - b.field("fd", &self.0.raw()); - if let Ok(path) = self.path() { - b.field("path", &path); - } - /* - if let Some((read, write)) = get_mode(fd) { - b.field("read", &read).field("write", &write); - } - */ - b.finish() - } -} - -pub fn readdir(p: &Path) -> io::Result { - let root = Arc::new(p.to_path_buf()); - - let flags = syscall::O_CLOEXEC | syscall::O_RDONLY | syscall::O_DIRECTORY; - let fd = cvt(syscall::open(p.to_str().unwrap(), flags))?; - let file = FileDesc::new(fd); - let mut data = Vec::new(); - file.read_to_end(&mut data)?; - - Ok(ReadDir { data: data, i: 0, root: root }) -} - -pub fn unlink(p: &Path) -> io::Result<()> { - cvt(syscall::unlink(p.to_str().unwrap()))?; - Ok(()) -} - -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let fd = cvt(syscall::open(old.to_str().unwrap(), - syscall::O_CLOEXEC | syscall::O_STAT | syscall::O_NOFOLLOW))?; - let res = cvt(syscall::frename(fd, new.to_str().unwrap())); - cvt(syscall::close(fd))?; - res?; - Ok(()) -} - -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - cvt(syscall::chmod(p.to_str().unwrap(), perm.mode as usize))?; - Ok(()) -} - -pub fn rmdir(p: &Path) -> io::Result<()> { - cvt(syscall::rmdir(p.to_str().unwrap()))?; - Ok(()) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { - unlink(path) - } else { - remove_dir_all_recursive(path) - } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - -pub fn readlink(p: &Path) -> io::Result { - let fd = cvt(syscall::open(p.to_str().unwrap(), - syscall::O_CLOEXEC | syscall::O_SYMLINK | syscall::O_RDONLY))?; - let mut buf: [u8; 4096] = [0; 4096]; - let res = cvt(syscall::read(fd, &mut buf)); - cvt(syscall::close(fd))?; - let count = res?; - Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) })) -} - -pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let fd = cvt(syscall::open(dst.to_str().unwrap(), - syscall::O_CLOEXEC | syscall::O_SYMLINK | - syscall::O_CREAT | syscall::O_WRONLY | 0o777))?; - let res = cvt(syscall::write(fd, src.to_str().unwrap().as_bytes())); - cvt(syscall::close(fd))?; - res?; - Ok(()) -} - -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - Err(Error::from_raw_os_error(syscall::ENOSYS)) -} - -pub fn stat(p: &Path) -> io::Result { - let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?; - let file = File(FileDesc::new(fd)); - file.file_attr() -} - -pub fn lstat(p: &Path) -> io::Result { - let fd = cvt(syscall::open(p.to_str().unwrap(), - syscall::O_CLOEXEC | syscall::O_STAT | syscall::O_NOFOLLOW))?; - let file = File(FileDesc::new(fd)); - file.file_attr() -} - -pub fn canonicalize(p: &Path) -> io::Result { - let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?; - let file = File(FileDesc::new(fd)); - file.path() -} - -pub fn copy(from: &Path, to: &Path) -> io::Result { - use fs::{File, set_permissions}; - if !from.is_file() { - return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing regular file")) - } - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let perm = reader.metadata()?.permissions(); - - let ret = io::copy(&mut reader, &mut writer)?; - set_permissions(to, perm)?; - Ok(ret) -} diff --git a/ctr-std/src/sys/redox/memchr.rs b/ctr-std/src/sys/redox/memchr.rs deleted file mode 100644 index 873b335..0000000 --- a/ctr-std/src/sys/redox/memchr.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// Original implementation taken from rust-memchr -// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch - -pub use core::slice::memchr::{memchr, memrchr}; diff --git a/ctr-std/src/sys/redox/mod.rs b/ctr-std/src/sys/redox/mod.rs deleted file mode 100644 index 4352b72..0000000 --- a/ctr-std/src/sys/redox/mod.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code, missing_docs, bad_style)] - -use io::{self, ErrorKind}; - -pub use libc::strlen; -pub use self::rand::hashmap_random_keys; - -pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; -pub mod cmath; -pub mod condvar; -pub mod env; -pub mod ext; -pub mod fast_thread_local; -pub mod fd; -pub mod fs; -pub mod memchr; -pub mod mutex; -pub mod net; -pub mod os; -pub mod os_str; -pub mod path; -pub mod pipe; -pub mod process; -pub mod rand; -pub mod rwlock; -pub mod stack_overflow; -pub mod stdio; -pub mod syscall; -pub mod thread; -pub mod thread_local; -pub mod time; - -#[cfg(not(test))] -pub fn init() {} - -pub fn decode_error_kind(errno: i32) -> ErrorKind { - match errno { - syscall::ECONNREFUSED => ErrorKind::ConnectionRefused, - syscall::ECONNRESET => ErrorKind::ConnectionReset, - syscall::EPERM | syscall::EACCES => ErrorKind::PermissionDenied, - syscall::EPIPE => ErrorKind::BrokenPipe, - syscall::ENOTCONN => ErrorKind::NotConnected, - syscall::ECONNABORTED => ErrorKind::ConnectionAborted, - syscall::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, - syscall::EADDRINUSE => ErrorKind::AddrInUse, - syscall::ENOENT => ErrorKind::NotFound, - syscall::EINTR => ErrorKind::Interrupted, - syscall::EINVAL => ErrorKind::InvalidInput, - syscall::ETIMEDOUT => ErrorKind::TimedOut, - syscall::EEXIST => ErrorKind::AlreadyExists, - - // These two constants can have the same value on some systems, - // but different values on others, so we can't use a match - // clause - x if x == syscall::EAGAIN || x == syscall::EWOULDBLOCK => - ErrorKind::WouldBlock, - - _ => ErrorKind::Other, - } -} - -pub fn cvt(result: Result) -> io::Result { - result.map_err(|err| io::Error::from_raw_os_error(err.errno)) -} - -/// On Redox, use an illegal instruction to abort -pub unsafe fn abort_internal() -> ! { - ::core::intrinsics::abort(); -} diff --git a/ctr-std/src/sys/redox/mutex.rs b/ctr-std/src/sys/redox/mutex.rs deleted file mode 100644 index a995f59..0000000 --- a/ctr-std/src/sys/redox/mutex.rs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use intrinsics::{atomic_cxchg, atomic_xchg}; -use ptr; - -use sys::syscall::{futex, getpid, FUTEX_WAIT, FUTEX_WAKE}; - -pub unsafe fn mutex_try_lock(m: *mut i32) -> bool { - atomic_cxchg(m, 0, 1).0 == 0 -} - -pub unsafe fn mutex_lock(m: *mut i32) { - let mut c = 0; - //Set to larger value for longer spin test - for _i in 0..100 { - c = atomic_cxchg(m, 0, 1).0; - if c == 0 { - break; - } - //cpu_relax() - } - if c == 1 { - c = atomic_xchg(m, 2); - } - while c != 0 { - let _ = futex(m, FUTEX_WAIT, 2, 0, ptr::null_mut()); - c = atomic_xchg(m, 2); - } -} - -pub unsafe fn mutex_unlock(m: *mut i32) { - if *m == 2 { - *m = 0; - } else if atomic_xchg(m, 0) == 1 { - return; - } - //Set to larger value for longer spin test - for _i in 0..100 { - if *m != 0 { - if atomic_cxchg(m, 1, 2).0 != 0 { - return; - } - } - //cpu_relax() - } - let _ = futex(m, FUTEX_WAKE, 1, 0, ptr::null_mut()); -} - -pub struct Mutex { - pub lock: UnsafeCell, -} - -impl Mutex { - /// Create a new mutex. - pub const fn new() -> Self { - Mutex { - lock: UnsafeCell::new(0), - } - } - - #[inline] - pub unsafe fn init(&self) { - *self.lock.get() = 0; - } - - /// Try to lock the mutex - #[inline] - pub unsafe fn try_lock(&self) -> bool { - mutex_try_lock(self.lock.get()) - } - - /// Lock the mutex - #[inline] - pub unsafe fn lock(&self) { - mutex_lock(self.lock.get()); - } - - /// Unlock the mutex - #[inline] - pub unsafe fn unlock(&self) { - mutex_unlock(self.lock.get()); - } - - #[inline] - pub unsafe fn destroy(&self) { - *self.lock.get() = 0; - } -} - -unsafe impl Send for Mutex {} - -unsafe impl Sync for Mutex {} - -pub struct ReentrantMutex { - pub lock: UnsafeCell, - pub owner: UnsafeCell, - pub own_count: UnsafeCell, -} - -impl ReentrantMutex { - pub const fn uninitialized() -> Self { - ReentrantMutex { - lock: UnsafeCell::new(0), - owner: UnsafeCell::new(0), - own_count: UnsafeCell::new(0), - } - } - - #[inline] - pub unsafe fn init(&mut self) { - *self.lock.get() = 0; - *self.owner.get() = 0; - *self.own_count.get() = 0; - } - - /// Try to lock the mutex - #[inline] - pub unsafe fn try_lock(&self) -> bool { - let pid = getpid().unwrap(); - if *self.own_count.get() > 0 && *self.owner.get() == pid { - *self.own_count.get() += 1; - true - } else { - if mutex_try_lock(self.lock.get()) { - *self.owner.get() = pid; - *self.own_count.get() = 1; - true - } else { - false - } - } - } - - /// Lock the mutex - #[inline] - pub unsafe fn lock(&self) { - let pid = getpid().unwrap(); - if *self.own_count.get() > 0 && *self.owner.get() == pid { - *self.own_count.get() += 1; - } else { - mutex_lock(self.lock.get()); - *self.owner.get() = pid; - *self.own_count.get() = 1; - } - } - - /// Unlock the mutex - #[inline] - pub unsafe fn unlock(&self) { - let pid = getpid().unwrap(); - if *self.own_count.get() > 0 && *self.owner.get() == pid { - *self.own_count.get() -= 1; - if *self.own_count.get() == 0 { - *self.owner.get() = 0; - mutex_unlock(self.lock.get()); - } - } - } - - #[inline] - pub unsafe fn destroy(&self) { - *self.lock.get() = 0; - *self.owner.get() = 0; - *self.own_count.get() = 0; - } -} - -unsafe impl Send for ReentrantMutex {} - -unsafe impl Sync for ReentrantMutex {} diff --git a/ctr-std/src/sys/redox/net/dns/answer.rs b/ctr-std/src/sys/redox/net/dns/answer.rs deleted file mode 100644 index 8e6aaeb..0000000 --- a/ctr-std/src/sys/redox/net/dns/answer.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use string::String; -use vec::Vec; - -#[derive(Clone, Debug)] -pub struct DnsAnswer { - pub name: String, - pub a_type: u16, - pub a_class: u16, - pub ttl_a: u16, - pub ttl_b: u16, - pub data: Vec -} diff --git a/ctr-std/src/sys/redox/net/dns/mod.rs b/ctr-std/src/sys/redox/net/dns/mod.rs deleted file mode 100644 index 1a26257..0000000 --- a/ctr-std/src/sys/redox/net/dns/mod.rs +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::answer::DnsAnswer; -pub use self::query::DnsQuery; - -use slice; -use u16; -use string::String; -use vec::Vec; - -mod answer; -mod query; - -#[unstable(feature = "n16", issue="0")] -#[allow(non_camel_case_types)] -#[derive(Copy, Clone, Debug, Default)] -#[repr(packed)] -pub struct n16 { - inner: u16 -} - -impl n16 { - #[unstable(feature = "n16", issue="0")] - pub fn as_bytes(&self) -> &[u8] { - unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) } - } - - #[unstable(feature = "n16", issue="0")] - pub fn from_bytes(bytes: &[u8]) -> Self { - n16 { - inner: unsafe { slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len()/2)[0] } - } - } -} - -#[unstable(feature = "n16", issue="0")] -impl From for n16 { - fn from(value: u16) -> Self { - n16 { - inner: value.to_be() - } - } -} - -#[unstable(feature = "n16", issue="0")] -impl From for u16 { - fn from(value: n16) -> Self { - u16::from_be(value.inner) - } -} - -#[derive(Clone, Debug)] -pub struct Dns { - pub transaction_id: u16, - pub flags: u16, - pub queries: Vec, - pub answers: Vec -} - -impl Dns { - pub fn compile(&self) -> Vec { - let mut data = Vec::new(); - - macro_rules! push_u8 { - ($value:expr) => { - data.push($value); - }; - }; - - macro_rules! push_n16 { - ($value:expr) => { - data.extend_from_slice(n16::from($value).as_bytes()); - }; - }; - - push_n16!(self.transaction_id); - push_n16!(self.flags); - push_n16!(self.queries.len() as u16); - push_n16!(self.answers.len() as u16); - push_n16!(0); - push_n16!(0); - - for query in self.queries.iter() { - for part in query.name.split('.') { - push_u8!(part.len() as u8); - data.extend_from_slice(part.as_bytes()); - } - push_u8!(0); - push_n16!(query.q_type); - push_n16!(query.q_class); - } - - data - } - - pub fn parse(data: &[u8]) -> Result { - let name_ind = 0b11000000; - let mut i = 0; - - macro_rules! pop_u8 { - () => { - { - i += 1; - if i > data.len() { - return Err(format!("{}: {}: pop_u8", file!(), line!())); - } - data[i - 1] - } - }; - }; - - macro_rules! pop_n16 { - () => { - { - i += 2; - if i > data.len() { - return Err(format!("{}: {}: pop_n16", file!(), line!())); - } - u16::from(n16::from_bytes(&data[i - 2 .. i])) - } - }; - }; - - macro_rules! pop_data { - () => { - { - let mut data = Vec::new(); - - let data_len = pop_n16!(); - for _data_i in 0..data_len { - data.push(pop_u8!()); - } - - data - } - }; - }; - - macro_rules! pop_name { - () => { - { - let mut name = String::new(); - let old_i = i; - - loop { - let name_len = pop_u8!(); - if name_len & name_ind == name_ind { - i -= 1; - i = (pop_n16!() - ((name_ind as u16) << 8)) as usize; - continue; - } - if name_len == 0 { - break; - } - if ! name.is_empty() { - name.push('.'); - } - for _name_i in 0..name_len { - name.push(pop_u8!() as char); - } - } - - if i <= old_i { - i = old_i + 2; - } - - name - } - }; - }; - - let transaction_id = pop_n16!(); - let flags = pop_n16!(); - let queries_len = pop_n16!(); - let answers_len = pop_n16!(); - pop_n16!(); - pop_n16!(); - - let mut queries = Vec::new(); - for _query_i in 0..queries_len { - queries.push(DnsQuery { - name: pop_name!(), - q_type: pop_n16!(), - q_class: pop_n16!() - }); - } - - let mut answers = Vec::new(); - for _answer_i in 0..answers_len { - answers.push(DnsAnswer { - name: pop_name!(), - a_type: pop_n16!(), - a_class: pop_n16!(), - ttl_a: pop_n16!(), - ttl_b: pop_n16!(), - data: pop_data!() - }); - } - - Ok(Dns { - transaction_id, - flags, - queries, - answers, - }) - } -} diff --git a/ctr-std/src/sys/redox/net/dns/query.rs b/ctr-std/src/sys/redox/net/dns/query.rs deleted file mode 100644 index b0dcdcb..0000000 --- a/ctr-std/src/sys/redox/net/dns/query.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use string::String; - -#[derive(Clone, Debug)] -pub struct DnsQuery { - pub name: String, - pub q_type: u16, - pub q_class: u16 -} diff --git a/ctr-std/src/sys/redox/net/mod.rs b/ctr-std/src/sys/redox/net/mod.rs deleted file mode 100644 index 67f2223..0000000 --- a/ctr-std/src/sys/redox/net/mod.rs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use fs::File; -use io::{Error, Result, Read}; -use iter::Iterator; -use net::{Ipv4Addr, SocketAddr, SocketAddrV4}; -use str::FromStr; -use string::{String, ToString}; -use sys::syscall::EINVAL; -use time::{self, Duration}; -use vec::{IntoIter, Vec}; - -use self::dns::{Dns, DnsQuery}; - -pub use self::tcp::{TcpStream, TcpListener}; -pub use self::udp::UdpSocket; - -pub mod netc; - -mod dns; -mod tcp; -mod udp; - -pub struct LookupHost(IntoIter); - -impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option { - self.0.next() - } -} - -pub fn lookup_host(host: &str) -> Result { - let mut ip_string = String::new(); - File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?; - let ip: Vec = ip_string.trim().split('.').map(|part| part.parse::() - .unwrap_or(0)).collect(); - - let mut dns_string = String::new(); - File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?; - let dns: Vec = dns_string.trim().split('.').map(|part| part.parse::() - .unwrap_or(0)).collect(); - - if ip.len() == 4 && dns.len() == 4 { - let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap(); - let tid = (time.subsec_nanos() >> 16) as u16; - - let packet = Dns { - transaction_id: tid, - flags: 0x0100, - queries: vec![DnsQuery { - name: host.to_string(), - q_type: 0x0001, - q_class: 0x0001, - }], - answers: vec![] - }; - - let packet_data = packet.compile(); - - let my_ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]); - let dns_ip = Ipv4Addr::new(dns[0], dns[1], dns[2], dns[3]); - let socket = UdpSocket::bind(&SocketAddr::V4(SocketAddrV4::new(my_ip, 0)))?; - socket.set_read_timeout(Some(Duration::new(5, 0)))?; - socket.set_write_timeout(Some(Duration::new(5, 0)))?; - socket.connect(&SocketAddr::V4(SocketAddrV4::new(dns_ip, 53)))?; - socket.send(&packet_data)?; - - let mut buf = [0; 65536]; - let count = socket.recv(&mut buf)?; - - match Dns::parse(&buf[.. count]) { - Ok(response) => { - let mut addrs = vec![]; - for answer in response.answers.iter() { - if answer.a_type == 0x0001 && answer.a_class == 0x0001 - && answer.data.len() == 4 - { - let answer_ip = Ipv4Addr::new(answer.data[0], - answer.data[1], - answer.data[2], - answer.data[3]); - addrs.push(SocketAddr::V4(SocketAddrV4::new(answer_ip, 0))); - } - } - Ok(LookupHost(addrs.into_iter())) - }, - Err(_err) => Err(Error::from_raw_os_error(EINVAL)) - } - } else { - Err(Error::from_raw_os_error(EINVAL)) - } -} - -fn path_to_peer_addr(path_str: &str) -> SocketAddr { - let mut parts = path_str.split('/').next().unwrap_or("").split(':').skip(1); - let host = Ipv4Addr::from_str(parts.next().unwrap_or("")).unwrap_or(Ipv4Addr::new(0, 0, 0, 0)); - let port = parts.next().unwrap_or("").parse::().unwrap_or(0); - SocketAddr::V4(SocketAddrV4::new(host, port)) -} - -fn path_to_local_addr(path_str: &str) -> SocketAddr { - let mut parts = path_str.split('/').nth(1).unwrap_or("").split(':'); - let host = Ipv4Addr::from_str(parts.next().unwrap_or("")).unwrap_or(Ipv4Addr::new(0, 0, 0, 0)); - let port = parts.next().unwrap_or("").parse::().unwrap_or(0); - SocketAddr::V4(SocketAddrV4::new(host, port)) -} diff --git a/ctr-std/src/sys/redox/net/netc.rs b/ctr-std/src/sys/redox/net/netc.rs deleted file mode 100644 index b6d9f45..0000000 --- a/ctr-std/src/sys/redox/net/netc.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub type in_addr_t = u32; -pub type in_port_t = u16; - -pub type socklen_t = u32; -pub type sa_family_t = u16; - -pub const AF_INET: sa_family_t = 2; -pub const AF_INET6: sa_family_t = 23; - -#[derive(Copy, Clone)] -#[repr(C)] -pub struct in_addr { - pub s_addr: in_addr_t, -} - -#[derive(Copy, Clone)] -#[repr(align(4))] -#[repr(C)] -pub struct in6_addr { - pub s6_addr: [u8; 16], -} - -#[derive(Copy, Clone)] -#[repr(C)] -pub struct sockaddr { - pub sa_family: sa_family_t, - pub sa_data: [u8; 14], -} - -#[derive(Copy, Clone)] -#[repr(C)] -pub struct sockaddr_in { - pub sin_family: sa_family_t, - pub sin_port: in_port_t, - pub sin_addr: in_addr, - pub sin_zero: [u8; 8], -} - -#[derive(Copy, Clone)] -#[repr(C)] -pub struct sockaddr_in6 { - pub sin6_family: sa_family_t, - pub sin6_port: in_port_t, - pub sin6_flowinfo: u32, - pub sin6_addr: in6_addr, - pub sin6_scope_id: u32, -} diff --git a/ctr-std/src/sys/redox/net/tcp.rs b/ctr-std/src/sys/redox/net/tcp.rs deleted file mode 100644 index b566490..0000000 --- a/ctr-std/src/sys/redox/net/tcp.rs +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cmp; -use io::{self, Error, ErrorKind, Result}; -use mem; -use net::{SocketAddr, Shutdown}; -use path::Path; -use sys::fs::{File, OpenOptions}; -use sys::syscall::TimeSpec; -use sys_common::{AsInner, FromInner, IntoInner}; -use time::Duration; - -use super::{path_to_peer_addr, path_to_local_addr}; - -#[derive(Debug)] -pub struct TcpStream(File); - -impl TcpStream { - pub fn connect(addr: &SocketAddr) -> Result { - let path = format!("tcp:{}", addr); - let mut options = OpenOptions::new(); - options.read(true); - options.write(true); - Ok(TcpStream(File::open(Path::new(path.as_str()), &options)?)) - } - - pub fn connect_timeout(_addr: &SocketAddr, _timeout: Duration) -> Result { - Err(Error::new(ErrorKind::Other, "TcpStream::connect_timeout not implemented")) - } - - pub fn duplicate(&self) -> Result { - Ok(TcpStream(self.0.dup(&[])?)) - } - - pub fn read(&self, buf: &mut [u8]) -> Result { - self.0.read(buf) - } - - pub fn write(&self, buf: &[u8]) -> Result { - self.0.write(buf) - } - - pub fn take_error(&self) -> Result> { - Ok(None) - } - - pub fn peer_addr(&self) -> Result { - let path = self.0.path()?; - Ok(path_to_peer_addr(path.to_str().unwrap_or(""))) - } - - pub fn socket_addr(&self) -> Result { - let path = self.0.path()?; - Ok(path_to_local_addr(path.to_str().unwrap_or(""))) - } - - pub fn peek(&self, _buf: &mut [u8]) -> Result { - Err(Error::new(ErrorKind::Other, "TcpStream::peek not implemented")) - } - - pub fn shutdown(&self, _how: Shutdown) -> Result<()> { - Err(Error::new(ErrorKind::Other, "TcpStream::shutdown not implemented")) - } - - pub fn nodelay(&self) -> Result { - Err(Error::new(ErrorKind::Other, "TcpStream::nodelay not implemented")) - } - - pub fn nonblocking(&self) -> Result { - self.0.fd().nonblocking() - } - - pub fn only_v6(&self) -> Result { - Err(Error::new(ErrorKind::Other, "TcpStream::only_v6 not implemented")) - } - - pub fn ttl(&self) -> Result { - let mut ttl = [0]; - let file = self.0.dup(b"ttl")?; - file.read(&mut ttl)?; - Ok(ttl[0] as u32) - } - - pub fn read_timeout(&self) -> Result> { - let mut time = TimeSpec::default(); - let file = self.0.dup(b"read_timeout")?; - if file.read(&mut time)? >= mem::size_of::() { - Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32))) - } else { - Ok(None) - } - } - - pub fn write_timeout(&self) -> Result> { - let mut time = TimeSpec::default(); - let file = self.0.dup(b"write_timeout")?; - if file.read(&mut time)? >= mem::size_of::() { - Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32))) - } else { - Ok(None) - } - } - - pub fn set_nodelay(&self, _nodelay: bool) -> Result<()> { - Err(Error::new(ErrorKind::Other, "TcpStream::set_nodelay not implemented")) - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> { - self.0.fd().set_nonblocking(nonblocking) - } - - pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> { - Err(Error::new(ErrorKind::Other, "TcpStream::set_only_v6 not implemented")) - } - - pub fn set_ttl(&self, ttl: u32) -> Result<()> { - let file = self.0.dup(b"ttl")?; - file.write(&[cmp::min(ttl, 255) as u8])?; - Ok(()) - } - - pub fn set_read_timeout(&self, duration_option: Option) -> Result<()> { - let file = self.0.dup(b"read_timeout")?; - if let Some(duration) = duration_option { - if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout")); - } - file.write(&TimeSpec { - tv_sec: duration.as_secs() as i64, - tv_nsec: duration.subsec_nanos() as i32 - })?; - } else { - file.write(&[])?; - } - Ok(()) - } - - pub fn set_write_timeout(&self, duration_option: Option) -> Result<()> { - let file = self.0.dup(b"write_timeout")?; - if let Some(duration) = duration_option { - if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout")); - } - file.write(&TimeSpec { - tv_sec: duration.as_secs() as i64, - tv_nsec: duration.subsec_nanos() as i32 - })?; - } else { - file.write(&[])?; - } - Ok(()) - } -} - -impl AsInner for TcpStream { - fn as_inner(&self) -> &File { &self.0 } -} - -impl FromInner for TcpStream { - fn from_inner(file: File) -> TcpStream { - TcpStream(file) - } -} - -impl IntoInner for TcpStream { - fn into_inner(self) -> File { self.0 } -} - -#[derive(Debug)] -pub struct TcpListener(File); - -impl TcpListener { - pub fn bind(addr: &SocketAddr) -> Result { - let path = format!("tcp:/{}", addr); - let mut options = OpenOptions::new(); - options.read(true); - options.write(true); - Ok(TcpListener(File::open(Path::new(path.as_str()), &options)?)) - } - - pub fn accept(&self) -> Result<(TcpStream, SocketAddr)> { - let file = self.0.dup(b"listen")?; - let path = file.path()?; - let peer_addr = path_to_peer_addr(path.to_str().unwrap_or("")); - Ok((TcpStream(file), peer_addr)) - } - - pub fn duplicate(&self) -> Result { - Ok(TcpListener(self.0.dup(&[])?)) - } - - pub fn take_error(&self) -> Result> { - Ok(None) - } - - pub fn socket_addr(&self) -> Result { - let path = self.0.path()?; - Ok(path_to_local_addr(path.to_str().unwrap_or(""))) - } - - pub fn nonblocking(&self) -> Result { - Err(Error::new(ErrorKind::Other, "TcpListener::nonblocking not implemented")) - } - - pub fn only_v6(&self) -> Result { - Err(Error::new(ErrorKind::Other, "TcpListener::only_v6 not implemented")) - } - - pub fn ttl(&self) -> Result { - let mut ttl = [0]; - let file = self.0.dup(b"ttl")?; - file.read(&mut ttl)?; - Ok(ttl[0] as u32) - } - - pub fn set_nonblocking(&self, _nonblocking: bool) -> Result<()> { - Err(Error::new(ErrorKind::Other, "TcpListener::set_nonblocking not implemented")) - } - - pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> { - Err(Error::new(ErrorKind::Other, "TcpListener::set_only_v6 not implemented")) - } - - pub fn set_ttl(&self, ttl: u32) -> Result<()> { - let file = self.0.dup(b"ttl")?; - file.write(&[cmp::min(ttl, 255) as u8])?; - Ok(()) - } -} - -impl AsInner for TcpListener { - fn as_inner(&self) -> &File { &self.0 } -} - -impl FromInner for TcpListener { - fn from_inner(file: File) -> TcpListener { - TcpListener(file) - } -} - -impl IntoInner for TcpListener { - fn into_inner(self) -> File { self.0 } -} diff --git a/ctr-std/src/sys/redox/net/udp.rs b/ctr-std/src/sys/redox/net/udp.rs deleted file mode 100644 index 22af020..0000000 --- a/ctr-std/src/sys/redox/net/udp.rs +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use cmp; -use io::{self, Error, ErrorKind, Result}; -use mem; -use net::{SocketAddr, Ipv4Addr, Ipv6Addr}; -use path::Path; -use sys::fs::{File, OpenOptions}; -use sys::syscall::TimeSpec; -use sys_common::{AsInner, FromInner, IntoInner}; -use time::Duration; - -use super::{path_to_peer_addr, path_to_local_addr}; - -#[derive(Debug)] -pub struct UdpSocket(File, UnsafeCell>); - -impl UdpSocket { - pub fn bind(addr: &SocketAddr) -> Result { - let path = format!("udp:/{}", addr); - let mut options = OpenOptions::new(); - options.read(true); - options.write(true); - Ok(UdpSocket(File::open(Path::new(path.as_str()), &options)?, UnsafeCell::new(None))) - } - - fn get_conn(&self) -> &mut Option { - unsafe { &mut *(self.1.get()) } - } - - pub fn connect(&self, addr: &SocketAddr) -> Result<()> { - unsafe { *self.1.get() = Some(*addr) }; - Ok(()) - } - - pub fn duplicate(&self) -> Result { - let new_bind = self.0.dup(&[])?; - let new_conn = *self.get_conn(); - Ok(UdpSocket(new_bind, UnsafeCell::new(new_conn))) - } - - pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> { - let from = self.0.dup(b"listen")?; - let path = from.path()?; - let peer_addr = path_to_peer_addr(path.to_str().unwrap_or("")); - let count = from.read(buf)?; - Ok((count, peer_addr)) - } - - pub fn recv(&self, buf: &mut [u8]) -> Result { - if let Some(addr) = *self.get_conn() { - let from = self.0.dup(addr.to_string().as_bytes())?; - from.read(buf) - } else { - Err(Error::new(ErrorKind::Other, "UdpSocket::recv not connected")) - } - } - - pub fn send_to(&self, buf: &[u8], addr: &SocketAddr) -> Result { - let to = self.0.dup(format!("{}", addr).as_bytes())?; - to.write(buf) - } - - pub fn send(&self, buf: &[u8]) -> Result { - if let Some(addr) = *self.get_conn() { - self.send_to(buf, &addr) - } else { - Err(Error::new(ErrorKind::Other, "UdpSocket::send not connected")) - } - } - - pub fn take_error(&self) -> Result> { - Ok(None) - } - - pub fn socket_addr(&self) -> Result { - let path = self.0.path()?; - Ok(path_to_local_addr(path.to_str().unwrap_or(""))) - } - - pub fn peek(&self, _buf: &mut [u8]) -> Result { - Err(Error::new(ErrorKind::Other, "UdpSocket::peek not implemented")) - } - - pub fn peek_from(&self, _buf: &mut [u8]) -> Result<(usize, SocketAddr)> { - Err(Error::new(ErrorKind::Other, "UdpSocket::peek_from not implemented")) - } - - pub fn broadcast(&self) -> Result { - Err(Error::new(ErrorKind::Other, "UdpSocket::broadcast not implemented")) - } - - pub fn multicast_loop_v4(&self) -> Result { - Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v4 not implemented")) - } - - pub fn multicast_loop_v6(&self) -> Result { - Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v6 not implemented")) - } - - pub fn multicast_ttl_v4(&self) -> Result { - Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_ttl_v4 not implemented")) - } - - pub fn nonblocking(&self) -> Result { - self.0.fd().nonblocking() - } - - pub fn only_v6(&self) -> Result { - Err(Error::new(ErrorKind::Other, "UdpSocket::only_v6 not implemented")) - } - - pub fn ttl(&self) -> Result { - let mut ttl = [0]; - let file = self.0.dup(b"ttl")?; - file.read(&mut ttl)?; - Ok(ttl[0] as u32) - } - - pub fn read_timeout(&self) -> Result> { - let mut time = TimeSpec::default(); - let file = self.0.dup(b"read_timeout")?; - if file.read(&mut time)? >= mem::size_of::() { - Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32))) - } else { - Ok(None) - } - } - - pub fn write_timeout(&self) -> Result> { - let mut time = TimeSpec::default(); - let file = self.0.dup(b"write_timeout")?; - if file.read(&mut time)? >= mem::size_of::() { - Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32))) - } else { - Ok(None) - } - } - - pub fn set_broadcast(&self, _broadcast: bool) -> Result<()> { - Err(Error::new(ErrorKind::Other, "UdpSocket::set_broadcast not implemented")) - } - - pub fn set_multicast_loop_v4(&self, _multicast_loop_v4: bool) -> Result<()> { - Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_loop_v4 not implemented")) - } - - pub fn set_multicast_loop_v6(&self, _multicast_loop_v6: bool) -> Result<()> { - Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_loop_v6 not implemented")) - } - - pub fn set_multicast_ttl_v4(&self, _multicast_ttl_v4: u32) -> Result<()> { - Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_ttl_v4 not implemented")) - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> { - self.0.fd().set_nonblocking(nonblocking) - } - - pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> { - Err(Error::new(ErrorKind::Other, "UdpSocket::set_only_v6 not implemented")) - } - - pub fn set_ttl(&self, ttl: u32) -> Result<()> { - let file = self.0.dup(b"ttl")?; - file.write(&[cmp::min(ttl, 255) as u8])?; - Ok(()) - } - - pub fn set_read_timeout(&self, duration_option: Option) -> Result<()> { - let file = self.0.dup(b"read_timeout")?; - if let Some(duration) = duration_option { - if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout")); - } - file.write(&TimeSpec { - tv_sec: duration.as_secs() as i64, - tv_nsec: duration.subsec_nanos() as i32 - })?; - } else { - file.write(&[])?; - } - Ok(()) - } - - pub fn set_write_timeout(&self, duration_option: Option) -> Result<()> { - let file = self.0.dup(b"write_timeout")?; - if let Some(duration) = duration_option { - if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout")); - } - file.write(&TimeSpec { - tv_sec: duration.as_secs() as i64, - tv_nsec: duration.subsec_nanos() as i32 - })?; - } else { - file.write(&[])?; - } - Ok(()) - } - - pub fn join_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> { - Err(Error::new(ErrorKind::Other, "UdpSocket::join_multicast_v4 not implemented")) - } - - pub fn join_multicast_v6(&self, _multiaddr: &Ipv6Addr, _interface: u32) -> Result<()> { - Err(Error::new(ErrorKind::Other, "UdpSocket::join_multicast_v6 not implemented")) - } - - pub fn leave_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> { - Err(Error::new(ErrorKind::Other, "UdpSocket::leave_multicast_v4 not implemented")) - } - - pub fn leave_multicast_v6(&self, _multiaddr: &Ipv6Addr, _interface: u32) -> Result<()> { - Err(Error::new(ErrorKind::Other, "UdpSocket::leave_multicast_v6 not implemented")) - } -} - -impl AsInner for UdpSocket { - fn as_inner(&self) -> &File { &self.0 } -} - -impl FromInner for UdpSocket { - fn from_inner(file: File) -> UdpSocket { - UdpSocket(file, UnsafeCell::new(None)) - } -} - -impl IntoInner for UdpSocket { - fn into_inner(self) -> File { self.0 } -} diff --git a/ctr-std/src/sys/redox/os.rs b/ctr-std/src/sys/redox/os.rs deleted file mode 100644 index 5822216..0000000 --- a/ctr-std/src/sys/redox/os.rs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation of `std::os` functionality for unix systems - -#![allow(unused_imports)] // lots of cfg code here - -use os::unix::prelude::*; - -use error::Error as StdError; -use ffi::{OsString, OsStr}; -use fmt; -use io::{self, Read, Write}; -use iter; -use marker::PhantomData; -use mem; -use memchr; -use path::{self, PathBuf}; -use ptr; -use slice; -use str; -use sys_common::mutex::Mutex; -use sys::{cvt, fd, syscall}; -use vec; - -extern { - #[link_name = "__errno_location"] - fn errno_location() -> *mut i32; -} - -/// Returns the platform-specific value of errno -pub fn errno() -> i32 { - unsafe { - (*errno_location()) - } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(errno: i32) -> String { - if let Some(string) = syscall::STR_ERROR.get(errno as usize) { - string.to_string() - } else { - "unknown error".to_string() - } -} - -pub fn getcwd() -> io::Result { - let mut buf = [0; 4096]; - let count = cvt(syscall::getcwd(&mut buf))?; - Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec()))) -} - -pub fn chdir(p: &path::Path) -> io::Result<()> { - cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(())) -} - -pub struct SplitPaths<'a> { - iter: iter::Map bool>, - fn(&'a [u8]) -> PathBuf>, -} - -pub fn split_paths(unparsed: &OsStr) -> SplitPaths { - fn bytes_to_path(b: &[u8]) -> PathBuf { - PathBuf::from(::from_bytes(b)) - } - fn is_semicolon(b: &u8) -> bool { *b == b';' } - let unparsed = unparsed.as_bytes(); - SplitPaths { - iter: unparsed.split(is_semicolon as fn(&u8) -> bool) - .map(bytes_to_path as fn(&[u8]) -> PathBuf) - } -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { self.iter.next() } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(paths: I) -> Result - where I: Iterator, T: AsRef -{ - let mut joined = Vec::new(); - let sep = b';'; - - for (i, path) in paths.enumerate() { - let path = path.as_ref().as_bytes(); - if i > 0 { joined.push(sep) } - if path.contains(&sep) { - return Err(JoinPathsError) - } - joined.extend_from_slice(path); - } - Ok(OsStringExt::from_vec(joined)) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "path segment contains separator `:`".fmt(f) - } -} - -impl StdError for JoinPathsError { - fn description(&self) -> &str { "failed to join paths" } -} - -pub fn current_exe() -> io::Result { - use fs::File; - - let mut file = File::open("sys:exe")?; - - let mut path = String::new(); - file.read_to_string(&mut path)?; - - if path.ends_with('\n') { - path.pop(); - } - - Ok(PathBuf::from(path)) -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env() -> Env { - let mut variables: Vec<(OsString, OsString)> = Vec::new(); - if let Ok(mut file) = ::fs::File::open("env:") { - let mut string = String::new(); - if file.read_to_string(&mut string).is_ok() { - for line in string.lines() { - let mut parts = line.splitn(2, '='); - if let Some(name) = parts.next() { - let value = parts.next().unwrap_or(""); - variables.push((OsString::from(name.to_string()), - OsString::from(value.to_string()))); - } - } - } - } - Env { iter: variables.into_iter(), _dont_send_or_sync_me: PhantomData } -} - -pub fn getenv(key: &OsStr) -> io::Result> { - if ! key.is_empty() { - if let Ok(mut file) = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap())) { - let mut string = String::new(); - file.read_to_string(&mut string)?; - Ok(Some(OsString::from(string))) - } else { - Ok(None) - } - } else { - Ok(None) - } -} - -pub fn setenv(key: &OsStr, value: &OsStr) -> io::Result<()> { - if ! key.is_empty() { - let mut file = ::fs::File::create(&("env:".to_owned() + key.to_str().unwrap()))?; - file.write_all(value.as_bytes())?; - file.set_len(value.len() as u64)?; - } - Ok(()) -} - -pub fn unsetenv(key: &OsStr) -> io::Result<()> { - ::fs::remove_file(&("env:".to_owned() + key.to_str().unwrap()))?; - Ok(()) -} - -pub fn page_size() -> usize { - 4096 -} - -pub fn temp_dir() -> PathBuf { - ::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| { - PathBuf::from("/tmp") - }) -} - -pub fn home_dir() -> Option { - return ::env::var_os("HOME").map(PathBuf::from); -} - -pub fn exit(code: i32) -> ! { - let _ = syscall::exit(code as usize); - unreachable!(); -} - -pub fn getpid() -> u32 { - syscall::getpid().unwrap() as u32 -} - -pub fn getppid() -> u32 { - syscall::getppid().unwrap() as u32 -} diff --git a/ctr-std/src/sys/redox/os_str.rs b/ctr-std/src/sys/redox/os_str.rs deleted file mode 100644 index eb3a1ea..0000000 --- a/ctr-std/src/sys/redox/os_str.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// The underlying OsString/OsStr implementation on Unix systems: just -/// a `Vec`/`[u8]`. - -use borrow::Cow; -use fmt; -use str; -use mem; -use rc::Rc; -use sync::Arc; -use sys_common::{AsInner, IntoInner}; -use sys_common::bytestring::debug_fmt_bytestring; -use core::str::lossy::Utf8Lossy; - -#[derive(Clone, Hash)] -pub struct Buf { - pub inner: Vec -} - -pub struct Slice { - pub inner: [u8] -} - -impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - debug_fmt_bytestring(&self.inner, formatter) - } -} - -impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) - } -} - -impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) - } -} - -impl IntoInner> for Buf { - fn into_inner(self) -> Vec { - self.inner - } -} - -impl AsInner<[u8]> for Buf { - fn as_inner(&self) -> &[u8] { - &self.inner - } -} - - -impl Buf { - pub fn from_string(s: String) -> Buf { - Buf { inner: s.into_bytes() } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Buf { - Buf { - inner: Vec::with_capacity(capacity) - } - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear() - } - - #[inline] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - pub fn as_slice(&self) -> &Slice { - unsafe { mem::transmute(&*self.inner) } - } - - pub fn into_string(self) -> Result { - String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) - } - - pub fn push_slice(&mut self, s: &Slice) { - self.inner.extend_from_slice(&s.inner) - } - - #[inline] - pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.inner.into_boxed_slice()) } - } - - #[inline] - pub fn from_box(boxed: Box) -> Buf { - let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Buf { inner: inner.into_vec() } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - self.as_slice().into_arc() - } - - #[inline] - pub fn into_rc(&self) -> Rc { - self.as_slice().into_rc() - } -} - -impl Slice { - fn from_u8_slice(s: &[u8]) -> &Slice { - unsafe { mem::transmute(s) } - } - - pub fn from_str(s: &str) -> &Slice { - Slice::from_u8_slice(s.as_bytes()) - } - - pub fn to_str(&self) -> Option<&str> { - str::from_utf8(&self.inner).ok() - } - - pub fn to_string_lossy(&self) -> Cow { - String::from_utf8_lossy(&self.inner) - } - - pub fn to_owned(&self) -> Buf { - Buf { inner: self.inner.to_vec() } - } - - #[inline] - pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.inner.into(); - unsafe { mem::transmute(boxed) } - } - - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.inner); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.inner); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } - } -} diff --git a/ctr-std/src/sys/redox/path.rs b/ctr-std/src/sys/redox/path.rs deleted file mode 100644 index e6a267d..0000000 --- a/ctr-std/src/sys/redox/path.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::OsStr; -use path::Prefix; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(path: &OsStr) -> Option { - if let Some(path_str) = path.to_str() { - if let Some(_i) = path_str.find(':') { - // FIXME: Redox specific prefix - // Some(Prefix::Verbatim(OsStr::new(&path_str[..i]))) - None - } else { - None - } - } else { - None - } -} - -pub const MAIN_SEP_STR: &'static str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/ctr-std/src/sys/redox/pipe.rs b/ctr-std/src/sys/redox/pipe.rs deleted file mode 100644 index 28645fa..0000000 --- a/ctr-std/src/sys/redox/pipe.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use sys::{cvt, syscall}; -use sys::fd::FileDesc; - -//////////////////////////////////////////////////////////////////////////////// -// Anonymous pipes -//////////////////////////////////////////////////////////////////////////////// - -pub struct AnonPipe(FileDesc); - -pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - let mut fds = [0; 2]; - cvt(syscall::pipe2(&mut fds, syscall::O_CLOEXEC))?; - Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1])))) -} - -impl AnonPipe { - pub fn from_fd(fd: FileDesc) -> io::Result { - fd.set_cloexec()?; - Ok(AnonPipe(fd)) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn fd(&self) -> &FileDesc { &self.0 } - pub fn into_fd(self) -> FileDesc { self.0 } -} - -pub fn read2(p1: AnonPipe, - v1: &mut Vec, - p2: AnonPipe, - v2: &mut Vec) -> io::Result<()> { - //FIXME: Use event based I/O multiplexing - //unimplemented!() - - p1.0.read_to_end(v1)?; - p2.0.read_to_end(v2)?; - - Ok(()) - - /* - // Set both pipes into nonblocking mode as we're gonna be reading from both - // in the `select` loop below, and we wouldn't want one to block the other! - let p1 = p1.into_fd(); - let p2 = p2.into_fd(); - p1.set_nonblocking(true)?; - p2.set_nonblocking(true)?; - - loop { - // wait for either pipe to become readable using `select` - cvt_r(|| unsafe { - let mut read: libc::fd_set = mem::zeroed(); - libc::FD_SET(p1.raw(), &mut read); - libc::FD_SET(p2.raw(), &mut read); - libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(), - ptr::null_mut()) - })?; - - // Read as much as we can from each pipe, ignoring EWOULDBLOCK or - // EAGAIN. If we hit EOF, then this will happen because the underlying - // reader will return Ok(0), in which case we'll see `Ok` ourselves. In - // this case we flip the other fd back into blocking mode and read - // whatever's leftover on that file descriptor. - let read = |fd: &FileDesc, dst: &mut Vec| { - match fd.read_to_end(dst) { - Ok(_) => Ok(true), - Err(e) => { - if e.raw_os_error() == Some(libc::EWOULDBLOCK) || - e.raw_os_error() == Some(libc::EAGAIN) { - Ok(false) - } else { - Err(e) - } - } - } - }; - if read(&p1, v1)? { - p2.set_nonblocking(false)?; - return p2.read_to_end(v2).map(|_| ()); - } - if read(&p2, v2)? { - p1.set_nonblocking(false)?; - return p1.read_to_end(v1).map(|_| ()); - } - } - */ -} diff --git a/ctr-std/src/sys/redox/process.rs b/ctr-std/src/sys/redox/process.rs deleted file mode 100644 index 2037616..0000000 --- a/ctr-std/src/sys/redox/process.rs +++ /dev/null @@ -1,544 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use env::{split_paths}; -use ffi::OsStr; -use os::unix::ffi::OsStrExt; -use fmt; -use io::{self, Error, ErrorKind}; -use iter; -use libc::{EXIT_SUCCESS, EXIT_FAILURE}; -use path::{Path, PathBuf}; -use sys::fd::FileDesc; -use sys::fs::{File, OpenOptions}; -use sys::pipe::{self, AnonPipe}; -use sys::{cvt, syscall}; -use sys_common::process::{CommandEnv, DefaultEnvKey}; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - // Currently we try hard to ensure that the call to `.exec()` doesn't - // actually allocate any memory. While many platforms try to ensure that - // memory allocation works after a fork in a multithreaded process, it's - // been observed to be buggy and somewhat unreliable, so we do our best to - // just not do it at all! - // - // Along those lines, the `argv` and `envp` raw pointers here are exactly - // what's gonna get passed to `execvp`. The `argv` array starts with the - // `program` and ends with a NULL, and the `envp` pointer, if present, is - // also null-terminated. - // - // Right now we don't support removing arguments, so there's no much fancy - // support there, but we support adding and removing environment variables, - // so a side table is used to track where in the `envp` array each key is - // located. Whenever we add a key we update it in place if it's already - // present, and whenever we remove a key we update the locations of all - // other keys. - program: String, - args: Vec, - env: CommandEnv, - - cwd: Option, - uid: Option, - gid: Option, - saw_nul: bool, - closures: Vec io::Result<()> + Send + Sync>>, - stdin: Option, - stdout: Option, - stderr: Option, -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -// passed to do_exec() with configuration of what the child stdio should look -// like -struct ChildPipes { - stdin: ChildStdio, - stdout: ChildStdio, - stderr: ChildStdio, -} - -enum ChildStdio { - Inherit, - Explicit(usize), - Owned(FileDesc), -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, - Fd(FileDesc), -} - -impl Command { - pub fn new(program: &OsStr) -> Command { - Command { - program: program.to_str().unwrap().to_owned(), - args: Vec::new(), - env: Default::default(), - cwd: None, - uid: None, - gid: None, - saw_nul: false, - closures: Vec::new(), - stdin: None, - stdout: None, - stderr: None, - } - } - - pub fn arg(&mut self, arg: &OsStr) { - self.args.push(arg.to_str().unwrap().to_owned()); - } - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(dir.to_str().unwrap().to_owned()); - } - pub fn uid(&mut self, id: u32) { - self.uid = Some(id); - } - pub fn gid(&mut self, id: u32) { - self.gid = Some(id); - } - - pub fn before_exec(&mut self, - f: Box io::Result<()> + Send + Sync>) { - self.closures.push(f); - } - - pub fn stdin(&mut self, stdin: Stdio) { - self.stdin = Some(stdin); - } - pub fn stdout(&mut self, stdout: Stdio) { - self.stdout = Some(stdout); - } - pub fn stderr(&mut self, stderr: Stdio) { - self.stderr = Some(stderr); - } - - pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) - -> io::Result<(Process, StdioPipes)> { - const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; - - if self.saw_nul { - return Err(io::Error::new(ErrorKind::InvalidInput, - "nul byte found in provided data")); - } - - let (ours, theirs) = self.setup_io(default, needs_stdin)?; - let (input, output) = pipe::anon_pipe()?; - - let pid = unsafe { - match cvt(syscall::clone(0))? { - 0 => { - drop(input); - let err = self.do_exec(theirs); - let errno = err.raw_os_error().unwrap_or(syscall::EINVAL) as u32; - let bytes = [ - (errno >> 24) as u8, - (errno >> 16) as u8, - (errno >> 8) as u8, - (errno >> 0) as u8, - CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1], - CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3] - ]; - // pipe I/O up to PIPE_BUF bytes should be atomic, and then - // we want to be sure we *don't* run at_exit destructors as - // we're being torn down regardless - assert!(output.write(&bytes).is_ok()); - let _ = syscall::exit(1); - panic!("failed to exit"); - } - n => n, - } - }; - - let mut p = Process { pid: pid, status: None }; - drop(output); - let mut bytes = [0; 8]; - - // loop to handle EINTR - loop { - match input.read(&mut bytes) { - Ok(0) => return Ok((p, ours)), - Ok(8) => { - assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]), - "Validation on the CLOEXEC pipe failed: {:?}", bytes); - let errno = combine(&bytes[0.. 4]); - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - return Err(Error::from_raw_os_error(errno)) - } - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => { - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - panic!("the CLOEXEC pipe failed: {:?}", e) - }, - Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - panic!("short read on the CLOEXEC pipe") - } - } - } - - fn combine(arr: &[u8]) -> i32 { - let a = arr[0] as u32; - let b = arr[1] as u32; - let c = arr[2] as u32; - let d = arr[3] as u32; - - ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32 - } - } - - pub fn exec(&mut self, default: Stdio) -> io::Error { - if self.saw_nul { - return io::Error::new(ErrorKind::InvalidInput, - "nul byte found in provided data") - } - - match self.setup_io(default, true) { - Ok((_, theirs)) => unsafe { self.do_exec(theirs) }, - Err(e) => e, - } - } - - // And at this point we've reached a special time in the life of the - // child. The child must now be considered hamstrung and unable to - // do anything other than syscalls really. Consider the following - // scenario: - // - // 1. Thread A of process 1 grabs the malloc() mutex - // 2. Thread B of process 1 forks(), creating thread C - // 3. Thread C of process 2 then attempts to malloc() - // 4. The memory of process 2 is the same as the memory of - // process 1, so the mutex is locked. - // - // This situation looks a lot like deadlock, right? It turns out - // that this is what pthread_atfork() takes care of, which is - // presumably implemented across platforms. The first thing that - // threads to *before* forking is to do things like grab the malloc - // mutex, and then after the fork they unlock it. - // - // Despite this information, libnative's spawn has been witnessed to - // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but - // all collected backtraces point at malloc/free traffic in the - // child spawned process. - // - // For this reason, the block of code below should contain 0 - // invocations of either malloc of free (or their related friends). - // - // As an example of not having malloc/free traffic, we don't close - // this file descriptor by dropping the FileDesc (which contains an - // allocation). Instead we just close it manually. This will never - // have the drop glue anyway because this code never returns (the - // child will either exec() or invoke syscall::exit) - unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error { - macro_rules! t { - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => return e, - }) - } - - if let Some(fd) = stdio.stderr.fd() { - t!(cvt(syscall::dup2(fd, 2, &[]))); - let mut flags = t!(cvt(syscall::fcntl(2, syscall::F_GETFD, 0))); - flags &= ! syscall::O_CLOEXEC; - t!(cvt(syscall::fcntl(2, syscall::F_SETFD, flags))); - } - if let Some(fd) = stdio.stdout.fd() { - t!(cvt(syscall::dup2(fd, 1, &[]))); - let mut flags = t!(cvt(syscall::fcntl(1, syscall::F_GETFD, 0))); - flags &= ! syscall::O_CLOEXEC; - t!(cvt(syscall::fcntl(1, syscall::F_SETFD, flags))); - } - if let Some(fd) = stdio.stdin.fd() { - t!(cvt(syscall::dup2(fd, 0, &[]))); - let mut flags = t!(cvt(syscall::fcntl(0, syscall::F_GETFD, 0))); - flags &= ! syscall::O_CLOEXEC; - t!(cvt(syscall::fcntl(0, syscall::F_SETFD, flags))); - } - - if let Some(g) = self.gid { - t!(cvt(syscall::setregid(g as usize, g as usize))); - } - if let Some(u) = self.uid { - t!(cvt(syscall::setreuid(u as usize, u as usize))); - } - if let Some(ref cwd) = self.cwd { - t!(cvt(syscall::chdir(cwd))); - } - - for callback in self.closures.iter_mut() { - t!(callback()); - } - - let args: Vec<[usize; 2]> = iter::once( - [self.program.as_ptr() as usize, self.program.len()] - ).chain( - self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()]) - ).collect(); - - self.env.apply(); - - let program = if self.program.contains(':') || self.program.contains('/') { - Some(PathBuf::from(&self.program)) - } else if let Ok(path_env) = ::env::var("PATH") { - let mut program = None; - for mut path in split_paths(&path_env) { - path.push(&self.program); - if path.exists() { - program = Some(path); - break; - } - } - program - } else { - None - }; - - if let Some(program) = program { - if let Err(err) = syscall::execve(program.as_os_str().as_bytes(), &args) { - io::Error::from_raw_os_error(err.errno as i32) - } else { - panic!("return from exec without err"); - } - } else { - io::Error::from_raw_os_error(syscall::ENOENT) - } - } - - - fn setup_io(&self, default: Stdio, needs_stdin: bool) - -> io::Result<(StdioPipes, ChildPipes)> { - let null = Stdio::Null; - let default_stdin = if needs_stdin {&default} else {&null}; - let stdin = self.stdin.as_ref().unwrap_or(default_stdin); - let stdout = self.stdout.as_ref().unwrap_or(&default); - let stderr = self.stderr.as_ref().unwrap_or(&default); - let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?; - let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?; - let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?; - let ours = StdioPipes { - stdin: our_stdin, - stdout: our_stdout, - stderr: our_stderr, - }; - let theirs = ChildPipes { - stdin: their_stdin, - stdout: their_stdout, - stderr: their_stderr, - }; - Ok((ours, theirs)) - } -} - -impl Stdio { - fn to_child_stdio(&self, readable: bool) - -> io::Result<(ChildStdio, Option)> { - match *self { - Stdio::Inherit => Ok((ChildStdio::Inherit, None)), - - // Make sure that the source descriptors are not an stdio - // descriptor, otherwise the order which we set the child's - // descriptors may blow away a descriptor which we are hoping to - // save. For example, suppose we want the child's stderr to be the - // parent's stdout, and the child's stdout to be the parent's - // stderr. No matter which we dup first, the second will get - // overwritten prematurely. - Stdio::Fd(ref fd) => { - if fd.raw() <= 2 { - Ok((ChildStdio::Owned(fd.duplicate()?), None)) - } else { - Ok((ChildStdio::Explicit(fd.raw()), None)) - } - } - - Stdio::MakePipe => { - let (reader, writer) = pipe::anon_pipe()?; - let (ours, theirs) = if readable { - (writer, reader) - } else { - (reader, writer) - }; - Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) - } - - Stdio::Null => { - let mut opts = OpenOptions::new(); - opts.read(readable); - opts.write(!readable); - let fd = File::open(Path::new("null:"), &opts)?; - Ok((ChildStdio::Owned(fd.into_fd()), None)) - } - } - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - Stdio::Fd(pipe.into_fd()) - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - Stdio::Fd(file.into_fd()) - } -} - -impl ChildStdio { - fn fd(&self) -> Option { - match *self { - ChildStdio::Inherit => None, - ChildStdio::Explicit(fd) => Some(fd), - ChildStdio::Owned(ref fd) => Some(fd.raw()), - } - } -} - -impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.program)?; - for arg in &self.args { - write!(f, " {:?}", arg)?; - } - Ok(()) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Processes -//////////////////////////////////////////////////////////////////////////////// - -/// Unix exit statuses -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatus(i32); - -impl ExitStatus { - fn exited(&self) -> bool { - self.0 & 0x7F == 0 - } - - pub fn success(&self) -> bool { - self.code() == Some(0) - } - - pub fn code(&self) -> Option { - if self.exited() { - Some((self.0 >> 8) & 0xFF) - } else { - None - } - } - - pub fn signal(&self) -> Option { - if !self.exited() { - Some(self.0 & 0x7F) - } else { - None - } - } -} - -impl From for ExitStatus { - fn from(a: i32) -> ExitStatus { - ExitStatus(a) - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(code) = self.code() { - write!(f, "exit code: {}", code) - } else { - let signal = self.signal().unwrap(); - write!(f, "signal: {}", signal) - } - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(u8); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); - pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -/// The unique id of the process (this should never be negative). -pub struct Process { - pid: usize, - status: Option, -} - -impl Process { - pub fn id(&self) -> u32 { - self.pid as u32 - } - - pub fn kill(&mut self) -> io::Result<()> { - // If we've already waited on this process then the pid can be recycled - // and used for another process, and we probably shouldn't be killing - // random processes, so just return an error. - if self.status.is_some() { - Err(Error::new(ErrorKind::InvalidInput, - "invalid argument: can't kill an exited process")) - } else { - cvt(syscall::kill(self.pid, syscall::SIGKILL))?; - Ok(()) - } - } - - pub fn wait(&mut self) -> io::Result { - if let Some(status) = self.status { - return Ok(status) - } - let mut status = 0; - cvt(syscall::waitpid(self.pid, &mut status, 0))?; - self.status = Some(ExitStatus(status as i32)); - Ok(ExitStatus(status as i32)) - } - - pub fn try_wait(&mut self) -> io::Result> { - if let Some(status) = self.status { - return Ok(Some(status)) - } - let mut status = 0; - let pid = cvt(syscall::waitpid(self.pid, &mut status, syscall::WNOHANG))?; - if pid == 0 { - Ok(None) - } else { - self.status = Some(ExitStatus(status as i32)); - Ok(Some(ExitStatus(status as i32))) - } - } -} diff --git a/ctr-std/src/sys/redox/rand.rs b/ctr-std/src/sys/redox/rand.rs deleted file mode 100644 index 3b378f5..0000000 --- a/ctr-std/src/sys/redox/rand.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn hashmap_random_keys() -> (u64, u64) { - (0, 0) -} diff --git a/ctr-std/src/sys/redox/rwlock.rs b/ctr-std/src/sys/redox/rwlock.rs deleted file mode 100644 index d74b614..0000000 --- a/ctr-std/src/sys/redox/rwlock.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::mutex::Mutex; - -pub struct RWLock { - mutex: Mutex -} - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { - mutex: Mutex::new() - } - } - - #[inline] - pub unsafe fn read(&self) { - self.mutex.lock(); - } - - #[inline] - pub unsafe fn try_read(&self) -> bool { - self.mutex.try_lock() - } - - #[inline] - pub unsafe fn write(&self) { - self.mutex.lock(); - } - - #[inline] - pub unsafe fn try_write(&self) -> bool { - self.mutex.try_lock() - } - - #[inline] - pub unsafe fn read_unlock(&self) { - self.mutex.unlock(); - } - - #[inline] - pub unsafe fn write_unlock(&self) { - self.mutex.unlock(); - } - - #[inline] - pub unsafe fn destroy(&self) { - self.mutex.destroy(); - } -} diff --git a/ctr-std/src/sys/redox/stack_overflow.rs b/ctr-std/src/sys/redox/stack_overflow.rs deleted file mode 100644 index 760fe06..0000000 --- a/ctr-std/src/sys/redox/stack_overflow.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg_attr(test, allow(dead_code))] - -pub struct Handler; - -impl Handler { - pub unsafe fn new() -> Handler { - Handler - } -} - -pub unsafe fn init() { - -} - -pub unsafe fn cleanup() { - -} diff --git a/ctr-std/src/sys/redox/stdio.rs b/ctr-std/src/sys/redox/stdio.rs deleted file mode 100644 index 7a4d11b..0000000 --- a/ctr-std/src/sys/redox/stdio.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use sys::{cvt, syscall}; -use sys::fd::FileDesc; - -pub struct Stdin(()); -pub struct Stdout(()); -pub struct Stderr(()); - -impl Stdin { - pub fn new() -> io::Result { Ok(Stdin(())) } - - pub fn read(&self, data: &mut [u8]) -> io::Result { - let fd = FileDesc::new(0); - let ret = fd.read(data); - fd.into_raw(); - ret - } -} - -impl Stdout { - pub fn new() -> io::Result { Ok(Stdout(())) } - - pub fn write(&self, data: &[u8]) -> io::Result { - let fd = FileDesc::new(1); - let ret = fd.write(data); - fd.into_raw(); - ret - } - - pub fn flush(&self) -> io::Result<()> { - cvt(syscall::fsync(1)).and(Ok(())) - } -} - -impl Stderr { - pub fn new() -> io::Result { Ok(Stderr(())) } - - pub fn write(&self, data: &[u8]) -> io::Result { - let fd = FileDesc::new(2); - let ret = fd.write(data); - fd.into_raw(); - ret - } - - pub fn flush(&self) -> io::Result<()> { - cvt(syscall::fsync(2)).and(Ok(())) - } -} - -// FIXME: right now this raw stderr handle is used in a few places because -// std::io::stderr_raw isn't exposed, but once that's exposed this impl -// should go away -impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result { - Stderr::write(self, data) - } - - fn flush(&mut self) -> io::Result<()> { - Stderr::flush(self) - } -} - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(::sys::syscall::EBADF as i32) -} - -pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; - -pub fn stderr_prints_nothing() -> bool { - false -} diff --git a/ctr-std/src/sys/redox/syscall/arch/arm.rs b/ctr-std/src/sys/redox/syscall/arch/arm.rs deleted file mode 100644 index 9fb3961..0000000 --- a/ctr-std/src/sys/redox/syscall/arch/arm.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::error::{Error, Result}; - -pub unsafe fn syscall0(mut a: usize) -> Result { - asm!("swi $$0" - : "={r0}"(a) - : "{r7}"(a) - : "memory" - : "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall1(mut a: usize, b: usize) -> Result { - asm!("swi $$0" - : "={r0}"(a) - : "{r7}"(a), "{r0}"(b) - : "memory" - : "volatile"); - - Error::demux(a) -} - -// Clobbers all registers - special for clone -pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result { - asm!("swi $$0" - : "={r0}"(a) - : "{r7}"(a), "{r0}"(b) - : "memory", "r0", "r1", "r2", "r3", "r4" - : "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result { - asm!("swi $$0" - : "={r0}"(a) - : "{r7}"(a), "{r0}"(b), "{r1}"(c) - : "memory" - : "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result { - asm!("swi $$0" - : "={r0}"(a) - : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d) - : "memory" - : "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result { - asm!("swi $$0" - : "={r0}"(a) - : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e) - : "memory" - : "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - -> Result { - asm!("swi $$0" - : "={r0}"(a) - : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e), "{r4}"(f) - : "memory" - : "volatile"); - - Error::demux(a) -} diff --git a/ctr-std/src/sys/redox/syscall/arch/x86.rs b/ctr-std/src/sys/redox/syscall/arch/x86.rs deleted file mode 100644 index 724a6b9..0000000 --- a/ctr-std/src/sys/redox/syscall/arch/x86.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::error::{Error, Result}; - -pub unsafe fn syscall0(mut a: usize) -> Result { - asm!("int 0x80" - : "={eax}"(a) - : "{eax}"(a) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall1(mut a: usize, b: usize) -> Result { - asm!("int 0x80" - : "={eax}"(a) - : "{eax}"(a), "{ebx}"(b) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} - -// Clobbers all registers - special for clone -pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result { - asm!("int 0x80" - : "={eax}"(a) - : "{eax}"(a), "{ebx}"(b) - : "memory", "ebx", "ecx", "edx", "esi", "edi" - : "intel", "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result { - asm!("int 0x80" - : "={eax}"(a) - : "{eax}"(a), "{ebx}"(b), "{ecx}"(c) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result { - asm!("int 0x80" - : "={eax}"(a) - : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result { - asm!("int 0x80" - : "={eax}"(a) - : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - -> Result { - asm!("int 0x80" - : "={eax}"(a) - : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e), "{edi}"(f) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} diff --git a/ctr-std/src/sys/redox/syscall/arch/x86_64.rs b/ctr-std/src/sys/redox/syscall/arch/x86_64.rs deleted file mode 100644 index a321c31..0000000 --- a/ctr-std/src/sys/redox/syscall/arch/x86_64.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::error::{Error, Result}; - -pub unsafe fn syscall0(mut a: usize) -> Result { - asm!("int 0x80" - : "={rax}"(a) - : "{rax}"(a) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall1(mut a: usize, b: usize) -> Result { - asm!("int 0x80" - : "={rax}"(a) - : "{rax}"(a), "{rbx}"(b) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} - -// Clobbers all registers - special for clone -pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result { - asm!("int 0x80" - : "={rax}"(a) - : "{rax}"(a), "{rbx}"(b) - : "memory", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", - "r9", "r10", "r11", "r12", "r13", "r14", "r15" - : "intel", "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result { - asm!("int 0x80" - : "={rax}"(a) - : "{rax}"(a), "{rbx}"(b), "{rcx}"(c) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result { - asm!("int 0x80" - : "={rax}"(a) - : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result { - asm!("int 0x80" - : "={rax}"(a) - : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} - -pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - -> Result { - asm!("int 0x80" - : "={rax}"(a) - : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e), "{rdi}"(f) - : "memory" - : "intel", "volatile"); - - Error::demux(a) -} diff --git a/ctr-std/src/sys/redox/syscall/call.rs b/ctr-std/src/sys/redox/syscall/call.rs deleted file mode 100644 index f9a8bd6..0000000 --- a/ctr-std/src/sys/redox/syscall/call.rs +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::arch::*; -use super::data::{SigAction, Stat, StatVfs, TimeSpec}; -use super::error::Result; -use super::number::*; - -use core::{mem, ptr}; - -// Signal restorer -extern "C" fn restorer() -> ! { - sigreturn().unwrap(); - unreachable!(); -} - -/// Set the end of the process's heap -/// -/// When `addr` is `0`, this function will return the current break. -/// -/// When `addr` is nonzero, this function will attempt to set the end of the process's -/// heap to `addr` and return the new program break. The new program break should be -/// checked by the allocator, it may not be exactly `addr`, as it may be aligned to a page -/// boundary. -/// -/// On error, `Err(ENOMEM)` will be returned indicating that no memory is available -pub unsafe fn brk(addr: usize) -> Result { - syscall1(SYS_BRK, addr) -} - -/// Change the process's working directory -/// -/// This function will attempt to set the process's working directory to `path`, which can be -/// either a relative, scheme relative, or absolute path. -/// -/// On success, `Ok(0)` will be returned. On error, one of the following errors will be returned. -/// -/// # Errors -/// -/// * `EACCES` - permission is denied for one of the components of `path`, or `path` -/// * `EFAULT` - `path` does not point to the process's addressible memory -/// * `EIO` - an I/O error occurred -/// * `ENOENT` - `path` does not exit -/// * `ENOTDIR` - `path` is not a directory -pub fn chdir>(path: T) -> Result { - unsafe { syscall2(SYS_CHDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) } -} - -pub fn chmod>(path: T, mode: usize) -> Result { - unsafe { syscall3(SYS_CHMOD, path.as_ref().as_ptr() as usize, path.as_ref().len(), mode) } -} - -/// Produce a fork of the current process, or a new process thread -pub unsafe fn clone(flags: usize) -> Result { - syscall1_clobber(SYS_CLONE, flags) -} - -/// Close a file -pub fn close(fd: usize) -> Result { - unsafe { syscall1(SYS_CLOSE, fd) } -} - -/// Get the current system time -pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result { - unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) } -} - -/// Copy and transform a file descriptor -pub fn dup(fd: usize, buf: &[u8]) -> Result { - unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) } -} - -/// Copy and transform a file descriptor -pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result { - unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) } -} - -/// Replace the current process with a new executable -pub fn execve>(path: T, args: &[[usize; 2]]) -> Result { - unsafe { syscall4(SYS_EXECVE, path.as_ref().as_ptr() as usize, - path.as_ref().len(), args.as_ptr() as usize, args.len()) } -} - -/// Exit the current process -pub fn exit(status: usize) -> Result { - unsafe { syscall1(SYS_EXIT, status) } -} - -/// Change file permissions -pub fn fchmod(fd: usize, mode: u16) -> Result { - unsafe { syscall2(SYS_FCHMOD, fd, mode as usize) } - -} - -/// Change file ownership -pub fn fchown(fd: usize, uid: u32, gid: u32) -> Result { - unsafe { syscall3(SYS_FCHOWN, fd, uid as usize, gid as usize) } - -} - -/// Change file descriptor flags -pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result { - unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) } -} - -/// Register a file for event-based I/O -pub fn fevent(fd: usize, flags: usize) -> Result { - unsafe { syscall2(SYS_FEVENT, fd, flags) } -} - -/// Map a file into memory -pub unsafe fn fmap(fd: usize, offset: usize, size: usize) -> Result { - syscall3(SYS_FMAP, fd, offset, size) -} - -/// Unmap a memory-mapped file -pub unsafe fn funmap(addr: usize) -> Result { - syscall1(SYS_FUNMAP, addr) -} - -/// Retrieve the canonical path of a file -pub fn fpath(fd: usize, buf: &mut [u8]) -> Result { - unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) } -} - -/// Rename a file -pub fn frename>(fd: usize, path: T) -> Result { - unsafe { syscall3(SYS_FRENAME, fd, path.as_ref().as_ptr() as usize, path.as_ref().len()) } -} - -/// Get metadata about a file -pub fn fstat(fd: usize, stat: &mut Stat) -> Result { - unsafe { syscall3(SYS_FSTAT, fd, stat as *mut Stat as usize, mem::size_of::()) } -} - -/// Get metadata about a filesystem -pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result { - unsafe { syscall3(SYS_FSTATVFS, fd, stat as *mut StatVfs as usize, mem::size_of::()) } -} - -/// Sync a file descriptor to its underlying medium -pub fn fsync(fd: usize) -> Result { - unsafe { syscall1(SYS_FSYNC, fd) } -} - -/// Truncate or extend a file to a specified length -pub fn ftruncate(fd: usize, len: usize) -> Result { - unsafe { syscall2(SYS_FTRUNCATE, fd, len) } -} - -// Change modify and/or access times -pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result { - unsafe { syscall3(SYS_FUTIMENS, fd, times.as_ptr() as usize, - times.len() * mem::size_of::()) } -} - -/// Fast userspace mutex -pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32) - -> Result { - syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize) -} - -/// Get the current working directory -pub fn getcwd(buf: &mut [u8]) -> Result { - unsafe { syscall2(SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()) } -} - -/// Get the effective group ID -pub fn getegid() -> Result { - unsafe { syscall0(SYS_GETEGID) } -} - -/// Get the effective namespace -pub fn getens() -> Result { - unsafe { syscall0(SYS_GETENS) } -} - -/// Get the effective user ID -pub fn geteuid() -> Result { - unsafe { syscall0(SYS_GETEUID) } -} - -/// Get the current group ID -pub fn getgid() -> Result { - unsafe { syscall0(SYS_GETGID) } -} - -/// Get the current namespace -pub fn getns() -> Result { - unsafe { syscall0(SYS_GETNS) } -} - -/// Get the current process ID -pub fn getpid() -> Result { - unsafe { syscall0(SYS_GETPID) } -} - -/// Get the process group ID -pub fn getpgid(pid: usize) -> Result { - unsafe { syscall1(SYS_GETPGID, pid) } -} - -/// Get the parent process ID -pub fn getppid() -> Result { - unsafe { syscall0(SYS_GETPPID) } -} - -/// Get the current user ID -pub fn getuid() -> Result { - unsafe { syscall0(SYS_GETUID) } -} - -/// Set the I/O privilege level -pub unsafe fn iopl(level: usize) -> Result { - syscall1(SYS_IOPL, level) -} - -/// Send a signal `sig` to the process identified by `pid` -pub fn kill(pid: usize, sig: usize) -> Result { - unsafe { syscall2(SYS_KILL, pid, sig) } -} - -/// Create a link to a file -pub unsafe fn link(old: *const u8, new: *const u8) -> Result { - syscall2(SYS_LINK, old as usize, new as usize) -} - -/// Seek to `offset` bytes in a file descriptor -pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result { - unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) } -} - -/// Make a new scheme namespace -pub fn mkns(schemes: &[[usize; 2]]) -> Result { - unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) } -} - -/// Sleep for the time specified in `req` -pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result { - unsafe { syscall2(SYS_NANOSLEEP, req as *const TimeSpec as usize, - rem as *mut TimeSpec as usize) } -} - -/// Open a file -pub fn open>(path: T, flags: usize) -> Result { - unsafe { syscall3(SYS_OPEN, path.as_ref().as_ptr() as usize, path.as_ref().len(), flags) } -} - -/// Allocate pages, linearly in physical memory -pub unsafe fn physalloc(size: usize) -> Result { - syscall1(SYS_PHYSALLOC, size) -} - -/// Free physically allocated pages -pub unsafe fn physfree(physical_address: usize, size: usize) -> Result { - syscall2(SYS_PHYSFREE, physical_address, size) -} - -/// Map physical memory to virtual memory -pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result { - syscall3(SYS_PHYSMAP, physical_address, size, flags) -} - -/// Unmap previously mapped physical memory -pub unsafe fn physunmap(virtual_address: usize) -> Result { - syscall1(SYS_PHYSUNMAP, virtual_address) -} - -/// Create a pair of file descriptors referencing the read and write ends of a pipe -pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result { - unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) } -} - -/// Read from a file descriptor into a buffer -pub fn read(fd: usize, buf: &mut [u8]) -> Result { - unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) } -} - -/// Remove a directory -pub fn rmdir>(path: T) -> Result { - unsafe { syscall2(SYS_RMDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) } -} - -/// Set the process group ID -pub fn setpgid(pid: usize, pgid: usize) -> Result { - unsafe { syscall2(SYS_SETPGID, pid, pgid) } -} - -/// Set the current process group IDs -pub fn setregid(rgid: usize, egid: usize) -> Result { - unsafe { syscall2(SYS_SETREGID, rgid, egid) } -} - -/// Make a new scheme namespace -pub fn setrens(rns: usize, ens: usize) -> Result { - unsafe { syscall2(SYS_SETRENS, rns, ens) } -} - -/// Set the current process user IDs -pub fn setreuid(ruid: usize, euid: usize) -> Result { - unsafe { syscall2(SYS_SETREUID, ruid, euid) } -} - -/// Set up a signal handler -pub fn sigaction(sig: usize, act: Option<&SigAction>, oldact: Option<&mut SigAction>) --> Result { - unsafe { syscall4(SYS_SIGACTION, sig, - act.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize, - oldact.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize, - restorer as usize) } -} - -// Return from signal handler -pub fn sigreturn() -> Result { - unsafe { syscall0(SYS_SIGRETURN) } -} - -/// Remove a file -pub fn unlink>(path: T) -> Result { - unsafe { syscall2(SYS_UNLINK, path.as_ref().as_ptr() as usize, path.as_ref().len()) } -} - -/// Convert a virtual address to a physical one -pub unsafe fn virttophys(virtual_address: usize) -> Result { - syscall1(SYS_VIRTTOPHYS, virtual_address) -} - -/// Check if a child process has exited or received a signal -pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result { - unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) } -} - -/// Write a buffer to a file descriptor -/// -/// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning -/// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which -/// were written. -/// -/// # Errors -/// -/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block -/// * `EBADF` - the file descriptor is not valid or is not open for writing -/// * `EFAULT` - `buf` does not point to the process's addressible memory -/// * `EIO` - an I/O error occurred -/// * `ENOSPC` - the device containing the file descriptor has no room for data -/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed -pub fn write(fd: usize, buf: &[u8]) -> Result { - unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) } -} - -/// Yield the process's time slice to the kernel -/// -/// This function will return Ok(0) on success -pub fn sched_yield() -> Result { - unsafe { syscall0(SYS_YIELD) } -} diff --git a/ctr-std/src/sys/redox/syscall/data.rs b/ctr-std/src/sys/redox/syscall/data.rs deleted file mode 100644 index 2e784eb..0000000 --- a/ctr-std/src/sys/redox/syscall/data.rs +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use core::ops::{Deref, DerefMut}; -use core::{mem, slice}; - -#[derive(Copy, Clone, Debug, Default)] -pub struct Event { - pub id: usize, - pub flags: usize, - pub data: usize -} - -impl Deref for Event { - type Target = [u8]; - fn deref(&self) -> &[u8] { - unsafe { - slice::from_raw_parts( - self as *const Event as *const u8, - mem::size_of::() - ) as &[u8] - } - } -} - -impl DerefMut for Event { - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { - slice::from_raw_parts_mut( - self as *mut Event as *mut u8, - mem::size_of::() - ) as &mut [u8] - } - } -} - -#[derive(Copy, Clone, Debug, Default)] -#[repr(C)] -pub struct Packet { - pub id: u64, - pub pid: usize, - pub uid: u32, - pub gid: u32, - pub a: usize, - pub b: usize, - pub c: usize, - pub d: usize -} - -impl Deref for Packet { - type Target = [u8]; - fn deref(&self) -> &[u8] { - unsafe { - slice::from_raw_parts( - self as *const Packet as *const u8, - mem::size_of::() - ) as &[u8] - } - } -} - -impl DerefMut for Packet { - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { - slice::from_raw_parts_mut( - self as *mut Packet as *mut u8, - mem::size_of::() - ) as &mut [u8] - } - } -} - -#[derive(Copy, Clone, Debug)] -#[repr(C)] -pub struct SigAction { - pub sa_handler: extern "C" fn(usize), - pub sa_mask: [u64; 2], - pub sa_flags: usize, -} - -impl Default for SigAction { - fn default() -> Self { - Self { - sa_handler: unsafe { mem::transmute(0usize) }, - sa_mask: [0; 2], - sa_flags: 0, - } - } -} - -#[derive(Copy, Clone, Debug, Default)] -#[repr(C)] -pub struct Stat { - pub st_dev: u64, - pub st_ino: u64, - pub st_mode: u16, - pub st_nlink: u32, - pub st_uid: u32, - pub st_gid: u32, - pub st_size: u64, - pub st_blksize: u32, - pub st_blocks: u64, - pub st_mtime: u64, - pub st_mtime_nsec: u32, - pub st_atime: u64, - pub st_atime_nsec: u32, - pub st_ctime: u64, - pub st_ctime_nsec: u32, -} - -impl Deref for Stat { - type Target = [u8]; - fn deref(&self) -> &[u8] { - unsafe { - slice::from_raw_parts( - self as *const Stat as *const u8, - mem::size_of::() - ) as &[u8] - } - } -} - -impl DerefMut for Stat { - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { - slice::from_raw_parts_mut( - self as *mut Stat as *mut u8, - mem::size_of::() - ) as &mut [u8] - } - } -} - -#[derive(Copy, Clone, Debug, Default)] -#[repr(C)] -pub struct StatVfs { - pub f_bsize: u32, - pub f_blocks: u64, - pub f_bfree: u64, - pub f_bavail: u64, -} - -impl Deref for StatVfs { - type Target = [u8]; - fn deref(&self) -> &[u8] { - unsafe { - slice::from_raw_parts( - self as *const StatVfs as *const u8, - mem::size_of::() - ) as &[u8] - } - } -} - -impl DerefMut for StatVfs { - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { - slice::from_raw_parts_mut( - self as *mut StatVfs as *mut u8, - mem::size_of::() - ) as &mut [u8] - } - } -} - -#[derive(Copy, Clone, Debug, Default)] -#[repr(C)] -pub struct TimeSpec { - pub tv_sec: i64, - pub tv_nsec: i32, -} - -impl Deref for TimeSpec { - type Target = [u8]; - fn deref(&self) -> &[u8] { - unsafe { - slice::from_raw_parts( - self as *const TimeSpec as *const u8, - mem::size_of::() - ) as &[u8] - } - } -} - -impl DerefMut for TimeSpec { - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { - slice::from_raw_parts_mut( - self as *mut TimeSpec as *mut u8, - mem::size_of::() - ) as &mut [u8] - } - } -} diff --git a/ctr-std/src/sys/redox/syscall/error.rs b/ctr-std/src/sys/redox/syscall/error.rs deleted file mode 100644 index 1ef7954..0000000 --- a/ctr-std/src/sys/redox/syscall/error.rs +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use core::{fmt, result}; - -#[derive(Eq, PartialEq)] -pub struct Error { - pub errno: i32, -} - -pub type Result = result::Result; - -impl Error { - pub fn new(errno: i32) -> Error { - Error { errno: errno } - } - - pub fn mux(result: Result) -> usize { - match result { - Ok(value) => value, - Err(error) => -error.errno as usize, - } - } - - pub fn demux(value: usize) -> Result { - let errno = -(value as i32); - if errno >= 1 && errno < STR_ERROR.len() as i32 { - Err(Error::new(errno)) - } else { - Ok(value) - } - } - - pub fn text(&self) -> &str { - if let Some(description) = STR_ERROR.get(self.errno as usize) { - description - } else { - "Unknown Error" - } - } -} - -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.text()) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.text()) - } -} - -pub const EPERM: i32 = 1; /* Operation not permitted */ -pub const ENOENT: i32 = 2; /* No such file or directory */ -pub const ESRCH: i32 = 3; /* No such process */ -pub const EINTR: i32 = 4; /* Interrupted system call */ -pub const EIO: i32 = 5; /* I/O error */ -pub const ENXIO: i32 = 6; /* No such device or address */ -pub const E2BIG: i32 = 7; /* Argument list too long */ -pub const ENOEXEC: i32 = 8; /* Exec format error */ -pub const EBADF: i32 = 9; /* Bad file number */ -pub const ECHILD: i32 = 10; /* No child processes */ -pub const EAGAIN: i32 = 11; /* Try again */ -pub const ENOMEM: i32 = 12; /* Out of memory */ -pub const EACCES: i32 = 13; /* Permission denied */ -pub const EFAULT: i32 = 14; /* Bad address */ -pub const ENOTBLK: i32 = 15; /* Block device required */ -pub const EBUSY: i32 = 16; /* Device or resource busy */ -pub const EEXIST: i32 = 17; /* File exists */ -pub const EXDEV: i32 = 18; /* Cross-device link */ -pub const ENODEV: i32 = 19; /* No such device */ -pub const ENOTDIR: i32 = 20; /* Not a directory */ -pub const EISDIR: i32 = 21; /* Is a directory */ -pub const EINVAL: i32 = 22; /* Invalid argument */ -pub const ENFILE: i32 = 23; /* File table overflow */ -pub const EMFILE: i32 = 24; /* Too many open files */ -pub const ENOTTY: i32 = 25; /* Not a typewriter */ -pub const ETXTBSY: i32 = 26; /* Text file busy */ -pub const EFBIG: i32 = 27; /* File too large */ -pub const ENOSPC: i32 = 28; /* No space left on device */ -pub const ESPIPE: i32 = 29; /* Illegal seek */ -pub const EROFS: i32 = 30; /* Read-only file system */ -pub const EMLINK: i32 = 31; /* Too many links */ -pub const EPIPE: i32 = 32; /* Broken pipe */ -pub const EDOM: i32 = 33; /* Math argument out of domain of func */ -pub const ERANGE: i32 = 34; /* Math result not representable */ -pub const EDEADLK: i32 = 35; /* Resource deadlock would occur */ -pub const ENAMETOOLONG: i32 = 36; /* File name too long */ -pub const ENOLCK: i32 = 37; /* No record locks available */ -pub const ENOSYS: i32 = 38; /* Function not implemented */ -pub const ENOTEMPTY: i32 = 39; /* Directory not empty */ -pub const ELOOP: i32 = 40; /* Too many symbolic links encountered */ -pub const EWOULDBLOCK: i32 = 41; /* Operation would block */ -pub const ENOMSG: i32 = 42; /* No message of desired type */ -pub const EIDRM: i32 = 43; /* Identifier removed */ -pub const ECHRNG: i32 = 44; /* Channel number out of range */ -pub const EL2NSYNC: i32 = 45; /* Level 2 not synchronized */ -pub const EL3HLT: i32 = 46; /* Level 3 halted */ -pub const EL3RST: i32 = 47; /* Level 3 reset */ -pub const ELNRNG: i32 = 48; /* Link number out of range */ -pub const EUNATCH: i32 = 49; /* Protocol driver not attached */ -pub const ENOCSI: i32 = 50; /* No CSI structure available */ -pub const EL2HLT: i32 = 51; /* Level 2 halted */ -pub const EBADE: i32 = 52; /* Invalid exchange */ -pub const EBADR: i32 = 53; /* Invalid request descriptor */ -pub const EXFULL: i32 = 54; /* Exchange full */ -pub const ENOANO: i32 = 55; /* No anode */ -pub const EBADRQC: i32 = 56; /* Invalid request code */ -pub const EBADSLT: i32 = 57; /* Invalid slot */ -pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */ -pub const EBFONT: i32 = 59; /* Bad font file format */ -pub const ENOSTR: i32 = 60; /* Device not a stream */ -pub const ENODATA: i32 = 61; /* No data available */ -pub const ETIME: i32 = 62; /* Timer expired */ -pub const ENOSR: i32 = 63; /* Out of streams resources */ -pub const ENONET: i32 = 64; /* Machine is not on the network */ -pub const ENOPKG: i32 = 65; /* Package not installed */ -pub const EREMOTE: i32 = 66; /* Object is remote */ -pub const ENOLINK: i32 = 67; /* Link has been severed */ -pub const EADV: i32 = 68; /* Advertise error */ -pub const ESRMNT: i32 = 69; /* Srmount error */ -pub const ECOMM: i32 = 70; /* Communication error on send */ -pub const EPROTO: i32 = 71; /* Protocol error */ -pub const EMULTIHOP: i32 = 72; /* Multihop attempted */ -pub const EDOTDOT: i32 = 73; /* RFS specific error */ -pub const EBADMSG: i32 = 74; /* Not a data message */ -pub const EOVERFLOW: i32 = 75; /* Value too large for defined data type */ -pub const ENOTUNIQ: i32 = 76; /* Name not unique on network */ -pub const EBADFD: i32 = 77; /* File descriptor in bad state */ -pub const EREMCHG: i32 = 78; /* Remote address changed */ -pub const ELIBACC: i32 = 79; /* Can not access a needed shared library */ -pub const ELIBBAD: i32 = 80; /* Accessing a corrupted shared library */ -pub const ELIBSCN: i32 = 81; /* .lib section in a.out corrupted */ -pub const ELIBMAX: i32 = 82; /* Attempting to link in too many shared libraries */ -pub const ELIBEXEC: i32 = 83; /* Cannot exec a shared library directly */ -pub const EILSEQ: i32 = 84; /* Illegal byte sequence */ -pub const ERESTART: i32 = 85; /* Interrupted system call should be restarted */ -pub const ESTRPIPE: i32 = 86; /* Streams pipe error */ -pub const EUSERS: i32 = 87; /* Too many users */ -pub const ENOTSOCK: i32 = 88; /* Socket operation on non-socket */ -pub const EDESTADDRREQ: i32 = 89; /* Destination address required */ -pub const EMSGSIZE: i32 = 90; /* Message too long */ -pub const EPROTOTYPE: i32 = 91; /* Protocol wrong type for socket */ -pub const ENOPROTOOPT: i32 = 92; /* Protocol not available */ -pub const EPROTONOSUPPORT: i32 = 93; /* Protocol not supported */ -pub const ESOCKTNOSUPPORT: i32 = 94; /* Socket type not supported */ -pub const EOPNOTSUPP: i32 = 95; /* Operation not supported on transport endpoint */ -pub const EPFNOSUPPORT: i32 = 96; /* Protocol family not supported */ -pub const EAFNOSUPPORT: i32 = 97; /* Address family not supported by protocol */ -pub const EADDRINUSE: i32 = 98; /* Address already in use */ -pub const EADDRNOTAVAIL: i32 = 99; /* Cannot assign requested address */ -pub const ENETDOWN: i32 = 100; /* Network is down */ -pub const ENETUNREACH: i32 = 101; /* Network is unreachable */ -pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */ -pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */ -pub const ECONNRESET: i32 = 104; /* Connection reset by peer */ -pub const ENOBUFS: i32 = 105; /* No buffer space available */ -pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */ -pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */ -pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */ -pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */ -pub const ETIMEDOUT: i32 = 110; /* Connection timed out */ -pub const ECONNREFUSED: i32 = 111; /* Connection refused */ -pub const EHOSTDOWN: i32 = 112; /* Host is down */ -pub const EHOSTUNREACH: i32 = 113; /* No route to host */ -pub const EALREADY: i32 = 114; /* Operation already in progress */ -pub const EINPROGRESS: i32 = 115; /* Operation now in progress */ -pub const ESTALE: i32 = 116; /* Stale NFS file handle */ -pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */ -pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */ -pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */ -pub const EISNAM: i32 = 120; /* Is a named type file */ -pub const EREMOTEIO: i32 = 121; /* Remote I/O error */ -pub const EDQUOT: i32 = 122; /* Quota exceeded */ -pub const ENOMEDIUM: i32 = 123; /* No medium found */ -pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */ -pub const ECANCELED: i32 = 125; /* Operation Canceled */ -pub const ENOKEY: i32 = 126; /* Required key not available */ -pub const EKEYEXPIRED: i32 = 127; /* Key has expired */ -pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */ -pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */ -pub const EOWNERDEAD: i32 = 130; /* Owner died */ -pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */ - -pub static STR_ERROR: [&'static str; 132] = ["Success", - "Operation not permitted", - "No such file or directory", - "No such process", - "Interrupted system call", - "I/O error", - "No such device or address", - "Argument list too long", - "Exec format error", - "Bad file number", - "No child processes", - "Try again", - "Out of memory", - "Permission denied", - "Bad address", - "Block device required", - "Device or resource busy", - "File exists", - "Cross-device link", - "No such device", - "Not a directory", - "Is a directory", - "Invalid argument", - "File table overflow", - "Too many open files", - "Not a typewriter", - "Text file busy", - "File too large", - "No space left on device", - "Illegal seek", - "Read-only file system", - "Too many links", - "Broken pipe", - "Math argument out of domain of func", - "Math result not representable", - "Resource deadlock would occur", - "File name too long", - "No record locks available", - "Function not implemented", - "Directory not empty", - "Too many symbolic links encountered", - "Operation would block", - "No message of desired type", - "Identifier removed", - "Channel number out of range", - "Level 2 not synchronized", - "Level 3 halted", - "Level 3 reset", - "Link number out of range", - "Protocol driver not attached", - "No CSI structure available", - "Level 2 halted", - "Invalid exchange", - "Invalid request descriptor", - "Exchange full", - "No anode", - "Invalid request code", - "Invalid slot", - "Resource deadlock would occur", - "Bad font file format", - "Device not a stream", - "No data available", - "Timer expired", - "Out of streams resources", - "Machine is not on the network", - "Package not installed", - "Object is remote", - "Link has been severed", - "Advertise error", - "Srmount error", - "Communication error on send", - "Protocol error", - "Multihop attempted", - "RFS specific error", - "Not a data message", - "Value too large for defined data type", - "Name not unique on network", - "File descriptor in bad state", - "Remote address changed", - "Can not access a needed shared library", - "Accessing a corrupted shared library", - ".lib section in a.out corrupted", - "Attempting to link in too many shared libraries", - "Cannot exec a shared library directly", - "Illegal byte sequence", - "Interrupted system call should be restarted", - "Streams pipe error", - "Too many users", - "Socket operation on non-socket", - "Destination address required", - "Message too long", - "Protocol wrong type for socket", - "Protocol not available", - "Protocol not supported", - "Socket type not supported", - "Operation not supported on transport endpoint", - "Protocol family not supported", - "Address family not supported by protocol", - "Address already in use", - "Cannot assign requested address", - "Network is down", - "Network is unreachable", - "Network dropped connection because of reset", - "Software caused connection abort", - "Connection reset by peer", - "No buffer space available", - "Transport endpoint is already connected", - "Transport endpoint is not connected", - "Cannot send after transport endpoint shutdown", - "Too many references: cannot splice", - "Connection timed out", - "Connection refused", - "Host is down", - "No route to host", - "Operation already in progress", - "Operation now in progress", - "Stale NFS file handle", - "Structure needs cleaning", - "Not a XENIX named type file", - "No XENIX semaphores available", - "Is a named type file", - "Remote I/O error", - "Quota exceeded", - "No medium found", - "Wrong medium type", - "Operation Canceled", - "Required key not available", - "Key has expired", - "Key has been revoked", - "Key was rejected by service", - "Owner died", - "State not recoverable"]; diff --git a/ctr-std/src/sys/redox/syscall/flag.rs b/ctr-std/src/sys/redox/syscall/flag.rs deleted file mode 100644 index 0f61b9f..0000000 --- a/ctr-std/src/sys/redox/syscall/flag.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub const CLONE_VM: usize = 0x100; -pub const CLONE_FS: usize = 0x200; -pub const CLONE_FILES: usize = 0x400; -pub const CLONE_SIGHAND: usize = 0x800; -pub const CLONE_VFORK: usize = 0x4000; -pub const CLONE_THREAD: usize = 0x10000; - -pub const CLOCK_REALTIME: usize = 1; -pub const CLOCK_MONOTONIC: usize = 4; - -pub const EVENT_NONE: usize = 0; -pub const EVENT_READ: usize = 1; -pub const EVENT_WRITE: usize = 2; - -pub const F_DUPFD: usize = 0; -pub const F_GETFD: usize = 1; -pub const F_SETFD: usize = 2; -pub const F_GETFL: usize = 3; -pub const F_SETFL: usize = 4; - -pub const FUTEX_WAIT: usize = 0; -pub const FUTEX_WAKE: usize = 1; -pub const FUTEX_REQUEUE: usize = 2; - -pub const MAP_WRITE: usize = 1; -pub const MAP_WRITE_COMBINE: usize = 2; - -pub const MODE_TYPE: u16 = 0xF000; -pub const MODE_DIR: u16 = 0x4000; -pub const MODE_FILE: u16 = 0x8000; -pub const MODE_SYMLINK: u16 = 0xA000; -pub const MODE_FIFO: u16 = 0x1000; -pub const MODE_CHR: u16 = 0x2000; - -pub const MODE_PERM: u16 = 0x0FFF; -pub const MODE_SETUID: u16 = 0o4000; -pub const MODE_SETGID: u16 = 0o2000; - -pub const O_RDONLY: usize = 0x0001_0000; -pub const O_WRONLY: usize = 0x0002_0000; -pub const O_RDWR: usize = 0x0003_0000; -pub const O_NONBLOCK: usize = 0x0004_0000; -pub const O_APPEND: usize = 0x0008_0000; -pub const O_SHLOCK: usize = 0x0010_0000; -pub const O_EXLOCK: usize = 0x0020_0000; -pub const O_ASYNC: usize = 0x0040_0000; -pub const O_FSYNC: usize = 0x0080_0000; -pub const O_CLOEXEC: usize = 0x0100_0000; -pub const O_CREAT: usize = 0x0200_0000; -pub const O_TRUNC: usize = 0x0400_0000; -pub const O_EXCL: usize = 0x0800_0000; -pub const O_DIRECTORY: usize = 0x1000_0000; -pub const O_STAT: usize = 0x2000_0000; -pub const O_SYMLINK: usize = 0x4000_0000; -pub const O_NOFOLLOW: usize = 0x8000_0000; -pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR; - -pub const SEEK_SET: usize = 0; -pub const SEEK_CUR: usize = 1; -pub const SEEK_END: usize = 2; - -pub const SIGHUP: usize = 1; -pub const SIGINT: usize = 2; -pub const SIGQUIT: usize = 3; -pub const SIGILL: usize = 4; -pub const SIGTRAP: usize = 5; -pub const SIGABRT: usize = 6; -pub const SIGBUS: usize = 7; -pub const SIGFPE: usize = 8; -pub const SIGKILL: usize = 9; -pub const SIGUSR1: usize = 10; -pub const SIGSEGV: usize = 11; -pub const SIGUSR2: usize = 12; -pub const SIGPIPE: usize = 13; -pub const SIGALRM: usize = 14; -pub const SIGTERM: usize = 15; -pub const SIGSTKFLT: usize= 16; -pub const SIGCHLD: usize = 17; -pub const SIGCONT: usize = 18; -pub const SIGSTOP: usize = 19; -pub const SIGTSTP: usize = 20; -pub const SIGTTIN: usize = 21; -pub const SIGTTOU: usize = 22; -pub const SIGURG: usize = 23; -pub const SIGXCPU: usize = 24; -pub const SIGXFSZ: usize = 25; -pub const SIGVTALRM: usize= 26; -pub const SIGPROF: usize = 27; -pub const SIGWINCH: usize = 28; -pub const SIGIO: usize = 29; -pub const SIGPWR: usize = 30; -pub const SIGSYS: usize = 31; - -pub const SIG_DFL: usize = 0; -pub const SIG_IGN: usize = 1; - -pub const SA_NOCLDSTOP: usize = 0x00000001; -pub const SA_NOCLDWAIT: usize = 0x00000002; -pub const SA_SIGINFO: usize = 0x00000004; -pub const SA_RESTORER: usize = 0x04000000; -pub const SA_ONSTACK: usize = 0x08000000; -pub const SA_RESTART: usize = 0x10000000; -pub const SA_NODEFER: usize = 0x40000000; -pub const SA_RESETHAND: usize = 0x80000000; - -pub const WNOHANG: usize = 1; diff --git a/ctr-std/src/sys/redox/syscall/mod.rs b/ctr-std/src/sys/redox/syscall/mod.rs deleted file mode 100644 index ce789c2..0000000 --- a/ctr-std/src/sys/redox/syscall/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::arch::*; -pub use self::call::*; -pub use self::data::*; -pub use self::error::*; -pub use self::flag::*; -pub use self::number::*; - -#[cfg(target_arch = "arm")] -#[path="arch/arm.rs"] -mod arch; - -#[cfg(target_arch = "x86")] -#[path="arch/x86.rs"] -mod arch; - -#[cfg(target_arch = "x86_64")] -#[path="arch/x86_64.rs"] -mod arch; - -/// Function definitions -pub mod call; - -/// Complex structures that are used for some system calls -pub mod data; - -/// All errors that can be generated by a system call -pub mod error; - -/// Flags used as an argument to many system calls -pub mod flag; - -/// Call numbers used by each system call -pub mod number; diff --git a/ctr-std/src/sys/redox/syscall/number.rs b/ctr-std/src/sys/redox/syscall/number.rs deleted file mode 100644 index 45cb40e..0000000 --- a/ctr-std/src/sys/redox/syscall/number.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub const SYS_CLASS: usize = 0xF000_0000; -pub const SYS_CLASS_PATH: usize=0x1000_0000; -pub const SYS_CLASS_FILE: usize=0x2000_0000; - -pub const SYS_ARG: usize = 0x0F00_0000; -pub const SYS_ARG_SLICE: usize =0x0100_0000; -pub const SYS_ARG_MSLICE: usize=0x0200_0000; -pub const SYS_ARG_PATH: usize = 0x0300_0000; - -pub const SYS_RET: usize = 0x00F0_0000; -pub const SYS_RET_FILE: usize = 0x0010_0000; - -pub const SYS_LINK: usize = SYS_CLASS_PATH | SYS_ARG_PATH | 9; -pub const SYS_OPEN: usize = SYS_CLASS_PATH | SYS_RET_FILE | 5; -pub const SYS_CHMOD: usize = SYS_CLASS_PATH | 15; -pub const SYS_RMDIR: usize = SYS_CLASS_PATH | 84; -pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10; - -pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6; -pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41; -pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63; -pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3; -pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4; -pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19; -pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94; -pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207; -pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55; -pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927; -pub const SYS_FMAP: usize = SYS_CLASS_FILE | 90; -pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 91; -pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928; -pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38; -pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28; -pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100; -pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118; -pub const SYS_FTRUNCATE: usize =SYS_CLASS_FILE | 93; -pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320; - -pub const SYS_BRK: usize = 45; -pub const SYS_CHDIR: usize = 12; -pub const SYS_CLOCK_GETTIME: usize = 265; -pub const SYS_CLONE: usize = 120; -pub const SYS_EXECVE: usize = 11; -pub const SYS_EXIT: usize = 1; -pub const SYS_FUTEX: usize = 240; -pub const SYS_GETCWD: usize = 183; -pub const SYS_GETEGID: usize = 202; -pub const SYS_GETENS: usize = 951; -pub const SYS_GETEUID: usize = 201; -pub const SYS_GETGID: usize = 200; -pub const SYS_GETNS: usize = 950; -pub const SYS_GETPID: usize = 20; -pub const SYS_GETPGID: usize = 132; -pub const SYS_GETPPID: usize = 64; -pub const SYS_GETUID: usize = 199; -pub const SYS_IOPL: usize = 110; -pub const SYS_KILL: usize = 37; -pub const SYS_MKNS: usize = 984; -pub const SYS_NANOSLEEP: usize =162; -pub const SYS_PHYSALLOC: usize =945; -pub const SYS_PHYSFREE: usize = 946; -pub const SYS_PHYSMAP: usize = 947; -pub const SYS_PHYSUNMAP: usize =948; -pub const SYS_VIRTTOPHYS: usize=949; -pub const SYS_PIPE2: usize = 331; -pub const SYS_SETPGID: usize = 57; -pub const SYS_SETREGID: usize = 204; -pub const SYS_SETRENS: usize = 952; -pub const SYS_SETREUID: usize = 203; -pub const SYS_SIGACTION: usize =67; -pub const SYS_SIGRETURN: usize =119; -pub const SYS_WAITPID: usize = 7; -pub const SYS_YIELD: usize = 158; diff --git a/ctr-std/src/sys/redox/thread.rs b/ctr-std/src/sys/redox/thread.rs deleted file mode 100644 index f417708..0000000 --- a/ctr-std/src/sys/redox/thread.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use boxed::FnBox; -use ffi::CStr; -use io; -use mem; -use sys_common::thread::start_thread; -use sys::{cvt, syscall}; -use time::Duration; - -pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; - -pub struct Thread { - id: usize, -} - -// Some platforms may have pthread_t as a pointer in which case we still want -// a thread to be Send/Sync -unsafe impl Send for Thread {} -unsafe impl Sync for Thread {} - -impl Thread { - pub unsafe fn new<'a>(_stack: usize, p: Box) -> io::Result { - let p = box p; - - let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?; - if id == 0 { - start_thread(&*p as *const _ as *mut _); - let _ = syscall::exit(0); - panic!("thread failed to exit"); - } else { - mem::forget(p); - Ok(Thread { id: id }) - } - } - - pub fn yield_now() { - let ret = syscall::sched_yield().expect("failed to sched_yield"); - debug_assert_eq!(ret, 0); - } - - pub fn set_name(_name: &CStr) { - - } - - pub fn sleep(dur: Duration) { - let mut secs = dur.as_secs(); - let mut nsecs = dur.subsec_nanos() as i32; - - // If we're awoken with a signal then the return value will be -1 and - // nanosleep will fill in `ts` with the remaining time. - while secs > 0 || nsecs > 0 { - let req = syscall::TimeSpec { - tv_sec: secs as i64, - tv_nsec: nsecs, - }; - secs -= req.tv_sec as u64; - let mut rem = syscall::TimeSpec::default(); - if syscall::nanosleep(&req, &mut rem).is_err() { - secs += rem.tv_sec as u64; - nsecs = rem.tv_nsec; - } else { - nsecs = 0; - } - } - } - - pub fn join(self) { - let mut status = 0; - syscall::waitpid(self.id, &mut status, 0).unwrap(); - } - - pub fn id(&self) -> usize { self.id } - - pub fn into_id(self) -> usize { - let id = self.id; - mem::forget(self); - id - } -} - -pub mod guard { - pub type Guard = !; - pub unsafe fn current() -> Option { None } - pub unsafe fn init() -> Option { None } - pub unsafe fn deinit() {} -} diff --git a/ctr-std/src/sys/redox/thread_local.rs b/ctr-std/src/sys/redox/thread_local.rs deleted file mode 100644 index cacd84e..0000000 --- a/ctr-std/src/sys/redox/thread_local.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] // not used on all platforms - -use collections::BTreeMap; -use ptr; -use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - -pub type Key = usize; - -type Dtor = unsafe extern fn(*mut u8); - -static NEXT_KEY: AtomicUsize = ATOMIC_USIZE_INIT; - -static mut KEYS: *mut BTreeMap> = ptr::null_mut(); - -#[thread_local] -static mut LOCALS: *mut BTreeMap = ptr::null_mut(); - -unsafe fn keys() -> &'static mut BTreeMap> { - if KEYS == ptr::null_mut() { - KEYS = Box::into_raw(Box::new(BTreeMap::new())); - } - &mut *KEYS -} - -unsafe fn locals() -> &'static mut BTreeMap { - if LOCALS == ptr::null_mut() { - LOCALS = Box::into_raw(Box::new(BTreeMap::new())); - } - &mut *LOCALS -} - -#[inline] -pub unsafe fn create(dtor: Option) -> Key { - let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst); - keys().insert(key, dtor); - key -} - -#[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - if let Some(&entry) = locals().get(&key) { - entry - } else { - ptr::null_mut() - } -} - -#[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - locals().insert(key, value); -} - -#[inline] -pub unsafe fn destroy(key: Key) { - keys().remove(&key); -} - -#[inline] -pub fn requires_synchronized_create() -> bool { - false -} diff --git a/ctr-std/src/sys/redox/time.rs b/ctr-std/src/sys/redox/time.rs deleted file mode 100644 index 5c49111..0000000 --- a/ctr-std/src/sys/redox/time.rs +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cmp::Ordering; -use fmt; -use sys::{cvt, syscall}; -use time::Duration; -use convert::TryInto; -use core::hash::{Hash, Hasher}; - -const NSEC_PER_SEC: u64 = 1_000_000_000; - -#[derive(Copy, Clone)] -struct Timespec { - t: syscall::TimeSpec, -} - -impl Timespec { - fn sub_timespec(&self, other: &Timespec) -> Result { - if self >= other { - Ok(if self.t.tv_nsec >= other.t.tv_nsec { - Duration::new((self.t.tv_sec - other.t.tv_sec) as u64, - (self.t.tv_nsec - other.t.tv_nsec) as u32) - } else { - Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64, - self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - - other.t.tv_nsec as u32) - }) - } else { - match other.sub_timespec(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } - } - - fn add_duration(&self, other: &Duration) -> Timespec { - let mut secs = other - .as_secs() - .try_into() // <- target type would be `i64` - .ok() - .and_then(|secs| self.t.tv_sec.checked_add(secs)) - .expect("overflow when adding duration to time"); - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; - if nsec >= NSEC_PER_SEC as u32 { - nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1).expect("overflow when adding \ - duration to time"); - } - Timespec { - t: syscall::TimeSpec { - tv_sec: secs, - tv_nsec: nsec as i32, - }, - } - } - - fn sub_duration(&self, other: &Duration) -> Timespec { - let mut secs = other - .as_secs() - .try_into() // <- target type would be `i64` - .ok() - .and_then(|secs| self.t.tv_sec.checked_sub(secs)) - .expect("overflow when subtracting duration from time"); - - // Similar to above, nanos can't overflow. - let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; - if nsec < 0 { - nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1).expect("overflow when subtracting \ - duration from time"); - } - Timespec { - t: syscall::TimeSpec { - tv_sec: secs, - tv_nsec: nsec as i32, - }, - } - } -} - -impl PartialEq for Timespec { - fn eq(&self, other: &Timespec) -> bool { - self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec - } -} - -impl Eq for Timespec {} - -impl PartialOrd for Timespec { - fn partial_cmp(&self, other: &Timespec) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Timespec { - fn cmp(&self, other: &Timespec) -> Ordering { - let me = (self.t.tv_sec, self.t.tv_nsec); - let other = (other.t.tv_sec, other.t.tv_nsec); - me.cmp(&other) - } -} - -impl Hash for Timespec { - fn hash(&self, state: &mut H) { - self.t.tv_sec.hash(state); - self.t.tv_nsec.hash(state); - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Instant { - t: Timespec, -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SystemTime { - t: Timespec, -} - -pub const UNIX_EPOCH: SystemTime = SystemTime { - t: Timespec { - t: syscall::TimeSpec { - tv_sec: 0, - tv_nsec: 0, - }, - }, -}; - -impl Instant { - pub fn now() -> Instant { - Instant { t: now(syscall::CLOCK_MONOTONIC) } - } - - pub fn sub_instant(&self, other: &Instant) -> Duration { - self.t.sub_timespec(&other.t).unwrap_or_else(|_| { - panic!("specified instant was later than self") - }) - } - - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant { t: self.t.add_duration(other) } - } - - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant { t: self.t.sub_duration(other) } - } -} - -impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Instant") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } -} - -impl SystemTime { - pub fn now() -> SystemTime { - SystemTime { t: now(syscall::CLOCK_REALTIME) } - } - - pub fn sub_time(&self, other: &SystemTime) - -> Result { - self.t.sub_timespec(&other.t) - } - - pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime { t: self.t.add_duration(other) } - } - - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - SystemTime { t: self.t.sub_duration(other) } - } -} - -impl From for SystemTime { - fn from(t: syscall::TimeSpec) -> SystemTime { - SystemTime { t: Timespec { t: t } } - } -} - -impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SystemTime") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } -} - -pub type clock_t = usize; - -fn now(clock: clock_t) -> Timespec { - let mut t = Timespec { - t: syscall::TimeSpec { - tv_sec: 0, - tv_nsec: 0, - } - }; - cvt(syscall::clock_gettime(clock, &mut t.t)).unwrap(); - t -} diff --git a/ctr-std/src/sys/unix/android.rs b/ctr-std/src/sys/unix/android.rs deleted file mode 100644 index 1043672..0000000 --- a/ctr-std/src/sys/unix/android.rs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Android ABI-compatibility module -//! -//! The ABI of Android has changed quite a bit over time, and libstd attempts to -//! be both forwards and backwards compatible as much as possible. We want to -//! always work with the most recent version of Android, but we also want to -//! work with older versions of Android for whenever projects need to. -//! -//! Our current minimum supported Android version is `android-9`, e.g. Android -//! with API level 9. We then in theory want to work on that and all future -//! versions of Android! -//! -//! Some of the detection here is done at runtime via `dlopen` and -//! introspection. Other times no detection is performed at all and we just -//! provide a fallback implementation as some versions of Android we support -//! don't have the function. -//! -//! You'll find more details below about why each compatibility shim is needed. - -#![cfg(target_os = "android")] - -use libc::{c_int, c_void, sighandler_t, size_t, ssize_t}; -use libc::{ftruncate, pread, pwrite}; - -use io; -use super::{cvt, cvt_r}; - -// The `log2` and `log2f` functions apparently appeared in android-18, or at -// least you can see they're not present in the android-17 header [1] and they -// are present in android-18 [2]. -// -// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms -// /android-17/arch-arm/usr/include/math.h -// [2]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms -// /android-18/arch-arm/usr/include/math.h -// -// Note that these shims are likely less precise than directly calling `log2`, -// but hopefully that should be enough for now... -// -// Note that mathematically, for any arbitrary `y`: -// -// log_2(x) = log_y(x) / log_y(2) -// = log_y(x) / (1 / log_2(y)) -// = log_y(x) * log_2(y) -// -// Hence because `ln` (log_e) is available on all Android we just choose `y = e` -// and get: -// -// log_2(x) = ln(x) * log_2(e) - -#[cfg(not(test))] -pub fn log2f32(f: f32) -> f32 { - f.ln() * ::f32::consts::LOG2_E -} - -#[cfg(not(test))] -pub fn log2f64(f: f64) -> f64 { - f.ln() * ::f64::consts::LOG2_E -} - -// Back in the day [1] the `signal` function was just an inline wrapper -// around `bsd_signal`, but starting in API level android-20 the `signal` -// symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was -// removed [3]. -// -// Basically this means that if we want to be binary compatible with multiple -// Android releases (oldest being 9 and newest being 21) then we need to check -// for both symbols and not actually link against either. -// -// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms -// /android-18/arch-arm/usr/include/signal.h -// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental -// /platforms/android-20/arch-arm -// /usr/include/signal.h -// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms -// /android-21/arch-arm/usr/include/signal.h -pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t { - weak!(fn signal(c_int, sighandler_t) -> sighandler_t); - weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t); - - let f = signal.get().or_else(|| bsd_signal.get()); - let f = f.expect("neither `signal` nor `bsd_signal` symbols found"); - f(signum, handler) -} - -// The `ftruncate64` symbol apparently appeared in android-12, so we do some -// dynamic detection to see if we can figure out whether `ftruncate64` exists. -// -// If it doesn't we just fall back to `ftruncate`, generating an error for -// too-large values. -#[cfg(target_pointer_width = "32")] -pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { - weak!(fn ftruncate64(c_int, i64) -> c_int); - - unsafe { - match ftruncate64.get() { - Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()), - None => { - if size > i32::max_value() as u64 { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot truncate >2GB")) - } else { - cvt_r(|| ftruncate(fd, size as i32)).map(|_| ()) - } - } - } - } -} - -#[cfg(target_pointer_width = "64")] -pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { - unsafe { - cvt_r(|| ftruncate(fd, size as i64)).map(|_| ()) - } -} - -#[cfg(target_pointer_width = "32")] -pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64) - -> io::Result -{ - use convert::TryInto; - weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t); - pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| { - if let Ok(o) = offset.try_into() { - cvt(pread(fd, buf, count, o)) - } else { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot pread >2GB")) - } - }) -} - -#[cfg(target_pointer_width = "32")] -pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64) - -> io::Result -{ - use convert::TryInto; - weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t); - pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| { - if let Ok(o) = offset.try_into() { - cvt(pwrite(fd, buf, count, o)) - } else { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot pwrite >2GB")) - } - }) -} - -#[cfg(target_pointer_width = "64")] -pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64) - -> io::Result -{ - cvt(pread(fd, buf, count, offset)) -} - -#[cfg(target_pointer_width = "64")] -pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64) - -> io::Result -{ - cvt(pwrite(fd, buf, count, offset)) -} diff --git a/ctr-std/src/sys/unix/args.rs b/ctr-std/src/sys/unix/args.rs deleted file mode 100644 index c3c033d..0000000 --- a/ctr-std/src/sys/unix/args.rs +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Global initialization and retrieval of command line arguments. -//! -//! On some platforms these are stored during runtime startup, -//! and on some they are retrieved from the system on demand. - -#![allow(dead_code)] // runtime init functions not used during testing - -use ffi::OsString; -use marker::PhantomData; -use vec; - -/// One-time global initialization. -pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } - -/// One-time global cleanup. -pub unsafe fn cleanup() { imp::cleanup() } - -/// Returns the command line arguments -pub fn args() -> Args { - imp::args() -} - -pub struct Args { - iter: vec::IntoIter, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Args { - pub fn inner_debug(&self) -> &[OsString] { - self.iter.as_slice() - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { self.iter.next() } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { self.iter.len() } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { self.iter.next_back() } -} - -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_os = "emscripten", - target_os = "haiku", - target_os = "l4re", - target_os = "fuchsia", - target_os = "hermit"))] -mod imp { - use os::unix::prelude::*; - use ptr; - use ffi::{CStr, OsString}; - use marker::PhantomData; - use libc; - use super::Args; - - use sys_common::mutex::Mutex; - - static mut ARGC: isize = 0; - static mut ARGV: *const *const u8 = ptr::null(); - // We never call `ENV_LOCK.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static LOCK: Mutex = Mutex::new(); - - pub unsafe fn init(argc: isize, argv: *const *const u8) { - let _guard = LOCK.lock(); - ARGC = argc; - ARGV = argv; - } - - pub unsafe fn cleanup() { - let _guard = LOCK.lock(); - ARGC = 0; - ARGV = ptr::null(); - } - - pub fn args() -> Args { - Args { - iter: clone().into_iter(), - _dont_send_or_sync_me: PhantomData - } - } - - fn clone() -> Vec { - unsafe { - let _guard = LOCK.lock(); - (0..ARGC).map(|i| { - let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char); - OsStringExt::from_vec(cstr.to_bytes().to_vec()) - }).collect() - } - } -} - -#[cfg(any(target_os = "macos", - target_os = "ios"))] -mod imp { - use ffi::CStr; - use marker::PhantomData; - use libc; - use super::Args; - - pub unsafe fn init(_argc: isize, _argv: *const *const u8) { - } - - pub fn cleanup() { - } - - #[cfg(target_os = "macos")] - pub fn args() -> Args { - use os::unix::prelude::*; - extern { - // These functions are in crt_externs.h. - fn _NSGetArgc() -> *mut libc::c_int; - fn _NSGetArgv() -> *mut *mut *mut libc::c_char; - } - - let vec = unsafe { - let (argc, argv) = (*_NSGetArgc() as isize, - *_NSGetArgv() as *const *const libc::c_char); - (0.. argc as isize).map(|i| { - let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec(); - OsStringExt::from_vec(bytes) - }).collect::>() - }; - Args { - iter: vec.into_iter(), - _dont_send_or_sync_me: PhantomData, - } - } - - // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs - // and use underscores in their names - they're most probably - // are considered private and therefore should be avoided - // Here is another way to get arguments using Objective C - // runtime - // - // In general it looks like: - // res = Vec::new() - // let args = [[NSProcessInfo processInfo] arguments] - // for i in (0..[args count]) - // res.push([args objectAtIndex:i]) - // res - #[cfg(target_os = "ios")] - pub fn args() -> Args { - use ffi::OsString; - use mem; - use str; - - extern { - fn sel_registerName(name: *const libc::c_uchar) -> Sel; - fn objc_getClass(class_name: *const libc::c_uchar) -> NsId; - } - - #[cfg(target_arch="aarch64")] - extern { - fn objc_msgSend(obj: NsId, sel: Sel) -> NsId; - #[link_name="objc_msgSend"] - fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId; - } - - #[cfg(not(target_arch="aarch64"))] - extern { - fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; - #[link_name="objc_msgSend"] - fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId; - } - - type Sel = *const libc::c_void; - type NsId = *const libc::c_void; - - let mut res = Vec::new(); - - unsafe { - let process_info_sel = sel_registerName("processInfo\0".as_ptr()); - let arguments_sel = sel_registerName("arguments\0".as_ptr()); - let utf8_sel = sel_registerName("UTF8String\0".as_ptr()); - let count_sel = sel_registerName("count\0".as_ptr()); - let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr()); - - let klass = objc_getClass("NSProcessInfo\0".as_ptr()); - let info = objc_msgSend(klass, process_info_sel); - let args = objc_msgSend(info, arguments_sel); - - let cnt: usize = mem::transmute(objc_msgSend(args, count_sel)); - for i in 0..cnt { - let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong); - let utf_c_str: *const libc::c_char = - mem::transmute(objc_msgSend(tmp, utf8_sel)); - let bytes = CStr::from_ptr(utf_c_str).to_bytes(); - res.push(OsString::from(str::from_utf8(bytes).unwrap())) - } - } - - Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData } - } -} diff --git a/ctr-std/src/sys/unix/backtrace/mod.rs b/ctr-std/src/sys/unix/backtrace/mod.rs deleted file mode 100644 index b5bf20c..0000000 --- a/ctr-std/src/sys/unix/backtrace/mod.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Backtrace support built on libgcc with some extra OS-specific support -/// -/// Some methods of getting a backtrace: -/// -/// * The backtrace() functions on unix. It turns out this doesn't work very -/// well for green threads on macOS, and the address to symbol portion of it -/// suffers problems that are described below. -/// -/// * Using libunwind. This is more difficult than it sounds because libunwind -/// isn't installed everywhere by default. It's also a bit of a hefty library, -/// so possibly not the best option. When testing, libunwind was excellent at -/// getting both accurate backtraces and accurate symbols across platforms. -/// This route was not chosen in favor of the next option, however. -/// -/// * We're already using libgcc_s for exceptions in rust (triggering thread -/// unwinding and running destructors on the stack), and it turns out that it -/// conveniently comes with a function that also gives us a backtrace. All of -/// these functions look like _Unwind_*, but it's not quite the full -/// repertoire of the libunwind API. Due to it already being in use, this was -/// the chosen route of getting a backtrace. -/// -/// After choosing libgcc_s for backtraces, the sad part is that it will only -/// give us a stack trace of instruction pointers. Thankfully these instruction -/// pointers are accurate (they work for green and native threads), but it's -/// then up to us again to figure out how to translate these addresses to -/// symbols. As with before, we have a few options. Before, that, a little bit -/// of an interlude about symbols. This is my very limited knowledge about -/// symbol tables, and this information is likely slightly wrong, but the -/// general idea should be correct. -/// -/// When talking about symbols, it's helpful to know a few things about where -/// symbols are located. Some symbols are located in the dynamic symbol table -/// of the executable which in theory means that they're available for dynamic -/// linking and lookup. Other symbols end up only in the local symbol table of -/// the file. This loosely corresponds to pub and priv functions in Rust. -/// -/// Armed with this knowledge, we know that our solution for address to symbol -/// translation will need to consult both the local and dynamic symbol tables. -/// With that in mind, here's our options of translating an address to -/// a symbol. -/// -/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() -/// behind the scenes to translate, and this is why backtrace() was not used. -/// Conveniently, this method works fantastically on macOS. It appears dladdr() -/// uses magic to consult the local symbol table, or we're putting everything -/// in the dynamic symbol table anyway. Regardless, for macOS, this is the -/// method used for translation. It's provided by the system and easy to do.o -/// -/// Sadly, all other systems have a dladdr() implementation that does not -/// consult the local symbol table. This means that most functions are blank -/// because they don't have symbols. This means that we need another solution. -/// -/// * Use unw_get_proc_name(). This is part of the libunwind api (not the -/// libgcc_s version of the libunwind api), but involves taking a dependency -/// to libunwind. We may pursue this route in the future if we bundle -/// libunwind, but libunwind was unwieldy enough that it was not chosen at -/// this time to provide this functionality. -/// -/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a -/// semi-reasonable solution. The stdlib already knows how to spawn processes, -/// so in theory it could invoke readelf, parse the output, and consult the -/// local/dynamic symbol tables from there. This ended up not getting chosen -/// due to the craziness of the idea plus the advent of the next option. -/// -/// * Use `libbacktrace`. It turns out that this is a small library bundled in -/// the gcc repository which provides backtrace and symbol translation -/// functionality. All we really need from it is the backtrace functionality, -/// and we only really need this on everything that's not macOS, so this is the -/// chosen route for now. -/// -/// In summary, the current situation uses libgcc_s to get a trace of stack -/// pointers, and we use dladdr() or libbacktrace to translate these addresses -/// to symbols. This is a bit of a hokey implementation as-is, but it works for -/// all unix platforms we support right now, so it at least gets the job done. - -pub use self::tracing::unwind_backtrace; -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; - -// tracing impls: -mod tracing; -// symbol resolvers: -mod printing; - -#[cfg(not(target_os = "emscripten"))] -pub mod gnu { - use io; - use fs; - use libc::c_char; - - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - use env; - use os::unix::ffi::OsStrExt; - - let filename = env::current_exe()?; - let file = fs::File::open(&filename)?; - let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter() - .map(|&x| x as c_char).collect(); - filename_cstr.push(0); // Null terminate - Ok((filename_cstr, file)) - } -} - -pub struct BacktraceContext; diff --git a/ctr-std/src/sys/unix/backtrace/printing/dladdr.rs b/ctr-std/src/sys/unix/backtrace/printing/dladdr.rs deleted file mode 100644 index bc56fd6..0000000 --- a/ctr-std/src/sys/unix/backtrace/printing/dladdr.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use intrinsics; -use ffi::CStr; -use libc; -use sys::backtrace::BacktraceContext; -use sys_common::backtrace::Frame; - -pub fn resolve_symname(frame: Frame, - callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - unsafe { - let mut info: Dl_info = intrinsics::init(); - let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 || - info.dli_sname.is_null() { - None - } else { - CStr::from_ptr(info.dli_sname).to_str().ok() - }; - callback(symname) - } -} - -#[repr(C)] -struct Dl_info { - dli_fname: *const libc::c_char, - dli_fbase: *mut libc::c_void, - dli_sname: *const libc::c_char, - dli_saddr: *mut libc::c_void, -} - -extern { - fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; -} diff --git a/ctr-std/src/sys/unix/backtrace/printing/mod.rs b/ctr-std/src/sys/unix/backtrace/printing/mod.rs deleted file mode 100644 index caa6071..0000000 --- a/ctr-std/src/sys/unix/backtrace/printing/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2014-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -mod dladdr; - -use sys::backtrace::BacktraceContext; -use sys_common::backtrace::Frame; -use io; - -#[cfg(target_os = "emscripten")] -pub use self::dladdr::resolve_symname; - -#[cfg(target_os = "emscripten")] -pub fn foreach_symbol_fileline(_: Frame, _: F, _: &BacktraceContext) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()> -{ - Ok(false) -} - -#[cfg(not(target_os = "emscripten"))] -pub use sys_common::gnu::libbacktrace::foreach_symbol_fileline; - -#[cfg(not(target_os = "emscripten"))] -pub fn resolve_symname(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()> -{ - ::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| { - if symname.is_some() { - callback(symname) - } else { - dladdr::resolve_symname(frame, callback, bc) - } - }, bc) -} diff --git a/ctr-std/src/sys/unix/backtrace/tracing/backtrace_fn.rs b/ctr-std/src/sys/unix/backtrace/tracing/backtrace_fn.rs deleted file mode 100644 index 6293eeb..0000000 --- a/ctr-std/src/sys/unix/backtrace/tracing/backtrace_fn.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// As always - iOS on arm uses SjLj exceptions and -/// _Unwind_Backtrace is even not available there. Still, -/// backtraces could be extracted using a backtrace function, -/// which thanks god is public -/// -/// As mentioned in a huge comment block in `super::super`, backtrace -/// doesn't play well with green threads, so while it is extremely nice and -/// simple to use it should be used only on iOS devices as the only viable -/// option. - -use io; -use libc; -use sys::backtrace::BacktraceContext; -use sys_common::backtrace::Frame; - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - const FRAME_LEN: usize = 100; - assert!(FRAME_LEN >= frames.len()); - let mut raw_frames = [::ptr::null_mut(); FRAME_LEN]; - let nb_frames = unsafe { - backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int) - } as usize; - for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) { - *to = Frame { - exact_position: *from as *mut u8, - symbol_addr: *from as *mut u8, - inline_context: 0, - }; - } - Ok((nb_frames as usize, BacktraceContext)) -} - -extern { - fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int; -} diff --git a/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs b/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs deleted file mode 100644 index 6e84156..0000000 --- a/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use error::Error; -use io; -use libc; -use sys::backtrace::BacktraceContext; -use sys_common::backtrace::Frame; - -use unwind as uw; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl ::fmt::Display for UnwindError { - fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - let mut cx = Context { - idx: 0, - frames, - }; - let result_unwind = unsafe { - uw::_Unwind_Backtrace(trace_fn, - &mut cx as *mut Context - as *mut libc::c_void) - }; - // See libunwind:src/unwind/Backtrace.c for the return values. - // No, there is no doc. - match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => { - Err(io::Error::new(io::ErrorKind::Other, - UnwindError(result_unwind))) - } - } -} - -extern fn trace_fn(ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { - let cx = unsafe { &mut *(arg as *mut Context) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - let mut ip_before_insn = 0; - let mut ip = unsafe { - uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void - }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; - } - - // dladdr() on osx gets whiny when we use FindEnclosingFunction, and - // it appears to work fine without it, so we only use - // FindEnclosingFunction on non-osx platforms. In doing so, we get a - // slightly more accurate stack trace in the process. - // - // This is often because panic involves the last instruction of a - // function being "call std::rt::begin_unwind", with no ret - // instructions after it. This means that the return instruction - // pointer points *outside* of the calling function, and by - // unwinding it we go back to the original function. - let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { - ip - } else { - unsafe { uw::_Unwind_FindEnclosingFunction(ip) } - }; - - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} diff --git a/ctr-std/src/sys/unix/backtrace/tracing/mod.rs b/ctr-std/src/sys/unix/backtrace/tracing/mod.rs deleted file mode 100644 index c9c8e26..0000000 --- a/ctr-std/src/sys/unix/backtrace/tracing/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::imp::*; - -#[cfg(not(all(target_os = "ios", target_arch = "arm")))] -#[path = "gcc_s.rs"] -mod imp; -#[cfg(all(target_os = "ios", target_arch = "arm"))] -#[path = "backtrace_fn.rs"] -mod imp; diff --git a/ctr-std/src/sys/unix/cmath.rs b/ctr-std/src/sys/unix/cmath.rs deleted file mode 100644 index 2bc9665..0000000 --- a/ctr-std/src/sys/unix/cmath.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg(not(test))] - -use libc::{c_float, c_double}; - -#[link_name = "m"] -extern { - pub fn acos(n: c_double) -> c_double; - pub fn acosf(n: c_float) -> c_float; - pub fn asin(n: c_double) -> c_double; - pub fn asinf(n: c_float) -> c_float; - pub fn atan(n: c_double) -> c_double; - pub fn atan2(a: c_double, b: c_double) -> c_double; - pub fn atan2f(a: c_float, b: c_float) -> c_float; - pub fn atanf(n: c_float) -> c_float; - pub fn cbrt(n: c_double) -> c_double; - pub fn cbrtf(n: c_float) -> c_float; - pub fn cosh(n: c_double) -> c_double; - pub fn coshf(n: c_float) -> c_float; - pub fn expm1(n: c_double) -> c_double; - pub fn expm1f(n: c_float) -> c_float; - pub fn fdim(a: c_double, b: c_double) -> c_double; - pub fn fdimf(a: c_float, b: c_float) -> c_float; - pub fn hypot(x: c_double, y: c_double) -> c_double; - pub fn hypotf(x: c_float, y: c_float) -> c_float; - pub fn log1p(n: c_double) -> c_double; - pub fn log1pf(n: c_float) -> c_float; - pub fn sinh(n: c_double) -> c_double; - pub fn sinhf(n: c_float) -> c_float; - pub fn tan(n: c_double) -> c_double; - pub fn tanf(n: c_float) -> c_float; - pub fn tanh(n: c_double) -> c_double; - pub fn tanhf(n: c_float) -> c_float; -} diff --git a/ctr-std/src/sys/unix/condvar.rs b/ctr-std/src/sys/unix/condvar.rs deleted file mode 100644 index 2007da7..0000000 --- a/ctr-std/src/sys/unix/condvar.rs +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use libc; -use sys::mutex::{self, Mutex}; -use time::Duration; - -pub struct Condvar { inner: UnsafeCell } - -unsafe impl Send for Condvar {} -unsafe impl Sync for Condvar {} - -const TIMESPEC_MAX: libc::timespec = libc::timespec { - tv_sec: ::max_value(), - tv_nsec: 1_000_000_000 - 1, -}; - -fn saturating_cast_to_time_t(value: u64) -> libc::time_t { - if value > ::max_value() as u64 { - ::max_value() - } else { - value as libc::time_t - } -} - -impl Condvar { - pub const fn new() -> Condvar { - // Might be moved and address is changing it is better to avoid - // initialization of potentially opaque OS data before it landed - Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) } - } - - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "l4re", - target_os = "android", - target_os = "hermit"))] - pub unsafe fn init(&mut self) {} - - #[cfg(not(any(target_os = "macos", - target_os = "ios", - target_os = "l4re", - target_os = "android", - target_os = "hermit")))] - pub unsafe fn init(&mut self) { - use mem; - let mut attr: libc::pthread_condattr_t = mem::uninitialized(); - let r = libc::pthread_condattr_init(&mut attr); - assert_eq!(r, 0); - let r = libc::pthread_condattr_setclock(&mut attr, libc::CLOCK_MONOTONIC); - assert_eq!(r, 0); - let r = libc::pthread_cond_init(self.inner.get(), &attr); - assert_eq!(r, 0); - let r = libc::pthread_condattr_destroy(&mut attr); - assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn notify_one(&self) { - let r = libc::pthread_cond_signal(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn notify_all(&self) { - let r = libc::pthread_cond_broadcast(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { - let r = libc::pthread_cond_wait(self.inner.get(), mutex::raw(mutex)); - debug_assert_eq!(r, 0); - } - - // This implementation is used on systems that support pthread_condattr_setclock - // where we configure condition variable to use monotonic clock (instead of - // default system clock). This approach avoids all problems that result - // from changes made to the system time. - #[cfg(not(any(target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "hermit")))] - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - use mem; - - let mut now: libc::timespec = mem::zeroed(); - let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now); - assert_eq!(r, 0); - - // Nanosecond calculations can't overflow because both values are below 1e9. - let nsec = dur.subsec_nanos() + now.tv_nsec as u32; - - let sec = saturating_cast_to_time_t(dur.as_secs()) - .checked_add((nsec / 1_000_000_000) as libc::time_t) - .and_then(|s| s.checked_add(now.tv_sec)); - let nsec = nsec % 1_000_000_000; - - let timeout = sec.map(|s| { - libc::timespec { tv_sec: s, tv_nsec: nsec as _} - }).unwrap_or(TIMESPEC_MAX); - - let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), - &timeout); - assert!(r == libc::ETIMEDOUT || r == 0); - r == 0 - } - - - // This implementation is modeled after libcxx's condition_variable - // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 - // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android", target_os = "hermit"))] - pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool { - use ptr; - use time::Instant; - - // 1000 years - let max_dur = Duration::from_secs(1000 * 365 * 86400); - - if dur > max_dur { - // OSX implementation of `pthread_cond_timedwait` is buggy - // with super long durations. When duration is greater than - // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait` - // in macOS Sierra return error 316. - // - // This program demonstrates the issue: - // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c - // - // To work around this issue, and possible bugs of other OSes, timeout - // is clamped to 1000 years, which is allowable per the API of `wait_timeout` - // because of spurious wakeups. - - dur = max_dur; - } - - // First, figure out what time it currently is, in both system and - // stable time. pthread_cond_timedwait uses system time, but we want to - // report timeout based on stable time. - let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 }; - let stable_now = Instant::now(); - let r = libc::gettimeofday(&mut sys_now, ptr::null_mut()); - debug_assert_eq!(r, 0); - - let nsec = dur.subsec_nanos() as libc::c_long + - (sys_now.tv_usec * 1000) as libc::c_long; - let extra = (nsec / 1_000_000_000) as libc::time_t; - let nsec = nsec % 1_000_000_000; - let seconds = saturating_cast_to_time_t(dur.as_secs()); - - let timeout = sys_now.tv_sec.checked_add(extra).and_then(|s| { - s.checked_add(seconds) - }).map(|s| { - libc::timespec { tv_sec: s, tv_nsec: nsec } - }).unwrap_or(TIMESPEC_MAX); - - // And wait! - let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), - &timeout); - debug_assert!(r == libc::ETIMEDOUT || r == 0); - - // ETIMEDOUT is not a totally reliable method of determining timeout due - // to clock shifts, so do the check ourselves - stable_now.elapsed() < dur - } - - #[inline] - #[cfg(not(target_os = "dragonfly"))] - pub unsafe fn destroy(&self) { - let r = libc::pthread_cond_destroy(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - #[cfg(target_os = "dragonfly")] - pub unsafe fn destroy(&self) { - let r = libc::pthread_cond_destroy(self.inner.get()); - // On DragonFly pthread_cond_destroy() returns EINVAL if called on - // a condvar that was just initialized with - // libc::PTHREAD_COND_INITIALIZER. Once it is used or - // pthread_cond_init() is called, this behaviour no longer occurs. - debug_assert!(r == 0 || r == libc::EINVAL); - } -} diff --git a/ctr-std/src/sys/unix/env.rs b/ctr-std/src/sys/unix/env.rs deleted file mode 100644 index ad116c5..0000000 --- a/ctr-std/src/sys/unix/env.rs +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[cfg(target_os = "linux")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "linux"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "macos")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "macos"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".dylib"; - pub const DLL_EXTENSION: &'static str = "dylib"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "ios")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "ios"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".dylib"; - pub const DLL_EXTENSION: &'static str = "dylib"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "freebsd")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "freebsd"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "dragonfly")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "dragonfly"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "bitrig")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "bitrig"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "netbsd")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "netbsd"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "openbsd")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "openbsd"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "android")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "android"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "solaris")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "solaris"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "haiku")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "haiku"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "emscripten"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ".js"; - pub const EXE_EXTENSION: &'static str = "js"; -} - -#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "emscripten"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ".js"; - pub const EXE_EXTENSION: &'static str = "js"; -} - -#[cfg(target_os = "fuchsia")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "fuchsia"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "l4re")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "l4re"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "hermit")] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "hermit"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} diff --git a/ctr-std/src/sys/unix/ext/ffi.rs b/ctr-std/src/sys/unix/ext/ffi.rs deleted file mode 100644 index 8347145..0000000 --- a/ctr-std/src/sys/unix/ext/ffi.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific extension to the primitives in the `std::ffi` module - -#![stable(feature = "rust1", since = "1.0.0")] - -use ffi::{OsStr, OsString}; -use mem; -use sys::os_str::Buf; -use sys_common::{FromInner, IntoInner, AsInner}; - -/// Unix-specific extensions to [`OsString`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStringExt { - /// Creates an [`OsString`] from a byte vector. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// use std::os::unix::ffi::OsStringExt; - /// - /// let bytes = b"foo".to_vec(); - /// let os_string = OsString::from_vec(bytes); - /// assert_eq!(os_string.to_str(), Some("foo")); - /// ``` - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html - #[stable(feature = "rust1", since = "1.0.0")] - fn from_vec(vec: Vec) -> Self; - - /// Yields the underlying byte vector of this [`OsString`]. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// use std::os::unix::ffi::OsStringExt; - /// - /// let mut os_string = OsString::new(); - /// os_string.push("foo"); - /// let bytes = os_string.into_vec(); - /// assert_eq!(bytes, b"foo"); - /// ``` - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html - #[stable(feature = "rust1", since = "1.0.0")] - fn into_vec(self) -> Vec; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStringExt for OsString { - fn from_vec(vec: Vec) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec { - self.into_inner().inner - } -} - -/// Unix-specific extensions to [`OsStr`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStrExt { - #[stable(feature = "rust1", since = "1.0.0")] - /// Creates an [`OsStr`] from a byte slice. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// use std::os::unix::ffi::OsStrExt; - /// - /// let bytes = b"foo"; - /// let os_str = OsStr::from_bytes(bytes); - /// assert_eq!(os_str.to_str(), Some("foo")); - /// ``` - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html - fn from_bytes(slice: &[u8]) -> &Self; - - /// Gets the underlying byte view of the [`OsStr`] slice. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// use std::os::unix::ffi::OsStrExt; - /// - /// let mut os_str = OsStr::new("foo"); - /// let bytes = os_str.as_bytes(); - /// assert_eq!(bytes, b"foo"); - /// ``` - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html - #[stable(feature = "rust1", since = "1.0.0")] - fn as_bytes(&self) -> &[u8]; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } -} diff --git a/ctr-std/src/sys/unix/ext/fs.rs b/ctr-std/src/sys/unix/ext/fs.rs deleted file mode 100644 index 507e9d8..0000000 --- a/ctr-std/src/sys/unix/ext/fs.rs +++ /dev/null @@ -1,863 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific extensions to primitives in the `std::fs` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use fs::{self, Permissions, OpenOptions}; -use io; -use libc; -use path::Path; -use sys; -use sys_common::{FromInner, AsInner, AsInnerMut}; -use sys::platform::fs::MetadataExt as UnixMetadataExt; - -/// Unix-specific extensions to [`File`]. -/// -/// [`File`]: ../../../../std/fs/struct.File.html -#[stable(feature = "file_offset", since = "1.15.0")] -pub trait FileExt { - /// Reads a number of bytes starting from a given offset. - /// - /// Returns the number of bytes read. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// Note that similar to [`File::read`], it is not an error to return with a - /// short read. - /// - /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs::File; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let mut buf = [0u8; 8]; - /// let file = File::open("foo.txt")?; - /// - /// // We now read 8 bytes from the offset 10. - /// let num_bytes_read = file.read_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", num_bytes_read, buf); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result; - - /// Reads the exact number of byte required to fill `buf` from the given offset. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`. - /// - /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact - /// [`read_at`]: #tymethod.read_at - /// - /// # Errors - /// - /// If this function encounters an error of the kind - /// [`ErrorKind::Interrupted`] then the error is ignored and the operation - /// will continue. - /// - /// If this function encounters an "end of file" before completely filling - /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. - /// The contents of `buf` are unspecified in this case. - /// - /// If any other read error is encountered then this function immediately - /// returns. The contents of `buf` are unspecified in this case. - /// - /// If this function returns an error, it is unspecified how many bytes it - /// has read, but it will never read more than would be necessary to - /// completely fill the buffer. - /// - /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted - /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof - /// - /// # Examples - /// - /// ```no_run - /// #![feature(rw_exact_all_at)] - /// use std::io; - /// use std::fs::File; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let mut buf = [0u8; 8]; - /// let file = File::open("foo.txt")?; - /// - /// // We now read exactly 8 bytes from the offset 10. - /// file.read_exact_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", buf.len(), buf); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "rw_exact_all_at", issue = "51984")] - fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { - while !buf.is_empty() { - match self.read_at(buf, offset) { - Ok(0) => break, - Ok(n) => { - let tmp = buf; - buf = &mut tmp[n..]; - offset += n as u64; - } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - if !buf.is_empty() { - Err(io::Error::new(io::ErrorKind::UnexpectedEof, - "failed to fill whole buffer")) - } else { - Ok(()) - } - } - - /// Writes a number of bytes starting from a given offset. - /// - /// Returns the number of bytes written. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// When writing beyond the end of the file, the file is appropriately - /// extended and the intermediate bytes are initialized with the value 0. - /// - /// Note that similar to [`File::write`], it is not an error to return a - /// short write. - /// - /// [`File::write`]: ../../../../std/fs/struct.File.html#write.v - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let file = File::open("foo.txt")?; - /// - /// // We now write at the offset 10. - /// file.write_at(b"sushi", 10)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn write_at(&self, buf: &[u8], offset: u64) -> io::Result; - - /// Attempts to write an entire buffer starting from a given offset. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// This method will continuously call [`write_at`] until there is no more data - /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is - /// returned. This method will not return until the entire buffer has been - /// successfully written or such an error occurs. The first error that is - /// not of [`ErrorKind::Interrupted`] kind generated from this method will be - /// returned. - /// - /// # Errors - /// - /// This function will return the first error of - /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns. - /// - /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted - /// [`write_at`]: #tymethod.write_at - /// - /// # Examples - /// - /// ```no_run - /// #![feature(rw_exact_all_at)] - /// use std::fs::File; - /// use std::io; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let file = File::open("foo.txt")?; - /// - /// // We now write at the offset 10. - /// file.write_all_at(b"sushi", 10)?; - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "rw_exact_all_at", issue = "51984")] - fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { - while !buf.is_empty() { - match self.write_at(buf, offset) { - Ok(0) => return Err(io::Error::new(io::ErrorKind::WriteZero, - "failed to write whole buffer")), - Ok(n) => { - buf = &buf[n..]; - offset += n as u64 - } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } -} - -#[stable(feature = "file_offset", since = "1.15.0")] -impl FileExt for fs::File { - fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - self.as_inner().read_at(buf, offset) - } - fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - self.as_inner().write_at(buf, offset) - } -} - -/// Unix-specific extensions to [`fs::Permissions`]. -/// -/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait PermissionsExt { - /// Returns the underlying raw `st_mode` bits that contain the standard - /// Unix permissions for this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let permissions = metadata.permissions(); - /// - /// println!("permissions: {}", permissions.mode()); - /// Ok(()) } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&self) -> u32; - - /// Sets the underlying raw bits for this set of permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); - /// - /// permissions.set_mode(0o644); // Read/write for owner and read for others. - /// assert_eq!(permissions.mode(), 0o644); - /// Ok(()) } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn set_mode(&mut self, mode: u32); - - /// Creates a new instance of `Permissions` from the given set of Unix - /// permission bits. - /// - /// # Examples - /// - /// ``` - /// use std::fs::Permissions; - /// use std::os::unix::fs::PermissionsExt; - /// - /// // Read/write for owner and read for others. - /// let permissions = Permissions::from_mode(0o644); - /// assert_eq!(permissions.mode(), 0o644); - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn from_mode(mode: u32) -> Self; -} - -#[stable(feature = "fs_ext", since = "1.1.0")] -impl PermissionsExt for Permissions { - fn mode(&self) -> u32 { - self.as_inner().mode() - } - - fn set_mode(&mut self, mode: u32) { - *self = Permissions::from_inner(FromInner::from_inner(mode)); - } - - fn from_mode(mode: u32) -> Permissions { - Permissions::from_inner(FromInner::from_inner(mode)) - } -} - -/// Unix-specific extensions to [`fs::OpenOptions`]. -/// -/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait OpenOptionsExt { - /// Sets the mode bits that a new file will be created with. - /// - /// If a new file is created as part of a `File::open_opts` call then this - /// specified `mode` will be used as the permission bits for the new file. - /// If no `mode` is set, the default of `0o666` will be used. - /// The operating system masks out bits with the systems `umask`, to produce - /// the final permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// use std::os::unix::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.mode(0o644); // Give read/write for owner and read for others. - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&mut self, mode: u32) -> &mut Self; - - /// Pass custom flags to the `flags` argument of `open`. - /// - /// The bits that define the access mode are masked out with `O_ACCMODE`, to - /// ensure they do not interfere with the access mode set by Rusts options. - /// - /// Custom flags can only set flags, not remove flags set by Rusts options. - /// This options overwrites any previously set custom flags. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(libc)] - /// extern crate libc; - /// use std::fs::OpenOptions; - /// use std::os::unix::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.write(true); - /// if cfg!(unix) { - /// options.custom_flags(libc::O_NOFOLLOW); - /// } - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn custom_flags(&mut self, flags: i32) -> &mut Self; -} - -#[stable(feature = "fs_ext", since = "1.1.0")] -impl OpenOptionsExt for OpenOptions { - fn mode(&mut self, mode: u32) -> &mut OpenOptions { - self.as_inner_mut().mode(mode); self - } - - fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { - self.as_inner_mut().custom_flags(flags); self - } -} - -/// Unix-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Returns the ID of the device containing the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let dev_id = meta.dev(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn dev(&self) -> u64; - /// Returns the inode number. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let inode = meta.ino(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ino(&self) -> u64; - /// Returns the rights applied to this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let mode = meta.mode(); - /// let user_has_write_access = mode & 0o200; - /// let user_has_read_write_access = mode & 0o600; - /// let group_has_read_access = mode & 0o040; - /// let others_have_exec_access = mode & 0o001; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mode(&self) -> u32; - /// Returns the number of hard links pointing to this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nb_hard_links = meta.nlink(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn nlink(&self) -> u64; - /// Returns the user ID of the owner of this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let user_id = meta.uid(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn uid(&self) -> u32; - /// Returns the group ID of the owner of this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let group_id = meta.gid(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn gid(&self) -> u32; - /// Returns the device ID of this file (if it is a special one). - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let device_id = meta.rdev(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn rdev(&self) -> u64; - /// Returns the total size of this file in bytes. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let file_size = meta.size(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn size(&self) -> u64; - /// Returns the time of the last access to the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_access_time = meta.atime(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn atime(&self) -> i64; - /// Returns the time of the last access to the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_access_time = meta.atime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn atime_nsec(&self) -> i64; - /// Returns the time of the last modification of the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_modification_time = meta.mtime(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mtime(&self) -> i64; - /// Returns the time of the last modification of the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_modification_time = meta.mtime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mtime_nsec(&self) -> i64; - /// Returns the time of the last status change of the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_status_change_time = meta.ctime(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ctime(&self) -> i64; - /// Returns the time of the last status change of the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_status_change_time = meta.ctime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ctime_nsec(&self) -> i64; - /// Returns the blocksize for filesystem I/O. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let blocksize = meta.blksize(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blksize(&self) -> u64; - /// Returns the number of blocks allocated to the file, in 512-byte units. - /// - /// Please note that this may be smaller than `st_size / 512` when the file has holes. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let blocks = meta.blocks(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blocks(&self) -> u64; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for fs::Metadata { - fn dev(&self) -> u64 { self.st_dev() } - fn ino(&self) -> u64 { self.st_ino() } - fn mode(&self) -> u32 { self.st_mode() } - fn nlink(&self) -> u64 { self.st_nlink() } - fn uid(&self) -> u32 { self.st_uid() } - fn gid(&self) -> u32 { self.st_gid() } - fn rdev(&self) -> u64 { self.st_rdev() } - fn size(&self) -> u64 { self.st_size() } - fn atime(&self) -> i64 { self.st_atime() } - fn atime_nsec(&self) -> i64 { self.st_atime_nsec() } - fn mtime(&self) -> i64 { self.st_mtime() } - fn mtime_nsec(&self) -> i64 { self.st_mtime_nsec() } - fn ctime(&self) -> i64 { self.st_ctime() } - fn ctime_nsec(&self) -> i64 { self.st_ctime_nsec() } - fn blksize(&self) -> u64 { self.st_blksize() } - fn blocks(&self) -> u64 { self.st_blocks() } -} - -/// Unix-specific extensions for [`FileType`]. -/// -/// Adds support for special Unix file types such as block/character devices, -/// pipes, and sockets. -/// -/// [`FileType`]: ../../../../std/fs/struct.FileType.html -#[stable(feature = "file_type_ext", since = "1.5.0")] -pub trait FileTypeExt { - /// Returns whether this file type is a block device. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("block_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_block_device()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_block_device(&self) -> bool; - /// Returns whether this file type is a char device. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("char_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_char_device()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_char_device(&self) -> bool; - /// Returns whether this file type is a fifo. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("fifo_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_fifo()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_fifo(&self) -> bool; - /// Returns whether this file type is a socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("unix.socket")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_socket()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_socket(&self) -> bool; -} - -#[stable(feature = "file_type_ext", since = "1.5.0")] -impl FileTypeExt for fs::FileType { - fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) } - fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) } - fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) } - fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) } -} - -/// Unix-specific extension methods for [`fs::DirEntry`]. -/// -/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html -#[stable(feature = "dir_entry_ext", since = "1.1.0")] -pub trait DirEntryExt { - /// Returns the underlying `d_ino` field in the contained `dirent` - /// structure. - /// - /// # Examples - /// - /// ``` - /// use std::fs; - /// use std::os::unix::fs::DirEntryExt; - /// - /// if let Ok(entries) = fs::read_dir(".") { - /// for entry in entries { - /// if let Ok(entry) = entry { - /// // Here, `entry` is a `DirEntry`. - /// println!("{:?}: {}", entry.file_name(), entry.ino()); - /// } - /// } - /// } - /// ``` - #[stable(feature = "dir_entry_ext", since = "1.1.0")] - fn ino(&self) -> u64; -} - -#[stable(feature = "dir_entry_ext", since = "1.1.0")] -impl DirEntryExt for fs::DirEntry { - fn ino(&self) -> u64 { self.as_inner().ino() } -} - -/// Creates a new symbolic link on the filesystem. -/// -/// The `dst` path will be a symbolic link pointing to the `src` path. -/// -/// # Note -/// -/// On Windows, you must specify whether a symbolic link points to a file -/// or directory. Use `os::windows::fs::symlink_file` to create a -/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a -/// symbolic link to a directory. Additionally, the process must have -/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a -/// symbolic link. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::symlink("a.txt", "b.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> -{ - sys::fs::symlink(src.as_ref(), dst.as_ref()) -} - -/// Unix-specific extensions to [`fs::DirBuilder`]. -/// -/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html -#[stable(feature = "dir_builder", since = "1.6.0")] -pub trait DirBuilderExt { - /// Sets the mode to create new directories with. This option defaults to - /// 0o777. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::DirBuilder; - /// use std::os::unix::fs::DirBuilderExt; - /// - /// let mut builder = DirBuilder::new(); - /// builder.mode(0o755); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - fn mode(&mut self, mode: u32) -> &mut Self; -} - -#[stable(feature = "dir_builder", since = "1.6.0")] -impl DirBuilderExt for fs::DirBuilder { - fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { - self.as_inner_mut().set_mode(mode); - self - } -} diff --git a/ctr-std/src/sys/unix/ext/io.rs b/ctr-std/src/sys/unix/ext/io.rs deleted file mode 100644 index c9fe359..0000000 --- a/ctr-std/src/sys/unix/ext/io.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific extensions to general I/O primitives - -#![stable(feature = "rust1", since = "1.0.0")] - -use fs; -use os::raw; -use sys; -use io; -use sys_common::{AsInner, FromInner, IntoInner}; -use libc; - -/// Raw file descriptors. -#[stable(feature = "rust1", since = "1.0.0")] -pub type RawFd = raw::c_int; - -/// A trait to extract the raw unix file descriptor from an underlying -/// object. -/// -/// This is only available on unix platforms and must be imported in order -/// to call the method. Windows platforms have a corresponding `AsRawHandle` -/// and `AsRawSocket` set of traits. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsRawFd { - /// Extracts the raw file descriptor. - /// - /// This method does **not** pass ownership of the raw file descriptor - /// to the caller. The descriptor is only guaranteed to be valid while - /// the original object has not yet been destroyed. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_fd(&self) -> RawFd; -} - -/// A trait to express the ability to construct an object from a raw file -/// descriptor. -#[stable(feature = "from_raw_os", since = "1.1.0")] -pub trait FromRawFd { - /// Constructs a new instance of `Self` from the given raw file - /// descriptor. - /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - #[stable(feature = "from_raw_os", since = "1.1.0")] - unsafe fn from_raw_fd(fd: RawFd) -> Self; -} - -/// A trait to express the ability to consume an object and acquire ownership of -/// its raw file descriptor. -#[stable(feature = "into_raw_os", since = "1.4.0")] -pub trait IntoRawFd { - /// Consumes this object, returning the raw underlying file descriptor. - /// - /// This function **transfers ownership** of the underlying file descriptor - /// to the caller. Callers are then the unique owners of the file descriptor - /// and must close the descriptor once it's no longer needed. - #[stable(feature = "into_raw_os", since = "1.4.0")] - fn into_raw_fd(self) -> RawFd; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for fs::File { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for fs::File { - unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs::File::from_inner(fd)) - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for fs::File { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdin { - fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdout { - fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stderr { - fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO } -} diff --git a/ctr-std/src/sys/unix/ext/mod.rs b/ctr-std/src/sys/unix/ext/mod.rs deleted file mode 100644 index 88e4237..0000000 --- a/ctr-std/src/sys/unix/ext/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Experimental extensions to `std` for Unix platforms. -//! -//! Provides access to platform-level information on Unix platforms, and -//! exposes Unix-specific functions that would otherwise be inappropriate as -//! part of the core `std` library. -//! -//! It exposes more ways to deal with platform-specific strings (`OsStr`, -//! `OsString`), allows to set permissions more granularly, extract low-level -//! file descriptors from files and sockets, and has platform-specific helpers -//! for spawning processes. -//! -//! # Examples -//! -//! ```no_run -//! use std::fs::File; -//! use std::os::unix::prelude::*; -//! -//! fn main() { -//! let f = File::create("foo.txt").unwrap(); -//! let fd = f.as_raw_fd(); -//! -//! // use fd with native unix bindings -//! } -//! ``` - -#![stable(feature = "rust1", since = "1.0.0")] -#![doc(cfg(unix))] -#![allow(missing_docs)] - -pub mod io; -pub mod ffi; -pub mod fs; -pub mod process; -pub mod raw; -pub mod thread; -pub mod net; - -/// A prelude for conveniently writing platform-specific code. -/// -/// Includes all extension traits, and some important type definitions. -#[stable(feature = "rust1", since = "1.0.0")] -pub mod prelude { - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::fs::DirEntryExt; - #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")] - pub use super::fs::FileExt; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::thread::JoinHandleExt; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::process::{CommandExt, ExitStatusExt}; -} diff --git a/ctr-std/src/sys/unix/ext/net.rs b/ctr-std/src/sys/unix/ext/net.rs deleted file mode 100644 index 55f43cc..0000000 --- a/ctr-std/src/sys/unix/ext/net.rs +++ /dev/null @@ -1,1824 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "unix_socket", since = "1.10.0")] - -//! Unix-specific networking functionality - -#[cfg(unix)] -use libc; - -// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? -#[cfg(not(unix))] -mod libc { - pub use libc::c_int; - pub type socklen_t = u32; - pub struct sockaddr; - #[derive(Clone)] - pub struct sockaddr_un; -} - -use ascii; -use ffi::OsStr; -use fmt; -use io::{self, Initializer}; -use mem; -use net::{self, Shutdown}; -use os::unix::ffi::OsStrExt; -use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; -use path::Path; -use time::Duration; -use sys::{self, cvt}; -use sys::net::Socket; -use sys_common::{self, AsInner, FromInner, IntoInner}; - -#[cfg(any(target_os = "linux", target_os = "android", - target_os = "dragonfly", target_os = "freebsd", - target_os = "openbsd", target_os = "netbsd", - target_os = "haiku", target_os = "bitrig"))] -use libc::MSG_NOSIGNAL; -#[cfg(not(any(target_os = "linux", target_os = "android", - target_os = "dragonfly", target_os = "freebsd", - target_os = "openbsd", target_os = "netbsd", - target_os = "haiku", target_os = "bitrig")))] -const MSG_NOSIGNAL: libc::c_int = 0x0; - -fn sun_path_offset() -> usize { - // Work with an actual instance of the type since using a null pointer is UB - let addr: libc::sockaddr_un = unsafe { mem::uninitialized() }; - let base = &addr as *const _ as usize; - let path = &addr.sun_path as *const _ as usize; - path - base -} - -unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { - let mut addr: libc::sockaddr_un = mem::zeroed(); - addr.sun_family = libc::AF_UNIX as libc::sa_family_t; - - let bytes = path.as_os_str().as_bytes(); - - if bytes.contains(&0) { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "paths may not contain interior null bytes")); - } - - if bytes.len() >= addr.sun_path.len() { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "path must be shorter than SUN_LEN")); - } - for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { - *dst = *src as libc::c_char; - } - // null byte for pathname addresses is already there because we zeroed the - // struct - - let mut len = sun_path_offset() + bytes.len(); - match bytes.get(0) { - Some(&0) | None => {} - Some(_) => len += 1, - } - Ok((addr, len as libc::socklen_t)) -} - -enum AddressKind<'a> { - Unnamed, - Pathname(&'a Path), - Abstract(&'a [u8]), -} - -/// An address associated with a Unix socket. -/// -/// # Examples -/// -/// ``` -/// use std::os::unix::net::UnixListener; -/// -/// let socket = match UnixListener::bind("/tmp/sock") { -/// Ok(sock) => sock, -/// Err(e) => { -/// println!("Couldn't bind: {:?}", e); -/// return -/// } -/// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); -/// ``` -#[derive(Clone)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct SocketAddr { - addr: libc::sockaddr_un, - len: libc::socklen_t, -} - -impl SocketAddr { - fn new(f: F) -> io::Result - where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int - { - unsafe { - let mut addr: libc::sockaddr_un = mem::zeroed(); - let mut len = mem::size_of::() as libc::socklen_t; - cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; - SocketAddr::from_parts(addr, len) - } - } - - fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { - if len == 0 { - // When there is a datagram from unnamed unix socket - // linux returns zero bytes of address - len = sun_path_offset() as libc::socklen_t; // i.e. zero-length address - } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "file descriptor did not correspond to a Unix socket")); - } - - Ok(SocketAddr { - addr, - len, - }) - } - - /// Returns true if and only if the address is unnamed. - /// - /// # Examples - /// - /// A named address: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let socket = UnixListener::bind("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), false); - /// ``` - /// - /// An unnamed address: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), true); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn is_unnamed(&self) -> bool { - if let AddressKind::Unnamed = self.address() { - true - } else { - false - } - } - - /// Returns the contents of this address if it is a `pathname` address. - /// - /// # Examples - /// - /// With a pathname: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// use std::path::Path; - /// - /// let socket = UnixListener::bind("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); - /// ``` - /// - /// Without a pathname: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), None); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn as_pathname(&self) -> Option<&Path> { - if let AddressKind::Pathname(path) = self.address() { - Some(path) - } else { - None - } - } - - fn address<'a>(&'a self) -> AddressKind<'a> { - let len = self.len as usize - sun_path_offset(); - let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; - - // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 - || (cfg!(not(any(target_os = "linux", target_os = "android"))) - && self.addr.sun_path[0] == 0) - { - AddressKind::Unnamed - } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(&path[1..len]) - } else { - AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) - } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self.address() { - AddressKind::Unnamed => write!(fmt, "(unnamed)"), - AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), - AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), - } - } -} - -struct AsciiEscaped<'a>(&'a [u8]); - -impl<'a> fmt::Display for AsciiEscaped<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "\"")?; - for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { - write!(fmt, "{}", byte as char)?; - } - write!(fmt, "\"") - } -} - -/// A Unix stream socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixStream; -/// use std::io::prelude::*; -/// -/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); -/// stream.write_all(b"hello world").unwrap(); -/// let mut response = String::new(); -/// stream.read_to_string(&mut response).unwrap(); -/// println!("{}", response); -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixStream(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixStream"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixStream { - /// Connects to the socket named by `path`. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = match UnixStream::connect("/tmp/sock") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; - Ok(UnixStream(inner)) - } - } - inner(path.as_ref()) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixStream`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let (sock1, sock2) = match UnixStream::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't create a pair of sockets: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; - Ok((UnixStream(i1), UnixStream(i2))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixStream` is a reference to the same stream that this - /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propagated to the other - /// stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixStream) - } - - /// Returns the socket address of the local half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the socket address of the remote half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns None. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::net::Shutdown; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Read for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - io::Read::read(&mut &*self, buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Write for UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - io::Write::write(&mut &*self, buf) - } - - fn flush(&mut self) -> io::Result<()> { - io::Write::flush(&mut &*self) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} - -/// A structure representing a Unix domain socket server. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); -/// -/// // accept connections and process them, spawning a new thread for each one -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// /* connection succeeded */ -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// /* connection failed */ -/// break; -/// } -/// } -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixListener(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixListener"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - builder.finish() - } -} - -impl UnixListener { - /// Creates a new `UnixListener` bound to the specified socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = match UnixListener::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(*inner.as_inner(), 128))?; - - Ok(UnixListener(inner)) - } - } - inner(path.as_ref()) - } - - /// Accepts a new incoming connection to this listener. - /// - /// This function will block the calling thread until a new Unix connection - /// is established. When established, the corresponding [`UnixStream`] and - /// the remote peer's address will be returned. - /// - /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; - let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; - let addr = SocketAddr::from_parts(storage, len)?; - Ok((UnixStream(sock), addr)) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixListener` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one listener will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let listener_copy = listener.try_clone().expect("try_clone failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixListener) - } - - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let addr = listener.local_addr().expect("Couldn't get local address"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/tmp/sock").unwrap(); - /// - /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns None. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Returns an iterator over incoming connections. - /// - /// The iterator will never return [`None`] and will also not yield the - /// peer's [`SocketAddr`] structure. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`SocketAddr`]: struct.SocketAddr.html - /// - /// # Examples - /// - /// ```no_run - /// use std::thread; - /// use std::os::unix::net::{UnixStream, UnixListener}; - /// - /// fn handle_client(stream: UnixStream) { - /// // ... - /// } - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// thread::spawn(|| handle_client(stream)); - /// } - /// Err(err) => { - /// break; - /// } - /// } - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn incoming<'a>(&'a self) -> Incoming<'a> { - Incoming { listener: self } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> IntoIterator for &'a UnixListener { - type Item = io::Result; - type IntoIter = Incoming<'a>; - - fn into_iter(self) -> Incoming<'a> { - self.incoming() - } -} - -/// An iterator over incoming connections to a [`UnixListener`]. -/// -/// It will never return [`None`]. -/// -/// [`None`]: ../../../../std/option/enum.Option.html#variant.None -/// [`UnixListener`]: struct.UnixListener.html -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); -/// -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// break; -/// } -/// } -/// } -/// ``` -#[derive(Debug)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct Incoming<'a> { - listener: &'a UnixListener, -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> Iterator for Incoming<'a> { - type Item = io::Result; - - fn next(&mut self) -> Option> { - Some(self.listener.accept().map(|s| s.0)) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::max_value(), None) - } -} - -/// A Unix datagram socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixDatagram; -/// -/// let socket = UnixDatagram::bind("/path/to/my/socket").unwrap(); -/// socket.send_to(b"hello world", "/path/to/other/socket").unwrap(); -/// let mut buf = [0; 100]; -/// let (count, address) = socket.recv_from(&mut buf).unwrap(); -/// println!("socket {:?} sent {:?}", address, &buf[..count]); -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixDatagram(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixDatagram { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixDatagram"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixDatagram { - /// Creates a Unix datagram socket bound to the given path. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't bind: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let socket = UnixDatagram::unbound()?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; - - Ok(socket) - } - } - inner(path.as_ref()) - } - - /// Creates a Unix Datagram socket which is not bound to any address. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::unbound() { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn unbound() -> io::Result { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok(UnixDatagram(inner)) - } - - /// Create an unnamed pair of connected sockets. - /// - /// Returns two `UnixDatagrams`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let (sock1, sock2) = match UnixDatagram::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok((UnixDatagram(i1), UnixDatagram(i2))) - } - - /// Connects the socket to the specified address. - /// - /// The [`send`] method may be used to send data to the specified address. - /// [`recv`] and [`recv_from`] will only receive data from that address. - /// - /// [`send`]: #method.send - /// [`recv`]: #method.recv - /// [`recv_from`]: #method.recv_from - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// match sock.connect("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(&self, path: P) -> io::Result<()> { - fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; - - Ok(()) - } - } - inner(self, path.as_ref()) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixDatagram` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one side will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap(); - /// - /// let sock_copy = sock.try_clone().expect("try_clone failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixDatagram) - } - - /// Returns the address of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap(); - /// - /// let addr = sock.local_addr().expect("Couldn't get local address"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the address of this socket's peer. - /// - /// The [`connect`] method will connect the socket to a peer. - /// - /// [`connect`]: #method.connect - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.connect("/path/to/the/socket").unwrap(); - /// - /// let addr = sock.peer_addr().expect("Couldn't get peer address"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read and the address from - /// whence the data came. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// let mut buf = vec![0; 10]; - /// match sock.recv_from(buf.as_mut_slice()) { - /// Ok((size, sender)) => println!("received {} bytes from {:?}", size, sender), - /// Err(e) => println!("recv_from function failed: {:?}", e), - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - let mut count = 0; - let addr = SocketAddr::new(|addr, len| { - unsafe { - count = libc::recvfrom(*self.0.as_inner(), - buf.as_mut_ptr() as *mut _, - buf.len(), - 0, - addr, - len); - if count > 0 { - 1 - } else if count == 0 { - 0 - } else { - -1 - } - } - })?; - - Ok((count as usize, addr)) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap(); - /// let mut buf = vec![0; 10]; - /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - /// Sends data on the socket to the specified address. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { - fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - let count = cvt(libc::sendto(*d.0.as_inner(), - buf.as_ptr() as *const _, - buf.len(), - MSG_NOSIGNAL, - &addr as *const _ as *const _, - len))?; - Ok(count as usize) - } - } - inner(self, buf, path.as_ref()) - } - - /// Sends data on the socket to the socket's peer. - /// - /// The peer address may be set by the `connect` method, and this method - /// will return an error if the socket has not already been connected. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.connect("/some/sock").expect("Couldn't connect"); - /// sock.send(b"omelette au fromage").expect("send_to function failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] - /// is passed to this method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`recv`]: #method.recv - /// [`recv_from`]: #method.recv_from - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`send`]: #method.send - /// [`send_to`]: #method.send_to - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed"); - /// assert_eq!(sock.read_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// assert_eq!(sock.write_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// if let Ok(Some(err)) = sock.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shut down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// use std::net::Shutdown; - /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixDatagram { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixDatagram { - unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { - UnixDatagram(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixDatagram { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod test { - use thread; - use io::{self, ErrorKind}; - use io::prelude::*; - use time::Duration; - use sys_common::io::test::tmpdir; - - use super::*; - - macro_rules! or_panic { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{}", e), - } - } - } - - #[test] - fn basic() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - let msg1 = b"hello"; - let msg2 = b"world!"; - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - let mut stream = or_panic!(listener.accept()).0; - let mut buf = [0; 5]; - or_panic!(stream.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(stream.write_all(msg2)); - }); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - assert_eq!(Some(&*socket_path), - stream.peer_addr().unwrap().as_pathname()); - or_panic!(stream.write_all(msg1)); - let mut buf = vec![]; - or_panic!(stream.read_to_end(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(stream); - - thread.join().unwrap(); - } - - #[test] - fn pair() { - let msg1 = b"hello"; - let msg2 = b"world!"; - - let (mut s1, mut s2) = or_panic!(UnixStream::pair()); - let thread = thread::spawn(move || { - // s1 must be moved in or the test will hang! - let mut buf = [0; 5]; - or_panic!(s1.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(s1.write_all(msg2)); - }); - - or_panic!(s2.write_all(msg1)); - let mut buf = vec![]; - or_panic!(s2.read_to_end(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(s2); - - thread.join().unwrap(); - } - - #[test] - fn try_clone() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - let msg1 = b"hello"; - let msg2 = b"world"; - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - let mut stream = or_panic!(listener.accept()).0; - or_panic!(stream.write_all(msg1)); - or_panic!(stream.write_all(msg2)); - }); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - let mut stream2 = or_panic!(stream.try_clone()); - - let mut buf = [0; 5]; - or_panic!(stream.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(stream2.read(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - - thread.join().unwrap(); - } - - #[test] - fn iter() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - for stream in listener.incoming().take(2) { - let mut stream = or_panic!(stream); - let mut buf = [0]; - or_panic!(stream.read(&mut buf)); - } - }); - - for _ in 0..2 { - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.write_all(&[0])); - } - - thread.join().unwrap(); - } - - #[test] - fn long_path() { - let dir = tmpdir(); - let socket_path = dir.path() - .join("asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\ - sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf"); - match UnixStream::connect(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - - match UnixListener::bind(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - - match UnixDatagram::bind(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - } - - #[test] - fn timeouts() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let _listener = or_panic!(UnixListener::bind(&socket_path)); - - let stream = or_panic!(UnixStream::connect(&socket_path)); - let dur = Duration::new(15410, 0); - - assert_eq!(None, or_panic!(stream.read_timeout())); - - or_panic!(stream.set_read_timeout(Some(dur))); - assert_eq!(Some(dur), or_panic!(stream.read_timeout())); - - assert_eq!(None, or_panic!(stream.write_timeout())); - - or_panic!(stream.set_write_timeout(Some(dur))); - assert_eq!(Some(dur), or_panic!(stream.write_timeout())); - - or_panic!(stream.set_read_timeout(None)); - assert_eq!(None, or_panic!(stream.read_timeout())); - - or_panic!(stream.set_write_timeout(None)); - assert_eq!(None, or_panic!(stream.write_timeout())); - } - - #[test] - fn test_read_timeout() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let _listener = or_panic!(UnixListener::bind(&socket_path)); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut buf = [0; 10]; - let kind = stream.read(&mut buf).err().expect("expected error").kind(); - assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut); - } - - #[test] - fn test_read_with_timeout() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut other_end = or_panic!(listener.accept()).0; - or_panic!(other_end.write_all(b"hello world")); - - let mut buf = [0; 11]; - or_panic!(stream.read(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - - let kind = stream.read(&mut buf).err().expect("expected error").kind(); - assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_unix_stream_timeout_zero_duration() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let stream = or_panic!(UnixStream::connect(&socket_path)); - - let result = stream.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = stream.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - drop(listener); - } - - #[test] - fn test_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - let path2 = dir.path().join("sock2"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::bind(&path2)); - - let msg = b"hello world"; - or_panic!(sock1.send_to(msg, &path2)); - let mut buf = [0; 11]; - or_panic!(sock2.recv_from(&mut buf)); - assert_eq!(msg, &buf[..]); - } - - #[test] - fn test_unnamed_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - - let msg = b"hello world"; - or_panic!(sock2.send_to(msg, &path1)); - let mut buf = [0; 11]; - let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); - assert_eq!(usize, 11); - assert!(addr.is_unnamed()); - assert_eq!(msg, &buf[..]); - } - - #[test] - fn test_connect_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - let path2 = dir.path().join("sock2"); - - let bsock1 = or_panic!(UnixDatagram::bind(&path1)); - let bsock2 = or_panic!(UnixDatagram::bind(&path2)); - let sock = or_panic!(UnixDatagram::unbound()); - or_panic!(sock.connect(&path1)); - - // Check send() - let msg = b"hello there"; - or_panic!(sock.send(msg)); - let mut buf = [0; 11]; - let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf)); - assert_eq!(usize, 11); - assert!(addr.is_unnamed()); - assert_eq!(msg, &buf[..]); - - // Changing default socket works too - or_panic!(sock.connect(&path2)); - or_panic!(sock.send(msg)); - or_panic!(bsock2.recv_from(&mut buf)); - } - - #[test] - fn test_unix_datagram_recv() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - or_panic!(sock2.connect(&path1)); - - let msg = b"hello world"; - or_panic!(sock2.send(msg)); - let mut buf = [0; 11]; - let size = or_panic!(sock1.recv(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); - } - - #[test] - fn datagram_pair() { - let msg1 = b"hello"; - let msg2 = b"world!"; - - let (s1, s2) = or_panic!(UnixDatagram::pair()); - let thread = thread::spawn(move || { - // s1 must be moved in or the test will hang! - let mut buf = [0; 5]; - or_panic!(s1.recv(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(s1.send(msg2)); - }); - - or_panic!(s2.send(msg1)); - let mut buf = [0; 6]; - or_panic!(s2.recv(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(s2); - - thread.join().unwrap(); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_unix_datagram_timeout_zero_duration() { - let dir = tmpdir(); - let path = dir.path().join("sock"); - - let datagram = or_panic!(UnixDatagram::bind(&path)); - - let result = datagram.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = datagram.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - } - - #[test] - fn abstract_namespace_not_allowed() { - assert!(UnixStream::connect("\0asdf").is_err()); - } -} diff --git a/ctr-std/src/sys/unix/ext/process.rs b/ctr-std/src/sys/unix/ext/process.rs deleted file mode 100644 index 21630ae..0000000 --- a/ctr-std/src/sys/unix/ext/process.rs +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific extensions to primitives in the `std::process` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use io; -use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd}; -use process; -use sys; -use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; - -/// Unix-specific extensions to the [`process::Command`] builder. -/// -/// [`process::Command`]: ../../../../std/process/struct.Command.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait CommandExt { - /// Sets the child process's user id. This translates to a - /// `setuid` call in the child process. Failure in the `setuid` - /// call will cause the spawn to fail. - #[stable(feature = "rust1", since = "1.0.0")] - fn uid(&mut self, id: u32) -> &mut process::Command; - - /// Similar to `uid`, but sets the group id of the child process. This has - /// the same semantics as the `uid` field. - #[stable(feature = "rust1", since = "1.0.0")] - fn gid(&mut self, id: u32) -> &mut process::Command; - - /// Schedules a closure to be run just before the `exec` function is - /// invoked. - /// - /// The closure is allowed to return an I/O error whose OS error code will - /// be communicated back to the parent and returned as an error from when - /// the spawn was requested. - /// - /// Multiple closures can be registered and they will be called in order of - /// their registration. If a closure returns `Err` then no further closures - /// will be called and the spawn operation will immediately return with a - /// failure. - /// - /// # Notes - /// - /// This closure will be run in the context of the child process after a - /// `fork`. This primarily means that any modifications made to memory on - /// behalf of this closure will **not** be visible to the parent process. - /// This is often a very constrained environment where normal operations - /// like `malloc` or acquiring a mutex are not guaranteed to work (due to - /// other threads perhaps still running when the `fork` was run). - /// - /// When this closure is run, aspects such as the stdio file descriptors and - /// working directory have successfully been changed, so output to these - /// locations may not appear where intended. - #[stable(feature = "process_exec", since = "1.15.0")] - fn before_exec(&mut self, f: F) -> &mut process::Command - where F: FnMut() -> io::Result<()> + Send + Sync + 'static; - - /// Performs all the required setup by this `Command`, followed by calling - /// the `execvp` syscall. - /// - /// On success this function will not return, and otherwise it will return - /// an error indicating why the exec (or another part of the setup of the - /// `Command`) failed. - /// - /// `exec` not returning has the same implications as calling - /// [`process::exit`] – no destructors on the current stack or any other - /// thread’s stack will be run. Therefore, it is recommended to only call - /// `exec` at a point where it is fine to not run any destructors. Note, - /// that the `execvp` syscall independently guarantees that all memory is - /// freed and all file descriptors with the `CLOEXEC` option (set by default - /// on all file descriptors opened by the standard library) are closed. - /// - /// This function, unlike `spawn`, will **not** `fork` the process to create - /// a new child. Like spawn, however, the default behavior for the stdio - /// descriptors will be to inherited from the current process. - /// - /// [`process::exit`]: ../../../process/fn.exit.html - /// - /// # Notes - /// - /// The process may be in a "broken state" if this function returns in - /// error. For example the working directory, environment variables, signal - /// handling settings, various user/group information, or aspects of stdio - /// file descriptors may have changed. If a "transactional spawn" is - /// required to gracefully handle errors it is recommended to use the - /// cross-platform `spawn` instead. - #[stable(feature = "process_exec2", since = "1.9.0")] - fn exec(&mut self) -> io::Error; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl CommandExt for process::Command { - fn uid(&mut self, id: u32) -> &mut process::Command { - self.as_inner_mut().uid(id); - self - } - - fn gid(&mut self, id: u32) -> &mut process::Command { - self.as_inner_mut().gid(id); - self - } - - fn before_exec(&mut self, f: F) -> &mut process::Command - where F: FnMut() -> io::Result<()> + Send + Sync + 'static - { - self.as_inner_mut().before_exec(Box::new(f)); - self - } - - fn exec(&mut self) -> io::Error { - self.as_inner_mut().exec(sys::process::Stdio::Inherit) - } -} - -/// Unix-specific extensions to [`process::ExitStatus`]. -/// -/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait ExitStatusExt { - /// Creates a new `ExitStatus` from the raw underlying `i32` return value of - /// a process. - #[stable(feature = "exit_status_from", since = "1.12.0")] - fn from_raw(raw: i32) -> Self; - - /// If the process was terminated by a signal, returns that signal. - #[stable(feature = "rust1", since = "1.0.0")] - fn signal(&self) -> Option; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExitStatusExt for process::ExitStatus { - fn from_raw(raw: i32) -> Self { - process::ExitStatus::from_inner(From::from(raw)) - } - - fn signal(&self) -> Option { - self.as_inner().signal() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl FromRawFd for process::Stdio { - unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { - let fd = sys::fd::FileDesc::new(fd); - let io = sys::process::Stdio::Fd(fd); - process::Stdio::from_inner(io) - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStdin { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStdout { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStderr { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStdin { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStdout { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStderr { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -/// Returns the OS-assigned process identifier associated with this process's parent. -#[stable(feature = "unix_ppid", since = "1.27.0")] -pub fn parent_id() -> u32 { - ::sys::os::getppid() -} diff --git a/ctr-std/src/sys/unix/ext/raw.rs b/ctr-std/src/sys/unix/ext/raw.rs deleted file mode 100644 index 7972990..0000000 --- a/ctr-std/src/sys/unix/ext/raw.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific primitives available on all unix platforms - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type uid_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type gid_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type pid_t = i32; - -#[doc(inline)] -#[stable(feature = "pthread_t", since = "1.8.0")] -pub use sys::platform::raw::pthread_t; -#[doc(inline)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub use sys::platform::raw::{dev_t, ino_t, mode_t, nlink_t, off_t, blksize_t}; -#[doc(inline)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub use sys::platform::raw::{blkcnt_t, time_t}; diff --git a/ctr-std/src/sys/unix/ext/thread.rs b/ctr-std/src/sys/unix/ext/thread.rs deleted file mode 100644 index 8dadf29..0000000 --- a/ctr-std/src/sys/unix/ext/thread.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific extensions to primitives in the `std::thread` module. - -#![stable(feature = "thread_extensions", since = "1.9.0")] - -#[allow(deprecated)] -use os::unix::raw::pthread_t; -use sys_common::{AsInner, IntoInner}; -use thread::JoinHandle; - -#[stable(feature = "thread_extensions", since = "1.9.0")] -#[allow(deprecated)] -pub type RawPthread = pthread_t; - -/// Unix-specific extensions to [`thread::JoinHandle`]. -/// -/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html -#[stable(feature = "thread_extensions", since = "1.9.0")] -pub trait JoinHandleExt { - /// Extracts the raw pthread_t without taking ownership - #[stable(feature = "thread_extensions", since = "1.9.0")] - fn as_pthread_t(&self) -> RawPthread; - - /// Consumes the thread, returning the raw pthread_t - /// - /// This function **transfers ownership** of the underlying pthread_t to - /// the caller. Callers are then the unique owners of the pthread_t and - /// must either detach or join the pthread_t once it's no longer needed. - #[stable(feature = "thread_extensions", since = "1.9.0")] - fn into_pthread_t(self) -> RawPthread; -} - -#[stable(feature = "thread_extensions", since = "1.9.0")] -impl JoinHandleExt for JoinHandle { - fn as_pthread_t(&self) -> RawPthread { - self.as_inner().id() as RawPthread - } - - fn into_pthread_t(self) -> RawPthread { - self.into_inner().into_id() as RawPthread - } -} diff --git a/ctr-std/src/sys/unix/fast_thread_local.rs b/ctr-std/src/sys/unix/fast_thread_local.rs deleted file mode 100644 index c13a0fe..0000000 --- a/ctr-std/src/sys/unix/fast_thread_local.rs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg(target_thread_local)] -#![unstable(feature = "thread_local_internals", issue = "0")] - -// Since what appears to be glibc 2.18 this symbol has been shipped which -// GCC and clang both use to invoke destructors in thread_local globals, so -// let's do the same! -// -// Note, however, that we run on lots older linuxes, as well as cross -// compiling from a newer linux to an older linux, so we also have a -// fallback implementation to use as well. -// -// Due to rust-lang/rust#18804, make sure this is not generic! -#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit"))] -pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - use libc; - use mem; - use sys_common::thread_local::register_dtor_fallback; - - extern { - #[linkage = "extern_weak"] - static __dso_handle: *mut u8; - #[linkage = "extern_weak"] - static __cxa_thread_atexit_impl: *const libc::c_void; - } - if !__cxa_thread_atexit_impl.is_null() { - type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), - arg: *mut u8, - dso_handle: *mut u8) -> libc::c_int; - mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) - (dtor, t, &__dso_handle as *const _ as *mut _); - return - } - register_dtor_fallback(t, dtor); -} - -// macOS's analog of the above linux function is this _tlv_atexit function. -// The disassembly of thread_local globals in C++ (at least produced by -// clang) will have this show up in the output. -#[cfg(target_os = "macos")] -pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - extern { - fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), - arg: *mut u8); - } - _tlv_atexit(dtor, t); -} - -pub fn requires_move_before_drop() -> bool { - // The macOS implementation of TLS apparently had an odd aspect to it - // where the pointer we have may be overwritten while this destructor - // is running. Specifically if a TLS destructor re-accesses TLS it may - // trigger a re-initialization of all TLS variables, paving over at - // least some destroyed ones with initial values. - // - // This means that if we drop a TLS value in place on macOS that we could - // revert the value to its original state halfway through the - // destructor, which would be bad! - // - // Hence, we use `ptr::read` on macOS (to move to a "safe" location) - // instead of drop_in_place. - cfg!(target_os = "macos") -} diff --git a/ctr-std/src/sys/unix/fd.rs b/ctr-std/src/sys/unix/fd.rs deleted file mode 100644 index 4830e38..0000000 --- a/ctr-std/src/sys/unix/fd.rs +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(reason = "not public", issue = "0", feature = "fd")] - -use cmp; -use io::{self, Read}; -use libc::{self, c_int, c_void, ssize_t}; -use mem; -use sync::atomic::{AtomicBool, Ordering}; -use sys::cvt; -use sys_common::AsInner; - -#[derive(Debug)] -pub struct FileDesc { - fd: c_int, -} - -fn max_len() -> usize { - // The maximum read limit on most posix-like systems is `SSIZE_MAX`, - // with the man page quoting that if the count of bytes to read is - // greater than `SSIZE_MAX` the result is "unspecified". - // - // On macOS, however, apparently the 64-bit libc is either buggy or - // intentionally showing odd behavior by rejecting any read with a size - // larger than or equal to INT_MAX. To handle both of these the read - // size is capped on both platforms. - if cfg!(target_os = "macos") { - ::max_value() as usize - 1 - } else { - ::max_value() as usize - } -} - -impl FileDesc { - pub fn new(fd: c_int) -> FileDesc { - FileDesc { fd: fd } - } - - pub fn raw(&self) -> c_int { self.fd } - - /// Extracts the actual filedescriptor without closing it. - pub fn into_raw(self) -> c_int { - let fd = self.fd; - mem::forget(self); - fd - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - let ret = cvt(unsafe { - libc::read(self.fd, - buf.as_mut_ptr() as *mut c_void, - cmp::min(buf.len(), max_len())) - })?; - Ok(ret as usize) - } - - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - let mut me = self; - (&mut me).read_to_end(buf) - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - #[cfg(target_os = "android")] - use super::android::cvt_pread64; - - #[cfg(target_os = "emscripten")] - unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) - -> io::Result - { - use convert::TryInto; - use libc::pread64; - // pread64 on emscripten actually takes a 32 bit offset - if let Ok(o) = offset.try_into() { - cvt(pread64(fd, buf, count, o)) - } else { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot pread >2GB")) - } - } - - #[cfg(not(any(target_os = "android", target_os = "emscripten")))] - unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) - -> io::Result - { - #[cfg(target_os = "linux")] - use libc::pread64; - #[cfg(not(target_os = "linux"))] - use libc::pread as pread64; - cvt(pread64(fd, buf, count, offset)) - } - - unsafe { - cvt_pread64(self.fd, - buf.as_mut_ptr() as *mut c_void, - cmp::min(buf.len(), max_len()), - offset as i64) - .map(|n| n as usize) - } - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - let ret = cvt(unsafe { - libc::write(self.fd, - buf.as_ptr() as *const c_void, - cmp::min(buf.len(), max_len())) - })?; - Ok(ret as usize) - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - #[cfg(target_os = "android")] - use super::android::cvt_pwrite64; - - #[cfg(target_os = "emscripten")] - unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) - -> io::Result - { - use convert::TryInto; - use libc::pwrite64; - // pwrite64 on emscripten actually takes a 32 bit offset - if let Ok(o) = offset.try_into() { - cvt(pwrite64(fd, buf, count, o)) - } else { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot pwrite >2GB")) - } - } - - #[cfg(not(any(target_os = "android", target_os = "emscripten")))] - unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) - -> io::Result - { - #[cfg(target_os = "linux")] - use libc::pwrite64; - #[cfg(not(target_os = "linux"))] - use libc::pwrite as pwrite64; - cvt(pwrite64(fd, buf, count, offset)) - } - - unsafe { - cvt_pwrite64(self.fd, - buf.as_ptr() as *const c_void, - cmp::min(buf.len(), max_len()), - offset as i64) - .map(|n| n as usize) - } - } - - #[cfg(target_os = "linux")] - pub fn get_cloexec(&self) -> io::Result { - unsafe { - Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) - } - } - - #[cfg(not(any(target_env = "newlib", - target_os = "solaris", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "l4re", - target_os = "haiku")))] - pub fn set_cloexec(&self) -> io::Result<()> { - unsafe { - cvt(libc::ioctl(self.fd, libc::FIOCLEX))?; - Ok(()) - } - } - #[cfg(any(target_env = "newlib", - target_os = "solaris", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "l4re", - target_os = "haiku"))] - pub fn set_cloexec(&self) -> io::Result<()> { - unsafe { - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?; - let new = previous | libc::FD_CLOEXEC; - if new != previous { - cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?; - } - Ok(()) - } - } - - #[cfg(target_os = "linux")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - unsafe { - let v = nonblocking as c_int; - cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?; - Ok(()) - } - } - - #[cfg(not(target_os = "linux"))] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - unsafe { - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?; - let new = if nonblocking { - previous | libc::O_NONBLOCK - } else { - previous & !libc::O_NONBLOCK - }; - if new != previous { - cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?; - } - Ok(()) - } - } - - pub fn duplicate(&self) -> io::Result { - // We want to atomically duplicate this file descriptor and set the - // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This - // flag, however, isn't supported on older Linux kernels (earlier than - // 2.6.24). - // - // To detect this and ensure that CLOEXEC is still set, we - // follow a strategy similar to musl [1] where if passing - // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not - // supported (the third parameter, 0, is always valid), so we stop - // trying that. - // - // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to - // resolve so we at least compile this. - // - // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963 - #[cfg(any(target_os = "android", target_os = "haiku"))] - use libc::F_DUPFD as F_DUPFD_CLOEXEC; - #[cfg(not(any(target_os = "android", target_os="haiku")))] - use libc::F_DUPFD_CLOEXEC; - - let make_filedesc = |fd| { - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - Ok(fd) - }; - static TRY_CLOEXEC: AtomicBool = - AtomicBool::new(!cfg!(target_os = "android")); - let fd = self.raw(); - if TRY_CLOEXEC.load(Ordering::Relaxed) { - match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) { - // We *still* call the `set_cloexec` method as apparently some - // linux kernel at some point stopped setting CLOEXEC even - // though it reported doing so on F_DUPFD_CLOEXEC. - Ok(fd) => { - return Ok(if cfg!(target_os = "linux") { - make_filedesc(fd)? - } else { - FileDesc::new(fd) - }) - } - Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => { - TRY_CLOEXEC.store(false, Ordering::Relaxed); - } - Err(e) => return Err(e), - } - } - cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc) - } -} - -impl<'a> Read for &'a FileDesc { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (**self).read(buf) - } -} - -impl AsInner for FileDesc { - fn as_inner(&self) -> &c_int { &self.fd } -} - -impl Drop for FileDesc { - fn drop(&mut self) { - // Note that errors are ignored when closing a file descriptor. The - // reason for this is that if an error occurs we don't actually know if - // the file descriptor was closed or not, and if we retried (for - // something like EINTR), we might close another valid file descriptor - // (opened after we closed ours. - let _ = unsafe { libc::close(self.fd) }; - } -} diff --git a/ctr-std/src/sys/unix/fs.rs b/ctr-std/src/sys/unix/fs.rs deleted file mode 100644 index 7a89d98..0000000 --- a/ctr-std/src/sys/unix/fs.rs +++ /dev/null @@ -1,945 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use os::unix::prelude::*; - -use ffi::{CString, CStr, OsString, OsStr}; -use fmt; -use io::{self, Error, ErrorKind, SeekFrom}; -use libc::{self, c_int, mode_t}; -use mem; -use path::{Path, PathBuf}; -use ptr; -use sync::Arc; -use sys::fd::FileDesc; -use sys::time::SystemTime; -use sys::{cvt, cvt_r}; -use sys_common::{AsInner, FromInner}; - -#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))] -use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64}; -#[cfg(any(target_os = "linux", target_os = "emscripten"))] -use libc::fstatat64; -#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] -use libc::dirfd; -#[cfg(target_os = "android")] -use libc::{stat as stat64, fstat as fstat64, fstatat as fstatat64, lstat as lstat64, lseek64, - dirent as dirent64, open as open64}; -#[cfg(not(any(target_os = "linux", - target_os = "emscripten", - target_os = "l4re", - target_os = "android")))] -use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t, - ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64}; -#[cfg(not(any(target_os = "linux", - target_os = "emscripten", - target_os = "solaris", - target_os = "l4re", - target_os = "fuchsia")))] -use libc::{readdir_r as readdir64_r}; - -pub struct File(FileDesc); - -#[derive(Clone)] -pub struct FileAttr { - stat: stat64, -} - -// all DirEntry's will have a reference to this struct -struct InnerReadDir { - dirp: Dir, - root: PathBuf, -} - -#[derive(Clone)] -pub struct ReadDir { - inner: Arc, - end_of_stream: bool, -} - -struct Dir(*mut libc::DIR); - -unsafe impl Send for Dir {} -unsafe impl Sync for Dir {} - -pub struct DirEntry { - entry: dirent64, - dir: ReadDir, - // We need to store an owned copy of the entry name - // on Solaris and Fuchsia because a) it uses a zero-length - // array to store the name, b) its lifetime between readdir - // calls is not guaranteed. - #[cfg(any(target_os = "solaris", target_os = "fuchsia"))] - name: Box<[u8]> -} - -#[derive(Clone, Debug)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - custom_flags: i32, - mode: mode_t, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct FilePermissions { mode: mode_t } - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct FileType { mode: mode_t } - -#[derive(Debug)] -pub struct DirBuilder { mode: mode_t } - -impl FileAttr { - pub fn size(&self) -> u64 { self.stat.st_size as u64 } - pub fn perm(&self) -> FilePermissions { - FilePermissions { mode: (self.stat.st_mode as mode_t) } - } - - pub fn file_type(&self) -> FileType { - FileType { mode: self.stat.st_mode as mode_t } - } -} - -#[cfg(target_os = "netbsd")] -impl FileAttr { - pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, - tv_nsec: self.stat.st_mtimensec as libc::c_long, - })) - } - - pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, - tv_nsec: self.stat.st_atimensec as libc::c_long, - })) - } - - pub fn created(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_birthtime as libc::time_t, - tv_nsec: self.stat.st_birthtimensec as libc::c_long, - })) - } -} - -#[cfg(not(target_os = "netbsd"))] -impl FileAttr { - pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, - tv_nsec: self.stat.st_mtime_nsec as _, - })) - } - - pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, - tv_nsec: self.stat.st_atime_nsec as _, - })) - } - - #[cfg(any(target_os = "bitrig", - target_os = "freebsd", - target_os = "openbsd", - target_os = "macos", - target_os = "ios"))] - pub fn created(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_birthtime as libc::time_t, - tv_nsec: self.stat.st_birthtime_nsec as libc::c_long, - })) - } - - #[cfg(not(any(target_os = "bitrig", - target_os = "freebsd", - target_os = "openbsd", - target_os = "macos", - target_os = "ios")))] - pub fn created(&self) -> io::Result { - Err(io::Error::new(io::ErrorKind::Other, - "creation time is not available on this platform \ - currently")) - } -} - -impl AsInner for FileAttr { - fn as_inner(&self) -> &stat64 { &self.stat } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - // check if any class (owner, group, others) has write permission - self.mode & 0o222 == 0 - } - - pub fn set_readonly(&mut self, readonly: bool) { - if readonly { - // remove write permission for all classes; equivalent to `chmod a-w ` - self.mode &= !0o222; - } else { - // add write permission for all classes; equivalent to `chmod a+w ` - self.mode |= 0o222; - } - } - pub fn mode(&self) -> u32 { self.mode as u32 } -} - -impl FileType { - pub fn is_dir(&self) -> bool { self.is(libc::S_IFDIR) } - pub fn is_file(&self) -> bool { self.is(libc::S_IFREG) } - pub fn is_symlink(&self) -> bool { self.is(libc::S_IFLNK) } - - pub fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode } -} - -impl FromInner for FilePermissions { - fn from_inner(mode: u32) -> FilePermissions { - FilePermissions { mode: mode as mode_t } - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. - // Thus the result will be e g 'ReadDir("/home")' - fmt::Debug::fmt(&*self.inner.root, f) - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - - #[cfg(any(target_os = "solaris", target_os = "fuchsia"))] - fn next(&mut self) -> Option> { - unsafe { - loop { - // Although readdir_r(3) would be a correct function to use here because - // of the thread safety, on Illumos and Fuchsia the readdir(3C) function - // is safe to use in threaded applications and it is generally preferred - // over the readdir_r(3C) function. - super::os::set_errno(0); - let entry_ptr = libc::readdir(self.inner.dirp.0); - if entry_ptr.is_null() { - // NULL can mean either the end is reached or an error occurred. - // So we had to clear errno beforehand to check for an error now. - return match super::os::errno() { - 0 => None, - e => Some(Err(Error::from_raw_os_error(e))), - } - } - - let name = (*entry_ptr).d_name.as_ptr(); - let namelen = libc::strlen(name) as usize; - - let ret = DirEntry { - entry: *entry_ptr, - name: ::slice::from_raw_parts(name as *const u8, - namelen as usize).to_owned().into_boxed_slice(), - dir: self.clone() - }; - if ret.name_bytes() != b"." && ret.name_bytes() != b".." { - return Some(Ok(ret)) - } - } - } - } - - #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))] - fn next(&mut self) -> Option> { - if self.end_of_stream { - return None; - } - - unsafe { - let mut ret = DirEntry { - entry: mem::zeroed(), - dir: self.clone(), - }; - let mut entry_ptr = ptr::null_mut(); - loop { - if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { - if entry_ptr.is_null() { - // We encountered an error (which will be returned in this iteration), but - // we also reached the end of the directory stream. The `end_of_stream` - // flag is enabled to make sure that we return `None` in the next iteration - // (instead of looping forever) - self.end_of_stream = true; - } - return Some(Err(Error::last_os_error())) - } - if entry_ptr.is_null() { - return None - } - if ret.name_bytes() != b"." && ret.name_bytes() != b".." { - return Some(Ok(ret)) - } - } - } - } -} - -impl Drop for Dir { - fn drop(&mut self) { - let r = unsafe { libc::closedir(self.0) }; - debug_assert_eq!(r, 0); - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes())) - } - - pub fn file_name(&self) -> OsString { - OsStr::from_bytes(self.name_bytes()).to_os_string() - } - - #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] - pub fn metadata(&self) -> io::Result { - let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { - fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW) - })?; - Ok(FileAttr { stat: stat }) - } - - #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))] - pub fn metadata(&self) -> io::Result { - lstat(&self.path()) - } - - #[cfg(any(target_os = "solaris", target_os = "haiku", target_os = "hermit"))] - pub fn file_type(&self) -> io::Result { - lstat(&self.path()).map(|m| m.file_type()) - } - - #[cfg(not(any(target_os = "solaris", target_os = "haiku", target_os = "hermit")))] - pub fn file_type(&self) -> io::Result { - match self.entry.d_type { - libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), - libc::DT_FIFO => Ok(FileType { mode: libc::S_IFIFO }), - libc::DT_LNK => Ok(FileType { mode: libc::S_IFLNK }), - libc::DT_REG => Ok(FileType { mode: libc::S_IFREG }), - libc::DT_SOCK => Ok(FileType { mode: libc::S_IFSOCK }), - libc::DT_DIR => Ok(FileType { mode: libc::S_IFDIR }), - libc::DT_BLK => Ok(FileType { mode: libc::S_IFBLK }), - _ => lstat(&self.path()).map(|m| m.file_type()), - } - } - - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "linux", - target_os = "emscripten", - target_os = "android", - target_os = "solaris", - target_os = "haiku", - target_os = "l4re", - target_os = "fuchsia", - target_os = "hermit"))] - pub fn ino(&self) -> u64 { - self.entry.d_ino as u64 - } - - #[cfg(any(target_os = "freebsd", - target_os = "openbsd", - target_os = "bitrig", - target_os = "netbsd", - target_os = "dragonfly"))] - pub fn ino(&self) -> u64 { - self.entry.d_fileno as u64 - } - - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig"))] - fn name_bytes(&self) -> &[u8] { - unsafe { - ::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8, - self.entry.d_namlen as usize) - } - } - #[cfg(any(target_os = "android", - target_os = "linux", - target_os = "emscripten", - target_os = "l4re", - target_os = "haiku", - target_os = "hermit"))] - fn name_bytes(&self) -> &[u8] { - unsafe { - CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() - } - } - #[cfg(any(target_os = "solaris", - target_os = "fuchsia"))] - fn name_bytes(&self) -> &[u8] { - &*self.name - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - custom_flags: 0, - mode: 0o666, - } - } - - pub fn read(&mut self, read: bool) { self.read = read; } - pub fn write(&mut self, write: bool) { self.write = write; } - pub fn append(&mut self, append: bool) { self.append = append; } - pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; } - pub fn create(&mut self, create: bool) { self.create = create; } - pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; } - - pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; } - pub fn mode(&mut self, mode: u32) { self.mode = mode as mode_t; } - - fn get_access_mode(&self) -> io::Result { - match (self.read, self.write, self.append) { - (true, false, false) => Ok(libc::O_RDONLY), - (false, true, false) => Ok(libc::O_WRONLY), - (true, true, false) => Ok(libc::O_RDWR), - (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND), - (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND), - (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)), - } - } - - fn get_creation_mode(&self) -> io::Result { - match (self.write, self.append) { - (true, false) => {} - (false, false) => - if self.truncate || self.create || self.create_new { - return Err(Error::from_raw_os_error(libc::EINVAL)); - }, - (_, true) => - if self.truncate && !self.create_new { - return Err(Error::from_raw_os_error(libc::EINVAL)); - }, - } - - Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => 0, - (true, false, false) => libc::O_CREAT, - (false, true, false) => libc::O_TRUNC, - (true, true, false) => libc::O_CREAT | libc::O_TRUNC, - (_, _, true) => libc::O_CREAT | libc::O_EXCL, - }) - } -} - -impl File { - pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let path = cstr(path)?; - File::open_c(&path, opts) - } - - pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result { - let flags = libc::O_CLOEXEC | - opts.get_access_mode()? | - opts.get_creation_mode()? | - (opts.custom_flags as c_int & !libc::O_ACCMODE); - let fd = cvt_r(|| unsafe { - open64(path.as_ptr(), flags, opts.mode as c_int) - })?; - let fd = FileDesc::new(fd); - - // Currently the standard library supports Linux 2.6.18 which did not - // have the O_CLOEXEC flag (passed above). If we're running on an older - // Linux kernel then the flag is just ignored by the OS. After we open - // the first file, we check whether it has CLOEXEC set. If it doesn't, - // we will explicitly ask for a CLOEXEC fd for every further file we - // open, if it does, we will skip that step. - // - // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc - // that we support, so we only do this on Linux currently. - #[cfg(target_os = "linux")] - fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> { - use sync::atomic::{AtomicUsize, Ordering}; - - const OPEN_CLOEXEC_UNKNOWN: usize = 0; - const OPEN_CLOEXEC_SUPPORTED: usize = 1; - const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2; - static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN); - - let need_to_set; - match OPEN_CLOEXEC.load(Ordering::Relaxed) { - OPEN_CLOEXEC_UNKNOWN => { - need_to_set = !fd.get_cloexec()?; - OPEN_CLOEXEC.store(if need_to_set { - OPEN_CLOEXEC_NOTSUPPORTED - } else { - OPEN_CLOEXEC_SUPPORTED - }, Ordering::Relaxed); - }, - OPEN_CLOEXEC_SUPPORTED => need_to_set = false, - OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true, - _ => unreachable!(), - } - if need_to_set { - fd.set_cloexec()?; - } - Ok(()) - } - - #[cfg(not(target_os = "linux"))] - fn ensure_cloexec(_: &FileDesc) -> io::Result<()> { - Ok(()) - } - - ensure_cloexec(&fd)?; - Ok(File(fd)) - } - - pub fn file_attr(&self) -> io::Result { - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { - fstat64(self.0.raw(), &mut stat) - })?; - Ok(FileAttr { stat: stat }) - } - - pub fn fsync(&self) -> io::Result<()> { - cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?; - Ok(()) - } - - pub fn datasync(&self) -> io::Result<()> { - cvt_r(|| unsafe { os_datasync(self.0.raw()) })?; - return Ok(()); - - #[cfg(any(target_os = "macos", target_os = "ios"))] - unsafe fn os_datasync(fd: c_int) -> c_int { - libc::fcntl(fd, libc::F_FULLFSYNC) - } - #[cfg(target_os = "linux")] - unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) } - #[cfg(not(any(target_os = "macos", - target_os = "ios", - target_os = "linux")))] - unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) } - } - - pub fn truncate(&self, size: u64) -> io::Result<()> { - #[cfg(target_os = "android")] - return ::sys::android::ftruncate64(self.0.raw(), size); - - #[cfg(not(target_os = "android"))] - return cvt_r(|| unsafe { - ftruncate64(self.0.raw(), size as off64_t) - }).map(|_| ()); - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - self.0.read_at(buf, offset) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - self.0.write_at(buf, offset) - } - - pub fn flush(&self) -> io::Result<()> { Ok(()) } - - pub fn seek(&self, pos: SeekFrom) -> io::Result { - let (whence, pos) = match pos { - // Casting to `i64` is fine, too large values will end up as - // negative which will cause an error in `lseek64`. - SeekFrom::Start(off) => (libc::SEEK_SET, off as i64), - SeekFrom::End(off) => (libc::SEEK_END, off), - SeekFrom::Current(off) => (libc::SEEK_CUR, off), - }; - #[cfg(target_os = "emscripten")] - let pos = pos as i32; - let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?; - Ok(n as u64) - } - - pub fn duplicate(&self) -> io::Result { - self.0.duplicate().map(File) - } - - pub fn fd(&self) -> &FileDesc { &self.0 } - - pub fn into_fd(self) -> FileDesc { self.0 } - - pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { - cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?; - Ok(()) - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder { mode: 0o777 } - } - - pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })?; - Ok(()) - } - - pub fn set_mode(&mut self, mode: u32) { - self.mode = mode as mode_t; - } -} - -fn cstr(path: &Path) -> io::Result { - Ok(CString::new(path.as_os_str().as_bytes())?) -} - -impl FromInner for File { - fn from_inner(fd: c_int) -> File { - File(FileDesc::new(fd)) - } -} - -impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - #[cfg(target_os = "linux")] - fn get_path(fd: c_int) -> Option { - let mut p = PathBuf::from("/proc/self/fd"); - p.push(&fd.to_string()); - readlink(&p).ok() - } - - #[cfg(target_os = "macos")] - fn get_path(fd: c_int) -> Option { - // FIXME: The use of PATH_MAX is generally not encouraged, but it - // is inevitable in this case because macOS defines `fcntl` with - // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no - // alternatives. If a better method is invented, it should be used - // instead. - let mut buf = vec![0;libc::PATH_MAX as usize]; - let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) }; - if n == -1 { - return None; - } - let l = buf.iter().position(|&c| c == 0).unwrap(); - buf.truncate(l as usize); - buf.shrink_to_fit(); - Some(PathBuf::from(OsString::from_vec(buf))) - } - - #[cfg(not(any(target_os = "linux", target_os = "macos")))] - fn get_path(_fd: c_int) -> Option { - // FIXME(#24570): implement this for other Unix platforms - None - } - - #[cfg(any(target_os = "linux", target_os = "macos"))] - fn get_mode(fd: c_int) -> Option<(bool, bool)> { - let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; - if mode == -1 { - return None; - } - match mode & libc::O_ACCMODE { - libc::O_RDONLY => Some((true, false)), - libc::O_RDWR => Some((true, true)), - libc::O_WRONLY => Some((false, true)), - _ => None - } - } - - #[cfg(not(any(target_os = "linux", target_os = "macos")))] - fn get_mode(_fd: c_int) -> Option<(bool, bool)> { - // FIXME(#24570): implement this for other Unix platforms - None - } - - let fd = self.0.raw(); - let mut b = f.debug_struct("File"); - b.field("fd", &fd); - if let Some(path) = get_path(fd) { - b.field("path", &path); - } - if let Some((read, write)) = get_mode(fd) { - b.field("read", &read).field("write", &write); - } - b.finish() - } -} - -pub fn readdir(p: &Path) -> io::Result { - let root = p.to_path_buf(); - let p = cstr(p)?; - unsafe { - let ptr = libc::opendir(p.as_ptr()); - if ptr.is_null() { - Err(Error::last_os_error()) - } else { - let inner = InnerReadDir { dirp: Dir(ptr), root }; - Ok(ReadDir{ - inner: Arc::new(inner), - end_of_stream: false, - }) - } - } -} - -pub fn unlink(p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::unlink(p.as_ptr()) })?; - Ok(()) -} - -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = cstr(old)?; - let new = cstr(new)?; - cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) })?; - Ok(()) -} - -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = cstr(p)?; - cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) })?; - Ok(()) -} - -pub fn rmdir(p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::rmdir(p.as_ptr()) })?; - Ok(()) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { - unlink(path) - } else { - remove_dir_all_recursive(path) - } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - -pub fn readlink(p: &Path) -> io::Result { - let c_path = cstr(p)?; - let p = c_path.as_ptr(); - - let mut buf = Vec::with_capacity(256); - - loop { - let buf_read = cvt(unsafe { - libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) - })? as usize; - - unsafe { buf.set_len(buf_read); } - - if buf_read != buf.capacity() { - buf.shrink_to_fit(); - - return Ok(PathBuf::from(OsString::from_vec(buf))); - } - - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. The length is guaranteed to be - // the same as the capacity due to the if statement above. - buf.reserve(1); - } -} - -pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; - cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })?; - Ok(()) -} - -pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; - cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?; - Ok(()) -} - -pub fn stat(p: &Path) -> io::Result { - let p = cstr(p)?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { - stat64(p.as_ptr(), &mut stat) - })?; - Ok(FileAttr { stat: stat }) -} - -pub fn lstat(p: &Path) -> io::Result { - let p = cstr(p)?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { - lstat64(p.as_ptr(), &mut stat) - })?; - Ok(FileAttr { stat: stat }) -} - -pub fn canonicalize(p: &Path) -> io::Result { - let path = CString::new(p.as_os_str().as_bytes())?; - let buf; - unsafe { - let r = libc::realpath(path.as_ptr(), ptr::null_mut()); - if r.is_null() { - return Err(io::Error::last_os_error()) - } - buf = CStr::from_ptr(r).to_bytes().to_vec(); - libc::free(r as *mut _); - } - Ok(PathBuf::from(OsString::from_vec(buf))) -} - -#[cfg(not(any(target_os = "linux", target_os = "android")))] -pub fn copy(from: &Path, to: &Path) -> io::Result { - use fs::File; - if !from.is_file() { - return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing regular file")) - } - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let perm = reader.metadata()?.permissions(); - - let ret = io::copy(&mut reader, &mut writer)?; - writer.set_permissions(perm)?; - Ok(ret) -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -pub fn copy(from: &Path, to: &Path) -> io::Result { - use cmp; - use fs::File; - use sync::atomic::{AtomicBool, Ordering}; - - // Kernel prior to 4.5 don't have copy_file_range - // We store the availability in a global to avoid unneccessary syscalls - static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true); - - unsafe fn copy_file_range( - fd_in: libc::c_int, - off_in: *mut libc::loff_t, - fd_out: libc::c_int, - off_out: *mut libc::loff_t, - len: libc::size_t, - flags: libc::c_uint, - ) -> libc::c_long { - libc::syscall( - libc::SYS_copy_file_range, - fd_in, - off_in, - fd_out, - off_out, - len, - flags, - ) - } - - if !from.is_file() { - return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing regular file")) - } - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let (perm, len) = { - let metadata = reader.metadata()?; - (metadata.permissions(), metadata.size()) - }; - - let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); - let mut written = 0u64; - while written < len { - let copy_result = if has_copy_file_range { - let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize; - let copy_result = unsafe { - // We actually don't have to adjust the offsets, - // because copy_file_range adjusts the file offset automatically - cvt(copy_file_range(reader.as_raw_fd(), - ptr::null_mut(), - writer.as_raw_fd(), - ptr::null_mut(), - bytes_to_copy, - 0) - ) - }; - if let Err(ref copy_err) = copy_result { - match copy_err.raw_os_error() { - Some(libc::ENOSYS) | Some(libc::EPERM) => { - HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); - } - _ => {} - } - } - copy_result - } else { - Err(io::Error::from_raw_os_error(libc::ENOSYS)) - }; - match copy_result { - Ok(ret) => written += ret as u64, - Err(err) => { - match err.raw_os_error() { - Some(os_err) if os_err == libc::ENOSYS - || os_err == libc::EXDEV - || os_err == libc::EPERM => { - // Try fallback io::copy if either: - // - Kernel version is < 4.5 (ENOSYS) - // - Files are mounted on different fs (EXDEV) - // - copy_file_range is disallowed, for example by seccomp (EPERM) - assert_eq!(written, 0); - let ret = io::copy(&mut reader, &mut writer)?; - writer.set_permissions(perm)?; - return Ok(ret) - }, - _ => return Err(err), - } - } - } - } - writer.set_permissions(perm)?; - Ok(written) -} diff --git a/ctr-std/src/sys/unix/l4re.rs b/ctr-std/src/sys/unix/l4re.rs deleted file mode 100644 index 2121848..0000000 --- a/ctr-std/src/sys/unix/l4re.rs +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright 2016-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -macro_rules! unimpl { - () => (return Err(io::Error::new(io::ErrorKind::Other, "No networking available on L4Re."));) -} - -pub mod net { - #![allow(warnings)] - use fmt; - use io; - use libc; - use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; - use sys_common::{AsInner, FromInner, IntoInner}; - use sys::fd::FileDesc; - use time::Duration; - - - pub extern crate libc as netc; - - pub struct Socket(FileDesc); - impl Socket { - pub fn new(_: &SocketAddr, _: libc::c_int) -> io::Result { - unimpl!(); - } - - pub fn new_raw(_: libc::c_int, _: libc::c_int) -> io::Result { - unimpl!(); - } - - pub fn new_pair(_: libc::c_int, _: libc::c_int) -> io::Result<(Socket, Socket)> { - unimpl!(); - } - - pub fn connect_timeout(&self, _: &SocketAddr, _: Duration) -> io::Result<()> { - unimpl!(); - } - - pub fn accept(&self, _: *mut libc::sockaddr, _: *mut libc::socklen_t) - -> io::Result { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn write(&self, _: &[u8]) -> io::Result { - unimpl!(); - } - - pub fn set_timeout(&self, _: Option, _: libc::c_int) -> io::Result<()> { - unimpl!(); - } - - pub fn timeout(&self, _: libc::c_int) -> io::Result> { - unimpl!(); - } - - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - unimpl!(); - } - - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn nodelay(&self) -> io::Result { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - } - - impl AsInner for Socket { - fn as_inner(&self) -> &libc::c_int { self.0.as_inner() } - } - - impl FromInner for Socket { - fn from_inner(fd: libc::c_int) -> Socket { Socket(FileDesc::new(fd)) } - } - - impl IntoInner for Socket { - fn into_inner(self) -> libc::c_int { self.0.into_raw() } - } - - pub struct TcpStream { - inner: Socket, - } - - impl TcpStream { - pub fn connect(_: &SocketAddr) -> io::Result { - unimpl!(); - } - - pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { - unimpl!(); - } - - pub fn socket(&self) -> &Socket { &self.inner } - - pub fn into_socket(self) -> Socket { self.inner } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn read_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn write_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn write(&self, _: &[u8]) -> io::Result { - unimpl!(); - } - - pub fn peer_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn socket_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn nodelay(&self) -> io::Result { - unimpl!(); - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn ttl(&self) -> io::Result { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - } - - impl FromInner for TcpStream { - fn from_inner(socket: Socket) -> TcpStream { - TcpStream { inner: socket } - } - } - - impl fmt::Debug for TcpStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "No networking support available on L4Re") - } - } - - pub struct TcpListener { - inner: Socket, - } - - impl TcpListener { - pub fn bind(_: &SocketAddr) -> io::Result { - unimpl!(); - } - - pub fn socket(&self) -> &Socket { &self.inner } - - pub fn into_socket(self) -> Socket { self.inner } - - pub fn socket_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn ttl(&self) -> io::Result { - unimpl!(); - } - - pub fn set_only_v6(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn only_v6(&self) -> io::Result { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - } - - impl FromInner for TcpListener { - fn from_inner(socket: Socket) -> TcpListener { - TcpListener { inner: socket } - } - } - - impl fmt::Debug for TcpListener { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "No networking support available on L4Re.") - } - } - - pub struct UdpSocket { - inner: Socket, - } - - impl UdpSocket { - pub fn bind(_: &SocketAddr) -> io::Result { - unimpl!(); - } - - pub fn socket(&self) -> &Socket { &self.inner } - - pub fn into_socket(self) -> Socket { self.inner } - - pub fn socket_addr(&self) -> io::Result { - unimpl!(); - } - - pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - unimpl!(); - } - - pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { - unimpl!(); - } - - pub fn duplicate(&self) -> io::Result { - unimpl!(); - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - unimpl!(); - } - - pub fn read_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn write_timeout(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_broadcast(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn broadcast(&self) -> io::Result { - unimpl!(); - } - - pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn multicast_loop_v4(&self) -> io::Result { - unimpl!(); - } - - pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - unimpl!(); - } - - pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn multicast_loop_v6(&self) -> io::Result { - unimpl!(); - } - - pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) - -> io::Result<()> { - unimpl!(); - } - - pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) - -> io::Result<()> { - unimpl!(); - } - - pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) - -> io::Result<()> { - unimpl!(); - } - - pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) - -> io::Result<()> { - unimpl!(); - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - unimpl!(); - } - - pub fn ttl(&self) -> io::Result { - unimpl!(); - } - - pub fn take_error(&self) -> io::Result> { - unimpl!(); - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unimpl!(); - } - - pub fn recv(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - unimpl!(); - } - - pub fn send(&self, _: &[u8]) -> io::Result { - unimpl!(); - } - - pub fn connect(&self, _: &SocketAddr) -> io::Result<()> { - unimpl!(); - } - } - - impl FromInner for UdpSocket { - fn from_inner(socket: Socket) -> UdpSocket { - UdpSocket { inner: socket } - } - } - - impl fmt::Debug for UdpSocket { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "No networking support on L4Re available.") - } - } - - pub struct LookupHost { - original: *mut libc::addrinfo, - cur: *mut libc::addrinfo, - } - - impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option { - None - } - } - - unsafe impl Sync for LookupHost {} - unsafe impl Send for LookupHost {} - - pub fn lookup_host(_: &str) -> io::Result { - unimpl!(); - } -} - diff --git a/ctr-std/src/sys/unix/memchr.rs b/ctr-std/src/sys/unix/memchr.rs deleted file mode 100644 index f49adc2..0000000 --- a/ctr-std/src/sys/unix/memchr.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// Original implementation taken from rust-memchr -// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch - -pub fn memchr(needle: u8, haystack: &[u8]) -> Option { - use libc; - - let p = unsafe { - libc::memchr( - haystack.as_ptr() as *const libc::c_void, - needle as libc::c_int, - haystack.len()) - }; - if p.is_null() { - None - } else { - Some(p as usize - (haystack.as_ptr() as usize)) - } -} - -pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { - - #[cfg(target_os = "linux")] - fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option { - use libc; - - // GNU's memrchr() will - unlike memchr() - error if haystack is empty. - if haystack.is_empty() {return None} - let p = unsafe { - libc::memrchr( - haystack.as_ptr() as *const libc::c_void, - needle as libc::c_int, - haystack.len()) - }; - if p.is_null() { - None - } else { - Some(p as usize - (haystack.as_ptr() as usize)) - } - } - - #[cfg(not(target_os = "linux"))] - fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option { - ::core::slice::memchr::memrchr(needle, haystack) - } - - memrchr_specific(needle, haystack) -} diff --git a/ctr-std/src/sys/unix/mod.rs b/ctr-std/src/sys/unix/mod.rs deleted file mode 100644 index c738003..0000000 --- a/ctr-std/src/sys/unix/mod.rs +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(missing_docs, bad_style)] - -use io::{self, ErrorKind}; -use libc; - -#[cfg(any(dox, target_os = "linux"))] pub use os::linux as platform; - -#[cfg(all(not(dox), target_os = "android"))] pub use os::android as platform; -#[cfg(all(not(dox), target_os = "bitrig"))] pub use os::bitrig as platform; -#[cfg(all(not(dox), target_os = "dragonfly"))] pub use os::dragonfly as platform; -#[cfg(all(not(dox), target_os = "freebsd"))] pub use os::freebsd as platform; -#[cfg(all(not(dox), target_os = "haiku"))] pub use os::haiku as platform; -#[cfg(all(not(dox), target_os = "ios"))] pub use os::ios as platform; -#[cfg(all(not(dox), target_os = "macos"))] pub use os::macos as platform; -#[cfg(all(not(dox), target_os = "netbsd"))] pub use os::netbsd as platform; -#[cfg(all(not(dox), target_os = "openbsd"))] pub use os::openbsd as platform; -#[cfg(all(not(dox), target_os = "solaris"))] pub use os::solaris as platform; -#[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform; -#[cfg(all(not(dox), target_os = "fuchsia"))] pub use os::fuchsia as platform; -#[cfg(all(not(dox), target_os = "l4re"))] pub use os::linux as platform; -#[cfg(all(not(dox), target_os = "hermit"))] pub use os::hermit as platform; - -pub use self::rand::hashmap_random_keys; -pub use libc::strlen; - -#[macro_use] -pub mod weak; - -pub mod args; -pub mod android; -#[cfg(feature = "backtrace")] -pub mod backtrace; -pub mod cmath; -pub mod condvar; -pub mod env; -pub mod ext; -pub mod fast_thread_local; -pub mod fd; -pub mod fs; -pub mod memchr; -pub mod mutex; -#[cfg(not(target_os = "l4re"))] -pub mod net; -#[cfg(target_os = "l4re")] -mod l4re; -#[cfg(target_os = "l4re")] -pub use self::l4re::net; -pub mod os; -pub mod os_str; -pub mod path; -pub mod pipe; -pub mod process; -pub mod rand; -pub mod rwlock; -pub mod stack_overflow; -pub mod thread; -pub mod thread_local; -pub mod time; -pub mod stdio; - -#[cfg(not(test))] -pub fn init() { - // By default, some platforms will send a *signal* when an EPIPE error - // would otherwise be delivered. This runtime doesn't install a SIGPIPE - // handler, causing it to kill the program, which isn't exactly what we - // want! - // - // Hence, we set SIGPIPE to ignore when the program starts up in order - // to prevent this problem. - unsafe { - reset_sigpipe(); - } - - #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] - unsafe fn reset_sigpipe() { - assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); - } - #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))] - unsafe fn reset_sigpipe() {} -} - -#[cfg(target_os = "android")] -pub use sys::android::signal; -#[cfg(not(target_os = "android"))] -pub use libc::signal; - -pub fn decode_error_kind(errno: i32) -> ErrorKind { - match errno as libc::c_int { - libc::ECONNREFUSED => ErrorKind::ConnectionRefused, - libc::ECONNRESET => ErrorKind::ConnectionReset, - libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied, - libc::EPIPE => ErrorKind::BrokenPipe, - libc::ENOTCONN => ErrorKind::NotConnected, - libc::ECONNABORTED => ErrorKind::ConnectionAborted, - libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, - libc::EADDRINUSE => ErrorKind::AddrInUse, - libc::ENOENT => ErrorKind::NotFound, - libc::EINTR => ErrorKind::Interrupted, - libc::EINVAL => ErrorKind::InvalidInput, - libc::ETIMEDOUT => ErrorKind::TimedOut, - libc::EEXIST => ErrorKind::AlreadyExists, - - // These two constants can have the same value on some systems, - // but different values on others, so we can't use a match - // clause - x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => - ErrorKind::WouldBlock, - - _ => ErrorKind::Other, - } -} - -#[doc(hidden)] -pub trait IsMinusOne { - fn is_minus_one(&self) -> bool; -} - -macro_rules! impl_is_minus_one { - ($($t:ident)*) => ($(impl IsMinusOne for $t { - fn is_minus_one(&self) -> bool { - *self == -1 - } - })*) -} - -impl_is_minus_one! { i8 i16 i32 i64 isize } - -pub fn cvt(t: T) -> io::Result { - if t.is_minus_one() { - Err(io::Error::last_os_error()) - } else { - Ok(t) - } -} - -pub fn cvt_r(mut f: F) -> io::Result - where T: IsMinusOne, - F: FnMut() -> T -{ - loop { - match cvt(f()) { - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - other => return other, - } - } -} - -// On Unix-like platforms, libc::abort will unregister signal handlers -// including the SIGABRT handler, preventing the abort from being blocked, and -// fclose streams, with the side effect of flushing them so libc bufferred -// output will be printed. Additionally the shell will generally print a more -// understandable error message like "Abort trap" rather than "Illegal -// instruction" that intrinsics::abort would cause, as intrinsics::abort is -// implemented as an illegal instruction. -pub unsafe fn abort_internal() -> ! { - ::libc::abort() -} diff --git a/ctr-std/src/sys/unix/mutex.rs b/ctr-std/src/sys/unix/mutex.rs deleted file mode 100644 index 1d447de..0000000 --- a/ctr-std/src/sys/unix/mutex.rs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use libc; -use mem; - -pub struct Mutex { inner: UnsafeCell } - -#[inline] -pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { - m.inner.get() -} - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} - -#[allow(dead_code)] // sys isn't exported yet -impl Mutex { - pub const fn new() -> Mutex { - // Might be moved to a different address, so it is better to avoid - // initialization of potentially opaque OS data before it landed. - // Be very careful using this newly constructed `Mutex`, reentrant - // locking is undefined behavior until `init` is called! - Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } - } - #[inline] - pub unsafe fn init(&mut self) { - // Issue #33770 - // - // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have - // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you - // try to re-lock it from the same thread when you already hold a lock. - // - // In practice, glibc takes advantage of this undefined behavior to - // implement hardware lock elision, which uses hardware transactional - // memory to avoid acquiring the lock. While a transaction is in - // progress, the lock appears to be unlocked. This isn't a problem for - // other threads since the transactional memory will abort if a conflict - // is detected, however no abort is generated if re-locking from the - // same thread. - // - // Since locking the same mutex twice will result in two aliasing &mut - // references, we instead create the mutex with type - // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to - // re-lock it from the same thread, thus avoiding undefined behavior. - let mut attr: libc::pthread_mutexattr_t = mem::uninitialized(); - let r = libc::pthread_mutexattr_init(&mut attr); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_settype(&mut attr, libc::PTHREAD_MUTEX_NORMAL); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutex_init(self.inner.get(), &attr); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_destroy(&mut attr); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn lock(&self) { - let r = libc::pthread_mutex_lock(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn unlock(&self) { - let r = libc::pthread_mutex_unlock(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn try_lock(&self) -> bool { - libc::pthread_mutex_trylock(self.inner.get()) == 0 - } - #[inline] - #[cfg(not(target_os = "dragonfly"))] - pub unsafe fn destroy(&self) { - let r = libc::pthread_mutex_destroy(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - #[cfg(target_os = "dragonfly")] - pub unsafe fn destroy(&self) { - use libc; - let r = libc::pthread_mutex_destroy(self.inner.get()); - // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a - // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. - // Once it is used (locked/unlocked) or pthread_mutex_init() is called, - // this behaviour no longer occurs. - debug_assert!(r == 0 || r == libc::EINVAL); - } -} - -pub struct ReentrantMutex { inner: UnsafeCell } - -unsafe impl Send for ReentrantMutex {} -unsafe impl Sync for ReentrantMutex {} - -impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: mem::uninitialized() } - } - - pub unsafe fn init(&mut self) { - let mut attr: libc::pthread_mutexattr_t = mem::uninitialized(); - let result = libc::pthread_mutexattr_init(&mut attr as *mut _); - debug_assert_eq!(result, 0); - let result = libc::pthread_mutexattr_settype(&mut attr as *mut _, - libc::PTHREAD_MUTEX_RECURSIVE); - debug_assert_eq!(result, 0); - let result = libc::pthread_mutex_init(self.inner.get(), &attr as *const _); - debug_assert_eq!(result, 0); - let result = libc::pthread_mutexattr_destroy(&mut attr as *mut _); - debug_assert_eq!(result, 0); - } - - pub unsafe fn lock(&self) { - let result = libc::pthread_mutex_lock(self.inner.get()); - debug_assert_eq!(result, 0); - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - libc::pthread_mutex_trylock(self.inner.get()) == 0 - } - - pub unsafe fn unlock(&self) { - let result = libc::pthread_mutex_unlock(self.inner.get()); - debug_assert_eq!(result, 0); - } - - pub unsafe fn destroy(&self) { - let result = libc::pthread_mutex_destroy(self.inner.get()); - debug_assert_eq!(result, 0); - } -} diff --git a/ctr-std/src/sys/unix/net.rs b/ctr-std/src/sys/unix/net.rs deleted file mode 100644 index 04d9f0b..0000000 --- a/ctr-std/src/sys/unix/net.rs +++ /dev/null @@ -1,424 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::CStr; -use io; -use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK}; -use mem; -use net::{SocketAddr, Shutdown}; -use str; -use sys::fd::FileDesc; -use sys_common::{AsInner, FromInner, IntoInner}; -use sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; -use time::{Duration, Instant}; -use cmp; - -pub use sys::{cvt, cvt_r}; -pub extern crate libc as netc; - -pub type wrlen_t = size_t; - -// See below for the usage of SOCK_CLOEXEC, but this constant is only defined on -// Linux currently (e.g. support doesn't exist on other platforms). In order to -// get name resolution to work and things to compile we just define a dummy -// SOCK_CLOEXEC here for other platforms. Note that the dummy constant isn't -// actually ever used (the blocks below are wrapped in `if cfg!` as well. -#[cfg(target_os = "linux")] -use libc::SOCK_CLOEXEC; -#[cfg(not(target_os = "linux"))] -const SOCK_CLOEXEC: c_int = 0; - -// Another conditional contant for name resolution: Macos et iOS use -// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket. -// Other platforms do otherwise. -#[cfg(target_vendor = "apple")] -use libc::SO_NOSIGPIPE; -#[cfg(not(target_vendor = "apple"))] -const SO_NOSIGPIPE: c_int = 0; - -pub struct Socket(FileDesc); - -pub fn init() {} - -pub fn cvt_gai(err: c_int) -> io::Result<()> { - if err == 0 { - return Ok(()) - } - - // We may need to trigger a glibc workaround. See on_resolver_failure() for details. - on_resolver_failure(); - - if err == EAI_SYSTEM { - return Err(io::Error::last_os_error()) - } - - let detail = unsafe { - str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap() - .to_owned() - }; - Err(io::Error::new(io::ErrorKind::Other, - &format!("failed to lookup address information: {}", - detail)[..])) -} - -impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => libc::AF_INET, - SocketAddr::V6(..) => libc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { - unsafe { - // On linux we first attempt to pass the SOCK_CLOEXEC flag to - // atomically create the socket and set it as CLOEXEC. Support for - // this option, however, was added in 2.6.27, and we still support - // 2.6.18 as a kernel, so if the returned error is EINVAL we - // fallthrough to the fallback. - if cfg!(target_os = "linux") { - match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) { - Ok(fd) => return Ok(Socket(FileDesc::new(fd))), - Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} - Err(e) => return Err(e), - } - } - - let fd = cvt(libc::socket(fam, ty, 0))?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - let socket = Socket(fd); - if cfg!(target_vendor = "apple") { - setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?; - } - Ok(socket) - } - } - - pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> { - unsafe { - let mut fds = [0, 0]; - - // Like above, see if we can set cloexec atomically - if cfg!(target_os = "linux") { - match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) { - Ok(_) => { - return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1])))); - } - Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}, - Err(e) => return Err(e), - } - } - - cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?; - let a = FileDesc::new(fds[0]); - let b = FileDesc::new(fds[1]); - a.set_cloexec()?; - b.set_cloexec()?; - Ok((Socket(a), Socket(b))) - } - } - - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = unsafe { - let (addrp, len) = addr.into_inner(); - cvt(libc::connect(self.0.raw(), addrp, len)) - }; - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS :( - Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} - Err(e) => return Err(e), - } - - let mut pollfd = libc::pollfd { - fd: self.0.raw(), - events: libc::POLLOUT, - revents: 0, - }; - - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout")); - } - - let start = Instant::now(); - - loop { - let elapsed = start.elapsed(); - if elapsed >= timeout { - return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")); - } - - let timeout = timeout - elapsed; - let mut timeout = timeout.as_secs() - .saturating_mul(1_000) - .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); - if timeout == 0 { - timeout = 1; - } - - let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int; - - match unsafe { libc::poll(&mut pollfd, 1, timeout) } { - -1 => { - let err = io::Error::last_os_error(); - if err.kind() != io::ErrorKind::Interrupted { - return Err(err); - } - } - 0 => {} - _ => { - // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look - // for POLLHUP rather than read readiness - if pollfd.revents & libc::POLLHUP != 0 { - let e = self.take_error()? - .unwrap_or_else(|| { - io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") - }); - return Err(e); - } - - return Ok(()); - } - } - } - } - - pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) - -> io::Result { - // Unfortunately the only known way right now to accept a socket and - // atomically set the CLOEXEC flag is to use the `accept4` syscall on - // Linux. This was added in 2.6.28, however, and because we support - // 2.6.18 we must detect this support dynamically. - if cfg!(target_os = "linux") { - weak! { - fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int - } - if let Some(accept) = accept4.get() { - let res = cvt_r(|| unsafe { - accept(self.0.raw(), storage, len, SOCK_CLOEXEC) - }); - match res { - Ok(fd) => return Ok(Socket(FileDesc::new(fd))), - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} - Err(e) => return Err(e), - } - } - } - - let fd = cvt_r(|| unsafe { - libc::accept(self.0.raw(), storage, len) - })?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - Ok(Socket(fd)) - } - - pub fn duplicate(&self) -> io::Result { - self.0.duplicate().map(Socket) - } - - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { - let ret = cvt(unsafe { - libc::recv(self.0.raw(), - buf.as_mut_ptr() as *mut c_void, - buf.len(), - flags) - })?; - Ok(ret as usize) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, 0) - } - - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, MSG_PEEK) - } - - fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int) - -> io::Result<(usize, SocketAddr)> { - let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t; - - let n = cvt(unsafe { - libc::recvfrom(self.0.raw(), - buf.as_mut_ptr() as *mut c_void, - buf.len(), - flags, - &mut storage as *mut _ as *mut _, - &mut addrlen) - })?; - Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) - } - - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, 0) - } - - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, MSG_PEEK) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn set_timeout(&self, dur: Option, kind: libc::c_int) -> io::Result<()> { - let timeout = match dur { - Some(dur) => { - if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout")); - } - - let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { - libc::time_t::max_value() - } else { - dur.as_secs() as libc::time_t - }; - let mut timeout = libc::timeval { - tv_sec: secs, - tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, - }; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } - timeout - } - None => { - libc::timeval { - tv_sec: 0, - tv_usec: 0, - } - } - }; - setsockopt(self, libc::SOL_SOCKET, kind, timeout) - } - - pub fn timeout(&self, kind: libc::c_int) -> io::Result> { - let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?; - if raw.tv_sec == 0 && raw.tv_usec == 0 { - Ok(None) - } else { - let sec = raw.tv_sec as u64; - let nsec = (raw.tv_usec as u32) * 1000; - Ok(Some(Duration::new(sec, nsec))) - } - } - - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - let how = match how { - Shutdown::Write => libc::SHUT_WR, - Shutdown::Read => libc::SHUT_RD, - Shutdown::Both => libc::SHUT_RDWR, - }; - cvt(unsafe { libc::shutdown(self.0.raw(), how) })?; - Ok(()) - } - - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) - } - - pub fn nodelay(&self) -> io::Result { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?; - Ok(raw != 0) - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as libc::c_int; - cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(|_| ()) - } - - pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; - if raw == 0 { - Ok(None) - } else { - Ok(Some(io::Error::from_raw_os_error(raw as i32))) - } - } -} - -impl AsInner for Socket { - fn as_inner(&self) -> &c_int { self.0.as_inner() } -} - -impl FromInner for Socket { - fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) } -} - -impl IntoInner for Socket { - fn into_inner(self) -> c_int { self.0.into_raw() } -} - -// In versions of glibc prior to 2.26, there's a bug where the DNS resolver -// will cache the contents of /etc/resolv.conf, so changes to that file on disk -// can be ignored by a long-running program. That can break DNS lookups on e.g. -// laptops where the network comes and goes. See -// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some -// distros including Debian have patched glibc to fix this for a long time. -// -// A workaround for this bug is to call the res_init libc function, to clear -// the cached configs. Unfortunately, while we believe glibc's implementation -// of res_init is thread-safe, we know that other implementations are not -// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could -// try to synchronize its res_init calls with a Mutex, but that wouldn't -// protect programs that call into libc in other ways. So instead of calling -// res_init unconditionally, we call it only when we detect we're linking -// against glibc version < 2.26. (That is, when we both know its needed and -// believe it's thread-safe). -#[cfg(target_env = "gnu")] -fn on_resolver_failure() { - use sys; - - // If the version fails to parse, we treat it the same as "not glibc". - if let Some(version) = sys::os::glibc_version() { - if version < (2, 26) { - unsafe { libc::res_init() }; - } - } -} - -#[cfg(not(target_env = "gnu"))] -fn on_resolver_failure() {} - -#[cfg(all(test, taget_env = "gnu"))] -mod test { - use super::*; - - #[test] - fn test_res_init() { - // This mostly just tests that the weak linkage doesn't panic wildly... - res_init_if_glibc_before_2_26().unwrap(); - } - - #[test] - fn test_parse_glibc_version() { - let cases = [ - ("0.0", Some((0, 0))), - ("01.+2", Some((1, 2))), - ("3.4.5.six", Some((3, 4))), - ("1", None), - ("1.-2", None), - ("1.foo", None), - ("foo.1", None), - ]; - for &(version_str, parsed) in cases.iter() { - assert_eq!(parsed, parse_glibc_version(version_str)); - } - } -} diff --git a/ctr-std/src/sys/unix/os.rs b/ctr-std/src/sys/unix/os.rs deleted file mode 100644 index f8f0bbd..0000000 --- a/ctr-std/src/sys/unix/os.rs +++ /dev/null @@ -1,571 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation of `std::os` functionality for unix systems - -#![allow(unused_imports)] // lots of cfg code here - -use os::unix::prelude::*; - -use error::Error as StdError; -use ffi::{CString, CStr, OsString, OsStr}; -use fmt; -use io; -use iter; -use libc::{self, c_int, c_char, c_void}; -use marker::PhantomData; -use mem; -use memchr; -use path::{self, PathBuf}; -use ptr; -use slice; -use str; -use sys_common::mutex::Mutex; -use sys::cvt; -use sys::fd; -use vec; - -const TMPBUF_SZ: usize = 128; -// We never call `ENV_LOCK.init()`, so it is UB to attempt to -// acquire this mutex reentrantly! -static ENV_LOCK: Mutex = Mutex::new(); - - -extern { - #[cfg(not(target_os = "dragonfly"))] - #[cfg_attr(any(target_os = "linux", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "l4re"), - link_name = "__errno_location")] - #[cfg_attr(any(target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd", - target_os = "android", - target_os = "hermit", - target_env = "newlib"), - link_name = "__errno")] - #[cfg_attr(target_os = "solaris", link_name = "___errno")] - #[cfg_attr(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd"), - link_name = "__error")] - #[cfg_attr(target_os = "haiku", link_name = "_errnop")] - fn errno_location() -> *mut c_int; -} - -/// Returns the platform-specific value of errno -#[cfg(not(target_os = "dragonfly"))] -pub fn errno() -> i32 { - unsafe { - (*errno_location()) as i32 - } -} - -/// Sets the platform-specific value of errno -#[cfg(any(target_os = "solaris", target_os = "fuchsia"))] // only needed for readdir so far -pub fn set_errno(e: i32) { - unsafe { - *errno_location() = e as c_int - } -} - -#[cfg(target_os = "dragonfly")] -pub fn errno() -> i32 { - extern { - #[thread_local] - static errno: c_int; - } - - unsafe { errno as i32 } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(errno: i32) -> String { - extern { - #[cfg_attr(any(target_os = "linux", target_env = "newlib"), - link_name = "__xpg_strerror_r")] - fn strerror_r(errnum: c_int, buf: *mut c_char, - buflen: libc::size_t) -> c_int; - } - - let mut buf = [0 as c_char; TMPBUF_SZ]; - - let p = buf.as_mut_ptr(); - unsafe { - if strerror_r(errno as c_int, p, buf.len()) < 0 { - panic!("strerror_r failure"); - } - - let p = p as *const _; - str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() - } -} - -pub fn getcwd() -> io::Result { - let mut buf = Vec::with_capacity(512); - loop { - unsafe { - let ptr = buf.as_mut_ptr() as *mut libc::c_char; - if !libc::getcwd(ptr, buf.capacity()).is_null() { - let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len(); - buf.set_len(len); - buf.shrink_to_fit(); - return Ok(PathBuf::from(OsString::from_vec(buf))); - } else { - let error = io::Error::last_os_error(); - if error.raw_os_error() != Some(libc::ERANGE) { - return Err(error); - } - } - - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. - let cap = buf.capacity(); - buf.set_len(cap); - buf.reserve(1); - } - } -} - -pub fn chdir(p: &path::Path) -> io::Result<()> { - let p: &OsStr = p.as_ref(); - let p = CString::new(p.as_bytes())?; - unsafe { - match libc::chdir(p.as_ptr()) == (0 as c_int) { - true => Ok(()), - false => Err(io::Error::last_os_error()), - } - } -} - -pub struct SplitPaths<'a> { - iter: iter::Map bool>, - fn(&'a [u8]) -> PathBuf>, -} - -pub fn split_paths(unparsed: &OsStr) -> SplitPaths { - fn bytes_to_path(b: &[u8]) -> PathBuf { - PathBuf::from(::from_bytes(b)) - } - fn is_colon(b: &u8) -> bool { *b == b':' } - let unparsed = unparsed.as_bytes(); - SplitPaths { - iter: unparsed.split(is_colon as fn(&u8) -> bool) - .map(bytes_to_path as fn(&[u8]) -> PathBuf) - } -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { self.iter.next() } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(paths: I) -> Result - where I: Iterator, T: AsRef -{ - let mut joined = Vec::new(); - let sep = b':'; - - for (i, path) in paths.enumerate() { - let path = path.as_ref().as_bytes(); - if i > 0 { joined.push(sep) } - if path.contains(&sep) { - return Err(JoinPathsError) - } - joined.extend_from_slice(path); - } - Ok(OsStringExt::from_vec(joined)) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "path segment contains separator `:`".fmt(f) - } -} - -impl StdError for JoinPathsError { - fn description(&self) -> &str { "failed to join paths" } -} - -#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] -pub fn current_exe() -> io::Result { - unsafe { - let mut mib = [libc::CTL_KERN as c_int, - libc::KERN_PROC as c_int, - libc::KERN_PROC_PATHNAME as c_int, - -1 as c_int]; - let mut sz = 0; - cvt(libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint, - ptr::null_mut(), &mut sz, ptr::null_mut(), 0))?; - if sz == 0 { - return Err(io::Error::last_os_error()) - } - let mut v: Vec = Vec::with_capacity(sz); - cvt(libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint, - v.as_mut_ptr() as *mut libc::c_void, &mut sz, - ptr::null_mut(), 0))?; - if sz == 0 { - return Err(io::Error::last_os_error()); - } - v.set_len(sz - 1); // chop off trailing NUL - Ok(PathBuf::from(OsString::from_vec(v))) - } -} - -#[cfg(target_os = "netbsd")] -pub fn current_exe() -> io::Result { - fn sysctl() -> io::Result { - unsafe { - let mib = [libc::CTL_KERN, libc::KERN_PROC_ARGS, -1, libc::KERN_PROC_PATHNAME]; - let mut path_len: usize = 0; - cvt(libc::sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint, - ptr::null_mut(), &mut path_len, - ptr::null(), 0))?; - if path_len <= 1 { - return Err(io::Error::new(io::ErrorKind::Other, - "KERN_PROC_PATHNAME sysctl returned zero-length string")) - } - let mut path: Vec = Vec::with_capacity(path_len); - cvt(libc::sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint, - path.as_ptr() as *mut libc::c_void, &mut path_len, - ptr::null(), 0))?; - path.set_len(path_len - 1); // chop off NUL - Ok(PathBuf::from(OsString::from_vec(path))) - } - } - fn procfs() -> io::Result { - let curproc_exe = path::Path::new("/proc/curproc/exe"); - if curproc_exe.is_file() { - return ::fs::read_link(curproc_exe); - } - Err(io::Error::new(io::ErrorKind::Other, - "/proc/curproc/exe doesn't point to regular file.")) - } - sysctl().or_else(|_| procfs()) -} - -#[cfg(any(target_os = "bitrig", target_os = "openbsd"))] -pub fn current_exe() -> io::Result { - unsafe { - let mut mib = [libc::CTL_KERN, - libc::KERN_PROC_ARGS, - libc::getpid(), - libc::KERN_PROC_ARGV]; - let mib = mib.as_mut_ptr(); - let mut argv_len = 0; - cvt(libc::sysctl(mib, 4, ptr::null_mut(), &mut argv_len, - ptr::null_mut(), 0))?; - let mut argv = Vec::<*const libc::c_char>::with_capacity(argv_len as usize); - cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, - &mut argv_len, ptr::null_mut(), 0))?; - argv.set_len(argv_len as usize); - if argv[0].is_null() { - return Err(io::Error::new(io::ErrorKind::Other, - "no current exe available")) - } - let argv0 = CStr::from_ptr(argv[0]).to_bytes(); - if argv0[0] == b'.' || argv0.iter().any(|b| *b == b'/') { - ::fs::canonicalize(OsStr::from_bytes(argv0)) - } else { - Ok(PathBuf::from(OsStr::from_bytes(argv0))) - } - } -} - -#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))] -pub fn current_exe() -> io::Result { - let selfexe = PathBuf::from("/proc/self/exe"); - if selfexe.exists() { - ::fs::read_link(selfexe) - } else { - Err(io::Error::new(io::ErrorKind::Other, "no /proc/self/exe available. Is /proc mounted?")) - } -} - -#[cfg(any(target_os = "macos", target_os = "ios"))] -pub fn current_exe() -> io::Result { - extern { - fn _NSGetExecutablePath(buf: *mut libc::c_char, - bufsize: *mut u32) -> libc::c_int; - } - unsafe { - let mut sz: u32 = 0; - _NSGetExecutablePath(ptr::null_mut(), &mut sz); - if sz == 0 { return Err(io::Error::last_os_error()); } - let mut v: Vec = Vec::with_capacity(sz as usize); - let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz); - if err != 0 { return Err(io::Error::last_os_error()); } - v.set_len(sz as usize - 1); // chop off trailing NUL - Ok(PathBuf::from(OsString::from_vec(v))) - } -} - -#[cfg(any(target_os = "solaris"))] -pub fn current_exe() -> io::Result { - extern { - fn getexecname() -> *const c_char; - } - unsafe { - let path = getexecname(); - if path.is_null() { - Err(io::Error::last_os_error()) - } else { - let filename = CStr::from_ptr(path).to_bytes(); - let path = PathBuf::from(::from_bytes(filename)); - - // Prepend a current working directory to the path if - // it doesn't contain an absolute pathname. - if filename[0] == b'/' { - Ok(path) - } else { - getcwd().map(|cwd| cwd.join(path)) - } - } - } -} - -#[cfg(target_os = "haiku")] -pub fn current_exe() -> io::Result { - // Use Haiku's image info functions - #[repr(C)] - struct image_info { - id: i32, - type_: i32, - sequence: i32, - init_order: i32, - init_routine: *mut libc::c_void, // function pointer - term_routine: *mut libc::c_void, // function pointer - device: libc::dev_t, - node: libc::ino_t, - name: [libc::c_char; 1024], // MAXPATHLEN - text: *mut libc::c_void, - data: *mut libc::c_void, - text_size: i32, - data_size: i32, - api_version: i32, - abi: i32, - } - - unsafe { - extern { - fn _get_next_image_info(team_id: i32, cookie: *mut i32, - info: *mut image_info, size: i32) -> i32; - } - - let mut info: image_info = mem::zeroed(); - let mut cookie: i32 = 0; - // the executable can be found at team id 0 - let result = _get_next_image_info(0, &mut cookie, &mut info, - mem::size_of::() as i32); - if result != 0 { - use io::ErrorKind; - Err(io::Error::new(ErrorKind::Other, "Error getting executable path")) - } else { - let name = CStr::from_ptr(info.name.as_ptr()).to_bytes(); - Ok(PathBuf::from(OsStr::from_bytes(name))) - } - } -} - -#[cfg(any(target_os = "fuchsia", target_os = "l4re", target_os = "hermit"))] -pub fn current_exe() -> io::Result { - use io::ErrorKind; - Err(io::Error::new(ErrorKind::Other, "Not yet implemented!")) -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} - -#[cfg(target_os = "macos")] -pub unsafe fn environ() -> *mut *const *const c_char { - extern { fn _NSGetEnviron() -> *mut *const *const c_char; } - _NSGetEnviron() -} - -#[cfg(not(target_os = "macos"))] -pub unsafe fn environ() -> *mut *const *const c_char { - extern { static mut environ: *const *const c_char; } - &mut environ -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env() -> Env { - unsafe { - let _guard = ENV_LOCK.lock(); - let mut environ = *environ(); - let mut result = Vec::new(); - while environ != ptr::null() && *environ != ptr::null() { - if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { - result.push(key_value); - } - environ = environ.offset(1); - } - return Env { - iter: result.into_iter(), - _dont_send_or_sync_me: PhantomData, - } - } - - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - // Strategy (copied from glibc): Variable name and value are separated - // by an ASCII equals sign '='. Since a variable name must not be - // empty, allow variable names starting with an equals sign. Skip all - // malformed lines. - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p+1..].to_vec()), - )) - } -} - -pub fn getenv(k: &OsStr) -> io::Result> { - // environment variables with a nul byte can't be set, so their value is - // always None as well - let k = CString::new(k.as_bytes())?; - unsafe { - let _guard = ENV_LOCK.lock(); - let s = libc::getenv(k.as_ptr()) as *const libc::c_char; - let ret = if s.is_null() { - None - } else { - Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) - }; - Ok(ret) - } -} - -pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let k = CString::new(k.as_bytes())?; - let v = CString::new(v.as_bytes())?; - - unsafe { - let _guard = ENV_LOCK.lock(); - cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()) - } -} - -pub fn unsetenv(n: &OsStr) -> io::Result<()> { - let nbuf = CString::new(n.as_bytes())?; - - unsafe { - let _guard = ENV_LOCK.lock(); - cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()) - } -} - -pub fn page_size() -> usize { - unsafe { - libc::sysconf(libc::_SC_PAGESIZE) as usize - } -} - -pub fn temp_dir() -> PathBuf { - ::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| { - if cfg!(target_os = "android") { - PathBuf::from("/data/local/tmp") - } else { - PathBuf::from("/tmp") - } - }) -} - -pub fn home_dir() -> Option { - return ::env::var_os("HOME").or_else(|| unsafe { - fallback() - }).map(PathBuf::from); - - #[cfg(any(target_os = "android", - target_os = "ios", - target_os = "emscripten"))] - unsafe fn fallback() -> Option { None } - #[cfg(not(any(target_os = "android", - target_os = "ios", - target_os = "emscripten")))] - unsafe fn fallback() -> Option { - let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) { - n if n < 0 => 512 as usize, - n => n as usize, - }; - let mut buf = Vec::with_capacity(amt); - let mut passwd: libc::passwd = mem::zeroed(); - let mut result = ptr::null_mut(); - match libc::getpwuid_r(libc::getuid(), &mut passwd, buf.as_mut_ptr(), - buf.capacity(), &mut result) { - 0 if !result.is_null() => { - let ptr = passwd.pw_dir as *const _; - let bytes = CStr::from_ptr(ptr).to_bytes().to_vec(); - Some(OsStringExt::from_vec(bytes)) - }, - _ => None, - } - } -} - -pub fn exit(code: i32) -> ! { - unsafe { libc::exit(code as c_int) } -} - -pub fn getpid() -> u32 { - unsafe { libc::getpid() as u32 } -} - -pub fn getppid() -> u32 { - unsafe { libc::getppid() as u32 } -} - -#[cfg(target_env = "gnu")] -pub fn glibc_version() -> Option<(usize, usize)> { - if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) { - parse_glibc_version(version_str) - } else { - None - } -} - -#[cfg(target_env = "gnu")] -fn glibc_version_cstr() -> Option<&'static CStr> { - weak! { - fn gnu_get_libc_version() -> *const libc::c_char - } - if let Some(f) = gnu_get_libc_version.get() { - unsafe { Some(CStr::from_ptr(f())) } - } else { - None - } -} - -// Returns Some((major, minor)) if the string is a valid "x.y" version, -// ignoring any extra dot-separated parts. Otherwise return None. -#[cfg(target_env = "gnu")] -fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { - let mut parsed_ints = version.split('.').map(str::parse::).fuse(); - match (parsed_ints.next(), parsed_ints.next()) { - (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), - _ => None - } -} diff --git a/ctr-std/src/sys/unix/os_str.rs b/ctr-std/src/sys/unix/os_str.rs deleted file mode 100644 index 01c0fb8..0000000 --- a/ctr-std/src/sys/unix/os_str.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// The underlying OsString/OsStr implementation on Unix systems: just -/// a `Vec`/`[u8]`. - -use borrow::Cow; -use fmt; -use str; -use mem; -use rc::Rc; -use sync::Arc; -use sys_common::{AsInner, IntoInner}; -use sys_common::bytestring::debug_fmt_bytestring; -use core::str::lossy::Utf8Lossy; - -#[derive(Clone, Hash)] -pub struct Buf { - pub inner: Vec -} - -pub struct Slice { - pub inner: [u8] -} - -impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - debug_fmt_bytestring(&self.inner, formatter) - } -} - -impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) - } -} - -impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) - } -} - -impl IntoInner> for Buf { - fn into_inner(self) -> Vec { - self.inner - } -} - -impl AsInner<[u8]> for Buf { - fn as_inner(&self) -> &[u8] { - &self.inner - } -} - - -impl Buf { - pub fn from_string(s: String) -> Buf { - Buf { inner: s.into_bytes() } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Buf { - Buf { - inner: Vec::with_capacity(capacity) - } - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear() - } - - #[inline] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - pub fn as_slice(&self) -> &Slice { - unsafe { mem::transmute(&*self.inner) } - } - - pub fn into_string(self) -> Result { - String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) - } - - pub fn push_slice(&mut self, s: &Slice) { - self.inner.extend_from_slice(&s.inner) - } - - #[inline] - pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.inner.into_boxed_slice()) } - } - - #[inline] - pub fn from_box(boxed: Box) -> Buf { - let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Buf { inner: inner.into_vec() } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - self.as_slice().into_arc() - } - - #[inline] - pub fn into_rc(&self) -> Rc { - self.as_slice().into_rc() - } -} - -impl Slice { - fn from_u8_slice(s: &[u8]) -> &Slice { - unsafe { mem::transmute(s) } - } - - pub fn from_str(s: &str) -> &Slice { - Slice::from_u8_slice(s.as_bytes()) - } - - pub fn to_str(&self) -> Option<&str> { - str::from_utf8(&self.inner).ok() - } - - pub fn to_string_lossy(&self) -> Cow { - String::from_utf8_lossy(&self.inner) - } - - pub fn to_owned(&self) -> Buf { - Buf { inner: self.inner.to_vec() } - } - - #[inline] - pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.inner.into(); - unsafe { mem::transmute(boxed) } - } - - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.inner); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.inner); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } - } -} diff --git a/ctr-std/src/sys/unix/path.rs b/ctr-std/src/sys/unix/path.rs deleted file mode 100644 index bf9af7a..0000000 --- a/ctr-std/src/sys/unix/path.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use path::Prefix; -use ffi::OsStr; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option { - None -} - -pub const MAIN_SEP_STR: &'static str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/ctr-std/src/sys/unix/pipe.rs b/ctr-std/src/sys/unix/pipe.rs deleted file mode 100644 index 0a5dccd..0000000 --- a/ctr-std/src/sys/unix/pipe.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use libc::{self, c_int}; -use mem; -use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; -use sys::fd::FileDesc; -use sys::{cvt, cvt_r}; - -//////////////////////////////////////////////////////////////////////////////// -// Anonymous pipes -//////////////////////////////////////////////////////////////////////////////// - -pub struct AnonPipe(FileDesc); - -pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - weak! { fn pipe2(*mut c_int, c_int) -> c_int } - static INVALID: AtomicBool = ATOMIC_BOOL_INIT; - - let mut fds = [0; 2]; - - // Unfortunately the only known way right now to create atomically set the - // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in - // 2.6.27, however, and because we support 2.6.18 we must detect this - // support dynamically. - if cfg!(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd")) && - !INVALID.load(Ordering::SeqCst) - { - - if let Some(pipe) = pipe2.get() { - // Note that despite calling a glibc function here we may still - // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to - // emulate on older kernels, so if you happen to be running on - // an older kernel you may see `pipe2` as a symbol but still not - // see the syscall. - match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { - Ok(_) => { - return Ok((AnonPipe(FileDesc::new(fds[0])), - AnonPipe(FileDesc::new(fds[1])))); - } - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => { - INVALID.store(true, Ordering::SeqCst); - } - Err(e) => return Err(e), - } - } - } - cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; - - let fd0 = FileDesc::new(fds[0]); - let fd1 = FileDesc::new(fds[1]); - fd0.set_cloexec()?; - fd1.set_cloexec()?; - Ok((AnonPipe(fd0), AnonPipe(fd1))) -} - -impl AnonPipe { - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn fd(&self) -> &FileDesc { &self.0 } - pub fn into_fd(self) -> FileDesc { self.0 } -} - -pub fn read2(p1: AnonPipe, - v1: &mut Vec, - p2: AnonPipe, - v2: &mut Vec) -> io::Result<()> { - - // Set both pipes into nonblocking mode as we're gonna be reading from both - // in the `select` loop below, and we wouldn't want one to block the other! - let p1 = p1.into_fd(); - let p2 = p2.into_fd(); - p1.set_nonblocking(true)?; - p2.set_nonblocking(true)?; - - let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; - fds[0].fd = p1.raw(); - fds[0].events = libc::POLLIN; - fds[1].fd = p2.raw(); - fds[1].events = libc::POLLIN; - loop { - // wait for either pipe to become readable using `poll` - cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; - - if fds[0].revents != 0 && read(&p1, v1)? { - p2.set_nonblocking(false)?; - return p2.read_to_end(v2).map(|_| ()); - } - if fds[1].revents != 0 && read(&p2, v2)? { - p1.set_nonblocking(false)?; - return p1.read_to_end(v1).map(|_| ()); - } - } - - // Read as much as we can from each pipe, ignoring EWOULDBLOCK or - // EAGAIN. If we hit EOF, then this will happen because the underlying - // reader will return Ok(0), in which case we'll see `Ok` ourselves. In - // this case we flip the other fd back into blocking mode and read - // whatever's leftover on that file descriptor. - fn read(fd: &FileDesc, dst: &mut Vec) -> Result { - match fd.read_to_end(dst) { - Ok(_) => Ok(true), - Err(e) => { - if e.raw_os_error() == Some(libc::EWOULDBLOCK) || - e.raw_os_error() == Some(libc::EAGAIN) { - Ok(false) - } else { - Err(e) - } - } - } - } -} diff --git a/ctr-std/src/sys/unix/process/mod.rs b/ctr-std/src/sys/unix/process/mod.rs deleted file mode 100644 index d8ac26c..0000000 --- a/ctr-std/src/sys/unix/process/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes}; -pub use self::process_inner::Process; - -mod process_common; -#[cfg(not(target_os = "fuchsia"))] -#[path = "process_unix.rs"] -mod process_inner; -#[cfg(target_os = "fuchsia")] -#[path = "process_fuchsia.rs"] -mod process_inner; -#[cfg(target_os = "fuchsia")] -mod zircon; diff --git a/ctr-std/src/sys/unix/process/process_common.rs b/ctr-std/src/sys/unix/process/process_common.rs deleted file mode 100644 index 77f125f..0000000 --- a/ctr-std/src/sys/unix/process/process_common.rs +++ /dev/null @@ -1,510 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use os::unix::prelude::*; - -use ffi::{OsString, OsStr, CString, CStr}; -use fmt; -use io; -use libc::{self, c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE}; -use ptr; -use sys::fd::FileDesc; -use sys::fs::{File, OpenOptions}; -use sys::pipe::{self, AnonPipe}; -use sys_common::process::{CommandEnv, DefaultEnvKey}; -use collections::BTreeMap; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - // Currently we try hard to ensure that the call to `.exec()` doesn't - // actually allocate any memory. While many platforms try to ensure that - // memory allocation works after a fork in a multithreaded process, it's - // been observed to be buggy and somewhat unreliable, so we do our best to - // just not do it at all! - // - // Along those lines, the `argv` and `envp` raw pointers here are exactly - // what's gonna get passed to `execvp`. The `argv` array starts with the - // `program` and ends with a NULL, and the `envp` pointer, if present, is - // also null-terminated. - // - // Right now we don't support removing arguments, so there's no much fancy - // support there, but we support adding and removing environment variables, - // so a side table is used to track where in the `envp` array each key is - // located. Whenever we add a key we update it in place if it's already - // present, and whenever we remove a key we update the locations of all - // other keys. - program: CString, - args: Vec, - argv: Argv, - env: CommandEnv, - - cwd: Option, - uid: Option, - gid: Option, - saw_nul: bool, - closures: Vec io::Result<()> + Send + Sync>>, - stdin: Option, - stdout: Option, - stderr: Option, -} - -// Create a new type for argv, so that we can make it `Send` -struct Argv(Vec<*const c_char>); - -// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args` -unsafe impl Send for Argv {} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -// passed to do_exec() with configuration of what the child stdio should look -// like -pub struct ChildPipes { - pub stdin: ChildStdio, - pub stdout: ChildStdio, - pub stderr: ChildStdio, -} - -pub enum ChildStdio { - Inherit, - Explicit(c_int), - Owned(FileDesc), -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, - Fd(FileDesc), -} - -impl Command { - pub fn new(program: &OsStr) -> Command { - let mut saw_nul = false; - let program = os2c(program, &mut saw_nul); - Command { - argv: Argv(vec![program.as_ptr(), ptr::null()]), - program, - args: Vec::new(), - env: Default::default(), - cwd: None, - uid: None, - gid: None, - saw_nul, - closures: Vec::new(), - stdin: None, - stdout: None, - stderr: None, - } - } - - pub fn arg(&mut self, arg: &OsStr) { - // Overwrite the trailing NULL pointer in `argv` and then add a new null - // pointer. - let arg = os2c(arg, &mut self.saw_nul); - self.argv.0[self.args.len() + 1] = arg.as_ptr(); - self.argv.0.push(ptr::null()); - - // Also make sure we keep track of the owned value to schedule a - // destructor for this memory. - self.args.push(arg); - } - - pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(os2c(dir, &mut self.saw_nul)); - } - pub fn uid(&mut self, id: uid_t) { - self.uid = Some(id); - } - pub fn gid(&mut self, id: gid_t) { - self.gid = Some(id); - } - - pub fn saw_nul(&self) -> bool { - self.saw_nul - } - pub fn get_argv(&self) -> &Vec<*const c_char> { - &self.argv.0 - } - - #[allow(dead_code)] - pub fn get_cwd(&self) -> &Option { - &self.cwd - } - #[allow(dead_code)] - pub fn get_uid(&self) -> Option { - self.uid - } - #[allow(dead_code)] - pub fn get_gid(&self) -> Option { - self.gid - } - - pub fn get_closures(&mut self) -> &mut Vec io::Result<()> + Send + Sync>> { - &mut self.closures - } - - pub fn before_exec(&mut self, - f: Box io::Result<()> + Send + Sync>) { - self.closures.push(f); - } - - pub fn stdin(&mut self, stdin: Stdio) { - self.stdin = Some(stdin); - } - - pub fn stdout(&mut self, stdout: Stdio) { - self.stdout = Some(stdout); - } - - pub fn stderr(&mut self, stderr: Stdio) { - self.stderr = Some(stderr); - } - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn capture_env(&mut self) -> Option { - let maybe_env = self.env.capture_if_changed(); - maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) - } - #[allow(dead_code)] - pub fn env_saw_path(&self) -> bool { - self.env.have_changed_path() - } - - pub fn setup_io(&self, default: Stdio, needs_stdin: bool) - -> io::Result<(StdioPipes, ChildPipes)> { - let null = Stdio::Null; - let default_stdin = if needs_stdin {&default} else {&null}; - let stdin = self.stdin.as_ref().unwrap_or(default_stdin); - let stdout = self.stdout.as_ref().unwrap_or(&default); - let stderr = self.stderr.as_ref().unwrap_or(&default); - let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?; - let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?; - let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?; - let ours = StdioPipes { - stdin: our_stdin, - stdout: our_stdout, - stderr: our_stderr, - }; - let theirs = ChildPipes { - stdin: their_stdin, - stdout: their_stdout, - stderr: their_stderr, - }; - Ok((ours, theirs)) - } -} - -fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { - CString::new(s.as_bytes()).unwrap_or_else(|_e| { - *saw_nul = true; - CString::new("").unwrap() - }) -} - -// Helper type to manage ownership of the strings within a C-style array. -pub struct CStringArray { - items: Vec, - ptrs: Vec<*const c_char> -} - -impl CStringArray { - pub fn with_capacity(capacity: usize) -> Self { - let mut result = CStringArray { - items: Vec::with_capacity(capacity), - ptrs: Vec::with_capacity(capacity+1) - }; - result.ptrs.push(ptr::null()); - result - } - pub fn push(&mut self, item: CString) { - let l = self.ptrs.len(); - self.ptrs[l-1] = item.as_ptr(); - self.ptrs.push(ptr::null()); - self.items.push(item); - } - pub fn as_ptr(&self) -> *const *const c_char { - self.ptrs.as_ptr() - } -} - -fn construct_envp(env: BTreeMap, saw_nul: &mut bool) -> CStringArray { - let mut result = CStringArray::with_capacity(env.len()); - for (k, v) in env { - let mut k: OsString = k.into(); - - // Reserve additional space for '=' and null terminator - k.reserve_exact(v.len() + 2); - k.push("="); - k.push(&v); - - // Add the new entry into the array - if let Ok(item) = CString::new(k.into_vec()) { - result.push(item); - } else { - *saw_nul = true; - } - } - - result -} - -impl Stdio { - pub fn to_child_stdio(&self, readable: bool) - -> io::Result<(ChildStdio, Option)> { - match *self { - Stdio::Inherit => { - Ok((ChildStdio::Inherit, None)) - }, - - // Make sure that the source descriptors are not an stdio - // descriptor, otherwise the order which we set the child's - // descriptors may blow away a descriptor which we are hoping to - // save. For example, suppose we want the child's stderr to be the - // parent's stdout, and the child's stdout to be the parent's - // stderr. No matter which we dup first, the second will get - // overwritten prematurely. - Stdio::Fd(ref fd) => { - if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO { - Ok((ChildStdio::Owned(fd.duplicate()?), None)) - } else { - Ok((ChildStdio::Explicit(fd.raw()), None)) - } - } - - Stdio::MakePipe => { - let (reader, writer) = pipe::anon_pipe()?; - let (ours, theirs) = if readable { - (writer, reader) - } else { - (reader, writer) - }; - Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) - } - - Stdio::Null => { - let mut opts = OpenOptions::new(); - opts.read(readable); - opts.write(!readable); - let path = unsafe { - CStr::from_ptr("/dev/null\0".as_ptr() as *const _) - }; - let fd = File::open_c(&path, &opts)?; - Ok((ChildStdio::Owned(fd.into_fd()), None)) - } - } - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - Stdio::Fd(pipe.into_fd()) - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - Stdio::Fd(file.into_fd()) - } -} - -impl ChildStdio { - pub fn fd(&self) -> Option { - match *self { - ChildStdio::Inherit => None, - ChildStdio::Explicit(fd) => Some(fd), - ChildStdio::Owned(ref fd) => Some(fd.raw()), - } - } -} - -impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.program)?; - for arg in &self.args { - write!(f, " {:?}", arg)?; - } - Ok(()) - } -} - -/// Unix exit statuses -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatus(c_int); - -impl ExitStatus { - pub fn new(status: c_int) -> ExitStatus { - ExitStatus(status) - } - - fn exited(&self) -> bool { - unsafe { libc::WIFEXITED(self.0) } - } - - pub fn success(&self) -> bool { - self.code() == Some(0) - } - - pub fn code(&self) -> Option { - if self.exited() { - Some(unsafe { libc::WEXITSTATUS(self.0) }) - } else { - None - } - } - - pub fn signal(&self) -> Option { - if !self.exited() { - Some(unsafe { libc::WTERMSIG(self.0) }) - } else { - None - } - } -} - -impl From for ExitStatus { - fn from(a: c_int) -> ExitStatus { - ExitStatus(a) - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(code) = self.code() { - write!(f, "exit code: {}", code) - } else { - let signal = self.signal().unwrap(); - write!(f, "signal: {}", signal) - } - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(u8); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); - pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); - - #[inline] - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::*; - - use ffi::OsStr; - use mem; - use ptr; - use libc; - use sys::cvt; - - macro_rules! t { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), - } - } - } - - // Android with api less than 21 define sig* functions inline, so it is not - // available for dynamic link. Implementing sigemptyset and sigaddset allow us - // to support older Android version (independent of libc version). - // The following implementations are based on https://git.io/vSkNf - - #[cfg(not(target_os = "android"))] - extern { - #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")] - fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int; - - #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")] - fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int; - } - - #[cfg(target_os = "android")] - unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int { - libc::memset(set as *mut _, 0, mem::size_of::()); - return 0; - } - - #[cfg(target_os = "android")] - unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int { - use slice; - - let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::()); - let bit = (signum - 1) as usize; - raw[bit / 8] |= 1 << (bit % 8); - return 0; - } - - // See #14232 for more information, but it appears that signal delivery to a - // newly spawned process may just be raced in the macOS, so to prevent this - // test from being flaky we ignore it on macOS. - #[test] - #[cfg_attr(target_os = "macos", ignore)] - // When run under our current QEMU emulation test suite this test fails, - // although the reason isn't very clear as to why. For now this test is - // ignored there. - #[cfg_attr(target_arch = "arm", ignore)] - #[cfg_attr(target_arch = "aarch64", ignore)] - fn test_process_mask() { - unsafe { - // Test to make sure that a signal mask does not get inherited. - let mut cmd = Command::new(OsStr::new("cat")); - - let mut set: libc::sigset_t = mem::uninitialized(); - let mut old_set: libc::sigset_t = mem::uninitialized(); - t!(cvt(sigemptyset(&mut set))); - t!(cvt(sigaddset(&mut set, libc::SIGINT))); - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set))); - - cmd.stdin(Stdio::MakePipe); - cmd.stdout(Stdio::MakePipe); - - let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true)); - let stdin_write = pipes.stdin.take().unwrap(); - let stdout_read = pipes.stdout.take().unwrap(); - - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &old_set, - ptr::null_mut()))); - - t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT))); - // We need to wait until SIGINT is definitely delivered. The - // easiest way is to write something to cat, and try to read it - // back: if SIGINT is unmasked, it'll get delivered when cat is - // next scheduled. - let _ = stdin_write.write(b"Hello"); - drop(stdin_write); - - // Either EOF or failure (EPIPE) is okay. - let mut buf = [0; 5]; - if let Ok(ret) = stdout_read.read(&mut buf) { - assert_eq!(ret, 0); - } - - t!(cat.wait()); - } - } -} diff --git a/ctr-std/src/sys/unix/process/process_fuchsia.rs b/ctr-std/src/sys/unix/process/process_fuchsia.rs deleted file mode 100644 index fa48001..0000000 --- a/ctr-std/src/sys/unix/process/process_fuchsia.rs +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use libc::{self, size_t}; -use mem; -use ptr; - -use sys::process::zircon::{Handle, zx_handle_t}; -use sys::process::process_common::*; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -impl Command { - pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) - -> io::Result<(Process, StdioPipes)> { - let envp = self.capture_env(); - - if self.saw_nul() { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "nul byte found in provided data")); - } - - let (ours, theirs) = self.setup_io(default, needs_stdin)?; - - let process_handle = unsafe { self.do_exec(theirs, envp.as_ref())? }; - - Ok((Process { handle: Handle::new(process_handle) }, ours)) - } - - pub fn exec(&mut self, default: Stdio) -> io::Error { - if self.saw_nul() { - return io::Error::new(io::ErrorKind::InvalidInput, - "nul byte found in provided data") - } - - match self.setup_io(default, true) { - Ok((_, _)) => { - // FIXME: This is tough because we don't support the exec syscalls - unimplemented!(); - }, - Err(e) => e, - } - } - - unsafe fn do_exec(&mut self, stdio: ChildPipes, maybe_envp: Option<&CStringArray>) - -> io::Result { - use sys::process::zircon::*; - - let envp = match maybe_envp { - Some(envp) => envp.as_ptr(), - None => ptr::null(), - }; - - let transfer_or_clone = |opt_fd, target_fd| if let Some(local_fd) = opt_fd { - fdio_spawn_action_t { - action: FDIO_SPAWN_ACTION_TRANSFER_FD, - local_fd, - target_fd, - ..Default::default() - } - } else { - fdio_spawn_action_t { - action: FDIO_SPAWN_ACTION_CLONE_FD, - local_fd: target_fd, - target_fd, - ..Default::default() - } - }; - - // Clone stdin, stdout, and stderr - let action1 = transfer_or_clone(stdio.stdin.fd(), 0); - let action2 = transfer_or_clone(stdio.stdout.fd(), 1); - let action3 = transfer_or_clone(stdio.stderr.fd(), 2); - let actions = [action1, action2, action3]; - - // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc - // always consumes transferred file descriptors. - mem::forget(stdio); - - for callback in self.get_closures().iter_mut() { - callback()?; - } - - let mut process_handle: zx_handle_t = 0; - zx_cvt(fdio_spawn_etc( - 0, - FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE, - self.get_argv()[0], self.get_argv().as_ptr(), envp, 3, actions.as_ptr(), - &mut process_handle, - ptr::null_mut(), - ))?; - // FIXME: See if we want to do something with that err_msg - - Ok(process_handle) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Processes -//////////////////////////////////////////////////////////////////////////////// - -pub struct Process { - handle: Handle, -} - -impl Process { - pub fn id(&self) -> u32 { - self.handle.raw() as u32 - } - - pub fn kill(&mut self) -> io::Result<()> { - use sys::process::zircon::*; - - unsafe { zx_cvt(zx_task_kill(self.handle.raw()))?; } - - Ok(()) - } - - pub fn wait(&mut self) -> io::Result { - use default::Default; - use sys::process::zircon::*; - - let mut proc_info: zx_info_process_t = Default::default(); - let mut actual: size_t = 0; - let mut avail: size_t = 0; - - unsafe { - zx_cvt(zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, - ZX_TIME_INFINITE, ptr::null_mut()))?; - zx_cvt(zx_object_get_info(self.handle.raw(), ZX_INFO_PROCESS, - &mut proc_info as *mut _ as *mut libc::c_void, - mem::size_of::(), &mut actual, - &mut avail))?; - } - if actual != 1 { - return Err(io::Error::new(io::ErrorKind::InvalidData, - "Failed to get exit status of process")); - } - Ok(ExitStatus::new(proc_info.rec.return_code)) - } - - pub fn try_wait(&mut self) -> io::Result> { - use default::Default; - use sys::process::zircon::*; - - let mut proc_info: zx_info_process_t = Default::default(); - let mut actual: size_t = 0; - let mut avail: size_t = 0; - - unsafe { - let status = zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, - 0, ptr::null_mut()); - match status { - 0 => { }, // Success - x if x == ERR_TIMED_OUT => { - return Ok(None); - }, - _ => { panic!("Failed to wait on process handle: {}", status); }, - } - zx_cvt(zx_object_get_info(self.handle.raw(), ZX_INFO_PROCESS, - &mut proc_info as *mut _ as *mut libc::c_void, - mem::size_of::(), &mut actual, - &mut avail))?; - } - if actual != 1 { - return Err(io::Error::new(io::ErrorKind::InvalidData, - "Failed to get exit status of process")); - } - Ok(Some(ExitStatus::new(proc_info.rec.return_code))) - } -} diff --git a/ctr-std/src/sys/unix/process/process_unix.rs b/ctr-std/src/sys/unix/process/process_unix.rs deleted file mode 100644 index 9d6d607..0000000 --- a/ctr-std/src/sys/unix/process/process_unix.rs +++ /dev/null @@ -1,405 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io::{self, Error, ErrorKind}; -use libc::{self, c_int, gid_t, pid_t, uid_t}; -use ptr; - -use sys::cvt; -use sys::process::process_common::*; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -impl Command { - pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) - -> io::Result<(Process, StdioPipes)> { - use sys; - - const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; - - let envp = self.capture_env(); - - if self.saw_nul() { - return Err(io::Error::new(ErrorKind::InvalidInput, - "nul byte found in provided data")); - } - - let (ours, theirs) = self.setup_io(default, needs_stdin)?; - - if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? { - return Ok((ret, ours)) - } - - let (input, output) = sys::pipe::anon_pipe()?; - - let pid = unsafe { - match cvt(libc::fork())? { - 0 => { - drop(input); - let err = self.do_exec(theirs, envp.as_ref()); - let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32; - let bytes = [ - (errno >> 24) as u8, - (errno >> 16) as u8, - (errno >> 8) as u8, - (errno >> 0) as u8, - CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1], - CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3] - ]; - // pipe I/O up to PIPE_BUF bytes should be atomic, and then - // we want to be sure we *don't* run at_exit destructors as - // we're being torn down regardless - assert!(output.write(&bytes).is_ok()); - libc::_exit(1) - } - n => n, - } - }; - - let mut p = Process { pid: pid, status: None }; - drop(output); - let mut bytes = [0; 8]; - - // loop to handle EINTR - loop { - match input.read(&mut bytes) { - Ok(0) => return Ok((p, ours)), - Ok(8) => { - assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]), - "Validation on the CLOEXEC pipe failed: {:?}", bytes); - let errno = combine(&bytes[0.. 4]); - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - return Err(Error::from_raw_os_error(errno)) - } - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => { - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - panic!("the CLOEXEC pipe failed: {:?}", e) - }, - Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - panic!("short read on the CLOEXEC pipe") - } - } - } - - fn combine(arr: &[u8]) -> i32 { - let a = arr[0] as u32; - let b = arr[1] as u32; - let c = arr[2] as u32; - let d = arr[3] as u32; - - ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32 - } - } - - pub fn exec(&mut self, default: Stdio) -> io::Error { - let envp = self.capture_env(); - - if self.saw_nul() { - return io::Error::new(ErrorKind::InvalidInput, - "nul byte found in provided data") - } - - match self.setup_io(default, true) { - Ok((_, theirs)) => unsafe { self.do_exec(theirs, envp.as_ref()) }, - Err(e) => e, - } - } - - // And at this point we've reached a special time in the life of the - // child. The child must now be considered hamstrung and unable to - // do anything other than syscalls really. Consider the following - // scenario: - // - // 1. Thread A of process 1 grabs the malloc() mutex - // 2. Thread B of process 1 forks(), creating thread C - // 3. Thread C of process 2 then attempts to malloc() - // 4. The memory of process 2 is the same as the memory of - // process 1, so the mutex is locked. - // - // This situation looks a lot like deadlock, right? It turns out - // that this is what pthread_atfork() takes care of, which is - // presumably implemented across platforms. The first thing that - // threads to *before* forking is to do things like grab the malloc - // mutex, and then after the fork they unlock it. - // - // Despite this information, libnative's spawn has been witnessed to - // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but - // all collected backtraces point at malloc/free traffic in the - // child spawned process. - // - // For this reason, the block of code below should contain 0 - // invocations of either malloc of free (or their related friends). - // - // As an example of not having malloc/free traffic, we don't close - // this file descriptor by dropping the FileDesc (which contains an - // allocation). Instead we just close it manually. This will never - // have the drop glue anyway because this code never returns (the - // child will either exec() or invoke libc::exit) - unsafe fn do_exec( - &mut self, - stdio: ChildPipes, - maybe_envp: Option<&CStringArray> - ) -> io::Error { - use sys::{self, cvt_r}; - - macro_rules! t { - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => return e, - }) - } - - if let Some(fd) = stdio.stdin.fd() { - t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO))); - } - if let Some(fd) = stdio.stdout.fd() { - t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO))); - } - if let Some(fd) = stdio.stderr.fd() { - t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO))); - } - - if cfg!(not(any(target_os = "l4re"))) { - if let Some(u) = self.get_gid() { - t!(cvt(libc::setgid(u as gid_t))); - } - if let Some(u) = self.get_uid() { - // When dropping privileges from root, the `setgroups` call - // will remove any extraneous groups. If we don't call this, - // then even though our uid has dropped, we may still have - // groups that enable us to do super-user things. This will - // fail if we aren't root, so don't bother checking the - // return value, this is just done as an optimistic - // privilege dropping function. - let _ = libc::setgroups(0, ptr::null()); - - t!(cvt(libc::setuid(u as uid_t))); - } - } - if let Some(ref cwd) = *self.get_cwd() { - t!(cvt(libc::chdir(cwd.as_ptr()))); - } - if let Some(envp) = maybe_envp { - *sys::os::environ() = envp.as_ptr(); - } - - // emscripten has no signal support. - #[cfg(not(any(target_os = "emscripten")))] - { - use mem; - // Reset signal handling so the child process starts in a - // standardized state. libstd ignores SIGPIPE, and signal-handling - // libraries often set a mask. Child processes inherit ignored - // signals and the signal mask from their parent, but most - // UNIX programs do not reset these things on their own, so we - // need to clean things up now to avoid confusing the program - // we're about to run. - let mut set: libc::sigset_t = mem::uninitialized(); - if cfg!(target_os = "android") { - // Implementing sigemptyset allow us to support older Android - // versions. See the comment about Android and sig* functions in - // process_common.rs - libc::memset(&mut set as *mut _ as *mut _, - 0, - mem::size_of::()); - } else { - t!(cvt(libc::sigemptyset(&mut set))); - } - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, - ptr::null_mut()))); - let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); - if ret == libc::SIG_ERR { - return io::Error::last_os_error() - } - } - - for callback in self.get_closures().iter_mut() { - t!(callback()); - } - - libc::execvp(self.get_argv()[0], self.get_argv().as_ptr()); - io::Error::last_os_error() - } - - #[cfg(not(any(target_os = "macos", target_os = "freebsd", - all(target_os = "linux", target_env = "gnu"))))] - fn posix_spawn(&mut self, _: &ChildPipes, _: Option<&CStringArray>) - -> io::Result> - { - Ok(None) - } - - // Only support platforms for which posix_spawn() can return ENOENT - // directly. - #[cfg(any(target_os = "macos", target_os = "freebsd", - all(target_os = "linux", target_env = "gnu")))] - fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) - -> io::Result> - { - use mem; - use sys; - - if self.get_cwd().is_some() || - self.get_gid().is_some() || - self.get_uid().is_some() || - self.env_saw_path() || - self.get_closures().len() != 0 { - return Ok(None) - } - - // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly. - #[cfg(all(target_os = "linux", target_env = "gnu"))] - { - if let Some(version) = sys::os::glibc_version() { - if version < (2, 24) { - return Ok(None) - } - } else { - return Ok(None) - } - } - - let mut p = Process { pid: 0, status: None }; - - struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t); - - impl Drop for PosixSpawnFileActions { - fn drop(&mut self) { - unsafe { - libc::posix_spawn_file_actions_destroy(&mut self.0); - } - } - } - - struct PosixSpawnattr(libc::posix_spawnattr_t); - - impl Drop for PosixSpawnattr { - fn drop(&mut self) { - unsafe { - libc::posix_spawnattr_destroy(&mut self.0); - } - } - } - - unsafe { - let mut file_actions = PosixSpawnFileActions(mem::uninitialized()); - let mut attrs = PosixSpawnattr(mem::uninitialized()); - - libc::posix_spawnattr_init(&mut attrs.0); - libc::posix_spawn_file_actions_init(&mut file_actions.0); - - if let Some(fd) = stdio.stdin.fd() { - cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, - fd, - libc::STDIN_FILENO))?; - } - if let Some(fd) = stdio.stdout.fd() { - cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, - fd, - libc::STDOUT_FILENO))?; - } - if let Some(fd) = stdio.stderr.fd() { - cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, - fd, - libc::STDERR_FILENO))?; - } - - let mut set: libc::sigset_t = mem::uninitialized(); - cvt(libc::sigemptyset(&mut set))?; - cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0, - &set))?; - cvt(libc::sigaddset(&mut set, libc::SIGPIPE))?; - cvt(libc::posix_spawnattr_setsigdefault(&mut attrs.0, - &set))?; - - let flags = libc::POSIX_SPAWN_SETSIGDEF | - libc::POSIX_SPAWN_SETSIGMASK; - cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?; - - let envp = envp.map(|c| c.as_ptr()) - .unwrap_or(*sys::os::environ() as *const _); - let ret = libc::posix_spawnp( - &mut p.pid, - self.get_argv()[0], - &file_actions.0, - &attrs.0, - self.get_argv().as_ptr() as *const _, - envp as *const _, - ); - if ret == 0 { - Ok(Some(p)) - } else { - Err(io::Error::from_raw_os_error(ret)) - } - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Processes -//////////////////////////////////////////////////////////////////////////////// - -/// The unique id of the process (this should never be negative). -pub struct Process { - pid: pid_t, - status: Option, -} - -impl Process { - pub fn id(&self) -> u32 { - self.pid as u32 - } - - pub fn kill(&mut self) -> io::Result<()> { - // If we've already waited on this process then the pid can be recycled - // and used for another process, and we probably shouldn't be killing - // random processes, so just return an error. - if self.status.is_some() { - Err(Error::new(ErrorKind::InvalidInput, - "invalid argument: can't kill an exited process")) - } else { - cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ()) - } - } - - pub fn wait(&mut self) -> io::Result { - use sys::cvt_r; - if let Some(status) = self.status { - return Ok(status) - } - let mut status = 0 as c_int; - cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?; - self.status = Some(ExitStatus::new(status)); - Ok(ExitStatus::new(status)) - } - - pub fn try_wait(&mut self) -> io::Result> { - if let Some(status) = self.status { - return Ok(Some(status)) - } - let mut status = 0 as c_int; - let pid = cvt(unsafe { - libc::waitpid(self.pid, &mut status, libc::WNOHANG) - })?; - if pid == 0 { - Ok(None) - } else { - self.status = Some(ExitStatus::new(status)); - Ok(Some(ExitStatus::new(status))) - } - } -} diff --git a/ctr-std/src/sys/unix/process/zircon.rs b/ctr-std/src/sys/unix/process/zircon.rs deleted file mode 100644 index a06c73e..0000000 --- a/ctr-std/src/sys/unix/process/zircon.rs +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_camel_case_types, unused)] - -use convert::TryInto; -use io; -use os::raw::c_char; -use u64; - -use libc::{c_int, c_void, size_t}; - -pub type zx_handle_t = u32; -pub type zx_vaddr_t = usize; -pub type zx_rights_t = u32; -pub type zx_status_t = i32; - -pub const ZX_HANDLE_INVALID: zx_handle_t = 0; - -pub type zx_time_t = u64; -pub const ZX_TIME_INFINITE : zx_time_t = u64::MAX; - -pub type zx_signals_t = u32; - -pub const ZX_OBJECT_SIGNAL_3 : zx_signals_t = 1 << 3; - -pub const ZX_TASK_TERMINATED : zx_signals_t = ZX_OBJECT_SIGNAL_3; - -pub const ZX_RIGHT_SAME_RIGHTS : zx_rights_t = 1 << 31; - -pub type zx_object_info_topic_t = u32; - -pub const ZX_INFO_PROCESS : zx_object_info_topic_t = 3; - -pub fn zx_cvt(t: T) -> io::Result where T: TryInto+Copy { - if let Ok(status) = TryInto::try_into(t) { - if status < 0 { - Err(io::Error::from_raw_os_error(status)) - } else { - Ok(t) - } - } else { - Err(io::Error::last_os_error()) - } -} - -// Safe wrapper around zx_handle_t -pub struct Handle { - raw: zx_handle_t, -} - -impl Handle { - pub fn new(raw: zx_handle_t) -> Handle { - Handle { - raw, - } - } - - pub fn raw(&self) -> zx_handle_t { - self.raw - } -} - -impl Drop for Handle { - fn drop(&mut self) { - unsafe { zx_cvt(zx_handle_close(self.raw)).expect("Failed to close zx_handle_t"); } - } -} - -// Common ZX_INFO header -#[derive(Default)] -#[repr(C)] -pub struct zx_info_header_t { - pub topic: u32, // identifies the info struct - pub avail_topic_size: u16, // “native” size of the struct - pub topic_size: u16, // size of the returned struct (<=topic_size) - pub avail_count: u32, // number of records the kernel has - pub count: u32, // number of records returned (limited by buffer size) -} - -#[derive(Default)] -#[repr(C)] -pub struct zx_record_process_t { - pub return_code: c_int, -} - -// Returned for topic ZX_INFO_PROCESS -#[derive(Default)] -#[repr(C)] -pub struct zx_info_process_t { - pub hdr: zx_info_header_t, - pub rec: zx_record_process_t, -} - -extern { - pub fn zx_job_default() -> zx_handle_t; - - pub fn zx_task_kill(handle: zx_handle_t) -> zx_status_t; - - pub fn zx_handle_close(handle: zx_handle_t) -> zx_status_t; - - pub fn zx_handle_duplicate(handle: zx_handle_t, rights: zx_rights_t, - out: *const zx_handle_t) -> zx_handle_t; - - pub fn zx_object_wait_one(handle: zx_handle_t, signals: zx_signals_t, timeout: zx_time_t, - pending: *mut zx_signals_t) -> zx_status_t; - - pub fn zx_object_get_info(handle: zx_handle_t, topic: u32, buffer: *mut c_void, - buffer_size: size_t, actual_size: *mut size_t, - avail: *mut size_t) -> zx_status_t; -} - -#[derive(Default)] -#[repr(C)] -pub struct fdio_spawn_action_t { - pub action: u32, - pub reserved0: u32, - pub local_fd: i32, - pub target_fd: i32, - pub reserved1: u64, -} - -extern { - pub fn fdio_spawn_etc(job: zx_handle_t, flags: u32, path: *const c_char, - argv: *const *const c_char, envp: *const *const c_char, - action_count: u64, actions: *const fdio_spawn_action_t, - process: *mut zx_handle_t, err_msg: *mut c_char) -> zx_status_t; -} - -// fdio_spawn_etc flags - -pub const FDIO_SPAWN_CLONE_JOB: u32 = 0x0001; -pub const FDIO_SPAWN_CLONE_LDSVC: u32 = 0x0002; -pub const FDIO_SPAWN_CLONE_NAMESPACE: u32 = 0x0004; -pub const FDIO_SPAWN_CLONE_STDIO: u32 = 0x0008; -pub const FDIO_SPAWN_CLONE_ENVIRON: u32 = 0x0010; -pub const FDIO_SPAWN_CLONE_ALL: u32 = 0xFFFF; - -// fdio_spawn_etc actions - -pub const FDIO_SPAWN_ACTION_CLONE_FD: u32 = 0x0001; -pub const FDIO_SPAWN_ACTION_TRANSFER_FD: u32 = 0x0002; - -// Errors - -#[allow(unused)] pub const ERR_INTERNAL: zx_status_t = -1; - -// ERR_NOT_SUPPORTED: The operation is not implemented, supported, -// or enabled. -#[allow(unused)] pub const ERR_NOT_SUPPORTED: zx_status_t = -2; - -// ERR_NO_RESOURCES: The system was not able to allocate some resource -// needed for the operation. -#[allow(unused)] pub const ERR_NO_RESOURCES: zx_status_t = -3; - -// ERR_NO_MEMORY: The system was not able to allocate memory needed -// for the operation. -#[allow(unused)] pub const ERR_NO_MEMORY: zx_status_t = -4; - -// ERR_CALL_FAILED: The second phase of zx_channel_call(; did not complete -// successfully. -#[allow(unused)] pub const ERR_CALL_FAILED: zx_status_t = -5; - -// ERR_INTERRUPTED_RETRY: The system call was interrupted, but should be -// retried. This should not be seen outside of the VDSO. -#[allow(unused)] pub const ERR_INTERRUPTED_RETRY: zx_status_t = -6; - -// ======= Parameter errors ======= -// ERR_INVALID_ARGS: an argument is invalid, ex. null pointer -#[allow(unused)] pub const ERR_INVALID_ARGS: zx_status_t = -10; - -// ERR_BAD_HANDLE: A specified handle value does not refer to a handle. -#[allow(unused)] pub const ERR_BAD_HANDLE: zx_status_t = -11; - -// ERR_WRONG_TYPE: The subject of the operation is the wrong type to -// perform the operation. -// Example: Attempting a message_read on a thread handle. -#[allow(unused)] pub const ERR_WRONG_TYPE: zx_status_t = -12; - -// ERR_BAD_SYSCALL: The specified syscall number is invalid. -#[allow(unused)] pub const ERR_BAD_SYSCALL: zx_status_t = -13; - -// ERR_OUT_OF_RANGE: An argument is outside the valid range for this -// operation. -#[allow(unused)] pub const ERR_OUT_OF_RANGE: zx_status_t = -14; - -// ERR_BUFFER_TOO_SMALL: A caller provided buffer is too small for -// this operation. -#[allow(unused)] pub const ERR_BUFFER_TOO_SMALL: zx_status_t = -15; - -// ======= Precondition or state errors ======= -// ERR_BAD_STATE: operation failed because the current state of the -// object does not allow it, or a precondition of the operation is -// not satisfied -#[allow(unused)] pub const ERR_BAD_STATE: zx_status_t = -20; - -// ERR_TIMED_OUT: The time limit for the operation elapsed before -// the operation completed. -#[allow(unused)] pub const ERR_TIMED_OUT: zx_status_t = -21; - -// ERR_SHOULD_WAIT: The operation cannot be performed currently but -// potentially could succeed if the caller waits for a prerequisite -// to be satisfied, for example waiting for a handle to be readable -// or writable. -// Example: Attempting to read from a message pipe that has no -// messages waiting but has an open remote will return ERR_SHOULD_WAIT. -// Attempting to read from a message pipe that has no messages waiting -// and has a closed remote end will return ERR_REMOTE_CLOSED. -#[allow(unused)] pub const ERR_SHOULD_WAIT: zx_status_t = -22; - -// ERR_CANCELED: The in-progress operation (e.g. a wait) has been -// // canceled. -#[allow(unused)] pub const ERR_CANCELED: zx_status_t = -23; - -// ERR_PEER_CLOSED: The operation failed because the remote end -// of the subject of the operation was closed. -#[allow(unused)] pub const ERR_PEER_CLOSED: zx_status_t = -24; - -// ERR_NOT_FOUND: The requested entity is not found. -#[allow(unused)] pub const ERR_NOT_FOUND: zx_status_t = -25; - -// ERR_ALREADY_EXISTS: An object with the specified identifier -// already exists. -// Example: Attempting to create a file when a file already exists -// with that name. -#[allow(unused)] pub const ERR_ALREADY_EXISTS: zx_status_t = -26; - -// ERR_ALREADY_BOUND: The operation failed because the named entity -// is already owned or controlled by another entity. The operation -// could succeed later if the current owner releases the entity. -#[allow(unused)] pub const ERR_ALREADY_BOUND: zx_status_t = -27; - -// ERR_UNAVAILABLE: The subject of the operation is currently unable -// to perform the operation. -// Note: This is used when there's no direct way for the caller to -// observe when the subject will be able to perform the operation -// and should thus retry. -#[allow(unused)] pub const ERR_UNAVAILABLE: zx_status_t = -28; - -// ======= Permission check errors ======= -// ERR_ACCESS_DENIED: The caller did not have permission to perform -// the specified operation. -#[allow(unused)] pub const ERR_ACCESS_DENIED: zx_status_t = -30; - -// ======= Input-output errors ======= -// ERR_IO: Otherwise unspecified error occurred during I/O. -#[allow(unused)] pub const ERR_IO: zx_status_t = -40; - -// ERR_REFUSED: The entity the I/O operation is being performed on -// rejected the operation. -// Example: an I2C device NAK'ing a transaction or a disk controller -// rejecting an invalid command. -#[allow(unused)] pub const ERR_IO_REFUSED: zx_status_t = -41; - -// ERR_IO_DATA_INTEGRITY: The data in the operation failed an integrity -// check and is possibly corrupted. -// Example: CRC or Parity error. -#[allow(unused)] pub const ERR_IO_DATA_INTEGRITY: zx_status_t = -42; - -// ERR_IO_DATA_LOSS: The data in the operation is currently unavailable -// and may be permanently lost. -// Example: A disk block is irrecoverably damaged. -#[allow(unused)] pub const ERR_IO_DATA_LOSS: zx_status_t = -43; - -// Filesystem specific errors -#[allow(unused)] pub const ERR_BAD_PATH: zx_status_t = -50; -#[allow(unused)] pub const ERR_NOT_DIR: zx_status_t = -51; -#[allow(unused)] pub const ERR_NOT_FILE: zx_status_t = -52; -// ERR_FILE_BIG: A file exceeds a filesystem-specific size limit. -#[allow(unused)] pub const ERR_FILE_BIG: zx_status_t = -53; -// ERR_NO_SPACE: Filesystem or device space is exhausted. -#[allow(unused)] pub const ERR_NO_SPACE: zx_status_t = -54; diff --git a/ctr-std/src/sys/unix/rand.rs b/ctr-std/src/sys/unix/rand.rs deleted file mode 100644 index 01c0ada..0000000 --- a/ctr-std/src/sys/unix/rand.rs +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use mem; -use slice; - -pub fn hashmap_random_keys() -> (u64, u64) { - let mut v = (0, 0); - unsafe { - let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, - mem::size_of_val(&v)); - imp::fill_bytes(view); - } - return v -} - -#[cfg(all(unix, - not(target_os = "ios"), - not(target_os = "openbsd"), - not(target_os = "freebsd"), - not(target_os = "fuchsia")))] -mod imp { - use fs::File; - use io::Read; - use libc; - use sys::os::errno; - - #[cfg(any(target_os = "linux", target_os = "android"))] - fn getrandom(buf: &mut [u8]) -> libc::c_long { - unsafe { - libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK) - } - } - - #[cfg(not(any(target_os = "linux", target_os = "android")))] - fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } - - fn getrandom_fill_bytes(v: &mut [u8]) -> bool { - let mut read = 0; - while read < v.len() { - let result = getrandom(&mut v[read..]); - if result == -1 { - let err = errno() as libc::c_int; - if err == libc::EINTR { - continue; - } else if err == libc::EAGAIN { - return false - } else { - panic!("unexpected getrandom error: {}", err); - } - } else { - read += result as usize; - } - } - - return true - } - - #[cfg(any(target_os = "linux", target_os = "android"))] - fn is_getrandom_available() -> bool { - use io; - use sync::atomic::{AtomicBool, Ordering}; - use sync::Once; - - static CHECKER: Once = Once::new(); - static AVAILABLE: AtomicBool = AtomicBool::new(false); - - CHECKER.call_once(|| { - let mut buf: [u8; 0] = []; - let result = getrandom(&mut buf); - let available = if result == -1 { - let err = io::Error::last_os_error().raw_os_error(); - err != Some(libc::ENOSYS) - } else { - true - }; - AVAILABLE.store(available, Ordering::Relaxed); - }); - - AVAILABLE.load(Ordering::Relaxed) - } - - #[cfg(not(any(target_os = "linux", target_os = "android")))] - fn is_getrandom_available() -> bool { false } - - pub fn fill_bytes(v: &mut [u8]) { - // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN, - // meaning it would have blocked because the non-blocking pool (urandom) - // has not initialized in the kernel yet due to a lack of entropy the - // fallback we do here is to avoid blocking applications which could - // depend on this call without ever knowing they do and don't have a - // work around. The PRNG of /dev/urandom will still be used but not - // over a completely full entropy pool - if is_getrandom_available() && getrandom_fill_bytes(v) { - return - } - - let mut file = File::open("/dev/urandom") - .expect("failed to open /dev/urandom"); - file.read_exact(v).expect("failed to read /dev/urandom"); - } -} - -#[cfg(target_os = "openbsd")] -mod imp { - use libc; - use sys::os::errno; - - pub fn fill_bytes(v: &mut [u8]) { - // getentropy(2) permits a maximum buffer size of 256 bytes - for s in v.chunks_mut(256) { - let ret = unsafe { - libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) - }; - if ret == -1 { - panic!("unexpected getentropy error: {}", errno()); - } - } - } -} - -#[cfg(target_os = "ios")] -mod imp { - use io; - use libc::{c_int, size_t}; - use ptr; - - enum SecRandom {} - - #[allow(non_upper_case_globals)] - const kSecRandomDefault: *const SecRandom = ptr::null(); - - extern { - fn SecRandomCopyBytes(rnd: *const SecRandom, - count: size_t, - bytes: *mut u8) -> c_int; - } - - pub fn fill_bytes(v: &mut [u8]) { - let ret = unsafe { - SecRandomCopyBytes(kSecRandomDefault, - v.len(), - v.as_mut_ptr()) - }; - if ret == -1 { - panic!("couldn't generate random bytes: {}", - io::Error::last_os_error()); - } - } -} - -#[cfg(target_os = "freebsd")] -mod imp { - use libc; - use ptr; - - pub fn fill_bytes(v: &mut [u8]) { - let mib = [libc::CTL_KERN, libc::KERN_ARND]; - // kern.arandom permits a maximum buffer size of 256 bytes - for s in v.chunks_mut(256) { - let mut s_len = s.len(); - let ret = unsafe { - libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, - s.as_mut_ptr() as *mut _, &mut s_len, - ptr::null(), 0) - }; - if ret == -1 || s_len != s.len() { - panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})", - ret, s.len(), s_len); - } - } - } -} - -#[cfg(target_os = "fuchsia")] -mod imp { - #[link(name = "zircon")] - extern { - fn zx_cprng_draw(buffer: *mut u8, len: usize); - } - - pub fn fill_bytes(v: &mut [u8]) { - unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) } - } -} diff --git a/ctr-std/src/sys/unix/rwlock.rs b/ctr-std/src/sys/unix/rwlock.rs deleted file mode 100644 index c754d5b..0000000 --- a/ctr-std/src/sys/unix/rwlock.rs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use libc; -use cell::UnsafeCell; -use sync::atomic::{AtomicUsize, Ordering}; - -pub struct RWLock { - inner: UnsafeCell, - write_locked: UnsafeCell, - num_readers: AtomicUsize, -} - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { - inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER), - write_locked: UnsafeCell::new(false), - num_readers: AtomicUsize::new(0), - } - } - #[inline] - pub unsafe fn read(&self) { - let r = libc::pthread_rwlock_rdlock(self.inner.get()); - - // According to the pthread_rwlock_rdlock spec, this function **may** - // fail with EDEADLK if a deadlock is detected. On the other hand - // pthread mutexes will *never* return EDEADLK if they are initialized - // as the "fast" kind (which ours always are). As a result, a deadlock - // situation may actually return from the call to pthread_rwlock_rdlock - // instead of blocking forever (as mutexes and Windows rwlocks do). Note - // that not all unix implementations, however, will return EDEADLK for - // their rwlocks. - // - // We roughly maintain the deadlocking behavior by panicking to ensure - // that this lock acquisition does not succeed. - // - // We also check whether this lock is already write locked. This - // is only possible if it was write locked by the current thread and - // the implementation allows recursive locking. The POSIX standard - // doesn't require recursively locking a rwlock to deadlock, but we can't - // allow that because it could lead to aliasing issues. - if r == libc::EAGAIN { - panic!("rwlock maximum reader count exceeded"); - } else if r == libc::EDEADLK || *self.write_locked.get() { - if r == 0 { - self.raw_unlock(); - } - panic!("rwlock read lock would result in deadlock"); - } else { - debug_assert_eq!(r, 0); - self.num_readers.fetch_add(1, Ordering::Relaxed); - } - } - #[inline] - pub unsafe fn try_read(&self) -> bool { - let r = libc::pthread_rwlock_tryrdlock(self.inner.get()); - if r == 0 { - if *self.write_locked.get() { - self.raw_unlock(); - false - } else { - self.num_readers.fetch_add(1, Ordering::Relaxed); - true - } - } else { - false - } - } - #[inline] - pub unsafe fn write(&self) { - let r = libc::pthread_rwlock_wrlock(self.inner.get()); - // See comments above for why we check for EDEADLK and write_locked. We - // also need to check that num_readers is 0. - if r == libc::EDEADLK || *self.write_locked.get() || - self.num_readers.load(Ordering::Relaxed) != 0 { - if r == 0 { - self.raw_unlock(); - } - panic!("rwlock write lock would result in deadlock"); - } else { - debug_assert_eq!(r, 0); - } - *self.write_locked.get() = true; - } - #[inline] - pub unsafe fn try_write(&self) -> bool { - let r = libc::pthread_rwlock_trywrlock(self.inner.get()); - if r == 0 { - if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 { - self.raw_unlock(); - false - } else { - *self.write_locked.get() = true; - true - } - } else { - false - } - } - #[inline] - unsafe fn raw_unlock(&self) { - let r = libc::pthread_rwlock_unlock(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn read_unlock(&self) { - debug_assert!(!*self.write_locked.get()); - self.num_readers.fetch_sub(1, Ordering::Relaxed); - self.raw_unlock(); - } - #[inline] - pub unsafe fn write_unlock(&self) { - debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0); - debug_assert!(*self.write_locked.get()); - *self.write_locked.get() = false; - self.raw_unlock(); - } - #[inline] - pub unsafe fn destroy(&self) { - let r = libc::pthread_rwlock_destroy(self.inner.get()); - // On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a - // rwlock that was just initialized with - // libc::PTHREAD_RWLOCK_INITIALIZER. Once it is used (locked/unlocked) - // or pthread_rwlock_init() is called, this behaviour no longer occurs. - if cfg!(target_os = "dragonfly") { - debug_assert!(r == 0 || r == libc::EINVAL); - } else { - debug_assert_eq!(r, 0); - } - } -} diff --git a/ctr-std/src/sys/unix/stack_overflow.rs b/ctr-std/src/sys/unix/stack_overflow.rs deleted file mode 100644 index 40453f9..0000000 --- a/ctr-std/src/sys/unix/stack_overflow.rs +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg_attr(test, allow(dead_code))] - -use libc; -use self::imp::{make_handler, drop_handler}; - -pub use self::imp::cleanup; -pub use self::imp::init; - -pub struct Handler { - _data: *mut libc::c_void -} - -impl Handler { - pub unsafe fn new() -> Handler { - make_handler() - } -} - -impl Drop for Handler { - fn drop(&mut self) { - unsafe { - drop_handler(self); - } - } -} - -#[cfg(any(target_os = "linux", - target_os = "macos", - target_os = "bitrig", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "solaris", - all(target_os = "netbsd", not(target_vendor = "rumprun")), - target_os = "openbsd"))] -mod imp { - use super::Handler; - use mem; - use ptr; - use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE}; - use libc::{sigaction, SIGBUS, SIG_DFL, - SA_SIGINFO, SA_ONSTACK, sighandler_t}; - use libc; - use libc::{mmap, munmap}; - use libc::{SIGSEGV, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON}; - use libc::MAP_FAILED; - - use sys_common::thread_info; - - - #[cfg(any(target_os = "linux", target_os = "android"))] - unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize { - #[repr(C)] - struct siginfo_t { - a: [libc::c_int; 3], // si_signo, si_errno, si_code - si_addr: *mut libc::c_void, - } - - (*(info as *const siginfo_t)).si_addr as usize - } - - #[cfg(not(any(target_os = "linux", target_os = "android")))] - unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize { - (*info).si_addr as usize - } - - // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages - // (unmapped pages) at the end of every thread's stack, so if a thread ends - // up running into the guard page it'll trigger this handler. We want to - // detect these cases and print out a helpful error saying that the stack - // has overflowed. All other signals, however, should go back to what they - // were originally supposed to do. - // - // This handler currently exists purely to print an informative message - // whenever a thread overflows its stack. We then abort to exit and - // indicate a crash, but to avoid a misleading SIGSEGV that might lead - // users to believe that unsafe code has accessed an invalid pointer; the - // SIGSEGV encountered when overflowing the stack is expected and - // well-defined. - // - // If this is not a stack overflow, the handler un-registers itself and - // then returns (to allow the original signal to be delivered again). - // Returning from this kind of signal handler is technically not defined - // to work when reading the POSIX spec strictly, but in practice it turns - // out many large systems and all implementations allow returning from a - // signal handler to work. For a more detailed explanation see the - // comments on #26458. - unsafe extern fn signal_handler(signum: libc::c_int, - info: *mut libc::siginfo_t, - _data: *mut libc::c_void) { - use sys_common::util::report_overflow; - - let guard = thread_info::stack_guard().unwrap_or(0..0); - let addr = siginfo_si_addr(info); - - // If the faulting address is within the guard page, then we print a - // message saying so and abort. - if guard.start <= addr && addr < guard.end { - report_overflow(); - rtabort!("stack overflow"); - } else { - // Unregister ourselves by reverting back to the default behavior. - let mut action: sigaction = mem::zeroed(); - action.sa_sigaction = SIG_DFL; - sigaction(signum, &action, ptr::null_mut()); - - // See comment above for why this function returns. - } - } - - static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut(); - - pub unsafe fn init() { - let mut action: sigaction = mem::zeroed(); - action.sa_flags = SA_SIGINFO | SA_ONSTACK; - action.sa_sigaction = signal_handler as sighandler_t; - sigaction(SIGSEGV, &action, ptr::null_mut()); - sigaction(SIGBUS, &action, ptr::null_mut()); - - let handler = make_handler(); - MAIN_ALTSTACK = handler._data; - mem::forget(handler); - } - - pub unsafe fn cleanup() { - Handler { _data: MAIN_ALTSTACK }; - } - - unsafe fn get_stackp() -> *mut libc::c_void { - let stackp = mmap(ptr::null_mut(), - SIGSTKSZ, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, - -1, - 0); - if stackp == MAP_FAILED { - panic!("failed to allocate an alternative stack"); - } - stackp - } - - #[cfg(any(target_os = "linux", - target_os = "macos", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] - unsafe fn get_stack() -> libc::stack_t { - libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ } - } - - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly"))] - unsafe fn get_stack() -> libc::stack_t { - libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ } - } - - pub unsafe fn make_handler() -> Handler { - let mut stack = mem::zeroed(); - sigaltstack(ptr::null(), &mut stack); - // Configure alternate signal stack, if one is not already set. - if stack.ss_flags & SS_DISABLE != 0 { - stack = get_stack(); - sigaltstack(&stack, ptr::null_mut()); - Handler { _data: stack.ss_sp as *mut libc::c_void } - } else { - Handler { _data: ptr::null_mut() } - } - } - - pub unsafe fn drop_handler(handler: &mut Handler) { - if !handler._data.is_null() { - let stack = libc::stack_t { - ss_sp: ptr::null_mut(), - ss_flags: SS_DISABLE, - // Workaround for bug in macOS implementation of sigaltstack - // UNIX2003 which returns ENOMEM when disabling a stack while - // passing ss_size smaller than MINSIGSTKSZ. According to POSIX - // both ss_sp and ss_size should be ignored in this case. - ss_size: SIGSTKSZ, - }; - sigaltstack(&stack, ptr::null_mut()); - munmap(handler._data, SIGSTKSZ); - } - } -} - -#[cfg(not(any(target_os = "linux", - target_os = "macos", - target_os = "bitrig", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "solaris", - all(target_os = "netbsd", not(target_vendor = "rumprun")), - target_os = "openbsd")))] -mod imp { - use ptr; - - pub unsafe fn init() { - } - - pub unsafe fn cleanup() { - } - - pub unsafe fn make_handler() -> super::Handler { - super::Handler { _data: ptr::null_mut() } - } - - pub unsafe fn drop_handler(_handler: &mut super::Handler) { - } -} diff --git a/ctr-std/src/sys/unix/stdio.rs b/ctr-std/src/sys/unix/stdio.rs deleted file mode 100644 index 87ba2ae..0000000 --- a/ctr-std/src/sys/unix/stdio.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use libc; -use sys::fd::FileDesc; - -pub struct Stdin(()); -pub struct Stdout(()); -pub struct Stderr(()); - -impl Stdin { - pub fn new() -> io::Result { Ok(Stdin(())) } - - pub fn read(&self, data: &mut [u8]) -> io::Result { - let fd = FileDesc::new(libc::STDIN_FILENO); - let ret = fd.read(data); - fd.into_raw(); - ret - } -} - -impl Stdout { - pub fn new() -> io::Result { Ok(Stdout(())) } - - pub fn write(&self, data: &[u8]) -> io::Result { - let fd = FileDesc::new(libc::STDOUT_FILENO); - let ret = fd.write(data); - fd.into_raw(); - ret - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub fn new() -> io::Result { Ok(Stderr(())) } - - pub fn write(&self, data: &[u8]) -> io::Result { - let fd = FileDesc::new(libc::STDERR_FILENO); - let ret = fd.write(data); - fd.into_raw(); - ret - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -// FIXME: right now this raw stderr handle is used in a few places because -// std::io::stderr_raw isn't exposed, but once that's exposed this impl -// should go away -impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result { - Stderr::write(self, data) - } - - fn flush(&mut self) -> io::Result<()> { - Stderr::flush(self) - } -} - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(libc::EBADF as i32) -} - -pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; - -pub fn stderr_prints_nothing() -> bool { - false -} diff --git a/ctr-std/src/sys/unix/thread.rs b/ctr-std/src/sys/unix/thread.rs deleted file mode 100644 index f3a45d2..0000000 --- a/ctr-std/src/sys/unix/thread.rs +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use boxed::FnBox; -use cmp; -use ffi::CStr; -use io; -use libc; -use mem; -use ptr; -use sys::os; -use time::Duration; - -use sys_common::thread::*; - -#[cfg(not(target_os = "l4re"))] -pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; -#[cfg(target_os = "l4re")] -pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; - -pub struct Thread { - id: libc::pthread_t, -} - -// Some platforms may have pthread_t as a pointer in which case we still want -// a thread to be Send/Sync -unsafe impl Send for Thread {} -unsafe impl Sync for Thread {} - -// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc, -// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS. -#[cfg(not(target_os = "emscripten"))] -unsafe fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t, - stack_size: libc::size_t) -> libc::c_int { - libc::pthread_attr_setstacksize(attr, stack_size) -} - -#[cfg(target_os = "emscripten")] -unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t, - _stack_size: libc::size_t) -> libc::c_int { - panic!() -} - -impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box) - -> io::Result { - let p = box p; - let mut native: libc::pthread_t = mem::zeroed(); - let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); - - let stack_size = cmp::max(stack, min_stack_size(&attr)); - - match pthread_attr_setstacksize(&mut attr, - stack_size) { - 0 => {} - n => { - assert_eq!(n, libc::EINVAL); - // EINVAL means |stack_size| is either too small or not a - // multiple of the system page size. Because it's definitely - // >= PTHREAD_STACK_MIN, it must be an alignment issue. - // Round up to the nearest page and try again. - let page_size = os::page_size(); - let stack_size = (stack_size + page_size - 1) & - (-(page_size as isize - 1) as usize - 1); - assert_eq!(libc::pthread_attr_setstacksize(&mut attr, - stack_size), 0); - } - }; - - let ret = libc::pthread_create(&mut native, &attr, thread_start, - &*p as *const _ as *mut _); - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); - - return if ret != 0 { - Err(io::Error::from_raw_os_error(ret)) - } else { - mem::forget(p); // ownership passed to pthread_create - Ok(Thread { id: native }) - }; - - extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { - unsafe { start_thread(main as *mut u8); } - ptr::null_mut() - } - } - - pub fn yield_now() { - let ret = unsafe { libc::sched_yield() }; - debug_assert_eq!(ret, 0); - } - - #[cfg(any(target_os = "linux", - target_os = "android"))] - pub fn set_name(name: &CStr) { - const PR_SET_NAME: libc::c_int = 15; - // pthread wrapper only appeared in glibc 2.12, so we use syscall - // directly. - unsafe { - libc::prctl(PR_SET_NAME, name.as_ptr() as libc::c_ulong, 0, 0, 0); - } - } - - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd"))] - pub fn set_name(name: &CStr) { - unsafe { - libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr()); - } - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn set_name(name: &CStr) { - unsafe { - libc::pthread_setname_np(name.as_ptr()); - } - } - - #[cfg(target_os = "netbsd")] - pub fn set_name(name: &CStr) { - use ffi::CString; - let cname = CString::new(&b"%s"[..]).unwrap(); - unsafe { - libc::pthread_setname_np(libc::pthread_self(), cname.as_ptr(), - name.as_ptr() as *mut libc::c_void); - } - } - #[cfg(any(target_env = "newlib", - target_os = "solaris", - target_os = "haiku", - target_os = "l4re", - target_os = "emscripten", - target_os = "hermit"))] - pub fn set_name(_name: &CStr) { - // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name. - } - #[cfg(target_os = "fuchsia")] - pub fn set_name(_name: &CStr) { - // FIXME: determine whether Fuchsia has a way to set a thread name. - } - - pub fn sleep(dur: Duration) { - let mut secs = dur.as_secs(); - let mut nsecs = dur.subsec_nanos() as _; - - // If we're awoken with a signal then the return value will be -1 and - // nanosleep will fill in `ts` with the remaining time. - unsafe { - while secs > 0 || nsecs > 0 { - let mut ts = libc::timespec { - tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, - tv_nsec: nsecs, - }; - secs -= ts.tv_sec as u64; - if libc::nanosleep(&ts, &mut ts) == -1 { - assert_eq!(os::errno(), libc::EINTR); - secs += ts.tv_sec as u64; - nsecs = ts.tv_nsec; - } else { - nsecs = 0; - } - } - } - } - - pub fn join(self) { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - assert!(ret == 0, - "failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } - } - - pub fn id(&self) -> libc::pthread_t { self.id } - - pub fn into_id(self) -> libc::pthread_t { - let id = self.id; - mem::forget(self); - id - } -} - -impl Drop for Thread { - fn drop(&mut self) { - let ret = unsafe { libc::pthread_detach(self.id) }; - debug_assert_eq!(ret, 0); - } -} - -#[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))), - not(target_os = "freebsd"), - not(target_os = "macos"), - not(target_os = "bitrig"), - not(all(target_os = "netbsd", not(target_vendor = "rumprun"))), - not(target_os = "openbsd"), - not(target_os = "solaris")))] -#[cfg_attr(test, allow(dead_code))] -pub mod guard { - use ops::Range; - pub type Guard = Range; - pub unsafe fn current() -> Option { None } - pub unsafe fn init() -> Option { None } - pub unsafe fn deinit() {} -} - - -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), - target_os = "freebsd", - target_os = "macos", - target_os = "bitrig", - all(target_os = "netbsd", not(target_vendor = "rumprun")), - target_os = "openbsd", - target_os = "solaris"))] -#[cfg_attr(test, allow(dead_code))] -pub mod guard { - use libc; - use libc::{mmap, mprotect}; - use libc::{PROT_NONE, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED}; - use ops::Range; - use sys::os; - - // This is initialized in init() and only read from after - static mut PAGE_SIZE: usize = 0; - - pub type Guard = Range; - - #[cfg(target_os = "solaris")] - unsafe fn get_stack_start() -> Option<*mut libc::c_void> { - let mut current_stack: libc::stack_t = ::mem::zeroed(); - assert_eq!(libc::stack_getbounds(&mut current_stack), 0); - Some(current_stack.ss_sp) - } - - #[cfg(target_os = "macos")] - unsafe fn get_stack_start() -> Option<*mut libc::c_void> { - let stackaddr = libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - - libc::pthread_get_stacksize_np(libc::pthread_self()); - Some(stackaddr as *mut libc::c_void) - } - - #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] - unsafe fn get_stack_start() -> Option<*mut libc::c_void> { - let mut current_stack: libc::stack_t = ::mem::zeroed(); - assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), - &mut current_stack), 0); - - let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE; - let stackaddr = if libc::pthread_main_np() == 1 { - // main thread - current_stack.ss_sp as usize - current_stack.ss_size + extra - } else { - // new thread - current_stack.ss_sp as usize - current_stack.ss_size - }; - Some(stackaddr as *mut libc::c_void) - } - - #[cfg(any(target_os = "android", target_os = "freebsd", - target_os = "linux", target_os = "netbsd", target_os = "l4re"))] - unsafe fn get_stack_start() -> Option<*mut libc::c_void> { - let mut ret = None; - let mut attr: libc::pthread_attr_t = ::mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); - #[cfg(target_os = "freebsd")] - let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); - #[cfg(not(target_os = "freebsd"))] - let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr); - if e == 0 { - let mut stackaddr = ::ptr::null_mut(); - let mut stacksize = 0; - assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, - &mut stacksize), 0); - ret = Some(stackaddr); - } - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); - ret - } - - // Precondition: PAGE_SIZE is initialized. - unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> { - assert!(PAGE_SIZE != 0); - let stackaddr = get_stack_start()?; - - // Ensure stackaddr is page aligned! A parent process might - // have reset RLIMIT_STACK to be non-page aligned. The - // pthread_attr_getstack() reports the usable stack area - // stackaddr < stackaddr + stacksize, so if stackaddr is not - // page-aligned, calculate the fix such that stackaddr < - // new_page_aligned_stackaddr < stackaddr + stacksize - let remainder = (stackaddr as usize) % PAGE_SIZE; - Some(if remainder == 0 { - stackaddr - } else { - ((stackaddr as usize) + PAGE_SIZE - remainder) as *mut libc::c_void - }) - } - - pub unsafe fn init() -> Option { - PAGE_SIZE = os::page_size(); - - let stackaddr = get_stack_start_aligned()?; - - if cfg!(target_os = "linux") { - // Linux doesn't allocate the whole stack right away, and - // the kernel has its own stack-guard mechanism to fault - // when growing too close to an existing mapping. If we map - // our own guard, then the kernel starts enforcing a rather - // large gap above that, rendering much of the possible - // stack space useless. See #43052. - // - // Instead, we'll just note where we expect rlimit to start - // faulting, so our handler can report "stack overflow", and - // trust that the kernel's own stack guard will work. - let stackaddr = stackaddr as usize; - Some(stackaddr - PAGE_SIZE..stackaddr) - } else { - // Reallocate the last page of the stack. - // This ensures SIGBUS will be raised on - // stack overflow. - // Systems which enforce strict PAX MPROTECT do not allow - // to mprotect() a mapping with less restrictive permissions - // than the initial mmap() used, so we mmap() here with - // read/write permissions and only then mprotect() it to - // no permissions at all. See issue #50313. - let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); - if result != stackaddr || result == MAP_FAILED { - panic!("failed to allocate a guard page"); - } - - let result = mprotect(stackaddr, PAGE_SIZE, PROT_NONE); - if result != 0 { - panic!("failed to protect the guard page"); - } - - let guardaddr = stackaddr as usize; - let offset = if cfg!(target_os = "freebsd") { - 2 - } else { - 1 - }; - - Some(guardaddr..guardaddr + offset * PAGE_SIZE) - } - } - - pub unsafe fn deinit() { - if !cfg!(target_os = "linux") { - if let Some(stackaddr) = get_stack_start_aligned() { - // Remove the protection on the guard page. - // FIXME: we cannot unmap the page, because when we mmap() - // above it may be already mapped by the OS, which we can't - // detect from mmap()'s return value. If we unmap this page, - // it will lead to failure growing stack size on platforms like - // macOS. Instead, just restore the page to a writable state. - // This ain't Linux, so we probably don't need to care about - // execstack. - let result = mprotect(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE); - - if result != 0 { - panic!("unable to reset the guard page"); - } - } - } - } - - #[cfg(any(target_os = "macos", - target_os = "bitrig", - target_os = "openbsd", - target_os = "solaris"))] - pub unsafe fn current() -> Option { - let stackaddr = get_stack_start()? as usize; - Some(stackaddr - PAGE_SIZE..stackaddr) - } - - #[cfg(any(target_os = "android", target_os = "freebsd", - target_os = "linux", target_os = "netbsd", target_os = "l4re"))] - pub unsafe fn current() -> Option { - let mut ret = None; - let mut attr: libc::pthread_attr_t = ::mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); - #[cfg(target_os = "freebsd")] - let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); - #[cfg(not(target_os = "freebsd"))] - let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr); - if e == 0 { - let mut guardsize = 0; - assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0); - if guardsize == 0 { - panic!("there is no guard page"); - } - let mut stackaddr = ::ptr::null_mut(); - let mut size = 0; - assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, - &mut size), 0); - - let stackaddr = stackaddr as usize; - ret = if cfg!(target_os = "freebsd") { - // FIXME does freebsd really fault *below* the guard addr? - let guardaddr = stackaddr - guardsize; - Some(guardaddr - PAGE_SIZE..guardaddr) - } else if cfg!(target_os = "netbsd") { - Some(stackaddr - guardsize..stackaddr) - } else if cfg!(all(target_os = "linux", target_env = "gnu")) { - // glibc used to include the guard area within the stack, as noted in the BUGS - // section of `man pthread_attr_getguardsize`. This has been corrected starting - // with glibc 2.27, and in some distro backports, so the guard is now placed at the - // end (below) the stack. There's no easy way for us to know which we have at - // runtime, so we'll just match any fault in the range right above or below the - // stack base to call that fault a stack overflow. - Some(stackaddr - guardsize..stackaddr + guardsize) - } else { - Some(stackaddr..stackaddr + guardsize) - }; - } - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); - ret - } -} - -// glibc >= 2.15 has a __pthread_get_minstack() function that returns -// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local -// storage. We need that information to avoid blowing up when a small stack -// is created in an application with big thread-local storage requirements. -// See #6233 for rationale and details. -#[cfg(target_os = "linux")] -#[allow(deprecated)] -fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { - weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t); - - match __pthread_get_minstack.get() { - None => libc::PTHREAD_STACK_MIN, - Some(f) => unsafe { f(attr) }, - } -} - -// No point in looking up __pthread_get_minstack() on non-glibc -// platforms. -#[cfg(all(not(target_os = "linux"), - not(target_os = "netbsd")))] -fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { - libc::PTHREAD_STACK_MIN -} - -#[cfg(target_os = "netbsd")] -fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { - 2048 // just a guess -} diff --git a/ctr-std/src/sys/unix/thread_local.rs b/ctr-std/src/sys/unix/thread_local.rs deleted file mode 100644 index 2487f6b..0000000 --- a/ctr-std/src/sys/unix/thread_local.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] // not used on all platforms - -use mem; -use libc; - -pub type Key = libc::pthread_key_t; - -#[inline] -pub unsafe fn create(dtor: Option) -> Key { - let mut key = 0; - assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0); - key -} - -#[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - let r = libc::pthread_setspecific(key, value as *mut _); - debug_assert_eq!(r, 0); -} - -#[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - libc::pthread_getspecific(key) as *mut u8 -} - -#[inline] -pub unsafe fn destroy(key: Key) { - let r = libc::pthread_key_delete(key); - debug_assert_eq!(r, 0); -} - -#[inline] -pub fn requires_synchronized_create() -> bool { - false -} diff --git a/ctr-std/src/sys/unix/time.rs b/ctr-std/src/sys/unix/time.rs deleted file mode 100644 index 0b1fb72..0000000 --- a/ctr-std/src/sys/unix/time.rs +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cmp::Ordering; -use libc; -use time::Duration; -use core::hash::{Hash, Hasher}; - -pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; -use convert::TryInto; - -const NSEC_PER_SEC: u64 = 1_000_000_000; - -#[derive(Copy, Clone)] -struct Timespec { - t: libc::timespec, -} - -impl Timespec { - fn sub_timespec(&self, other: &Timespec) -> Result { - if self >= other { - Ok(if self.t.tv_nsec >= other.t.tv_nsec { - Duration::new((self.t.tv_sec - other.t.tv_sec) as u64, - (self.t.tv_nsec - other.t.tv_nsec) as u32) - } else { - Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64, - self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - - other.t.tv_nsec as u32) - }) - } else { - match other.sub_timespec(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } - } - - fn add_duration(&self, other: &Duration) -> Timespec { - let mut secs = other - .as_secs() - .try_into() // <- target type would be `libc::time_t` - .ok() - .and_then(|secs| self.t.tv_sec.checked_add(secs)) - .expect("overflow when adding duration to time"); - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; - if nsec >= NSEC_PER_SEC as u32 { - nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1).expect("overflow when adding \ - duration to time"); - } - Timespec { - t: libc::timespec { - tv_sec: secs, - tv_nsec: nsec as _, - }, - } - } - - fn sub_duration(&self, other: &Duration) -> Timespec { - let mut secs = other - .as_secs() - .try_into() // <- target type would be `libc::time_t` - .ok() - .and_then(|secs| self.t.tv_sec.checked_sub(secs)) - .expect("overflow when subtracting duration from time"); - - // Similar to above, nanos can't overflow. - let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; - if nsec < 0 { - nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1).expect("overflow when subtracting \ - duration from time"); - } - Timespec { - t: libc::timespec { - tv_sec: secs, - tv_nsec: nsec as _, - }, - } - } -} - -impl PartialEq for Timespec { - fn eq(&self, other: &Timespec) -> bool { - self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec - } -} - -impl Eq for Timespec {} - -impl PartialOrd for Timespec { - fn partial_cmp(&self, other: &Timespec) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Timespec { - fn cmp(&self, other: &Timespec) -> Ordering { - let me = (self.t.tv_sec, self.t.tv_nsec); - let other = (other.t.tv_sec, other.t.tv_nsec); - me.cmp(&other) - } -} - -impl Hash for Timespec { - fn hash(&self, state: &mut H) { - self.t.tv_sec.hash(state); - self.t.tv_nsec.hash(state); - } -} - -#[cfg(any(target_os = "macos", target_os = "ios"))] -mod inner { - use fmt; - use libc; - use sync::Once; - use sys::cvt; - use sys_common::mul_div_u64; - use time::Duration; - - use super::NSEC_PER_SEC; - use super::Timespec; - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] - pub struct Instant { - t: u64 - } - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct SystemTime { - t: Timespec, - } - - pub const UNIX_EPOCH: SystemTime = SystemTime { - t: Timespec { - t: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, - }, - }; - - impl Instant { - pub fn now() -> Instant { - Instant { t: unsafe { libc::mach_absolute_time() } } - } - - pub fn sub_instant(&self, other: &Instant) -> Duration { - let info = info(); - let diff = self.t.checked_sub(other.t) - .expect("second instant is later than self"); - let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64); - Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32) - } - - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant { - t: self.t.checked_add(dur2intervals(other)) - .expect("overflow when adding duration to instant"), - } - } - - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant { - t: self.t.checked_sub(dur2intervals(other)) - .expect("overflow when subtracting duration from instant"), - } - } - } - - impl SystemTime { - pub fn now() -> SystemTime { - use ptr; - - let mut s = libc::timeval { - tv_sec: 0, - tv_usec: 0, - }; - cvt(unsafe { - libc::gettimeofday(&mut s, ptr::null_mut()) - }).unwrap(); - return SystemTime::from(s) - } - - pub fn sub_time(&self, other: &SystemTime) - -> Result { - self.t.sub_timespec(&other.t) - } - - pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime { t: self.t.add_duration(other) } - } - - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - SystemTime { t: self.t.sub_duration(other) } - } - } - - impl From for SystemTime { - fn from(t: libc::timeval) -> SystemTime { - SystemTime::from(libc::timespec { - tv_sec: t.tv_sec, - tv_nsec: (t.tv_usec * 1000) as libc::c_long, - }) - } - } - - impl From for SystemTime { - fn from(t: libc::timespec) -> SystemTime { - SystemTime { t: Timespec { t: t } } - } - } - - impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SystemTime") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } - } - - fn dur2intervals(dur: &Duration) -> u64 { - let info = info(); - let nanos = dur.as_secs().checked_mul(NSEC_PER_SEC).and_then(|nanos| { - nanos.checked_add(dur.subsec_nanos() as u64) - }).expect("overflow converting duration to nanoseconds"); - mul_div_u64(nanos, info.denom as u64, info.numer as u64) - } - - fn info() -> &'static libc::mach_timebase_info { - static mut INFO: libc::mach_timebase_info = libc::mach_timebase_info { - numer: 0, - denom: 0, - }; - static ONCE: Once = Once::new(); - - unsafe { - ONCE.call_once(|| { - libc::mach_timebase_info(&mut INFO); - }); - &INFO - } - } -} - -#[cfg(not(any(target_os = "macos", target_os = "ios")))] -mod inner { - use fmt; - use libc; - use sys::cvt; - use time::Duration; - - use super::Timespec; - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct Instant { - t: Timespec, - } - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct SystemTime { - t: Timespec, - } - - pub const UNIX_EPOCH: SystemTime = SystemTime { - t: Timespec { - t: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, - }, - }; - - impl Instant { - pub fn now() -> Instant { - Instant { t: now(libc::CLOCK_MONOTONIC) } - } - - pub fn sub_instant(&self, other: &Instant) -> Duration { - self.t.sub_timespec(&other.t).unwrap_or_else(|_| { - panic!("specified instant was later than self") - }) - } - - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant { t: self.t.add_duration(other) } - } - - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant { t: self.t.sub_duration(other) } - } - } - - impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Instant") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } - } - - impl SystemTime { - pub fn now() -> SystemTime { - SystemTime { t: now(libc::CLOCK_REALTIME) } - } - - pub fn sub_time(&self, other: &SystemTime) - -> Result { - self.t.sub_timespec(&other.t) - } - - pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime { t: self.t.add_duration(other) } - } - - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - SystemTime { t: self.t.sub_duration(other) } - } - } - - impl From for SystemTime { - fn from(t: libc::timespec) -> SystemTime { - SystemTime { t: Timespec { t: t } } - } - } - - impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SystemTime") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } - } - - #[cfg(not(any(target_os = "dragonfly", target_os = "hermit")))] - pub type clock_t = libc::c_int; - #[cfg(any(target_os = "dragonfly", target_os = "hermit"))] - pub type clock_t = libc::c_ulong; - - fn now(clock: clock_t) -> Timespec { - let mut t = Timespec { - t: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - } - }; - cvt(unsafe { - libc::clock_gettime(clock, &mut t.t) - }).unwrap(); - t - } -} diff --git a/ctr-std/src/sys/unix/weak.rs b/ctr-std/src/sys/unix/weak.rs deleted file mode 100644 index 18944be..0000000 --- a/ctr-std/src/sys/unix/weak.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Support for "weak linkage" to symbols on Unix -//! -//! Some I/O operations we do in libstd require newer versions of OSes but we -//! need to maintain binary compatibility with older releases for now. In order -//! to use the new functionality when available we use this module for -//! detection. -//! -//! One option to use here is weak linkage, but that is unfortunately only -//! really workable on Linux. Hence, use dlsym to get the symbol value at -//! runtime. This is also done for compatibility with older versions of glibc, -//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that -//! we've been dynamically linked to the library the symbol comes from, but that -//! is currently always the case for things like libpthread/libc. -//! -//! A long time ago this used weak linkage for the __pthread_get_minstack -//! symbol, but that caused Debian to detect an unnecessarily strict versioned -//! dependency on libc6 (#23628). - -use libc; - -use ffi::CString; -use marker; -use mem; -use sync::atomic::{AtomicUsize, Ordering}; - -macro_rules! weak { - (fn $name:ident($($t:ty),*) -> $ret:ty) => ( - static $name: ::sys::weak::Weak $ret> = - ::sys::weak::Weak::new(stringify!($name)); - ) -} - -pub struct Weak { - name: &'static str, - addr: AtomicUsize, - _marker: marker::PhantomData, -} - -impl Weak { - pub const fn new(name: &'static str) -> Weak { - Weak { - name, - addr: AtomicUsize::new(1), - _marker: marker::PhantomData, - } - } - - pub fn get(&self) -> Option<&F> { - assert_eq!(mem::size_of::(), mem::size_of::()); - unsafe { - if self.addr.load(Ordering::SeqCst) == 1 { - self.addr.store(fetch(self.name), Ordering::SeqCst); - } - if self.addr.load(Ordering::SeqCst) == 0 { - None - } else { - mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr) - } - } - } -} - -unsafe fn fetch(name: &str) -> usize { - let name = match CString::new(name) { - Ok(cstr) => cstr, - Err(..) => return 0, - }; - libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize -} diff --git a/ctr-std/src/sys/wasm/args.rs b/ctr-std/src/sys/wasm/args.rs deleted file mode 100644 index b3c6b67..0000000 --- a/ctr-std/src/sys/wasm/args.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::OsString; -use marker::PhantomData; -use vec; -use sys::ArgsSysCall; - -pub unsafe fn init(_argc: isize, _argv: *const *const u8) { - // On wasm these should always be null, so there's nothing for us to do here -} - -pub unsafe fn cleanup() { -} - -pub fn args() -> Args { - let v = ArgsSysCall::perform(); - Args { - iter: v.into_iter(), - _dont_send_or_sync_me: PhantomData, - } -} - -pub struct Args { - iter: vec::IntoIter, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Args { - pub fn inner_debug(&self) -> &[OsString] { - self.iter.as_slice() - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.iter.next_back() - } -} diff --git a/ctr-std/src/sys/wasm/backtrace.rs b/ctr-std/src/sys/wasm/backtrace.rs deleted file mode 100644 index 9a8c48f..0000000 --- a/ctr-std/src/sys/wasm/backtrace.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use sys::unsupported; -use sys_common::backtrace::Frame; - -pub struct BacktraceContext; - -pub fn unwind_backtrace(_frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - unsupported() -} - -pub fn resolve_symname(_frame: Frame, - _callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - unsupported() -} - -pub fn foreach_symbol_fileline(_: Frame, - _: F, - _: &BacktraceContext) -> io::Result - where F: FnMut(&[u8], u32) -> io::Result<()> -{ - unsupported() -} diff --git a/ctr-std/src/sys/wasm/cmath.rs b/ctr-std/src/sys/wasm/cmath.rs deleted file mode 100644 index 87ac209..0000000 --- a/ctr-std/src/sys/wasm/cmath.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[inline] -pub unsafe fn cbrtf(n: f32) -> f32 { - f64::cbrt(n as f64) as f32 -} - -#[inline] -pub unsafe fn expm1f(n: f32) -> f32 { - f64::exp_m1(n as f64) as f32 -} - -#[inline] -#[allow(deprecated)] -pub unsafe fn fdimf(a: f32, b: f32) -> f32 { - f64::abs_sub(a as f64, b as f64) as f32 -} - -#[inline] -pub unsafe fn log1pf(n: f32) -> f32 { - f64::ln_1p(n as f64) as f32 -} - -#[inline] -pub unsafe fn hypotf(x: f32, y: f32) -> f32 { - f64::hypot(x as f64, y as f64) as f32 -} - -#[inline] -pub unsafe fn acosf(n: f32) -> f32 { - f64::acos(n as f64) as f32 -} - -#[inline] -pub unsafe fn asinf(n: f32) -> f32 { - f64::asin(n as f64) as f32 -} - -#[inline] -pub unsafe fn atan2f(n: f32, b: f32) -> f32 { - f64::atan2(n as f64, b as f64) as f32 -} - -#[inline] -pub unsafe fn atanf(n: f32) -> f32 { - f64::atan(n as f64) as f32 -} - -#[inline] -pub unsafe fn coshf(n: f32) -> f32 { - f64::cosh(n as f64) as f32 -} - -#[inline] -pub unsafe fn sinhf(n: f32) -> f32 { - f64::sinh(n as f64) as f32 -} - -#[inline] -pub unsafe fn tanf(n: f32) -> f32 { - f64::tan(n as f64) as f32 -} - -#[inline] -pub unsafe fn tanhf(n: f32) -> f32 { - f64::tanh(n as f64) as f32 -} - -// Right now all these functions, the f64 version of the functions above, all -// shell out to random names. These names aren't actually defined anywhere, per -// se, but we need this to compile somehow. -// -// The idea with this is that when you're using wasm then, for now, we have no -// way of providing an implementation of these which delegates to a "correct" -// implementation. For example most wasm applications probably just want to -// delegate to the javascript `Math` object and its related functions, but wasm -// doesn't currently have the ability to seamlessly do that (when you -// instantiate a module you have to set that up). -// -// As a result these are just defined here with "hopefully helpful" names. The -// symbols won't ever be needed or show up unless these functions are called, -// and hopefully when they're called the errors are self-explanatory enough to -// figure out what's going on. - -extern { - #[link_name = "Math_acos"] - pub fn acos(n: f64) -> f64; - #[link_name = "Math_asin"] - pub fn asin(n: f64) -> f64; - #[link_name = "Math_atan"] - pub fn atan(n: f64) -> f64; - #[link_name = "Math_atan2"] - pub fn atan2(a: f64, b: f64) -> f64; - #[link_name = "Math_cbrt"] - pub fn cbrt(n: f64) -> f64; - #[link_name = "Math_cosh"] - pub fn cosh(n: f64) -> f64; - #[link_name = "Math_expm1"] - pub fn expm1(n: f64) -> f64; - pub fn fdim(a: f64, b: f64) -> f64; - #[link_name = "Math_log1p"] - pub fn log1p(n: f64) -> f64; - #[link_name = "Math_sinh"] - pub fn sinh(n: f64) -> f64; - #[link_name = "Math_tan"] - pub fn tan(n: f64) -> f64; - #[link_name = "Math_tanh"] - pub fn tanh(n: f64) -> f64; - #[link_name = "Math_hypot"] - pub fn hypot(x: f64, y: f64) -> f64; -} diff --git a/ctr-std/src/sys/wasm/condvar.rs b/ctr-std/src/sys/wasm/condvar.rs deleted file mode 100644 index afa7afe..0000000 --- a/ctr-std/src/sys/wasm/condvar.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use sys::mutex::Mutex; -use time::Duration; - -pub struct Condvar { } - -impl Condvar { - pub const fn new() -> Condvar { - Condvar { } - } - - #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] - pub unsafe fn notify_one(&self) { - } - - #[inline] - pub unsafe fn notify_all(&self) { - } - - pub unsafe fn wait(&self, _mutex: &Mutex) { - panic!("can't block with web assembly") - } - - pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { - panic!("can't block with web assembly"); - } - - #[inline] - pub unsafe fn destroy(&self) { - } -} diff --git a/ctr-std/src/sys/wasm/env.rs b/ctr-std/src/sys/wasm/env.rs deleted file mode 100644 index 1422042..0000000 --- a/ctr-std/src/sys/wasm/env.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub mod os { - pub const FAMILY: &'static str = ""; - pub const OS: &'static str = ""; - pub const DLL_PREFIX: &'static str = ""; - pub const DLL_SUFFIX: &'static str = ".wasm"; - pub const DLL_EXTENSION: &'static str = "wasm"; - pub const EXE_SUFFIX: &'static str = ".wasm"; - pub const EXE_EXTENSION: &'static str = "wasm"; -} diff --git a/ctr-std/src/sys/wasm/fs.rs b/ctr-std/src/sys/wasm/fs.rs deleted file mode 100644 index b3c70a6..0000000 --- a/ctr-std/src/sys/wasm/fs.rs +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::OsString; -use fmt; -use hash::{Hash, Hasher}; -use io::{self, SeekFrom}; -use path::{Path, PathBuf}; -use sys::time::SystemTime; -use sys::{unsupported, Void}; - -pub struct File(Void); - -pub struct FileAttr(Void); - -pub struct ReadDir(Void); - -pub struct DirEntry(Void); - -#[derive(Clone, Debug)] -pub struct OpenOptions { } - -pub struct FilePermissions(Void); - -pub struct FileType(Void); - -#[derive(Debug)] -pub struct DirBuilder { } - -impl FileAttr { - pub fn size(&self) -> u64 { - match self.0 {} - } - - pub fn perm(&self) -> FilePermissions { - match self.0 {} - } - - pub fn file_type(&self) -> FileType { - match self.0 {} - } - - pub fn modified(&self) -> io::Result { - match self.0 {} - } - - pub fn accessed(&self) -> io::Result { - match self.0 {} - } - - pub fn created(&self) -> io::Result { - match self.0 {} - } -} - -impl Clone for FileAttr { - fn clone(&self) -> FileAttr { - match self.0 {} - } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - match self.0 {} - } - - pub fn set_readonly(&mut self, _readonly: bool) { - match self.0 {} - } -} - -impl Clone for FilePermissions { - fn clone(&self) -> FilePermissions { - match self.0 {} - } -} - -impl PartialEq for FilePermissions { - fn eq(&self, _other: &FilePermissions) -> bool { - match self.0 {} - } -} - -impl Eq for FilePermissions { -} - -impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -impl FileType { - pub fn is_dir(&self) -> bool { - match self.0 {} - } - - pub fn is_file(&self) -> bool { - match self.0 {} - } - - pub fn is_symlink(&self) -> bool { - match self.0 {} - } -} - -impl Clone for FileType { - fn clone(&self) -> FileType { - match self.0 {} - } -} - -impl Copy for FileType {} - -impl PartialEq for FileType { - fn eq(&self, _other: &FileType) -> bool { - match self.0 {} - } -} - -impl Eq for FileType { -} - -impl Hash for FileType { - fn hash(&self, _h: &mut H) { - match self.0 {} - } -} - -impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - match self.0 {} - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - match self.0 {} - } - - pub fn file_name(&self) -> OsString { - match self.0 {} - } - - pub fn metadata(&self) -> io::Result { - match self.0 {} - } - - pub fn file_type(&self) -> io::Result { - match self.0 {} - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions { } - } - - pub fn read(&mut self, _read: bool) { } - pub fn write(&mut self, _write: bool) { } - pub fn append(&mut self, _append: bool) { } - pub fn truncate(&mut self, _truncate: bool) { } - pub fn create(&mut self, _create: bool) { } - pub fn create_new(&mut self, _create_new: bool) { } -} - -impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { - unsupported() - } - - pub fn file_attr(&self) -> io::Result { - match self.0 {} - } - - pub fn fsync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn datasync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn truncate(&self, _size: u64) -> io::Result<()> { - match self.0 {} - } - - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn flush(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder { } - } - - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() - } -} - -impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -pub fn readdir(_p: &Path) -> io::Result { - unsupported() -} - -pub fn unlink(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { - unsupported() -} - -pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { - match perm.0 {} -} - -pub fn rmdir(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - unsupported() -} - -pub fn readlink(_p: &Path) -> io::Result { - unsupported() -} - -pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn stat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn lstat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn canonicalize(_p: &Path) -> io::Result { - unsupported() -} - -pub fn copy(_from: &Path, _to: &Path) -> io::Result { - unsupported() -} diff --git a/ctr-std/src/sys/wasm/memchr.rs b/ctr-std/src/sys/wasm/memchr.rs deleted file mode 100644 index 964e359..0000000 --- a/ctr-std/src/sys/wasm/memchr.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use core::slice::memchr::{memchr, memrchr}; diff --git a/ctr-std/src/sys/wasm/mod.rs b/ctr-std/src/sys/wasm/mod.rs deleted file mode 100644 index c02e5e8..0000000 --- a/ctr-std/src/sys/wasm/mod.rs +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! System bindings for the wasm/web platform -//! -//! This module contains the facade (aka platform-specific) implementations of -//! OS level functionality for wasm. Note that this wasm is *not* the emscripten -//! wasm, so we have no runtime here. -//! -//! This is all super highly experimental and not actually intended for -//! wide/production use yet, it's still all in the experimental category. This -//! will likely change over time. -//! -//! Currently all functions here are basically stubs that immediately return -//! errors. The hope is that with a portability lint we can turn actually just -//! remove all this and just omit parts of the standard library if we're -//! compiling for wasm. That way it's a compile time error for something that's -//! guaranteed to be a runtime error! - -use io; -use os::raw::c_char; -use ptr; -use sys::os_str::Buf; -use sys_common::{AsInner, FromInner}; -use ffi::{OsString, OsStr}; -use time::Duration; - -pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; -pub mod cmath; -pub mod condvar; -pub mod env; -pub mod fs; -pub mod memchr; -pub mod mutex; -pub mod net; -pub mod os; -pub mod os_str; -pub mod path; -pub mod pipe; -pub mod process; -pub mod rwlock; -pub mod stack_overflow; -pub mod thread; -pub mod thread_local; -pub mod time; -pub mod stdio; - -#[cfg(not(test))] -pub fn init() { -} - -pub fn unsupported() -> io::Result { - Err(unsupported_err()) -} - -pub fn unsupported_err() -> io::Error { - io::Error::new(io::ErrorKind::Other, - "operation not supported on wasm yet") -} - -pub fn decode_error_kind(_code: i32) -> io::ErrorKind { - io::ErrorKind::Other -} - -// This enum is used as the storage for a bunch of types which can't actually -// exist. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub enum Void {} - -pub unsafe fn strlen(mut s: *const c_char) -> usize { - let mut n = 0; - while *s != 0 { - n += 1; - s = s.offset(1); - } - return n -} - -pub unsafe fn abort_internal() -> ! { - ExitSysCall::perform(1) -} - -// We don't have randomness yet, but I totally used a random number generator to -// generate these numbers. -// -// More seriously though this is just for DOS protection in hash maps. It's ok -// if we don't do that on wasm just yet. -pub fn hashmap_random_keys() -> (u64, u64) { - (1, 2) -} - -// Implement a minimal set of system calls to enable basic IO -pub enum SysCallIndex { - Read = 0, - Write = 1, - Exit = 2, - Args = 3, - GetEnv = 4, - SetEnv = 5, - Time = 6, -} - -#[repr(C)] -pub struct ReadSysCall { - fd: usize, - ptr: *mut u8, - len: usize, - result: usize, -} - -impl ReadSysCall { - pub fn perform(fd: usize, buffer: &mut [u8]) -> usize { - let mut call_record = ReadSysCall { - fd, - len: buffer.len(), - ptr: buffer.as_mut_ptr(), - result: 0 - }; - if unsafe { syscall(SysCallIndex::Read, &mut call_record) } { - call_record.result - } else { - 0 - } - } -} - -#[repr(C)] -pub struct WriteSysCall { - fd: usize, - ptr: *const u8, - len: usize, -} - -impl WriteSysCall { - pub fn perform(fd: usize, buffer: &[u8]) { - let mut call_record = WriteSysCall { - fd, - len: buffer.len(), - ptr: buffer.as_ptr() - }; - unsafe { syscall(SysCallIndex::Write, &mut call_record); } - } -} - -#[repr(C)] -pub struct ExitSysCall { - code: usize, -} - -impl ExitSysCall { - pub fn perform(code: usize) -> ! { - let mut call_record = ExitSysCall { - code - }; - unsafe { - syscall(SysCallIndex::Exit, &mut call_record); - ::intrinsics::abort(); - } - } -} - -fn receive_buffer Result>(estimate: usize, mut f: F) - -> Result, E> -{ - let mut buffer = vec![0; estimate]; - loop { - let result = f(&mut buffer)?; - if result <= buffer.len() { - buffer.truncate(result); - break; - } - buffer.resize(result, 0); - } - Ok(buffer) -} - -#[repr(C)] -pub struct ArgsSysCall { - ptr: *mut u8, - len: usize, - result: usize -} - -impl ArgsSysCall { - pub fn perform() -> Vec { - receive_buffer(1024, |buffer| -> Result { - let mut call_record = ArgsSysCall { - len: buffer.len(), - ptr: buffer.as_mut_ptr(), - result: 0 - }; - if unsafe { syscall(SysCallIndex::Args, &mut call_record) } { - Ok(call_record.result) - } else { - Ok(0) - } - }) - .unwrap() - .split(|b| *b == 0) - .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() })) - .collect() - } -} - -#[repr(C)] -pub struct GetEnvSysCall { - key_ptr: *const u8, - key_len: usize, - value_ptr: *mut u8, - value_len: usize, - result: usize -} - -impl GetEnvSysCall { - pub fn perform(key: &OsStr) -> Option { - let key_buf = &AsInner::as_inner(key).inner; - receive_buffer(64, |buffer| { - let mut call_record = GetEnvSysCall { - key_len: key_buf.len(), - key_ptr: key_buf.as_ptr(), - value_len: buffer.len(), - value_ptr: buffer.as_mut_ptr(), - result: !0usize - }; - if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } { - if call_record.result == !0usize { - Err(()) - } else { - Ok(call_record.result) - } - } else { - Err(()) - } - }).ok().map(|s| { - FromInner::from_inner(Buf { inner: s }) - }) - } -} - -#[repr(C)] -pub struct SetEnvSysCall { - key_ptr: *const u8, - key_len: usize, - value_ptr: *const u8, - value_len: usize -} - -impl SetEnvSysCall { - pub fn perform(key: &OsStr, value: Option<&OsStr>) { - let key_buf = &AsInner::as_inner(key).inner; - let value_buf = value.map(|v| &AsInner::as_inner(v).inner); - let mut call_record = SetEnvSysCall { - key_len: key_buf.len(), - key_ptr: key_buf.as_ptr(), - value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize), - value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null()) - }; - unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); } - } -} - -pub enum TimeClock { - Monotonic = 0, - System = 1, -} - -#[repr(C)] -pub struct TimeSysCall { - clock: usize, - secs_hi: usize, - secs_lo: usize, - nanos: usize -} - -impl TimeSysCall { - pub fn perform(clock: TimeClock) -> Duration { - let mut call_record = TimeSysCall { - clock: clock as usize, - secs_hi: 0, - secs_lo: 0, - nanos: 0 - }; - if unsafe { syscall(SysCallIndex::Time, &mut call_record) } { - Duration::new( - ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64), - call_record.nanos as u32 - ) - } else { - panic!("Time system call is not implemented by WebAssembly host"); - } - } -} - -unsafe fn syscall(index: SysCallIndex, data: &mut T) -> bool { - #[cfg(feature = "wasm_syscall")] - extern { - #[no_mangle] - fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize; - } - - #[cfg(not(feature = "wasm_syscall"))] - unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 } - - rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0 -} diff --git a/ctr-std/src/sys/wasm/mutex.rs b/ctr-std/src/sys/wasm/mutex.rs deleted file mode 100644 index 4197bdc..0000000 --- a/ctr-std/src/sys/wasm/mutex.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; - -pub struct Mutex { - locked: UnsafeCell, -} - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} // no threads on wasm - -impl Mutex { - pub const fn new() -> Mutex { - Mutex { locked: UnsafeCell::new(false) } - } - - #[inline] - pub unsafe fn init(&mut self) { - } - - #[inline] - pub unsafe fn lock(&self) { - let locked = self.locked.get(); - assert!(!*locked, "cannot recursively acquire mutex"); - *locked = true; - } - - #[inline] - pub unsafe fn unlock(&self) { - *self.locked.get() = false; - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - let locked = self.locked.get(); - if *locked { - false - } else { - *locked = true; - true - } - } - - #[inline] - pub unsafe fn destroy(&self) { - } -} - -// All empty stubs because wasm has no threads yet, so lock acquisition always -// succeeds. -pub struct ReentrantMutex { -} - -impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex { } - } - - pub unsafe fn init(&mut self) {} - - pub unsafe fn lock(&self) {} - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - true - } - - pub unsafe fn unlock(&self) {} - - pub unsafe fn destroy(&self) {} -} diff --git a/ctr-std/src/sys/wasm/net.rs b/ctr-std/src/sys/wasm/net.rs deleted file mode 100644 index e7476ab..0000000 --- a/ctr-std/src/sys/wasm/net.rs +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use fmt; -use io; -use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; -use time::Duration; -use sys::{unsupported, Void}; - -pub struct TcpStream(Void); - -impl TcpStream { - pub fn connect(_: &SocketAddr) -> io::Result { - unsupported() - } - - pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { - unsupported() - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn read_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn write_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn write(&self, _: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn peer_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn socket_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn nodelay(&self) -> io::Result { - match self.0 {} - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn ttl(&self) -> io::Result { - match self.0 {} - } - - pub fn take_error(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} - } -} - -impl fmt::Debug for TcpStream { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -pub struct TcpListener(Void); - -impl TcpListener { - pub fn bind(_: &SocketAddr) -> io::Result { - unsupported() - } - - pub fn socket_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn ttl(&self) -> io::Result { - match self.0 {} - } - - pub fn set_only_v6(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn only_v6(&self) -> io::Result { - match self.0 {} - } - - pub fn take_error(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} - } -} - -impl fmt::Debug for TcpListener { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -pub struct UdpSocket(Void); - -impl UdpSocket { - pub fn bind(_: &SocketAddr) -> io::Result { - unsupported() - } - - pub fn socket_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - match self.0 {} - } - - pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - match self.0 {} - } - - pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn read_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn write_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_broadcast(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn broadcast(&self) -> io::Result { - match self.0 {} - } - - pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn multicast_loop_v4(&self) -> io::Result { - match self.0 {} - } - - pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - match self.0 {} - } - - pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn multicast_loop_v6(&self) -> io::Result { - match self.0 {} - } - - pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) - -> io::Result<()> { - match self.0 {} - } - - pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) - -> io::Result<()> { - match self.0 {} - } - - pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) - -> io::Result<()> { - match self.0 {} - } - - pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) - -> io::Result<()> { - match self.0 {} - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn ttl(&self) -> io::Result { - match self.0 {} - } - - pub fn take_error(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn recv(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn send(&self, _: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn connect(&self, _: &SocketAddr) -> io::Result<()> { - match self.0 {} - } -} - -impl fmt::Debug for UdpSocket { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -pub struct LookupHost(Void); - -impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option { - match self.0 {} - } -} - -pub fn lookup_host(_: &str) -> io::Result { - unsupported() -} - -#[allow(bad_style)] -pub mod netc { - pub const AF_INET: u8 = 0; - pub const AF_INET6: u8 = 1; - pub type sa_family_t = u8; - - #[derive(Copy, Clone)] - pub struct in_addr { - pub s_addr: u32, - } - - #[derive(Copy, Clone)] - pub struct sockaddr_in { - pub sin_family: sa_family_t, - pub sin_port: u16, - pub sin_addr: in_addr, - } - - #[derive(Copy, Clone)] - pub struct in6_addr { - pub s6_addr: [u8; 16], - } - - #[derive(Copy, Clone)] - pub struct sockaddr_in6 { - pub sin6_family: sa_family_t, - pub sin6_port: u16, - pub sin6_addr: in6_addr, - pub sin6_flowinfo: u32, - pub sin6_scope_id: u32, - } - - #[derive(Copy, Clone)] - pub struct sockaddr { - } - - pub type socklen_t = usize; -} diff --git a/ctr-std/src/sys/wasm/os.rs b/ctr-std/src/sys/wasm/os.rs deleted file mode 100644 index 0cb991e..0000000 --- a/ctr-std/src/sys/wasm/os.rs +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use error::Error as StdError; -use ffi::{OsString, OsStr}; -use fmt; -use io; -use path::{self, PathBuf}; -use str; -use sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall}; - -pub fn errno() -> i32 { - 0 -} - -pub fn error_string(_errno: i32) -> String { - "operation successful".to_string() -} - -pub fn getcwd() -> io::Result { - unsupported() -} - -pub fn chdir(_: &path::Path) -> io::Result<()> { - unsupported() -} - -pub struct SplitPaths<'a>(&'a Void); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - match *self.0 {} - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result - where I: Iterator, T: AsRef -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "not supported on wasm yet".fmt(f) - } -} - -impl StdError for JoinPathsError { - fn description(&self) -> &str { - "not supported on wasm yet" - } -} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub struct Env(Void); - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - match self.0 {} - } -} - -pub fn env() -> Env { - panic!("not supported on web assembly") -} - -pub fn getenv(k: &OsStr) -> io::Result> { - Ok(GetEnvSysCall::perform(k)) -} - -pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - Ok(SetEnvSysCall::perform(k, Some(v))) -} - -pub fn unsetenv(k: &OsStr) -> io::Result<()> { - Ok(SetEnvSysCall::perform(k, None)) -} - -pub fn temp_dir() -> PathBuf { - panic!("no filesystem on wasm") -} - -pub fn home_dir() -> Option { - None -} - -pub fn exit(_code: i32) -> ! { - ExitSysCall::perform(_code as isize as usize) -} - -pub fn getpid() -> u32 { - panic!("no pids on wasm") -} diff --git a/ctr-std/src/sys/wasm/os_str.rs b/ctr-std/src/sys/wasm/os_str.rs deleted file mode 100644 index e0da5bd..0000000 --- a/ctr-std/src/sys/wasm/os_str.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// The underlying OsString/OsStr implementation on Unix systems: just -/// a `Vec`/`[u8]`. - -use borrow::Cow; -use fmt; -use str; -use mem; -use rc::Rc; -use sync::Arc; -use sys_common::{AsInner, IntoInner}; -use sys_common::bytestring::debug_fmt_bytestring; -use core::str::lossy::Utf8Lossy; - -#[derive(Clone, Hash)] -pub struct Buf { - pub inner: Vec -} - -pub struct Slice { - pub inner: [u8] -} - -impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - debug_fmt_bytestring(&self.inner, formatter) - } -} - -impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) - } -} - -impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) - } -} - -impl IntoInner> for Buf { - fn into_inner(self) -> Vec { - self.inner - } -} - -impl AsInner<[u8]> for Buf { - fn as_inner(&self) -> &[u8] { - &self.inner - } -} - - -impl Buf { - pub fn from_string(s: String) -> Buf { - Buf { inner: s.into_bytes() } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Buf { - Buf { - inner: Vec::with_capacity(capacity) - } - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear() - } - - #[inline] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - pub fn as_slice(&self) -> &Slice { - unsafe { mem::transmute(&*self.inner) } - } - - pub fn into_string(self) -> Result { - String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) - } - - pub fn push_slice(&mut self, s: &Slice) { - self.inner.extend_from_slice(&s.inner) - } - - #[inline] - pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.inner.into_boxed_slice()) } - } - - #[inline] - pub fn from_box(boxed: Box) -> Buf { - let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Buf { inner: inner.into_vec() } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - self.as_slice().into_arc() - } - - #[inline] - pub fn into_rc(&self) -> Rc { - self.as_slice().into_rc() - } -} - -impl Slice { - fn from_u8_slice(s: &[u8]) -> &Slice { - unsafe { mem::transmute(s) } - } - - pub fn from_str(s: &str) -> &Slice { - Slice::from_u8_slice(s.as_bytes()) - } - - pub fn to_str(&self) -> Option<&str> { - str::from_utf8(&self.inner).ok() - } - - pub fn to_string_lossy(&self) -> Cow { - String::from_utf8_lossy(&self.inner) - } - - pub fn to_owned(&self) -> Buf { - Buf { inner: self.inner.to_vec() } - } - - #[inline] - pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.inner.into(); - unsafe { mem::transmute(boxed) } - } - - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.inner); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.inner); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } - } -} diff --git a/ctr-std/src/sys/wasm/path.rs b/ctr-std/src/sys/wasm/path.rs deleted file mode 100644 index 395b8c1..0000000 --- a/ctr-std/src/sys/wasm/path.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use path::Prefix; -use ffi::OsStr; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option { - None -} - -pub const MAIN_SEP_STR: &'static str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/ctr-std/src/sys/wasm/pipe.rs b/ctr-std/src/sys/wasm/pipe.rs deleted file mode 100644 index 992e1ac..0000000 --- a/ctr-std/src/sys/wasm/pipe.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use sys::Void; - -pub struct AnonPipe(Void); - -impl AnonPipe { - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -pub fn read2(p1: AnonPipe, - _v1: &mut Vec, - _p2: AnonPipe, - _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} diff --git a/ctr-std/src/sys/wasm/process.rs b/ctr-std/src/sys/wasm/process.rs deleted file mode 100644 index 433e9ce..0000000 --- a/ctr-std/src/sys/wasm/process.rs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::OsStr; -use fmt; -use io; -use sys::fs::File; -use sys::pipe::AnonPipe; -use sys::{unsupported, Void}; -use sys_common::process::{CommandEnv, DefaultEnvKey}; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - env: CommandEnv -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, -} - -impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { - env: Default::default() - } - } - - pub fn arg(&mut self, _arg: &OsStr) { - } - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, _dir: &OsStr) { - } - - pub fn stdin(&mut self, _stdin: Stdio) { - } - - pub fn stdout(&mut self, _stdout: Stdio) { - } - - pub fn stderr(&mut self, _stderr: Stdio) { - } - - pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool) - -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - file.diverge() - } -} - -impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - Ok(()) - } -} - -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } -} - -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - match self.0 {} - } -} - -impl Copy for ExitStatus {} - -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { - match self.0 {} - } -} - -impl Eq for ExitStatus { -} - -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - match self.0 {} - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(bool); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(false); - pub const FAILURE: ExitCode = ExitCode(true); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} diff --git a/ctr-std/src/sys/wasm/rwlock.rs b/ctr-std/src/sys/wasm/rwlock.rs deleted file mode 100644 index 6516010..0000000 --- a/ctr-std/src/sys/wasm/rwlock.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; - -pub struct RWLock { - mode: UnsafeCell, -} - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} // no threads on wasm - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { - mode: UnsafeCell::new(0), - } - } - - #[inline] - pub unsafe fn read(&self) { - let mode = self.mode.get(); - if *mode >= 0 { - *mode += 1; - } else { - rtabort!("rwlock locked for writing"); - } - } - - #[inline] - pub unsafe fn try_read(&self) -> bool { - let mode = self.mode.get(); - if *mode >= 0 { - *mode += 1; - true - } else { - false - } - } - - #[inline] - pub unsafe fn write(&self) { - let mode = self.mode.get(); - if *mode == 0 { - *mode = -1; - } else { - rtabort!("rwlock locked for reading") - } - } - - #[inline] - pub unsafe fn try_write(&self) -> bool { - let mode = self.mode.get(); - if *mode == 0 { - *mode = -1; - true - } else { - false - } - } - - #[inline] - pub unsafe fn read_unlock(&self) { - *self.mode.get() -= 1; - } - - #[inline] - pub unsafe fn write_unlock(&self) { - *self.mode.get() += 1; - } - - #[inline] - pub unsafe fn destroy(&self) { - } -} diff --git a/ctr-std/src/sys/wasm/stack_overflow.rs b/ctr-std/src/sys/wasm/stack_overflow.rs deleted file mode 100644 index bed2741..0000000 --- a/ctr-std/src/sys/wasm/stack_overflow.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub struct Handler; - -impl Handler { - pub unsafe fn new() -> Handler { - Handler - } -} - -pub unsafe fn init() { -} - -pub unsafe fn cleanup() { -} diff --git a/ctr-std/src/sys/wasm/stdio.rs b/ctr-std/src/sys/wasm/stdio.rs deleted file mode 100644 index 023f295..0000000 --- a/ctr-std/src/sys/wasm/stdio.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use sys::{ReadSysCall, WriteSysCall}; - -pub struct Stdin; -pub struct Stdout; -pub struct Stderr; - -impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin) - } - - pub fn read(&self, data: &mut [u8]) -> io::Result { - Ok(ReadSysCall::perform(0, data)) - } -} - -impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout) - } - - pub fn write(&self, data: &[u8]) -> io::Result { - WriteSysCall::perform(1, data); - Ok(data.len()) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr) - } - - pub fn write(&self, data: &[u8]) -> io::Result { - WriteSysCall::perform(2, data); - Ok(data.len()) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result { - (&*self).write(data) - } - fn flush(&mut self) -> io::Result<()> { - (&*self).flush() - } -} - -pub const STDIN_BUF_SIZE: usize = 0; - -pub fn is_ebadf(_err: &io::Error) -> bool { - true -} - -pub fn stderr_prints_nothing() -> bool { - !cfg!(feature = "wasm_syscall") -} diff --git a/ctr-std/src/sys/wasm/thread.rs b/ctr-std/src/sys/wasm/thread.rs deleted file mode 100644 index 8173a62..0000000 --- a/ctr-std/src/sys/wasm/thread.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use boxed::FnBox; -use ffi::CStr; -use io; -use sys::{unsupported, Void}; -use time::Duration; - -pub struct Thread(Void); - -pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; - -impl Thread { - pub unsafe fn new<'a>(_stack: usize, _p: Box) - -> io::Result - { - unsupported() - } - - pub fn yield_now() { - // do nothing - } - - pub fn set_name(_name: &CStr) { - // nope - } - - pub fn sleep(_dur: Duration) { - panic!("can't sleep"); - } - - pub fn join(self) { - match self.0 {} - } -} - -pub mod guard { - pub type Guard = !; - pub unsafe fn current() -> Option { None } - pub unsafe fn init() -> Option { None } - pub unsafe fn deinit() {} -} diff --git a/ctr-std/src/sys/wasm/thread_local.rs b/ctr-std/src/sys/wasm/thread_local.rs deleted file mode 100644 index 442dd33..0000000 --- a/ctr-std/src/sys/wasm/thread_local.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use boxed::Box; -use ptr; - -pub type Key = usize; - -struct Allocated { - value: *mut u8, - dtor: Option, -} - -#[inline] -pub unsafe fn create(dtor: Option) -> Key { - Box::into_raw(Box::new(Allocated { - value: ptr::null_mut(), - dtor, - })) as usize -} - -#[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - (*(key as *mut Allocated)).value = value; -} - -#[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - (*(key as *mut Allocated)).value -} - -#[inline] -pub unsafe fn destroy(key: Key) { - let key = Box::from_raw(key as *mut Allocated); - if let Some(f) = key.dtor { - f(key.value); - } -} - -#[inline] -pub fn requires_synchronized_create() -> bool { - false -} diff --git a/ctr-std/src/sys/wasm/time.rs b/ctr-std/src/sys/wasm/time.rs deleted file mode 100644 index e52435e..0000000 --- a/ctr-std/src/sys/wasm/time.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use time::Duration; -use sys::{TimeSysCall, TimeClock}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(Duration); - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct SystemTime(Duration); - -pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); - -impl Instant { - pub fn now() -> Instant { - Instant(TimeSysCall::perform(TimeClock::Monotonic)) - } - - pub fn sub_instant(&self, other: &Instant) -> Duration { - self.0 - other.0 - } - - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant(self.0 + *other) - } - - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant(self.0 - *other) - } -} - -impl SystemTime { - pub fn now() -> SystemTime { - SystemTime(TimeSysCall::perform(TimeClock::System)) - } - - pub fn sub_time(&self, other: &SystemTime) - -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) - } - - pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime(self.0 + *other) - } - - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - SystemTime(self.0 - *other) - } -} diff --git a/ctr-std/src/sys/windows/args.rs b/ctr-std/src/sys/windows/args.rs deleted file mode 100644 index 4784633..0000000 --- a/ctr-std/src/sys/windows/args.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] // runtime init functions not used during testing - -use os::windows::prelude::*; -use sys::c; -use slice; -use ops::Range; -use ffi::OsString; -use libc::{c_int, c_void}; -use fmt; - -pub unsafe fn init(_argc: isize, _argv: *const *const u8) { } - -pub unsafe fn cleanup() { } - -pub fn args() -> Args { - unsafe { - let mut nArgs: c_int = 0; - let lpCmdLine = c::GetCommandLineW(); - let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs); - - // szArcList can be NULL if CommandLinToArgvW failed, - // but in that case nArgs is 0 so we won't actually - // try to read a null pointer - Args { cur: szArgList, range: 0..(nArgs as isize) } - } -} - -pub struct Args { - range: Range, - cur: *mut *mut u16, -} - -pub struct ArgsInnerDebug<'a> { - args: &'a Args, -} - -impl<'a> fmt::Debug for ArgsInnerDebug<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("[")?; - let mut first = true; - for i in self.args.range.clone() { - if !first { - f.write_str(", ")?; - } - first = false; - - // Here we do allocation which could be avoided. - fmt::Debug::fmt(&unsafe { os_string_from_ptr(*self.args.cur.offset(i)) }, f)?; - } - f.write_str("]")?; - Ok(()) - } -} - -impl Args { - pub fn inner_debug(&self) -> ArgsInnerDebug { - ArgsInnerDebug { - args: self - } - } -} - -unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString { - let mut len = 0; - while *ptr.offset(len) != 0 { len += 1; } - - // Push it onto the list. - let ptr = ptr as *const u16; - let buf = slice::from_raw_parts(ptr, len as usize); - OsStringExt::from_wide(buf) -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) - } - fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { self.range.len() } -} - -impl Drop for Args { - fn drop(&mut self) { - // self.cur can be null if CommandLineToArgvW previously failed, - // but LocalFree ignores NULL pointers - unsafe { c::LocalFree(self.cur as *mut c_void); } - } -} diff --git a/ctr-std/src/sys/windows/backtrace/backtrace_gnu.rs b/ctr-std/src/sys/windows/backtrace/backtrace_gnu.rs deleted file mode 100644 index f0d29dd..0000000 --- a/ctr-std/src/sys/windows/backtrace/backtrace_gnu.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use sys::c; -use libc::c_char; -use path::PathBuf; -use fs::{OpenOptions, File}; -use sys::ext::fs::OpenOptionsExt; -use sys::handle::Handle; -use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte}; - -fn query_full_process_image_name() -> io::Result { - unsafe { - let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION, - c::FALSE, - c::GetCurrentProcessId())); - fill_utf16_buf(|buf, mut sz| { - if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 { - 0 - } else { - sz - } - }, os2path) - } -} - -fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> { - // We query the current image name, open the file without FILE_SHARE_DELETE so it - // can't be moved and then get the current image name again. If the names are the - // same than we have successfully locked the file - let image_name1 = query_full_process_image_name()?; - let file = OpenOptions::new() - .read(true) - .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE) - .open(&image_name1)?; - let image_name2 = query_full_process_image_name()?; - - if image_name1 != image_name2 { - return Err(io::Error::new(io::ErrorKind::Other, - "executable moved while trying to lock it")); - } - - Ok((image_name1, file)) -} - -// Get the executable filename for libbacktrace -// This returns the path in the ANSI code page and a File which should remain open -// for as long as the path should remain valid -pub fn get_executable_filename() -> io::Result<(Vec, File)> { - let (executable, file) = lock_and_get_executable_filename()?; - let u16_executable = to_u16s(executable.into_os_string())?; - Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS, - &u16_executable, true)?, file)) -} diff --git a/ctr-std/src/sys/windows/backtrace/mod.rs b/ctr-std/src/sys/windows/backtrace/mod.rs deleted file mode 100644 index f64cae8..0000000 --- a/ctr-std/src/sys/windows/backtrace/mod.rs +++ /dev/null @@ -1,326 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! As always, windows has something very different than unix, we mainly want -//! to avoid having to depend too much on libunwind for windows. -//! -//! If you google around, you'll find a fair bit of references to built-in -//! functions to get backtraces on windows. It turns out that most of these are -//! in an external library called dbghelp. I was unable to find this library -//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent -//! of it. -//! -//! You'll also find that there's a function called CaptureStackBackTrace -//! mentioned frequently (which is also easy to use), but sadly I didn't have a -//! copy of that function in my mingw install (maybe it was broken?). Instead, -//! this takes the route of using StackWalk64 in order to walk the stack. - -#![allow(deprecated)] // dynamic_lib - -use io; -use libc::c_void; -use mem; -use ptr; -use sys::c; -use sys::dynamic_lib::DynamicLibrary; -use sys_common::backtrace::Frame; - -macro_rules! sym { - ($lib:expr, $e:expr, $t:ident) => ( - $lib.symbol($e).map(|f| unsafe { - $crate::mem::transmute::(f) - }) - ) -} - -mod printing; - -#[cfg(target_env = "gnu")] -#[path = "backtrace_gnu.rs"] -pub mod gnu; - -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; -use self::printing::{load_printing_fns_64, load_printing_fns_ex}; - -pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { - let dbghelp = DynamicLibrary::open("dbghelp.dll")?; - - // Fetch the symbols necessary from dbghelp.dll - let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; - let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - - // StackWalkEx might not be present and we'll fall back to StackWalk64 - let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) { - Ok(StackWalkEx) => { - StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?) - } - Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) { - Ok(StackWalk64) => { - StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?) - } - Err(..) => return Err(e), - }, - }; - - // Allocate necessary structures for doing the stack walk - let process = unsafe { c::GetCurrentProcess() }; - - let backtrace_context = BacktraceContext { - handle: process, - SymCleanup, - StackWalkVariant: sw_var, - dbghelp, - }; - - // Initialize this process's symbols - let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) }; - if ret != c::TRUE { - return Ok((0, backtrace_context)); - } - - // And now that we're done with all the setup, do the stack walking! - match backtrace_context.StackWalkVariant { - StackWalkVariant::StackWalkEx(StackWalkEx, _) => { - set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context)) - } - - StackWalkVariant::StackWalk64(StackWalk64, _) => { - set_frames(StackWalk64, frames).map(|i| (i, backtrace_context)) - } - } -} - -fn set_frames(StackWalk: W, frames: &mut [Frame]) -> io::Result { - let process = unsafe { c::GetCurrentProcess() }; - let thread = unsafe { c::GetCurrentProcess() }; - let mut context: c::CONTEXT = unsafe { mem::zeroed() }; - unsafe { c::RtlCaptureContext(&mut context) }; - let mut frame = W::Item::new(); - let image = frame.init(&context); - - let mut i = 0; - while i < frames.len() - && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE - { - let addr = frame.get_addr(); - frames[i] = Frame { - symbol_addr: addr, - exact_position: addr, - inline_context: 0, - }; - - i += 1 - } - Ok(i) -} - -type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; -type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL; - -type StackWalkExFn = unsafe extern "system" fn( - c::DWORD, - c::HANDLE, - c::HANDLE, - *mut c::STACKFRAME_EX, - *mut c::CONTEXT, - *mut c_void, - *mut c_void, - *mut c_void, - *mut c_void, - c::DWORD, -) -> c::BOOL; - -type StackWalk64Fn = unsafe extern "system" fn( - c::DWORD, - c::HANDLE, - c::HANDLE, - *mut c::STACKFRAME64, - *mut c::CONTEXT, - *mut c_void, - *mut c_void, - *mut c_void, - *mut c_void, -) -> c::BOOL; - -trait StackWalker { - type Item: StackFrame; - - fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL; -} - -impl StackWalker for StackWalkExFn { - type Item = c::STACKFRAME_EX; - fn walk( - &self, - image: c::DWORD, - process: c::HANDLE, - thread: c::HANDLE, - frame: &mut Self::Item, - context: &mut c::CONTEXT, - ) -> c::BOOL { - unsafe { - self( - image, - process, - thread, - frame, - context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0, - ) - } - } -} - -impl StackWalker for StackWalk64Fn { - type Item = c::STACKFRAME64; - fn walk( - &self, - image: c::DWORD, - process: c::HANDLE, - thread: c::HANDLE, - frame: &mut Self::Item, - context: &mut c::CONTEXT, - ) -> c::BOOL { - unsafe { - self( - image, - process, - thread, - frame, - context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ) - } - } -} - -trait StackFrame { - fn new() -> Self; - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD; - fn get_addr(&self) -> *const u8; -} - -impl StackFrame for c::STACKFRAME_EX { - fn new() -> c::STACKFRAME_EX { - unsafe { mem::zeroed() } - } - - #[cfg(target_arch = "x86")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Eip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Esp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Ebp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 - } - - #[cfg(target_arch = "x86_64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Rip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Rsp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Rbp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 - } - - #[cfg(target_arch = "aarch64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Pc as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Sp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Fp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_ARM64 - } - - fn get_addr(&self) -> *const u8 { - (self.AddrPC.Offset - 1) as *const u8 - } -} - -impl StackFrame for c::STACKFRAME64 { - fn new() -> c::STACKFRAME64 { - unsafe { mem::zeroed() } - } - - #[cfg(target_arch = "x86")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Eip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Esp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Ebp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 - } - - #[cfg(target_arch = "x86_64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Rip as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Rsp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Rbp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 - } - - #[cfg(target_arch = "aarch64")] - fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { - self.AddrPC.Offset = ctx.Pc as u64; - self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrStack.Offset = ctx.Sp as u64; - self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - self.AddrFrame.Offset = ctx.Fp as u64; - self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_ARM64 - } - - fn get_addr(&self) -> *const u8 { - (self.AddrPC.Offset - 1) as *const u8 - } -} - -enum StackWalkVariant { - StackWalkEx(StackWalkExFn, printing::PrintingFnsEx), - StackWalk64(StackWalk64Fn, printing::PrintingFns64), -} - -pub struct BacktraceContext { - handle: c::HANDLE, - SymCleanup: SymCleanupFn, - // Only used in printing for msvc and not gnu - // The gnu version is effectively a ZST dummy. - #[allow(dead_code)] - StackWalkVariant: StackWalkVariant, - // keeping DynamycLibrary loaded until its functions no longer needed - #[allow(dead_code)] - dbghelp: DynamicLibrary, -} - -impl Drop for BacktraceContext { - fn drop(&mut self) { - unsafe { - (self.SymCleanup)(self.handle); - } - } -} diff --git a/ctr-std/src/sys/windows/backtrace/printing/mod.rs b/ctr-std/src/sys/windows/backtrace/printing/mod.rs deleted file mode 100644 index 251d502..0000000 --- a/ctr-std/src/sys/windows/backtrace/printing/mod.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[cfg(target_env = "msvc")] -#[path = "msvc.rs"] -mod printing; - -#[cfg(target_env = "gnu")] -mod printing { - pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; - - // dummy functions to mirror those present in msvc version. - use sys::dynamic_lib::DynamicLibrary; - use io; - pub struct PrintingFnsEx {} - pub struct PrintingFns64 {} - pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result { - Ok(PrintingFnsEx{}) - } - pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result { - Ok(PrintingFns64{}) - } -} - -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; -pub use self::printing::{load_printing_fns_ex, load_printing_fns_64, - PrintingFnsEx, PrintingFns64}; diff --git a/ctr-std/src/sys/windows/backtrace/printing/msvc.rs b/ctr-std/src/sys/windows/backtrace/printing/msvc.rs deleted file mode 100644 index c8b946b..0000000 --- a/ctr-std/src/sys/windows/backtrace/printing/msvc.rs +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ffi::CStr; -use io; -use libc::{c_char, c_ulong}; -use mem; -use sys::backtrace::BacktraceContext; -use sys::backtrace::StackWalkVariant; -use sys::c; -use sys::dynamic_lib::DynamicLibrary; -use sys_common::backtrace::Frame; - -// Structs holding printing functions and loaders for them -// Two versions depending on whether dbghelp.dll has StackWalkEx or not -// (the former being in newer Windows versions, the older being in Win7 and before) -pub struct PrintingFnsEx { - resolve_symname: SymFromInlineContextFn, - sym_get_line: SymGetLineFromInlineContextFn, -} -pub struct PrintingFns64 { - resolve_symname: SymFromAddrFn, - sym_get_line: SymGetLineFromAddr64Fn, -} - -pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result { - Ok(PrintingFnsEx { - resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?, - sym_get_line: sym!( - dbghelp, - "SymGetLineFromInlineContext", - SymGetLineFromInlineContextFn - )?, - }) -} -pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result { - Ok(PrintingFns64 { - resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?, - sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?, - }) -} - -type SymFromAddrFn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; -type SymFromInlineContextFn = - unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; - -type SymGetLineFromAddr64Fn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL; -type SymGetLineFromInlineContextFn = unsafe extern "system" fn( - c::HANDLE, - u64, - c::ULONG, - u64, - *mut c::DWORD, - *mut c::IMAGEHLP_LINE64, -) -> c::BOOL; - -/// Converts a pointer to symbol to its string value. -pub fn resolve_symname(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()>, -{ - match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal( - |process: c::HANDLE, - symbol_address: u64, - inline_context: c::ULONG, - info: *mut c::SYMBOL_INFO| unsafe { - let mut displacement = 0u64; - (fns.resolve_symname)( - process, - symbol_address, - inline_context, - &mut displacement, - info, - ) - }, - frame, - callback, - context, - ), - StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal( - |process: c::HANDLE, - symbol_address: u64, - _inline_context: c::ULONG, - info: *mut c::SYMBOL_INFO| unsafe { - let mut displacement = 0u64; - (fns.resolve_symname)(process, symbol_address, &mut displacement, info) - }, - frame, - callback, - context, - ), - } -} - -fn resolve_symname_internal( - mut symbol_resolver: R, - frame: Frame, - callback: F, - context: &BacktraceContext, -) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()>, - R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL, -{ - unsafe { - let mut info: c::SYMBOL_INFO = mem::zeroed(); - info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; - // the struct size in C. the value is different to - // `size_of::() - MAX_SYM_NAME + 1` (== 81) - // due to struct alignment. - info.SizeOfStruct = 88; - - let ret = symbol_resolver( - context.handle, - frame.symbol_addr as u64, - frame.inline_context, - &mut info, - ); - let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { - if info.Size != 0 { - (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize - } else { - true - } - } else { - false - }; - let symname = if valid_range { - let ptr = info.Name.as_ptr() as *const c_char; - CStr::from_ptr(ptr).to_str().ok() - } else { - None - }; - callback(symname) - } -} - -pub fn foreach_symbol_fileline( - frame: Frame, - callback: F, - context: &BacktraceContext, -) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()>, -{ - match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal( - |process: c::HANDLE, - frame_address: u64, - inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64| unsafe { - let mut displacement = 0u32; - (fns.sym_get_line)( - process, - frame_address, - inline_context, - 0, - &mut displacement, - line, - ) - }, - frame, - callback, - context, - ), - StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal( - |process: c::HANDLE, - frame_address: u64, - _inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64| unsafe { - let mut displacement = 0u32; - (fns.sym_get_line)(process, frame_address, &mut displacement, line) - }, - frame, - callback, - context, - ), - } -} - -fn foreach_symbol_fileline_iternal( - mut line_getter: G, - frame: Frame, - mut callback: F, - context: &BacktraceContext, -) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()>, - G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL, -{ - unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = ::mem::size_of::() as u32; - - let ret = line_getter( - context.handle, - frame.exact_position as u64, - frame.inline_context, - &mut line, - ); - if ret == c::TRUE { - let name = CStr::from_ptr(line.Filename).to_bytes(); - callback(name, line.LineNumber as u32)?; - } - Ok(false) - } -} diff --git a/ctr-std/src/sys/windows/c.rs b/ctr-std/src/sys/windows/c.rs deleted file mode 100644 index e514a56..0000000 --- a/ctr-std/src/sys/windows/c.rs +++ /dev/null @@ -1,1334 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! C definitions used by libnative that don't belong in liblibc - -#![allow(bad_style)] -#![cfg_attr(test, allow(dead_code))] -#![unstable(issue = "0", feature = "windows_c")] - -use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort, c_char}; -#[cfg(target_arch = "x86_64")] -use os::raw::c_ulonglong; -use libc::{wchar_t, size_t, c_void}; -use ptr; - -pub use self::FILE_INFO_BY_HANDLE_CLASS::*; -pub use self::EXCEPTION_DISPOSITION::*; - -pub type DWORD = c_ulong; -pub type HANDLE = LPVOID; -pub type HINSTANCE = HANDLE; -pub type HMODULE = HINSTANCE; -pub type HRESULT = LONG; -pub type BOOL = c_int; -pub type BYTE = u8; -pub type BOOLEAN = BYTE; -pub type GROUP = c_uint; -pub type LARGE_INTEGER = c_longlong; -pub type LONG = c_long; -pub type UINT = c_uint; -pub type WCHAR = u16; -pub type USHORT = c_ushort; -pub type SIZE_T = usize; -pub type WORD = u16; -pub type CHAR = c_char; -pub type ULONG_PTR = usize; -pub type ULONG = c_ulong; -#[cfg(target_arch = "x86_64")] -pub type ULONGLONG = u64; -#[cfg(target_arch = "x86_64")] -pub type DWORDLONG = ULONGLONG; - -pub type LPBOOL = *mut BOOL; -pub type LPBYTE = *mut BYTE; -pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION; -pub type LPCSTR = *const CHAR; -pub type LPCVOID = *const c_void; -pub type LPCWSTR = *const WCHAR; -pub type LPDWORD = *mut DWORD; -pub type LPHANDLE = *mut HANDLE; -pub type LPOVERLAPPED = *mut OVERLAPPED; -pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; -pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; -pub type LPSTARTUPINFO = *mut STARTUPINFO; -pub type LPVOID = *mut c_void; -pub type LPWCH = *mut WCHAR; -pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; -pub type LPWSADATA = *mut WSADATA; -pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; -pub type LPSTR = *mut CHAR; -pub type LPWSTR = *mut WCHAR; -pub type LPFILETIME = *mut FILETIME; - -pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; -pub type PLARGE_INTEGER = *mut c_longlong; -pub type PSRWLOCK = *mut SRWLOCK; - -pub type SOCKET = ::os::windows::raw::SOCKET; -pub type socklen_t = c_int; -pub type ADDRESS_FAMILY = USHORT; - -pub const TRUE: BOOL = 1; -pub const FALSE: BOOL = 0; - -pub const FILE_ATTRIBUTE_READONLY: DWORD = 0x1; -pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10; -pub const FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x400; - -pub const FILE_SHARE_DELETE: DWORD = 0x4; -pub const FILE_SHARE_READ: DWORD = 0x1; -pub const FILE_SHARE_WRITE: DWORD = 0x2; - -pub const CREATE_ALWAYS: DWORD = 2; -pub const CREATE_NEW: DWORD = 1; -pub const OPEN_ALWAYS: DWORD = 4; -pub const OPEN_EXISTING: DWORD = 3; -pub const TRUNCATE_EXISTING: DWORD = 5; - -pub const FILE_WRITE_DATA: DWORD = 0x00000002; -pub const FILE_APPEND_DATA: DWORD = 0x00000004; -pub const FILE_WRITE_EA: DWORD = 0x00000010; -pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100; -pub const READ_CONTROL: DWORD = 0x00020000; -pub const SYNCHRONIZE: DWORD = 0x00100000; -pub const GENERIC_READ: DWORD = 0x80000000; -pub const GENERIC_WRITE: DWORD = 0x40000000; -pub const STANDARD_RIGHTS_WRITE: DWORD = READ_CONTROL; -pub const FILE_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | - FILE_WRITE_ATTRIBUTES | - FILE_WRITE_EA | - FILE_APPEND_DATA | - SYNCHRONIZE; - -pub const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000; -pub const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000; -pub const SECURITY_SQOS_PRESENT: DWORD = 0x00100000; - -pub const FIONBIO: c_ulong = 0x8004667e; - -#[repr(C)] -#[derive(Copy)] -pub struct WIN32_FIND_DATAW { - pub dwFileAttributes: DWORD, - pub ftCreationTime: FILETIME, - pub ftLastAccessTime: FILETIME, - pub ftLastWriteTime: FILETIME, - pub nFileSizeHigh: DWORD, - pub nFileSizeLow: DWORD, - pub dwReserved0: DWORD, - pub dwReserved1: DWORD, - pub cFileName: [wchar_t; 260], // #define MAX_PATH 260 - pub cAlternateFileName: [wchar_t; 14], -} -impl Clone for WIN32_FIND_DATAW { - fn clone(&self) -> Self { *self } -} - -pub const WSA_FLAG_OVERLAPPED: DWORD = 0x01; - -pub const WSADESCRIPTION_LEN: usize = 256; -pub const WSASYS_STATUS_LEN: usize = 128; -pub const WSAPROTOCOL_LEN: DWORD = 255; -pub const INVALID_SOCKET: SOCKET = !0; - -pub const WSAEACCES: c_int = 10013; -pub const WSAEINVAL: c_int = 10022; -pub const WSAEWOULDBLOCK: c_int = 10035; -pub const WSAEADDRINUSE: c_int = 10048; -pub const WSAEADDRNOTAVAIL: c_int = 10049; -pub const WSAECONNABORTED: c_int = 10053; -pub const WSAECONNRESET: c_int = 10054; -pub const WSAENOTCONN: c_int = 10057; -pub const WSAESHUTDOWN: c_int = 10058; -pub const WSAETIMEDOUT: c_int = 10060; -pub const WSAECONNREFUSED: c_int = 10061; - -pub const MAX_PROTOCOL_CHAIN: DWORD = 7; - -pub const TOKEN_READ: DWORD = 0x20008; -pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; -pub const FSCTL_GET_REPARSE_POINT: DWORD = 0x900a8; -pub const IO_REPARSE_TAG_SYMLINK: DWORD = 0xa000000c; -pub const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xa0000003; -pub const SYMLINK_FLAG_RELATIVE: DWORD = 0x00000001; -pub const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4; - -pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1; -pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2; - -// Note that these are not actually HANDLEs, just values to pass to GetStdHandle -pub const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD; -pub const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD; -pub const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; - -pub const HANDLE_FLAG_INHERIT: DWORD = 0x00000001; - -pub const PROGRESS_CONTINUE: DWORD = 0; - -pub const ERROR_FILE_NOT_FOUND: DWORD = 2; -pub const ERROR_PATH_NOT_FOUND: DWORD = 3; -pub const ERROR_ACCESS_DENIED: DWORD = 5; -pub const ERROR_INVALID_HANDLE: DWORD = 6; -pub const ERROR_NO_MORE_FILES: DWORD = 18; -pub const ERROR_HANDLE_EOF: DWORD = 38; -pub const ERROR_FILE_EXISTS: DWORD = 80; -pub const ERROR_INVALID_PARAMETER: DWORD = 87; -pub const ERROR_BROKEN_PIPE: DWORD = 109; -pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120; -pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122; -pub const ERROR_ALREADY_EXISTS: DWORD = 183; -pub const ERROR_NO_DATA: DWORD = 232; -pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203; -pub const ERROR_OPERATION_ABORTED: DWORD = 995; -pub const ERROR_IO_PENDING: DWORD = 997; -pub const ERROR_TIMEOUT: DWORD = 0x5B4; - -pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT; - -pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE; - -pub const FACILITY_NT_BIT: DWORD = 0x1000_0000; - -pub const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; -pub const FORMAT_MESSAGE_FROM_HMODULE: DWORD = 0x00000800; -pub const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; - -pub const TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF; - -pub const DLL_THREAD_DETACH: DWORD = 3; -pub const DLL_PROCESS_DETACH: DWORD = 0; - -pub const INFINITE: DWORD = !0; - -pub const DUPLICATE_SAME_ACCESS: DWORD = 0x00000002; - -pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { - ptr: ptr::null_mut(), -}; -pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: ptr::null_mut() }; - -pub const DETACHED_PROCESS: DWORD = 0x00000008; -pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200; -pub const CREATE_UNICODE_ENVIRONMENT: DWORD = 0x00000400; -pub const STARTF_USESTDHANDLES: DWORD = 0x00000100; - -pub const AF_INET: c_int = 2; -pub const AF_INET6: c_int = 23; -pub const SD_BOTH: c_int = 2; -pub const SD_RECEIVE: c_int = 0; -pub const SD_SEND: c_int = 1; -pub const SOCK_DGRAM: c_int = 2; -pub const SOCK_STREAM: c_int = 1; -pub const SOL_SOCKET: c_int = 0xffff; -pub const SO_RCVTIMEO: c_int = 0x1006; -pub const SO_SNDTIMEO: c_int = 0x1005; -pub const SO_REUSEADDR: c_int = 0x0004; -pub const IPPROTO_IP: c_int = 0; -pub const IPPROTO_TCP: c_int = 6; -pub const IPPROTO_IPV6: c_int = 41; -pub const TCP_NODELAY: c_int = 0x0001; -pub const IP_TTL: c_int = 4; -pub const IPV6_V6ONLY: c_int = 27; -pub const SO_ERROR: c_int = 0x1007; -pub const SO_BROADCAST: c_int = 0x0020; -pub const IP_MULTICAST_LOOP: c_int = 11; -pub const IPV6_MULTICAST_LOOP: c_int = 11; -pub const IP_MULTICAST_TTL: c_int = 10; -pub const IP_ADD_MEMBERSHIP: c_int = 12; -pub const IP_DROP_MEMBERSHIP: c_int = 13; -pub const IPV6_ADD_MEMBERSHIP: c_int = 12; -pub const IPV6_DROP_MEMBERSHIP: c_int = 13; -pub const MSG_PEEK: c_int = 0x2; - -#[repr(C)] -pub struct ip_mreq { - pub imr_multiaddr: in_addr, - pub imr_interface: in_addr, -} - -#[repr(C)] -pub struct ipv6_mreq { - pub ipv6mr_multiaddr: in6_addr, - pub ipv6mr_interface: c_uint, -} - -pub const VOLUME_NAME_DOS: DWORD = 0x0; -pub const MOVEFILE_REPLACE_EXISTING: DWORD = 1; - -pub const FILE_BEGIN: DWORD = 0; -pub const FILE_CURRENT: DWORD = 1; -pub const FILE_END: DWORD = 2; - -pub const WAIT_OBJECT_0: DWORD = 0x00000000; -pub const WAIT_TIMEOUT: DWORD = 258; -pub const WAIT_FAILED: DWORD = 0xFFFFFFFF; - -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub const MAX_SYM_NAME: usize = 2000; -#[cfg(target_arch = "x86")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c; -#[cfg(target_arch = "x86_64")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664; -#[cfg(target_arch = "aarch64")] -#[cfg(feature = "backtrace")] -pub const IMAGE_FILE_MACHINE_ARM64: DWORD = 0xAA64; - -pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; -pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; -pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; - -pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001; -pub const PIPE_ACCESS_OUTBOUND: DWORD = 0x00000002; -pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000; -pub const FILE_FLAG_OVERLAPPED: DWORD = 0x40000000; -pub const PIPE_WAIT: DWORD = 0x00000000; -pub const PIPE_TYPE_BYTE: DWORD = 0x00000000; -pub const PIPE_REJECT_REMOTE_CLIENTS: DWORD = 0x00000008; -pub const PIPE_READMODE_BYTE: DWORD = 0x00000000; - -pub const FD_SETSIZE: usize = 64; - -pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000; - -#[repr(C)] -#[cfg(not(target_pointer_width = "64"))] -pub struct WSADATA { - pub wVersion: WORD, - pub wHighVersion: WORD, - pub szDescription: [u8; WSADESCRIPTION_LEN + 1], - pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1], - pub iMaxSockets: u16, - pub iMaxUdpDg: u16, - pub lpVendorInfo: *mut u8, -} -#[repr(C)] -#[cfg(target_pointer_width = "64")] -pub struct WSADATA { - pub wVersion: WORD, - pub wHighVersion: WORD, - pub iMaxSockets: u16, - pub iMaxUdpDg: u16, - pub lpVendorInfo: *mut u8, - pub szDescription: [u8; WSADESCRIPTION_LEN + 1], - pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1], -} - -#[repr(C)] -pub struct WSAPROTOCOL_INFO { - pub dwServiceFlags1: DWORD, - pub dwServiceFlags2: DWORD, - pub dwServiceFlags3: DWORD, - pub dwServiceFlags4: DWORD, - pub dwProviderFlags: DWORD, - pub ProviderId: GUID, - pub dwCatalogEntryId: DWORD, - pub ProtocolChain: WSAPROTOCOLCHAIN, - pub iVersion: c_int, - pub iAddressFamily: c_int, - pub iMaxSockAddr: c_int, - pub iMinSockAddr: c_int, - pub iSocketType: c_int, - pub iProtocol: c_int, - pub iProtocolMaxOffset: c_int, - pub iNetworkByteOrder: c_int, - pub iSecurityScheme: c_int, - pub dwMessageSize: DWORD, - pub dwProviderReserved: DWORD, - pub szProtocol: [u16; (WSAPROTOCOL_LEN as usize) + 1], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct WIN32_FILE_ATTRIBUTE_DATA { - pub dwFileAttributes: DWORD, - pub ftCreationTime: FILETIME, - pub ftLastAccessTime: FILETIME, - pub ftLastWriteTime: FILETIME, - pub nFileSizeHigh: DWORD, - pub nFileSizeLow: DWORD, -} - -#[repr(C)] -pub struct BY_HANDLE_FILE_INFORMATION { - pub dwFileAttributes: DWORD, - pub ftCreationTime: FILETIME, - pub ftLastAccessTime: FILETIME, - pub ftLastWriteTime: FILETIME, - pub dwVolumeSerialNumber: DWORD, - pub nFileSizeHigh: DWORD, - pub nFileSizeLow: DWORD, - pub nNumberOfLinks: DWORD, - pub nFileIndexHigh: DWORD, - pub nFileIndexLow: DWORD, -} - -#[repr(C)] -#[allow(dead_code)] // we only use some variants -pub enum FILE_INFO_BY_HANDLE_CLASS { - FileBasicInfo = 0, - FileStandardInfo = 1, - FileNameInfo = 2, - FileRenameInfo = 3, - FileDispositionInfo = 4, - FileAllocationInfo = 5, - FileEndOfFileInfo = 6, - FileStreamInfo = 7, - FileCompressionInfo = 8, - FileAttributeTagInfo = 9, - FileIdBothDirectoryInfo = 10, // 0xA - FileIdBothDirectoryRestartInfo = 11, // 0xB - FileIoPriorityHintInfo = 12, // 0xC - FileRemoteProtocolInfo = 13, // 0xD - FileFullDirectoryInfo = 14, // 0xE - FileFullDirectoryRestartInfo = 15, // 0xF - FileStorageInfo = 16, // 0x10 - FileAlignmentInfo = 17, // 0x11 - FileIdInfo = 18, // 0x12 - FileIdExtdDirectoryInfo = 19, // 0x13 - FileIdExtdDirectoryRestartInfo = 20, // 0x14 - MaximumFileInfoByHandlesClass -} - -#[repr(C)] -pub struct FILE_BASIC_INFO { - pub CreationTime: LARGE_INTEGER, - pub LastAccessTime: LARGE_INTEGER, - pub LastWriteTime: LARGE_INTEGER, - pub ChangeTime: LARGE_INTEGER, - pub FileAttributes: DWORD, -} - -#[repr(C)] -pub struct FILE_END_OF_FILE_INFO { - pub EndOfFile: LARGE_INTEGER, -} - -#[repr(C)] -pub struct REPARSE_DATA_BUFFER { - pub ReparseTag: c_uint, - pub ReparseDataLength: c_ushort, - pub Reserved: c_ushort, - pub rest: (), -} - -#[repr(C)] -pub struct SYMBOLIC_LINK_REPARSE_BUFFER { - pub SubstituteNameOffset: c_ushort, - pub SubstituteNameLength: c_ushort, - pub PrintNameOffset: c_ushort, - pub PrintNameLength: c_ushort, - pub Flags: c_ulong, - pub PathBuffer: WCHAR, -} - -#[repr(C)] -pub struct MOUNT_POINT_REPARSE_BUFFER { - pub SubstituteNameOffset: c_ushort, - pub SubstituteNameLength: c_ushort, - pub PrintNameOffset: c_ushort, - pub PrintNameLength: c_ushort, - pub PathBuffer: WCHAR, -} - -pub type LPPROGRESS_ROUTINE = ::option::Option DWORD>; - -#[repr(C)] -pub struct CONDITION_VARIABLE { pub ptr: LPVOID } -#[repr(C)] -pub struct SRWLOCK { pub ptr: LPVOID } -#[repr(C)] -pub struct CRITICAL_SECTION { - CriticalSectionDebug: LPVOID, - LockCount: LONG, - RecursionCount: LONG, - OwningThread: HANDLE, - LockSemaphore: HANDLE, - SpinCount: ULONG_PTR -} - -#[repr(C)] -pub struct REPARSE_MOUNTPOINT_DATA_BUFFER { - pub ReparseTag: DWORD, - pub ReparseDataLength: DWORD, - pub Reserved: WORD, - pub ReparseTargetLength: WORD, - pub ReparseTargetMaximumLength: WORD, - pub Reserved1: WORD, - pub ReparseTarget: WCHAR, -} - -#[repr(C)] -pub struct EXCEPTION_RECORD { - pub ExceptionCode: DWORD, - pub ExceptionFlags: DWORD, - pub ExceptionRecord: *mut EXCEPTION_RECORD, - pub ExceptionAddress: LPVOID, - pub NumberParameters: DWORD, - pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS] -} - -#[repr(C)] -pub struct EXCEPTION_POINTERS { - pub ExceptionRecord: *mut EXCEPTION_RECORD, - pub ContextRecord: *mut CONTEXT, -} - -pub type PVECTORED_EXCEPTION_HANDLER = extern "system" - fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG; - -#[repr(C)] -pub struct GUID { - pub Data1: DWORD, - pub Data2: WORD, - pub Data3: WORD, - pub Data4: [BYTE; 8], -} - -#[repr(C)] -pub struct WSAPROTOCOLCHAIN { - pub ChainLen: c_int, - pub ChainEntries: [DWORD; MAX_PROTOCOL_CHAIN as usize], -} - -#[repr(C)] -pub struct SECURITY_ATTRIBUTES { - pub nLength: DWORD, - pub lpSecurityDescriptor: LPVOID, - pub bInheritHandle: BOOL, -} - -#[repr(C)] -pub struct PROCESS_INFORMATION { - pub hProcess: HANDLE, - pub hThread: HANDLE, - pub dwProcessId: DWORD, - pub dwThreadId: DWORD, -} - -#[repr(C)] -pub struct STARTUPINFO { - pub cb: DWORD, - pub lpReserved: LPWSTR, - pub lpDesktop: LPWSTR, - pub lpTitle: LPWSTR, - pub dwX: DWORD, - pub dwY: DWORD, - pub dwXSize: DWORD, - pub dwYSize: DWORD, - pub dwXCountChars: DWORD, - pub dwYCountCharts: DWORD, - pub dwFillAttribute: DWORD, - pub dwFlags: DWORD, - pub wShowWindow: WORD, - pub cbReserved2: WORD, - pub lpReserved2: LPBYTE, - pub hStdInput: HANDLE, - pub hStdOutput: HANDLE, - pub hStdError: HANDLE, -} - -#[repr(C)] -pub struct SOCKADDR { - pub sa_family: ADDRESS_FAMILY, - pub sa_data: [CHAR; 14], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct FILETIME { - pub dwLowDateTime: DWORD, - pub dwHighDateTime: DWORD, -} - -#[repr(C)] -pub struct OVERLAPPED { - pub Internal: *mut c_ulong, - pub InternalHigh: *mut c_ulong, - pub Offset: DWORD, - pub OffsetHigh: DWORD, - pub hEvent: HANDLE, -} - -#[repr(C)] -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub struct SYMBOL_INFO { - pub SizeOfStruct: c_ulong, - pub TypeIndex: c_ulong, - pub Reserved: [u64; 2], - pub Index: c_ulong, - pub Size: c_ulong, - pub ModBase: u64, - pub Flags: c_ulong, - pub Value: u64, - pub Address: u64, - pub Register: c_ulong, - pub Scope: c_ulong, - pub Tag: c_ulong, - pub NameLen: c_ulong, - pub MaxNameLen: c_ulong, - // note that windows has this as 1, but it basically just means that - // the name is inline at the end of the struct. For us, we just bump - // the struct size up to MAX_SYM_NAME. - pub Name: [c_char; MAX_SYM_NAME], -} - -#[repr(C)] -#[cfg(target_env = "msvc")] -#[cfg(feature = "backtrace")] -pub struct IMAGEHLP_LINE64 { - pub SizeOfStruct: u32, - pub Key: *const c_void, - pub LineNumber: u32, - pub Filename: *const c_char, - pub Address: u64, -} - -#[repr(C)] -#[allow(dead_code)] // we only use some variants -pub enum ADDRESS_MODE { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct ADDRESS64 { - pub Offset: u64, - pub Segment: u16, - pub Mode: ADDRESS_MODE, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct STACKFRAME_EX { - pub AddrPC: ADDRESS64, - pub AddrReturn: ADDRESS64, - pub AddrFrame: ADDRESS64, - pub AddrStack: ADDRESS64, - pub AddrBStore: ADDRESS64, - pub FuncTableEntry: *mut c_void, - pub Params: [u64; 4], - pub Far: BOOL, - pub Virtual: BOOL, - pub Reserved: [u64; 3], - pub KdHelp: KDHELP64, - pub StackFrameSize: DWORD, - pub InlineFrameContext: DWORD, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct STACKFRAME64 { - pub AddrPC: ADDRESS64, - pub AddrReturn: ADDRESS64, - pub AddrFrame: ADDRESS64, - pub AddrStack: ADDRESS64, - pub AddrBStore: ADDRESS64, - pub FuncTableEntry: *mut c_void, - pub Params: [u64; 4], - pub Far: BOOL, - pub Virtual: BOOL, - pub Reserved: [u64; 3], - pub KdHelp: KDHELP64, -} - -#[repr(C)] -#[cfg(feature = "backtrace")] -pub struct KDHELP64 { - pub Thread: u64, - pub ThCallbackStack: DWORD, - pub ThCallbackBStore: DWORD, - pub NextCallback: DWORD, - pub FramePointer: DWORD, - pub KiCallUserMode: u64, - pub KeUserCallbackDispatcher: u64, - pub SystemRangeStart: u64, - pub KiUserExceptionDispatcher: u64, - pub StackBase: u64, - pub StackLimit: u64, - pub Reserved: [u64; 5], -} - -#[cfg(target_arch = "x86")] -#[repr(C)] -pub struct CONTEXT { - pub ContextFlags: DWORD, - pub Dr0: DWORD, - pub Dr1: DWORD, - pub Dr2: DWORD, - pub Dr3: DWORD, - pub Dr6: DWORD, - pub Dr7: DWORD, - pub FloatSave: FLOATING_SAVE_AREA, - pub SegGs: DWORD, - pub SegFs: DWORD, - pub SegEs: DWORD, - pub SegDs: DWORD, - pub Edi: DWORD, - pub Esi: DWORD, - pub Ebx: DWORD, - pub Edx: DWORD, - pub Ecx: DWORD, - pub Eax: DWORD, - pub Ebp: DWORD, - pub Eip: DWORD, - pub SegCs: DWORD, - pub EFlags: DWORD, - pub Esp: DWORD, - pub SegSs: DWORD, - pub ExtendedRegisters: [u8; 512], -} - -#[cfg(target_arch = "x86")] -#[repr(C)] -pub struct FLOATING_SAVE_AREA { - pub ControlWord: DWORD, - pub StatusWord: DWORD, - pub TagWord: DWORD, - pub ErrorOffset: DWORD, - pub ErrorSelector: DWORD, - pub DataOffset: DWORD, - pub DataSelector: DWORD, - pub RegisterArea: [u8; 80], - pub Cr0NpxState: DWORD, -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct CONTEXT { - pub P1Home: DWORDLONG, - pub P2Home: DWORDLONG, - pub P3Home: DWORDLONG, - pub P4Home: DWORDLONG, - pub P5Home: DWORDLONG, - pub P6Home: DWORDLONG, - - pub ContextFlags: DWORD, - pub MxCsr: DWORD, - - pub SegCs: WORD, - pub SegDs: WORD, - pub SegEs: WORD, - pub SegFs: WORD, - pub SegGs: WORD, - pub SegSs: WORD, - pub EFlags: DWORD, - - pub Dr0: DWORDLONG, - pub Dr1: DWORDLONG, - pub Dr2: DWORDLONG, - pub Dr3: DWORDLONG, - pub Dr6: DWORDLONG, - pub Dr7: DWORDLONG, - - pub Rax: DWORDLONG, - pub Rcx: DWORDLONG, - pub Rdx: DWORDLONG, - pub Rbx: DWORDLONG, - pub Rsp: DWORDLONG, - pub Rbp: DWORDLONG, - pub Rsi: DWORDLONG, - pub Rdi: DWORDLONG, - pub R8: DWORDLONG, - pub R9: DWORDLONG, - pub R10: DWORDLONG, - pub R11: DWORDLONG, - pub R12: DWORDLONG, - pub R13: DWORDLONG, - pub R14: DWORDLONG, - pub R15: DWORDLONG, - - pub Rip: DWORDLONG, - - pub FltSave: FLOATING_SAVE_AREA, - - pub VectorRegister: [M128A; 26], - pub VectorControl: DWORDLONG, - - pub DebugControl: DWORDLONG, - pub LastBranchToRip: DWORDLONG, - pub LastBranchFromRip: DWORDLONG, - pub LastExceptionToRip: DWORDLONG, - pub LastExceptionFromRip: DWORDLONG, -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct M128A { - pub Low: c_ulonglong, - pub High: c_longlong -} - -#[cfg(target_arch = "x86_64")] -#[repr(C, align(16))] -pub struct FLOATING_SAVE_AREA { - _Dummy: [u8; 512] // FIXME: Fill this out -} - -// FIXME(#43348): This structure is used for backtrace only, and a fake -// definition is provided here only to allow rustdoc to pass type-check. This -// will not appear in the final documentation. This should be also defined for -// other architectures supported by Windows such as ARM, and for historical -// interest, maybe MIPS and PowerPC as well. -#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))))] -pub enum CONTEXT {} - -#[cfg(target_arch = "aarch64")] -pub const ARM64_MAX_BREAKPOINTS: usize = 8; - -#[cfg(target_arch = "aarch64")] -pub const ARM64_MAX_WATCHPOINTS: usize = 2; - -#[cfg(target_arch = "aarch64")] -#[repr(C)] -pub struct ARM64_NT_NEON128 { - pub D: [f64; 2], -} - -#[cfg(target_arch = "aarch64")] -#[repr(C, align(16))] -pub struct CONTEXT { - pub ContextFlags: DWORD, - pub Cpsr: DWORD, - pub X0: u64, - pub X1: u64, - pub X2: u64, - pub X3: u64, - pub X4: u64, - pub X5: u64, - pub X6: u64, - pub X7: u64, - pub X8: u64, - pub X9: u64, - pub X10: u64, - pub X11: u64, - pub X12: u64, - pub X13: u64, - pub X14: u64, - pub X15: u64, - pub X16: u64, - pub X17: u64, - pub X18: u64, - pub X19: u64, - pub X20: u64, - pub X21: u64, - pub X22: u64, - pub X23: u64, - pub X24: u64, - pub X25: u64, - pub X26: u64, - pub X27: u64, - pub X28: u64, - pub Fp: u64, - pub Lr: u64, - pub Sp: u64, - pub Pc: u64, - pub V: [ARM64_NT_NEON128; 32], - pub Fpcr: DWORD, - pub Fpsr: DWORD, - pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS], - pub Bvr: [DWORD; ARM64_MAX_BREAKPOINTS], - pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS], - pub Wvr: [DWORD; ARM64_MAX_WATCHPOINTS], -} - -#[repr(C)] -pub struct SOCKADDR_STORAGE_LH { - pub ss_family: ADDRESS_FAMILY, - pub __ss_pad1: [CHAR; 6], - pub __ss_align: i64, - pub __ss_pad2: [CHAR; 112], -} - -#[repr(C)] -pub struct ADDRINFOA { - pub ai_flags: c_int, - pub ai_family: c_int, - pub ai_socktype: c_int, - pub ai_protocol: c_int, - pub ai_addrlen: size_t, - pub ai_canonname: *mut c_char, - pub ai_addr: *mut SOCKADDR, - pub ai_next: *mut ADDRINFOA, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in { - pub sin_family: ADDRESS_FAMILY, - pub sin_port: USHORT, - pub sin_addr: in_addr, - pub sin_zero: [CHAR; 8], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in6 { - pub sin6_family: ADDRESS_FAMILY, - pub sin6_port: USHORT, - pub sin6_flowinfo: c_ulong, - pub sin6_addr: in6_addr, - pub sin6_scope_id: c_ulong, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in_addr { - pub s_addr: u32, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in6_addr { - pub s6_addr: [u8; 16], -} - -#[repr(C)] -#[derive(Copy, Clone)] -#[allow(dead_code)] // we only use some variants -pub enum EXCEPTION_DISPOSITION { - ExceptionContinueExecution, - ExceptionContinueSearch, - ExceptionNestedException, - ExceptionCollidedUnwind -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct CONSOLE_READCONSOLE_CONTROL { - pub nLength: ULONG, - pub nInitialChars: ULONG, - pub dwCtrlWakeupMask: ULONG, - pub dwControlKeyState: ULONG, -} -pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL; - -#[repr(C)] -#[derive(Copy)] -pub struct fd_set { - pub fd_count: c_uint, - pub fd_array: [SOCKET; FD_SETSIZE], -} - -impl Clone for fd_set { - fn clone(&self) -> fd_set { - *self - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct timeval { - pub tv_sec: c_long, - pub tv_usec: c_long, -} - -extern "system" { - pub fn WSAStartup(wVersionRequested: WORD, - lpWSAData: LPWSADATA) -> c_int; - pub fn WSACleanup() -> c_int; - pub fn WSAGetLastError() -> c_int; - pub fn WSADuplicateSocketW(s: SOCKET, - dwProcessId: DWORD, - lpProtocolInfo: LPWSAPROTOCOL_INFO) - -> c_int; - pub fn GetCurrentProcessId() -> DWORD; - pub fn WSASocketW(af: c_int, - kind: c_int, - protocol: c_int, - lpProtocolInfo: LPWSAPROTOCOL_INFO, - g: GROUP, - dwFlags: DWORD) -> SOCKET; - pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int; - pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOLEAN; - pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - - pub fn ReadConsoleW(hConsoleInput: HANDLE, - lpBuffer: LPVOID, - nNumberOfCharsToRead: DWORD, - lpNumberOfCharsRead: LPDWORD, - pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL; - - pub fn WriteConsoleW(hConsoleOutput: HANDLE, - lpBuffer: LPCVOID, - nNumberOfCharsToWrite: DWORD, - lpNumberOfCharsWritten: LPDWORD, - lpReserved: LPVOID) -> BOOL; - - pub fn GetConsoleMode(hConsoleHandle: HANDLE, - lpMode: LPDWORD) -> BOOL; - pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL; - pub fn SetFileAttributesW(lpFileName: LPCWSTR, - dwFileAttributes: DWORD) -> BOOL; - pub fn GetFileInformationByHandle(hFile: HANDLE, - lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) - -> BOOL; - - pub fn SetLastError(dwErrCode: DWORD); - pub fn GetCommandLineW() -> *mut LPCWSTR; - pub fn LocalFree(ptr: *mut c_void); - pub fn CommandLineToArgvW(lpCmdLine: *mut LPCWSTR, - pNumArgs: *mut c_int) -> *mut *mut u16; - pub fn GetTempPathW(nBufferLength: DWORD, - lpBuffer: LPCWSTR) -> DWORD; - pub fn OpenProcessToken(ProcessHandle: HANDLE, - DesiredAccess: DWORD, - TokenHandle: *mut HANDLE) -> BOOL; - pub fn GetCurrentProcess() -> HANDLE; - pub fn GetCurrentThread() -> HANDLE; - pub fn GetStdHandle(which: DWORD) -> HANDLE; - pub fn ExitProcess(uExitCode: c_uint) -> !; - pub fn DeviceIoControl(hDevice: HANDLE, - dwIoControlCode: DWORD, - lpInBuffer: LPVOID, - nInBufferSize: DWORD, - lpOutBuffer: LPVOID, - nOutBufferSize: DWORD, - lpBytesReturned: LPDWORD, - lpOverlapped: LPOVERLAPPED) -> BOOL; - pub fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES, - dwStackSize: SIZE_T, - lpStartAddress: extern "system" fn(*mut c_void) - -> DWORD, - lpParameter: LPVOID, - dwCreationFlags: DWORD, - lpThreadId: LPDWORD) -> HANDLE; - pub fn WaitForSingleObject(hHandle: HANDLE, - dwMilliseconds: DWORD) -> DWORD; - pub fn SwitchToThread() -> BOOL; - pub fn Sleep(dwMilliseconds: DWORD); - pub fn GetProcessId(handle: HANDLE) -> DWORD; - pub fn GetUserProfileDirectoryW(hToken: HANDLE, - lpProfileDir: LPWSTR, - lpcchSize: *mut DWORD) -> BOOL; - pub fn SetHandleInformation(hObject: HANDLE, - dwMask: DWORD, - dwFlags: DWORD) -> BOOL; - pub fn CopyFileExW(lpExistingFileName: LPCWSTR, - lpNewFileName: LPCWSTR, - lpProgressRoutine: LPPROGRESS_ROUTINE, - lpData: LPVOID, - pbCancel: LPBOOL, - dwCopyFlags: DWORD) -> BOOL; - pub fn AddVectoredExceptionHandler(FirstHandler: ULONG, - VectoredHandler: PVECTORED_EXCEPTION_HANDLER) - -> LPVOID; - pub fn FormatMessageW(flags: DWORD, - lpSrc: LPVOID, - msgId: DWORD, - langId: DWORD, - buf: LPWSTR, - nsize: DWORD, - args: *const c_void) - -> DWORD; - pub fn TlsAlloc() -> DWORD; - pub fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID; - pub fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL; - pub fn GetLastError() -> DWORD; - pub fn QueryPerformanceFrequency(lpFrequency: *mut LARGE_INTEGER) -> BOOL; - pub fn QueryPerformanceCounter(lpPerformanceCount: *mut LARGE_INTEGER) - -> BOOL; - pub fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL; - pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL; - pub fn CreateProcessW(lpApplicationName: LPCWSTR, - lpCommandLine: LPWSTR, - lpProcessAttributes: LPSECURITY_ATTRIBUTES, - lpThreadAttributes: LPSECURITY_ATTRIBUTES, - bInheritHandles: BOOL, - dwCreationFlags: DWORD, - lpEnvironment: LPVOID, - lpCurrentDirectory: LPCWSTR, - lpStartupInfo: LPSTARTUPINFO, - lpProcessInformation: LPPROCESS_INFORMATION) - -> BOOL; - pub fn GetEnvironmentVariableW(n: LPCWSTR, v: LPWSTR, nsize: DWORD) -> DWORD; - pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR) -> BOOL; - pub fn GetEnvironmentStringsW() -> LPWCH; - pub fn FreeEnvironmentStringsW(env_ptr: LPWCH) -> BOOL; - pub fn GetModuleFileNameW(hModule: HMODULE, - lpFilename: LPWSTR, - nSize: DWORD) - -> DWORD; - pub fn CreateDirectoryW(lpPathName: LPCWSTR, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES) - -> BOOL; - pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL; - pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD; - pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL; - pub fn WideCharToMultiByte(CodePage: UINT, - dwFlags: DWORD, - lpWideCharStr: LPCWSTR, - cchWideChar: c_int, - lpMultiByteStr: LPSTR, - cbMultiByte: c_int, - lpDefaultChar: LPCSTR, - lpUsedDefaultChar: LPBOOL) -> c_int; - - pub fn closesocket(socket: SOCKET) -> c_int; - pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, - flags: c_int) -> c_int; - pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, - flags: c_int) -> c_int; - pub fn recvfrom(socket: SOCKET, - buf: *mut c_void, - len: c_int, - flags: c_int, - addr: *mut SOCKADDR, - addrlen: *mut c_int) - -> c_int; - pub fn sendto(socket: SOCKET, - buf: *const c_void, - len: c_int, - flags: c_int, - addr: *const SOCKADDR, - addrlen: c_int) - -> c_int; - pub fn shutdown(socket: SOCKET, how: c_int) -> c_int; - pub fn accept(socket: SOCKET, - address: *mut SOCKADDR, - address_len: *mut c_int) - -> SOCKET; - pub fn DuplicateHandle(hSourceProcessHandle: HANDLE, - hSourceHandle: HANDLE, - hTargetProcessHandle: HANDLE, - lpTargetHandle: LPHANDLE, - dwDesiredAccess: DWORD, - bInheritHandle: BOOL, - dwOptions: DWORD) - -> BOOL; - pub fn ReadFile(hFile: HANDLE, - lpBuffer: LPVOID, - nNumberOfBytesToRead: DWORD, - lpNumberOfBytesRead: LPDWORD, - lpOverlapped: LPOVERLAPPED) - -> BOOL; - pub fn WriteFile(hFile: HANDLE, - lpBuffer: LPVOID, - nNumberOfBytesToWrite: DWORD, - lpNumberOfBytesWritten: LPDWORD, - lpOverlapped: LPOVERLAPPED) - -> BOOL; - pub fn CloseHandle(hObject: HANDLE) -> BOOL; - pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR, - lpTargetFileName: LPCWSTR, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES) - -> BOOL; - pub fn MoveFileExW(lpExistingFileName: LPCWSTR, - lpNewFileName: LPCWSTR, - dwFlags: DWORD) - -> BOOL; - pub fn SetFilePointerEx(hFile: HANDLE, - liDistanceToMove: LARGE_INTEGER, - lpNewFilePointer: PLARGE_INTEGER, - dwMoveMethod: DWORD) - -> BOOL; - pub fn FlushFileBuffers(hFile: HANDLE) -> BOOL; - pub fn CreateFileW(lpFileName: LPCWSTR, - dwDesiredAccess: DWORD, - dwShareMode: DWORD, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES, - dwCreationDisposition: DWORD, - dwFlagsAndAttributes: DWORD, - hTemplateFile: HANDLE) - -> HANDLE; - - pub fn FindFirstFileW(fileName: LPCWSTR, - findFileData: LPWIN32_FIND_DATAW) - -> HANDLE; - pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) - -> BOOL; - pub fn FindClose(findFile: HANDLE) -> BOOL; - #[cfg(feature = "backtrace")] - pub fn RtlCaptureContext(ctx: *mut CONTEXT); - pub fn getsockopt(s: SOCKET, - level: c_int, - optname: c_int, - optval: *mut c_char, - optlen: *mut c_int) - -> c_int; - pub fn setsockopt(s: SOCKET, - level: c_int, - optname: c_int, - optval: *const c_void, - optlen: c_int) - -> c_int; - pub fn getsockname(socket: SOCKET, - address: *mut SOCKADDR, - address_len: *mut c_int) - -> c_int; - pub fn getpeername(socket: SOCKET, - address: *mut SOCKADDR, - address_len: *mut c_int) - -> c_int; - pub fn bind(socket: SOCKET, address: *const SOCKADDR, - address_len: socklen_t) -> c_int; - pub fn listen(socket: SOCKET, backlog: c_int) -> c_int; - pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) - -> c_int; - pub fn getaddrinfo(node: *const c_char, service: *const c_char, - hints: *const ADDRINFOA, - res: *mut *mut ADDRINFOA) -> c_int; - pub fn freeaddrinfo(res: *mut ADDRINFOA); - - #[cfg(feature = "backtrace")] - pub fn LoadLibraryW(name: LPCWSTR) -> HMODULE; - #[cfg(feature = "backtrace")] - pub fn FreeLibrary(handle: HMODULE) -> BOOL; - pub fn GetProcAddress(handle: HMODULE, - name: LPCSTR) -> *mut c_void; - pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; - - pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME); - - pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES, - bManualReset: BOOL, - bInitialState: BOOL, - lpName: LPCWSTR) -> HANDLE; - pub fn WaitForMultipleObjects(nCount: DWORD, - lpHandles: *const HANDLE, - bWaitAll: BOOL, - dwMilliseconds: DWORD) -> DWORD; - pub fn CreateNamedPipeW(lpName: LPCWSTR, - dwOpenMode: DWORD, - dwPipeMode: DWORD, - nMaxInstances: DWORD, - nOutBufferSize: DWORD, - nInBufferSize: DWORD, - nDefaultTimeOut: DWORD, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES) - -> HANDLE; - pub fn CancelIo(handle: HANDLE) -> BOOL; - pub fn GetOverlappedResult(hFile: HANDLE, - lpOverlapped: LPOVERLAPPED, - lpNumberOfBytesTransferred: LPDWORD, - bWait: BOOL) -> BOOL; - pub fn select(nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - exceptfds: *mut fd_set, - timeout: *const timeval) -> c_int; - - #[link_name = "SystemFunction036"] - pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN; -} - -// Functions that aren't available on every version of Windows that we support, -// but we still use them and just provide some form of a fallback implementation. -compat_fn! { - kernel32: - - pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, - _lpTargetFileName: LPCWSTR, - _dwFlags: DWORD) -> BOOLEAN { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - pub fn GetFinalPathNameByHandleW(_hFile: HANDLE, - _lpszFilePath: LPCWSTR, - _cchFilePath: DWORD, - _dwFlags: DWORD) -> DWORD { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - pub fn SetThreadDescription(hThread: HANDLE, - lpThreadDescription: LPCWSTR) -> HRESULT { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL - } - pub fn SetFileInformationByHandle(_hFile: HANDLE, - _FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, - _lpFileInformation: LPVOID, - _dwBufferSize: DWORD) -> BOOL { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE, - SRWLock: PSRWLOCK, - dwMilliseconds: DWORD, - Flags: ULONG) -> BOOL { - panic!("condition variables not available") - } - pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE) - -> () { - panic!("condition variables not available") - } - pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE) - -> () { - panic!("condition variables not available") - } - pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN { - panic!("rwlocks not available") - } - pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN { - panic!("rwlocks not available") - } -} - -#[cfg(all(target_env = "gnu", feature = "backtrace"))] -mod gnu { - use super::*; - - pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400; - - pub const CP_ACP: UINT = 0; - - pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400; - - extern "system" { - pub fn OpenProcess(dwDesiredAccess: DWORD, - bInheritHandle: BOOL, - dwProcessId: DWORD) -> HANDLE; - } - - compat_fn! { - kernel32: - - pub fn QueryFullProcessImageNameW(_hProcess: HANDLE, - _dwFlags: DWORD, - _lpExeName: LPWSTR, - _lpdwSize: LPDWORD) -> BOOL { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - } -} - -#[cfg(all(target_env = "gnu", feature = "backtrace"))] -pub use self::gnu::*; diff --git a/ctr-std/src/sys/windows/cmath.rs b/ctr-std/src/sys/windows/cmath.rs deleted file mode 100644 index b665a2c..0000000 --- a/ctr-std/src/sys/windows/cmath.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg(not(test))] - -use libc::{c_float, c_double}; - -#[link_name = "m"] -extern { - pub fn acos(n: c_double) -> c_double; - pub fn asin(n: c_double) -> c_double; - pub fn atan(n: c_double) -> c_double; - pub fn atan2(a: c_double, b: c_double) -> c_double; - pub fn cbrt(n: c_double) -> c_double; - pub fn cbrtf(n: c_float) -> c_float; - pub fn cosh(n: c_double) -> c_double; - pub fn expm1(n: c_double) -> c_double; - pub fn expm1f(n: c_float) -> c_float; - pub fn fdim(a: c_double, b: c_double) -> c_double; - pub fn fdimf(a: c_float, b: c_float) -> c_float; - #[cfg_attr(target_env = "msvc", link_name = "_hypot")] - pub fn hypot(x: c_double, y: c_double) -> c_double; - #[cfg_attr(target_env = "msvc", link_name = "_hypotf")] - pub fn hypotf(x: c_float, y: c_float) -> c_float; - pub fn log1p(n: c_double) -> c_double; - pub fn log1pf(n: c_float) -> c_float; - pub fn sinh(n: c_double) -> c_double; - pub fn tan(n: c_double) -> c_double; - pub fn tanh(n: c_double) -> c_double; -} - -pub use self::shims::*; - -#[cfg(not(target_env = "msvc"))] -mod shims { - use libc::c_float; - - extern { - pub fn acosf(n: c_float) -> c_float; - pub fn asinf(n: c_float) -> c_float; - pub fn atan2f(a: c_float, b: c_float) -> c_float; - pub fn atanf(n: c_float) -> c_float; - pub fn coshf(n: c_float) -> c_float; - pub fn sinhf(n: c_float) -> c_float; - pub fn tanf(n: c_float) -> c_float; - pub fn tanhf(n: c_float) -> c_float; - } -} - -// On MSVC these functions aren't defined, so we just define shims which promote -// everything fo f64, perform the calculation, and then demote back to f32. -// While not precisely correct should be "correct enough" for now. -#[cfg(target_env = "msvc")] -mod shims { - use libc::c_float; - - #[inline] - pub unsafe fn acosf(n: c_float) -> c_float { - f64::acos(n as f64) as c_float - } - - #[inline] - pub unsafe fn asinf(n: c_float) -> c_float { - f64::asin(n as f64) as c_float - } - - #[inline] - pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float { - f64::atan2(n as f64, b as f64) as c_float - } - - #[inline] - pub unsafe fn atanf(n: c_float) -> c_float { - f64::atan(n as f64) as c_float - } - - #[inline] - pub unsafe fn coshf(n: c_float) -> c_float { - f64::cosh(n as f64) as c_float - } - - #[inline] - pub unsafe fn sinhf(n: c_float) -> c_float { - f64::sinh(n as f64) as c_float - } - - #[inline] - pub unsafe fn tanf(n: c_float) -> c_float { - f64::tan(n as f64) as c_float - } - - #[inline] - pub unsafe fn tanhf(n: c_float) -> c_float { - f64::tanh(n as f64) as c_float - } -} diff --git a/ctr-std/src/sys/windows/compat.rs b/ctr-std/src/sys/windows/compat.rs deleted file mode 100644 index cd42b7d..0000000 --- a/ctr-std/src/sys/windows/compat.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A "compatibility layer" for spanning XP and Windows 7 -//! -//! The standard library currently binds many functions that are not available -//! on Windows XP, but we would also like to support building executables that -//! run on XP. To do this we specify all non-XP APIs as having a fallback -//! implementation to do something reasonable. -//! -//! This dynamic runtime detection of whether a function is available is -//! implemented with `GetModuleHandle` and `GetProcAddress` paired with a -//! static-per-function which caches the result of the first check. In this -//! manner we pay a semi-large one-time cost up front for detecting whether a -//! function is available but afterwards it's just a load and a jump. - -use ffi::CString; -use sync::atomic::{AtomicUsize, Ordering}; -use sys::c; - -pub fn lookup(module: &str, symbol: &str) -> Option { - let mut module: Vec = module.encode_utf16().collect(); - module.push(0); - let symbol = CString::new(symbol).unwrap(); - unsafe { - let handle = c::GetModuleHandleW(module.as_ptr()); - match c::GetProcAddress(handle, symbol.as_ptr()) as usize { - 0 => None, - n => Some(n), - } - } -} - -pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, - fallback: usize) -> usize { - let value = lookup(module, symbol).unwrap_or(fallback); - ptr.store(value, Ordering::SeqCst); - value -} - -macro_rules! compat_fn { - ($module:ident: $( - pub fn $symbol:ident($($argname:ident: $argtype:ty),*) - -> $rettype:ty { - $($body:expr);* - } - )*) => ($( - #[allow(unused_variables)] - pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { - use sync::atomic::{AtomicUsize, Ordering}; - use mem; - type F = unsafe extern "system" fn($($argtype),*) -> $rettype; - - static PTR: AtomicUsize = AtomicUsize::new(0); - - fn load() -> usize { - ::sys::compat::store_func(&PTR, - stringify!($module), - stringify!($symbol), - fallback as usize) - } - unsafe extern "system" fn fallback($($argname: $argtype),*) - -> $rettype { - $($body);* - } - - let addr = match PTR.load(Ordering::SeqCst) { - 0 => load(), - n => n, - }; - mem::transmute::(addr)($($argname),*) - } - )*) -} diff --git a/ctr-std/src/sys/windows/condvar.rs b/ctr-std/src/sys/windows/condvar.rs deleted file mode 100644 index d708b32..0000000 --- a/ctr-std/src/sys/windows/condvar.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use sys::c; -use sys::mutex::{self, Mutex}; -use sys::os; -use time::Duration; - -pub struct Condvar { inner: UnsafeCell } - -unsafe impl Send for Condvar {} -unsafe impl Sync for Condvar {} - -impl Condvar { - pub const fn new() -> Condvar { - Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) } - } - - #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { - let r = c::SleepConditionVariableSRW(self.inner.get(), - mutex::raw(mutex), - c::INFINITE, - 0); - debug_assert!(r != 0); - } - - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let r = c::SleepConditionVariableSRW(self.inner.get(), - mutex::raw(mutex), - super::dur2timeout(dur), - 0); - if r == 0 { - debug_assert_eq!(os::errno() as usize, c::ERROR_TIMEOUT as usize); - false - } else { - true - } - } - - #[inline] - pub unsafe fn notify_one(&self) { - c::WakeConditionVariable(self.inner.get()) - } - - #[inline] - pub unsafe fn notify_all(&self) { - c::WakeAllConditionVariable(self.inner.get()) - } - - pub unsafe fn destroy(&self) { - // ... - } -} diff --git a/ctr-std/src/sys/windows/dynamic_lib.rs b/ctr-std/src/sys/windows/dynamic_lib.rs deleted file mode 100644 index 5227280..0000000 --- a/ctr-std/src/sys/windows/dynamic_lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use os::windows::prelude::*; - -use ffi::{CString, OsStr}; -use io; -use sys::c; - -pub struct DynamicLibrary { - handle: c::HMODULE, -} - -impl DynamicLibrary { - pub fn open(filename: &str) -> io::Result { - let filename = OsStr::new(filename) - .encode_wide() - .chain(Some(0)) - .collect::>(); - let result = unsafe { - c::LoadLibraryW(filename.as_ptr()) - }; - if result.is_null() { - Err(io::Error::last_os_error()) - } else { - Ok(DynamicLibrary { handle: result }) - } - } - - pub fn symbol(&self, symbol: &str) -> io::Result { - let symbol = CString::new(symbol)?; - unsafe { - match c::GetProcAddress(self.handle, symbol.as_ptr()) as usize { - 0 => Err(io::Error::last_os_error()), - n => Ok(n), - } - } - } -} - -impl Drop for DynamicLibrary { - fn drop(&mut self) { - unsafe { - c::FreeLibrary(self.handle); - } - } -} diff --git a/ctr-std/src/sys/windows/env.rs b/ctr-std/src/sys/windows/env.rs deleted file mode 100644 index e6d7489..0000000 --- a/ctr-std/src/sys/windows/env.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub mod os { - pub const FAMILY: &'static str = "windows"; - pub const OS: &'static str = "windows"; - pub const DLL_PREFIX: &'static str = ""; - pub const DLL_SUFFIX: &'static str = ".dll"; - pub const DLL_EXTENSION: &'static str = "dll"; - pub const EXE_SUFFIX: &'static str = ".exe"; - pub const EXE_EXTENSION: &'static str = "exe"; -} diff --git a/ctr-std/src/sys/windows/ext/ffi.rs b/ctr-std/src/sys/windows/ext/ffi.rs deleted file mode 100644 index bae0d02..0000000 --- a/ctr-std/src/sys/windows/ext/ffi.rs +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Windows-specific extensions to the primitives in the `std::ffi` module. -//! -//! # Overview -//! -//! For historical reasons, the Windows API uses a form of potentially -//! ill-formed UTF-16 encoding for strings. Specifically, the 16-bit -//! code units in Windows strings may contain [isolated surrogate code -//! points which are not paired together][ill-formed-utf-16]. The -//! Unicode standard requires that surrogate code points (those in the -//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16 -//! encoding a *surrogate code unit pair* is used to encode a single -//! character. For compatibility with code that does not enforce -//! these pairings, Windows does not enforce them, either. -//! -//! While it is not always possible to convert such a string losslessly into -//! a valid UTF-16 string (or even UTF-8), it is often desirable to be -//! able to round-trip such a string from and to Windows APIs -//! losslessly. For example, some Rust code may be "bridging" some -//! Windows APIs together, just passing `WCHAR` strings among those -//! APIs without ever really looking into the strings. -//! -//! If Rust code *does* need to look into those strings, it can -//! convert them to valid UTF-8, possibly lossily, by substituting -//! invalid sequences with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], as is -//! conventionally done in other Rust APIs that deal with string -//! encodings. -//! -//! # `OsStringExt` and `OsStrExt` -//! -//! [`OsString`] is the Rust wrapper for owned strings in the -//! preferred representation of the operating system. On Windows, -//! this struct gets augmented with an implementation of the -//! [`OsStringExt`] trait, which has a [`from_wide`] method. This -//! lets you create an [`OsString`] from a `&[u16]` slice; presumably -//! you get such a slice out of a `WCHAR` Windows API. -//! -//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from -//! preferred representation of the operating system. On Windows, the -//! [`OsStrExt`] trait provides the [`encode_wide`] method, which -//! outputs an [`EncodeWide`] iterator. You can [`collect`] this -//! iterator, for example, to obtain a `Vec`; you can later get a -//! pointer to this vector's contents and feed it to Windows APIs. -//! -//! These traits, along with [`OsString`] and [`OsStr`], work in -//! conjunction so that it is possible to **round-trip** strings from -//! Windows and back, with no loss of data, even if the strings are -//! ill-formed UTF-16. -//! -//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16 -//! [`OsString`]: ../../../ffi/struct.OsString.html -//! [`OsStr`]: ../../../ffi/struct.OsStr.html -//! [`OsStringExt`]: trait.OsStringExt.html -//! [`OsStrExt`]: trait.OsStrExt.html -//! [`EncodeWide`]: struct.EncodeWide.html -//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide -//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide -//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect -//! [U+FFFD]: ../../../char/constant.REPLACEMENT_CHARACTER.html - -#![stable(feature = "rust1", since = "1.0.0")] - -use ffi::{OsString, OsStr}; -use sys::os_str::Buf; -use sys_common::wtf8::Wtf8Buf; -use sys_common::{FromInner, AsInner}; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use sys_common::wtf8::EncodeWide; - -/// Windows-specific extensions to [`OsString`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStringExt { - /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of - /// 16-bit code units. - /// - /// This is lossless: calling [`encode_wide`] on the resulting string - /// will always return the original code units. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// use std::os::windows::prelude::*; - /// - /// // UTF-16 encoding for "Unicode". - /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065]; - /// - /// let string = OsString::from_wide(&source[..]); - /// ``` - /// - /// [`encode_wide`]: ./trait.OsStrExt.html#tymethod.encode_wide - #[stable(feature = "rust1", since = "1.0.0")] - fn from_wide(wide: &[u16]) -> Self; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStringExt for OsString { - fn from_wide(wide: &[u16]) -> OsString { - FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) }) - } -} - -/// Windows-specific extensions to [`OsStr`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStrExt { - /// Re-encodes an `OsStr` as a wide character sequence, i.e. potentially - /// ill-formed UTF-16. - /// - /// This is lossless: calling [`OsString::from_wide`] and then - /// `encode_wide` on the result will yield the original code units. - /// Note that the encoding does not add a final null terminator. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsString; - /// use std::os::windows::prelude::*; - /// - /// // UTF-16 encoding for "Unicode". - /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065]; - /// - /// let string = OsString::from_wide(&source[..]); - /// - /// let result: Vec = string.encode_wide().collect(); - /// assert_eq!(&source[..], &result[..]); - /// ``` - /// - /// [`OsString::from_wide`]: ./trait.OsStringExt.html#tymethod.from_wide - #[stable(feature = "rust1", since = "1.0.0")] - fn encode_wide(&self) -> EncodeWide; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStrExt for OsStr { - fn encode_wide(&self) -> EncodeWide { - self.as_inner().inner.encode_wide() - } -} diff --git a/ctr-std/src/sys/windows/ext/fs.rs b/ctr-std/src/sys/windows/ext/fs.rs deleted file mode 100644 index 78c9e95..0000000 --- a/ctr-std/src/sys/windows/ext/fs.rs +++ /dev/null @@ -1,508 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Windows-specific extensions for the primitives in the `std::fs` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use fs::{self, OpenOptions, Metadata}; -use io; -use path::Path; -use sys; -use sys_common::{AsInnerMut, AsInner}; - -/// Windows-specific extensions to [`File`]. -/// -/// [`File`]: ../../../fs/struct.File.html -#[stable(feature = "file_offset", since = "1.15.0")] -pub trait FileExt { - /// Seeks to a given position and reads a number of bytes. - /// - /// Returns the number of bytes read. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. The current cursor **is** affected by this - /// function, it is set to the end of the read. - /// - /// Reading beyond the end of the file will always return with a length of - /// 0\. - /// - /// Note that similar to `File::read`, it is not an error to return with a - /// short read. When returning from such a short read, the file pointer is - /// still updated. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs::File; - /// use std::os::windows::prelude::*; - /// - /// fn main() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// let mut buffer = [0; 10]; - /// - /// // Read 10 bytes, starting 72 bytes from the - /// // start of the file. - /// file.seek_read(&mut buffer[..], 72)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result; - - /// Seeks to a given position and writes a number of bytes. - /// - /// Returns the number of bytes written. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. The current cursor **is** affected by this - /// function, it is set to the end of the write. - /// - /// When writing beyond the end of the file, the file is appropriately - /// extended and the intermediate bytes are left uninitialized. - /// - /// Note that similar to `File::write`, it is not an error to return a - /// short write. When returning from such a short write, the file pointer - /// is still updated. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::windows::prelude::*; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// // Write a byte string starting 72 bytes from - /// // the start of the file. - /// buffer.seek_write(b"some bytes", 72)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result; -} - -#[stable(feature = "file_offset", since = "1.15.0")] -impl FileExt for fs::File { - fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result { - self.as_inner().read_at(buf, offset) - } - - fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result { - self.as_inner().write_at(buf, offset) - } -} - -/// Windows-specific extensions to [`fs::OpenOptions`]. -/// -/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html -#[stable(feature = "open_options_ext", since = "1.10.0")] -pub trait OpenOptionsExt { - /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`] - /// with the specified value. - /// - /// This will override the `read`, `write`, and `append` flags on the - /// `OpenOptions` structure. This method provides fine-grained control over - /// the permissions to read, write and append data, attributes (like hidden - /// and system), and extended attributes. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// use std::os::windows::prelude::*; - /// - /// // Open without read and write permission, for example if you only need - /// // to call `stat` on the file - /// let file = OpenOptions::new().access_mode(0).open("foo.txt"); - /// ``` - /// - /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn access_mode(&mut self, access: u32) -> &mut Self; - - /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with - /// the specified value. - /// - /// By default `share_mode` is set to - /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows - /// other processes to to read, write, and delete/rename the same file - /// while it is open. Removing any of the flags will prevent other - /// processes from performing the corresponding operation until the file - /// handle is closed. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// use std::os::windows::prelude::*; - /// - /// // Do not allow others to read or modify this file while we have it open - /// // for writing. - /// let file = OpenOptions::new() - /// .write(true) - /// .share_mode(0) - /// .open("foo.txt"); - /// ``` - /// - /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn share_mode(&mut self, val: u32) -> &mut Self; - - /// Sets extra flags for the `dwFileFlags` argument to the call to - /// [`CreateFile2`] to the specified value (or combines it with - /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes` - /// for [`CreateFile`]). - /// - /// Custom flags can only set flags, not remove flags set by Rust's options. - /// This option overwrites any previously set custom flags. - /// - /// # Examples - /// - /// ```no_run - /// # #[cfg(for_demonstration_only)] - /// extern crate winapi; - /// # mod winapi { pub const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; } - /// - /// use std::fs::OpenOptions; - /// use std::os::windows::prelude::*; - /// - /// let file = OpenOptions::new() - /// .create(true) - /// .write(true) - /// .custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE) - /// .open("foo.txt"); - /// ``` - /// - /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx - /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn custom_flags(&mut self, flags: u32) -> &mut Self; - - /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to - /// the specified value (or combines it with `custom_flags` and - /// `security_qos_flags` to set the `dwFlagsAndAttributes` for - /// [`CreateFile`]). - /// - /// If a _new_ file is created because it does not yet exist and - /// `.create(true)` or `.create_new(true)` are specified, the new file is - /// given the attributes declared with `.attributes()`. - /// - /// If an _existing_ file is opened with `.create(true).truncate(true)`, its - /// existing attributes are preserved and combined with the ones declared - /// with `.attributes()`. - /// - /// In all other cases the attributes get ignored. - /// - /// # Examples - /// - /// ```no_run - /// # #[cfg(for_demonstration_only)] - /// extern crate winapi; - /// # mod winapi { pub const FILE_ATTRIBUTE_HIDDEN: u32 = 2; } - /// - /// use std::fs::OpenOptions; - /// use std::os::windows::prelude::*; - /// - /// let file = OpenOptions::new() - /// .write(true) - /// .create(true) - /// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN) - /// .open("foo.txt"); - /// ``` - /// - /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx - /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn attributes(&mut self, val: u32) -> &mut Self; - - /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to - /// the specified value (or combines it with `custom_flags` and `attributes` - /// to set the `dwFlagsAndAttributes` for [`CreateFile`]). - /// - /// By default, `security_qos_flags` is set to `SECURITY_ANONYMOUS`. For - /// information about possible values, see [Impersonation Levels] on the - /// Windows Dev Center site. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// use std::os::windows::prelude::*; - /// - /// let file = OpenOptions::new() - /// .write(true) - /// .create(true) - /// - /// // Sets the flag value to `SecurityIdentification`. - /// .security_qos_flags(1) - /// - /// .open("foo.txt"); - /// ``` - /// - /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx - /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx - /// [Impersonation Levels]: - /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa379572.aspx - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions; -} - -#[stable(feature = "open_options_ext", since = "1.10.0")] -impl OpenOptionsExt for OpenOptions { - fn access_mode(&mut self, access: u32) -> &mut OpenOptions { - self.as_inner_mut().access_mode(access); self - } - - fn share_mode(&mut self, share: u32) -> &mut OpenOptions { - self.as_inner_mut().share_mode(share); self - } - - fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions { - self.as_inner_mut().custom_flags(flags); self - } - - fn attributes(&mut self, attributes: u32) -> &mut OpenOptions { - self.as_inner_mut().attributes(attributes); self - } - - fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions { - self.as_inner_mut().security_qos_flags(flags); self - } -} - -/// Windows-specific extensions to [`fs::Metadata`]. -/// -/// The data members that this trait exposes correspond to the members -/// of the [`BY_HANDLE_FILE_INFORMATION`] structure. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html -/// [`BY_HANDLE_FILE_INFORMATION`]: -/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788.aspx -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Returns the value of the `dwFileAttributes` field of this metadata. - /// - /// This field contains the file system attribute information for a file - /// or directory. For possible values and their descriptions, see - /// [File Attribute Constants] in the Windows Dev Center. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs; - /// use std::os::windows::prelude::*; - /// - /// fn main() -> io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// let attributes = metadata.file_attributes(); - /// Ok(()) - /// } - /// ``` - /// - /// [File Attribute Constants]: - /// https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117.aspx - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn file_attributes(&self) -> u32; - - /// Returns the value of the `ftCreationTime` field of this metadata. - /// - /// The returned 64-bit value is equivalent to a [`FILETIME`] struct, - /// which represents the number of 100-nanosecond intervals since - /// January 1, 1601 (UTC). The struct is automatically - /// converted to a `u64` value, as that is the recommended way - /// to use it. - /// - /// If the underlying filesystem does not support creation time, the - /// returned value is 0. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs; - /// use std::os::windows::prelude::*; - /// - /// fn main() -> io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// let creation_time = metadata.creation_time(); - /// Ok(()) - /// } - /// ``` - /// - /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn creation_time(&self) -> u64; - - /// Returns the value of the `ftLastAccessTime` field of this metadata. - /// - /// The returned 64-bit value is equivalent to a [`FILETIME`] struct, - /// which represents the number of 100-nanosecond intervals since - /// January 1, 1601 (UTC). The struct is automatically - /// converted to a `u64` value, as that is the recommended way - /// to use it. - /// - /// For a file, the value specifies the last time that a file was read - /// from or written to. For a directory, the value specifies when - /// the directory was created. For both files and directories, the - /// specified date is correct, but the time of day is always set to - /// midnight. - /// - /// If the underlying filesystem does not support last access time, the - /// returned value is 0. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs; - /// use std::os::windows::prelude::*; - /// - /// fn main() -> io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// let last_access_time = metadata.last_access_time(); - /// Ok(()) - /// } - /// ``` - /// - /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn last_access_time(&self) -> u64; - - /// Returns the value of the `ftLastWriteTime` field of this metadata. - /// - /// The returned 64-bit value is equivalent to a [`FILETIME`] struct, - /// which represents the number of 100-nanosecond intervals since - /// January 1, 1601 (UTC). The struct is automatically - /// converted to a `u64` value, as that is the recommended way - /// to use it. - /// - /// For a file, the value specifies the last time that a file was written - /// to. For a directory, the structure specifies when the directory was - /// created. - /// - /// If the underlying filesystem does not support the last write time, - /// the returned value is 0. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs; - /// use std::os::windows::prelude::*; - /// - /// fn main() -> io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// let last_write_time = metadata.last_write_time(); - /// Ok(()) - /// } - /// ``` - /// - /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn last_write_time(&self) -> u64; - - /// Returns the value of the `nFileSize{High,Low}` fields of this - /// metadata. - /// - /// The returned value does not have meaning for directories. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs; - /// use std::os::windows::prelude::*; - /// - /// fn main() -> io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// let file_size = metadata.file_size(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn file_size(&self) -> u64; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - fn file_attributes(&self) -> u32 { self.as_inner().attrs() } - fn creation_time(&self) -> u64 { self.as_inner().created_u64() } - fn last_access_time(&self) -> u64 { self.as_inner().accessed_u64() } - fn last_write_time(&self) -> u64 { self.as_inner().modified_u64() } - fn file_size(&self) -> u64 { self.as_inner().size() } -} - -/// Windows-specific extensions to [`FileType`]. -/// -/// On Windows, a symbolic link knows whether it is a file or directory. -/// -/// [`FileType`]: ../../../../std/fs/struct.FileType.html -#[unstable(feature = "windows_file_type_ext", issue = "0")] -pub trait FileTypeExt { - /// Returns whether this file type is a symbolic link that is also a directory. - #[unstable(feature = "windows_file_type_ext", issue = "0")] - fn is_symlink_dir(&self) -> bool; - /// Returns whether this file type is a symbolic link that is also a file. - #[unstable(feature = "windows_file_type_ext", issue = "0")] - fn is_symlink_file(&self) -> bool; -} - -#[unstable(feature = "windows_file_type_ext", issue = "0")] -impl FileTypeExt for fs::FileType { - fn is_symlink_dir(&self) -> bool { self.as_inner().is_symlink_dir() } - fn is_symlink_file(&self) -> bool { self.as_inner().is_symlink_file() } -} - -/// Creates a new file symbolic link on the filesystem. -/// -/// The `dst` path will be a file symbolic link pointing to the `src` -/// path. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::windows::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::symlink_file("a.txt", "b.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink_file, Q: AsRef>(src: P, dst: Q) - -> io::Result<()> { - sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), false) -} - -/// Creates a new directory symlink on the filesystem. -/// -/// The `dst` path will be a directory symbolic link pointing to the `src` -/// path. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::windows::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::symlink_dir("a", "b")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink_dir, Q: AsRef>(src: P, dst: Q) - -> io::Result<()> { - sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), true) -} diff --git a/ctr-std/src/sys/windows/ext/io.rs b/ctr-std/src/sys/windows/ext/io.rs deleted file mode 100644 index 90128dd..0000000 --- a/ctr-std/src/sys/windows/ext/io.rs +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "rust1", since = "1.0.0")] - -use fs; -use os::windows::raw; -use net; -use sys_common::{self, AsInner, FromInner, IntoInner}; -use sys; -use io; -use sys::c; - -/// Raw HANDLEs. -#[stable(feature = "rust1", since = "1.0.0")] -pub type RawHandle = raw::HANDLE; - -/// Raw SOCKETs. -#[stable(feature = "rust1", since = "1.0.0")] -pub type RawSocket = raw::SOCKET; - -/// Extract raw handles. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsRawHandle { - /// Extracts the raw handle, without taking any ownership. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_handle(&self) -> RawHandle; -} - -/// Construct I/O objects from raw handles. -#[stable(feature = "from_raw_os", since = "1.1.0")] -pub trait FromRawHandle { - /// Constructs a new I/O object from the specified raw handle. - /// - /// This function will **consume ownership** of the handle given, - /// passing responsibility for closing the handle to the returned - /// object. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - #[stable(feature = "from_raw_os", since = "1.1.0")] - unsafe fn from_raw_handle(handle: RawHandle) -> Self; -} - -/// A trait to express the ability to consume an object and acquire ownership of -/// its raw `HANDLE`. -#[stable(feature = "into_raw_os", since = "1.4.0")] -pub trait IntoRawHandle { - /// Consumes this object, returning the raw underlying handle. - /// - /// This function **transfers ownership** of the underlying handle to the - /// caller. Callers are then the unique owners of the handle and must close - /// it once it's no longer needed. - #[stable(feature = "into_raw_os", since = "1.4.0")] - fn into_raw_handle(self) -> RawHandle; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawHandle for fs::File { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as RawHandle - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawHandle for io::Stdin { - fn as_raw_handle(&self) -> RawHandle { - unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle } - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawHandle for io::Stdout { - fn as_raw_handle(&self) -> RawHandle { - unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle } - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawHandle for io::Stderr { - fn as_raw_handle(&self) -> RawHandle { - unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle } - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawHandle for fs::File { - unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { - let handle = handle as c::HANDLE; - fs::File::from_inner(sys::fs::File::from_inner(handle)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawHandle for fs::File { - fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ - } -} - -/// Extract raw sockets. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsRawSocket { - /// Extracts the underlying raw socket from this object. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_socket(&self) -> RawSocket; -} - -/// Create I/O objects from raw sockets. -#[stable(feature = "from_raw_os", since = "1.1.0")] -pub trait FromRawSocket { - /// Creates a new I/O object from the given raw socket. - /// - /// This function will **consume ownership** of the socket provided and - /// it will be closed when the returned object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - #[stable(feature = "from_raw_os", since = "1.1.0")] - unsafe fn from_raw_socket(sock: RawSocket) -> Self; -} - -/// A trait to express the ability to consume an object and acquire ownership of -/// its raw `SOCKET`. -#[stable(feature = "into_raw_os", since = "1.4.0")] -pub trait IntoRawSocket { - /// Consumes this object, returning the raw underlying socket. - /// - /// This function **transfers ownership** of the underlying socket to the - /// caller. Callers are then the unique owners of the socket and must close - /// it once it's no longer needed. - #[stable(feature = "into_raw_os", since = "1.4.0")] - fn into_raw_socket(self) -> RawSocket; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawSocket for net::TcpStream { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawSocket for net::TcpListener { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawSocket for net::UdpSocket { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawSocket for net::TcpStream { - unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { - let sock = sys::net::Socket::from_inner(sock); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock)) - } -} -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawSocket for net::TcpListener { - unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { - let sock = sys::net::Socket::from_inner(sock); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock)) - } -} -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawSocket for net::UdpSocket { - unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { - let sock = sys::net::Socket::from_inner(sock); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawSocket for net::TcpStream { - fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawSocket for net::TcpListener { - fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawSocket for net::UdpSocket { - fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() - } -} diff --git a/ctr-std/src/sys/windows/ext/mod.rs b/ctr-std/src/sys/windows/ext/mod.rs deleted file mode 100644 index 1f10609..0000000 --- a/ctr-std/src/sys/windows/ext/mod.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Platform-specific extensions to `std` for Windows. -//! -//! Provides access to platform-level information for Windows, and exposes -//! Windows-specific idioms that would otherwise be inappropriate as part -//! the core `std` library. These extensions allow developers to use -//! `std` types and idioms with Windows in a way that the normal -//! platform-agnostic idioms would not normally support. - -#![stable(feature = "rust1", since = "1.0.0")] -#![doc(cfg(windows))] -#![allow(missing_docs)] - -pub mod ffi; -pub mod fs; -pub mod io; -pub mod raw; -pub mod process; -pub mod thread; - -/// A prelude for conveniently writing platform-specific code. -/// -/// Includes all extension traits, and some important type definitions. -#[stable(feature = "rust1", since = "1.0.0")] -pub mod prelude { - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{FromRawSocket, FromRawHandle, IntoRawSocket, IntoRawHandle}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::fs::{OpenOptionsExt, MetadataExt}; - #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")] - pub use super::fs::FileExt; -} diff --git a/ctr-std/src/sys/windows/ext/process.rs b/ctr-std/src/sys/windows/ext/process.rs deleted file mode 100644 index a02bcbe..0000000 --- a/ctr-std/src/sys/windows/ext/process.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Extensions to `std::process` for Windows. - -#![stable(feature = "process_extensions", since = "1.2.0")] - -use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle, IntoRawHandle}; -use process; -use sys; -use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl FromRawHandle for process::Stdio { - unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { - let handle = sys::handle::Handle::new(handle as *mut _); - let io = sys::process::Stdio::Handle(handle); - process::Stdio::from_inner(io) - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawHandle for process::Child { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawHandle for process::Child { - fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawHandle for process::ChildStdin { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawHandle for process::ChildStdout { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawHandle for process::ChildStderr { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawHandle for process::ChildStdin { - fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawHandle for process::ChildStdout { - fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawHandle for process::ChildStderr { - fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ - } -} - -/// Windows-specific extensions to [`process::ExitStatus`]. -/// -/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html -#[stable(feature = "exit_status_from", since = "1.12.0")] -pub trait ExitStatusExt { - /// Creates a new `ExitStatus` from the raw underlying `u32` return value of - /// a process. - #[stable(feature = "exit_status_from", since = "1.12.0")] - fn from_raw(raw: u32) -> Self; -} - -#[stable(feature = "exit_status_from", since = "1.12.0")] -impl ExitStatusExt for process::ExitStatus { - fn from_raw(raw: u32) -> Self { - process::ExitStatus::from_inner(From::from(raw)) - } -} - -/// Windows-specific extensions to the [`process::Command`] builder. -/// -/// [`process::Command`]: ../../../../std/process/struct.Command.html -#[stable(feature = "windows_process_extensions", since = "1.16.0")] -pub trait CommandExt { - /// Sets the [process creation flags][1] to be passed to `CreateProcess`. - /// - /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. - /// - /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx - #[stable(feature = "windows_process_extensions", since = "1.16.0")] - fn creation_flags(&mut self, flags: u32) -> &mut process::Command; -} - -#[stable(feature = "windows_process_extensions", since = "1.16.0")] -impl CommandExt for process::Command { - fn creation_flags(&mut self, flags: u32) -> &mut process::Command { - self.as_inner_mut().creation_flags(flags); - self - } -} diff --git a/ctr-std/src/sys/windows/ext/raw.rs b/ctr-std/src/sys/windows/ext/raw.rs deleted file mode 100644 index 92d53e2..0000000 --- a/ctr-std/src/sys/windows/ext/raw.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Windows-specific primitives - -#![stable(feature = "raw_ext", since = "1.1.0")] - -use os::raw::c_void; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type HANDLE = *mut c_void; -#[cfg(target_pointer_width = "32")] -#[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u32; -#[cfg(target_pointer_width = "64")] -#[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u64; diff --git a/ctr-std/src/sys/windows/ext/thread.rs b/ctr-std/src/sys/windows/ext/thread.rs deleted file mode 100644 index 36b3a3d..0000000 --- a/ctr-std/src/sys/windows/ext/thread.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Extensions to `std::thread` for Windows. - -#![stable(feature = "thread_extensions", since = "1.9.0")] - -use os::windows::io::{RawHandle, AsRawHandle, IntoRawHandle}; -use thread; -use sys_common::{AsInner, IntoInner}; - -#[stable(feature = "thread_extensions", since = "1.9.0")] -impl AsRawHandle for thread::JoinHandle { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ - } -} - -#[stable(feature = "thread_extensions", since = "1.9.0")] -impl IntoRawHandle for thread::JoinHandle { - fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ - } -} diff --git a/ctr-std/src/sys/windows/fast_thread_local.rs b/ctr-std/src/sys/windows/fast_thread_local.rs deleted file mode 100644 index 9fee9bd..0000000 --- a/ctr-std/src/sys/windows/fast_thread_local.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "thread_local_internals", issue = "0")] -#![cfg(target_thread_local)] - -pub use sys_common::thread_local::register_dtor_fallback as register_dtor; - -pub fn requires_move_before_drop() -> bool { - false -} diff --git a/ctr-std/src/sys/windows/fs.rs b/ctr-std/src/sys/windows/fs.rs deleted file mode 100644 index 082d468..0000000 --- a/ctr-std/src/sys/windows/fs.rs +++ /dev/null @@ -1,804 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use os::windows::prelude::*; - -use ffi::OsString; -use fmt; -use io::{self, Error, SeekFrom}; -use mem; -use path::{Path, PathBuf}; -use ptr; -use slice; -use sync::Arc; -use sys::handle::Handle; -use sys::time::SystemTime; -use sys::{c, cvt}; -use sys_common::FromInner; - -use super::to_u16s; - -pub struct File { handle: Handle } - -#[derive(Clone)] -pub struct FileAttr { - attributes: c::DWORD, - creation_time: c::FILETIME, - last_access_time: c::FILETIME, - last_write_time: c::FILETIME, - file_size: u64, - reparse_tag: c::DWORD, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct FileType { - attributes: c::DWORD, - reparse_tag: c::DWORD, -} - -pub struct ReadDir { - handle: FindNextFileHandle, - root: Arc, - first: Option, -} - -struct FindNextFileHandle(c::HANDLE); - -unsafe impl Send for FindNextFileHandle {} -unsafe impl Sync for FindNextFileHandle {} - -pub struct DirEntry { - root: Arc, - data: c::WIN32_FIND_DATAW, -} - -#[derive(Clone, Debug)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - custom_flags: u32, - access_mode: Option, - attributes: c::DWORD, - share_mode: c::DWORD, - security_qos_flags: c::DWORD, - security_attributes: usize, // FIXME: should be a reference -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct FilePermissions { attrs: c::DWORD } - -#[derive(Debug)] -pub struct DirBuilder; - -impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. - // Thus the result will be e g 'ReadDir("C:\")' - fmt::Debug::fmt(&*self.root, f) - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - fn next(&mut self) -> Option> { - if let Some(first) = self.first.take() { - if let Some(e) = DirEntry::new(&self.root, &first) { - return Some(Ok(e)); - } - } - unsafe { - let mut wfd = mem::zeroed(); - loop { - if c::FindNextFileW(self.handle.0, &mut wfd) == 0 { - if c::GetLastError() == c::ERROR_NO_MORE_FILES { - return None - } else { - return Some(Err(Error::last_os_error())) - } - } - if let Some(e) = DirEntry::new(&self.root, &wfd) { - return Some(Ok(e)) - } - } - } - } -} - -impl Drop for FindNextFileHandle { - fn drop(&mut self) { - let r = unsafe { c::FindClose(self.0) }; - debug_assert!(r != 0); - } -} - -impl DirEntry { - fn new(root: &Arc, wfd: &c::WIN32_FIND_DATAW) -> Option { - match &wfd.cFileName[0..3] { - // check for '.' and '..' - &[46, 0, ..] | - &[46, 46, 0, ..] => return None, - _ => {} - } - - Some(DirEntry { - root: root.clone(), - data: *wfd, - }) - } - - pub fn path(&self) -> PathBuf { - self.root.join(&self.file_name()) - } - - pub fn file_name(&self) -> OsString { - let filename = super::truncate_utf16_at_nul(&self.data.cFileName); - OsString::from_wide(filename) - } - - pub fn file_type(&self) -> io::Result { - Ok(FileType::new(self.data.dwFileAttributes, - /* reparse_tag = */ self.data.dwReserved0)) - } - - pub fn metadata(&self) -> io::Result { - Ok(FileAttr { - attributes: self.data.dwFileAttributes, - creation_time: self.data.ftCreationTime, - last_access_time: self.data.ftLastAccessTime, - last_write_time: self.data.ftLastWriteTime, - file_size: ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64), - reparse_tag: if self.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - // reserved unless this is a reparse point - self.data.dwReserved0 - } else { - 0 - }, - }) - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - custom_flags: 0, - access_mode: None, - share_mode: c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE, - attributes: 0, - security_qos_flags: 0, - security_attributes: 0, - } - } - - pub fn read(&mut self, read: bool) { self.read = read; } - pub fn write(&mut self, write: bool) { self.write = write; } - pub fn append(&mut self, append: bool) { self.append = append; } - pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; } - pub fn create(&mut self, create: bool) { self.create = create; } - pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; } - - pub fn custom_flags(&mut self, flags: u32) { self.custom_flags = flags; } - pub fn access_mode(&mut self, access_mode: u32) { self.access_mode = Some(access_mode); } - pub fn share_mode(&mut self, share_mode: u32) { self.share_mode = share_mode; } - pub fn attributes(&mut self, attrs: u32) { self.attributes = attrs; } - pub fn security_qos_flags(&mut self, flags: u32) { self.security_qos_flags = flags; } - pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) { - self.security_attributes = attrs as usize; - } - - fn get_access_mode(&self) -> io::Result { - const ERROR_INVALID_PARAMETER: i32 = 87; - - match (self.read, self.write, self.append, self.access_mode) { - (.., Some(mode)) => Ok(mode), - (true, false, false, None) => Ok(c::GENERIC_READ), - (false, true, false, None) => Ok(c::GENERIC_WRITE), - (true, true, false, None) => Ok(c::GENERIC_READ | c::GENERIC_WRITE), - (false, _, true, None) => Ok(c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA), - (true, _, true, None) => Ok(c::GENERIC_READ | - (c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA)), - (false, false, false, None) => Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)), - } - } - - fn get_creation_mode(&self) -> io::Result { - const ERROR_INVALID_PARAMETER: i32 = 87; - - match (self.write, self.append) { - (true, false) => {} - (false, false) => - if self.truncate || self.create || self.create_new { - return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); - }, - (_, true) => - if self.truncate && !self.create_new { - return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); - }, - } - - Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => c::OPEN_EXISTING, - (true, false, false) => c::OPEN_ALWAYS, - (false, true, false) => c::TRUNCATE_EXISTING, - (true, true, false) => c::CREATE_ALWAYS, - (_, _, true) => c::CREATE_NEW, - }) - } - - fn get_flags_and_attributes(&self) -> c::DWORD { - self.custom_flags | - self.attributes | - self.security_qos_flags | - if self.security_qos_flags != 0 { c::SECURITY_SQOS_PRESENT } else { 0 } | - if self.create_new { c::FILE_FLAG_OPEN_REPARSE_POINT } else { 0 } - } -} - -impl File { - pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let path = to_u16s(path)?; - let handle = unsafe { - c::CreateFileW(path.as_ptr(), - opts.get_access_mode()?, - opts.share_mode, - opts.security_attributes as *mut _, - opts.get_creation_mode()?, - opts.get_flags_and_attributes(), - ptr::null_mut()) - }; - if handle == c::INVALID_HANDLE_VALUE { - Err(Error::last_os_error()) - } else { - Ok(File { handle: Handle::new(handle) }) - } - } - - pub fn fsync(&self) -> io::Result<()> { - cvt(unsafe { c::FlushFileBuffers(self.handle.raw()) })?; - Ok(()) - } - - pub fn datasync(&self) -> io::Result<()> { self.fsync() } - - pub fn truncate(&self, size: u64) -> io::Result<()> { - let mut info = c::FILE_END_OF_FILE_INFO { - EndOfFile: size as c::LARGE_INTEGER, - }; - let size = mem::size_of_val(&info); - cvt(unsafe { - c::SetFileInformationByHandle(self.handle.raw(), - c::FileEndOfFileInfo, - &mut info as *mut _ as *mut _, - size as c::DWORD) - })?; - Ok(()) - } - - pub fn file_attr(&self) -> io::Result { - unsafe { - let mut info: c::BY_HANDLE_FILE_INFORMATION = mem::zeroed(); - cvt(c::GetFileInformationByHandle(self.handle.raw(), - &mut info))?; - let mut attr = FileAttr { - attributes: info.dwFileAttributes, - creation_time: info.ftCreationTime, - last_access_time: info.ftLastAccessTime, - last_write_time: info.ftLastWriteTime, - file_size: ((info.nFileSizeHigh as u64) << 32) | (info.nFileSizeLow as u64), - reparse_tag: 0, - }; - if attr.is_reparse_point() { - let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - if let Ok((_, buf)) = self.reparse_point(&mut b) { - attr.reparse_tag = buf.ReparseTag; - } - } - Ok(attr) - } - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.handle.read(buf) - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - self.handle.read_at(buf, offset) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.handle.write(buf) - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - self.handle.write_at(buf, offset) - } - - pub fn flush(&self) -> io::Result<()> { Ok(()) } - - pub fn seek(&self, pos: SeekFrom) -> io::Result { - let (whence, pos) = match pos { - // Casting to `i64` is fine, `SetFilePointerEx` reinterprets this - // integer as `u64`. - SeekFrom::Start(n) => (c::FILE_BEGIN, n as i64), - SeekFrom::End(n) => (c::FILE_END, n), - SeekFrom::Current(n) => (c::FILE_CURRENT, n), - }; - let pos = pos as c::LARGE_INTEGER; - let mut newpos = 0; - cvt(unsafe { - c::SetFilePointerEx(self.handle.raw(), pos, - &mut newpos, whence) - })?; - Ok(newpos as u64) - } - - pub fn duplicate(&self) -> io::Result { - Ok(File { - handle: self.handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS)?, - }) - } - - pub fn handle(&self) -> &Handle { &self.handle } - - pub fn into_handle(self) -> Handle { self.handle } - - fn reparse_point<'a>(&self, - space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]) - -> io::Result<(c::DWORD, &'a c::REPARSE_DATA_BUFFER)> { - unsafe { - let mut bytes = 0; - cvt({ - c::DeviceIoControl(self.handle.raw(), - c::FSCTL_GET_REPARSE_POINT, - ptr::null_mut(), - 0, - space.as_mut_ptr() as *mut _, - space.len() as c::DWORD, - &mut bytes, - ptr::null_mut()) - })?; - Ok((bytes, &*(space.as_ptr() as *const c::REPARSE_DATA_BUFFER))) - } - } - - fn readlink(&self) -> io::Result { - let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - let (_bytes, buf) = self.reparse_point(&mut space)?; - unsafe { - let (path_buffer, subst_off, subst_len, relative) = match buf.ReparseTag { - c::IO_REPARSE_TAG_SYMLINK => { - let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER = - &buf.rest as *const _ as *const _; - (&(*info).PathBuffer as *const _ as *const u16, - (*info).SubstituteNameOffset / 2, - (*info).SubstituteNameLength / 2, - (*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0) - }, - c::IO_REPARSE_TAG_MOUNT_POINT => { - let info: *const c::MOUNT_POINT_REPARSE_BUFFER = - &buf.rest as *const _ as *const _; - (&(*info).PathBuffer as *const _ as *const u16, - (*info).SubstituteNameOffset / 2, - (*info).SubstituteNameLength / 2, - false) - }, - _ => return Err(io::Error::new(io::ErrorKind::Other, - "Unsupported reparse point type")) - }; - let subst_ptr = path_buffer.offset(subst_off as isize); - let mut subst = slice::from_raw_parts(subst_ptr, subst_len as usize); - // Absolute paths start with an NT internal namespace prefix `\??\` - // We should not let it leak through. - if !relative && subst.starts_with(&[92u16, 63u16, 63u16, 92u16]) { - subst = &subst[4..]; - } - Ok(PathBuf::from(OsString::from_wide(subst))) - } - } - - pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { - let mut info = c::FILE_BASIC_INFO { - CreationTime: 0, - LastAccessTime: 0, - LastWriteTime: 0, - ChangeTime: 0, - FileAttributes: perm.attrs, - }; - let size = mem::size_of_val(&info); - cvt(unsafe { - c::SetFileInformationByHandle(self.handle.raw(), - c::FileBasicInfo, - &mut info as *mut _ as *mut _, - size as c::DWORD) - })?; - Ok(()) - } -} - -impl FromInner for File { - fn from_inner(handle: c::HANDLE) -> File { - File { handle: Handle::new(handle) } - } -} - -impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // FIXME(#24570): add more info here (e.g. mode) - let mut b = f.debug_struct("File"); - b.field("handle", &self.handle.raw()); - if let Ok(path) = get_path(&self) { - b.field("path", &path); - } - b.finish() - } -} - -impl FileAttr { - pub fn size(&self) -> u64 { - self.file_size - } - - pub fn perm(&self) -> FilePermissions { - FilePermissions { attrs: self.attributes } - } - - pub fn attrs(&self) -> u32 { self.attributes as u32 } - - pub fn file_type(&self) -> FileType { - FileType::new(self.attributes, self.reparse_tag) - } - - pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(self.last_write_time)) - } - - pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(self.last_access_time)) - } - - pub fn created(&self) -> io::Result { - Ok(SystemTime::from(self.creation_time)) - } - - pub fn modified_u64(&self) -> u64 { - to_u64(&self.last_write_time) - } - - pub fn accessed_u64(&self) -> u64 { - to_u64(&self.last_access_time) - } - - pub fn created_u64(&self) -> u64 { - to_u64(&self.creation_time) - } - - fn is_reparse_point(&self) -> bool { - self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 - } -} - -fn to_u64(ft: &c::FILETIME) -> u64 { - (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32) -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - self.attrs & c::FILE_ATTRIBUTE_READONLY != 0 - } - - pub fn set_readonly(&mut self, readonly: bool) { - if readonly { - self.attrs |= c::FILE_ATTRIBUTE_READONLY; - } else { - self.attrs &= !c::FILE_ATTRIBUTE_READONLY; - } - } -} - -impl FileType { - fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType { - FileType { - attributes: attrs, - reparse_tag: reparse_tag, - } - } - pub fn is_dir(&self) -> bool { - !self.is_symlink() && self.is_directory() - } - pub fn is_file(&self) -> bool { - !self.is_symlink() && !self.is_directory() - } - pub fn is_symlink(&self) -> bool { - self.is_reparse_point() && self.is_reparse_tag_name_surrogate() - } - pub fn is_symlink_dir(&self) -> bool { - self.is_symlink() && self.is_directory() - } - pub fn is_symlink_file(&self) -> bool { - self.is_symlink() && !self.is_directory() - } - fn is_directory(&self) -> bool { - self.attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 - } - fn is_reparse_point(&self) -> bool { - self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 - } - fn is_reparse_tag_name_surrogate(&self) -> bool { - self.reparse_tag & 0x20000000 != 0 - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { DirBuilder } - - pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let p = to_u16s(p)?; - cvt(unsafe { - c::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) - })?; - Ok(()) - } -} - -pub fn readdir(p: &Path) -> io::Result { - let root = p.to_path_buf(); - let star = p.join("*"); - let path = to_u16s(&star)?; - - unsafe { - let mut wfd = mem::zeroed(); - let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd); - if find_handle != c::INVALID_HANDLE_VALUE { - Ok(ReadDir { - handle: FindNextFileHandle(find_handle), - root: Arc::new(root), - first: Some(wfd), - }) - } else { - Err(Error::last_os_error()) - } - } -} - -pub fn unlink(p: &Path) -> io::Result<()> { - let p_u16s = to_u16s(p)?; - cvt(unsafe { c::DeleteFileW(p_u16s.as_ptr()) })?; - Ok(()) -} - -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = to_u16s(old)?; - let new = to_u16s(new)?; - cvt(unsafe { - c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) - })?; - Ok(()) -} - -pub fn rmdir(p: &Path) -> io::Result<()> { - let p = to_u16s(p)?; - cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?; - Ok(()) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { - // On Windows symlinks to files and directories are removed differently. - // rmdir only deletes dir symlinks and junctions, not file symlinks. - rmdir(path) - } else { - remove_dir_all_recursive(path) - } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - let child_type = child.file_type()?; - if child_type.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else if child_type.is_symlink_dir() { - rmdir(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - -pub fn readlink(path: &Path) -> io::Result { - // Open the link with no access mode, instead of generic read. - // By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so - // this is needed for a common case. - let mut opts = OpenOptions::new(); - opts.access_mode(0); - opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | - c::FILE_FLAG_BACKUP_SEMANTICS); - let file = File::open(&path, &opts)?; - file.readlink() -} - -pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - symlink_inner(src, dst, false) -} - -pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> { - let src = to_u16s(src)?; - let dst = to_u16s(dst)?; - let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 }; - // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10 - // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the - // computer is in Developer Mode, but SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE must be - // added to dwFlags to opt into this behaviour. - let result = cvt(unsafe { - c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), - flags | c::SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) as c::BOOL - }); - if let Err(err) = result { - if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) { - // Older Windows objects to SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE, - // so if we encounter ERROR_INVALID_PARAMETER, retry without that flag. - cvt(unsafe { - c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL - })?; - } else { - return Err(err); - } - } - Ok(()) -} - -pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let src = to_u16s(src)?; - let dst = to_u16s(dst)?; - cvt(unsafe { - c::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut()) - })?; - Ok(()) -} - -pub fn stat(path: &Path) -> io::Result { - let mut opts = OpenOptions::new(); - // No read or write permissions are necessary - opts.access_mode(0); - // This flag is so we can open directories too - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - let file = File::open(path, &opts)?; - file.file_attr() -} - -pub fn lstat(path: &Path) -> io::Result { - let mut opts = OpenOptions::new(); - // No read or write permissions are necessary - opts.access_mode(0); - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); - let file = File::open(path, &opts)?; - file.file_attr() -} - -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = to_u16s(p)?; - unsafe { - cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?; - Ok(()) - } -} - -fn get_path(f: &File) -> io::Result { - super::fill_utf16_buf(|buf, sz| unsafe { - c::GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, - c::VOLUME_NAME_DOS) - }, |buf| { - PathBuf::from(OsString::from_wide(buf)) - }) -} - -pub fn canonicalize(p: &Path) -> io::Result { - let mut opts = OpenOptions::new(); - // No read or write permissions are necessary - opts.access_mode(0); - // This flag is so we can open directories too - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - let f = File::open(p, &opts)?; - get_path(&f) -} - -pub fn copy(from: &Path, to: &Path) -> io::Result { - unsafe extern "system" fn callback( - _TotalFileSize: c::LARGE_INTEGER, - _TotalBytesTransferred: c::LARGE_INTEGER, - _StreamSize: c::LARGE_INTEGER, - StreamBytesTransferred: c::LARGE_INTEGER, - dwStreamNumber: c::DWORD, - _dwCallbackReason: c::DWORD, - _hSourceFile: c::HANDLE, - _hDestinationFile: c::HANDLE, - lpData: c::LPVOID, - ) -> c::DWORD { - if dwStreamNumber == 1 {*(lpData as *mut i64) = StreamBytesTransferred;} - c::PROGRESS_CONTINUE - } - let pfrom = to_u16s(from)?; - let pto = to_u16s(to)?; - let mut size = 0i64; - cvt(unsafe { - c::CopyFileExW(pfrom.as_ptr(), pto.as_ptr(), Some(callback), - &mut size as *mut _ as *mut _, ptr::null_mut(), 0) - })?; - Ok(size as u64) -} - -#[allow(dead_code)] -pub fn symlink_junction, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - symlink_junction_inner(src.as_ref(), dst.as_ref()) -} - -// Creating a directory junction on windows involves dealing with reparse -// points and the DeviceIoControl function, and this code is a skeleton of -// what can be found here: -// -// http://www.flexhex.com/docs/articles/hard-links.phtml -#[allow(dead_code)] -fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> { - let d = DirBuilder::new(); - d.mkdir(&junction)?; - - let mut opts = OpenOptions::new(); - opts.write(true); - opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | - c::FILE_FLAG_BACKUP_SEMANTICS); - let f = File::open(junction, &opts)?; - let h = f.handle().raw(); - - unsafe { - let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - let db = data.as_mut_ptr() - as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER; - let buf = &mut (*db).ReparseTarget as *mut c::WCHAR; - let mut i = 0; - // FIXME: this conversion is very hacky - let v = br"\??\"; - let v = v.iter().map(|x| *x as u16); - for c in v.chain(target.as_os_str().encode_wide()) { - *buf.offset(i) = c; - i += 1; - } - *buf.offset(i) = 0; - i += 1; - (*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT; - (*db).ReparseTargetMaximumLength = (i * 2) as c::WORD; - (*db).ReparseTargetLength = ((i - 1) * 2) as c::WORD; - (*db).ReparseDataLength = - (*db).ReparseTargetLength as c::DWORD + 12; - - let mut ret = 0; - cvt(c::DeviceIoControl(h as *mut _, - c::FSCTL_SET_REPARSE_POINT, - data.as_ptr() as *mut _, - (*db).ReparseDataLength + 8, - ptr::null_mut(), 0, - &mut ret, - ptr::null_mut())).map(|_| ()) - } -} diff --git a/ctr-std/src/sys/windows/handle.rs b/ctr-std/src/sys/windows/handle.rs deleted file mode 100644 index 3729d6d..0000000 --- a/ctr-std/src/sys/windows/handle.rs +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(issue = "0", feature = "windows_handle")] - -use cmp; -use io::{ErrorKind, Read}; -use io; -use mem; -use ops::Deref; -use ptr; -use sys::c; -use sys::cvt; - -/// An owned container for `HANDLE` object, closing them on Drop. -/// -/// All methods are inherited through a `Deref` impl to `RawHandle` -pub struct Handle(RawHandle); - -/// A wrapper type for `HANDLE` objects to give them proper Send/Sync inference -/// as well as Rust-y methods. -/// -/// This does **not** drop the handle when it goes out of scope, use `Handle` -/// instead for that. -#[derive(Copy, Clone)] -pub struct RawHandle(c::HANDLE); - -unsafe impl Send for RawHandle {} -unsafe impl Sync for RawHandle {} - -impl Handle { - pub fn new(handle: c::HANDLE) -> Handle { - Handle(RawHandle::new(handle)) - } - - pub fn new_event(manual: bool, init: bool) -> io::Result { - unsafe { - let event = c::CreateEventW(ptr::null_mut(), - manual as c::BOOL, - init as c::BOOL, - ptr::null()); - if event.is_null() { - Err(io::Error::last_os_error()) - } else { - Ok(Handle::new(event)) - } - } - } - - pub fn into_raw(self) -> c::HANDLE { - let ret = self.raw(); - mem::forget(self); - return ret; - } -} - -impl Deref for Handle { - type Target = RawHandle; - fn deref(&self) -> &RawHandle { &self.0 } -} - -impl Drop for Handle { - fn drop(&mut self) { - unsafe { let _ = c::CloseHandle(self.raw()); } - } -} - -impl RawHandle { - pub fn new(handle: c::HANDLE) -> RawHandle { - RawHandle(handle) - } - - pub fn raw(&self) -> c::HANDLE { self.0 } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - let mut read = 0; - let len = cmp::min(buf.len(), ::max_value() as usize) as c::DWORD; - let res = cvt(unsafe { - c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, - len, &mut read, ptr::null_mut()) - }); - - match res { - Ok(_) => Ok(read as usize), - - // The special treatment of BrokenPipe is to deal with Windows - // pipe semantics, which yields this error when *reading* from - // a pipe after the other end has closed; we interpret that as - // EOF on the pipe. - Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(0), - - Err(e) => Err(e) - } - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - let mut read = 0; - let len = cmp::min(buf.len(), ::max_value() as usize) as c::DWORD; - let res = unsafe { - let mut overlapped: c::OVERLAPPED = mem::zeroed(); - overlapped.Offset = offset as u32; - overlapped.OffsetHigh = (offset >> 32) as u32; - cvt(c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, - len, &mut read, &mut overlapped)) - }; - match res { - Ok(_) => Ok(read as usize), - Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(0), - Err(e) => Err(e), - } - } - - pub unsafe fn read_overlapped(&self, - buf: &mut [u8], - overlapped: *mut c::OVERLAPPED) - -> io::Result> { - let len = cmp::min(buf.len(), ::max_value() as usize) as c::DWORD; - let mut amt = 0; - let res = cvt({ - c::ReadFile(self.0, buf.as_ptr() as c::LPVOID, - len, &mut amt, overlapped) - }); - match res { - Ok(_) => Ok(Some(amt as usize)), - Err(e) => { - if e.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) { - Ok(None) - } else if e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) { - Ok(Some(0)) - } else { - Err(e) - } - } - } - } - - pub fn overlapped_result(&self, - overlapped: *mut c::OVERLAPPED, - wait: bool) -> io::Result { - unsafe { - let mut bytes = 0; - let wait = if wait {c::TRUE} else {c::FALSE}; - let res = cvt({ - c::GetOverlappedResult(self.raw(), overlapped, &mut bytes, wait) - }); - match res { - Ok(_) => Ok(bytes as usize), - Err(e) => { - if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) || - e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) { - Ok(0) - } else { - Err(e) - } - } - } - } - } - - pub fn cancel_io(&self) -> io::Result<()> { - unsafe { - cvt(c::CancelIo(self.raw())).map(|_| ()) - } - } - - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - let mut me = self; - (&mut me).read_to_end(buf) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - let mut amt = 0; - let len = cmp::min(buf.len(), ::max_value() as usize) as c::DWORD; - cvt(unsafe { - c::WriteFile(self.0, buf.as_ptr() as c::LPVOID, - len, &mut amt, ptr::null_mut()) - })?; - Ok(amt as usize) - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - let mut written = 0; - let len = cmp::min(buf.len(), ::max_value() as usize) as c::DWORD; - unsafe { - let mut overlapped: c::OVERLAPPED = mem::zeroed(); - overlapped.Offset = offset as u32; - overlapped.OffsetHigh = (offset >> 32) as u32; - cvt(c::WriteFile(self.0, buf.as_ptr() as c::LPVOID, - len, &mut written, &mut overlapped))?; - } - Ok(written as usize) - } - - pub fn duplicate(&self, access: c::DWORD, inherit: bool, - options: c::DWORD) -> io::Result { - let mut ret = 0 as c::HANDLE; - cvt(unsafe { - let cur_proc = c::GetCurrentProcess(); - c::DuplicateHandle(cur_proc, self.0, cur_proc, &mut ret, - access, inherit as c::BOOL, - options) - })?; - Ok(Handle::new(ret)) - } -} - -impl<'a> Read for &'a RawHandle { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (**self).read(buf) - } -} diff --git a/ctr-std/src/sys/windows/memchr.rs b/ctr-std/src/sys/windows/memchr.rs deleted file mode 100644 index fa7c816..0000000 --- a/ctr-std/src/sys/windows/memchr.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// Original implementation taken from rust-memchr -// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch - -// Fallback memchr is fastest on windows -pub use core::slice::memchr::{memchr, memrchr}; diff --git a/ctr-std/src/sys/windows/mod.rs b/ctr-std/src/sys/windows/mod.rs deleted file mode 100644 index ccf79de..0000000 --- a/ctr-std/src/sys/windows/mod.rs +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(missing_docs, bad_style)] - -use ptr; -use ffi::{OsStr, OsString}; -use io::{self, ErrorKind}; -use os::windows::ffi::{OsStrExt, OsStringExt}; -use path::PathBuf; -use time::Duration; - -pub use libc::strlen; -pub use self::rand::hashmap_random_keys; - -#[macro_use] pub mod compat; - -pub mod args; -#[cfg(feature = "backtrace")] -pub mod backtrace; -pub mod c; -pub mod cmath; -pub mod condvar; -#[cfg(feature = "backtrace")] -pub mod dynamic_lib; -pub mod env; -pub mod ext; -pub mod fast_thread_local; -pub mod fs; -pub mod handle; -pub mod memchr; -pub mod mutex; -pub mod net; -pub mod os; -pub mod os_str; -pub mod path; -pub mod pipe; -pub mod process; -pub mod rand; -pub mod rwlock; -pub mod stack_overflow; -pub mod thread; -pub mod thread_local; -pub mod time; -pub mod stdio; - -#[cfg(not(test))] -pub fn init() { -} - -pub fn decode_error_kind(errno: i32) -> ErrorKind { - match errno as c::DWORD { - c::ERROR_ACCESS_DENIED => return ErrorKind::PermissionDenied, - c::ERROR_ALREADY_EXISTS => return ErrorKind::AlreadyExists, - c::ERROR_FILE_EXISTS => return ErrorKind::AlreadyExists, - c::ERROR_BROKEN_PIPE => return ErrorKind::BrokenPipe, - c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound, - c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound, - c::ERROR_NO_DATA => return ErrorKind::BrokenPipe, - c::ERROR_OPERATION_ABORTED => return ErrorKind::TimedOut, - _ => {} - } - - match errno { - c::WSAEACCES => ErrorKind::PermissionDenied, - c::WSAEADDRINUSE => ErrorKind::AddrInUse, - c::WSAEADDRNOTAVAIL => ErrorKind::AddrNotAvailable, - c::WSAECONNABORTED => ErrorKind::ConnectionAborted, - c::WSAECONNREFUSED => ErrorKind::ConnectionRefused, - c::WSAECONNRESET => ErrorKind::ConnectionReset, - c::WSAEINVAL => ErrorKind::InvalidInput, - c::WSAENOTCONN => ErrorKind::NotConnected, - c::WSAEWOULDBLOCK => ErrorKind::WouldBlock, - c::WSAETIMEDOUT => ErrorKind::TimedOut, - - _ => ErrorKind::Other, - } -} - -pub fn to_u16s>(s: S) -> io::Result> { - fn inner(s: &OsStr) -> io::Result> { - let mut maybe_result: Vec = s.encode_wide().collect(); - if maybe_result.iter().any(|&u| u == 0) { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "strings passed to WinAPI cannot contain NULs")); - } - maybe_result.push(0); - Ok(maybe_result) - } - inner(s.as_ref()) -} - -// Many Windows APIs follow a pattern of where we hand a buffer and then they -// will report back to us how large the buffer should be or how many bytes -// currently reside in the buffer. This function is an abstraction over these -// functions by making them easier to call. -// -// The first callback, `f1`, is yielded a (pointer, len) pair which can be -// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case). -// The closure is expected to return what the syscall returns which will be -// interpreted by this function to determine if the syscall needs to be invoked -// again (with more buffer space). -// -// Once the syscall has completed (errors bail out early) the second closure is -// yielded the data which has been read from the syscall. The return value -// from this closure is then the return value of the function. -fn fill_utf16_buf(mut f1: F1, f2: F2) -> io::Result - where F1: FnMut(*mut u16, c::DWORD) -> c::DWORD, - F2: FnOnce(&[u16]) -> T -{ - // Start off with a stack buf but then spill over to the heap if we end up - // needing more space. - let mut stack_buf = [0u16; 512]; - let mut heap_buf = Vec::new(); - unsafe { - let mut n = stack_buf.len(); - loop { - let buf = if n <= stack_buf.len() { - &mut stack_buf[..] - } else { - let extra = n - heap_buf.len(); - heap_buf.reserve(extra); - heap_buf.set_len(n); - &mut heap_buf[..] - }; - - // This function is typically called on windows API functions which - // will return the correct length of the string, but these functions - // also return the `0` on error. In some cases, however, the - // returned "correct length" may actually be 0! - // - // To handle this case we call `SetLastError` to reset it to 0 and - // then check it again if we get the "0 error value". If the "last - // error" is still 0 then we interpret it as a 0 length buffer and - // not an actual error. - c::SetLastError(0); - let k = match f1(buf.as_mut_ptr(), n as c::DWORD) { - 0 if c::GetLastError() == 0 => 0, - 0 => return Err(io::Error::last_os_error()), - n => n, - } as usize; - if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER { - n *= 2; - } else if k >= n { - n = k; - } else { - return Ok(f2(&buf[..k])) - } - } - } -} - -fn os2path(s: &[u16]) -> PathBuf { - PathBuf::from(OsString::from_wide(s)) -} - -#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename() -fn wide_char_to_multi_byte(code_page: u32, - flags: u32, - s: &[u16], - no_default_char: bool) - -> io::Result> { - unsafe { - let mut size = c::WideCharToMultiByte(code_page, - flags, - s.as_ptr(), - s.len() as i32, - ptr::null_mut(), - 0, - ptr::null(), - ptr::null_mut()); - if size == 0 { - return Err(io::Error::last_os_error()); - } - - let mut buf = Vec::with_capacity(size as usize); - buf.set_len(size as usize); - - let mut used_default_char = c::FALSE; - size = c::WideCharToMultiByte(code_page, - flags, - s.as_ptr(), - s.len() as i32, - buf.as_mut_ptr(), - buf.len() as i32, - ptr::null(), - if no_default_char { &mut used_default_char } - else { ptr::null_mut() }); - if size == 0 { - return Err(io::Error::last_os_error()); - } - if no_default_char && used_default_char == c::TRUE { - return Err(io::Error::new(io::ErrorKind::InvalidData, - "string cannot be converted to requested code page")); - } - - buf.set_len(size as usize); - - Ok(buf) - } -} - -pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { - match v.iter().position(|c| *c == 0) { - // don't include the 0 - Some(i) => &v[..i], - None => v - } -} - -pub trait IsZero { - fn is_zero(&self) -> bool; -} - -macro_rules! impl_is_zero { - ($($t:ident)*) => ($(impl IsZero for $t { - fn is_zero(&self) -> bool { - *self == 0 - } - })*) -} - -impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } - -pub fn cvt(i: I) -> io::Result { - if i.is_zero() { - Err(io::Error::last_os_error()) - } else { - Ok(i) - } -} - -pub fn dur2timeout(dur: Duration) -> c::DWORD { - // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the - // timeouts in windows APIs are typically u32 milliseconds. To translate, we - // have two pieces to take care of: - // - // * Nanosecond precision is rounded up - // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE - // (never time out). - dur.as_secs().checked_mul(1000).and_then(|ms| { - ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000) - }).and_then(|ms| { - ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 {1} else {0}) - }).map(|ms| { - if ms > ::max_value() as u64 { - c::INFINITE - } else { - ms as c::DWORD - } - }).unwrap_or(c::INFINITE) -} - -// On Windows, use the processor-specific __fastfail mechanism. In Windows 8 -// and later, this will terminate the process immediately without running any -// in-process exception handlers. In earlier versions of Windows, this -// sequence of instructions will be treated as an access violation, -// terminating the process but without necessarily bypassing all exception -// handlers. -// -// https://msdn.microsoft.com/en-us/library/dn774154.aspx -#[allow(unreachable_code)] -pub unsafe fn abort_internal() -> ! { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT - ::intrinsics::unreachable(); - } - ::intrinsics::abort(); -} diff --git a/ctr-std/src/sys/windows/mutex.rs b/ctr-std/src/sys/windows/mutex.rs deleted file mode 100644 index 9bf9f74..0000000 --- a/ctr-std/src/sys/windows/mutex.rs +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! System Mutexes -//! -//! The Windows implementation of mutexes is a little odd and it may not be -//! immediately obvious what's going on. The primary oddness is that SRWLock is -//! used instead of CriticalSection, and this is done because: -//! -//! 1. SRWLock is several times faster than CriticalSection according to -//! benchmarks performed on both Windows 8 and Windows 7. -//! -//! 2. CriticalSection allows recursive locking while SRWLock deadlocks. The -//! Unix implementation deadlocks so consistency is preferred. See #19962 for -//! more details. -//! -//! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy -//! is that there are no guarantees of fairness. -//! -//! The downside of this approach, however, is that SRWLock is not available on -//! Windows XP, so we continue to have a fallback implementation where -//! CriticalSection is used and we keep track of who's holding the mutex to -//! detect recursive locks. - -use cell::UnsafeCell; -use mem; -use sync::atomic::{AtomicUsize, Ordering}; -use sys::c; -use sys::compat; - -pub struct Mutex { - lock: AtomicUsize, - held: UnsafeCell, -} - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} - -#[derive(Clone, Copy)] -enum Kind { - SRWLock = 1, - CriticalSection = 2, -} - -#[inline] -pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK { - debug_assert!(mem::size_of::() <= mem::size_of_val(&m.lock)); - &m.lock as *const _ as *mut _ -} - -impl Mutex { - pub const fn new() -> Mutex { - Mutex { - lock: AtomicUsize::new(0), - held: UnsafeCell::new(false), - } - } - #[inline] - pub unsafe fn init(&mut self) {} - pub unsafe fn lock(&self) { - match kind() { - Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)), - Kind::CriticalSection => { - let re = self.remutex(); - (*re).lock(); - if !self.flag_locked() { - (*re).unlock(); - panic!("cannot recursively lock a mutex"); - } - } - } - } - pub unsafe fn try_lock(&self) -> bool { - match kind() { - Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0, - Kind::CriticalSection => { - let re = self.remutex(); - if !(*re).try_lock() { - false - } else if self.flag_locked() { - true - } else { - (*re).unlock(); - false - } - } - } - } - pub unsafe fn unlock(&self) { - *self.held.get() = false; - match kind() { - Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)), - Kind::CriticalSection => (*self.remutex()).unlock(), - } - } - pub unsafe fn destroy(&self) { - match kind() { - Kind::SRWLock => {} - Kind::CriticalSection => { - match self.lock.load(Ordering::SeqCst) { - 0 => {} - n => { Box::from_raw(n as *mut ReentrantMutex).destroy(); } - } - } - } - } - - unsafe fn remutex(&self) -> *mut ReentrantMutex { - match self.lock.load(Ordering::SeqCst) { - 0 => {} - n => return n as *mut _, - } - let mut re = box ReentrantMutex::uninitialized(); - re.init(); - let re = Box::into_raw(re); - match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) { - 0 => re, - n => { Box::from_raw(re).destroy(); n as *mut _ } - } - } - - unsafe fn flag_locked(&self) -> bool { - if *self.held.get() { - false - } else { - *self.held.get() = true; - true - } - - } -} - -fn kind() -> Kind { - static KIND: AtomicUsize = AtomicUsize::new(0); - - let val = KIND.load(Ordering::SeqCst); - if val == Kind::SRWLock as usize { - return Kind::SRWLock - } else if val == Kind::CriticalSection as usize { - return Kind::CriticalSection - } - - let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") { - None => Kind::CriticalSection, - Some(..) => Kind::SRWLock, - }; - KIND.store(ret as usize, Ordering::SeqCst); - return ret; -} - -pub struct ReentrantMutex { inner: UnsafeCell } - -unsafe impl Send for ReentrantMutex {} -unsafe impl Sync for ReentrantMutex {} - -impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { - mem::uninitialized() - } - - pub unsafe fn init(&mut self) { - c::InitializeCriticalSection(self.inner.get()); - } - - pub unsafe fn lock(&self) { - c::EnterCriticalSection(self.inner.get()); - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - c::TryEnterCriticalSection(self.inner.get()) != 0 - } - - pub unsafe fn unlock(&self) { - c::LeaveCriticalSection(self.inner.get()); - } - - pub unsafe fn destroy(&self) { - c::DeleteCriticalSection(self.inner.get()); - } -} diff --git a/ctr-std/src/sys/windows/net.rs b/ctr-std/src/sys/windows/net.rs deleted file mode 100644 index cd8acff..0000000 --- a/ctr-std/src/sys/windows/net.rs +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(issue = "0", feature = "windows_net")] - -use cmp; -use io::{self, Read}; -use libc::{c_int, c_void, c_ulong, c_long}; -use mem; -use net::{SocketAddr, Shutdown}; -use ptr; -use sync::Once; -use sys::c; -use sys; -use sys_common::{self, AsInner, FromInner, IntoInner}; -use sys_common::net; -use time::Duration; - -pub type wrlen_t = i32; - -pub mod netc { - pub use sys::c::*; - pub use sys::c::SOCKADDR as sockaddr; - pub use sys::c::SOCKADDR_STORAGE_LH as sockaddr_storage; - pub use sys::c::ADDRINFOA as addrinfo; - pub use sys::c::ADDRESS_FAMILY as sa_family_t; -} - -pub struct Socket(c::SOCKET); - -/// Checks whether the Windows socket interface has been started already, and -/// if not, starts it. -pub fn init() { - static START: Once = Once::new(); - - START.call_once(|| unsafe { - let mut data: c::WSADATA = mem::zeroed(); - let ret = c::WSAStartup(0x202, // version 2.2 - &mut data); - assert_eq!(ret, 0); - - let _ = sys_common::at_exit(|| { c::WSACleanup(); }); - }); -} - -/// Returns the last error from the Windows socket interface. -fn last_error() -> io::Error { - io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) -} - -#[doc(hidden)] -pub trait IsMinusOne { - fn is_minus_one(&self) -> bool; -} - -macro_rules! impl_is_minus_one { - ($($t:ident)*) => ($(impl IsMinusOne for $t { - fn is_minus_one(&self) -> bool { - *self == -1 - } - })*) -} - -impl_is_minus_one! { i8 i16 i32 i64 isize } - -/// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1) -/// and if so, returns the last error from the Windows socket interface. This -/// function must be called before another call to the socket API is made. -pub fn cvt(t: T) -> io::Result { - if t.is_minus_one() { - Err(last_error()) - } else { - Ok(t) - } -} - -/// A variant of `cvt` for `getaddrinfo` which return 0 for a success. -pub fn cvt_gai(err: c_int) -> io::Result<()> { - if err == 0 { - Ok(()) - } else { - Err(last_error()) - } -} - -/// Just to provide the same interface as sys/unix/net.rs -pub fn cvt_r(mut f: F) -> io::Result - where T: IsMinusOne, - F: FnMut() -> T -{ - cvt(f()) -} - -impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => c::AF_INET, - SocketAddr::V6(..) => c::AF_INET6, - }; - let socket = unsafe { - match c::WSASocketW(fam, ty, 0, ptr::null_mut(), 0, - c::WSA_FLAG_OVERLAPPED) { - c::INVALID_SOCKET => Err(last_error()), - n => Ok(Socket(n)), - } - }?; - socket.set_no_inherit()?; - Ok(socket) - } - - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = unsafe { - let (addrp, len) = addr.into_inner(); - cvt(c::connect(self.0, addrp, len)) - }; - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {} - Err(e) => return Err(e), - } - - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout")); - } - - let mut timeout = c::timeval { - tv_sec: timeout.as_secs() as c_long, - tv_usec: (timeout.subsec_nanos() / 1000) as c_long, - }; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } - - let fds = unsafe { - let mut fds = mem::zeroed::(); - fds.fd_count = 1; - fds.fd_array[0] = self.0; - fds - }; - - let mut writefds = fds; - let mut errorfds = fds; - - let n = unsafe { - cvt(c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout))? - }; - - match n { - 0 => Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")), - _ => { - if writefds.fd_count != 1 { - if let Some(e) = self.take_error()? { - return Err(e); - } - } - Ok(()) - } - } - } - - pub fn accept(&self, storage: *mut c::SOCKADDR, - len: *mut c_int) -> io::Result { - let socket = unsafe { - match c::accept(self.0, storage, len) { - c::INVALID_SOCKET => Err(last_error()), - n => Ok(Socket(n)), - } - }?; - socket.set_no_inherit()?; - Ok(socket) - } - - pub fn duplicate(&self) -> io::Result { - let socket = unsafe { - let mut info: c::WSAPROTOCOL_INFO = mem::zeroed(); - cvt(c::WSADuplicateSocketW(self.0, - c::GetCurrentProcessId(), - &mut info))?; - match c::WSASocketW(info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, 0, - c::WSA_FLAG_OVERLAPPED) { - c::INVALID_SOCKET => Err(last_error()), - n => Ok(Socket(n)), - } - }?; - socket.set_no_inherit()?; - Ok(socket) - } - - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { - // On unix when a socket is shut down all further reads return 0, so we - // do the same on windows to map a shut down socket to returning EOF. - let len = cmp::min(buf.len(), i32::max_value() as usize) as i32; - unsafe { - match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) { - -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0), - -1 => Err(last_error()), - n => Ok(n as usize) - } - } - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, 0) - } - - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, c::MSG_PEEK) - } - - fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int) - -> io::Result<(usize, SocketAddr)> { - let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; - let len = cmp::min(buf.len(), ::max_value() as usize) as wrlen_t; - - // On unix when a socket is shut down all further reads return 0, so we - // do the same on windows to map a shut down socket to returning EOF. - unsafe { - match c::recvfrom(self.0, - buf.as_mut_ptr() as *mut c_void, - len, - flags, - &mut storage as *mut _ as *mut _, - &mut addrlen) { - -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => { - Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?)) - }, - -1 => Err(last_error()), - n => Ok((n as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)), - } - } - } - - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, 0) - } - - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, c::MSG_PEEK) - } - - pub fn set_timeout(&self, dur: Option, - kind: c_int) -> io::Result<()> { - let timeout = match dur { - Some(dur) => { - let timeout = sys::dur2timeout(dur); - if timeout == 0 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout")); - } - timeout - } - None => 0 - }; - net::setsockopt(self, c::SOL_SOCKET, kind, timeout) - } - - pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: c::DWORD = net::getsockopt(self, c::SOL_SOCKET, kind)?; - if raw == 0 { - Ok(None) - } else { - let secs = raw / 1000; - let nsec = (raw % 1000) * 1000000; - Ok(Some(Duration::new(secs as u64, nsec as u32))) - } - } - - fn set_no_inherit(&self) -> io::Result<()> { - sys::cvt(unsafe { - c::SetHandleInformation(self.0 as c::HANDLE, - c::HANDLE_FLAG_INHERIT, 0) - }).map(|_| ()) - } - - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - let how = match how { - Shutdown::Write => c::SD_SEND, - Shutdown::Read => c::SD_RECEIVE, - Shutdown::Both => c::SD_BOTH, - }; - cvt(unsafe { c::shutdown(self.0, how) })?; - Ok(()) - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as c_ulong; - let r = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) }; - if r == 0 { - Ok(()) - } else { - Err(io::Error::last_os_error()) - } - } - - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BYTE) - } - - pub fn nodelay(&self) -> io::Result { - let raw: c::BYTE = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; - Ok(raw != 0) - } - - pub fn take_error(&self) -> io::Result> { - let raw: c_int = net::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?; - if raw == 0 { - Ok(None) - } else { - Ok(Some(io::Error::from_raw_os_error(raw as i32))) - } - } -} - -#[unstable(reason = "not public", issue = "0", feature = "fd_read")] -impl<'a> Read for &'a Socket { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (**self).read(buf) - } -} - -impl Drop for Socket { - fn drop(&mut self) { - let _ = unsafe { c::closesocket(self.0) }; - } -} - -impl AsInner for Socket { - fn as_inner(&self) -> &c::SOCKET { &self.0 } -} - -impl FromInner for Socket { - fn from_inner(sock: c::SOCKET) -> Socket { Socket(sock) } -} - -impl IntoInner for Socket { - fn into_inner(self) -> c::SOCKET { - let ret = self.0; - mem::forget(self); - ret - } -} diff --git a/ctr-std/src/sys/windows/os.rs b/ctr-std/src/sys/windows/os.rs deleted file mode 100644 index b944824..0000000 --- a/ctr-std/src/sys/windows/os.rs +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation of `std::os` functionality for Windows - -#![allow(bad_style)] - -use os::windows::prelude::*; - -use error::Error as StdError; -use ffi::{OsString, OsStr}; -use fmt; -use io; -use os::windows::ffi::EncodeWide; -use path::{self, PathBuf}; -use ptr; -use slice; -use sys::{c, cvt}; -use sys::handle::Handle; - -use super::to_u16s; - -pub fn errno() -> i32 { - unsafe { c::GetLastError() as i32 } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(mut errnum: i32) -> String { - // This value is calculated from the macro - // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) - let langId = 0x0800 as c::DWORD; - - let mut buf = [0 as c::WCHAR; 2048]; - - unsafe { - let mut module = ptr::null_mut(); - let mut flags = 0; - - // NTSTATUS errors may be encoded as HRESULT, which may returned from - // GetLastError. For more information about Windows error codes, see - // `[MS-ERREF]`: https://msdn.microsoft.com/en-us/library/cc231198.aspx - if (errnum & c::FACILITY_NT_BIT as i32) != 0 { - // format according to https://support.microsoft.com/en-us/help/259693 - const NTDLL_DLL: &'static [u16] = &['N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, - '.' as _, 'D' as _, 'L' as _, 'L' as _, 0]; - module = c::GetModuleHandleW(NTDLL_DLL.as_ptr()); - - if module != ptr::null_mut() { - errnum ^= c::FACILITY_NT_BIT as i32; - flags = c::FORMAT_MESSAGE_FROM_HMODULE; - } - } - - let res = c::FormatMessageW(flags | c::FORMAT_MESSAGE_FROM_SYSTEM | - c::FORMAT_MESSAGE_IGNORE_INSERTS, - module, - errnum as c::DWORD, - langId, - buf.as_mut_ptr(), - buf.len() as c::DWORD, - ptr::null()) as usize; - if res == 0 { - // Sometimes FormatMessageW can fail e.g. system doesn't like langId, - let fm_err = errno(); - return format!("OS Error {} (FormatMessageW() returned error {})", - errnum, fm_err); - } - - match String::from_utf16(&buf[..res]) { - Ok(mut msg) => { - // Trim trailing CRLF inserted by FormatMessageW - let len = msg.trim_right().len(); - msg.truncate(len); - msg - }, - Err(..) => format!("OS Error {} (FormatMessageW() returned \ - invalid UTF-16)", errnum), - } - } -} - -pub struct Env { - base: c::LPWCH, - cur: c::LPWCH, -} - -impl Iterator for Env { - type Item = (OsString, OsString); - - fn next(&mut self) -> Option<(OsString, OsString)> { - loop { - unsafe { - if *self.cur == 0 { return None } - let p = &*self.cur as *const u16; - let mut len = 0; - while *p.offset(len) != 0 { - len += 1; - } - let s = slice::from_raw_parts(p, len as usize); - self.cur = self.cur.offset(len + 1); - - // Windows allows environment variables to start with an equals - // symbol (in any other position, this is the separator between - // variable name and value). Since`s` has at least length 1 at - // this point (because the empty string terminates the array of - // environment variables), we can safely slice. - let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) { - Some(p) => p, - None => continue, - }; - return Some(( - OsStringExt::from_wide(&s[..pos]), - OsStringExt::from_wide(&s[pos+1..]), - )) - } - } - } -} - -impl Drop for Env { - fn drop(&mut self) { - unsafe { c::FreeEnvironmentStringsW(self.base); } - } -} - -pub fn env() -> Env { - unsafe { - let ch = c::GetEnvironmentStringsW(); - if ch as usize == 0 { - panic!("failure getting env string from OS: {}", - io::Error::last_os_error()); - } - Env { base: ch, cur: ch } - } -} - -pub struct SplitPaths<'a> { - data: EncodeWide<'a>, - must_yield: bool, -} - -pub fn split_paths(unparsed: &OsStr) -> SplitPaths { - SplitPaths { - data: unparsed.encode_wide(), - must_yield: true, - } -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - // On Windows, the PATH environment variable is semicolon separated. - // Double quotes are used as a way of introducing literal semicolons - // (since c:\some;dir is a valid Windows path). Double quotes are not - // themselves permitted in path names, so there is no way to escape a - // double quote. Quoted regions can appear in arbitrary locations, so - // - // c:\foo;c:\som"e;di"r;c:\bar - // - // Should parse as [c:\foo, c:\some;dir, c:\bar]. - // - // (The above is based on testing; there is no clear reference available - // for the grammar.) - - - let must_yield = self.must_yield; - self.must_yield = false; - - let mut in_progress = Vec::new(); - let mut in_quote = false; - for b in self.data.by_ref() { - if b == '"' as u16 { - in_quote = !in_quote; - } else if b == ';' as u16 && !in_quote { - self.must_yield = true; - break - } else { - in_progress.push(b) - } - } - - if !must_yield && in_progress.is_empty() { - None - } else { - Some(super::os2path(&in_progress)) - } - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(paths: I) -> Result - where I: Iterator, T: AsRef -{ - let mut joined = Vec::new(); - let sep = b';' as u16; - - for (i, path) in paths.enumerate() { - let path = path.as_ref(); - if i > 0 { joined.push(sep) } - let v = path.encode_wide().collect::>(); - if v.contains(&(b'"' as u16)) { - return Err(JoinPathsError) - } else if v.contains(&sep) { - joined.push(b'"' as u16); - joined.extend_from_slice(&v[..]); - joined.push(b'"' as u16); - } else { - joined.extend_from_slice(&v[..]); - } - } - - Ok(OsStringExt::from_wide(&joined[..])) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "path segment contains `\"`".fmt(f) - } -} - -impl StdError for JoinPathsError { - fn description(&self) -> &str { "failed to join paths" } -} - -pub fn current_exe() -> io::Result { - super::fill_utf16_buf(|buf, sz| unsafe { - c::GetModuleFileNameW(ptr::null_mut(), buf, sz) - }, super::os2path) -} - -pub fn getcwd() -> io::Result { - super::fill_utf16_buf(|buf, sz| unsafe { - c::GetCurrentDirectoryW(sz, buf) - }, super::os2path) -} - -pub fn chdir(p: &path::Path) -> io::Result<()> { - let p: &OsStr = p.as_ref(); - let mut p = p.encode_wide().collect::>(); - p.push(0); - - cvt(unsafe { - c::SetCurrentDirectoryW(p.as_ptr()) - }).map(|_| ()) -} - -pub fn getenv(k: &OsStr) -> io::Result> { - let k = to_u16s(k)?; - let res = super::fill_utf16_buf(|buf, sz| unsafe { - c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) - }, |buf| { - OsStringExt::from_wide(buf) - }); - match res { - Ok(value) => Ok(Some(value)), - Err(e) => { - if e.raw_os_error() == Some(c::ERROR_ENVVAR_NOT_FOUND as i32) { - Ok(None) - } else { - Err(e) - } - } - } -} - -pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let k = to_u16s(k)?; - let v = to_u16s(v)?; - - cvt(unsafe { - c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr()) - }).map(|_| ()) -} - -pub fn unsetenv(n: &OsStr) -> io::Result<()> { - let v = to_u16s(n)?; - cvt(unsafe { - c::SetEnvironmentVariableW(v.as_ptr(), ptr::null()) - }).map(|_| ()) -} - -pub fn temp_dir() -> PathBuf { - super::fill_utf16_buf(|buf, sz| unsafe { - c::GetTempPathW(sz, buf) - }, super::os2path).unwrap() -} - -pub fn home_dir() -> Option { - ::env::var_os("HOME").or_else(|| { - ::env::var_os("USERPROFILE") - }).map(PathBuf::from).or_else(|| unsafe { - let me = c::GetCurrentProcess(); - let mut token = ptr::null_mut(); - if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 { - return None - } - let _handle = Handle::new(token); - super::fill_utf16_buf(|buf, mut sz| { - match c::GetUserProfileDirectoryW(token, buf, &mut sz) { - 0 if c::GetLastError() != c::ERROR_INSUFFICIENT_BUFFER => 0, - 0 => sz, - _ => sz - 1, // sz includes the null terminator - } - }, super::os2path).ok() - }) -} - -pub fn exit(code: i32) -> ! { - unsafe { c::ExitProcess(code as c::UINT) } -} - -pub fn getpid() -> u32 { - unsafe { c::GetCurrentProcessId() as u32 } -} - -#[cfg(test)] -mod tests { - use io::Error; - use sys::c; - - // tests `error_string` above - #[test] - fn ntstatus_error() { - const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001; - assert!(!Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _) - .to_string().contains("FormatMessageW() returned error")); - } -} diff --git a/ctr-std/src/sys/windows/os_str.rs b/ctr-std/src/sys/windows/os_str.rs deleted file mode 100644 index bcc66b9..0000000 --- a/ctr-std/src/sys/windows/os_str.rs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// The underlying OsString/OsStr implementation on Windows is a -/// wrapper around the "WTF-8" encoding; see the `wtf8` module for more. - -use borrow::Cow; -use fmt; -use sys_common::wtf8::{Wtf8, Wtf8Buf}; -use mem; -use rc::Rc; -use sync::Arc; -use sys_common::{AsInner, IntoInner, FromInner}; - -#[derive(Clone, Hash)] -pub struct Buf { - pub inner: Wtf8Buf -} - -impl IntoInner for Buf { - fn into_inner(self) -> Wtf8Buf { - self.inner - } -} - -impl FromInner for Buf { - fn from_inner(inner: Wtf8Buf) -> Self { - Buf { inner } - } -} - -impl AsInner for Buf { - fn as_inner(&self) -> &Wtf8 { - &self.inner - } -} - -impl fmt::Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), formatter) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), formatter) - } -} - -pub struct Slice { - pub inner: Wtf8 -} - -impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.inner, formatter) - } -} - -impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.inner, formatter) - } -} - -impl Buf { - pub fn with_capacity(capacity: usize) -> Buf { - Buf { - inner: Wtf8Buf::with_capacity(capacity) - } - } - - pub fn clear(&mut self) { - self.inner.clear() - } - - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - pub fn from_string(s: String) -> Buf { - Buf { inner: Wtf8Buf::from_string(s) } - } - - pub fn as_slice(&self) -> &Slice { - unsafe { mem::transmute(self.inner.as_slice()) } - } - - pub fn into_string(self) -> Result { - self.inner.into_string().map_err(|buf| Buf { inner: buf }) - } - - pub fn push_slice(&mut self, s: &Slice) { - self.inner.push_wtf8(&s.inner) - } - - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - #[inline] - pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.inner.into_box()) } - } - - #[inline] - pub fn from_box(boxed: Box) -> Buf { - let inner: Box = unsafe { mem::transmute(boxed) }; - Buf { inner: Wtf8Buf::from_box(inner) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - self.as_slice().into_arc() - } - - #[inline] - pub fn into_rc(&self) -> Rc { - self.as_slice().into_rc() - } -} - -impl Slice { - pub fn from_str(s: &str) -> &Slice { - unsafe { mem::transmute(Wtf8::from_str(s)) } - } - - pub fn to_str(&self) -> Option<&str> { - self.inner.as_str() - } - - pub fn to_string_lossy(&self) -> Cow { - self.inner.to_string_lossy() - } - - pub fn to_owned(&self) -> Buf { - let mut buf = Wtf8Buf::with_capacity(self.inner.len()); - buf.push_wtf8(&self.inner); - Buf { inner: buf } - } - - #[inline] - pub fn into_box(&self) -> Box { - unsafe { mem::transmute(self.inner.into_box()) } - } - - pub fn empty_box() -> Box { - unsafe { mem::transmute(Wtf8::empty_box()) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc = self.inner.into_arc(); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc = self.inner.into_rc(); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } - } -} diff --git a/ctr-std/src/sys/windows/path.rs b/ctr-std/src/sys/windows/path.rs deleted file mode 100644 index 98d62a0..0000000 --- a/ctr-std/src/sys/windows/path.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use path::Prefix; -use ffi::OsStr; -use mem; - -fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { - unsafe { mem::transmute(s) } -} -unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - mem::transmute(s) -} - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' || b == b'\\' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'\\' -} - -pub fn parse_prefix<'a>(path: &'a OsStr) -> Option { - use path::Prefix::*; - unsafe { - // The unsafety here stems from converting between &OsStr and &[u8] - // and back. This is safe to do because (1) we only look at ASCII - // contents of the encoding and (2) new &OsStr values are produced - // only from ASCII-bounded slices of existing &OsStr values. - let mut path = os_str_as_u8_slice(path); - - if path.starts_with(br"\\") { - // \\ - path = &path[2..]; - if path.starts_with(br"?\") { - // \\?\ - path = &path[2..]; - if path.starts_with(br"UNC\") { - // \\?\UNC\server\share - path = &path[4..]; - let (server, share) = match parse_two_comps(path, is_verbatim_sep) { - Some((server, share)) => - (u8_slice_as_os_str(server), u8_slice_as_os_str(share)), - None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])), - }; - return Some(VerbatimUNC(server, share)); - } else { - // \\?\path - let idx = path.iter().position(|&b| b == b'\\'); - if idx == Some(2) && path[1] == b':' { - let c = path[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - // \\?\C:\ path - return Some(VerbatimDisk(c.to_ascii_uppercase())); - } - } - let slice = &path[..idx.unwrap_or(path.len())]; - return Some(Verbatim(u8_slice_as_os_str(slice))); - } - } else if path.starts_with(b".\\") { - // \\.\path - path = &path[2..]; - let pos = path.iter().position(|&b| b == b'\\'); - let slice = &path[..pos.unwrap_or(path.len())]; - return Some(DeviceNS(u8_slice_as_os_str(slice))); - } - match parse_two_comps(path, is_sep_byte) { - Some((server, share)) if !server.is_empty() && !share.is_empty() => { - // \\server\share - return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share))); - } - _ => (), - } - } else if path.get(1) == Some(& b':') { - // C: - let c = path[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - return Some(Disk(c.to_ascii_uppercase())); - } - } - return None; - } - - fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { - let first = match path.iter().position(|x| f(*x)) { - None => return None, - Some(x) => &path[..x], - }; - path = &path[(first.len() + 1)..]; - let idx = path.iter().position(|x| f(*x)); - let second = &path[..idx.unwrap_or(path.len())]; - Some((first, second)) - } -} - -pub const MAIN_SEP_STR: &'static str = "\\"; -pub const MAIN_SEP: char = '\\'; diff --git a/ctr-std/src/sys/windows/pipe.rs b/ctr-std/src/sys/windows/pipe.rs deleted file mode 100644 index df1dd74..0000000 --- a/ctr-std/src/sys/windows/pipe.rs +++ /dev/null @@ -1,364 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use os::windows::prelude::*; - -use ffi::OsStr; -use io; -use mem; -use path::Path; -use ptr; -use slice; -use sync::atomic::Ordering::SeqCst; -use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; -use sys::c; -use sys::fs::{File, OpenOptions}; -use sys::handle::Handle; -use sys::hashmap_random_keys; - -//////////////////////////////////////////////////////////////////////////////// -// Anonymous pipes -//////////////////////////////////////////////////////////////////////////////// - -pub struct AnonPipe { - inner: Handle, -} - -pub struct Pipes { - pub ours: AnonPipe, - pub theirs: AnonPipe, -} - -/// Although this looks similar to `anon_pipe` in the Unix module it's actually -/// subtly different. Here we'll return two pipes in the `Pipes` return value, -/// but one is intended for "us" where as the other is intended for "someone -/// else". -/// -/// Currently the only use case for this function is pipes for stdio on -/// processes in the standard library, so "ours" is the one that'll stay in our -/// process whereas "theirs" will be inherited to a child. -/// -/// The ours/theirs pipes are *not* specifically readable or writable. Each -/// one only supports a read or a write, but which is which depends on the -/// boolean flag given. If `ours_readable` is true then `ours` is readable where -/// `theirs` is writable. Conversely if `ours_readable` is false then `ours` is -/// writable where `theirs` is readable. -/// -/// Also note that the `ours` pipe is always a handle opened up in overlapped -/// mode. This means that technically speaking it should only ever be used -/// with `OVERLAPPED` instances, but also works out ok if it's only ever used -/// once at a time (which we do indeed guarantee). -pub fn anon_pipe(ours_readable: bool) -> io::Result { - // Note that we specifically do *not* use `CreatePipe` here because - // unfortunately the anonymous pipes returned do not support overlapped - // operations. Instead, we create a "hopefully unique" name and create a - // named pipe which has overlapped operations enabled. - // - // Once we do this, we connect do it as usual via `CreateFileW`, and then - // we return those reader/writer halves. Note that the `ours` pipe return - // value is always the named pipe, whereas `theirs` is just the normal file. - // This should hopefully shield us from child processes which assume their - // stdout is a named pipe, which would indeed be odd! - unsafe { - let ours; - let mut name; - let mut tries = 0; - let mut reject_remote_clients_flag = c::PIPE_REJECT_REMOTE_CLIENTS; - loop { - tries += 1; - name = format!(r"\\.\pipe\__rust_anonymous_pipe1__.{}.{}", - c::GetCurrentProcessId(), - random_number()); - let wide_name = OsStr::new(&name) - .encode_wide() - .chain(Some(0)) - .collect::>(); - let mut flags = c::FILE_FLAG_FIRST_PIPE_INSTANCE | - c::FILE_FLAG_OVERLAPPED; - if ours_readable { - flags |= c::PIPE_ACCESS_INBOUND; - } else { - flags |= c::PIPE_ACCESS_OUTBOUND; - } - - let handle = c::CreateNamedPipeW(wide_name.as_ptr(), - flags, - c::PIPE_TYPE_BYTE | - c::PIPE_READMODE_BYTE | - c::PIPE_WAIT | - reject_remote_clients_flag, - 1, - 4096, - 4096, - 0, - ptr::null_mut()); - - // We pass the FILE_FLAG_FIRST_PIPE_INSTANCE flag above, and we're - // also just doing a best effort at selecting a unique name. If - // ERROR_ACCESS_DENIED is returned then it could mean that we - // accidentally conflicted with an already existing pipe, so we try - // again. - // - // Don't try again too much though as this could also perhaps be a - // legit error. - // If ERROR_INVALID_PARAMETER is returned, this probably means we're - // running on pre-Vista version where PIPE_REJECT_REMOTE_CLIENTS is - // not supported, so we continue retrying without it. This implies - // reduced security on Windows versions older than Vista by allowing - // connections to this pipe from remote machines. - // Proper fix would increase the number of FFI imports and introduce - // significant amount of Windows XP specific code with no clean - // testing strategy - // for more info see https://github.com/rust-lang/rust/pull/37677 - if handle == c::INVALID_HANDLE_VALUE { - let err = io::Error::last_os_error(); - let raw_os_err = err.raw_os_error(); - if tries < 10 { - if raw_os_err == Some(c::ERROR_ACCESS_DENIED as i32) { - continue - } else if reject_remote_clients_flag != 0 && - raw_os_err == Some(c::ERROR_INVALID_PARAMETER as i32) { - reject_remote_clients_flag = 0; - tries -= 1; - continue - } - } - return Err(err) - } - ours = Handle::new(handle); - break - } - - // Connect to the named pipe we just created. This handle is going to be - // returned in `theirs`, so if `ours` is readable we want this to be - // writable, otherwise if `ours` is writable we want this to be - // readable. - // - // Additionally we don't enable overlapped mode on this because most - // client processes aren't enabled to work with that. - let mut opts = OpenOptions::new(); - opts.write(ours_readable); - opts.read(!ours_readable); - opts.share_mode(0); - let theirs = File::open(Path::new(&name), &opts)?; - let theirs = AnonPipe { inner: theirs.into_handle() }; - - Ok(Pipes { - ours: AnonPipe { inner: ours }, - theirs: AnonPipe { inner: theirs.into_handle() }, - }) - } -} - -fn random_number() -> usize { - static N: AtomicUsize = ATOMIC_USIZE_INIT; - loop { - if N.load(SeqCst) != 0 { - return N.fetch_add(1, SeqCst) - } - - N.store(hashmap_random_keys().0 as usize, SeqCst); - } -} - -impl AnonPipe { - pub fn handle(&self) -> &Handle { &self.inner } - pub fn into_handle(self) -> Handle { self.inner } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.inner.write(buf) - } -} - -pub fn read2(p1: AnonPipe, - v1: &mut Vec, - p2: AnonPipe, - v2: &mut Vec) -> io::Result<()> { - let p1 = p1.into_handle(); - let p2 = p2.into_handle(); - - let mut p1 = AsyncPipe::new(p1, v1)?; - let mut p2 = AsyncPipe::new(p2, v2)?; - let objs = [p1.event.raw(), p2.event.raw()]; - - // In a loop we wait for either pipe's scheduled read operation to complete. - // If the operation completes with 0 bytes, that means EOF was reached, in - // which case we just finish out the other pipe entirely. - // - // Note that overlapped I/O is in general super unsafe because we have to - // be careful to ensure that all pointers in play are valid for the entire - // duration of the I/O operation (where tons of operations can also fail). - // The destructor for `AsyncPipe` ends up taking care of most of this. - loop { - let res = unsafe { - c::WaitForMultipleObjects(2, objs.as_ptr(), c::FALSE, c::INFINITE) - }; - if res == c::WAIT_OBJECT_0 { - if !p1.result()? || !p1.schedule_read()? { - return p2.finish() - } - } else if res == c::WAIT_OBJECT_0 + 1 { - if !p2.result()? || !p2.schedule_read()? { - return p1.finish() - } - } else { - return Err(io::Error::last_os_error()) - } - } -} - -struct AsyncPipe<'a> { - pipe: Handle, - event: Handle, - overlapped: Box, // needs a stable address - dst: &'a mut Vec, - state: State, -} - -#[derive(PartialEq, Debug)] -enum State { - NotReading, - Reading, - Read(usize), -} - -impl<'a> AsyncPipe<'a> { - fn new(pipe: Handle, dst: &'a mut Vec) -> io::Result> { - // Create an event which we'll use to coordinate our overlapped - // operations, this event will be used in WaitForMultipleObjects - // and passed as part of the OVERLAPPED handle. - // - // Note that we do a somewhat clever thing here by flagging the - // event as being manually reset and setting it initially to the - // signaled state. This means that we'll naturally fall through the - // WaitForMultipleObjects call above for pipes created initially, - // and the only time an even will go back to "unset" will be once an - // I/O operation is successfully scheduled (what we want). - let event = Handle::new_event(true, true)?; - let mut overlapped: Box = unsafe { - Box::new(mem::zeroed()) - }; - overlapped.hEvent = event.raw(); - Ok(AsyncPipe { - pipe, - overlapped, - event, - dst, - state: State::NotReading, - }) - } - - /// Executes an overlapped read operation. - /// - /// Must not currently be reading, and returns whether the pipe is currently - /// at EOF or not. If the pipe is not at EOF then `result()` must be called - /// to complete the read later on (may block), but if the pipe is at EOF - /// then `result()` should not be called as it will just block forever. - fn schedule_read(&mut self) -> io::Result { - assert_eq!(self.state, State::NotReading); - let amt = unsafe { - let slice = slice_to_end(self.dst); - self.pipe.read_overlapped(slice, &mut *self.overlapped)? - }; - - // If this read finished immediately then our overlapped event will - // remain signaled (it was signaled coming in here) and we'll progress - // down to the method below. - // - // Otherwise the I/O operation is scheduled and the system set our event - // to not signaled, so we flag ourselves into the reading state and move - // on. - self.state = match amt { - Some(0) => return Ok(false), - Some(amt) => State::Read(amt), - None => State::Reading, - }; - Ok(true) - } - - /// Wait for the result of the overlapped operation previously executed. - /// - /// Takes a parameter `wait` which indicates if this pipe is currently being - /// read whether the function should block waiting for the read to complete. - /// - /// Return values: - /// - /// * `true` - finished any pending read and the pipe is not at EOF (keep - /// going) - /// * `false` - finished any pending read and pipe is at EOF (stop issuing - /// reads) - fn result(&mut self) -> io::Result { - let amt = match self.state { - State::NotReading => return Ok(true), - State::Reading => { - self.pipe.overlapped_result(&mut *self.overlapped, true)? - } - State::Read(amt) => amt, - }; - self.state = State::NotReading; - unsafe { - let len = self.dst.len(); - self.dst.set_len(len + amt); - } - Ok(amt != 0) - } - - /// Finishes out reading this pipe entirely. - /// - /// Waits for any pending and schedule read, and then calls `read_to_end` - /// if necessary to read all the remaining information. - fn finish(&mut self) -> io::Result<()> { - while self.result()? && self.schedule_read()? { - // ... - } - Ok(()) - } -} - -impl<'a> Drop for AsyncPipe<'a> { - fn drop(&mut self) { - match self.state { - State::Reading => {} - _ => return, - } - - // If we have a pending read operation, then we have to make sure that - // it's *done* before we actually drop this type. The kernel requires - // that the `OVERLAPPED` and buffer pointers are valid for the entire - // I/O operation. - // - // To do that, we call `CancelIo` to cancel any pending operation, and - // if that succeeds we wait for the overlapped result. - // - // If anything here fails, there's not really much we can do, so we leak - // the buffer/OVERLAPPED pointers to ensure we're at least memory safe. - if self.pipe.cancel_io().is_err() || self.result().is_err() { - let buf = mem::replace(self.dst, Vec::new()); - let overlapped = Box::new(unsafe { mem::zeroed() }); - let overlapped = mem::replace(&mut self.overlapped, overlapped); - mem::forget((buf, overlapped)); - } - } -} - -unsafe fn slice_to_end(v: &mut Vec) -> &mut [u8] { - if v.capacity() == 0 { - v.reserve(16); - } - if v.capacity() == v.len() { - v.reserve(1); - } - slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize), - v.capacity() - v.len()) -} diff --git a/ctr-std/src/sys/windows/process.rs b/ctr-std/src/sys/windows/process.rs deleted file mode 100644 index 4974a8d..0000000 --- a/ctr-std/src/sys/windows/process.rs +++ /dev/null @@ -1,581 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "process_internals", issue = "0")] - -use collections::BTreeMap; -use env::split_paths; -use env; -use ffi::{OsString, OsStr}; -use fmt; -use fs; -use io::{self, Error, ErrorKind}; -use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE}; -use mem; -use os::windows::ffi::OsStrExt; -use path::Path; -use ptr; -use sys::mutex::Mutex; -use sys::c; -use sys::fs::{OpenOptions, File}; -use sys::handle::Handle; -use sys::pipe::{self, AnonPipe}; -use sys::stdio; -use sys::cvt; -use sys_common::{AsInner, FromInner, IntoInner}; -use sys_common::process::{CommandEnv, EnvKey}; -use borrow::Borrow; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] -#[doc(hidden)] -pub struct WindowsEnvKey(OsString); - -impl From for WindowsEnvKey { - fn from(k: OsString) -> Self { - let mut buf = k.into_inner().into_inner(); - buf.make_ascii_uppercase(); - WindowsEnvKey(FromInner::from_inner(FromInner::from_inner(buf))) - } -} - -impl From for OsString { - fn from(k: WindowsEnvKey) -> Self { k.0 } -} - -impl Borrow for WindowsEnvKey { - fn borrow(&self) -> &OsStr { &self.0 } -} - -impl AsRef for WindowsEnvKey { - fn as_ref(&self) -> &OsStr { &self.0 } -} - -impl EnvKey for WindowsEnvKey {} - - -fn ensure_no_nuls>(str: T) -> io::Result { - if str.as_ref().encode_wide().any(|b| b == 0) { - Err(io::Error::new(ErrorKind::InvalidInput, "nul byte found in provided data")) - } else { - Ok(str) - } -} - -pub struct Command { - program: OsString, - args: Vec, - env: CommandEnv, - cwd: Option, - flags: u32, - detach: bool, // not currently exposed in std::process - stdin: Option, - stdout: Option, - stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, - Handle(Handle), -} - -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -struct DropGuard<'a> { - lock: &'a Mutex, -} - -impl Command { - pub fn new(program: &OsStr) -> Command { - Command { - program: program.to_os_string(), - args: Vec::new(), - env: Default::default(), - cwd: None, - flags: 0, - detach: false, - stdin: None, - stdout: None, - stderr: None, - } - } - - pub fn arg(&mut self, arg: &OsStr) { - self.args.push(arg.to_os_string()) - } - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(dir.to_os_string()) - } - pub fn stdin(&mut self, stdin: Stdio) { - self.stdin = Some(stdin); - } - pub fn stdout(&mut self, stdout: Stdio) { - self.stdout = Some(stdout); - } - pub fn stderr(&mut self, stderr: Stdio) { - self.stderr = Some(stderr); - } - pub fn creation_flags(&mut self, flags: u32) { - self.flags = flags; - } - - pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) - -> io::Result<(Process, StdioPipes)> { - let maybe_env = self.env.capture_if_changed(); - // To have the spawning semantics of unix/windows stay the same, we need - // to read the *child's* PATH if one is provided. See #15149 for more - // details. - let program = maybe_env.as_ref().and_then(|env| { - if let Some(v) = env.get(OsStr::new("PATH")) { - // Split the value and test each path to see if the - // program exists. - for path in split_paths(&v) { - let path = path.join(self.program.to_str().unwrap()) - .with_extension(env::consts::EXE_EXTENSION); - if fs::metadata(&path).is_ok() { - return Some(path.into_os_string()) - } - } - } - None - }); - - let mut si = zeroed_startupinfo(); - si.cb = mem::size_of::() as c::DWORD; - si.dwFlags = c::STARTF_USESTDHANDLES; - - let program = program.as_ref().unwrap_or(&self.program); - let mut cmd_str = make_command_line(program, &self.args)?; - cmd_str.push(0); // add null terminator - - // stolen from the libuv code. - let mut flags = self.flags | c::CREATE_UNICODE_ENVIRONMENT; - if self.detach { - flags |= c::DETACHED_PROCESS | c::CREATE_NEW_PROCESS_GROUP; - } - - let (envp, _data) = make_envp(maybe_env)?; - let (dirp, _data) = make_dirp(self.cwd.as_ref())?; - let mut pi = zeroed_process_information(); - - // Prepare all stdio handles to be inherited by the child. This - // currently involves duplicating any existing ones with the ability to - // be inherited by child processes. Note, however, that once an - // inheritable handle is created, *any* spawned child will inherit that - // handle. We only want our own child to inherit this handle, so we wrap - // the remaining portion of this spawn in a mutex. - // - // For more information, msdn also has an article about this race: - // http://support.microsoft.com/kb/315939 - static CREATE_PROCESS_LOCK: Mutex = Mutex::new(); - let _guard = DropGuard::new(&CREATE_PROCESS_LOCK); - - let mut pipes = StdioPipes { - stdin: None, - stdout: None, - stderr: None, - }; - let null = Stdio::Null; - let default_stdin = if needs_stdin {&default} else {&null}; - let stdin = self.stdin.as_ref().unwrap_or(default_stdin); - let stdout = self.stdout.as_ref().unwrap_or(&default); - let stderr = self.stderr.as_ref().unwrap_or(&default); - let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?; - let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, - &mut pipes.stdout)?; - let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, - &mut pipes.stderr)?; - si.hStdInput = stdin.raw(); - si.hStdOutput = stdout.raw(); - si.hStdError = stderr.raw(); - - unsafe { - cvt(c::CreateProcessW(ptr::null(), - cmd_str.as_mut_ptr(), - ptr::null_mut(), - ptr::null_mut(), - c::TRUE, flags, envp, dirp, - &mut si, &mut pi)) - }?; - - // We close the thread handle because we don't care about keeping - // the thread id valid, and we aren't keeping the thread handle - // around to be able to close it later. - drop(Handle::new(pi.hThread)); - - Ok((Process { handle: Handle::new(pi.hProcess) }, pipes)) - } - -} - -impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.program)?; - for arg in &self.args { - write!(f, " {:?}", arg)?; - } - Ok(()) - } -} - -impl<'a> DropGuard<'a> { - fn new(lock: &'a Mutex) -> DropGuard<'a> { - unsafe { - lock.lock(); - DropGuard { lock: lock } - } - } -} - -impl<'a> Drop for DropGuard<'a> { - fn drop(&mut self) { - unsafe { - self.lock.unlock(); - } - } -} - -impl Stdio { - fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option) - -> io::Result { - match *self { - // If no stdio handle is available, then inherit means that it - // should still be unavailable so propagate the - // INVALID_HANDLE_VALUE. - Stdio::Inherit => { - match stdio::get(stdio_id) { - Ok(io) => { - let io = Handle::new(io.handle()); - let ret = io.duplicate(0, true, - c::DUPLICATE_SAME_ACCESS); - io.into_raw(); - return ret - } - Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)), - } - } - - Stdio::MakePipe => { - let ours_readable = stdio_id != c::STD_INPUT_HANDLE; - let pipes = pipe::anon_pipe(ours_readable)?; - *pipe = Some(pipes.ours); - cvt(unsafe { - c::SetHandleInformation(pipes.theirs.handle().raw(), - c::HANDLE_FLAG_INHERIT, - c::HANDLE_FLAG_INHERIT) - })?; - Ok(pipes.theirs.into_handle()) - } - - Stdio::Handle(ref handle) => { - handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS) - } - - // Open up a reference to NUL with appropriate read/write - // permissions as well as the ability to be inherited to child - // processes (as this is about to be inherited). - Stdio::Null => { - let size = mem::size_of::(); - let mut sa = c::SECURITY_ATTRIBUTES { - nLength: size as c::DWORD, - lpSecurityDescriptor: ptr::null_mut(), - bInheritHandle: 1, - }; - let mut opts = OpenOptions::new(); - opts.read(stdio_id == c::STD_INPUT_HANDLE); - opts.write(stdio_id != c::STD_INPUT_HANDLE); - opts.security_attributes(&mut sa); - File::open(Path::new("NUL"), &opts).map(|file| { - file.into_handle() - }) - } - } - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - Stdio::Handle(pipe.into_handle()) - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - Stdio::Handle(file.into_handle()) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Processes -//////////////////////////////////////////////////////////////////////////////// - -/// A value representing a child process. -/// -/// The lifetime of this value is linked to the lifetime of the actual -/// process - the Process destructor calls self.finish() which waits -/// for the process to terminate. -pub struct Process { - handle: Handle, -} - -impl Process { - pub fn kill(&mut self) -> io::Result<()> { - cvt(unsafe { - c::TerminateProcess(self.handle.raw(), 1) - })?; - Ok(()) - } - - pub fn id(&self) -> u32 { - unsafe { - c::GetProcessId(self.handle.raw()) as u32 - } - } - - pub fn wait(&mut self) -> io::Result { - unsafe { - let res = c::WaitForSingleObject(self.handle.raw(), c::INFINITE); - if res != c::WAIT_OBJECT_0 { - return Err(Error::last_os_error()) - } - let mut status = 0; - cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?; - Ok(ExitStatus(status)) - } - } - - pub fn try_wait(&mut self) -> io::Result> { - unsafe { - match c::WaitForSingleObject(self.handle.raw(), 0) { - c::WAIT_OBJECT_0 => {} - c::WAIT_TIMEOUT => { - return Ok(None); - } - _ => return Err(io::Error::last_os_error()), - } - let mut status = 0; - cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?; - Ok(Some(ExitStatus(status))) - } - } - - pub fn handle(&self) -> &Handle { &self.handle } - - pub fn into_handle(self) -> Handle { self.handle } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatus(c::DWORD); - -impl ExitStatus { - pub fn success(&self) -> bool { - self.0 == 0 - } - pub fn code(&self) -> Option { - Some(self.0 as i32) - } -} - -impl From for ExitStatus { - fn from(u: c::DWORD) -> ExitStatus { - ExitStatus(u) - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "exit code: {}", self.0) - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(c::DWORD); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); - pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); - - #[inline] - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -fn zeroed_startupinfo() -> c::STARTUPINFO { - c::STARTUPINFO { - cb: 0, - lpReserved: ptr::null_mut(), - lpDesktop: ptr::null_mut(), - lpTitle: ptr::null_mut(), - dwX: 0, - dwY: 0, - dwXSize: 0, - dwYSize: 0, - dwXCountChars: 0, - dwYCountCharts: 0, - dwFillAttribute: 0, - dwFlags: 0, - wShowWindow: 0, - cbReserved2: 0, - lpReserved2: ptr::null_mut(), - hStdInput: c::INVALID_HANDLE_VALUE, - hStdOutput: c::INVALID_HANDLE_VALUE, - hStdError: c::INVALID_HANDLE_VALUE, - } -} - -fn zeroed_process_information() -> c::PROCESS_INFORMATION { - c::PROCESS_INFORMATION { - hProcess: ptr::null_mut(), - hThread: ptr::null_mut(), - dwProcessId: 0, - dwThreadId: 0 - } -} - -// Produces a wide string *without terminating null*; returns an error if -// `prog` or any of the `args` contain a nul. -fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result> { - // Encode the command and arguments in a command line string such - // that the spawned process may recover them using CommandLineToArgvW. - let mut cmd: Vec = Vec::new(); - // Always quote the program name so CreateProcess doesn't interpret args as - // part of the name if the binary wasn't found first time. - append_arg(&mut cmd, prog, true)?; - for arg in args { - cmd.push(' ' as u16); - append_arg(&mut cmd, arg, false)?; - } - return Ok(cmd); - - fn append_arg(cmd: &mut Vec, arg: &OsStr, force_quotes: bool) -> io::Result<()> { - // If an argument has 0 characters then we need to quote it to ensure - // that it actually gets passed through on the command line or otherwise - // it will be dropped entirely when parsed on the other end. - ensure_no_nuls(arg)?; - let arg_bytes = &arg.as_inner().inner.as_inner(); - let quote = force_quotes || arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') - || arg_bytes.is_empty(); - if quote { - cmd.push('"' as u16); - } - - let mut iter = arg.encode_wide(); - let mut backslashes: usize = 0; - while let Some(x) = iter.next() { - if x == '\\' as u16 { - backslashes += 1; - } else { - if x == '"' as u16 { - // Add n+1 backslashes to total 2n+1 before internal '"'. - cmd.extend((0..(backslashes + 1)).map(|_| '\\' as u16)); - } - backslashes = 0; - } - cmd.push(x); - } - - if quote { - // Add n backslashes to total 2n before ending '"'. - cmd.extend((0..backslashes).map(|_| '\\' as u16)); - cmd.push('"' as u16); - } - Ok(()) - } -} - -fn make_envp(maybe_env: Option>) - -> io::Result<(*mut c_void, Vec)> { - // On Windows we pass an "environment block" which is not a char**, but - // rather a concatenation of null-terminated k=v\0 sequences, with a final - // \0 to terminate. - if let Some(env) = maybe_env { - let mut blk = Vec::new(); - - for (k, v) in env { - blk.extend(ensure_no_nuls(k.0)?.encode_wide()); - blk.push('=' as u16); - blk.extend(ensure_no_nuls(v)?.encode_wide()); - blk.push(0); - } - blk.push(0); - Ok((blk.as_mut_ptr() as *mut c_void, blk)) - } else { - Ok((ptr::null_mut(), Vec::new())) - } -} - -fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec)> { - - match d { - Some(dir) => { - let mut dir_str: Vec = ensure_no_nuls(dir)?.encode_wide().collect(); - dir_str.push(0); - Ok((dir_str.as_ptr(), dir_str)) - }, - None => Ok((ptr::null(), Vec::new())) - } -} - -#[cfg(test)] -mod tests { - use ffi::{OsStr, OsString}; - use super::make_command_line; - - #[test] - fn test_make_command_line() { - fn test_wrapper(prog: &str, args: &[&str]) -> String { - let command_line = &make_command_line(OsStr::new(prog), - &args.iter() - .map(|a| OsString::from(a)) - .collect::>()) - .unwrap(); - String::from_utf16(command_line).unwrap() - } - - assert_eq!( - test_wrapper("prog", &["aaa", "bbb", "ccc"]), - "\"prog\" aaa bbb ccc" - ); - - assert_eq!( - test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]), - "\"C:\\Program Files\\blah\\blah.exe\" aaa" - ); - assert_eq!( - test_wrapper("C:\\Program Files\\test", &["aa\"bb"]), - "\"C:\\Program Files\\test\" aa\\\"bb" - ); - assert_eq!( - test_wrapper("echo", &["a b c"]), - "\"echo\" \"a b c\"" - ); - assert_eq!( - test_wrapper("echo", &["\" \\\" \\", "\\"]), - "\"echo\" \"\\\" \\\\\\\" \\\\\" \\" - ); - assert_eq!( - test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]), - "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\"" - ); - } -} diff --git a/ctr-std/src/sys/windows/rand.rs b/ctr-std/src/sys/windows/rand.rs deleted file mode 100644 index 2623236..0000000 --- a/ctr-std/src/sys/windows/rand.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use io; -use mem; -use sys::c; - -pub fn hashmap_random_keys() -> (u64, u64) { - let mut v = (0, 0); - let ret = unsafe { - c::RtlGenRandom(&mut v as *mut _ as *mut u8, - mem::size_of_val(&v) as c::ULONG) - }; - if ret == 0 { - panic!("couldn't generate random bytes: {}", - io::Error::last_os_error()); - } - return v -} diff --git a/ctr-std/src/sys/windows/rwlock.rs b/ctr-std/src/sys/windows/rwlock.rs deleted file mode 100644 index 3e81ebf..0000000 --- a/ctr-std/src/sys/windows/rwlock.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cell::UnsafeCell; -use sys::c; - -pub struct RWLock { inner: UnsafeCell } - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { inner: UnsafeCell::new(c::SRWLOCK_INIT) } - } - #[inline] - pub unsafe fn read(&self) { - c::AcquireSRWLockShared(self.inner.get()) - } - #[inline] - pub unsafe fn try_read(&self) -> bool { - c::TryAcquireSRWLockShared(self.inner.get()) != 0 - } - #[inline] - pub unsafe fn write(&self) { - c::AcquireSRWLockExclusive(self.inner.get()) - } - #[inline] - pub unsafe fn try_write(&self) -> bool { - c::TryAcquireSRWLockExclusive(self.inner.get()) != 0 - } - #[inline] - pub unsafe fn read_unlock(&self) { - c::ReleaseSRWLockShared(self.inner.get()) - } - #[inline] - pub unsafe fn write_unlock(&self) { - c::ReleaseSRWLockExclusive(self.inner.get()) - } - - #[inline] - pub unsafe fn destroy(&self) { - // ... - } -} diff --git a/ctr-std/src/sys/windows/stack_overflow.rs b/ctr-std/src/sys/windows/stack_overflow.rs deleted file mode 100644 index 4a406d7..0000000 --- a/ctr-std/src/sys/windows/stack_overflow.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg_attr(test, allow(dead_code))] - -use sys_common::util::report_overflow; -use sys::c; - -pub struct Handler; - -impl Handler { - pub unsafe fn new() -> Handler { - // This API isn't available on XP, so don't panic in that case and just - // pray it works out ok. - if c::SetThreadStackGuarantee(&mut 0x5000) == 0 { - if c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32 { - panic!("failed to reserve stack space for exception handling"); - } - } - Handler - } -} - -extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) - -> c::LONG { - unsafe { - let rec = &(*(*ExceptionInfo).ExceptionRecord); - let code = rec.ExceptionCode; - - if code == c::EXCEPTION_STACK_OVERFLOW { - report_overflow(); - } - c::EXCEPTION_CONTINUE_SEARCH - } -} - -pub unsafe fn init() { - if c::AddVectoredExceptionHandler(0, vectored_handler).is_null() { - panic!("failed to install exception handler"); - } - // Set the thread stack guarantee for the main thread. - let _h = Handler::new(); -} - -pub unsafe fn cleanup() {} diff --git a/ctr-std/src/sys/windows/stdio.rs b/ctr-std/src/sys/windows/stdio.rs deleted file mode 100644 index 81b89da..0000000 --- a/ctr-std/src/sys/windows/stdio.rs +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(issue = "0", feature = "windows_stdio")] - -use io::prelude::*; - -use cmp; -use io::{self, Cursor}; -use ptr; -use str; -use sync::Mutex; -use sys::c; -use sys::cvt; -use sys::handle::Handle; - -pub enum Output { - Console(c::HANDLE), - Pipe(c::HANDLE), -} - -pub struct Stdin { - utf8: Mutex>>, -} -pub struct Stdout; -pub struct Stderr; - -pub fn get(handle: c::DWORD) -> io::Result { - let handle = unsafe { c::GetStdHandle(handle) }; - if handle == c::INVALID_HANDLE_VALUE { - Err(io::Error::last_os_error()) - } else if handle.is_null() { - Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32)) - } else { - let mut out = 0; - match unsafe { c::GetConsoleMode(handle, &mut out) } { - 0 => Ok(Output::Pipe(handle)), - _ => Ok(Output::Console(handle)), - } - } -} - -fn write(handle: c::DWORD, data: &[u8]) -> io::Result { - let handle = match try!(get(handle)) { - Output::Console(c) => c, - Output::Pipe(p) => { - let handle = Handle::new(p); - let ret = handle.write(data); - handle.into_raw(); - return ret - } - }; - - // As with stdin on windows, stdout often can't handle writes of large - // sizes. For an example, see #14940. For this reason, don't try to - // write the entire output buffer on windows. - // - // For some other references, it appears that this problem has been - // encountered by others [1] [2]. We choose the number 8K just because - // libuv does the same. - // - // [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232 - // [2]: http://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html - const OUT_MAX: usize = 8192; - let len = cmp::min(data.len(), OUT_MAX); - let utf8 = match str::from_utf8(&data[..len]) { - Ok(s) => s, - Err(ref e) if e.valid_up_to() == 0 => return Err(invalid_encoding()), - Err(e) => str::from_utf8(&data[..e.valid_up_to()]).unwrap(), - }; - let utf16 = utf8.encode_utf16().collect::>(); - let mut written = 0; - cvt(unsafe { - c::WriteConsoleW(handle, - utf16.as_ptr() as c::LPCVOID, - utf16.len() as u32, - &mut written, - ptr::null_mut()) - })?; - - // FIXME if this only partially writes the utf16 buffer then we need to - // figure out how many bytes of `data` were actually written - assert_eq!(written as usize, utf16.len()); - Ok(utf8.len()) -} - -impl Stdin { - pub fn new() -> io::Result { - Ok(Stdin { - utf8: Mutex::new(Cursor::new(Vec::new())), - }) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - let handle = match try!(get(c::STD_INPUT_HANDLE)) { - Output::Console(c) => c, - Output::Pipe(p) => { - let handle = Handle::new(p); - let ret = handle.read(buf); - handle.into_raw(); - return ret - } - }; - let mut utf8 = self.utf8.lock().unwrap(); - // Read more if the buffer is empty - if utf8.position() as usize == utf8.get_ref().len() { - let mut utf16 = vec![0u16; 0x1000]; - let mut num = 0; - let mut input_control = readconsole_input_control(CTRL_Z_MASK); - cvt(unsafe { - c::ReadConsoleW(handle, - utf16.as_mut_ptr() as c::LPVOID, - utf16.len() as u32, - &mut num, - &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL) - })?; - utf16.truncate(num as usize); - // FIXME: what to do about this data that has already been read? - let mut data = match String::from_utf16(&utf16) { - Ok(utf8) => utf8.into_bytes(), - Err(..) => return Err(invalid_encoding()), - }; - if let Some(&last_byte) = data.last() { - if last_byte == CTRL_Z { - data.pop(); - } - } - *utf8 = Cursor::new(data); - } - - // MemReader shouldn't error here since we just filled it - utf8.read(buf) - } - - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - let mut me = self; - (&mut me).read_to_end(buf) - } -} - -#[unstable(reason = "not public", issue = "0", feature = "fd_read")] -impl<'a> Read for &'a Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (**self).read(buf) - } -} - -impl Stdout { - pub fn new() -> io::Result { - Ok(Stdout) - } - - pub fn write(&self, data: &[u8]) -> io::Result { - write(c::STD_OUTPUT_HANDLE, data) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub fn new() -> io::Result { - Ok(Stderr) - } - - pub fn write(&self, data: &[u8]) -> io::Result { - write(c::STD_ERROR_HANDLE, data) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } -} - -// FIXME: right now this raw stderr handle is used in a few places because -// std::io::stderr_raw isn't exposed, but once that's exposed this impl -// should go away -impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result { - Stderr::write(self, data) - } - - fn flush(&mut self) -> io::Result<()> { - Stderr::flush(self) - } -} - -impl Output { - pub fn handle(&self) -> c::HANDLE { - match *self { - Output::Console(c) => c, - Output::Pipe(c) => c, - } - } -} - -fn invalid_encoding() -> io::Error { - io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode") -} - -fn readconsole_input_control(wakeup_mask: c::ULONG) -> c::CONSOLE_READCONSOLE_CONTROL { - c::CONSOLE_READCONSOLE_CONTROL { - nLength: ::mem::size_of::() as c::ULONG, - nInitialChars: 0, - dwCtrlWakeupMask: wakeup_mask, - dwControlKeyState: 0, - } -} - -const CTRL_Z: u8 = 0x1A; -const CTRL_Z_MASK: c::ULONG = 0x4000000; //1 << 0x1A - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32) -} - -// The default buffer capacity is 64k, but apparently windows -// doesn't like 64k reads on stdin. See #13304 for details, but the -// idea is that on windows we use a slightly smaller buffer that's -// been seen to be acceptable. -pub const STDIN_BUF_SIZE: usize = 8 * 1024; - -pub fn stderr_prints_nothing() -> bool { - false -} diff --git a/ctr-std/src/sys/windows/thread.rs b/ctr-std/src/sys/windows/thread.rs deleted file mode 100644 index 85588cc..0000000 --- a/ctr-std/src/sys/windows/thread.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use boxed::FnBox; -use io; -use ffi::CStr; -use mem; -use libc::c_void; -use ptr; -use sys::c; -use sys::handle::Handle; -use sys_common::thread::*; -use time::Duration; - -use super::to_u16s; - -pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; - -pub struct Thread { - handle: Handle -} - -impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box) - -> io::Result { - let p = box p; - - // FIXME On UNIX, we guard against stack sizes that are too small but - // that's because pthreads enforces that stacks are at least - // PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's - // just that below a certain threshold you can't do anything useful. - // That threshold is application and architecture-specific, however. - // Round up to the next 64 kB because that's what the NT kernel does, - // might as well make it explicit. - let stack_size = (stack + 0xfffe) & (!0xfffe); - let ret = c::CreateThread(ptr::null_mut(), stack_size, - thread_start, &*p as *const _ as *mut _, - c::STACK_SIZE_PARAM_IS_A_RESERVATION, - ptr::null_mut()); - - return if ret as usize == 0 { - Err(io::Error::last_os_error()) - } else { - mem::forget(p); // ownership passed to CreateThread - Ok(Thread { handle: Handle::new(ret) }) - }; - - extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { - unsafe { start_thread(main as *mut u8); } - 0 - } - } - - pub fn set_name(name: &CStr) { - if let Ok(utf8) = name.to_str() { - if let Ok(utf16) = to_u16s(utf8) { - unsafe { c::SetThreadDescription(c::GetCurrentThread(), utf16.as_ptr()); }; - }; - }; - } - - pub fn join(self) { - let rc = unsafe { c::WaitForSingleObject(self.handle.raw(), c::INFINITE) }; - if rc == c::WAIT_FAILED { - panic!("failed to join on thread: {}", - io::Error::last_os_error()); - } - } - - pub fn yield_now() { - // This function will return 0 if there are no other threads to execute, - // but this also means that the yield was useless so this isn't really a - // case that needs to be worried about. - unsafe { c::SwitchToThread(); } - } - - pub fn sleep(dur: Duration) { - unsafe { - c::Sleep(super::dur2timeout(dur)) - } - } - - pub fn handle(&self) -> &Handle { &self.handle } - - pub fn into_handle(self) -> Handle { self.handle } -} - -#[cfg_attr(test, allow(dead_code))] -pub mod guard { - pub type Guard = !; - pub unsafe fn current() -> Option { None } - pub unsafe fn init() -> Option { None } - pub unsafe fn deinit() {} -} diff --git a/ctr-std/src/sys/windows/thread_local.rs b/ctr-std/src/sys/windows/thread_local.rs deleted file mode 100644 index cdad320..0000000 --- a/ctr-std/src/sys/windows/thread_local.rs +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use mem; -use ptr; -use sync::atomic::AtomicPtr; -use sync::atomic::Ordering::SeqCst; -use sys::c; - -pub type Key = c::DWORD; -pub type Dtor = unsafe extern fn(*mut u8); - -// Turns out, like pretty much everything, Windows is pretty close the -// functionality that Unix provides, but slightly different! In the case of -// TLS, Windows does not provide an API to provide a destructor for a TLS -// variable. This ends up being pretty crucial to this implementation, so we -// need a way around this. -// -// The solution here ended up being a little obscure, but fear not, the -// internet has informed me [1][2] that this solution is not unique (no way -// I could have thought of it as well!). The key idea is to insert some hook -// somewhere to run arbitrary code on thread termination. With this in place -// we'll be able to run anything we like, including all TLS destructors! -// -// To accomplish this feat, we perform a number of threads, all contained -// within this module: -// -// * All TLS destructors are tracked by *us*, not the windows runtime. This -// means that we have a global list of destructors for each TLS key that -// we know about. -// * When a thread exits, we run over the entire list and run dtors for all -// non-null keys. This attempts to match Unix semantics in this regard. -// -// This ends up having the overhead of using a global list, having some -// locks here and there, and in general just adding some more code bloat. We -// attempt to optimize runtime by forgetting keys that don't have -// destructors, but this only gets us so far. -// -// For more details and nitty-gritty, see the code sections below! -// -// [1]: http://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way -// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base -// /threading/thread_local_storage_win.cc#L42 - -// ------------------------------------------------------------------------- -// Native bindings -// -// This section is just raw bindings to the native functions that Windows -// provides, There's a few extra calls to deal with destructors. - -#[inline] -pub unsafe fn create(dtor: Option) -> Key { - let key = c::TlsAlloc(); - assert!(key != c::TLS_OUT_OF_INDEXES); - if let Some(f) = dtor { - register_dtor(key, f); - } - return key; -} - -#[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - let r = c::TlsSetValue(key, value as c::LPVOID); - debug_assert!(r != 0); -} - -#[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - c::TlsGetValue(key) as *mut u8 -} - -#[inline] -pub unsafe fn destroy(_key: Key) { - rtabort!("can't destroy tls keys on windows") -} - -#[inline] -pub fn requires_synchronized_create() -> bool { - true -} - -// ------------------------------------------------------------------------- -// Dtor registration -// -// Windows has no native support for running destructors so we manage our own -// list of destructors to keep track of how to destroy keys. We then install a -// callback later to get invoked whenever a thread exits, running all -// appropriate destructors. -// -// Currently unregistration from this list is not supported. A destructor can be -// registered but cannot be unregistered. There's various simplifying reasons -// for doing this, the big ones being: -// -// 1. Currently we don't even support deallocating TLS keys, so normal operation -// doesn't need to deallocate a destructor. -// 2. There is no point in time where we know we can unregister a destructor -// because it could always be getting run by some remote thread. -// -// Typically processes have a statically known set of TLS keys which is pretty -// small, and we'd want to keep this memory alive for the whole process anyway -// really. -// -// Perhaps one day we can fold the `Box` here into a static allocation, -// expanding the `StaticKey` structure to contain not only a slot for the TLS -// key but also a slot for the destructor queue on windows. An optimization for -// another day! - -static DTORS: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - -struct Node { - dtor: Dtor, - key: Key, - next: *mut Node, -} - -unsafe fn register_dtor(key: Key, dtor: Dtor) { - let mut node = Box::new(Node { - key, - dtor, - next: ptr::null_mut(), - }); - - let mut head = DTORS.load(SeqCst); - loop { - node.next = head; - match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) { - Ok(_) => return mem::forget(node), - Err(cur) => head = cur, - } - } -} - -// ------------------------------------------------------------------------- -// Where the Magic (TM) Happens -// -// If you're looking at this code, and wondering "what is this doing?", -// you're not alone! I'll try to break this down step by step: -// -// # What's up with CRT$XLB? -// -// For anything about TLS destructors to work on Windows, we have to be able -// to run *something* when a thread exits. To do so, we place a very special -// static in a very special location. If this is encoded in just the right -// way, the kernel's loader is apparently nice enough to run some function -// of ours whenever a thread exits! How nice of the kernel! -// -// Lots of detailed information can be found in source [1] above, but the -// gist of it is that this is leveraging a feature of Microsoft's PE format -// (executable format) which is not actually used by any compilers today. -// This apparently translates to any callbacks in the ".CRT$XLB" section -// being run on certain events. -// -// So after all that, we use the compiler's #[link_section] feature to place -// a callback pointer into the magic section so it ends up being called. -// -// # What's up with this callback? -// -// The callback specified receives a number of parameters from... someone! -// (the kernel? the runtime? I'm not quite sure!) There are a few events that -// this gets invoked for, but we're currently only interested on when a -// thread or a process "detaches" (exits). The process part happens for the -// last thread and the thread part happens for any normal thread. -// -// # Ok, what's up with running all these destructors? -// -// This will likely need to be improved over time, but this function -// attempts a "poor man's" destructor callback system. Once we've got a list -// of what to run, we iterate over all keys, check their values, and then run -// destructors if the values turn out to be non null (setting them to null just -// beforehand). We do this a few times in a loop to basically match Unix -// semantics. If we don't reach a fixed point after a short while then we just -// inevitably leak something most likely. -// -// # The article mentions weird stuff about "/INCLUDE"? -// -// It sure does! Specifically we're talking about this quote: -// -// The Microsoft run-time library facilitates this process by defining a -// memory image of the TLS Directory and giving it the special name -// “__tls_used” (Intel x86 platforms) or “_tls_used” (other platforms). The -// linker looks for this memory image and uses the data there to create the -// TLS Directory. Other compilers that support TLS and work with the -// Microsoft linker must use this same technique. -// -// Basically what this means is that if we want support for our TLS -// destructors/our hook being called then we need to make sure the linker does -// not omit this symbol. Otherwise it will omit it and our callback won't be -// wired up. -// -// We don't actually use the `/INCLUDE` linker flag here like the article -// mentions because the Rust compiler doesn't propagate linker flags, but -// instead we use a shim function which performs a volatile 1-byte load from -// the address of the symbol to ensure it sticks around. - -#[link_section = ".CRT$XLB"] -#[allow(dead_code, unused_variables)] -#[used] // we don't want LLVM eliminating this symbol for any reason, and - // when the symbol makes it to the linker the linker will take over -pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, - c::LPVOID) = - on_tls_callback; - -#[allow(dead_code, unused_variables)] -unsafe extern "system" fn on_tls_callback(h: c::LPVOID, - dwReason: c::DWORD, - pv: c::LPVOID) { - if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH { - run_dtors(); - } - - // See comments above for what this is doing. Note that we don't need this - // trickery on GNU windows, just on MSVC. - reference_tls_used(); - #[cfg(target_env = "msvc")] - unsafe fn reference_tls_used() { - extern { static _tls_used: u8; } - ::intrinsics::volatile_load(&_tls_used); - } - #[cfg(not(target_env = "msvc"))] - unsafe fn reference_tls_used() {} -} - -#[allow(dead_code)] // actually called above -unsafe fn run_dtors() { - let mut any_run = true; - for _ in 0..5 { - if !any_run { - break - } - any_run = false; - let mut cur = DTORS.load(SeqCst); - while !cur.is_null() { - let ptr = c::TlsGetValue((*cur).key); - - if !ptr.is_null() { - c::TlsSetValue((*cur).key, ptr::null_mut()); - ((*cur).dtor)(ptr as *mut _); - any_run = true; - } - - cur = (*cur).next; - } - } -} diff --git a/ctr-std/src/sys/windows/time.rs b/ctr-std/src/sys/windows/time.rs deleted file mode 100644 index 07e64d3..0000000 --- a/ctr-std/src/sys/windows/time.rs +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cmp::Ordering; -use fmt; -use mem; -use sync::Once; -use sys::c; -use sys::cvt; -use sys_common::mul_div_u64; -use time::Duration; -use convert::TryInto; -use core::hash::{Hash, Hasher}; - -const NANOS_PER_SEC: u64 = 1_000_000_000; -const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100; - -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] -pub struct Instant { - t: c::LARGE_INTEGER, -} - -#[derive(Copy, Clone)] -pub struct SystemTime { - t: c::FILETIME, -} - -const INTERVALS_TO_UNIX_EPOCH: u64 = 11_644_473_600 * INTERVALS_PER_SEC; - -pub const UNIX_EPOCH: SystemTime = SystemTime { - t: c::FILETIME { - dwLowDateTime: INTERVALS_TO_UNIX_EPOCH as u32, - dwHighDateTime: (INTERVALS_TO_UNIX_EPOCH >> 32) as u32, - }, -}; - -impl Instant { - pub fn now() -> Instant { - let mut t = Instant { t: 0 }; - cvt(unsafe { - c::QueryPerformanceCounter(&mut t.t) - }).unwrap(); - t - } - - pub fn sub_instant(&self, other: &Instant) -> Duration { - // Values which are +- 1 need to be considered as basically the same - // units in time due to various measurement oddities, according to - // Windows [1] - // - // [1]: - // https://msdn.microsoft.com/en-us/library/windows/desktop - // /dn553408%28v=vs.85%29.aspx#guidance - if other.t > self.t && other.t - self.t == 1 { - return Duration::new(0, 0) - } - let diff = (self.t as u64).checked_sub(other.t as u64) - .expect("specified instant was later than \ - self"); - let nanos = mul_div_u64(diff, NANOS_PER_SEC, frequency() as u64); - Duration::new(nanos / NANOS_PER_SEC, (nanos % NANOS_PER_SEC) as u32) - } - - pub fn add_duration(&self, other: &Duration) -> Instant { - let freq = frequency() as u64; - let t = other.as_secs().checked_mul(freq).and_then(|i| { - (self.t as u64).checked_add(i) - }).and_then(|i| { - i.checked_add(mul_div_u64(other.subsec_nanos() as u64, freq, - NANOS_PER_SEC)) - }).expect("overflow when adding duration to time"); - Instant { - t: t as c::LARGE_INTEGER, - } - } - - pub fn sub_duration(&self, other: &Duration) -> Instant { - let freq = frequency() as u64; - let t = other.as_secs().checked_mul(freq).and_then(|i| { - (self.t as u64).checked_sub(i) - }).and_then(|i| { - i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, - NANOS_PER_SEC)) - }).expect("overflow when subtracting duration from time"); - Instant { - t: t as c::LARGE_INTEGER, - } - } -} - -impl SystemTime { - pub fn now() -> SystemTime { - unsafe { - let mut t: SystemTime = mem::zeroed(); - c::GetSystemTimeAsFileTime(&mut t.t); - return t - } - } - - fn from_intervals(intervals: i64) -> SystemTime { - SystemTime { - t: c::FILETIME { - dwLowDateTime: intervals as c::DWORD, - dwHighDateTime: (intervals >> 32) as c::DWORD, - } - } - } - - fn intervals(&self) -> i64 { - (self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32) - } - - pub fn sub_time(&self, other: &SystemTime) -> Result { - let me = self.intervals(); - let other = other.intervals(); - if me >= other { - Ok(intervals2dur((me - other) as u64)) - } else { - Err(intervals2dur((other - me) as u64)) - } - } - - pub fn add_duration(&self, other: &Duration) -> SystemTime { - let intervals = self.intervals().checked_add(dur2intervals(other)) - .expect("overflow when adding duration to time"); - SystemTime::from_intervals(intervals) - } - - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - let intervals = self.intervals().checked_sub(dur2intervals(other)) - .expect("overflow when subtracting from time"); - SystemTime::from_intervals(intervals) - } -} - -impl PartialEq for SystemTime { - fn eq(&self, other: &SystemTime) -> bool { - self.intervals() == other.intervals() - } -} - -impl Eq for SystemTime {} - -impl PartialOrd for SystemTime { - fn partial_cmp(&self, other: &SystemTime) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for SystemTime { - fn cmp(&self, other: &SystemTime) -> Ordering { - self.intervals().cmp(&other.intervals()) - } -} - -impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SystemTime") - .field("intervals", &self.intervals()) - .finish() - } -} - -impl From for SystemTime { - fn from(t: c::FILETIME) -> SystemTime { - SystemTime { t: t } - } -} - -impl Hash for SystemTime { - fn hash(&self, state: &mut H) { - self.intervals().hash(state) - } -} - -fn dur2intervals(d: &Duration) -> i64 { - d.as_secs() - .checked_mul(INTERVALS_PER_SEC) - .and_then(|i| i.checked_add(d.subsec_nanos() as u64 / 100)) - .and_then(|i| i.try_into().ok()) - .expect("overflow when converting duration to intervals") -} - -fn intervals2dur(intervals: u64) -> Duration { - Duration::new(intervals / INTERVALS_PER_SEC, - ((intervals % INTERVALS_PER_SEC) * 100) as u32) -} - -fn frequency() -> c::LARGE_INTEGER { - static mut FREQUENCY: c::LARGE_INTEGER = 0; - static ONCE: Once = Once::new(); - - unsafe { - ONCE.call_once(|| { - cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap(); - }); - FREQUENCY - } -} diff --git a/ctr-std/src/sys_common/at_exit_imp.rs b/ctr-std/src/sys_common/at_exit_imp.rs deleted file mode 100644 index 76e5df2..0000000 --- a/ctr-std/src/sys_common/at_exit_imp.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation of running at_exit routines -//! -//! Documentation can be found on the `rt::at_exit` function. - -use boxed::FnBox; -use ptr; -use mem; -use sys_common::mutex::Mutex; - -type Queue = Vec>; - -// NB these are specifically not types from `std::sync` as they currently rely -// on poisoning and this module needs to operate at a lower level than requiring -// the thread infrastructure to be in place (useful on the borders of -// initialization/destruction). -// We never call `LOCK.init()`, so it is UB to attempt to -// acquire this mutex reentrantly! -static LOCK: Mutex = Mutex::new(); -static mut QUEUE: *mut Queue = ptr::null_mut(); - -const DONE: *mut Queue = 1_usize as *mut _; - -// The maximum number of times the cleanup routines will be run. While running -// the at_exit closures new ones may be registered, and this count is the number -// of times the new closures will be allowed to register successfully. After -// this number of iterations all new registrations will return `false`. -const ITERS: usize = 10; - -unsafe fn init() -> bool { - if QUEUE.is_null() { - let state: Box = box Vec::new(); - QUEUE = Box::into_raw(state); - } else if QUEUE == DONE { - // can't re-init after a cleanup - return false - } - - true -} - -pub fn cleanup() { - for i in 1..=ITERS { - unsafe { - let queue = { - let _guard = LOCK.lock(); - mem::replace(&mut QUEUE, if i == ITERS { DONE } else { ptr::null_mut() }) - }; - - // make sure we're not recursively cleaning up - assert!(queue != DONE); - - // If we never called init, not need to cleanup! - if !queue.is_null() { - let queue: Box = Box::from_raw(queue); - for to_run in *queue { - // We are not holding any lock, so reentrancy is fine. - to_run(); - } - } - } - } -} - -pub fn push(f: Box) -> bool { - unsafe { - let _guard = LOCK.lock(); - if init() { - // We are just moving `f` around, not calling it. - // There is no possibility of reentrancy here. - (*QUEUE).push(f); - true - } else { - false - } - } -} diff --git a/ctr-std/src/sys_common/backtrace.rs b/ctr-std/src/sys_common/backtrace.rs deleted file mode 100644 index 7737178..0000000 --- a/ctr-std/src/sys_common/backtrace.rs +++ /dev/null @@ -1,462 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Common code for printing the backtrace in the same way across the different -/// supported platforms. - -use env; -use io::prelude::*; -use io; -use str; -use sync::atomic::{self, Ordering}; -use path::{self, Path}; -use sys::mutex::Mutex; -use ptr; - -pub use sys::backtrace::{ - unwind_backtrace, - resolve_symname, - foreach_symbol_fileline, - BacktraceContext -}; - -#[cfg(target_pointer_width = "64")] -pub const HEX_WIDTH: usize = 18; - -#[cfg(target_pointer_width = "32")] -pub const HEX_WIDTH: usize = 10; - -/// Represents an item in the backtrace list. See `unwind_backtrace` for how -/// it is created. -#[derive(Debug, Copy, Clone)] -pub struct Frame { - /// Exact address of the call that failed. - pub exact_position: *const u8, - /// Address of the enclosing function. - pub symbol_addr: *const u8, - /// Which inlined function is this frame referring to - pub inline_context: u32, -} - -/// Max number of frames to print. -const MAX_NB_FRAMES: usize = 100; - -/// Prints the current backtrace. -pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { - static LOCK: Mutex = Mutex::new(); - - // Use a lock to prevent mixed output in multithreading context. - // Some platforms also requires it, like `SymFromAddr` on Windows. - unsafe { - LOCK.lock(); - let res = _print(w, format); - LOCK.unlock(); - res - } -} - -fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { - let mut frames = [Frame { - exact_position: ptr::null(), - symbol_addr: ptr::null(), - inline_context: 0, - }; MAX_NB_FRAMES]; - let (nb_frames, context) = unwind_backtrace(&mut frames)?; - let (skipped_before, skipped_after) = - filter_frames(&frames[..nb_frames], format, &context); - if skipped_before + skipped_after > 0 { - writeln!(w, "note: Some details are omitted, \ - run with `RUST_BACKTRACE=full` for a verbose backtrace.")?; - } - writeln!(w, "stack backtrace:")?; - - let filtered_frames = &frames[..nb_frames - skipped_after]; - for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() { - resolve_symname(*frame, |symname| { - output(w, index, *frame, symname, format) - }, &context)?; - let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| { - output_fileline(w, file, line, format) - }, &context)?; - if has_more_filenames { - w.write_all(b" <... and possibly more>")?; - } - } - - Ok(()) -} - -/// Returns a number of frames to remove at the beginning and at the end of the -/// backtrace, according to the backtrace format. -fn filter_frames(frames: &[Frame], - format: PrintFormat, - context: &BacktraceContext) -> (usize, usize) -{ - if format == PrintFormat::Full { - return (0, 0); - } - - let skipped_before = 0; - - let skipped_after = frames.len() - frames.iter().position(|frame| { - let mut is_marker = false; - let _ = resolve_symname(*frame, |symname| { - if let Some(mangled_symbol_name) = symname { - // Use grep to find the concerned functions - if mangled_symbol_name.contains("__rust_begin_short_backtrace") { - is_marker = true; - } - } - Ok(()) - }, context); - is_marker - }).unwrap_or(frames.len()); - - if skipped_before + skipped_after >= frames.len() { - // Avoid showing completely empty backtraces - return (0, 0); - } - - (skipped_before, skipped_after) -} - - -/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. -#[inline(never)] -pub fn __rust_begin_short_backtrace(f: F) -> T - where F: FnOnce() -> T, F: Send, T: Send -{ - f() -} - -/// Controls how the backtrace should be formatted. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum PrintFormat { - /// Show only relevant data from the backtrace. - Short = 2, - /// Show all the frames with absolute path for files. - Full = 3, -} - -// For now logging is turned off by default, and this function checks to see -// whether the magical environment variable is present to see if it's turned on. -pub fn log_enabled() -> Option { - static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0); - match ENABLED.load(Ordering::SeqCst) { - 0 => {} - 1 => return None, - 2 => return Some(PrintFormat::Short), - _ => return Some(PrintFormat::Full), - } - - let val = env::var_os("RUST_BACKTRACE").and_then(|x| - if &x == "0" { - None - } else if &x == "full" { - Some(PrintFormat::Full) - } else { - Some(PrintFormat::Short) - } - ); - ENABLED.store(match val { - Some(v) => v as isize, - None => 1, - }, Ordering::SeqCst); - val -} - -/// Print the symbol of the backtrace frame. -/// -/// These output functions should now be used everywhere to ensure consistency. -/// You may want to also use `output_fileline`. -fn output(w: &mut dyn Write, idx: usize, frame: Frame, - s: Option<&str>, format: PrintFormat) -> io::Result<()> { - // Remove the `17: 0x0 - ` line. - if format == PrintFormat::Short && frame.exact_position == ptr::null() { - return Ok(()); - } - match format { - PrintFormat::Full => write!(w, - " {:2}: {:2$?} - ", - idx, - frame.exact_position, - HEX_WIDTH)?, - PrintFormat::Short => write!(w, " {:2}: ", idx)?, - } - match s { - Some(string) => demangle(w, string, format)?, - None => w.write_all(b"")?, - } - w.write_all(b"\n") -} - -/// Print the filename and line number of the backtrace frame. -/// -/// See also `output`. -#[allow(dead_code)] -fn output_fileline(w: &mut dyn Write, - file: &[u8], - line: u32, - format: PrintFormat) -> io::Result<()> { - // prior line: " ##: {:2$} - func" - w.write_all(b"")?; - match format { - PrintFormat::Full => write!(w, - " {:1$}", - "", - HEX_WIDTH)?, - PrintFormat::Short => write!(w, " ")?, - } - - let file = str::from_utf8(file).unwrap_or(""); - let file_path = Path::new(file); - let mut already_printed = false; - if format == PrintFormat::Short && file_path.is_absolute() { - if let Ok(cwd) = env::current_dir() { - if let Ok(stripped) = file_path.strip_prefix(&cwd) { - if let Some(s) = stripped.to_str() { - write!(w, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?; - already_printed = true; - } - } - } - } - if !already_printed { - write!(w, " at {}:{}", file, line)?; - } - - w.write_all(b"\n") -} - - -// All rust symbols are in theory lists of "::"-separated identifiers. Some -// assemblers, however, can't handle these characters in symbol names. To get -// around this, we use C++-style mangling. The mangling method is: -// -// 1. Prefix the symbol with "_ZN" -// 2. For each element of the path, emit the length plus the element -// 3. End the path with "E" -// -// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar". -// -// We're the ones printing our backtraces, so we can't rely on anything else to -// demangle our symbols. It's *much* nicer to look at demangled symbols, so -// this function is implemented to give us nice pretty output. -// -// Note that this demangler isn't quite as fancy as it could be. We have lots -// of other information in our symbols like hashes, version, type information, -// etc. Additionally, this doesn't handle glue symbols at all. -pub fn demangle(writer: &mut dyn Write, mut s: &str, format: PrintFormat) -> io::Result<()> { - // During ThinLTO LLVM may import and rename internal symbols, so strip out - // those endings first as they're one of the last manglings applied to - // symbol names. - let llvm = ".llvm."; - if let Some(i) = s.find(llvm) { - let candidate = &s[i + llvm.len()..]; - let all_hex = candidate.chars().all(|c| { - match c { - 'A' ..= 'F' | '0' ..= '9' => true, - _ => false, - } - }); - - if all_hex { - s = &s[..i]; - } - } - - // Validate the symbol. If it doesn't look like anything we're - // expecting, we just print it literally. Note that we must handle non-rust - // symbols because we could have any function in the backtrace. - let mut valid = true; - let mut inner = s; - if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") { - inner = &s[3 .. s.len() - 1]; - // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too. - } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") { - inner = &s[2 .. s.len() - 1]; - } else { - valid = false; - } - - if valid { - let mut chars = inner.chars(); - while valid { - let mut i = 0; - for c in chars.by_ref() { - if c.is_numeric() { - i = i * 10 + c as usize - '0' as usize; - } else { - break - } - } - if i == 0 { - valid = chars.next().is_none(); - break - } else if chars.by_ref().take(i - 1).count() != i - 1 { - valid = false; - } - } - } - - // Alright, let's do this. - if !valid { - writer.write_all(s.as_bytes())?; - } else { - // remove the `::hfc2edb670e5eda97` part at the end of the symbol. - if format == PrintFormat::Short { - // The symbol in still mangled. - let mut split = inner.rsplitn(2, "17h"); - match (split.next(), split.next()) { - (Some(addr), rest) => { - if addr.len() == 16 && - addr.chars().all(|c| c.is_digit(16)) - { - inner = rest.unwrap_or(""); - } - } - _ => (), - } - } - - let mut first = true; - while !inner.is_empty() { - if !first { - writer.write_all(b"::")?; - } else { - first = false; - } - let mut rest = inner; - while rest.chars().next().unwrap().is_numeric() { - rest = &rest[1..]; - } - let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap(); - inner = &rest[i..]; - rest = &rest[..i]; - if rest.starts_with("_$") { - rest = &rest[1..]; - } - while !rest.is_empty() { - if rest.starts_with(".") { - if let Some('.') = rest[1..].chars().next() { - writer.write_all(b"::")?; - rest = &rest[2..]; - } else { - writer.write_all(b".")?; - rest = &rest[1..]; - } - } else if rest.starts_with("$") { - macro_rules! demangle { - ($($pat:expr => $demangled:expr),*) => ({ - $(if rest.starts_with($pat) { - writer.write_all($demangled)?; - rest = &rest[$pat.len()..]; - } else)* - { - writer.write_all(rest.as_bytes())?; - break; - } - - }) - } - - // see src/librustc/back/link.rs for these mappings - demangle! ( - "$SP$" => b"@", - "$BP$" => b"*", - "$RF$" => b"&", - "$LT$" => b"<", - "$GT$" => b">", - "$LP$" => b"(", - "$RP$" => b")", - "$C$" => b",", - - // in theory we can demangle any Unicode code point, but - // for simplicity we just catch the common ones. - "$u7e$" => b"~", - "$u20$" => b" ", - "$u27$" => b"'", - "$u5b$" => b"[", - "$u5d$" => b"]", - "$u7b$" => b"{", - "$u7d$" => b"}", - "$u3b$" => b";", - "$u2b$" => b"+", - "$u22$" => b"\"" - ) - } else { - let idx = match rest.char_indices().find(|&(_, c)| c == '$' || c == '.') { - None => rest.len(), - Some((i, _)) => i, - }; - writer.write_all(rest[..idx].as_bytes())?; - rest = &rest[idx..]; - } - } - } - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use sys_common; - macro_rules! t { ($a:expr, $b:expr) => ({ - let mut m = Vec::new(); - sys_common::backtrace::demangle(&mut m, - $a, - super::PrintFormat::Full).unwrap(); - assert_eq!(String::from_utf8(m).unwrap(), $b); - }) } - - #[test] - fn demangle() { - t!("test", "test"); - t!("_ZN4testE", "test"); - t!("_ZN4test", "_ZN4test"); - t!("_ZN4test1a2bcE", "test::a::bc"); - } - - #[test] - fn demangle_dollars() { - t!("_ZN4$RP$E", ")"); - t!("_ZN8$RF$testE", "&test"); - t!("_ZN8$BP$test4foobE", "*test::foob"); - t!("_ZN9$u20$test4foobE", " test::foob"); - t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>"); - } - - #[test] - fn demangle_many_dollars() { - t!("_ZN13test$u20$test4foobE", "test test::foob"); - t!("_ZN12test$BP$test4foobE", "test*test::foob"); - } - - #[test] - fn demangle_windows() { - t!("ZN4testE", "test"); - t!("ZN13test$u20$test4foobE", "test test::foob"); - t!("ZN12test$RF$test4foobE", "test&test::foob"); - } - - #[test] - fn demangle_elements_beginning_with_underscore() { - t!("_ZN13_$LT$test$GT$E", ""); - t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}"); - t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR"); - } - - #[test] - fn demangle_trait_impls() { - t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE", - ">::bar"); - } -} diff --git a/ctr-std/src/sys_common/bytestring.rs b/ctr-std/src/sys_common/bytestring.rs deleted file mode 100644 index 971b839..0000000 --- a/ctr-std/src/sys_common/bytestring.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] - -use fmt::{Formatter, Result, Write}; -use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; - -pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter) -> Result { - // Writes out a valid unicode string with the correct escape sequences - fn write_str_escaped(f: &mut Formatter, s: &str) -> Result { - for c in s.chars().flat_map(|c| c.escape_debug()) { - f.write_char(c)? - } - Ok(()) - } - - f.write_str("\"")?; - for Utf8LossyChunk { valid, broken } in Utf8Lossy::from_bytes(slice).chunks() { - write_str_escaped(f, valid)?; - for b in broken { - write!(f, "\\x{:02X}", b)?; - } - } - f.write_str("\"") -} - -#[cfg(test)] -mod tests { - use super::*; - use fmt::{Formatter, Result, Debug}; - - #[test] - fn smoke() { - struct Helper<'a>(&'a [u8]); - - impl<'a> Debug for Helper<'a> { - fn fmt(&self, f: &mut Formatter) -> Result { - debug_fmt_bytestring(self.0, f) - } - } - - let input = b"\xF0hello,\tworld"; - let expected = r#""\xF0hello,\tworld""#; - let output = format!("{:?}", Helper(input)); - - assert!(output == expected); - } -} diff --git a/ctr-std/src/sys_common/condvar.rs b/ctr-std/src/sys_common/condvar.rs deleted file mode 100644 index b6f29dd..0000000 --- a/ctr-std/src/sys_common/condvar.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use time::Duration; -use sys_common::mutex::{self, Mutex}; -use sys::condvar as imp; - -/// An OS-based condition variable. -/// -/// This structure is the lowest layer possible on top of the OS-provided -/// condition variables. It is consequently entirely unsafe to use. It is -/// recommended to use the safer types at the top level of this crate instead of -/// this type. -pub struct Condvar(imp::Condvar); - -impl Condvar { - /// Creates a new condition variable for use. - /// - /// Behavior is undefined if the condition variable is moved after it is - /// first used with any of the functions below. - pub const fn new() -> Condvar { Condvar(imp::Condvar::new()) } - - /// Prepares the condition variable for use. - /// - /// This should be called once the condition variable is at a stable memory - /// address. - #[inline] - pub unsafe fn init(&mut self) { self.0.init() } - - /// Signals one waiter on this condition variable to wake up. - #[inline] - pub unsafe fn notify_one(&self) { self.0.notify_one() } - - /// Awakens all current waiters on this condition variable. - #[inline] - pub unsafe fn notify_all(&self) { self.0.notify_all() } - - /// Waits for a signal on the specified mutex. - /// - /// Behavior is undefined if the mutex is not locked by the current thread. - /// Behavior is also undefined if more than one mutex is used concurrently - /// on this condition variable. - #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { self.0.wait(mutex::raw(mutex)) } - - /// Waits for a signal on the specified mutex with a timeout duration - /// specified by `dur` (a relative time into the future). - /// - /// Behavior is undefined if the mutex is not locked by the current thread. - /// Behavior is also undefined if more than one mutex is used concurrently - /// on this condition variable. - #[inline] - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - self.0.wait_timeout(mutex::raw(mutex), dur) - } - - /// Deallocates all resources associated with this condition variable. - /// - /// Behavior is undefined if there are current or will be future users of - /// this condition variable. - #[inline] - pub unsafe fn destroy(&self) { self.0.destroy() } -} diff --git a/ctr-std/src/sys_common/gnu/libbacktrace.rs b/ctr-std/src/sys_common/gnu/libbacktrace.rs deleted file mode 100644 index 6ad3af6..0000000 --- a/ctr-std/src/sys_common/gnu/libbacktrace.rs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use libc; - -use ffi::CStr; -use io; -use mem; -use ptr; -use sys::backtrace::BacktraceContext; -use sys_common::backtrace::Frame; - -pub fn foreach_symbol_fileline(frame: Frame, - mut f: F, - _: &BacktraceContext) -> io::Result -where F: FnMut(&[u8], u32) -> io::Result<()> -{ - // pcinfo may return an arbitrary number of file:line pairs, - // in the order of stack trace (i.e. inlined calls first). - // in order to avoid allocation, we stack-allocate a fixed size of entries. - const FILELINE_SIZE: usize = 32; - let mut fileline_buf = [(ptr::null(), !0); FILELINE_SIZE]; - let ret; - let fileline_count = { - let state = unsafe { init_state() }; - if state.is_null() { - return Err(io::Error::new( - io::ErrorKind::Other, - "failed to allocate libbacktrace state") - ) - } - let mut fileline_win: &mut [FileLine] = &mut fileline_buf; - let fileline_addr = &mut fileline_win as *mut &mut [FileLine]; - ret = unsafe { - backtrace_pcinfo(state, - frame.exact_position as libc::uintptr_t, - pcinfo_cb, - error_cb, - fileline_addr as *mut libc::c_void) - }; - FILELINE_SIZE - fileline_win.len() - }; - if ret == 0 { - for &(file, line) in &fileline_buf[..fileline_count] { - if file.is_null() { continue; } // just to be sure - let file = unsafe { CStr::from_ptr(file).to_bytes() }; - f(file, line)?; - } - Ok(fileline_count == FILELINE_SIZE) - } else { - Ok(false) - } -} - -/// Converts a pointer to symbol to its string value. -pub fn resolve_symname(frame: Frame, - callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - let symname = { - let state = unsafe { init_state() }; - if state.is_null() { - return Err(io::Error::new( - io::ErrorKind::Other, - "failed to allocate libbacktrace state") - ) - } - let mut data: *const libc::c_char = ptr::null(); - let data_addr = &mut data as *mut *const libc::c_char; - let ret = unsafe { - backtrace_syminfo(state, - frame.symbol_addr as libc::uintptr_t, - syminfo_cb, - error_cb, - data_addr as *mut libc::c_void) - }; - if ret == 0 || data.is_null() { - None - } else { - unsafe { - CStr::from_ptr(data).to_str().ok() - } - } - }; - callback(symname) -} - -//////////////////////////////////////////////////////////////////////// -// libbacktrace.h API -//////////////////////////////////////////////////////////////////////// -type backtrace_syminfo_callback = -extern "C" fn(data: *mut libc::c_void, - pc: libc::uintptr_t, - symname: *const libc::c_char, - symval: libc::uintptr_t, - symsize: libc::uintptr_t); -type backtrace_full_callback = -extern "C" fn(data: *mut libc::c_void, - pc: libc::uintptr_t, - filename: *const libc::c_char, - lineno: libc::c_int, - function: *const libc::c_char) -> libc::c_int; -type backtrace_error_callback = -extern "C" fn(data: *mut libc::c_void, - msg: *const libc::c_char, - errnum: libc::c_int); -enum backtrace_state {} - -extern { - fn backtrace_create_state(filename: *const libc::c_char, - threaded: libc::c_int, - error: backtrace_error_callback, - data: *mut libc::c_void) - -> *mut backtrace_state; - fn backtrace_syminfo(state: *mut backtrace_state, - addr: libc::uintptr_t, - cb: backtrace_syminfo_callback, - error: backtrace_error_callback, - data: *mut libc::c_void) -> libc::c_int; - fn backtrace_pcinfo(state: *mut backtrace_state, - addr: libc::uintptr_t, - cb: backtrace_full_callback, - error: backtrace_error_callback, - data: *mut libc::c_void) -> libc::c_int; -} - -//////////////////////////////////////////////////////////////////////// -// helper callbacks -//////////////////////////////////////////////////////////////////////// - -type FileLine = (*const libc::c_char, u32); - -extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char, - _errnum: libc::c_int) { - // do nothing for now -} -extern fn syminfo_cb(data: *mut libc::c_void, - _pc: libc::uintptr_t, - symname: *const libc::c_char, - _symval: libc::uintptr_t, - _symsize: libc::uintptr_t) { - let slot = data as *mut *const libc::c_char; - unsafe { *slot = symname; } -} -extern fn pcinfo_cb(data: *mut libc::c_void, - _pc: libc::uintptr_t, - filename: *const libc::c_char, - lineno: libc::c_int, - _function: *const libc::c_char) -> libc::c_int { - if !filename.is_null() { - let slot = data as *mut &mut [FileLine]; - let buffer = unsafe {ptr::read(slot)}; - - // if the buffer is not full, add file:line to the buffer - // and adjust the buffer for next possible calls to pcinfo_cb. - if !buffer.is_empty() { - buffer[0] = (filename, lineno as u32); - unsafe { ptr::write(slot, &mut buffer[1..]); } - } - } - - 0 -} - -// The libbacktrace API supports creating a state, but it does not -// support destroying a state. I personally take this to mean that a -// state is meant to be created and then live forever. -// -// I would love to register an at_exit() handler which cleans up this -// state, but libbacktrace provides no way to do so. -// -// With these constraints, this function has a statically cached state -// that is calculated the first time this is requested. Remember that -// backtracing all happens serially (one global lock). -// -// Things don't work so well on not-Linux since libbacktrace can't track -// down that executable this is. We at one point used env::current_exe but -// it turns out that there are some serious security issues with that -// approach. -// -// Specifically, on certain platforms like BSDs, a malicious actor can cause -// an arbitrary file to be placed at the path returned by current_exe. -// libbacktrace does not behave defensively in the presence of ill-formed -// DWARF information, and has been demonstrated to segfault in at least one -// case. There is no evidence at the moment to suggest that a more carefully -// constructed file can't cause arbitrary code execution. As a result of all -// of this, we don't hint libbacktrace with the path to the current process. -unsafe fn init_state() -> *mut backtrace_state { - static mut STATE: *mut backtrace_state = ptr::null_mut(); - if !STATE.is_null() { return STATE } - - let filename = match ::sys::backtrace::gnu::get_executable_filename() { - Ok((filename, file)) => { - // filename is purposely leaked here since libbacktrace requires - // it to stay allocated permanently, file is also leaked so that - // the file stays locked - let filename_ptr = filename.as_ptr(); - mem::forget(filename); - mem::forget(file); - filename_ptr - }, - Err(_) => ptr::null(), - }; - - STATE = backtrace_create_state(filename, 0, error_cb, - ptr::null_mut()); - STATE -} diff --git a/ctr-std/src/sys_common/gnu/mod.rs b/ctr-std/src/sys_common/gnu/mod.rs deleted file mode 100644 index 3a8cf2d..0000000 --- a/ctr-std/src/sys_common/gnu/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(missing_docs)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -pub mod libbacktrace; diff --git a/ctr-std/src/sys_common/io.rs b/ctr-std/src/sys_common/io.rs deleted file mode 100644 index ab23936..0000000 --- a/ctr-std/src/sys_common/io.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -pub const DEFAULT_BUF_SIZE: usize = 8 * 1024; - -#[cfg(test)] -#[allow(dead_code)] // not used on emscripten -pub mod test { - use path::{Path, PathBuf}; - use env; - use rand::{self, Rng}; - use fs; - - pub struct TempDir(PathBuf); - - impl TempDir { - pub fn join(&self, path: &str) -> PathBuf { - let TempDir(ref p) = *self; - p.join(path) - } - - pub fn path<'a>(&'a self) -> &'a Path { - let TempDir(ref p) = *self; - p - } - } - - impl Drop for TempDir { - fn drop(&mut self) { - // Gee, seeing how we're testing the fs module I sure hope that we - // at least implement this correctly! - let TempDir(ref p) = *self; - fs::remove_dir_all(p).unwrap(); - } - } - - pub fn tmpdir() -> TempDir { - let p = env::temp_dir(); - let mut r = rand::thread_rng(); - let ret = p.join(&format!("rust-{}", r.next_u32())); - fs::create_dir(&ret).unwrap(); - TempDir(ret) - } -} diff --git a/ctr-std/src/sys_common/mod.rs b/ctr-std/src/sys_common/mod.rs deleted file mode 100644 index d0c4d6a..0000000 --- a/ctr-std/src/sys_common/mod.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Platform-independent platform abstraction -//! -//! This is the platform-independent portion of the standard library's -//! platform abstraction layer, whereas `std::sys` is the -//! platform-specific portion. -//! -//! The relationship between `std::sys_common`, `std::sys` and the -//! rest of `std` is complex, with dependencies going in all -//! directions: `std` depending on `sys_common`, `sys_common` -//! depending on `sys`, and `sys` depending on `sys_common` and `std`. -//! Ideally `sys_common` would be split into two and the dependencies -//! between them all would form a dag, facilitating the extraction of -//! `std::sys` from the standard library. - -#![allow(missing_docs)] -#![allow(missing_debug_implementations)] - -use sync::Once; -use sys; - -macro_rules! rtabort { - ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) -} - -macro_rules! rtassert { - ($e:expr) => (if !$e { - rtabort!(concat!("assertion failed: ", stringify!($e))); - }) -} - -pub mod at_exit_imp; -#[cfg(feature = "backtrace")] -pub mod backtrace; -pub mod condvar; -pub mod io; -pub mod mutex; -pub mod poison; -pub mod remutex; -pub mod rwlock; -pub mod thread; -pub mod thread_info; -pub mod thread_local; -pub mod util; -pub mod wtf8; -pub mod bytestring; -pub mod process; - -cfg_if! { - if #[cfg(any(target_os = "cloudabi", target_os = "l4re", target_os = "redox"))] { - pub use sys::net; - } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] { - pub use sys::net; - } else { - pub mod net; - } -} - -#[cfg(feature = "backtrace")] -#[cfg(any(all(unix, not(target_os = "emscripten")), - all(windows, target_env = "gnu"), - target_os = "redox"))] -pub mod gnu; - -// common error constructors - -/// A trait for viewing representations from std types -#[doc(hidden)] -pub trait AsInner { - fn as_inner(&self) -> &Inner; -} - -/// A trait for viewing representations from std types -#[doc(hidden)] -pub trait AsInnerMut { - fn as_inner_mut(&mut self) -> &mut Inner; -} - -/// A trait for extracting representations from std types -#[doc(hidden)] -pub trait IntoInner { - fn into_inner(self) -> Inner; -} - -/// A trait for creating std types from internal representations -#[doc(hidden)] -pub trait FromInner { - fn from_inner(inner: Inner) -> Self; -} - -/// Enqueues a procedure to run when the main thread exits. -/// -/// Currently these closures are only run once the main *Rust* thread exits. -/// Once the `at_exit` handlers begin running, more may be enqueued, but not -/// infinitely so. Eventually a handler registration will be forced to fail. -/// -/// Returns `Ok` if the handler was successfully registered, meaning that the -/// closure will be run once the main thread exits. Returns `Err` to indicate -/// that the closure could not be registered, meaning that it is not scheduled -/// to be run. -pub fn at_exit(f: F) -> Result<(), ()> { - if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())} -} - -/// One-time runtime cleanup. -pub fn cleanup() { - static CLEANUP: Once = Once::new(); - CLEANUP.call_once(|| unsafe { - sys::args::cleanup(); - sys::stack_overflow::cleanup(); - at_exit_imp::cleanup(); - }); -} - -// Computes (value*numer)/denom without overflow, as long as both -// (numer*denom) and the overall result fit into i64 (which is the case -// for our time conversions). -#[allow(dead_code)] // not used on all platforms -pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 { - let q = value / denom; - let r = value % denom; - // Decompose value as (value/denom*denom + value%denom), - // substitute into (value*numer)/denom and simplify. - // r < denom, so (denom*numer) is the upper bound of (r*numer) - q * numer + r * numer / denom -} - -#[test] -fn test_muldiv() { - assert_eq!(mul_div_u64( 1_000_000_000_001, 1_000_000_000, 1_000_000), - 1_000_000_000_001_000); -} diff --git a/ctr-std/src/sys_common/mutex.rs b/ctr-std/src/sys_common/mutex.rs deleted file mode 100644 index c6d531c..0000000 --- a/ctr-std/src/sys_common/mutex.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use sys::mutex as imp; - -/// An OS-based mutual exclusion lock. -/// -/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of -/// this mutex is unsafe and it is recommended to instead use the safe wrapper -/// at the top level of the crate instead of this type. -pub struct Mutex(imp::Mutex); - -unsafe impl Sync for Mutex {} - -impl Mutex { - /// Creates a new mutex for use. - /// - /// Behavior is undefined if the mutex is moved after it is - /// first used with any of the functions below. - /// Also, until `init` is called, behavior is undefined if this - /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock` - /// are called by the thread currently holding the lock. - pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) } - - /// Prepare the mutex for use. - /// - /// This should be called once the mutex is at a stable memory address. - /// If called, this must be the very first thing that happens to the mutex. - /// Calling it in parallel with or after any operation (including another - /// `init()`) is undefined behavior. - #[inline] - pub unsafe fn init(&mut self) { self.0.init() } - - /// Locks the mutex blocking the current thread until it is available. - /// - /// Behavior is undefined if the mutex has been moved between this and any - /// previous function call. - #[inline] - pub unsafe fn raw_lock(&self) { self.0.lock() } - - /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex - /// will be unlocked. - #[inline] - pub unsafe fn lock(&self) -> MutexGuard { - self.raw_lock(); - MutexGuard(&self.0) - } - - /// Attempts to lock the mutex without blocking, returning whether it was - /// successfully acquired or not. - /// - /// Behavior is undefined if the mutex has been moved between this and any - /// previous function call. - #[inline] - pub unsafe fn try_lock(&self) -> bool { self.0.try_lock() } - - /// Unlocks the mutex. - /// - /// Behavior is undefined if the current thread does not actually hold the - /// mutex. - /// - /// Consider switching from the pair of raw_lock() and raw_unlock() to - /// lock() whenever possible. - #[inline] - pub unsafe fn raw_unlock(&self) { self.0.unlock() } - - /// Deallocates all resources associated with this mutex. - /// - /// Behavior is undefined if there are current or will be future users of - /// this mutex. - #[inline] - pub unsafe fn destroy(&self) { self.0.destroy() } -} - -// not meant to be exported to the outside world, just the containing module -pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 } - -#[must_use] -/// A simple RAII utility for the above Mutex without the poisoning semantics. -pub struct MutexGuard<'a>(&'a imp::Mutex); - -impl<'a> Drop for MutexGuard<'a> { - #[inline] - fn drop(&mut self) { - unsafe { self.0.unlock(); } - } -} diff --git a/ctr-std/src/sys_common/net.rs b/ctr-std/src/sys_common/net.rs deleted file mode 100644 index a0dbda0..0000000 --- a/ctr-std/src/sys_common/net.rs +++ /dev/null @@ -1,630 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] - -use cmp; -use ffi::CString; -use fmt; -use io::{self, Error, ErrorKind}; -use libc::{c_int, c_void}; -use mem; -use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; -use ptr; -use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t}; -use sys::net::netc as c; -use sys_common::{AsInner, FromInner, IntoInner}; -use time::Duration; - -// IPV6 stuff does not seem to be supported on 3DS. TODO: Determine if that's true -const IPV6_ADD_MEMBERSHIP: c_int = 0x0; -const IPV6_DROP_MEMBERSHIP: c_int = 0x0; -const IPV6_MULTICAST_LOOP: c_int = 0x0; -const IPV6_V6ONLY: c_int = 0x0; - -// Neither are signals -const MSG_NOSIGNAL: c_int = 0x0; - -// These constants are also currently missing from libctru. TODO: Find them? -const SO_SNDTIMEO: c_int = 0x0; -const SO_RCVTIMEO: c_int = 0x0; -const SO_BROADCAST: c_int = 0x0; - -//////////////////////////////////////////////////////////////////////////////// -// sockaddr and misc bindings -//////////////////////////////////////////////////////////////////////////////// - -pub fn setsockopt(sock: &Socket, opt: c_int, val: c_int, - payload: T) -> io::Result<()> { - unsafe { - let payload = &payload as *const T as *const c_void; - cvt(c::setsockopt(*sock.as_inner(), opt, val, payload, - mem::size_of::() as c::socklen_t))?; - Ok(()) - } -} - -pub fn getsockopt(sock: &Socket, opt: c_int, - val: c_int) -> io::Result { - unsafe { - let mut slot: T = mem::zeroed(); - let mut len = mem::size_of::() as c::socklen_t; - cvt(c::getsockopt(*sock.as_inner(), opt, val, - &mut slot as *mut _ as *mut _, - &mut len))?; - assert_eq!(len as usize, mem::size_of::()); - Ok(slot) - } -} - -fn sockname(f: F) -> io::Result - where F: FnOnce(*mut c::sockaddr, *mut c::socklen_t) -> c_int -{ - unsafe { - let mut storage: c::sockaddr_storage = mem::zeroed(); - let mut len = mem::size_of_val(&storage) as c::socklen_t; - cvt(f(&mut storage as *mut _ as *mut _, &mut len))?; - sockaddr_to_addr(&storage, len as usize) - } -} - -pub fn sockaddr_to_addr(storage: &c::sockaddr_storage, - len: usize) -> io::Result { - match storage.ss_family as c_int { - c::AF_INET => { - assert!(len as usize >= mem::size_of::()); - Ok(SocketAddr::V4(FromInner::from_inner(unsafe { - *(storage as *const _ as *const c::sockaddr_in) - }))) - } - c::AF_INET6 => { - assert!(len as usize >= mem::size_of::()); - Ok(SocketAddr::V6(FromInner::from_inner(unsafe { - *(storage as *const _ as *const c::sockaddr_in6) - }))) - } - _ => { - Err(Error::new(ErrorKind::InvalidInput, "invalid argument")) - } - } -} - -#[cfg(target_os = "android")] -fn to_ipv6mr_interface(value: u32) -> c_int { - value as c_int -} - -#[cfg(not(target_os = "android"))] -fn to_ipv6mr_interface(value: u32) -> ::libc::c_uint { - value as ::libc::c_uint -} - -//////////////////////////////////////////////////////////////////////////////// -// get_host_addresses -//////////////////////////////////////////////////////////////////////////////// - -pub struct LookupHost { - original: *mut c::addrinfo, - cur: *mut c::addrinfo, -} - -impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option { - loop { - unsafe { - let cur = self.cur.as_ref()?; - self.cur = cur.ai_next; - match sockaddr_to_addr(mem::transmute(cur.ai_addr), - cur.ai_addrlen as usize) - { - Ok(addr) => return Some(addr), - Err(_) => continue, - } - } - } - } -} - -unsafe impl Sync for LookupHost {} -unsafe impl Send for LookupHost {} - -impl Drop for LookupHost { - fn drop(&mut self) { - unsafe { c::freeaddrinfo(self.original) } - } -} - -pub fn lookup_host(host: &str) -> io::Result { - init(); - - let c_host = CString::new(host)?; - let mut hints: c::addrinfo = unsafe { mem::zeroed() }; - hints.ai_socktype = c::SOCK_STREAM; - let mut res = ptr::null_mut(); - unsafe { - match cvt_gai(c::getaddrinfo(c_host.as_ptr() as *const u8, ptr::null(), &hints, &mut res)) { - Ok(_) => { - Ok(LookupHost { original: res, cur: res }) - }, - #[cfg(target_env = "gnu")] - Err(e) => { - // If we're running glibc prior to version 2.26, the lookup - // failure could be caused by caching a stale /etc/resolv.conf. - // We need to call libc::res_init() to clear the cache. But we - // shouldn't call it in on any other platform, because other - // res_init implementations aren't thread-safe. See - // https://github.com/rust-lang/rust/issues/41570 and - // https://github.com/rust-lang/rust/issues/43592. - use sys::net::res_init_if_glibc_before_2_26; - let _ = res_init_if_glibc_before_2_26(); - Err(e) - }, - // the cfg is needed here to avoid an "unreachable pattern" warning - #[cfg(not(target_env = "gnu"))] - Err(e) => Err(e), - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// TCP streams -//////////////////////////////////////////////////////////////////////////////// - -pub struct TcpStream { - inner: Socket, -} - -impl TcpStream { - pub fn connect(addr: &SocketAddr) -> io::Result { - init(); - - let sock = Socket::new(addr, c::SOCK_STREAM)?; - - let (addrp, len) = addr.into_inner(); - cvt_r(|| unsafe { c::connect(*sock.as_inner(), addrp, len) })?; - Ok(TcpStream { inner: sock }) - } - - pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { - init(); - - let sock = Socket::new(addr, c::SOCK_STREAM)?; - sock.connect_timeout(addr, timeout)?; - Ok(TcpStream { inner: sock }) - } - - pub fn socket(&self) -> &Socket { &self.inner } - - pub fn into_socket(self) -> Socket { self.inner } - - pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { - self.inner.set_timeout(dur, SO_RCVTIMEO) - } - - pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { - self.inner.set_timeout(dur, SO_SNDTIMEO) - } - - pub fn read_timeout(&self) -> io::Result> { - self.inner.timeout(SO_RCVTIMEO) - } - - pub fn write_timeout(&self) -> io::Result> { - self.inner.timeout(SO_SNDTIMEO) - } - - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.inner.peek(buf) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - let len = cmp::min(buf.len(), ::max_value() as usize) as wrlen_t; - let ret = cvt(unsafe { - c::send(*self.inner.as_inner(), - buf.as_ptr() as *const c_void, - len, - MSG_NOSIGNAL) - })?; - Ok(ret as usize) - } - - pub fn peer_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { - c::getpeername(*self.inner.as_inner(), buf, len) - }) - } - - pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { - c::getsockname(*self.inner.as_inner(), buf, len) - }) - } - - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.inner.shutdown(how) - } - - pub fn duplicate(&self) -> io::Result { - self.inner.duplicate().map(|s| TcpStream { inner: s }) - } - - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - self.inner.set_nodelay(nodelay) - } - - pub fn nodelay(&self) -> io::Result { - self.inner.nodelay() - } - - pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) - } - - pub fn ttl(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; - Ok(raw as u32) - } - - pub fn take_error(&self) -> io::Result> { - self.inner.take_error() - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.inner.set_nonblocking(nonblocking) - } -} - -impl FromInner for TcpStream { - fn from_inner(socket: Socket) -> TcpStream { - TcpStream { inner: socket } - } -} - -impl fmt::Debug for TcpStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut res = f.debug_struct("TcpStream"); - - if let Ok(addr) = self.socket_addr() { - res.field("addr", &addr); - } - - if let Ok(peer) = self.peer_addr() { - res.field("peer", &peer); - } - - let name = if cfg!(windows) {"socket"} else {"fd"}; - res.field(name, &self.inner.as_inner()) - .finish() - } -} - -//////////////////////////////////////////////////////////////////////////////// -// TCP listeners -//////////////////////////////////////////////////////////////////////////////// - -pub struct TcpListener { - inner: Socket, -} - -impl TcpListener { - pub fn bind(addr: &SocketAddr) -> io::Result { - init(); - - let sock = Socket::new(addr, c::SOCK_STREAM)?; - - // On platforms with Berkeley-derived sockets, this allows - // to quickly rebind a socket, without needing to wait for - // the OS to clean up the previous one. - if !cfg!(windows) { - setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, - 1 as c_int)?; - } - - // Bind our new socket - let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; - - // Start listening - cvt(unsafe { c::listen(*sock.as_inner(), 128) })?; - Ok(TcpListener { inner: sock }) - } - - pub fn socket(&self) -> &Socket { &self.inner } - - pub fn into_socket(self) -> Socket { self.inner } - - pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { - c::getsockname(*self.inner.as_inner(), buf, len) - }) - } - - pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() }; - let mut len = mem::size_of_val(&storage) as c::socklen_t; - let sock = self.inner.accept(&mut storage as *mut _ as *mut _, - &mut len)?; - let addr = sockaddr_to_addr(&storage, len as usize)?; - Ok((TcpStream { inner: sock, }, addr)) - } - - pub fn duplicate(&self) -> io::Result { - self.inner.duplicate().map(|s| TcpListener { inner: s }) - } - - pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) - } - - pub fn ttl(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; - Ok(raw as u32) - } - - pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_V6ONLY, only_v6 as c_int) - } - - pub fn only_v6(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_V6ONLY)?; - Ok(raw != 0) - } - - pub fn take_error(&self) -> io::Result> { - self.inner.take_error() - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.inner.set_nonblocking(nonblocking) - } -} - -impl FromInner for TcpListener { - fn from_inner(socket: Socket) -> TcpListener { - TcpListener { inner: socket } - } -} - -impl fmt::Debug for TcpListener { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut res = f.debug_struct("TcpListener"); - - if let Ok(addr) = self.socket_addr() { - res.field("addr", &addr); - } - - let name = if cfg!(windows) {"socket"} else {"fd"}; - res.field(name, &self.inner.as_inner()) - .finish() - } -} - -//////////////////////////////////////////////////////////////////////////////// -// UDP -//////////////////////////////////////////////////////////////////////////////// - -pub struct UdpSocket { - inner: Socket, -} - -impl UdpSocket { - pub fn bind(addr: &SocketAddr) -> io::Result { - init(); - - let sock = Socket::new(addr, c::SOCK_DGRAM)?; - let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; - Ok(UdpSocket { inner: sock }) - } - - pub fn socket(&self) -> &Socket { &self.inner } - - pub fn into_socket(self) -> Socket { self.inner } - - pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { - c::getsockname(*self.inner.as_inner(), buf, len) - }) - } - - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.inner.recv_from(buf) - } - - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.inner.peek_from(buf) - } - - pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result { - let len = cmp::min(buf.len(), ::max_value() as usize) as wrlen_t; - let (dstp, dstlen) = dst.into_inner(); - let ret = cvt(unsafe { - c::sendto(*self.inner.as_inner(), - buf.as_ptr() as *const c_void, len, - MSG_NOSIGNAL, dstp, dstlen) - })?; - Ok(ret as usize) - } - - pub fn duplicate(&self) -> io::Result { - self.inner.duplicate().map(|s| UdpSocket { inner: s }) - } - - pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { - self.inner.set_timeout(dur, SO_RCVTIMEO) - } - - pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { - self.inner.set_timeout(dur, SO_SNDTIMEO) - } - - pub fn read_timeout(&self) -> io::Result> { - self.inner.timeout(SO_RCVTIMEO) - } - - pub fn write_timeout(&self) -> io::Result> { - self.inner.timeout(SO_SNDTIMEO) - } - - pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { - setsockopt(&self.inner, c::SOL_SOCKET, SO_BROADCAST, broadcast as c_int) - } - - pub fn broadcast(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::SOL_SOCKET, SO_BROADCAST)?; - Ok(raw != 0) - } - - pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_int) - } - - pub fn multicast_loop_v4(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; - Ok(raw != 0) - } - - pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_int) - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; - Ok(raw as u32) - } - - pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int) - } - - pub fn multicast_loop_v6(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_MULTICAST_LOOP)?; - Ok(raw != 0) - } - - pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) - -> io::Result<()> { - let mreq = c::ip_mreq { - imr_multiaddr: *multiaddr.as_inner(), - imr_interface: *interface.as_inner(), - }; - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) - } - - pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) - -> io::Result<()> { - let mreq = c::ipv6_mreq { - ipv6mr_multiaddr: *multiaddr.as_inner(), - ipv6mr_interface: to_ipv6mr_interface(interface), - }; - setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) - } - - pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) - -> io::Result<()> { - let mreq = c::ip_mreq { - imr_multiaddr: *multiaddr.as_inner(), - imr_interface: *interface.as_inner(), - }; - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) - } - - pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) - -> io::Result<()> { - let mreq = c::ipv6_mreq { - ipv6mr_multiaddr: *multiaddr.as_inner(), - ipv6mr_interface: to_ipv6mr_interface(interface), - }; - setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) - } - - pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) - } - - pub fn ttl(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; - Ok(raw as u32) - } - - pub fn take_error(&self) -> io::Result> { - self.inner.take_error() - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.inner.set_nonblocking(nonblocking) - } - - pub fn recv(&self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.inner.peek(buf) - } - - pub fn send(&self, buf: &[u8]) -> io::Result { - let len = cmp::min(buf.len(), ::max_value() as usize) as wrlen_t; - let ret = cvt(unsafe { - c::send(*self.inner.as_inner(), - buf.as_ptr() as *const c_void, - len, - MSG_NOSIGNAL) - })?; - Ok(ret as usize) - } - - pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { - let (addrp, len) = addr.into_inner(); - cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(|_| ()) - } -} - -impl FromInner for UdpSocket { - fn from_inner(socket: Socket) -> UdpSocket { - UdpSocket { inner: socket } - } -} - -impl fmt::Debug for UdpSocket { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut res = f.debug_struct("UdpSocket"); - - if let Ok(addr) = self.socket_addr() { - res.field("addr", &addr); - } - - let name = if cfg!(windows) {"socket"} else {"fd"}; - res.field(name, &self.inner.as_inner()) - .finish() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use collections::HashMap; - - #[test] - fn no_lookup_host_duplicates() { - let mut addrs = HashMap::new(); - let lh = match lookup_host("localhost") { - Ok(lh) => lh, - Err(e) => panic!("couldn't resolve `localhost': {}", e) - }; - let _na = lh.map(|sa| *addrs.entry(sa).or_insert(0) += 1).count(); - assert!(addrs.values().filter(|&&v| v > 1).count() == 0); - } -} diff --git a/ctr-std/src/sys_common/poison.rs b/ctr-std/src/sys_common/poison.rs deleted file mode 100644 index 1625efe..0000000 --- a/ctr-std/src/sys_common/poison.rs +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use error::{Error}; -use fmt; -use sync::atomic::{AtomicBool, Ordering}; -use thread; - -pub struct Flag { failed: AtomicBool } - -// Note that the Ordering uses to access the `failed` field of `Flag` below is -// always `Relaxed`, and that's because this isn't actually protecting any data, -// it's just a flag whether we've panicked or not. -// -// The actual location that this matters is when a mutex is **locked** which is -// where we have external synchronization ensuring that we see memory -// reads/writes to this flag. -// -// As a result, if it matters, we should see the correct value for `failed` in -// all cases. - -impl Flag { - pub const fn new() -> Flag { - Flag { failed: AtomicBool::new(false) } - } - - #[inline] - pub fn borrow(&self) -> LockResult { - let ret = Guard { panicking: thread::panicking() }; - if self.get() { - Err(PoisonError::new(ret)) - } else { - Ok(ret) - } - } - - #[inline] - pub fn done(&self, guard: &Guard) { - if !guard.panicking && thread::panicking() { - self.failed.store(true, Ordering::Relaxed); - } - } - - #[inline] - pub fn get(&self) -> bool { - self.failed.load(Ordering::Relaxed) - } -} - -pub struct Guard { - panicking: bool, -} - -/// A type of error which can be returned whenever a lock is acquired. -/// -/// Both [`Mutex`]es and [`RwLock`]s are poisoned whenever a thread fails while the lock -/// is held. The precise semantics for when a lock is poisoned is documented on -/// each lock, but once a lock is poisoned then all future acquisitions will -/// return this error. -/// -/// # Examples -/// -/// ``` -/// use std::sync::{Arc, Mutex}; -/// use std::thread; -/// -/// let mutex = Arc::new(Mutex::new(1)); -/// -/// // poison the mutex -/// let c_mutex = mutex.clone(); -/// let _ = thread::spawn(move || { -/// let mut data = c_mutex.lock().unwrap(); -/// *data = 2; -/// panic!(); -/// }).join(); -/// -/// match mutex.lock() { -/// Ok(_) => unreachable!(), -/// Err(p_err) => { -/// let data = p_err.get_ref(); -/// println!("recovered: {}", data); -/// } -/// }; -/// ``` -/// -/// [`Mutex`]: ../../std/sync/struct.Mutex.html -/// [`RwLock`]: ../../std/sync/struct.RwLock.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct PoisonError { - guard: T, -} - -/// An enumeration of possible errors associated with a [`TryLockResult`] which -/// can occur while trying to acquire a lock, from the [`try_lock`] method on a -/// [`Mutex`] or the [`try_read`] and [`try_write`] methods on an [`RwLock`]. -/// -/// [`Mutex`]: struct.Mutex.html -/// [`RwLock`]: struct.RwLock.html -/// [`TryLockResult`]: type.TryLockResult.html -/// [`try_lock`]: struct.Mutex.html#method.try_lock -/// [`try_read`]: struct.RwLock.html#method.try_read -/// [`try_write`]: struct.RwLock.html#method.try_write -#[stable(feature = "rust1", since = "1.0.0")] -pub enum TryLockError { - /// The lock could not be acquired because another thread failed while holding - /// the lock. - #[stable(feature = "rust1", since = "1.0.0")] - Poisoned(#[stable(feature = "rust1", since = "1.0.0")] PoisonError), - /// The lock could not be acquired at this time because the operation would - /// otherwise block. - #[stable(feature = "rust1", since = "1.0.0")] - WouldBlock, -} - -/// A type alias for the result of a lock method which can be poisoned. -/// -/// The [`Ok`] variant of this result indicates that the primitive was not -/// poisoned, and the `Guard` is contained within. The [`Err`] variant indicates -/// that the primitive was poisoned. Note that the [`Err`] variant *also* carries -/// the associated guard, and it can be acquired through the [`into_inner`] -/// method. -/// -/// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok -/// [`Err`]: ../../std/result/enum.Result.html#variant.Err -/// [`into_inner`]: ../../std/sync/struct.PoisonError.html#method.into_inner -#[stable(feature = "rust1", since = "1.0.0")] -pub type LockResult = Result>; - -/// A type alias for the result of a nonblocking locking method. -/// -/// For more information, see [`LockResult`]. A `TryLockResult` doesn't -/// necessarily hold the associated guard in the [`Err`] type as the lock may not -/// have been acquired for other reasons. -/// -/// [`LockResult`]: ../../std/sync/type.LockResult.html -/// [`Err`]: ../../std/result/enum.Result.html#variant.Err -#[stable(feature = "rust1", since = "1.0.0")] -pub type TryLockResult = Result>; - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for PoisonError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "PoisonError { inner: .. }".fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for PoisonError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "poisoned lock: another task failed inside".fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for PoisonError { - fn description(&self) -> &str { - "poisoned lock: another task failed inside" - } -} - -impl PoisonError { - /// Creates a `PoisonError`. - /// - /// This is generally created by methods like [`Mutex::lock`] or [`RwLock::read`]. - /// - /// [`Mutex::lock`]: ../../std/sync/struct.Mutex.html#method.lock - /// [`RwLock::read`]: ../../std/sync/struct.RwLock.html#method.read - #[stable(feature = "sync_poison", since = "1.2.0")] - pub fn new(guard: T) -> PoisonError { - PoisonError { guard: guard } - } - - /// Consumes this error indicating that a lock is poisoned, returning the - /// underlying guard to allow access regardless. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// use std::sync::{Arc, Mutex}; - /// use std::thread; - /// - /// let mutex = Arc::new(Mutex::new(HashSet::new())); - /// - /// // poison the mutex - /// let c_mutex = mutex.clone(); - /// let _ = thread::spawn(move || { - /// let mut data = c_mutex.lock().unwrap(); - /// data.insert(10); - /// panic!(); - /// }).join(); - /// - /// let p_err = mutex.lock().unwrap_err(); - /// let data = p_err.into_inner(); - /// println!("recovered {} items", data.len()); - /// ``` - #[stable(feature = "sync_poison", since = "1.2.0")] - pub fn into_inner(self) -> T { self.guard } - - /// Reaches into this error indicating that a lock is poisoned, returning a - /// reference to the underlying guard to allow access regardless. - #[stable(feature = "sync_poison", since = "1.2.0")] - pub fn get_ref(&self) -> &T { &self.guard } - - /// Reaches into this error indicating that a lock is poisoned, returning a - /// mutable reference to the underlying guard to allow access regardless. - #[stable(feature = "sync_poison", since = "1.2.0")] - pub fn get_mut(&mut self) -> &mut T { &mut self.guard } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl From> for TryLockError { - fn from(err: PoisonError) -> TryLockError { - TryLockError::Poisoned(err) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for TryLockError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - TryLockError::Poisoned(..) => "Poisoned(..)".fmt(f), - TryLockError::WouldBlock => "WouldBlock".fmt(f) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for TryLockError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - TryLockError::Poisoned(..) => "poisoned lock: another task failed inside", - TryLockError::WouldBlock => "try_lock failed because the operation would block" - }.fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for TryLockError { - fn description(&self) -> &str { - match *self { - TryLockError::Poisoned(ref p) => p.description(), - TryLockError::WouldBlock => "try_lock failed because the operation would block" - } - } - - fn cause(&self) -> Option<&dyn Error> { - match *self { - TryLockError::Poisoned(ref p) => Some(p), - _ => None - } - } -} - -pub fn map_result(result: LockResult, f: F) - -> LockResult - where F: FnOnce(T) -> U { - match result { - Ok(t) => Ok(f(t)), - Err(PoisonError { guard }) => Err(PoisonError::new(f(guard))) - } -} diff --git a/ctr-std/src/sys_common/process.rs b/ctr-std/src/sys_common/process.rs deleted file mode 100644 index ddf0ebe..0000000 --- a/ctr-std/src/sys_common/process.rs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] -#![unstable(feature = "process_internals", issue = "0")] - -use ffi::{OsStr, OsString}; -use env; -use collections::BTreeMap; -use borrow::Borrow; - -pub trait EnvKey: - From + Into + - Borrow + Borrow + AsRef + - Ord + Clone {} - -// Implement a case-sensitive environment variable key -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub struct DefaultEnvKey(OsString); - -impl From for DefaultEnvKey { - fn from(k: OsString) -> Self { DefaultEnvKey(k) } -} - -impl From for OsString { - fn from(k: DefaultEnvKey) -> Self { k.0 } -} - -impl Borrow for DefaultEnvKey { - fn borrow(&self) -> &OsStr { &self.0 } -} - -impl AsRef for DefaultEnvKey { - fn as_ref(&self) -> &OsStr { &self.0 } -} - -impl EnvKey for DefaultEnvKey {} - -// Stores a set of changes to an environment -#[derive(Clone, Debug)] -pub struct CommandEnv { - clear: bool, - saw_path: bool, - vars: BTreeMap> -} - -impl Default for CommandEnv { - fn default() -> Self { - CommandEnv { - clear: false, - saw_path: false, - vars: Default::default() - } - } -} - -impl CommandEnv { - // Capture the current environment with these changes applied - pub fn capture(&self) -> BTreeMap { - let mut result = BTreeMap::::new(); - if !self.clear { - for (k, v) in env::vars_os() { - result.insert(k.into(), v); - } - } - for (k, maybe_v) in &self.vars { - if let &Some(ref v) = maybe_v { - result.insert(k.clone(), v.clone()); - } else { - result.remove(k); - } - } - result - } - - // Apply these changes directly to the current environment - pub fn apply(&self) { - if self.clear { - for (k, _) in env::vars_os() { - env::remove_var(k); - } - } - for (key, maybe_val) in self.vars.iter() { - if let &Some(ref val) = maybe_val { - env::set_var(key, val); - } else { - env::remove_var(key); - } - } - } - - pub fn is_unchanged(&self) -> bool { - !self.clear && self.vars.is_empty() - } - - pub fn capture_if_changed(&self) -> Option> { - if self.is_unchanged() { - None - } else { - Some(self.capture()) - } - } - - // The following functions build up changes - pub fn set(&mut self, key: &OsStr, value: &OsStr) { - self.maybe_saw_path(&key); - self.vars.insert(key.to_owned().into(), Some(value.to_owned())); - } - pub fn remove(&mut self, key: &OsStr) { - self.maybe_saw_path(&key); - if self.clear { - self.vars.remove(key); - } else { - self.vars.insert(key.to_owned().into(), None); - } - } - pub fn clear(&mut self) { - self.clear = true; - self.vars.clear(); - } - pub fn have_changed_path(&self) -> bool { - self.saw_path || self.clear - } - fn maybe_saw_path(&mut self, key: &OsStr) { - if !self.saw_path && key == "PATH" { - self.saw_path = true; - } - } -} diff --git a/ctr-std/src/sys_common/remutex.rs b/ctr-std/src/sys_common/remutex.rs deleted file mode 100644 index 071a3a2..0000000 --- a/ctr-std/src/sys_common/remutex.rs +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use fmt; -use marker; -use ops::Deref; -use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; -use sys::mutex as sys; -use panic::{UnwindSafe, RefUnwindSafe}; - -/// A re-entrant mutual exclusion -/// -/// This mutex will block *other* threads waiting for the lock to become -/// available. The thread which has already locked the mutex can lock it -/// multiple times without blocking, preventing a common source of deadlocks. -pub struct ReentrantMutex { - inner: Box, - poison: poison::Flag, - data: T, -} - -unsafe impl Send for ReentrantMutex {} -unsafe impl Sync for ReentrantMutex {} - -impl UnwindSafe for ReentrantMutex {} -impl RefUnwindSafe for ReentrantMutex {} - - -/// An RAII implementation of a "scoped lock" of a mutex. When this structure is -/// dropped (falls out of scope), the lock will be unlocked. -/// -/// The data protected by the mutex can be accessed through this guard via its -/// Deref implementation. -/// -/// # Mutability -/// -/// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`, -/// because implementation of the trait would violate Rust’s reference aliasing -/// rules. Use interior mutability (usually `RefCell`) in order to mutate the -/// guarded data. -#[must_use = "if unused the ReentrantMutex will immediately unlock"] -pub struct ReentrantMutexGuard<'a, T: 'a> { - // funny underscores due to how Deref currently works (it disregards field - // privacy). - __lock: &'a ReentrantMutex, - __poison: poison::Guard, -} - -impl<'a, T> !marker::Send for ReentrantMutexGuard<'a, T> {} - - -impl ReentrantMutex { - /// Creates a new reentrant mutex in an unlocked state. - pub fn new(t: T) -> ReentrantMutex { - unsafe { - let mut mutex = ReentrantMutex { - inner: box sys::ReentrantMutex::uninitialized(), - poison: poison::Flag::new(), - data: t, - }; - mutex.inner.init(); - mutex - } - } - - /// Acquires a mutex, blocking the current thread until it is able to do so. - /// - /// This function will block the caller until it is available to acquire the mutex. - /// Upon returning, the thread is the only thread with the mutex held. When the thread - /// calling this method already holds the lock, the call shall succeed without - /// blocking. - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return failure if the mutex would otherwise be - /// acquired. - pub fn lock(&self) -> LockResult> { - unsafe { self.inner.lock() } - ReentrantMutexGuard::new(&self) - } - - /// Attempts to acquire this lock. - /// - /// If the lock could not be acquired at this time, then `Err` is returned. - /// Otherwise, an RAII guard is returned. - /// - /// This function does not block. - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return failure if the mutex would otherwise be - /// acquired. - pub fn try_lock(&self) -> TryLockResult> { - if unsafe { self.inner.try_lock() } { - Ok(ReentrantMutexGuard::new(&self)?) - } else { - Err(TryLockError::WouldBlock) - } - } -} - -impl Drop for ReentrantMutex { - fn drop(&mut self) { - // This is actually safe b/c we know that there is no further usage of - // this mutex (it's up to the user to arrange for a mutex to get - // dropped, that's not our job) - unsafe { self.inner.destroy() } - } -} - -impl fmt::Debug for ReentrantMutex { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.try_lock() { - Ok(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(), - Err(TryLockError::Poisoned(err)) => { - f.debug_struct("ReentrantMutex").field("data", &**err.get_ref()).finish() - }, - Err(TryLockError::WouldBlock) => { - struct LockedPlaceholder; - impl fmt::Debug for LockedPlaceholder { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } - } - - f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish() - } - } - } -} - -impl<'mutex, T> ReentrantMutexGuard<'mutex, T> { - fn new(lock: &'mutex ReentrantMutex) - -> LockResult> { - poison::map_result(lock.poison.borrow(), |guard| { - ReentrantMutexGuard { - __lock: lock, - __poison: guard, - } - }) - } -} - -impl<'mutex, T> Deref for ReentrantMutexGuard<'mutex, T> { - type Target = T; - - fn deref(&self) -> &T { - &self.__lock.data - } -} - -impl<'a, T> Drop for ReentrantMutexGuard<'a, T> { - #[inline] - fn drop(&mut self) { - unsafe { - self.__lock.poison.done(&self.__poison); - self.__lock.inner.unlock(); - } - } -} - - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; - use cell::RefCell; - use sync::Arc; - use thread; - - #[test] - fn smoke() { - let m = ReentrantMutex::new(()); - { - let a = m.lock().unwrap(); - { - let b = m.lock().unwrap(); - { - let c = m.lock().unwrap(); - assert_eq!(*c, ()); - } - assert_eq!(*b, ()); - } - assert_eq!(*a, ()); - } - } - - #[test] - fn is_mutex() { - let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); - let m2 = m.clone(); - let lock = m.lock().unwrap(); - let child = thread::spawn(move || { - let lock = m2.lock().unwrap(); - assert_eq!(*lock.borrow(), 4950); - }); - for i in 0..100 { - let lock = m.lock().unwrap(); - *lock.borrow_mut() += i; - } - drop(lock); - child.join().unwrap(); - } - - #[test] - fn trylock_works() { - let m = Arc::new(ReentrantMutex::new(())); - let m2 = m.clone(); - let _lock = m.try_lock().unwrap(); - let _lock2 = m.try_lock().unwrap(); - thread::spawn(move || { - let lock = m2.try_lock(); - assert!(lock.is_err()); - }).join().unwrap(); - let _lock3 = m.try_lock().unwrap(); - } - - pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>); - impl<'a> Drop for Answer<'a> { - fn drop(&mut self) { - *self.0.borrow_mut() = 42; - } - } - - #[test] - fn poison_works() { - let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); - let mc = m.clone(); - let result = thread::spawn(move ||{ - let lock = mc.lock().unwrap(); - *lock.borrow_mut() = 1; - let lock2 = mc.lock().unwrap(); - *lock.borrow_mut() = 2; - let _answer = Answer(lock2); - panic!("What the answer to my lifetimes dilemma is?"); - }).join(); - assert!(result.is_err()); - let r = m.lock().err().unwrap().into_inner(); - assert_eq!(*r.borrow(), 42); - } -} diff --git a/ctr-std/src/sys_common/rwlock.rs b/ctr-std/src/sys_common/rwlock.rs deleted file mode 100644 index 71a4f01..0000000 --- a/ctr-std/src/sys_common/rwlock.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use sys::rwlock as imp; - -/// An OS-based reader-writer lock. -/// -/// This structure is entirely unsafe and serves as the lowest layer of a -/// cross-platform binding of system rwlocks. It is recommended to use the -/// safer types at the top level of this crate instead of this type. -pub struct RWLock(imp::RWLock); - -impl RWLock { - /// Creates a new reader-writer lock for use. - /// - /// Behavior is undefined if the reader-writer lock is moved after it is - /// first used with any of the functions below. - pub const fn new() -> RWLock { RWLock(imp::RWLock::new()) } - - /// Acquires shared access to the underlying lock, blocking the current - /// thread to do so. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. - #[inline] - pub unsafe fn read(&self) { self.0.read() } - - /// Attempts to acquire shared access to this lock, returning whether it - /// succeeded or not. - /// - /// This function does not block the current thread. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. - #[inline] - pub unsafe fn try_read(&self) -> bool { self.0.try_read() } - - /// Acquires write access to the underlying lock, blocking the current thread - /// to do so. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. - #[inline] - pub unsafe fn write(&self) { self.0.write() } - - /// Attempts to acquire exclusive access to this lock, returning whether it - /// succeeded or not. - /// - /// This function does not block the current thread. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. - #[inline] - pub unsafe fn try_write(&self) -> bool { self.0.try_write() } - - /// Unlocks previously acquired shared access to this lock. - /// - /// Behavior is undefined if the current thread does not have shared access. - #[inline] - pub unsafe fn read_unlock(&self) { self.0.read_unlock() } - - /// Unlocks previously acquired exclusive access to this lock. - /// - /// Behavior is undefined if the current thread does not currently have - /// exclusive access. - #[inline] - pub unsafe fn write_unlock(&self) { self.0.write_unlock() } - - /// Destroys OS-related resources with this RWLock. - /// - /// Behavior is undefined if there are any currently active users of this - /// lock. - #[inline] - pub unsafe fn destroy(&self) { self.0.destroy() } -} diff --git a/ctr-std/src/sys_common/thread.rs b/ctr-std/src/sys_common/thread.rs deleted file mode 100644 index 86a5e2b..0000000 --- a/ctr-std/src/sys_common/thread.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use boxed::FnBox; -use env; -use sync::atomic::{self, Ordering}; -use sys::stack_overflow; -use sys::thread as imp; - -#[allow(dead_code)] -pub unsafe fn start_thread(main: *mut u8) { - // Next, set up our stack overflow handler which may get triggered if we run - // out of stack. - let _handler = stack_overflow::Handler::new(); - - // Finally, let's run some code. - Box::from_raw(main as *mut Box)() -} - -pub fn min_stack() -> usize { - static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0); - match MIN.load(Ordering::SeqCst) { - 0 => {} - n => return n - 1, - } - let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()); - let amt = amt.unwrap_or(imp::DEFAULT_MIN_STACK_SIZE); - - // 0 is our sentinel value, so ensure that we'll never see 0 after - // initialization has run - MIN.store(amt + 1, Ordering::SeqCst); - amt -} diff --git a/ctr-std/src/sys_common/thread_info.rs b/ctr-std/src/sys_common/thread_info.rs deleted file mode 100644 index 7970042..0000000 --- a/ctr-std/src/sys_common/thread_info.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] // stack_guard isn't used right now on all platforms - -use cell::RefCell; -use thread::Thread; - -struct ThreadInfo { - stack_guard: Option, - thread: Thread, -} - -thread_local! { static THREAD_INFO: RefCell> = RefCell::new(None) } - -impl ThreadInfo { - fn with(f: F) -> Option where F: FnOnce(&mut ThreadInfo) -> R { - THREAD_INFO.try_with(move |c| { - if c.borrow().is_none() { - *c.borrow_mut() = Some(ThreadInfo { - stack_guard: None, - thread: Thread::new(None), - }) - } - f(c.borrow_mut().as_mut().unwrap()) - }).ok() - } -} - -pub fn current_thread() -> Option { - ThreadInfo::with(|info| info.thread.clone()) -} - -pub fn stack_guard() -> Option { - ThreadInfo::with(|info| info.stack_guard).and_then(|o| o) -} - -pub fn set(stack_guard: Option, thread: Thread) { - THREAD_INFO.with(|c| assert!(c.borrow().is_none())); - THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ - stack_guard, - thread, - })); -} diff --git a/ctr-std/src/sys_common/thread_local.rs b/ctr-std/src/sys_common/thread_local.rs deleted file mode 100644 index bb72cb0..0000000 --- a/ctr-std/src/sys_common/thread_local.rs +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! OS-based thread local storage -//! -//! This module provides an implementation of OS-based thread local storage, -//! using the native OS-provided facilities (think `TlsAlloc` or -//! `pthread_setspecific`). The interface of this differs from the other types -//! of thread-local-storage provided in this crate in that OS-based TLS can only -//! get/set pointers, -//! -//! This module also provides two flavors of TLS. One is intended for static -//! initialization, and does not contain a `Drop` implementation to deallocate -//! the OS-TLS key. The other is a type which does implement `Drop` and hence -//! has a safe interface. -//! -//! # Usage -//! -//! This module should likely not be used directly unless other primitives are -//! being built on. types such as `thread_local::spawn::Key` are likely much -//! more useful in practice than this OS-based version which likely requires -//! unsafe code to interoperate with. -//! -//! # Examples -//! -//! Using a dynamically allocated TLS key. Note that this key can be shared -//! among many threads via an `Arc`. -//! -//! ```ignore (cannot-doctest-private-modules) -//! let key = Key::new(None); -//! assert!(key.get().is_null()); -//! key.set(1 as *mut u8); -//! assert!(!key.get().is_null()); -//! -//! drop(key); // deallocate this TLS slot. -//! ``` -//! -//! Sometimes a statically allocated key is either required or easier to work -//! with, however. -//! -//! ```ignore (cannot-doctest-private-modules) -//! static KEY: StaticKey = INIT; -//! -//! unsafe { -//! assert!(KEY.get().is_null()); -//! KEY.set(1 as *mut u8); -//! } -//! ``` - -#![allow(non_camel_case_types)] -#![unstable(feature = "thread_local_internals", issue = "0")] -#![allow(dead_code)] // sys isn't exported yet - -use ptr; -use sync::atomic::{self, AtomicUsize, Ordering}; -use sys::thread_local as imp; -use sys_common::mutex::Mutex; - -/// A type for TLS keys that are statically allocated. -/// -/// This type is entirely `unsafe` to use as it does not protect against -/// use-after-deallocation or use-during-deallocation. -/// -/// The actual OS-TLS key is lazily allocated when this is used for the first -/// time. The key is also deallocated when the Rust runtime exits or `destroy` -/// is called, whichever comes first. -/// -/// # Examples -/// -/// ```ignore (cannot-doctest-private-modules) -/// use tls::os::{StaticKey, INIT}; -/// -/// static KEY: StaticKey = INIT; -/// -/// unsafe { -/// assert!(KEY.get().is_null()); -/// KEY.set(1 as *mut u8); -/// } -/// ``` -pub struct StaticKey { - /// Inner static TLS key (internals). - key: AtomicUsize, - /// Destructor for the TLS value. - /// - /// See `Key::new` for information about when the destructor runs and how - /// it runs. - dtor: Option, -} - -/// A type for a safely managed OS-based TLS slot. -/// -/// This type allocates an OS TLS key when it is initialized and will deallocate -/// the key when it falls out of scope. When compared with `StaticKey`, this -/// type is entirely safe to use. -/// -/// Implementations will likely, however, contain unsafe code as this type only -/// operates on `*mut u8`, a raw pointer. -/// -/// # Examples -/// -/// ```ignore (cannot-doctest-private-modules) -/// use tls::os::Key; -/// -/// let key = Key::new(None); -/// assert!(key.get().is_null()); -/// key.set(1 as *mut u8); -/// assert!(!key.get().is_null()); -/// -/// drop(key); // deallocate this TLS slot. -/// ``` -pub struct Key { - key: imp::Key, -} - -/// Constant initialization value for static TLS keys. -/// -/// This value specifies no destructor by default. -pub const INIT: StaticKey = StaticKey::new(None); - -impl StaticKey { - pub const fn new(dtor: Option) -> StaticKey { - StaticKey { - key: atomic::AtomicUsize::new(0), - dtor, - } - } - - /// Gets the value associated with this TLS key - /// - /// This will lazily allocate a TLS key from the OS if one has not already - /// been allocated. - #[inline] - pub unsafe fn get(&self) -> *mut u8 { imp::get(self.key()) } - - /// Sets this TLS key to a new value. - /// - /// This will lazily allocate a TLS key from the OS if one has not already - /// been allocated. - #[inline] - pub unsafe fn set(&self, val: *mut u8) { imp::set(self.key(), val) } - - #[inline] - unsafe fn key(&self) -> imp::Key { - match self.key.load(Ordering::Relaxed) { - 0 => self.lazy_init() as imp::Key, - n => n as imp::Key - } - } - - unsafe fn lazy_init(&self) -> usize { - // Currently the Windows implementation of TLS is pretty hairy, and - // it greatly simplifies creation if we just synchronize everything. - // - // Additionally a 0-index of a tls key hasn't been seen on windows, so - // we just simplify the whole branch. - if imp::requires_synchronized_create() { - // We never call `INIT_LOCK.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static INIT_LOCK: Mutex = Mutex::new(); - let _guard = INIT_LOCK.lock(); - let mut key = self.key.load(Ordering::SeqCst); - if key == 0 { - key = imp::create(self.dtor) as usize; - self.key.store(key, Ordering::SeqCst); - } - rtassert!(key != 0); - return key - } - - // POSIX allows the key created here to be 0, but the compare_and_swap - // below relies on using 0 as a sentinel value to check who won the - // race to set the shared TLS key. As far as I know, there is no - // guaranteed value that cannot be returned as a posix_key_create key, - // so there is no value we can initialize the inner key with to - // prove that it has not yet been set. As such, we'll continue using a - // value of 0, but with some gyrations to make sure we have a non-0 - // value returned from the creation routine. - // FIXME: this is clearly a hack, and should be cleaned up. - let key1 = imp::create(self.dtor); - let key = if key1 != 0 { - key1 - } else { - let key2 = imp::create(self.dtor); - imp::destroy(key1); - key2 - }; - rtassert!(key != 0); - match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) { - // The CAS succeeded, so we've created the actual key - 0 => key as usize, - // If someone beat us to the punch, use their key instead - n => { imp::destroy(key); n } - } - } -} - -impl Key { - /// Creates a new managed OS TLS key. - /// - /// This key will be deallocated when the key falls out of scope. - /// - /// The argument provided is an optionally-specified destructor for the - /// value of this TLS key. When a thread exits and the value for this key - /// is non-null the destructor will be invoked. The TLS value will be reset - /// to null before the destructor is invoked. - /// - /// Note that the destructor will not be run when the `Key` goes out of - /// scope. - #[inline] - pub fn new(dtor: Option) -> Key { - Key { key: unsafe { imp::create(dtor) } } - } - - /// See StaticKey::get - #[inline] - pub fn get(&self) -> *mut u8 { - unsafe { imp::get(self.key) } - } - - /// See StaticKey::set - #[inline] - pub fn set(&self, val: *mut u8) { - unsafe { imp::set(self.key, val) } - } -} - -impl Drop for Key { - fn drop(&mut self) { - // Right now Windows doesn't support TLS key destruction, but this also - // isn't used anywhere other than tests, so just leak the TLS key. - // unsafe { imp::destroy(self.key) } - } -} - -pub unsafe fn register_dtor_fallback(t: *mut u8, - dtor: unsafe extern fn(*mut u8)) { - // The fallback implementation uses a vanilla OS-based TLS key to track - // the list of destructors that need to be run for this thread. The key - // then has its own destructor which runs all the other destructors. - // - // The destructor for DTORS is a little special in that it has a `while` - // loop to continuously drain the list of registered destructors. It - // *should* be the case that this loop always terminates because we - // provide the guarantee that a TLS key cannot be set after it is - // flagged for destruction. - - static DTORS: StaticKey = StaticKey::new(Some(run_dtors)); - type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; - if DTORS.get().is_null() { - let v: Box = box Vec::new(); - DTORS.set(Box::into_raw(v) as *mut u8); - } - let list: &mut List = &mut *(DTORS.get() as *mut List); - list.push((t, dtor)); - - unsafe extern fn run_dtors(mut ptr: *mut u8) { - while !ptr.is_null() { - let list: Box = Box::from_raw(ptr as *mut List); - for (ptr, dtor) in list.into_iter() { - dtor(ptr); - } - ptr = DTORS.get(); - DTORS.set(ptr::null_mut()); - } - } -} - -#[cfg(test)] -mod tests { - use super::{Key, StaticKey}; - - fn assert_sync() {} - fn assert_send() {} - - #[test] - fn smoke() { - assert_sync::(); - assert_send::(); - - let k1 = Key::new(None); - let k2 = Key::new(None); - assert!(k1.get().is_null()); - assert!(k2.get().is_null()); - k1.set(1 as *mut _); - k2.set(2 as *mut _); - assert_eq!(k1.get() as usize, 1); - assert_eq!(k2.get() as usize, 2); - } - - #[test] - fn statik() { - static K1: StaticKey = StaticKey::new(None); - static K2: StaticKey = StaticKey::new(None); - - unsafe { - assert!(K1.get().is_null()); - assert!(K2.get().is_null()); - K1.set(1 as *mut _); - K2.set(2 as *mut _); - assert_eq!(K1.get() as usize, 1); - assert_eq!(K2.get() as usize, 2); - } - } -} diff --git a/ctr-std/src/sys_common/util.rs b/ctr-std/src/sys_common/util.rs deleted file mode 100644 index a373e98..0000000 --- a/ctr-std/src/sys_common/util.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use fmt; -use io::prelude::*; -use sys::stdio::{Stderr, stderr_prints_nothing}; -use thread; - -pub fn dumb_print(args: fmt::Arguments) { - if stderr_prints_nothing() { - return - } - let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args)); -} - -// Other platforms should use the appropriate platform-specific mechanism for -// aborting the process. If no platform-specific mechanism is available, -// ::intrinsics::abort() may be used instead. The above implementations cover -// all targets currently supported by libstd. - -pub fn abort(args: fmt::Arguments) -> ! { - dumb_print(format_args!("fatal runtime error: {}\n", args)); - unsafe { ::sys::abort_internal(); } -} - -#[allow(dead_code)] // stack overflow detection not enabled on all platforms -pub unsafe fn report_overflow() { - dumb_print(format_args!("\nthread '{}' has overflowed its stack\n", - thread::current().name().unwrap_or(""))); -} diff --git a/ctr-std/src/sys_common/wtf8.rs b/ctr-std/src/sys_common/wtf8.rs deleted file mode 100644 index 45204b5..0000000 --- a/ctr-std/src/sys_common/wtf8.rs +++ /dev/null @@ -1,1267 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation of [the WTF-8 encoding](https://simonsapin.github.io/wtf-8/). -//! -//! This library uses Rust’s type system to maintain -//! [well-formedness](https://simonsapin.github.io/wtf-8/#well-formed), -//! like the `String` and `&str` types do for UTF-8. -//! -//! Since [WTF-8 must not be used -//! for interchange](https://simonsapin.github.io/wtf-8/#intended-audience), -//! this library deliberately does not provide access to the underlying bytes -//! of WTF-8 strings, -//! nor can it decode WTF-8 from arbitrary bytes. -//! WTF-8 strings can be obtained from UTF-8, UTF-16, or code points. - -// this module is imported from @SimonSapin's repo and has tons of dead code on -// unix (it's mostly used on windows), so don't worry about dead code here. -#![allow(dead_code)] - -use core::str::next_code_point; - -use borrow::Cow; -use char; -use fmt; -use hash::{Hash, Hasher}; -use iter::FromIterator; -use mem; -use ops; -use rc::Rc; -use slice; -use str; -use sync::Arc; -use sys_common::AsInner; - -const UTF8_REPLACEMENT_CHARACTER: &'static str = "\u{FFFD}"; - -/// A Unicode code point: from U+0000 to U+10FFFF. -/// -/// Compare with the `char` type, -/// which represents a Unicode scalar value: -/// a code point that is not a surrogate (U+D800 to U+DFFF). -#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] -pub struct CodePoint { - value: u32 -} - -/// Format the code point as `U+` followed by four to six hexadecimal digits. -/// Example: `U+1F4A9` -impl fmt::Debug for CodePoint { - #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "U+{:04X}", self.value) - } -} - -impl CodePoint { - /// Unsafely creates a new `CodePoint` without checking the value. - /// - /// Only use when `value` is known to be less than or equal to 0x10FFFF. - #[inline] - pub unsafe fn from_u32_unchecked(value: u32) -> CodePoint { - CodePoint { value: value } - } - - /// Creates a new `CodePoint` if the value is a valid code point. - /// - /// Returns `None` if `value` is above 0x10FFFF. - #[inline] - pub fn from_u32(value: u32) -> Option { - match value { - 0 ..= 0x10FFFF => Some(CodePoint { value: value }), - _ => None - } - } - - /// Creates a new `CodePoint` from a `char`. - /// - /// Since all Unicode scalar values are code points, this always succeeds. - #[inline] - pub fn from_char(value: char) -> CodePoint { - CodePoint { value: value as u32 } - } - - /// Returns the numeric value of the code point. - #[inline] - pub fn to_u32(&self) -> u32 { - self.value - } - - /// Optionally returns a Unicode scalar value for the code point. - /// - /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF). - #[inline] - pub fn to_char(&self) -> Option { - match self.value { - 0xD800 ..= 0xDFFF => None, - _ => Some(unsafe { char::from_u32_unchecked(self.value) }) - } - } - - /// Returns a Unicode scalar value for the code point. - /// - /// Returns `'\u{FFFD}'` (the replacement character “�”) - /// if the code point is a surrogate (from U+D800 to U+DFFF). - #[inline] - pub fn to_char_lossy(&self) -> char { - self.to_char().unwrap_or('\u{FFFD}') - } -} - -/// An owned, growable string of well-formed WTF-8 data. -/// -/// Similar to `String`, but can additionally contain surrogate code points -/// if they’re not in a surrogate pair. -#[derive(Eq, PartialEq, Ord, PartialOrd, Clone)] -pub struct Wtf8Buf { - bytes: Vec -} - -impl ops::Deref for Wtf8Buf { - type Target = Wtf8; - - fn deref(&self) -> &Wtf8 { - self.as_slice() - } -} - -impl ops::DerefMut for Wtf8Buf { - fn deref_mut(&mut self) -> &mut Wtf8 { - self.as_mut_slice() - } -} - -/// Format the string with double quotes, -/// and surrogates as `\u` followed by four hexadecimal digits. -/// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800] -impl fmt::Debug for Wtf8Buf { - #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&**self, formatter) - } -} - -impl Wtf8Buf { - /// Creates a new, empty WTF-8 string. - #[inline] - pub fn new() -> Wtf8Buf { - Wtf8Buf { bytes: Vec::new() } - } - - /// Creates a new, empty WTF-8 string with pre-allocated capacity for `n` bytes. - #[inline] - pub fn with_capacity(n: usize) -> Wtf8Buf { - Wtf8Buf { bytes: Vec::with_capacity(n) } - } - - /// Creates a WTF-8 string from a UTF-8 `String`. - /// - /// This takes ownership of the `String` and does not copy. - /// - /// Since WTF-8 is a superset of UTF-8, this always succeeds. - #[inline] - pub fn from_string(string: String) -> Wtf8Buf { - Wtf8Buf { bytes: string.into_bytes() } - } - - /// Creates a WTF-8 string from a UTF-8 `&str` slice. - /// - /// This copies the content of the slice. - /// - /// Since WTF-8 is a superset of UTF-8, this always succeeds. - #[inline] - pub fn from_str(str: &str) -> Wtf8Buf { - Wtf8Buf { bytes: <[_]>::to_vec(str.as_bytes()) } - } - - pub fn clear(&mut self) { - self.bytes.clear() - } - - /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units. - /// - /// This is lossless: calling `.encode_wide()` on the resulting string - /// will always return the original code units. - pub fn from_wide(v: &[u16]) -> Wtf8Buf { - let mut string = Wtf8Buf::with_capacity(v.len()); - for item in char::decode_utf16(v.iter().cloned()) { - match item { - Ok(ch) => string.push_char(ch), - Err(surrogate) => { - let surrogate = surrogate.unpaired_surrogate(); - // Surrogates are known to be in the code point range. - let code_point = unsafe { - CodePoint::from_u32_unchecked(surrogate as u32) - }; - // Skip the WTF-8 concatenation check, - // surrogate pairs are already decoded by decode_utf16 - string.push_code_point_unchecked(code_point) - } - } - } - string - } - - /// Copied from String::push - /// This does **not** include the WTF-8 concatenation check. - fn push_code_point_unchecked(&mut self, code_point: CodePoint) { - let c = unsafe { - char::from_u32_unchecked(code_point.value) - }; - let mut bytes = [0; 4]; - let bytes = c.encode_utf8(&mut bytes).as_bytes(); - self.bytes.extend_from_slice(bytes) - } - - #[inline] - pub fn as_slice(&self) -> &Wtf8 { - unsafe { Wtf8::from_bytes_unchecked(&self.bytes) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut Wtf8 { - unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) } - } - - /// Reserves capacity for at least `additional` more bytes to be inserted - /// in the given `Wtf8Buf`. - /// The collection may reserve more space to avoid frequent reallocations. - /// - /// # Panics - /// - /// Panics if the new capacity overflows `usize`. - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.bytes.reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.bytes.reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.bytes.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.bytes.shrink_to(min_capacity) - } - - /// Returns the number of bytes that this string buffer can hold without reallocating. - #[inline] - pub fn capacity(&self) -> usize { - self.bytes.capacity() - } - - /// Append a UTF-8 slice at the end of the string. - #[inline] - pub fn push_str(&mut self, other: &str) { - self.bytes.extend_from_slice(other.as_bytes()) - } - - /// Append a WTF-8 slice at the end of the string. - /// - /// This replaces newly paired surrogates at the boundary - /// with a supplementary code point, - /// like concatenating ill-formed UTF-16 strings effectively would. - #[inline] - pub fn push_wtf8(&mut self, other: &Wtf8) { - match ((&*self).final_lead_surrogate(), other.initial_trail_surrogate()) { - // Replace newly paired surrogates by a supplementary code point. - (Some(lead), Some(trail)) => { - let len_without_lead_surrogate = self.len() - 3; - self.bytes.truncate(len_without_lead_surrogate); - let other_without_trail_surrogate = &other.bytes[3..]; - // 4 bytes for the supplementary code point - self.bytes.reserve(4 + other_without_trail_surrogate.len()); - self.push_char(decode_surrogate_pair(lead, trail)); - self.bytes.extend_from_slice(other_without_trail_surrogate); - } - _ => self.bytes.extend_from_slice(&other.bytes) - } - } - - /// Append a Unicode scalar value at the end of the string. - #[inline] - pub fn push_char(&mut self, c: char) { - self.push_code_point_unchecked(CodePoint::from_char(c)) - } - - /// Append a code point at the end of the string. - /// - /// This replaces newly paired surrogates at the boundary - /// with a supplementary code point, - /// like concatenating ill-formed UTF-16 strings effectively would. - #[inline] - pub fn push(&mut self, code_point: CodePoint) { - if let trail @ 0xDC00..=0xDFFF = code_point.to_u32() { - if let Some(lead) = (&*self).final_lead_surrogate() { - let len_without_lead_surrogate = self.len() - 3; - self.bytes.truncate(len_without_lead_surrogate); - self.push_char(decode_surrogate_pair(lead, trail as u16)); - return - } - } - - // No newly paired surrogates at the boundary. - self.push_code_point_unchecked(code_point) - } - - /// Shortens a string to the specified length. - /// - /// # Panics - /// - /// Panics if `new_len` > current length, - /// or if `new_len` is not a code point boundary. - #[inline] - pub fn truncate(&mut self, new_len: usize) { - assert!(is_code_point_boundary(self, new_len)); - self.bytes.truncate(new_len) - } - - /// Consumes the WTF-8 string and tries to convert it to UTF-8. - /// - /// This does not copy the data. - /// - /// If the contents are not well-formed UTF-8 - /// (that is, if the string contains surrogates), - /// the original WTF-8 string is returned instead. - pub fn into_string(self) -> Result { - match self.next_surrogate(0) { - None => Ok(unsafe { String::from_utf8_unchecked(self.bytes) }), - Some(_) => Err(self), - } - } - - /// Consumes the WTF-8 string and converts it lossily to UTF-8. - /// - /// This does not copy the data (but may overwrite parts of it in place). - /// - /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”) - pub fn into_string_lossy(mut self) -> String { - let mut pos = 0; - loop { - match self.next_surrogate(pos) { - Some((surrogate_pos, _)) => { - pos = surrogate_pos + 3; - self.bytes[surrogate_pos..pos] - .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); - }, - None => return unsafe { String::from_utf8_unchecked(self.bytes) } - } - } - } - - /// Converts this `Wtf8Buf` into a boxed `Wtf8`. - #[inline] - pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.bytes.into_boxed_slice()) } - } - - /// Converts a `Box` into a `Wtf8Buf`. - pub fn from_box(boxed: Box) -> Wtf8Buf { - let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Wtf8Buf { bytes: bytes.into_vec() } - } -} - -/// Create a new WTF-8 string from an iterator of code points. -/// -/// This replaces surrogate code point pairs with supplementary code points, -/// like concatenating ill-formed UTF-16 strings effectively would. -impl FromIterator for Wtf8Buf { - fn from_iter>(iter: T) -> Wtf8Buf { - let mut string = Wtf8Buf::new(); - string.extend(iter); - string - } -} - -/// Append code points from an iterator to the string. -/// -/// This replaces surrogate code point pairs with supplementary code points, -/// like concatenating ill-formed UTF-16 strings effectively would. -impl Extend for Wtf8Buf { - fn extend>(&mut self, iter: T) { - let iterator = iter.into_iter(); - let (low, _high) = iterator.size_hint(); - // Lower bound of one byte per code point (ASCII only) - self.bytes.reserve(low); - for code_point in iterator { - self.push(code_point); - } - } -} - -/// A borrowed slice of well-formed WTF-8 data. -/// -/// Similar to `&str`, but can additionally contain surrogate code points -/// if they’re not in a surrogate pair. -#[derive(Eq, Ord, PartialEq, PartialOrd)] -pub struct Wtf8 { - bytes: [u8] -} - -impl AsInner<[u8]> for Wtf8 { - fn as_inner(&self) -> &[u8] { &self.bytes } -} - -/// Format the slice with double quotes, -/// and surrogates as `\u` followed by four hexadecimal digits. -/// Example: `"a\u{D800}"` for a slice with code points [U+0061, U+D800] -impl fmt::Debug for Wtf8 { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fn write_str_escaped(f: &mut fmt::Formatter, s: &str) -> fmt::Result { - use fmt::Write; - for c in s.chars().flat_map(|c| c.escape_debug()) { - f.write_char(c)? - } - Ok(()) - } - - formatter.write_str("\"")?; - let mut pos = 0; - while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) { - write_str_escaped( - formatter, - unsafe { str::from_utf8_unchecked( - &self.bytes[pos .. surrogate_pos] - )}, - )?; - write!(formatter, "\\u{{{:x}}}", surrogate)?; - pos = surrogate_pos + 3; - } - write_str_escaped( - formatter, - unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) }, - )?; - formatter.write_str("\"") - } -} - -impl fmt::Display for Wtf8 { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let wtf8_bytes = &self.bytes; - let mut pos = 0; - loop { - match self.next_surrogate(pos) { - Some((surrogate_pos, _)) => { - formatter.write_str(unsafe { - str::from_utf8_unchecked(&wtf8_bytes[pos .. surrogate_pos]) - })?; - formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?; - pos = surrogate_pos + 3; - }, - None => { - let s = unsafe { - str::from_utf8_unchecked(&wtf8_bytes[pos..]) - }; - if pos == 0 { - return s.fmt(formatter) - } else { - return formatter.write_str(s) - } - } - } - } - } -} - -impl Wtf8 { - /// Creates a WTF-8 slice from a UTF-8 `&str` slice. - /// - /// Since WTF-8 is a superset of UTF-8, this always succeeds. - #[inline] - pub fn from_str(value: &str) -> &Wtf8 { - unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) } - } - - /// Creates a WTF-8 slice from a WTF-8 byte slice. - /// - /// Since the byte slice is not checked for valid WTF-8, this functions is - /// marked unsafe. - #[inline] - unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { - mem::transmute(value) - } - - /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice. - /// - /// Since the byte slice is not checked for valid WTF-8, this functions is - /// marked unsafe. - #[inline] - unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { - mem::transmute(value) - } - - /// Returns the length, in WTF-8 bytes. - #[inline] - pub fn len(&self) -> usize { - self.bytes.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.bytes.is_empty() - } - - /// Returns the code point at `position` if it is in the ASCII range, - /// or `b'\xFF' otherwise. - /// - /// # Panics - /// - /// Panics if `position` is beyond the end of the string. - #[inline] - pub fn ascii_byte_at(&self, position: usize) -> u8 { - match self.bytes[position] { - ascii_byte @ 0x00 ..= 0x7F => ascii_byte, - _ => 0xFF - } - } - - /// Returns an iterator for the string’s code points. - #[inline] - pub fn code_points(&self) -> Wtf8CodePoints { - Wtf8CodePoints { bytes: self.bytes.iter() } - } - - /// Tries to convert the string to UTF-8 and return a `&str` slice. - /// - /// Returns `None` if the string contains surrogates. - /// - /// This does not copy the data. - #[inline] - pub fn as_str(&self) -> Option<&str> { - // Well-formed WTF-8 is also well-formed UTF-8 - // if and only if it contains no surrogate. - match self.next_surrogate(0) { - None => Some(unsafe { str::from_utf8_unchecked(&self.bytes) }), - Some(_) => None, - } - } - - /// Lossily converts the string to UTF-8. - /// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8. - /// - /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”). - /// - /// This only copies the data if necessary (if it contains any surrogate). - pub fn to_string_lossy(&self) -> Cow { - let surrogate_pos = match self.next_surrogate(0) { - None => return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }), - Some((pos, _)) => pos, - }; - let wtf8_bytes = &self.bytes; - let mut utf8_bytes = Vec::with_capacity(self.len()); - utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]); - utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); - let mut pos = surrogate_pos + 3; - loop { - match self.next_surrogate(pos) { - Some((surrogate_pos, _)) => { - utf8_bytes.extend_from_slice(&wtf8_bytes[pos .. surrogate_pos]); - utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); - pos = surrogate_pos + 3; - }, - None => { - utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]); - return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) }) - } - } - } - } - - /// Converts the WTF-8 string to potentially ill-formed UTF-16 - /// and return an iterator of 16-bit code units. - /// - /// This is lossless: - /// calling `Wtf8Buf::from_ill_formed_utf16` on the resulting code units - /// would always return the original WTF-8 string. - #[inline] - pub fn encode_wide(&self) -> EncodeWide { - EncodeWide { code_points: self.code_points(), extra: 0 } - } - - #[inline] - fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> { - let mut iter = self.bytes[pos..].iter(); - loop { - let b = *iter.next()?; - if b < 0x80 { - pos += 1; - } else if b < 0xE0 { - iter.next(); - pos += 2; - } else if b == 0xED { - match (iter.next(), iter.next()) { - (Some(&b2), Some(&b3)) if b2 >= 0xA0 => { - return Some((pos, decode_surrogate(b2, b3))) - } - _ => pos += 3 - } - } else if b < 0xF0 { - iter.next(); - iter.next(); - pos += 3; - } else { - iter.next(); - iter.next(); - iter.next(); - pos += 4; - } - } - } - - #[inline] - fn final_lead_surrogate(&self) -> Option { - let len = self.len(); - if len < 3 { - return None - } - match &self.bytes[(len - 3)..] { - &[0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), - _ => None - } - } - - #[inline] - fn initial_trail_surrogate(&self) -> Option { - let len = self.len(); - if len < 3 { - return None - } - match &self.bytes[..3] { - &[0xED, b2 @ 0xB0..=0xBF, b3] => Some(decode_surrogate(b2, b3)), - _ => None - } - } - - /// Boxes this `Wtf8`. - #[inline] - pub fn into_box(&self) -> Box { - let boxed: Box<[u8]> = self.bytes.into(); - unsafe { mem::transmute(boxed) } - } - - /// Creates a boxed, empty `Wtf8`. - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.bytes); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.bytes); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) } - } -} - - -/// Return a slice of the given string for the byte range [`begin`..`end`). -/// -/// # Panics -/// -/// Panics when `begin` and `end` do not point to code point boundaries, -/// or point beyond the end of the string. -impl ops::Index> for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, range: ops::Range) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] - if range.start <= range.end && - is_code_point_boundary(self, range.start) && - is_code_point_boundary(self, range.end) { - unsafe { slice_unchecked(self, range.start, range.end) } - } else { - slice_error_fail(self, range.start, range.end) - } - } -} - -/// Return a slice of the given string from byte `begin` to its end. -/// -/// # Panics -/// -/// Panics when `begin` is not at a code point boundary, -/// or is beyond the end of the string. -impl ops::Index> for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, range: ops::RangeFrom) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] - if is_code_point_boundary(self, range.start) { - unsafe { slice_unchecked(self, range.start, self.len()) } - } else { - slice_error_fail(self, range.start, self.len()) - } - } -} - -/// Return a slice of the given string from its beginning to byte `end`. -/// -/// # Panics -/// -/// Panics when `end` is not at a code point boundary, -/// or is beyond the end of the string. -impl ops::Index> for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, range: ops::RangeTo) -> &Wtf8 { - // is_code_point_boundary checks that the index is in [0, .len()] - if is_code_point_boundary(self, range.end) { - unsafe { slice_unchecked(self, 0, range.end) } - } else { - slice_error_fail(self, 0, range.end) - } - } -} - -impl ops::Index for Wtf8 { - type Output = Wtf8; - - #[inline] - fn index(&self, _range: ops::RangeFull) -> &Wtf8 { - self - } -} - -#[inline] -fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 { - // The first byte is assumed to be 0xED - 0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F -} - -#[inline] -fn decode_surrogate_pair(lead: u16, trail: u16) -> char { - let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32); - unsafe { char::from_u32_unchecked(code_point) } -} - -/// Copied from core::str::StrPrelude::is_char_boundary -#[inline] -pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool { - if index == slice.len() { return true; } - match slice.bytes.get(index) { - None => false, - Some(&b) => b < 128 || b >= 192, - } -} - -/// Copied from core::str::raw::slice_unchecked -#[inline] -pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { - // memory layout of an &[u8] and &Wtf8 are the same - Wtf8::from_bytes_unchecked(slice::from_raw_parts( - s.bytes.as_ptr().offset(begin as isize), - end - begin - )) -} - -/// Copied from core::str::raw::slice_error_fail -#[inline(never)] -pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! { - assert!(begin <= end); - panic!("index {} and/or {} in `{:?}` do not lie on character boundary", - begin, end, s); -} - -/// Iterator for the code points of a WTF-8 string. -/// -/// Created with the method `.code_points()`. -#[derive(Clone)] -pub struct Wtf8CodePoints<'a> { - bytes: slice::Iter<'a, u8> -} - -impl<'a> Iterator for Wtf8CodePoints<'a> { - type Item = CodePoint; - - #[inline] - fn next(&mut self) -> Option { - next_code_point(&mut self.bytes).map(|c| CodePoint { value: c }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.bytes.len(); - (len.saturating_add(3) / 4, Some(len)) - } -} - -/// Generates a wide character sequence for potentially ill-formed UTF-16. -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct EncodeWide<'a> { - code_points: Wtf8CodePoints<'a>, - extra: u16 -} - -// Copied from libunicode/u_str.rs -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for EncodeWide<'a> { - type Item = u16; - - #[inline] - fn next(&mut self) -> Option { - if self.extra != 0 { - let tmp = self.extra; - self.extra = 0; - return Some(tmp); - } - - let mut buf = [0; 2]; - self.code_points.next().map(|code_point| { - let c = unsafe { - char::from_u32_unchecked(code_point.value) - }; - let n = c.encode_utf16(&mut buf).len(); - if n == 2 { - self.extra = buf[1]; - } - buf[0] - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.code_points.size_hint(); - // every code point gets either one u16 or two u16, - // so this iterator is between 1 or 2 times as - // long as the underlying iterator. - (low, high.and_then(|n| n.checked_mul(2))) - } -} - -impl Hash for CodePoint { - #[inline] - fn hash(&self, state: &mut H) { - self.value.hash(state) - } -} - -impl Hash for Wtf8Buf { - #[inline] - fn hash(&self, state: &mut H) { - state.write(&self.bytes); - 0xfeu8.hash(state) - } -} - -impl Hash for Wtf8 { - #[inline] - fn hash(&self, state: &mut H) { - state.write(&self.bytes); - 0xfeu8.hash(state) - } -} - -impl Wtf8 { - pub fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() } -} - -#[cfg(test)] -mod tests { - use borrow::Cow; - use super::*; - - #[test] - fn code_point_from_u32() { - assert!(CodePoint::from_u32(0).is_some()); - assert!(CodePoint::from_u32(0xD800).is_some()); - assert!(CodePoint::from_u32(0x10FFFF).is_some()); - assert!(CodePoint::from_u32(0x110000).is_none()); - } - - #[test] - fn code_point_to_u32() { - fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() } - assert_eq!(c(0).to_u32(), 0); - assert_eq!(c(0xD800).to_u32(), 0xD800); - assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF); - } - - #[test] - fn code_point_from_char() { - assert_eq!(CodePoint::from_char('a').to_u32(), 0x61); - assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9); - } - - #[test] - fn code_point_to_string() { - assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061"); - assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9"); - } - - #[test] - fn code_point_to_char() { - fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() } - assert_eq!(c(0x61).to_char(), Some('a')); - assert_eq!(c(0x1F4A9).to_char(), Some('💩')); - assert_eq!(c(0xD800).to_char(), None); - } - - #[test] - fn code_point_to_char_lossy() { - fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() } - assert_eq!(c(0x61).to_char_lossy(), 'a'); - assert_eq!(c(0x1F4A9).to_char_lossy(), '💩'); - assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}'); - } - - #[test] - fn wtf8buf_new() { - assert_eq!(Wtf8Buf::new().bytes, b""); - } - - #[test] - fn wtf8buf_from_str() { - assert_eq!(Wtf8Buf::from_str("").bytes, b""); - assert_eq!(Wtf8Buf::from_str("aé 💩").bytes, - b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8buf_from_string() { - assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b""); - assert_eq!(Wtf8Buf::from_string(String::from("aé 💩")).bytes, - b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8buf_from_wide() { - assert_eq!(Wtf8Buf::from_wide(&[]).bytes, b""); - assert_eq!(Wtf8Buf::from_wide( - &[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]).bytes, - b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8buf_push_str() { - let mut string = Wtf8Buf::new(); - assert_eq!(string.bytes, b""); - string.push_str("aé 💩"); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8buf_push_char() { - let mut string = Wtf8Buf::from_str("aé "); - assert_eq!(string.bytes, b"a\xC3\xA9 "); - string.push_char('💩'); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8buf_push() { - let mut string = Wtf8Buf::from_str("aé "); - assert_eq!(string.bytes, b"a\xC3\xA9 "); - string.push(CodePoint::from_char('💩')); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - - fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() } - - let mut string = Wtf8Buf::new(); - string.push(c(0xD83D)); // lead - string.push(c(0xDCA9)); // trail - assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! - - let mut string = Wtf8Buf::new(); - string.push(c(0xD83D)); // lead - string.push(c(0x20)); // not surrogate - string.push(c(0xDCA9)); // trail - assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xD800)); // lead - string.push(c(0xDBFF)); // lead - assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xD800)); // lead - string.push(c(0xE000)); // not surrogate - assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xD7FF)); // not surrogate - string.push(c(0xDC00)); // trail - assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push(c(0x61)); // not surrogate, < 3 bytes - string.push(c(0xDC00)); // trail - assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xDC00)); // trail - assert_eq!(string.bytes, b"\xED\xB0\x80"); - } - - #[test] - fn wtf8buf_push_wtf8() { - let mut string = Wtf8Buf::from_str("aé"); - assert_eq!(string.bytes, b"a\xC3\xA9"); - string.push_wtf8(Wtf8::from_str(" 💩")); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - - fn w(v: &[u8]) -> &Wtf8 { unsafe { Wtf8::from_bytes_unchecked(v) } } - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\xBD")); // lead - string.push_wtf8(w(b"\xED\xB2\xA9")); // trail - assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\xBD")); // lead - string.push_wtf8(w(b" ")); // not surrogate - string.push_wtf8(w(b"\xED\xB2\xA9")); // trail - assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\x80")); // lead - string.push_wtf8(w(b"\xED\xAF\xBF")); // lead - assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\x80")); // lead - string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate - assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate - string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes - string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\xED\xB0\x80"); - } - - #[test] - fn wtf8buf_truncate() { - let mut string = Wtf8Buf::from_str("aé"); - string.truncate(1); - assert_eq!(string.bytes, b"a"); - } - - #[test] - #[should_panic] - fn wtf8buf_truncate_fail_code_point_boundary() { - let mut string = Wtf8Buf::from_str("aé"); - string.truncate(2); - } - - #[test] - #[should_panic] - fn wtf8buf_truncate_fail_longer() { - let mut string = Wtf8Buf::from_str("aé"); - string.truncate(4); - } - - #[test] - fn wtf8buf_into_string() { - let mut string = Wtf8Buf::from_str("aé 💩"); - assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩"))); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(string.clone().into_string(), Err(string)); - } - - #[test] - fn wtf8buf_into_string_lossy() { - let mut string = Wtf8Buf::from_str("aé 💩"); - assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩")); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�")); - } - - #[test] - fn wtf8buf_from_iterator() { - fn f(values: &[u32]) -> Wtf8Buf { - values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::() - } - assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - - assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - assert_eq!(f(&[0xD800, 0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - assert_eq!(f(&[0xD800, 0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80"); - assert_eq!(f(&[0xD7FF, 0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - assert_eq!(f(&[0x61, 0xDC00]).bytes, b"\x61\xED\xB0\x80"); - assert_eq!(f(&[0xDC00]).bytes, b"\xED\xB0\x80"); - } - - #[test] - fn wtf8buf_extend() { - fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf { - fn c(value: &u32) -> CodePoint { CodePoint::from_u32(*value).unwrap() } - let mut string = initial.iter().map(c).collect::(); - string.extend(extended.iter().map(c)); - string - } - - assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes, - b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - - assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - assert_eq!(e(&[0xD800], &[0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - assert_eq!(e(&[0xD800], &[0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80"); - assert_eq!(e(&[0xD7FF], &[0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - assert_eq!(e(&[0x61], &[0xDC00]).bytes, b"\x61\xED\xB0\x80"); - assert_eq!(e(&[], &[0xDC00]).bytes, b"\xED\xB0\x80"); - } - - #[test] - fn wtf8buf_show() { - let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\""); - } - - #[test] - fn wtf8buf_as_slice() { - assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé")); - } - - #[test] - fn wtf8buf_show_str() { - let text = "a\té 💩\r"; - let string = Wtf8Buf::from_str(text); - assert_eq!(format!("{:?}", text), format!("{:?}", string)); - } - - #[test] - fn wtf8_from_str() { - assert_eq!(&Wtf8::from_str("").bytes, b""); - assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8_len() { - assert_eq!(Wtf8::from_str("").len(), 0); - assert_eq!(Wtf8::from_str("aé 💩").len(), 8); - } - - #[test] - fn wtf8_slice() { - assert_eq!(&Wtf8::from_str("aé 💩")[1.. 4].bytes, b"\xC3\xA9 "); - } - - #[test] - #[should_panic] - fn wtf8_slice_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[2.. 4]; - } - - #[test] - fn wtf8_slice_from() { - assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - #[should_panic] - fn wtf8_slice_from_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[2..]; - } - - #[test] - fn wtf8_slice_to() { - assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 "); - } - - #[test] - #[should_panic] - fn wtf8_slice_to_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[5..]; - } - - #[test] - fn wtf8_ascii_byte_at() { - let slice = Wtf8::from_str("aé 💩"); - assert_eq!(slice.ascii_byte_at(0), b'a'); - assert_eq!(slice.ascii_byte_at(1), b'\xFF'); - assert_eq!(slice.ascii_byte_at(2), b'\xFF'); - assert_eq!(slice.ascii_byte_at(3), b' '); - assert_eq!(slice.ascii_byte_at(4), b'\xFF'); - } - - #[test] - fn wtf8_code_points() { - fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() } - fn cp(string: &Wtf8Buf) -> Vec> { - string.code_points().map(|c| c.to_char()).collect::>() - } - let mut string = Wtf8Buf::from_str("é "); - assert_eq!(cp(&string), [Some('é'), Some(' ')]); - string.push(c(0xD83D)); - assert_eq!(cp(&string), [Some('é'), Some(' '), None]); - string.push(c(0xDCA9)); - assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]); - } - - #[test] - fn wtf8_as_str() { - assert_eq!(Wtf8::from_str("").as_str(), Some("")); - assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩")); - let mut string = Wtf8Buf::new(); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(string.as_str(), None); - } - - #[test] - fn wtf8_to_string_lossy() { - assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed("")); - assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩")); - let mut string = Wtf8Buf::from_str("aé 💩"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - let expected: Cow = Cow::Owned(String::from("aé 💩�")); - assert_eq!(string.to_string_lossy(), expected); - } - - #[test] - fn wtf8_display() { - fn d(b: &[u8]) -> String { - (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string() - } - - assert_eq!("", d("".as_bytes())); - assert_eq!("aé 💩", d("aé 💩".as_bytes())); - - let mut string = Wtf8Buf::from_str("aé 💩"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!("aé 💩�", d(string.as_inner())); - } - - #[test] - fn wtf8_encode_wide() { - let mut string = Wtf8Buf::from_str("aé "); - string.push(CodePoint::from_u32(0xD83D).unwrap()); - string.push_char('💩'); - assert_eq!(string.encode_wide().collect::>(), - vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]); - } -} diff --git a/ctr-std/src/tests/env.rs b/ctr-std/src/tests/env.rs deleted file mode 100644 index 8acb8a4..0000000 --- a/ctr-std/src/tests/env.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern crate rand; - -use std::env::*; -use std::ffi::{OsString, OsStr}; - -use rand::Rng; - -fn make_rand_name() -> OsString { - let mut rng = rand::thread_rng(); - let n = format!("TEST{}", rng.gen_ascii_chars().take(10) - .collect::()); - let n = OsString::from(n); - assert!(var_os(&n).is_none()); - n -} - -fn eq(a: Option, b: Option<&str>) { - assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); -} - -#[test] -fn test_set_var() { - let n = make_rand_name(); - set_var(&n, "VALUE"); - eq(var_os(&n), Some("VALUE")); -} - -#[test] -fn test_remove_var() { - let n = make_rand_name(); - set_var(&n, "VALUE"); - remove_var(&n); - eq(var_os(&n), None); -} - -#[test] -fn test_set_var_overwrite() { - let n = make_rand_name(); - set_var(&n, "1"); - set_var(&n, "2"); - eq(var_os(&n), Some("2")); - set_var(&n, ""); - eq(var_os(&n), Some("")); -} - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn test_var_big() { - let mut s = "".to_string(); - let mut i = 0; - while i < 100 { - s.push_str("aaaaaaaaaa"); - i += 1; - } - let n = make_rand_name(); - set_var(&n, &s); - eq(var_os(&n), Some(&s)); -} - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn test_env_set_get_huge() { - let n = make_rand_name(); - let s = "x".repeat(10000); - set_var(&n, &s); - eq(var_os(&n), Some(&s)); - remove_var(&n); - eq(var_os(&n), None); -} - -#[test] -fn test_env_set_var() { - let n = make_rand_name(); - - let mut e = vars_os(); - set_var(&n, "VALUE"); - assert!(!e.any(|(k, v)| { - &*k == &*n && &*v == "VALUE" - })); - - assert!(vars_os().any(|(k, v)| { - &*k == &*n && &*v == "VALUE" - })); -} diff --git a/ctr-std/src/thread/local.rs b/ctr-std/src/thread/local.rs deleted file mode 100644 index a170abb..0000000 --- a/ctr-std/src/thread/local.rs +++ /dev/null @@ -1,669 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Thread local storage - -#![unstable(feature = "thread_local_internals", issue = "0")] - -use cell::UnsafeCell; -use fmt; -use mem; - -/// A thread local storage key which owns its contents. -/// -/// This key uses the fastest possible implementation available to it for the -/// target platform. It is instantiated with the [`thread_local!`] macro and the -/// primary method is the [`with`] method. -/// -/// The [`with`] method yields a reference to the contained value which cannot be -/// sent across threads or escape the given closure. -/// -/// # Initialization and Destruction -/// -/// Initialization is dynamically performed on the first call to [`with`] -/// within a thread, and values that implement [`Drop`] get destructed when a -/// thread exits. Some caveats apply, which are explained below. -/// -/// A `LocalKey`'s initializer cannot recursively depend on itself, and using -/// a `LocalKey` in this way will cause the initializer to infinitely recurse -/// on the first call to `with`. -/// -/// # Examples -/// -/// ``` -/// use std::cell::RefCell; -/// use std::thread; -/// -/// thread_local!(static FOO: RefCell = RefCell::new(1)); -/// -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 1); -/// *f.borrow_mut() = 2; -/// }); -/// -/// // each thread starts out with the initial value of 1 -/// thread::spawn(move|| { -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 1); -/// *f.borrow_mut() = 3; -/// }); -/// }); -/// -/// // we retain our original value of 2 despite the child thread -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 2); -/// }); -/// ``` -/// -/// # Platform-specific behavior -/// -/// Note that a "best effort" is made to ensure that destructors for types -/// stored in thread local storage are run, but not all platforms can guarantee -/// that destructors will be run for all types in thread local storage. For -/// example, there are a number of known caveats where destructors are not run: -/// -/// 1. On Unix systems when pthread-based TLS is being used, destructors will -/// not be run for TLS values on the main thread when it exits. Note that the -/// application will exit immediately after the main thread exits as well. -/// 2. On all platforms it's possible for TLS to re-initialize other TLS slots -/// during destruction. Some platforms ensure that this cannot happen -/// infinitely by preventing re-initialization of any slot that has been -/// destroyed, but not all platforms have this guard. Those platforms that do -/// not guard typically have a synthetic limit after which point no more -/// destructors are run. -/// 3. On macOS, initializing TLS during destruction of other TLS slots can -/// sometimes cancel *all* destructors for the current thread, whether or not -/// the slots have already had their destructors run or not. -/// -/// [`with`]: ../../std/thread/struct.LocalKey.html#method.with -/// [`thread_local!`]: ../../std/macro.thread_local.html -/// [`Drop`]: ../../std/ops/trait.Drop.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct LocalKey { - // This outer `LocalKey` type is what's going to be stored in statics, - // but actual data inside will sometimes be tagged with #[thread_local]. - // It's not valid for a true static to reference a #[thread_local] static, - // so we get around that by exposing an accessor through a layer of function - // indirection (this thunk). - // - // Note that the thunk is itself unsafe because the returned lifetime of the - // slot where data lives, `'static`, is not actually valid. The lifetime - // here is actually slightly shorter than the currently running thread! - // - // Although this is an extra layer of indirection, it should in theory be - // trivially devirtualizable by LLVM because the value of `inner` never - // changes and the constant should be readonly within a crate. This mainly - // only runs into problems when TLS statics are exported across crates. - inner: unsafe fn() -> Option<&'static UnsafeCell>>, - - // initialization routine to invoke to create a value - init: fn() -> T, -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for LocalKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("LocalKey { .. }") - } -} - -/// Declare a new thread local storage key of type [`std::thread::LocalKey`]. -/// -/// # Syntax -/// -/// The macro wraps any number of static declarations and makes them thread local. -/// Publicity and attributes for each static are allowed. Example: -/// -/// ``` -/// use std::cell::RefCell; -/// thread_local! { -/// pub static FOO: RefCell = RefCell::new(1); -/// -/// #[allow(unused)] -/// static BAR: RefCell = RefCell::new(1.0); -/// } -/// # fn main() {} -/// ``` -/// -/// See [LocalKey documentation][`std::thread::LocalKey`] for more -/// information. -/// -/// [`std::thread::LocalKey`]: ../std/thread/struct.LocalKey.html -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable] -macro_rules! thread_local { - // empty (base case for the recursion) - () => {}; - - // process multiple declarations - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( - __thread_local_inner!($(#[$attr])* $vis $name, $t, $init); - thread_local!($($rest)*); - ); - - // handle a single declaration - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => ( - __thread_local_inner!($(#[$attr])* $vis $name, $t, $init); - ); -} - -#[doc(hidden)] -#[unstable(feature = "thread_local_internals", - reason = "should not be necessary", - issue = "0")] -#[macro_export] -#[allow_internal_unstable] -#[allow_internal_unsafe] -macro_rules! __thread_local_inner { - (@key $(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => { - { - #[inline] - fn __init() -> $t { $init } - - unsafe fn __getit() -> $crate::option::Option< - &'static $crate::cell::UnsafeCell< - $crate::option::Option<$t>>> - { - #[cfg(target_arch = "wasm32")] - static __KEY: $crate::thread::__StaticLocalKeyInner<$t> = - $crate::thread::__StaticLocalKeyInner::new(); - - #[thread_local] - #[cfg(all(target_thread_local, not(target_arch = "wasm32")))] - static __KEY: $crate::thread::__FastLocalKeyInner<$t> = - $crate::thread::__FastLocalKeyInner::new(); - - #[cfg(all(not(target_thread_local), not(target_arch = "wasm32")))] - static __KEY: $crate::thread::__OsLocalKeyInner<$t> = - $crate::thread::__OsLocalKeyInner::new(); - - __KEY.get() - } - - unsafe { - $crate::thread::LocalKey::new(__getit, __init) - } - } - }; - ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => { - $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = - __thread_local_inner!(@key $(#[$attr])* $vis $name, $t, $init); - } -} - -/// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with). -#[stable(feature = "thread_local_try_with", since = "1.26.0")] -pub struct AccessError { - _private: (), -} - -#[stable(feature = "thread_local_try_with", since = "1.26.0")] -impl fmt::Debug for AccessError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("AccessError").finish() - } -} - -#[stable(feature = "thread_local_try_with", since = "1.26.0")] -impl fmt::Display for AccessError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt("already destroyed", f) - } -} - -impl LocalKey { - #[doc(hidden)] - #[unstable(feature = "thread_local_internals", - reason = "recently added to create a key", - issue = "0")] - pub const unsafe fn new(inner: unsafe fn() -> Option<&'static UnsafeCell>>, - init: fn() -> T) -> LocalKey { - LocalKey { - inner, - init, - } - } - - /// Acquires a reference to the value in this TLS key. - /// - /// This will lazily initialize the value if this thread has not referenced - /// this key yet. - /// - /// # Panics - /// - /// This function will `panic!()` if the key currently has its - /// destructor running, and it **may** panic if the destructor has - /// previously been run for this thread. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with(&'static self, f: F) -> R - where F: FnOnce(&T) -> R { - self.try_with(f).expect("cannot access a TLS value during or \ - after it is destroyed") - } - - unsafe fn init(&self, slot: &UnsafeCell>) -> &T { - // Execute the initialization up front, *then* move it into our slot, - // just in case initialization fails. - let value = (self.init)(); - let ptr = slot.get(); - - // note that this can in theory just be `*ptr = Some(value)`, but due to - // the compiler will currently codegen that pattern with something like: - // - // ptr::drop_in_place(ptr) - // ptr::write(ptr, Some(value)) - // - // Due to this pattern it's possible for the destructor of the value in - // `ptr` (e.g. if this is being recursively initialized) to re-access - // TLS, in which case there will be a `&` and `&mut` pointer to the same - // value (an aliasing violation). To avoid setting the "I'm running a - // destructor" flag we just use `mem::replace` which should sequence the - // operations a little differently and make this safe to call. - mem::replace(&mut *ptr, Some(value)); - - (*ptr).as_ref().unwrap() - } - - /// Acquires a reference to the value in this TLS key. - /// - /// This will lazily initialize the value if this thread has not referenced - /// this key yet. If the key has been destroyed (which may happen if this is called - /// in a destructor), this function will return an [`AccessError`](struct.AccessError.html). - /// - /// # Panics - /// - /// This function will still `panic!()` if the key is uninitialized and the - /// key's initializer panics. - #[stable(feature = "thread_local_try_with", since = "1.26.0")] - pub fn try_with(&'static self, f: F) -> Result - where - F: FnOnce(&T) -> R, - { - unsafe { - let slot = (self.inner)().ok_or(AccessError { - _private: (), - })?; - Ok(f(match *slot.get() { - Some(ref inner) => inner, - None => self.init(slot), - })) - } - } -} - -/// On some platforms like wasm32 there's no threads, so no need to generate -/// thread locals and we can instead just use plain statics! -#[doc(hidden)] -#[cfg(target_arch = "wasm32")] -pub mod statik { - use cell::UnsafeCell; - use fmt; - - pub struct Key { - inner: UnsafeCell>, - } - - unsafe impl ::marker::Sync for Key { } - - impl fmt::Debug for Key { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Key { .. }") - } - } - - impl Key { - pub const fn new() -> Key { - Key { - inner: UnsafeCell::new(None), - } - } - - pub unsafe fn get(&self) -> Option<&'static UnsafeCell>> { - Some(&*(&self.inner as *const _)) - } - } -} - -#[doc(hidden)] -#[cfg(target_thread_local)] -pub mod fast { - use cell::{Cell, UnsafeCell}; - use fmt; - use mem; - use ptr; - use sys::fast_thread_local::{register_dtor, requires_move_before_drop}; - - pub struct Key { - inner: UnsafeCell>, - - // Metadata to keep track of the state of the destructor. Remember that - // these variables are thread-local, not global. - dtor_registered: Cell, - dtor_running: Cell, - } - - impl fmt::Debug for Key { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Key { .. }") - } - } - - impl Key { - pub const fn new() -> Key { - Key { - inner: UnsafeCell::new(None), - dtor_registered: Cell::new(false), - dtor_running: Cell::new(false) - } - } - - pub unsafe fn get(&self) -> Option<&'static UnsafeCell>> { - if mem::needs_drop::() && self.dtor_running.get() { - return None - } - self.register_dtor(); - Some(&*(&self.inner as *const _)) - } - - unsafe fn register_dtor(&self) { - if !mem::needs_drop::() || self.dtor_registered.get() { - return - } - - register_dtor(self as *const _ as *mut u8, - destroy_value::); - self.dtor_registered.set(true); - } - } - - unsafe extern fn destroy_value(ptr: *mut u8) { - let ptr = ptr as *mut Key; - // Right before we run the user destructor be sure to flag the - // destructor as running for this thread so calls to `get` will return - // `None`. - (*ptr).dtor_running.set(true); - - // Some implementations may require us to move the value before we drop - // it as it could get re-initialized in-place during destruction. - // - // Hence, we use `ptr::read` on those platforms (to move to a "safe" - // location) instead of drop_in_place. - if requires_move_before_drop() { - ptr::read((*ptr).inner.get()); - } else { - ptr::drop_in_place((*ptr).inner.get()); - } - } -} - -#[doc(hidden)] -pub mod os { - use cell::{Cell, UnsafeCell}; - use fmt; - use marker; - use ptr; - use sys_common::thread_local::StaticKey as OsStaticKey; - - pub struct Key { - // OS-TLS key that we'll use to key off. - os: OsStaticKey, - marker: marker::PhantomData>, - } - - impl fmt::Debug for Key { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Key { .. }") - } - } - - unsafe impl ::marker::Sync for Key { } - - struct Value { - key: &'static Key, - value: UnsafeCell>, - } - - impl Key { - pub const fn new() -> Key { - Key { - os: OsStaticKey::new(Some(destroy_value::)), - marker: marker::PhantomData - } - } - - pub unsafe fn get(&'static self) -> Option<&'static UnsafeCell>> { - let ptr = self.os.get() as *mut Value; - if !ptr.is_null() { - if ptr as usize == 1 { - return None - } - return Some(&(*ptr).value); - } - - // If the lookup returned null, we haven't initialized our own - // local copy, so do that now. - let ptr: Box> = box Value { - key: self, - value: UnsafeCell::new(None), - }; - let ptr = Box::into_raw(ptr); - self.os.set(ptr as *mut u8); - Some(&(*ptr).value) - } - } - - unsafe extern fn destroy_value(ptr: *mut u8) { - // The OS TLS ensures that this key contains a NULL value when this - // destructor starts to run. We set it back to a sentinel value of 1 to - // ensure that any future calls to `get` for this thread will return - // `None`. - // - // Note that to prevent an infinite loop we reset it back to null right - // before we return from the destructor ourselves. - let ptr = Box::from_raw(ptr as *mut Value); - let key = ptr.key; - key.os.set(1 as *mut u8); - drop(ptr); - key.os.set(ptr::null_mut()); - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use sync::mpsc::{channel, Sender}; - use cell::{Cell, UnsafeCell}; - use thread; - - struct Foo(Sender<()>); - - impl Drop for Foo { - fn drop(&mut self) { - let Foo(ref s) = *self; - s.send(()).unwrap(); - } - } - - #[test] - fn smoke_no_dtor() { - thread_local!(static FOO: Cell = Cell::new(1)); - - FOO.with(|f| { - assert_eq!(f.get(), 1); - f.set(2); - }); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - FOO.with(|f| { - assert_eq!(f.get(), 1); - }); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - - FOO.with(|f| { - assert_eq!(f.get(), 2); - }); - } - - #[test] - fn states() { - struct Foo; - impl Drop for Foo { - fn drop(&mut self) { - assert!(FOO.try_with(|_| ()).is_err()); - } - } - thread_local!(static FOO: Foo = Foo); - - thread::spawn(|| { - assert!(FOO.try_with(|_| ()).is_ok()); - }).join().ok().unwrap(); - } - - #[test] - fn smoke_dtor() { - thread_local!(static FOO: UnsafeCell> = UnsafeCell::new(None)); - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| unsafe { - let mut tx = Some(tx); - FOO.with(|f| { - *f.get() = Some(Foo(tx.take().unwrap())); - }); - }); - rx.recv().unwrap(); - } - - #[test] - fn circular() { - struct S1; - struct S2; - thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); - thread_local!(static K2: UnsafeCell> = UnsafeCell::new(None)); - static mut HITS: u32 = 0; - - impl Drop for S1 { - fn drop(&mut self) { - unsafe { - HITS += 1; - if K2.try_with(|_| ()).is_err() { - assert_eq!(HITS, 3); - } else { - if HITS == 1 { - K2.with(|s| *s.get() = Some(S2)); - } else { - assert_eq!(HITS, 3); - } - } - } - } - } - impl Drop for S2 { - fn drop(&mut self) { - unsafe { - HITS += 1; - assert!(K1.try_with(|_| ()).is_ok()); - assert_eq!(HITS, 2); - K1.with(|s| *s.get() = Some(S1)); - } - } - } - - thread::spawn(move|| { - drop(S1); - }).join().ok().unwrap(); - } - - #[test] - fn self_referential() { - struct S1; - thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); - - impl Drop for S1 { - fn drop(&mut self) { - assert!(K1.try_with(|_| ()).is_err()); - } - } - - thread::spawn(move|| unsafe { - K1.with(|s| *s.get() = Some(S1)); - }).join().ok().unwrap(); - } - - // Note that this test will deadlock if TLS destructors aren't run (this - // requires the destructor to be run to pass the test). macOS has a known bug - // where dtors-in-dtors may cancel other destructors, so we just ignore this - // test on macOS. - #[test] - #[cfg_attr(target_os = "macos", ignore)] - fn dtors_in_dtors_in_dtors() { - struct S1(Sender<()>); - thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); - thread_local!(static K2: UnsafeCell> = UnsafeCell::new(None)); - - impl Drop for S1 { - fn drop(&mut self) { - let S1(ref tx) = *self; - unsafe { - let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone()))); - } - } - } - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| unsafe { - let mut tx = Some(tx); - K1.with(|s| *s.get() = Some(S1(tx.take().unwrap()))); - }); - rx.recv().unwrap(); - } -} - -#[cfg(test)] -mod dynamic_tests { - use cell::RefCell; - use collections::HashMap; - - #[test] - fn smoke() { - fn square(i: i32) -> i32 { i * i } - thread_local!(static FOO: i32 = square(3)); - - FOO.with(|f| { - assert_eq!(*f, 9); - }); - } - - #[test] - fn hashmap() { - fn map() -> RefCell> { - let mut m = HashMap::new(); - m.insert(1, 2); - RefCell::new(m) - } - thread_local!(static FOO: RefCell> = map()); - - FOO.with(|map| { - assert_eq!(map.borrow()[&1], 2); - }); - } - - #[test] - fn refcell_vec() { - thread_local!(static FOO: RefCell> = RefCell::new(vec![1, 2, 3])); - - FOO.with(|vec| { - assert_eq!(vec.borrow().len(), 3); - vec.borrow_mut().push(4); - assert_eq!(vec.borrow()[3], 4); - }); - } -} diff --git a/ctr-std/src/thread/mod.rs b/ctr-std/src/thread/mod.rs deleted file mode 100644 index 61c6084..0000000 --- a/ctr-std/src/thread/mod.rs +++ /dev/null @@ -1,1616 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Native threads. -//! -//! ## The threading model -//! -//! An executing Rust program consists of a collection of native OS threads, -//! each with their own stack and local state. Threads can be named, and -//! provide some built-in support for low-level synchronization. -//! -//! Communication between threads can be done through -//! [channels], Rust's message-passing types, along with [other forms of thread -//! synchronization](../../std/sync/index.html) and shared-memory data -//! structures. In particular, types that are guaranteed to be -//! threadsafe are easily shared between threads using the -//! atomically-reference-counted container, [`Arc`]. -//! -//! Fatal logic errors in Rust cause *thread panic*, during which -//! a thread will unwind the stack, running destructors and freeing -//! owned resources. While not meant as a 'try/catch' mechanism, panics -//! in Rust can nonetheless be caught (unless compiling with `panic=abort`) with -//! [`catch_unwind`](../../std/panic/fn.catch_unwind.html) and recovered -//! from, or alternatively be resumed with -//! [`resume_unwind`](../../std/panic/fn.resume_unwind.html). If the panic -//! is not caught the thread will exit, but the panic may optionally be -//! detected from a different thread with [`join`]. If the main thread panics -//! without the panic being caught, the application will exit with a -//! non-zero exit code. -//! -//! When the main thread of a Rust program terminates, the entire program shuts -//! down, even if other threads are still running. However, this module provides -//! convenient facilities for automatically waiting for the termination of a -//! child thread (i.e., join). -//! -//! ## Spawning a thread -//! -//! A new thread can be spawned using the [`thread::spawn`][`spawn`] function: -//! -//! ```rust -//! use std::thread; -//! -//! thread::spawn(move || { -//! // some work here -//! }); -//! ``` -//! -//! In this example, the spawned thread is "detached" from the current -//! thread. This means that it can outlive its parent (the thread that spawned -//! it), unless this parent is the main thread. -//! -//! The parent thread can also wait on the completion of the child -//! thread; a call to [`spawn`] produces a [`JoinHandle`], which provides -//! a `join` method for waiting: -//! -//! ```rust -//! use std::thread; -//! -//! let child = thread::spawn(move || { -//! // some work here -//! }); -//! // some work here -//! let res = child.join(); -//! ``` -//! -//! The [`join`] method returns a [`thread::Result`] containing [`Ok`] of the final -//! value produced by the child thread, or [`Err`] of the value given to -//! a call to [`panic!`] if the child panicked. -//! -//! ## Configuring threads -//! -//! A new thread can be configured before it is spawned via the [`Builder`] type, -//! which currently allows you to set the name and stack size for the child thread: -//! -//! ```rust -//! # #![allow(unused_must_use)] -//! use std::thread; -//! -//! thread::Builder::new().name("child1".to_string()).spawn(move || { -//! println!("Hello, world!"); -//! }); -//! ``` -//! -//! ## The `Thread` type -//! -//! Threads are represented via the [`Thread`] type, which you can get in one of -//! two ways: -//! -//! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] -//! function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`]. -//! * By requesting the current thread, using the [`thread::current`] function. -//! -//! The [`thread::current`] function is available even for threads not spawned -//! by the APIs of this module. -//! -//! ## Thread-local storage -//! -//! This module also provides an implementation of thread-local storage for Rust -//! programs. Thread-local storage is a method of storing data into a global -//! variable that each thread in the program will have its own copy of. -//! Threads do not share this data, so accesses do not need to be synchronized. -//! -//! A thread-local key owns the value it contains and will destroy the value when the -//! thread exits. It is created with the [`thread_local!`] macro and can contain any -//! value that is `'static` (no borrowed pointers). It provides an accessor function, -//! [`with`], that yields a shared reference to the value to the specified -//! closure. Thread-local keys allow only shared access to values, as there would be no -//! way to guarantee uniqueness if mutable borrows were allowed. Most values -//! will want to make use of some form of **interior mutability** through the -//! [`Cell`] or [`RefCell`] types. -//! -//! ## Naming threads -//! -//! Threads are able to have associated names for identification purposes. By default, spawned -//! threads are unnamed. To specify a name for a thread, build the thread with [`Builder`] and pass -//! the desired thread name to [`Builder::name`]. To retrieve the thread name from within the -//! thread, use [`Thread::name`]. A couple examples of where the name of a thread gets used: -//! -//! * If a panic occurs in a named thread, the thread name will be printed in the panic message. -//! * The thread name is provided to the OS where applicable (e.g. `pthread_setname_np` in -//! unix-like platforms). -//! -//! ## Stack size -//! -//! The default stack size for spawned threads is 2 MiB, though this particular stack size is -//! subject to change in the future. There are two ways to manually specify the stack size for -//! spawned threads: -//! -//! * Build the thread with [`Builder`] and pass the desired stack size to [`Builder::stack_size`]. -//! * Set the `RUST_MIN_STACK` environment variable to an integer representing the desired stack -//! size (in bytes). Note that setting [`Builder::stack_size`] will override this. -//! -//! Note that the stack size of the main thread is *not* determined by Rust. -//! -//! [channels]: ../../std/sync/mpsc/index.html -//! [`Arc`]: ../../std/sync/struct.Arc.html -//! [`spawn`]: ../../std/thread/fn.spawn.html -//! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -//! [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread -//! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join -//! [`Result`]: ../../std/result/enum.Result.html -//! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok -//! [`Err`]: ../../std/result/enum.Result.html#variant.Err -//! [`panic!`]: ../../std/macro.panic.html -//! [`Builder`]: ../../std/thread/struct.Builder.html -//! [`Builder::stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size -//! [`Builder::name`]: ../../std/thread/struct.Builder.html#method.name -//! [`thread::current`]: ../../std/thread/fn.current.html -//! [`thread::Result`]: ../../std/thread/type.Result.html -//! [`Thread`]: ../../std/thread/struct.Thread.html -//! [`park`]: ../../std/thread/fn.park.html -//! [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark -//! [`Thread::name`]: ../../std/thread/struct.Thread.html#method.name -//! [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html -//! [`Cell`]: ../cell/struct.Cell.html -//! [`RefCell`]: ../cell/struct.RefCell.html -//! [`thread_local!`]: ../macro.thread_local.html -//! [`with`]: struct.LocalKey.html#method.with - -#![stable(feature = "rust1", since = "1.0.0")] - -use any::Any; -use cell::UnsafeCell; -use ffi::{CStr, CString}; -use fmt; -use io; -use panic; -use panicking; -use str; -use sync::{Mutex, Condvar, Arc}; -use sync::atomic::AtomicUsize; -use sync::atomic::Ordering::SeqCst; -use sys::thread as imp; -use sys_common::mutex; -use sys_common::thread_info; -use sys_common::thread; -use sys_common::{AsInner, IntoInner}; -use time::Duration; - -//////////////////////////////////////////////////////////////////////////////// -// Thread-local storage -//////////////////////////////////////////////////////////////////////////////// - -#[macro_use] mod local; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::local::{LocalKey, AccessError}; - -// The types used by the thread_local! macro to access TLS keys. Note that there -// are two types, the "OS" type and the "fast" type. The OS thread local key -// type is accessed via platform-specific API calls and is slow, while the fast -// key type is accessed via code generated via LLVM, where TLS keys are set up -// by the elf linker. Note that the OS TLS type is always available: on macOS -// the standard library is compiled with support for older platform versions -// where fast TLS was not available; end-user code is compiled with fast TLS -// where available, but both are needed. - -#[unstable(feature = "libstd_thread_internals", issue = "0")] -#[cfg(target_arch = "wasm32")] -#[doc(hidden)] pub use self::local::statik::Key as __StaticLocalKeyInner; -#[unstable(feature = "libstd_thread_internals", issue = "0")] -#[cfg(target_thread_local)] -#[doc(hidden)] pub use self::local::fast::Key as __FastLocalKeyInner; -#[unstable(feature = "libstd_thread_internals", issue = "0")] -#[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner; - -//////////////////////////////////////////////////////////////////////////////// -// Builder -//////////////////////////////////////////////////////////////////////////////// - -/// Thread factory, which can be used in order to configure the properties of -/// a new thread. -/// -/// Methods can be chained on it in order to configure it. -/// -/// The two configurations available are: -/// -/// - [`name`]: specifies an [associated name for the thread][naming-threads] -/// - [`stack_size`]: specifies the [desired stack size for the thread][stack-size] -/// -/// The [`spawn`] method will take ownership of the builder and create an -/// [`io::Result`] to the thread handle with the given configuration. -/// -/// The [`thread::spawn`] free function uses a `Builder` with default -/// configuration and [`unwrap`]s its return value. -/// -/// You may want to use [`spawn`] instead of [`thread::spawn`], when you want -/// to recover from a failure to launch a thread, indeed the free function will -/// panick where the `Builder` method will return a [`io::Result`]. -/// -/// # Examples -/// -/// ``` -/// use std::thread; -/// -/// let builder = thread::Builder::new(); -/// -/// let handler = builder.spawn(|| { -/// // thread code -/// }).unwrap(); -/// -/// handler.join().unwrap(); -/// ``` -/// -/// [`thread::spawn`]: ../../std/thread/fn.spawn.html -/// [`stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size -/// [`name`]: ../../std/thread/struct.Builder.html#method.name -/// [`spawn`]: ../../std/thread/struct.Builder.html#method.spawn -/// [`io::Result`]: ../../std/io/type.Result.html -/// [`unwrap`]: ../../std/result/enum.Result.html#method.unwrap -/// [naming-threads]: ./index.html#naming-threads -/// [stack-size]: ./index.html#stack-size -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct Builder { - // A name for the thread-to-be, for identification in panic messages - name: Option, - // The size of the stack for the spawned thread in bytes - stack_size: Option, -} - -impl Builder { - /// Generates the base configuration for spawning a thread, from which - /// configuration methods can be chained. - /// - /// # Examples - /// - /// ``` - /// use std::thread; - /// - /// let builder = thread::Builder::new() - /// .name("foo".into()) - /// .stack_size(10); - /// - /// let handler = builder.spawn(|| { - /// // thread code - /// }).unwrap(); - /// - /// handler.join().unwrap(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> Builder { - Builder { - name: None, - stack_size: None, - } - } - - /// Names the thread-to-be. Currently the name is used for identification - /// only in panic messages. - /// - /// The name must not contain null bytes (`\0`). - /// - /// For more information about named threads, see - /// [this module-level documentation][naming-threads]. - /// - /// # Examples - /// - /// ``` - /// use std::thread; - /// - /// let builder = thread::Builder::new() - /// .name("foo".into()); - /// - /// let handler = builder.spawn(|| { - /// assert_eq!(thread::current().name(), Some("foo")) - /// }).unwrap(); - /// - /// handler.join().unwrap(); - /// ``` - /// - /// [naming-threads]: ./index.html#naming-threads - #[stable(feature = "rust1", since = "1.0.0")] - pub fn name(mut self, name: String) -> Builder { - self.name = Some(name); - self - } - - /// Sets the size of the stack (in bytes) for the new thread. - /// - /// The actual stack size may be greater than this value if - /// the platform specifies minimal stack size. - /// - /// For more information about the stack size for threads, see - /// [this module-level documentation][stack-size]. - /// - /// # Examples - /// - /// ``` - /// use std::thread; - /// - /// let builder = thread::Builder::new().stack_size(32 * 1024); - /// ``` - /// - /// [stack-size]: ./index.html#stack-size - #[stable(feature = "rust1", since = "1.0.0")] - pub fn stack_size(mut self, size: usize) -> Builder { - self.stack_size = Some(size); - self - } - - /// Spawns a new thread by taking ownership of the `Builder`, and returns an - /// [`io::Result`] to its [`JoinHandle`]. - /// - /// The spawned thread may outlive the caller (unless the caller thread - /// is the main thread; the whole process is terminated when the main - /// thread finishes). The join handle can be used to block on - /// termination of the child thread, including recovering its panics. - /// - /// For a more complete documentation see [`thread::spawn`][`spawn`]. - /// - /// # Errors - /// - /// Unlike the [`spawn`] free function, this method yields an - /// [`io::Result`] to capture any failure to create the thread at - /// the OS level. - /// - /// [`spawn`]: ../../std/thread/fn.spawn.html - /// [`io::Result`]: ../../std/io/type.Result.html - /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html - /// - /// # Panics - /// - /// Panics if a thread name was set and it contained null bytes. - /// - /// # Examples - /// - /// ``` - /// use std::thread; - /// - /// let builder = thread::Builder::new(); - /// - /// let handler = builder.spawn(|| { - /// // thread code - /// }).unwrap(); - /// - /// handler.join().unwrap(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn spawn(self, f: F) -> io::Result> where - F: FnOnce() -> T, F: Send + 'static, T: Send + 'static - { - let Builder { name, stack_size } = self; - - let stack_size = stack_size.unwrap_or_else(thread::min_stack); - - let my_thread = Thread::new(name); - let their_thread = my_thread.clone(); - - let my_packet : Arc>>> - = Arc::new(UnsafeCell::new(None)); - let their_packet = my_packet.clone(); - - let main = move || { - if let Some(name) = their_thread.cname() { - imp::Thread::set_name(name); - } - unsafe { - thread_info::set(imp::guard::current(), their_thread); - #[cfg(feature = "backtrace")] - let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { - ::sys_common::backtrace::__rust_begin_short_backtrace(f) - })); - #[cfg(not(feature = "backtrace"))] - let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f)); - *their_packet.get() = Some(try_result); - } - }; - - Ok(JoinHandle(JoinInner { - native: unsafe { - Some(imp::Thread::new(stack_size, Box::new(main))?) - }, - thread: my_thread, - packet: Packet(my_packet), - })) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Free functions -//////////////////////////////////////////////////////////////////////////////// - -/// Spawns a new thread, returning a [`JoinHandle`] for it. -/// -/// The join handle will implicitly *detach* the child thread upon being -/// dropped. In this case, the child thread may outlive the parent (unless -/// the parent thread is the main thread; the whole process is terminated when -/// the main thread finishes). Additionally, the join handle provides a [`join`] -/// method that can be used to join the child thread. If the child thread -/// panics, [`join`] will return an [`Err`] containing the argument given to -/// [`panic`]. -/// -/// This will create a thread using default parameters of [`Builder`], if you -/// want to specify the stack size or the name of the thread, use this API -/// instead. -/// -/// As you can see in the signature of `spawn` there are two constraints on -/// both the closure given to `spawn` and its return value, let's explain them: -/// -/// - The `'static` constraint means that the closure and its return value -/// must have a lifetime of the whole program execution. The reason for this -/// is that threads can `detach` and outlive the lifetime they have been -/// created in. -/// Indeed if the thread, and by extension its return value, can outlive their -/// caller, we need to make sure that they will be valid afterwards, and since -/// we *can't* know when it will return we need to have them valid as long as -/// possible, that is until the end of the program, hence the `'static` -/// lifetime. -/// - The [`Send`] constraint is because the closure will need to be passed -/// *by value* from the thread where it is spawned to the new thread. Its -/// return value will need to be passed from the new thread to the thread -/// where it is `join`ed. -/// As a reminder, the [`Send`] marker trait expresses that it is safe to be -/// passed from thread to thread. [`Sync`] expresses that it is safe to have a -/// reference be passed from thread to thread. -/// -/// # Panics -/// -/// Panics if the OS fails to create a thread; use [`Builder::spawn`] -/// to recover from such errors. -/// -/// # Examples -/// -/// Creating a thread. -/// -/// ``` -/// use std::thread; -/// -/// let handler = thread::spawn(|| { -/// // thread code -/// }); -/// -/// handler.join().unwrap(); -/// ``` -/// -/// As mentioned in the module documentation, threads are usually made to -/// communicate using [`channels`], here is how it usually looks. -/// -/// This example also shows how to use `move`, in order to give ownership -/// of values to a thread. -/// -/// ``` -/// use std::thread; -/// use std::sync::mpsc::channel; -/// -/// let (tx, rx) = channel(); -/// -/// let sender = thread::spawn(move || { -/// tx.send("Hello, thread".to_owned()) -/// .expect("Unable to send on channel"); -/// }); -/// -/// let receiver = thread::spawn(move || { -/// let value = rx.recv().expect("Unable to receive from channel"); -/// println!("{}", value); -/// }); -/// -/// sender.join().expect("The sender thread has panicked"); -/// receiver.join().expect("The receiver thread has panicked"); -/// ``` -/// -/// A thread can also return a value through its [`JoinHandle`], you can use -/// this to make asynchronous computations (futures might be more appropriate -/// though). -/// -/// ``` -/// use std::thread; -/// -/// let computation = thread::spawn(|| { -/// // Some expensive computation. -/// 42 -/// }); -/// -/// let result = computation.join().unwrap(); -/// println!("{}", result); -/// ``` -/// -/// [`channels`]: ../../std/sync/mpsc/index.html -/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join -/// [`Err`]: ../../std/result/enum.Result.html#variant.Err -/// [`panic`]: ../../std/macro.panic.html -/// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn -/// [`Builder`]: ../../std/thread/struct.Builder.html -/// [`Send`]: ../../std/marker/trait.Send.html -/// [`Sync`]: ../../std/marker/trait.Sync.html -#[stable(feature = "rust1", since = "1.0.0")] -pub fn spawn(f: F) -> JoinHandle where - F: FnOnce() -> T, F: Send + 'static, T: Send + 'static -{ - Builder::new().spawn(f).unwrap() -} - -/// Gets a handle to the thread that invokes it. -/// -/// # Examples -/// -/// Getting a handle to the current thread with `thread::current()`: -/// -/// ``` -/// use std::thread; -/// -/// let handler = thread::Builder::new() -/// .name("named thread".into()) -/// .spawn(|| { -/// let handle = thread::current(); -/// assert_eq!(handle.name(), Some("named thread")); -/// }) -/// .unwrap(); -/// -/// handler.join().unwrap(); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn current() -> Thread { - thread_info::current_thread().expect("use of std::thread::current() is not \ - possible after the thread's local \ - data has been destroyed") -} - -/// Cooperatively gives up a timeslice to the OS scheduler. -/// -/// This is used when the programmer knows that the thread will have nothing -/// to do for some time, and thus avoid wasting computing time. -/// -/// For example when polling on a resource, it is common to check that it is -/// available, and if not to yield in order to avoid busy waiting. -/// -/// Thus the pattern of `yield`ing after a failed poll is rather common when -/// implementing low-level shared resources or synchronization primitives. -/// -/// However programmers will usually prefer to use, [`channel`]s, [`Condvar`]s, -/// [`Mutex`]es or [`join`] for their synchronization routines, as they avoid -/// thinking about thread scheduling. -/// -/// Note that [`channel`]s for example are implemented using this primitive. -/// Indeed when you call `send` or `recv`, which are blocking, they will yield -/// if the channel is not available. -/// -/// # Examples -/// -/// ``` -/// use std::thread; -/// -/// thread::yield_now(); -/// ``` -/// -/// [`channel`]: ../../std/sync/mpsc/index.html -/// [`spawn`]: ../../std/thread/fn.spawn.html -/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join -/// [`Mutex`]: ../../std/sync/struct.Mutex.html -/// [`Condvar`]: ../../std/sync/struct.Condvar.html -#[stable(feature = "rust1", since = "1.0.0")] -pub fn yield_now() { - imp::Thread::yield_now() -} - -/// Determines whether the current thread is unwinding because of panic. -/// -/// A common use of this feature is to poison shared resources when writing -/// unsafe code, by checking `panicking` when the `drop` is called. -/// -/// This is usually not needed when writing safe code, as [`Mutex`es][Mutex] -/// already poison themselves when a thread panics while holding the lock. -/// -/// This can also be used in multithreaded applications, in order to send a -/// message to other threads warning that a thread has panicked (e.g. for -/// monitoring purposes). -/// -/// # Examples -/// -/// ```should_panic -/// use std::thread; -/// -/// struct SomeStruct; -/// -/// impl Drop for SomeStruct { -/// fn drop(&mut self) { -/// if thread::panicking() { -/// println!("dropped while unwinding"); -/// } else { -/// println!("dropped while not unwinding"); -/// } -/// } -/// } -/// -/// { -/// print!("a: "); -/// let a = SomeStruct; -/// } -/// -/// { -/// print!("b: "); -/// let b = SomeStruct; -/// panic!() -/// } -/// ``` -/// -/// [Mutex]: ../../std/sync/struct.Mutex.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn panicking() -> bool { - panicking::panicking() -} - -/// Puts the current thread to sleep for the specified amount of time. -/// -/// The thread may sleep longer than the duration specified due to scheduling -/// specifics or platform-dependent functionality. -/// -/// # Platform-specific behavior -/// -/// On Unix platforms this function will not return early due to a -/// signal being received or a spurious wakeup. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// -/// // Let's sleep for 2 seconds: -/// thread::sleep_ms(2000); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::sleep`")] -pub fn sleep_ms(ms: u32) { - sleep(Duration::from_millis(ms as u64)) -} - -/// Puts the current thread to sleep for the specified amount of time. -/// -/// The thread may sleep longer than the duration specified due to scheduling -/// specifics or platform-dependent functionality. -/// -/// # Platform-specific behavior -/// -/// On Unix platforms this function will not return early due to a -/// signal being received or a spurious wakeup. Platforms which do not support -/// nanosecond precision for sleeping will have `dur` rounded up to the nearest -/// granularity of time they can sleep for. -/// -/// # Examples -/// -/// ```no_run -/// use std::{thread, time}; -/// -/// let ten_millis = time::Duration::from_millis(10); -/// let now = time::Instant::now(); -/// -/// thread::sleep(ten_millis); -/// -/// assert!(now.elapsed() >= ten_millis); -/// ``` -#[stable(feature = "thread_sleep", since = "1.4.0")] -pub fn sleep(dur: Duration) { - imp::Thread::sleep(dur) -} - -// constants for park/unpark -const EMPTY: usize = 0; -const PARKED: usize = 1; -const NOTIFIED: usize = 2; - -/// Blocks unless or until the current thread's token is made available. -/// -/// A call to `park` does not guarantee that the thread will remain parked -/// forever, and callers should be prepared for this possibility. -/// -/// # park and unpark -/// -/// Every thread is equipped with some basic low-level blocking support, via the -/// [`thread::park`][`park`] function and [`thread::Thread::unpark`][`unpark`] -/// method. [`park`] blocks the current thread, which can then be resumed from -/// another thread by calling the [`unpark`] method on the blocked thread's -/// handle. -/// -/// Conceptually, each [`Thread`] handle has an associated token, which is -/// initially not present: -/// -/// * The [`thread::park`][`park`] function blocks the current thread unless or -/// until the token is available for its thread handle, at which point it -/// atomically consumes the token. It may also return *spuriously*, without -/// consuming the token. [`thread::park_timeout`] does the same, but allows -/// specifying a maximum time to block the thread for. -/// -/// * The [`unpark`] method on a [`Thread`] atomically makes the token available -/// if it wasn't already. Because the token is initially absent, [`unpark`] -/// followed by [`park`] will result in the second call returning immediately. -/// -/// In other words, each [`Thread`] acts a bit like a spinlock that can be -/// locked and unlocked using `park` and `unpark`. -/// -/// The API is typically used by acquiring a handle to the current thread, -/// placing that handle in a shared data structure so that other threads can -/// find it, and then `park`ing. When some desired condition is met, another -/// thread calls [`unpark`] on the handle. -/// -/// The motivation for this design is twofold: -/// -/// * It avoids the need to allocate mutexes and condvars when building new -/// synchronization primitives; the threads already provide basic -/// blocking/signaling. -/// -/// * It can be implemented very efficiently on many platforms. -/// -/// # Examples -/// -/// ``` -/// use std::thread; -/// use std::time::Duration; -/// -/// let parked_thread = thread::Builder::new() -/// .spawn(|| { -/// println!("Parking thread"); -/// thread::park(); -/// println!("Thread unparked"); -/// }) -/// .unwrap(); -/// -/// // Let some time pass for the thread to be spawned. -/// thread::sleep(Duration::from_millis(10)); -/// -/// // There is no race condition here, if `unpark` -/// // happens first, `park` will return immediately. -/// println!("Unpark the thread"); -/// parked_thread.thread().unpark(); -/// -/// parked_thread.join().unwrap(); -/// ``` -/// -/// [`Thread`]: ../../std/thread/struct.Thread.html -/// [`park`]: ../../std/thread/fn.park.html -/// [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark -/// [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html -// -// The implementation currently uses the trivial strategy of a Mutex+Condvar -// with wakeup flag, which does not actually allow spurious wakeups. In the -// future, this will be implemented in a more efficient way, perhaps along the lines of -// http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp -// or futuxes, and in either case may allow spurious wakeups. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn park() { - let thread = current(); - - // If we were previously notified then we consume this notification and - // return quickly. - if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { - return - } - - // Otherwise we need to coordinate going to sleep - let mut m = thread.inner.lock.lock().unwrap(); - match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { - Ok(_) => {} - Err(NOTIFIED) => { - thread.inner.state.store(EMPTY, SeqCst); - return; - } // should consume this notification, so prohibit spurious wakeups in next park. - Err(_) => panic!("inconsistent park state"), - } - loop { - m = thread.inner.cvar.wait(m).unwrap(); - match thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { - Ok(_) => return, // got a notification - Err(_) => {} // spurious wakeup, go back to sleep - } - } -} - -/// Use [`park_timeout`]. -/// -/// Blocks unless or until the current thread's token is made available or -/// the specified duration has been reached (may wake spuriously). -/// -/// The semantics of this function are equivalent to [`park`] except -/// that the thread will be blocked for roughly no longer than `dur`. This -/// method should not be used for precise timing due to anomalies such as -/// preemption or platform differences that may not cause the maximum -/// amount of time waited to be precisely `ms` long. -/// -/// See the [park documentation][`park`] for more detail. -/// -/// [`park_timeout`]: fn.park_timeout.html -/// [`park`]: ../../std/thread/fn.park.html -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::park_timeout`")] -pub fn park_timeout_ms(ms: u32) { - park_timeout(Duration::from_millis(ms as u64)) -} - -/// Blocks unless or until the current thread's token is made available or -/// the specified duration has been reached (may wake spuriously). -/// -/// The semantics of this function are equivalent to [`park`][park] except -/// that the thread will be blocked for roughly no longer than `dur`. This -/// method should not be used for precise timing due to anomalies such as -/// preemption or platform differences that may not cause the maximum -/// amount of time waited to be precisely `dur` long. -/// -/// See the [park documentation][park] for more details. -/// -/// # Platform-specific behavior -/// -/// Platforms which do not support nanosecond precision for sleeping will have -/// `dur` rounded up to the nearest granularity of time they can sleep for. -/// -/// # Examples -/// -/// Waiting for the complete expiration of the timeout: -/// -/// ```rust,no_run -/// use std::thread::park_timeout; -/// use std::time::{Instant, Duration}; -/// -/// let timeout = Duration::from_secs(2); -/// let beginning_park = Instant::now(); -/// -/// let mut timeout_remaining = timeout; -/// loop { -/// park_timeout(timeout_remaining); -/// let elapsed = beginning_park.elapsed(); -/// if elapsed >= timeout { -/// break; -/// } -/// println!("restarting park_timeout after {:?}", elapsed); -/// timeout_remaining = timeout - elapsed; -/// } -/// ``` -/// -/// [park]: fn.park.html -#[stable(feature = "park_timeout", since = "1.4.0")] -pub fn park_timeout(dur: Duration) { - let thread = current(); - - // Like `park` above we have a fast path for an already-notified thread, and - // afterwards we start coordinating for a sleep. - // return quickly. - if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { - return - } - let m = thread.inner.lock.lock().unwrap(); - match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { - Ok(_) => {} - Err(NOTIFIED) => { - thread.inner.state.store(EMPTY, SeqCst); - return; - } // should consume this notification, so prohibit spurious wakeups in next park. - Err(_) => panic!("inconsistent park_timeout state"), - } - - // Wait with a timeout, and if we spuriously wake up or otherwise wake up - // from a notification we just want to unconditionally set the state back to - // empty, either consuming a notification or un-flagging ourselves as - // parked. - let (_m, _result) = thread.inner.cvar.wait_timeout(m, dur).unwrap(); - match thread.inner.state.swap(EMPTY, SeqCst) { - NOTIFIED => {} // got a notification, hurray! - PARKED => {} // no notification, alas - n => panic!("inconsistent park_timeout state: {}", n), - } -} - -//////////////////////////////////////////////////////////////////////////////// -// ThreadId -//////////////////////////////////////////////////////////////////////////////// - -/// A unique identifier for a running thread. -/// -/// A `ThreadId` is an opaque object that has a unique value for each thread -/// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's -/// system-designated identifier. A `ThreadId` can be retrieved from the [`id`] -/// method on a [`Thread`]. -/// -/// # Examples -/// -/// ``` -/// use std::thread; -/// -/// let other_thread = thread::spawn(|| { -/// thread::current().id() -/// }); -/// -/// let other_thread_id = other_thread.join().unwrap(); -/// assert!(thread::current().id() != other_thread_id); -/// ``` -/// -/// [`id`]: ../../std/thread/struct.Thread.html#method.id -/// [`Thread`]: ../../std/thread/struct.Thread.html -#[stable(feature = "thread_id", since = "1.19.0")] -#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)] -pub struct ThreadId(u64); - -impl ThreadId { - // Generate a new unique thread ID. - fn new() -> ThreadId { - // We never call `GUARD.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static GUARD: mutex::Mutex = mutex::Mutex::new(); - static mut COUNTER: u64 = 0; - - unsafe { - let _guard = GUARD.lock(); - - // If we somehow use up all our bits, panic so that we're not - // covering up subtle bugs of IDs being reused. - if COUNTER == ::u64::MAX { - panic!("failed to generate unique thread ID: bitspace exhausted"); - } - - let id = COUNTER; - COUNTER += 1; - - ThreadId(id) - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Thread -//////////////////////////////////////////////////////////////////////////////// - -/// The internal representation of a `Thread` handle -struct Inner { - name: Option, // Guaranteed to be UTF-8 - id: ThreadId, - - // state for thread park/unpark - state: AtomicUsize, - lock: Mutex<()>, - cvar: Condvar, -} - -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -/// A handle to a thread. -/// -/// Threads are represented via the `Thread` type, which you can get in one of -/// two ways: -/// -/// * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] -/// function, and calling [`thread`][`JoinHandle::thread`] on the -/// [`JoinHandle`]. -/// * By requesting the current thread, using the [`thread::current`] function. -/// -/// The [`thread::current`] function is available even for threads not spawned -/// by the APIs of this module. -/// -/// There is usually no need to create a `Thread` struct yourself, one -/// should instead use a function like `spawn` to create new threads, see the -/// docs of [`Builder`] and [`spawn`] for more details. -/// -/// [`Builder`]: ../../std/thread/struct.Builder.html -/// [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread -/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -/// [`thread::current`]: ../../std/thread/fn.current.html -/// [`spawn`]: ../../std/thread/fn.spawn.html - -pub struct Thread { - inner: Arc, -} - -impl Thread { - // Used only internally to construct a thread object without spawning - // Panics if the name contains nuls. - pub(crate) fn new(name: Option) -> Thread { - let cname = name.map(|n| { - CString::new(n).expect("thread name may not contain interior null bytes") - }); - Thread { - inner: Arc::new(Inner { - name: cname, - id: ThreadId::new(), - state: AtomicUsize::new(EMPTY), - lock: Mutex::new(()), - cvar: Condvar::new(), - }) - } - } - - /// Atomically makes the handle's token available if it is not already. - /// - /// Every thread is equipped with some basic low-level blocking support, via - /// the [`park`][park] function and the `unpark()` method. These can be - /// used as a more CPU-efficient implementation of a spinlock. - /// - /// See the [park documentation][park] for more details. - /// - /// # Examples - /// - /// ``` - /// use std::thread; - /// use std::time::Duration; - /// - /// let parked_thread = thread::Builder::new() - /// .spawn(|| { - /// println!("Parking thread"); - /// thread::park(); - /// println!("Thread unparked"); - /// }) - /// .unwrap(); - /// - /// // Let some time pass for the thread to be spawned. - /// thread::sleep(Duration::from_millis(10)); - /// - /// println!("Unpark the thread"); - /// parked_thread.thread().unpark(); - /// - /// parked_thread.join().unwrap(); - /// ``` - /// - /// [park]: fn.park.html - #[stable(feature = "rust1", since = "1.0.0")] - pub fn unpark(&self) { - loop { - match self.inner.state.compare_exchange(EMPTY, NOTIFIED, SeqCst, SeqCst) { - Ok(_) => return, // no one was waiting - Err(NOTIFIED) => return, // already unparked - Err(PARKED) => {} // gotta go wake someone up - _ => panic!("inconsistent state in unpark"), - } - - // Coordinate wakeup through the mutex and a condvar notification - let _lock = self.inner.lock.lock().unwrap(); - match self.inner.state.compare_exchange(PARKED, NOTIFIED, SeqCst, SeqCst) { - Ok(_) => return self.inner.cvar.notify_one(), - Err(NOTIFIED) => return, // a different thread unparked - Err(EMPTY) => {} // parked thread went away, try again - _ => panic!("inconsistent state in unpark"), - } - } - } - - /// Gets the thread's unique identifier. - /// - /// # Examples - /// - /// ``` - /// use std::thread; - /// - /// let other_thread = thread::spawn(|| { - /// thread::current().id() - /// }); - /// - /// let other_thread_id = other_thread.join().unwrap(); - /// assert!(thread::current().id() != other_thread_id); - /// ``` - #[stable(feature = "thread_id", since = "1.19.0")] - pub fn id(&self) -> ThreadId { - self.inner.id - } - - /// Gets the thread's name. - /// - /// For more information about named threads, see - /// [this module-level documentation][naming-threads]. - /// - /// # Examples - /// - /// Threads by default have no name specified: - /// - /// ``` - /// use std::thread; - /// - /// let builder = thread::Builder::new(); - /// - /// let handler = builder.spawn(|| { - /// assert!(thread::current().name().is_none()); - /// }).unwrap(); - /// - /// handler.join().unwrap(); - /// ``` - /// - /// Thread with a specified name: - /// - /// ``` - /// use std::thread; - /// - /// let builder = thread::Builder::new() - /// .name("foo".into()); - /// - /// let handler = builder.spawn(|| { - /// assert_eq!(thread::current().name(), Some("foo")) - /// }).unwrap(); - /// - /// handler.join().unwrap(); - /// ``` - /// - /// [naming-threads]: ./index.html#naming-threads - #[stable(feature = "rust1", since = "1.0.0")] - pub fn name(&self) -> Option<&str> { - self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) } ) - } - - fn cname(&self) -> Option<&CStr> { - self.inner.name.as_ref().map(|s| &**s) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Thread { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.name(), f) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// JoinHandle -//////////////////////////////////////////////////////////////////////////////// - -/// A specialized [`Result`] type for threads. -/// -/// Indicates the manner in which a thread exited. -/// -/// A thread that completes without panicking is considered to exit successfully. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::fs; -/// -/// fn copy_in_thread() -> thread::Result<()> { -/// thread::spawn(move || { fs::copy("foo.txt", "bar.txt").unwrap(); }).join() -/// } -/// -/// fn main() { -/// match copy_in_thread() { -/// Ok(_) => println!("this is fine"), -/// Err(_) => println!("thread panicked"), -/// } -/// } -/// ``` -/// -/// [`Result`]: ../../std/result/enum.Result.html -#[stable(feature = "rust1", since = "1.0.0")] -pub type Result = ::result::Result>; - -// This packet is used to communicate the return value between the child thread -// and the parent thread. Memory is shared through the `Arc` within and there's -// no need for a mutex here because synchronization happens with `join()` (the -// parent thread never reads this packet until the child has exited). -// -// This packet itself is then stored into a `JoinInner` which in turns is placed -// in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to -// manually worry about impls like Send and Sync. The type `T` should -// already always be Send (otherwise the thread could not have been created) and -// this type is inherently Sync because no methods take &self. Regardless, -// however, we add inheriting impls for Send/Sync to this type to ensure it's -// Send/Sync and that future modifications will still appropriately classify it. -struct Packet(Arc>>>); - -unsafe impl Send for Packet {} -unsafe impl Sync for Packet {} - -/// Inner representation for JoinHandle -struct JoinInner { - native: Option, - thread: Thread, - packet: Packet, -} - -impl JoinInner { - fn join(&mut self) -> Result { - self.native.take().unwrap().join(); - unsafe { - (*self.packet.0.get()).take().unwrap() - } - } -} - -/// An owned permission to join on a thread (block on its termination). -/// -/// A `JoinHandle` *detaches* the associated thread when it is dropped, which -/// means that there is no longer any handle to thread and no way to `join` -/// on it. -/// -/// Due to platform restrictions, it is not possible to [`Clone`] this -/// handle: the ability to join a thread is a uniquely-owned permission. -/// -/// This `struct` is created by the [`thread::spawn`] function and the -/// [`thread::Builder::spawn`] method. -/// -/// # Examples -/// -/// Creation from [`thread::spawn`]: -/// -/// ``` -/// use std::thread; -/// -/// let join_handle: thread::JoinHandle<_> = thread::spawn(|| { -/// // some work here -/// }); -/// ``` -/// -/// Creation from [`thread::Builder::spawn`]: -/// -/// ``` -/// use std::thread; -/// -/// let builder = thread::Builder::new(); -/// -/// let join_handle: thread::JoinHandle<_> = builder.spawn(|| { -/// // some work here -/// }).unwrap(); -/// ``` -/// -/// Child being detached and outliving its parent: -/// -/// ```no_run -/// use std::thread; -/// use std::time::Duration; -/// -/// let original_thread = thread::spawn(|| { -/// let _detached_thread = thread::spawn(|| { -/// // Here we sleep to make sure that the first thread returns before. -/// thread::sleep(Duration::from_millis(10)); -/// // This will be called, even though the JoinHandle is dropped. -/// println!("♫ Still alive ♫"); -/// }); -/// }); -/// -/// original_thread.join().expect("The thread being joined has panicked"); -/// println!("Original thread is joined."); -/// -/// // We make sure that the new thread has time to run, before the main -/// // thread returns. -/// -/// thread::sleep(Duration::from_millis(1000)); -/// ``` -/// -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [`thread::spawn`]: fn.spawn.html -/// [`thread::Builder::spawn`]: struct.Builder.html#method.spawn -#[stable(feature = "rust1", since = "1.0.0")] -pub struct JoinHandle(JoinInner); - -#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")] -unsafe impl Send for JoinHandle {} -#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")] -unsafe impl Sync for JoinHandle {} - -impl JoinHandle { - /// Extracts a handle to the underlying thread. - /// - /// # Examples - /// - /// ``` - /// use std::thread; - /// - /// let builder = thread::Builder::new(); - /// - /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| { - /// // some work here - /// }).unwrap(); - /// - /// let thread = join_handle.thread(); - /// println!("thread id: {:?}", thread.id()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn thread(&self) -> &Thread { - &self.0.thread - } - - /// Waits for the associated thread to finish. - /// - /// If the child thread panics, [`Err`] is returned with the parameter given - /// to [`panic`]. - /// - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// [`panic`]: ../../std/macro.panic.html - /// - /// # Panics - /// - /// This function may panic on some platforms if a thread attempts to join - /// itself or otherwise may create a deadlock with joining threads. - /// - /// # Examples - /// - /// ``` - /// use std::thread; - /// - /// let builder = thread::Builder::new(); - /// - /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| { - /// // some work here - /// }).unwrap(); - /// join_handle.join().expect("Couldn't join on the associated thread"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn join(mut self) -> Result { - self.0.join() - } -} - -impl AsInner for JoinHandle { - fn as_inner(&self) -> &imp::Thread { self.0.native.as_ref().unwrap() } -} - -impl IntoInner for JoinHandle { - fn into_inner(self) -> imp::Thread { self.0.native.unwrap() } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for JoinHandle { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("JoinHandle { .. }") - } -} - -fn _assert_sync_and_send() { - fn _assert_both() {} - _assert_both::>(); - _assert_both::(); -} - -//////////////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////////////// - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use any::Any; - use sync::mpsc::{channel, Sender}; - use result; - use super::{Builder}; - use thread; - use time::Duration; - use u32; - - // !!! These tests are dangerous. If something is buggy, they will hang, !!! - // !!! instead of exiting cleanly. This might wedge the buildbots. !!! - - #[test] - fn test_unnamed_thread() { - thread::spawn(move|| { - assert!(thread::current().name().is_none()); - }).join().ok().unwrap(); - } - - #[test] - fn test_named_thread() { - Builder::new().name("ada lovelace".to_string()).spawn(move|| { - assert!(thread::current().name().unwrap() == "ada lovelace".to_string()); - }).unwrap().join().unwrap(); - } - - #[test] - #[should_panic] - fn test_invalid_named_thread() { - let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {}); - } - - #[test] - fn test_run_basic() { - let (tx, rx) = channel(); - thread::spawn(move|| { - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_join_panic() { - match thread::spawn(move|| { - panic!() - }).join() { - result::Result::Err(_) => (), - result::Result::Ok(()) => panic!() - } - } - - #[test] - fn test_spawn_sched() { - let (tx, rx) = channel(); - - fn f(i: i32, tx: Sender<()>) { - let tx = tx.clone(); - thread::spawn(move|| { - if i == 0 { - tx.send(()).unwrap(); - } else { - f(i - 1, tx); - } - }); - - } - f(10, tx); - rx.recv().unwrap(); - } - - #[test] - fn test_spawn_sched_childs_on_default_sched() { - let (tx, rx) = channel(); - - thread::spawn(move|| { - thread::spawn(move|| { - tx.send(()).unwrap(); - }); - }); - - rx.recv().unwrap(); - } - - fn avoid_copying_the_body(spawnfn: F) where F: FnOnce(Box) { - let (tx, rx) = channel(); - - let x: Box<_> = box 1; - let x_in_parent = (&*x) as *const i32 as usize; - - spawnfn(Box::new(move|| { - let x_in_child = (&*x) as *const i32 as usize; - tx.send(x_in_child).unwrap(); - })); - - let x_in_child = rx.recv().unwrap(); - assert_eq!(x_in_parent, x_in_child); - } - - #[test] - fn test_avoid_copying_the_body_spawn() { - avoid_copying_the_body(|v| { - thread::spawn(move || v()); - }); - } - - #[test] - fn test_avoid_copying_the_body_thread_spawn() { - avoid_copying_the_body(|f| { - thread::spawn(move|| { - f(); - }); - }) - } - - #[test] - fn test_avoid_copying_the_body_join() { - avoid_copying_the_body(|f| { - let _ = thread::spawn(move|| { - f() - }).join(); - }) - } - - #[test] - fn test_child_doesnt_ref_parent() { - // If the child refcounts the parent thread, this will stack overflow when - // climbing the thread tree to dereference each ancestor. (See #1789) - // (well, it would if the constant were 8000+ - I lowered it to be more - // valgrind-friendly. try this at home, instead..!) - const GENERATIONS: u32 = 16; - fn child_no(x: u32) -> Box { - return Box::new(move|| { - if x < GENERATIONS { - thread::spawn(move|| child_no(x+1)()); - } - }); - } - thread::spawn(|| child_no(0)()); - } - - #[test] - fn test_simple_newsched_spawn() { - thread::spawn(move || {}); - } - - #[test] - fn test_try_panic_message_static_str() { - match thread::spawn(move|| { - panic!("static string"); - }).join() { - Err(e) => { - type T = &'static str; - assert!(e.is::()); - assert_eq!(*e.downcast::().unwrap(), "static string"); - } - Ok(()) => panic!() - } - } - - #[test] - fn test_try_panic_message_owned_str() { - match thread::spawn(move|| { - panic!("owned string".to_string()); - }).join() { - Err(e) => { - type T = String; - assert!(e.is::()); - assert_eq!(*e.downcast::().unwrap(), "owned string".to_string()); - } - Ok(()) => panic!() - } - } - - #[test] - fn test_try_panic_message_any() { - match thread::spawn(move|| { - panic!(box 413u16 as Box); - }).join() { - Err(e) => { - type T = Box; - assert!(e.is::()); - let any = e.downcast::().unwrap(); - assert!(any.is::()); - assert_eq!(*any.downcast::().unwrap(), 413); - } - Ok(()) => panic!() - } - } - - #[test] - fn test_try_panic_message_unit_struct() { - struct Juju; - - match thread::spawn(move|| { - panic!(Juju) - }).join() { - Err(ref e) if e.is::() => {} - Err(_) | Ok(()) => panic!() - } - } - - #[test] - fn test_park_timeout_unpark_before() { - for _ in 0..10 { - thread::current().unpark(); - thread::park_timeout(Duration::from_millis(u32::MAX as u64)); - } - } - - #[test] - fn test_park_timeout_unpark_not_called() { - for _ in 0..10 { - thread::park_timeout(Duration::from_millis(10)); - } - } - - #[test] - fn test_park_timeout_unpark_called_other_thread() { - for _ in 0..10 { - let th = thread::current(); - - let _guard = thread::spawn(move || { - super::sleep(Duration::from_millis(50)); - th.unpark(); - }); - - thread::park_timeout(Duration::from_millis(u32::MAX as u64)); - } - } - - #[test] - fn sleep_ms_smoke() { - thread::sleep(Duration::from_millis(2)); - } - - #[test] - fn test_thread_id_equal() { - assert!(thread::current().id() == thread::current().id()); - } - - #[test] - fn test_thread_id_not_equal() { - let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap(); - assert!(thread::current().id() != spawned_id); - } - - // NOTE: the corresponding test for stderr is in run-pass/thread-stderr, due - // to the test harness apparently interfering with stderr configuration. -} diff --git a/ctr-std/src/time.rs b/ctr-std/src/time.rs deleted file mode 100644 index 90ab349..0000000 --- a/ctr-std/src/time.rs +++ /dev/null @@ -1,593 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Temporal quantification. -//! -//! Example: -//! -//! ``` -//! use std::time::Duration; -//! -//! let five_seconds = Duration::new(5, 0); -//! // both declarations are equivalent -//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); -//! ``` - -#![stable(feature = "time", since = "1.3.0")] - -use error::Error; -use fmt; -use ops::{Add, Sub, AddAssign, SubAssign}; -use sys::time; -use sys_common::FromInner; - -#[stable(feature = "time", since = "1.3.0")] -pub use core::time::Duration; - -/// A measurement of a monotonically nondecreasing clock. -/// Opaque and useful only with `Duration`. -/// -/// Instants are always guaranteed to be no less than any previously measured -/// instant when created, and are often useful for tasks such as measuring -/// benchmarks or timing how long an operation takes. -/// -/// Note, however, that instants are not guaranteed to be **steady**. In other -/// words, each tick of the underlying clock may not be the same length (e.g. -/// some seconds may be longer than others). An instant may jump forwards or -/// experience time dilation (slow down or speed up), but it will never go -/// backwards. -/// -/// Instants are opaque types that can only be compared to one another. There is -/// no method to get "the number of seconds" from an instant. Instead, it only -/// allows measuring the duration between two instants (or comparing two -/// instants). -/// -/// The size of an `Instant` struct may vary depending on the target operating -/// system. -/// -/// Example: -/// -/// ```no_run -/// use std::time::{Duration, Instant}; -/// use std::thread::sleep; -/// -/// fn main() { -/// let now = Instant::now(); -/// -/// // we sleep for 2 seconds -/// sleep(Duration::new(2, 0)); -/// // it prints '2' -/// println!("{}", now.elapsed().as_secs()); -/// } -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[stable(feature = "time2", since = "1.8.0")] -pub struct Instant(time::Instant); - -/// A measurement of the system clock, useful for talking to -/// external entities like the file system or other processes. -/// -/// Distinct from the [`Instant`] type, this time measurement **is not -/// monotonic**. This means that you can save a file to the file system, then -/// save another file to the file system, **and the second file has a -/// `SystemTime` measurement earlier than the first**. In other words, an -/// operation that happens after another operation in real time may have an -/// earlier `SystemTime`! -/// -/// Consequently, comparing two `SystemTime` instances to learn about the -/// duration between them returns a [`Result`] instead of an infallible [`Duration`] -/// to indicate that this sort of time drift may happen and needs to be handled. -/// -/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`] -/// constant is provided in this module as an anchor in time to learn -/// information about a `SystemTime`. By calculating the duration from this -/// fixed point in time, a `SystemTime` can be converted to a human-readable time, -/// or perhaps some other string representation. -/// -/// The size of a `SystemTime` struct may vary depending on the target operating -/// system. -/// -/// [`Instant`]: ../../std/time/struct.Instant.html -/// [`Result`]: ../../std/result/enum.Result.html -/// [`Duration`]: ../../std/time/struct.Duration.html -/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html -/// -/// Example: -/// -/// ```no_run -/// use std::time::{Duration, SystemTime}; -/// use std::thread::sleep; -/// -/// fn main() { -/// let now = SystemTime::now(); -/// -/// // we sleep for 2 seconds -/// sleep(Duration::new(2, 0)); -/// match now.elapsed() { -/// Ok(elapsed) => { -/// // it prints '2' -/// println!("{}", elapsed.as_secs()); -/// } -/// Err(e) => { -/// // an error occurred! -/// println!("Error: {:?}", e); -/// } -/// } -/// } -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[stable(feature = "time2", since = "1.8.0")] -pub struct SystemTime(time::SystemTime); - -/// An error returned from the `duration_since` and `elapsed` methods on -/// `SystemTime`, used to learn how far in the opposite direction a system time -/// lies. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread::sleep; -/// use std::time::{Duration, SystemTime}; -/// -/// let sys_time = SystemTime::now(); -/// sleep(Duration::from_secs(1)); -/// let new_sys_time = SystemTime::now(); -/// match sys_time.duration_since(new_sys_time) { -/// Ok(_) => {} -/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), -/// } -/// ``` -#[derive(Clone, Debug)] -#[stable(feature = "time2", since = "1.8.0")] -pub struct SystemTimeError(Duration); - -impl Instant { - /// Returns an instant corresponding to "now". - /// - /// # Examples - /// - /// ``` - /// use std::time::Instant; - /// - /// let now = Instant::now(); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn now() -> Instant { - Instant(time::Instant::now()) - } - - /// Returns the amount of time elapsed from another instant to this one. - /// - /// # Panics - /// - /// This function will panic if `earlier` is later than `self`. - /// - /// # Examples - /// - /// ```no_run - /// use std::time::{Duration, Instant}; - /// use std::thread::sleep; - /// - /// let now = Instant::now(); - /// sleep(Duration::new(1, 0)); - /// let new_now = Instant::now(); - /// println!("{:?}", new_now.duration_since(now)); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration_since(&self, earlier: Instant) -> Duration { - self.0.sub_instant(&earlier.0) - } - - /// Returns the amount of time elapsed since this instant was created. - /// - /// # Panics - /// - /// This function may panic if the current time is earlier than this - /// instant, which is something that can happen if an `Instant` is - /// produced synthetically. - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, Instant}; - /// - /// let instant = Instant::now(); - /// let three_secs = Duration::from_secs(3); - /// sleep(three_secs); - /// assert!(instant.elapsed() >= three_secs); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn elapsed(&self) -> Duration { - Instant::now() - *self - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Add for Instant { - type Output = Instant; - - fn add(self, other: Duration) -> Instant { - Instant(self.0.add_duration(&other)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for Instant { - fn add_assign(&mut self, other: Duration) { - *self = *self + other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for Instant { - type Output = Instant; - - fn sub(self, other: Duration) -> Instant { - Instant(self.0.sub_duration(&other)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for Instant { - fn sub_assign(&mut self, other: Duration) { - *self = *self - other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for Instant { - type Output = Duration; - - fn sub(self, other: Instant) -> Duration { - self.duration_since(other) - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl SystemTime { - /// An anchor in time which can be used to create new `SystemTime` instances or - /// learn about where in time a `SystemTime` lies. - /// - /// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with - /// respect to the system clock. Using `duration_since` on an existing - /// `SystemTime` instance can tell how far away from this point in time a - /// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a - /// `SystemTime` instance to represent another fixed point in time. - /// - /// # Examples - /// - /// ```no_run - /// use std::time::SystemTime; - /// - /// match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { - /// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), - /// Err(_) => panic!("SystemTime before UNIX EPOCH!"), - /// } - /// ``` - #[stable(feature = "assoc_unix_epoch", since = "1.28.0")] - pub const UNIX_EPOCH: SystemTime = UNIX_EPOCH; - - /// Returns the system time corresponding to "now". - /// - /// # Examples - /// - /// ``` - /// use std::time::SystemTime; - /// - /// let sys_time = SystemTime::now(); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn now() -> SystemTime { - SystemTime(time::SystemTime::now()) - } - - /// Returns the amount of time elapsed from an earlier point in time. - /// - /// This function may fail because measurements taken earlier are not - /// guaranteed to always be before later measurements (due to anomalies such - /// as the system clock being adjusted either forwards or backwards). - /// - /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents - /// the amount of time elapsed from the specified measurement to this one. - /// - /// Returns an [`Err`] if `earlier` is later than `self`, and the error - /// contains how far from `self` the time is. - /// - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Duration`]: ../../std/time/struct.Duration.html - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ``` - /// use std::time::SystemTime; - /// - /// let sys_time = SystemTime::now(); - /// let difference = sys_time.duration_since(sys_time) - /// .expect("SystemTime::duration_since failed"); - /// println!("{:?}", difference); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration_since(&self, earlier: SystemTime) - -> Result { - self.0.sub_time(&earlier.0).map_err(SystemTimeError) - } - - /// Returns the amount of time elapsed since this system time was created. - /// - /// This function may fail as the underlying system clock is susceptible to - /// drift and updates (e.g. the system clock could go backwards), so this - /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is - /// returned where the duration represents the amount of time elapsed from - /// this time measurement to the current time. - /// - /// Returns an [`Err`] if `self` is later than the current system time, and - /// the error contains how far from the current system time `self` is. - /// - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Duration`]: ../../std/time/struct.Duration.html - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, SystemTime}; - /// - /// let sys_time = SystemTime::now(); - /// let one_sec = Duration::from_secs(1); - /// sleep(one_sec); - /// assert!(sys_time.elapsed().unwrap() >= one_sec); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn elapsed(&self) -> Result { - SystemTime::now().duration_since(*self) - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Add for SystemTime { - type Output = SystemTime; - - fn add(self, dur: Duration) -> SystemTime { - SystemTime(self.0.add_duration(&dur)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for SystemTime { - fn add_assign(&mut self, other: Duration) { - *self = *self + other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for SystemTime { - type Output = SystemTime; - - fn sub(self, dur: Duration) -> SystemTime { - SystemTime(self.0.sub_duration(&dur)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for SystemTime { - fn sub_assign(&mut self, other: Duration) { - *self = *self - other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -/// An anchor in time which can be used to create new `SystemTime` instances or -/// learn about where in time a `SystemTime` lies. -/// -/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with -/// respect to the system clock. Using `duration_since` on an existing -/// [`SystemTime`] instance can tell how far away from this point in time a -/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a -/// [`SystemTime`] instance to represent another fixed point in time. -/// -/// [`SystemTime`]: ../../std/time/struct.SystemTime.html -/// -/// # Examples -/// -/// ```no_run -/// use std::time::{SystemTime, UNIX_EPOCH}; -/// -/// match SystemTime::now().duration_since(UNIX_EPOCH) { -/// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), -/// Err(_) => panic!("SystemTime before UNIX EPOCH!"), -/// } -/// ``` -#[stable(feature = "time2", since = "1.8.0")] -pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH); - -impl SystemTimeError { - /// Returns the positive duration which represents how far forward the - /// second system time was from the first. - /// - /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`] - /// methods of [`SystemTime`] whenever the second system time represents a point later - /// in time than the `self` of the method call. - /// - /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since - /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed - /// [`SystemTime`]: ../../std/time/struct.SystemTime.html - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, SystemTime}; - /// - /// let sys_time = SystemTime::now(); - /// sleep(Duration::from_secs(1)); - /// let new_sys_time = SystemTime::now(); - /// match sys_time.duration_since(new_sys_time) { - /// Ok(_) => {} - /// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), - /// } - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration(&self) -> Duration { - self.0 - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Error for SystemTimeError { - fn description(&self) -> &str { "other time was not earlier than self" } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Display for SystemTimeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "second time provided was later than self") - } -} - -impl FromInner for SystemTime { - fn from_inner(time: time::SystemTime) -> SystemTime { - SystemTime(time) - } -} - -#[cfg(test)] -mod tests { - use super::{Instant, SystemTime, Duration, UNIX_EPOCH}; - - macro_rules! assert_almost_eq { - ($a:expr, $b:expr) => ({ - let (a, b) = ($a, $b); - if a != b { - let (a, b) = if a > b {(a, b)} else {(b, a)}; - assert!(a - Duration::new(0, 100) <= b); - } - }) - } - - #[test] - fn instant_monotonic() { - let a = Instant::now(); - let b = Instant::now(); - assert!(b >= a); - } - - #[test] - fn instant_elapsed() { - let a = Instant::now(); - a.elapsed(); - } - - #[test] - fn instant_math() { - let a = Instant::now(); - let b = Instant::now(); - let dur = b.duration_since(a); - assert_almost_eq!(b - dur, a); - assert_almost_eq!(a + dur, b); - - let second = Duration::new(1, 0); - assert_almost_eq!(a - second + second, a); - } - - #[test] - #[should_panic] - fn instant_duration_panic() { - let a = Instant::now(); - (a - Duration::new(1, 0)).duration_since(a); - } - - #[test] - fn system_time_math() { - let a = SystemTime::now(); - let b = SystemTime::now(); - match b.duration_since(a) { - Ok(dur) if dur == Duration::new(0, 0) => { - assert_almost_eq!(a, b); - } - Ok(dur) => { - assert!(b > a); - assert_almost_eq!(b - dur, a); - assert_almost_eq!(a + dur, b); - } - Err(dur) => { - let dur = dur.duration(); - assert!(a > b); - assert_almost_eq!(b + dur, a); - assert_almost_eq!(a - dur, b); - } - } - - let second = Duration::new(1, 0); - assert_almost_eq!(a.duration_since(a - second).unwrap(), second); - assert_almost_eq!(a.duration_since(a + second).unwrap_err() - .duration(), second); - - assert_almost_eq!(a - second + second, a); - - // A difference of 80 and 800 years cannot fit inside a 32-bit time_t - if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) { - let eighty_years = second * 60 * 60 * 24 * 365 * 80; - assert_almost_eq!(a - eighty_years + eighty_years, a); - assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a); - } - - let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); - let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000) - + Duration::new(0, 500_000_000); - assert_eq!(one_second_from_epoch, one_second_from_epoch2); - } - - #[test] - fn system_time_elapsed() { - let a = SystemTime::now(); - drop(a.elapsed()); - } - - #[test] - fn since_epoch() { - let ts = SystemTime::now(); - let a = ts.duration_since(UNIX_EPOCH).unwrap(); - let b = ts.duration_since(UNIX_EPOCH - Duration::new(1, 0)).unwrap(); - assert!(b > a); - assert_eq!(b - a, Duration::new(1, 0)); - - let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30; - - // Right now for CI this test is run in an emulator, and apparently the - // aarch64 emulator's sense of time is that we're still living in the - // 70s. - // - // Otherwise let's assume that we're all running computers later than - // 2000. - if !cfg!(target_arch = "aarch64") { - assert!(a > thirty_years); - } - - // let's assume that we're all running computers earlier than 2090. - // Should give us ~70 years to fix this! - let hundred_twenty_years = thirty_years * 4; - assert!(a < hundred_twenty_years); - } -}