From 08b71a18cd917724ee3d270d49a78e508a176e36 Mon Sep 17 00:00:00 2001 From: Fenrir Date: Thu, 19 Jan 2017 01:30:05 -0700 Subject: [PATCH] We stdlib now --- 3ds.json | 5 +- Cargo.toml | 5 +- Xargo.toml | 12 +- build.rs | 4 +- ctr-libc/Cargo.toml | 14 + ctr-libc/README.md | 1 + ctr-libc/src/constants.rs | 122 +++ ctr-libc/src/functions.rs | 39 + ctr-libc/src/lib.rs | 190 ++++ ctr-std/3ds.json | 31 + ctr-std/Cargo.toml | 13 + ctr-std/README.md | 1 + ctr-std/Xargo.toml | 6 + {std => ctr-std}/src/ascii.rs | 30 +- {std => ctr-std}/src/error.rs | 53 +- {std/src/num => ctr-std/src}/f32.rs | 181 ++-- {std/src/num => ctr-std/src}/f64.rs | 216 ++-- {std => ctr-std}/src/ffi/c_str.rs | 74 +- ctr-std/src/ffi/mod.rs | 24 + {std => ctr-std}/src/ffi/os_str.rs | 166 ++- {std => ctr-std}/src/io/buffered.rs | 72 +- {std => ctr-std}/src/io/cursor.rs | 70 +- {std => ctr-std}/src/io/error.rs | 315 +++++- {std => ctr-std}/src/io/impls.rs | 25 +- {std => ctr-std}/src/io/mod.rs | 297 ++++-- {std => ctr-std}/src/io/prelude.rs | 2 + {std => ctr-std}/src/io/print.rs | 3 +- {std => ctr-std}/src/io/util.rs | 11 + ctr-std/src/lib.rs | 174 ++++ ctr-std/src/macros.rs | 481 +++++++++ ctr-std/src/memchr.rs | 143 +++ std/src/num/mod.rs => ctr-std/src/num.rs | 44 +- ctr-std/src/os/mod.rs | 17 + {std => ctr-std}/src/panicking.rs | 11 +- {std => ctr-std}/src/path.rs | 510 ++++++--- ctr-std/src/prelude/mod.rs | 146 +++ ctr-std/src/prelude/v1.rs | 53 + {std => ctr-std}/src/rt.rs | 6 + ctr-std/src/sync/mod.rs | 29 + ctr-std/src/sys/mod.rs | 37 + ctr-std/src/sys/unix/ext/ffi.rs | 61 ++ ctr-std/src/sys/unix/ext/mod.rs | 41 + ctr-std/src/sys/unix/memchr.rs | 51 + ctr-std/src/sys/unix/mod.rs | 50 + ctr-std/src/sys/unix/os.rs | 123 +++ ctr-std/src/sys/unix/os_str.rs | 119 +++ ctr-std/src/sys/unix/path.rs | 29 + ctr-std/src/sys_common/io.rs | 179 ++++ ctr-std/src/sys_common/mod.rs | 76 ++ ctru-sys/Cargo.toml | 5 +- ctru-sys/src/applets/mod.rs | 1 + ctru-sys/src/applets/swkbd.rs | 258 +++++ ctru-sys/src/lib.rs | 7 +- ctru-sys/src/ndsp/channel.rs | 82 ++ ctru-sys/src/ndsp/mod.rs | 2 + ctru-sys/src/ndsp/ndsp.rs | 112 ++ ctru-sys/src/os.rs | 62 +- ctru-sys/src/romfs.rs | 64 ++ ctru-sys/src/sdmc.rs | 24 +- ctru-sys/src/services/apt.rs | 28 +- ctru-sys/src/services/mod.rs | 1 - ctru-sys/src/services/nfc.rs | 6 +- ctru-sys/src/services/ps.rs | 2 +- ctru-sys/src/services/soc.rs | 2 +- ctru-sys/src/services/sslc.rs | 4 +- ctru-sys/src/svc.rs | 244 +++-- ctru-sys/src/sys/inaddr.rs | 6 +- ctru-sys/src/sys/libc.rs | 6 +- ctru-sys/src/sys/mod.rs | 3 +- ctru-sys/src/sys/socket.rs | 20 +- ctru-sys/src/types.rs | 4 - src/lib.rs | 1 + src/services/fs.rs | 15 +- std/Cargo.toml | 15 - std/src/ffi/mod.rs | 5 - std/src/lib.rs | 100 -- std/src/macros.rs | 105 -- std/src/memchr.rs | 397 ------- std/src/prelude/mod.rs | 1 - std/src/prelude/v1.rs | 49 - std/src/sync/mod.rs | 5 - std/src/sync/mutex.rs | 92 -- std/src/sys/mod.rs | 25 - std/src/sys/wtf8.rs | 1204 ---------------------- 84 files changed, 4569 insertions(+), 2750 deletions(-) create mode 100644 ctr-libc/Cargo.toml create mode 100644 ctr-libc/README.md create mode 100644 ctr-libc/src/constants.rs create mode 100644 ctr-libc/src/functions.rs create mode 100644 ctr-libc/src/lib.rs create mode 100644 ctr-std/3ds.json create mode 100644 ctr-std/Cargo.toml create mode 100644 ctr-std/README.md create mode 100644 ctr-std/Xargo.toml rename {std => ctr-std}/src/ascii.rs (94%) rename {std => ctr-std}/src/error.rs (83%) rename {std/src/num => ctr-std/src}/f32.rs (89%) rename {std/src/num => ctr-std/src}/f64.rs (86%) rename {std => ctr-std}/src/ffi/c_str.rs (88%) create mode 100644 ctr-std/src/ffi/mod.rs rename {std => ctr-std}/src/ffi/os_str.rs (75%) rename {std => ctr-std}/src/io/buffered.rs (92%) rename {std => ctr-std}/src/io/cursor.rs (88%) rename {std => ctr-std}/src/io/error.rs (50%) rename {std => ctr-std}/src/io/impls.rs (86%) rename {std => ctr-std}/src/io/mod.rs (85%) rename {std => ctr-std}/src/io/prelude.rs (89%) rename {std => ctr-std}/src/io/print.rs (94%) rename {std => ctr-std}/src/io/util.rs (92%) create mode 100644 ctr-std/src/lib.rs create mode 100644 ctr-std/src/macros.rs create mode 100644 ctr-std/src/memchr.rs rename std/src/num/mod.rs => ctr-std/src/num.rs (89%) create mode 100644 ctr-std/src/os/mod.rs rename {std => ctr-std}/src/panicking.rs (87%) rename {std => ctr-std}/src/path.rs (85%) create mode 100644 ctr-std/src/prelude/mod.rs create mode 100644 ctr-std/src/prelude/v1.rs rename {std => ctr-std}/src/rt.rs (85%) create mode 100644 ctr-std/src/sync/mod.rs create mode 100644 ctr-std/src/sys/mod.rs create mode 100644 ctr-std/src/sys/unix/ext/ffi.rs create mode 100644 ctr-std/src/sys/unix/ext/mod.rs create mode 100644 ctr-std/src/sys/unix/memchr.rs create mode 100644 ctr-std/src/sys/unix/mod.rs create mode 100644 ctr-std/src/sys/unix/os.rs create mode 100644 ctr-std/src/sys/unix/os_str.rs create mode 100644 ctr-std/src/sys/unix/path.rs create mode 100644 ctr-std/src/sys_common/io.rs create mode 100644 ctr-std/src/sys_common/mod.rs create mode 100644 ctru-sys/src/applets/mod.rs create mode 100644 ctru-sys/src/applets/swkbd.rs create mode 100644 ctru-sys/src/ndsp/channel.rs create mode 100644 ctru-sys/src/ndsp/mod.rs create mode 100644 ctru-sys/src/ndsp/ndsp.rs create mode 100644 ctru-sys/src/romfs.rs delete mode 100644 std/Cargo.toml delete mode 100644 std/src/ffi/mod.rs delete mode 100644 std/src/lib.rs delete mode 100644 std/src/macros.rs delete mode 100644 std/src/memchr.rs delete mode 100644 std/src/prelude/mod.rs delete mode 100644 std/src/prelude/v1.rs delete mode 100644 std/src/sync/mod.rs delete mode 100644 std/src/sync/mutex.rs delete mode 100644 std/src/sys/mod.rs delete mode 100644 std/src/sys/wtf8.rs diff --git a/3ds.json b/3ds.json index fbdf65d..1f2484b 100644 --- a/3ds.json +++ b/3ds.json @@ -5,15 +5,16 @@ "ar": "arm-none-eabi-ar", "target-endian": "little", "target-pointer-width": "32", + "target-family": "unix", "arch": "arm", "os": "linux", + "env": "newlib", "cpu": "mpcore", "features": "+vfp2", "relocation-model": "static", - "disable-redzone": true, "executables": true, - "no-compiler-rt": true, "exe-suffix": ".elf", + "panic-strategy": "abort", "pre-link-args": [ "-specs=3dsx.specs", "-march=armv6k", diff --git a/Cargo.toml b/Cargo.toml index 81239fa..56c2a78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,10 @@ crate-type = ["rlib"] name = "ctru" [dependencies.ctru-sys] -path = "ctru-sys" +path = "../ctru-sys" [dependencies.bitflags] version = "0.7.0" + +[dependencies.widestring] +widestring = "0.2.2" diff --git a/Xargo.toml b/Xargo.toml index afe92d8..05f1470 100644 --- a/Xargo.toml +++ b/Xargo.toml @@ -1,2 +1,10 @@ -[target.3ds.dependencies] -collections = {} +[dependencies.collections] + +[dependencies.ctr-libc] +path = "ctr-libc" +default-features = false +stage = 0 + +[dependencies.std] +path = "ctr-std" +stage = 1 diff --git a/build.rs b/build.rs index 6b07e4e..57ff190 100644 --- a/build.rs +++ b/build.rs @@ -4,12 +4,12 @@ use std::fs; use std::option::Option::{self, Some, None}; -const ENV_DKP: &'static str = "CTRULIB"; +const ENV_DKP: &'static str = "DEVKITPRO"; fn find_libctru() -> Option { if let Ok(value) = env::var(ENV_DKP) { let mut path = PathBuf::from(value); - path.push("lib"); + path.push("libctru/lib"); // metadata returns Err if the dir does not exist if let Ok(metadata) = fs::metadata(path.as_path()) { if metadata.is_dir() { diff --git a/ctr-libc/Cargo.toml b/ctr-libc/Cargo.toml new file mode 100644 index 0000000..5bc4c6b --- /dev/null +++ b/ctr-libc/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "ctr-libc" +version = "0.1.0" +authors = ["Fenrir ", "The Rust Project Developers"] +license = "MIT/Apache 2.0" + +description = """ +A library for types and bindings to native C functions found in newlib +for devkitARM +""" + +[features] +default = ["use_std"] +use_std = [] diff --git a/ctr-libc/README.md b/ctr-libc/README.md new file mode 100644 index 0000000..ce5eb41 --- /dev/null +++ b/ctr-libc/README.md @@ -0,0 +1 @@ +Extended libc bindings for use with ctr-std. This library is experimental. Use of some functions might result in undefined symbols. diff --git a/ctr-libc/src/constants.rs b/ctr-libc/src/constants.rs new file mode 100644 index 0000000..d007e53 --- /dev/null +++ b/ctr-libc/src/constants.rs @@ -0,0 +1,122 @@ +// Many of these constants are unused/unnecessary. But let's keep them around for now. + +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; + +pub const EPERM: ::c_int = 1; +pub const ENOENT: ::c_int = 2; +pub const ESRCH: ::c_int = 3; +pub const EINTR: ::c_int = 4; +pub const EIO: ::c_int = 5; +pub const ENXIO: ::c_int = 6; +pub const E2BIG: ::c_int = 7; +pub const ENOEXEC: ::c_int = 8; +pub const EBADF: ::c_int = 9; +pub const ECHILD: ::c_int = 10; +pub const EAGAIN: ::c_int = 11; +pub const ENOMEM: ::c_int = 12; +pub const EACCES: ::c_int = 13; +pub const EFAULT: ::c_int = 14; +pub const EBUSY: ::c_int = 16; +pub const EEXIST: ::c_int = 17; +pub const EXDEV: ::c_int = 18; +pub const ENODEV: ::c_int = 19; +pub const ENOTDIR: ::c_int = 20; +pub const EISDIR: ::c_int = 21; +pub const EINVAL: ::c_int = 22; +pub const ENFILE: ::c_int = 23; +pub const EMFILE: ::c_int = 24; +pub const ENOTTY: ::c_int = 25; +pub const ETXTBSY: ::c_int = 26; +pub const EFBIG: ::c_int = 27; +pub const ENOSPC: ::c_int = 28; +pub const ESPIPE: ::c_int = 29; +pub const EROFS: ::c_int = 30; +pub const EMLINK: ::c_int = 31; +pub const EPIPE: ::c_int = 32; +pub const EDOM: ::c_int = 33; +pub const ERANGE: ::c_int = 34; +pub const ENOMSG: ::c_int = 35; +pub const EIDRM: ::c_int = 36; +pub const EDEADLK: ::c_int = 45; +pub const ENOLCK: ::c_int = 46; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENOLINK: ::c_int = 67; +pub const EPROTO: ::c_int = 71; +pub const EMULTIHOP: ::c_int = 74; +pub const EBADMSG: ::c_int = 77; +pub const EFTYPE: ::c_int = 79; +pub const ENOSYS: ::c_int = 88; +pub const ENOTEMPTY: ::c_int = 90; +pub const ENAMETOOLONG: ::c_int = 91; +pub const ELOOP: ::c_int = 92; +pub const EOPNOTSUPP: ::c_int = 95; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EAFNOSUPPORT: ::c_int = 106; +pub const EPROTOTYPE: ::c_int = 107; +pub const ENOTSOCK: ::c_int = 108; +pub const ENOPROTOOPT: ::c_int = 109; +pub const ECONNREFUSED: ::c_int = 111; +pub const EADDRINUSE: ::c_int = 112; +pub const ECONNABORTED: ::c_int = 113; +pub const ENETUNREACH: ::c_int = 114; +pub const ENETDOWN: ::c_int = 115; +pub const ETIMEDOUT: ::c_int = 116; +pub const EHOSTDOWN: ::c_int = 117; +pub const EHOSTUNREACH: ::c_int = 118; +pub const EINPROGRESS: ::c_int = 119; +pub const EALREADY: ::c_int = 120; +pub const EDESTADDRREQ: ::c_int = 121; +pub const EMSGSIZE: ::c_int = 122; +pub const EPROTONOSUPPORT: ::c_int = 123; +pub const EADDRNOTAVAIL: ::c_int = 125; +pub const ENETRESET: ::c_int = 126; +pub const EISCONN: ::c_int = 127; +pub const ENOTCONN: ::c_int = 128; +pub const ETOOMANYREFS: ::c_int = 129; +pub const EDQUOT: ::c_int = 132; +pub const ESTALE: ::c_int = 133; +pub const ENOTSUP: ::c_int = 134; +pub const EILSEQ: ::c_int = 138; +pub const EOVERFLOW: ::c_int = 139; +pub const ECANCELED: ::c_int = 140; +pub const ENOTRECOVERABLE: ::c_int = 141; +pub const EOWNERDEAD: ::c_int = 142; +pub const EWOULDBLOCK: ::c_int = 11; +pub const __ELASTERROR: ::c_int = 2000; + +pub const O_RDONLY: ::c_int = 0; +pub const O_WRONLY: ::c_int = 1; +pub const O_RDWR: ::c_int = 2; +pub const O_APPEND: ::c_int = 8; +pub const O_CREAT: ::c_int = 512; +pub const O_TRUNC: ::c_int = 1024; +pub const O_EXCL: ::c_int = 2048; +pub const O_SYNC: ::c_int = 8192; +pub const O_NONBLOCK: ::c_int = 16384; +pub const O_NOCTTY: ::c_int = 32768; +pub const FD_CLOEXEC: ::c_int = 1; + +pub const DT_FIFO: u8 = 1; +pub const DT_CHR: u8 = 2; +pub const DT_DIR: u8 = 4; +pub const DT_BLK: u8 = 6; +pub const DT_REG: u8 = 8; +pub const DT_LNK: u8 = 10; +pub const DT_SOCK: u8 = 12; + +pub const O_CLOEXEC: ::c_int = 0x80000; +pub const O_ACCMODE: ::c_int = 3; + +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; + +pub const SIG_IGN: ::sighandler_t = 1 as ::sighandler_t; +pub const SIGPIPE: ::c_int = 13; diff --git a/ctr-libc/src/functions.rs b/ctr-libc/src/functions.rs new file mode 100644 index 0000000..a0d21ac --- /dev/null +++ b/ctr-libc/src/functions.rs @@ -0,0 +1,39 @@ +extern "C" { + pub fn abort() -> !; + pub fn chdir(dir: *const ::c_char) -> ::c_int; + pub fn chmod(path: *const ::c_char, mode: ::mode_t) -> ::c_int; + pub fn close(fd: ::c_int) -> ::c_int; + pub fn closedir(dirp: *mut ::DIR) -> ::c_int; + pub fn exit(status: ::c_int) -> !; + pub fn fchmod(fd: ::c_int, mode: ::mode_t) -> ::c_int; + pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int; + pub fn fdatasync(fd: ::c_int) -> ::c_int; + pub fn free(p: *mut ::c_void); + pub fn fstat(fildes: ::c_int, buf: *mut ::stat) -> ::c_int; + pub fn ftruncate(fd: ::c_int, length: ::off_t) -> ::c_int; + pub fn fsync(fd: ::c_int) -> ::c_int; + pub fn getcwd(buf: *mut ::c_char, size: ::size_t) -> *mut ::c_char; + pub fn gettimeofday(tp: *mut ::timeval, tz: *mut ::c_void) -> ::c_int; + pub fn link(src: *const ::c_char, dst: *const ::c_char) -> ::c_int; + pub fn lstat(path: *const ::c_char, buf: *mut ::stat) -> ::c_int; + pub fn lseek(fd: ::c_int, offset: ::off_t, whence: ::c_int) -> ::off_t; + pub fn memchr(cx: *const ::c_void, c: ::c_int, n: ::size_t) -> *mut ::c_void; + pub fn memrchr(cx: *const ::c_void, c: ::c_int, n: ::size_t) -> *mut ::c_void; + pub fn mkdir(path: *const ::c_char, mode: ::mode_t) -> ::c_int; + pub fn open(path: *const ::c_char, oflag: ::c_int, ...) -> ::c_int; + pub fn opendir(dirname: *const ::c_char) -> *mut ::DIR; + pub fn pread(fd: ::c_int, buf: *mut ::c_void, count: ::size_t, offset: ::off_t) -> ::ssize_t; + pub fn pwrite(fd: ::c_int, buf: *const ::c_void, count: ::size_t, offset: ::off_t) -> ::ssize_t; + pub fn read(fd: ::c_int, puf: *mut ::c_void, count: ::size_t) -> ::ssize_t; + pub fn readlink(path: *const ::c_char, buf: *mut ::c_char, bufsz: ::size_t) -> ::ssize_t; + pub fn readdir_r(dirp: *mut ::DIR, entry: *mut ::dirent, result: *mut *mut ::dirent) -> ::c_int; + pub fn realpath(pathname: *const ::c_char, resolved: *mut ::c_char) -> *mut ::c_char; + pub fn rename(oldname: *const ::c_char, newname: *const ::c_char) -> ::c_int; + pub fn rmdir(path: *const ::c_char) -> ::c_int; + pub fn signal(signum: ::c_int, handler: ::sighandler_t) -> ::sighandler_t; + pub fn stat(path: *const ::c_char, buf: *mut ::stat) -> ::c_int; + pub fn strlen(cs: *const ::c_char) -> ::size_t; + pub fn symlink(path1: *const ::c_char, path2: *const ::c_char) -> ::c_int; + pub fn unlink(c: *const ::c_char) -> ::c_int; + pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t) -> ::ssize_t; +} diff --git a/ctr-libc/src/lib.rs b/ctr-libc/src/lib.rs new file mode 100644 index 0000000..729a38d --- /dev/null +++ b/ctr-libc/src/lib.rs @@ -0,0 +1,190 @@ +// 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(bad_style, overflowing_literals, improper_ctypes, non_camel_case_types)] + +// Attributes needed when building as part of the standard library +#![cfg_attr(stdbuild, feature(no_std, core, core_slice_ext, staged_api, custom_attribute, cfg_target_vendor))] +#![cfg_attr(stdbuild, feature(link_cfg))] +#![cfg_attr(stdbuild, no_std)] +#![cfg_attr(stdbuild, staged_api)] +#![cfg_attr(stdbuild, allow(warnings))] +#![cfg_attr(stdbuild, unstable(feature = "libc", + reason = "use `libc` from crates.io", + issue = "27783"))] + +#![cfg_attr(not(feature = "use_std"), no_std)] + +#[cfg(all(not(stdbuild), not(dox), feature = "use_std"))] +extern crate std as core; + +mod constants; +mod functions; +pub use constants::*; +pub use functions::*; + +#[link(name = "c")] +#[link(name = "m")] +extern {} + +#[repr(u8)] +pub enum c_void { + __variant1, + __variant2, +} + +// char is u8 on ARM +pub type c_char = u8; +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_float = f32; +pub type c_double = f64; +pub type c_longlong = i64; +pub type c_ulonglong = u64; + +// 4 bytes on ARM +pub type c_long = i32; +pub type c_ulong = u32; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +// devkitARM says wchar_t is 4 bytes. Nintendo's API says it's 2 bytes. +// hope you never have to interact between the two... +pub type wchar_t = c_int; + +pub type int8_t = i8; +pub type uint8_t = u8; +pub type int16_t = i16; +pub type uint16_t = u16; +pub type int32_t = i32; +pub type uint32_t = u32; +pub type int64_t = i64; +pub type uint64_t = u64; + +pub type time_t = i32; +pub type clockid_t = c_int; +pub type mode_t = u32; +pub type sighandler_t = size_t; +pub type dev_t = u32; +pub type nlink_t = u32; +pub type uid_t = u32; +pub type gid_t = u32; +pub type off_t = i64; +pub type blksize_t = i32; +pub type blkcnt_t = c_ulong; +pub type fsblkcnt_t = uint64_t; +pub type fsfilcnt_t = uint32_t; +pub type ino_t = u32; +pub type suseconds_t = i32; +pub type error_t = c_int; + +pub enum timezone {} + +pub enum _reent {} + +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct timeval { + pub tv_sec: time_t, + pub tv_usec: suseconds_t, +} + +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: c_long, +} + +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct itimerspec { + pub it_interval: timespec, + pub it_value: timespec, +} + +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, +} + +pub enum DIR {} + +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_atime: time_t, + pub st_spare1: c_long, + pub st_mtime: time_t, + pub st_spare2: c_long, + pub st_ctime: time_t, + pub st_spare3: c_long, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_spare4: [c_long; 2usize], +} + +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct statvfs { + pub f_bsize: c_ulong, + pub f_frsize: c_ulong, + pub f_blocks: fsblkcnt_t, + pub f_bfree: fsblkcnt_t, + pub f_bavail: fsblkcnt_t, + pub f_files: fsfilcnt_t, + pub f_ffree: fsfilcnt_t, + pub f_favail: fsfilcnt_t, + pub f_fsid: c_ulong, + pub f_flag: c_ulong, + pub f_namemax: c_ulong, +} + +#[repr(C)] +#[derive(Copy)] +pub struct dirent { + pub d_ino: ino_t, + pub d_type: c_uchar, + pub d_name: [c_char; 256usize], +} +impl Clone for dirent { + fn clone(&self) -> Self { *self } +} diff --git a/ctr-std/3ds.json b/ctr-std/3ds.json new file mode 100644 index 0000000..bdd5caa --- /dev/null +++ b/ctr-std/3ds.json @@ -0,0 +1,31 @@ +{ + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "llvm-target": "arm-none-eabihf", + "linker": "arm-none-eabi-gcc", + "ar": "arm-none-eabi-ar", + "target-endian": "little", + "target-pointer-width": "32", + "target-family": "unix", + "arch": "arm", + "os": "linux", + "env": "newlib", + "cpu": "mpcore", + "features": "+vfp2", + "relocation-model": "static", + "executables": true, + "exe-suffix": ".elf", + "panic-strategy": "abort", + "pre-link-args": [ + "-specs=3dsx.specs", + "-march=armv6k", + "-mtune=mpcore", + "-mfloat-abi=hard", + "-mtp=soft" + ], + "post-link-args": [ + "-lc", + "-lm", + "-lsysbase", + "-lc" + ] +} diff --git a/ctr-std/Cargo.toml b/ctr-std/Cargo.toml new file mode 100644 index 0000000..dfd5037 --- /dev/null +++ b/ctr-std/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "std" +version = "0.0.0" +license = "MIT/Apache 2.0" + +[dependencies.compiler_builtins] +git = "https://github.com/rust-lang-nursery/compiler-builtins" + +[dependencies.alloc_system] +version = "0.1.1" + +[dependencies.spin] +version = "0.4" diff --git a/ctr-std/README.md b/ctr-std/README.md new file mode 100644 index 0000000..604a43c --- /dev/null +++ b/ctr-std/README.md @@ -0,0 +1 @@ +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. diff --git a/ctr-std/Xargo.toml b/ctr-std/Xargo.toml new file mode 100644 index 0000000..3bc68c1 --- /dev/null +++ b/ctr-std/Xargo.toml @@ -0,0 +1,6 @@ +[dependencies.collections] + +[dependencies.ctr-libc] +path = "../ctr-libc" +default-features = false +stage = 1 diff --git a/std/src/ascii.rs b/ctr-std/src/ascii.rs similarity index 94% rename from std/src/ascii.rs rename to ctr-std/src/ascii.rs index 5424921..a063b85 100644 --- a/std/src/ascii.rs +++ b/ctr-std/src/ascii.rs @@ -10,8 +10,11 @@ //! Operations on ASCII strings and characters. +#![stable(feature = "rust1", since = "1.0.0")] + use mem; use ops::Range; +use iter::FusedIterator; /// Extension methods for ASCII-subset only operations on string slices. /// @@ -35,8 +38,10 @@ use ops::Range; /// 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")] 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. @@ -52,6 +57,7 @@ pub trait AsciiExt { /// assert!(ascii.is_ascii()); /// assert!(!utf8.is_ascii()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn is_ascii(&self) -> bool; /// Makes a copy of the string in ASCII upper case. @@ -70,6 +76,7 @@ pub trait AsciiExt { /// assert_eq!('A', ascii.to_ascii_uppercase()); /// assert_eq!('❤', utf8.to_ascii_uppercase()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_uppercase(&self) -> Self::Owned; /// Makes a copy of the string in ASCII lower case. @@ -88,6 +95,7 @@ pub trait AsciiExt { /// assert_eq!('a', ascii.to_ascii_lowercase()); /// assert_eq!('❤', utf8.to_ascii_lowercase()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_lowercase(&self) -> Self::Owned; /// Checks that two strings are an ASCII case-insensitive match. @@ -109,6 +117,7 @@ pub trait AsciiExt { /// assert!(ascii1.eq_ignore_ascii_case(&ascii3)); /// assert!(!ascii1.eq_ignore_ascii_case(&ascii4)); /// ``` + #[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. @@ -126,6 +135,7 @@ pub trait AsciiExt { /// /// assert_eq!('A', ascii); /// ``` + #[stable(feature = "ascii", since = "1.9.0")] fn make_ascii_uppercase(&mut self); /// Converts this type to its ASCII lower case equivalent in-place. @@ -143,9 +153,11 @@ pub trait AsciiExt { /// /// assert_eq!('a', ascii); /// ``` + #[stable(feature = "ascii", since = "1.9.0")] fn make_ascii_lowercase(&mut self); } +#[stable(feature = "rust1", since = "1.0.0")] impl AsciiExt for str { type Owned = String; @@ -186,6 +198,7 @@ impl AsciiExt for str { } } +#[stable(feature = "rust1", since = "1.0.0")] impl AsciiExt for [u8] { type Owned = Vec; #[inline] @@ -228,6 +241,7 @@ impl AsciiExt for [u8] { } } +#[stable(feature = "rust1", since = "1.0.0")] impl AsciiExt for u8 { type Owned = u8; #[inline] @@ -246,6 +260,7 @@ impl AsciiExt for u8 { fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); } } +#[stable(feature = "rust1", since = "1.0.0")] impl AsciiExt for char { type Owned = char; #[inline] @@ -284,6 +299,7 @@ impl AsciiExt for char { /// An iterator over the escaped version of a byte, constructed via /// `std::ascii::escape_default`. +#[stable(feature = "rust1", since = "1.0.0")] pub struct EscapeDefault { range: Range, data: [u8; 4], @@ -314,6 +330,7 @@ pub struct EscapeDefault { /// assert_eq!(b'\\', escaped.next().unwrap()); /// assert_eq!(b't', escaped.next().unwrap()); /// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub fn escape_default(c: u8) -> EscapeDefault { let (data, len) = match c { b'\t' => ([b'\\', b't', 0, 0], 2), @@ -336,17 +353,23 @@ pub fn escape_default(c: u8) -> EscapeDefault { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Iterator for EscapeDefault { type Item = u8; fn next(&mut self) -> Option { self.range.next().map(|i| self.data[i]) } fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } } +#[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for EscapeDefault { fn next_back(&mut self) -> Option { self.range.next_back().map(|i| self.data[i]) } } +#[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for EscapeDefault {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for EscapeDefault {} + static ASCII_LOWERCASE_MAP: [u8; 256] = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, @@ -430,8 +453,7 @@ static ASCII_UPPERCASE_MAP: [u8; 256] = [ #[cfg(test)] mod tests { use super::*; - use std_unicode::char::from_u32; - use collections::string::ToString; + use char::from_u32; #[test] fn test_is_ascii() { @@ -446,9 +468,7 @@ mod tests { assert!("banana\0\u{7F}".is_ascii()); assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); - - // NOTE: This test fails for some reason. - assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); } #[test] diff --git a/std/src/error.rs b/ctr-std/src/error.rs similarity index 83% rename from std/src/error.rs rename to ctr-std/src/error.rs index 5beae2f..454fa47 100644 --- a/std/src/error.rs +++ b/ctr-std/src/error.rs @@ -38,6 +38,8 @@ //! [`Display`]: ../fmt/trait.Display.html //! [`cause`]: trait.Error.html#method.cause +#![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 @@ -59,12 +61,17 @@ use str; use string; /// Base functionality for all errors in Rust. +#[stable(feature = "rust1", since = "1.0.0")] pub trait Error: Debug + Display { /// A short description of the error. /// - /// The description should not contain newlines or sentence-ending - /// punctuation, to facilitate embedding in larger user-facing - /// strings. + /// The description should only be used for a simple message. + /// It should not contain newlines or sentence-ending punctuation, + /// to facilitate embedding in larger user-facing strings. + /// For showing formatted error messages with more information see + /// [`Display`]. + /// + /// [`Display`]: ../fmt/trait.Display.html /// /// # Examples /// @@ -78,6 +85,7 @@ pub trait Error: Debug + Display { /// _ => println!("No error"), /// } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn description(&self) -> &str; /// The lower-level cause of this error, if any. @@ -138,27 +146,34 @@ pub trait Error: Debug + Display { /// } /// } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn cause(&self) -> Option<&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)] @@ -178,6 +193,7 @@ impl From for Box { } } +#[stable(feature = "string_box_error", since = "1.7.0")] impl From for Box { fn from(str_err: String) -> Box { let err1: Box = From::from(str_err); @@ -186,70 +202,82 @@ impl From for Box { } } +#[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.7.0")] impl<'a> From<&'a str> for Box { fn from(err: &'a str) -> Box { From::from(String::from(err)) } } +#[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() } } +#[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.7.0")] impl Error for Box { fn description(&self) -> &str { Error::description(&**self) @@ -260,24 +288,28 @@ impl Error for Box { } } +#[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`" @@ -287,6 +319,7 @@ impl Error for char::CharTryFromError { // copied from any.rs impl 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 @@ -301,6 +334,7 @@ impl Error + 'static { /// 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::() { @@ -314,6 +348,7 @@ impl Error + 'static { /// 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::() { @@ -328,18 +363,21 @@ impl Error + 'static { impl 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) @@ -348,18 +386,21 @@ impl Error + 'static + Send { impl 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) @@ -368,6 +409,7 @@ impl Error + 'static + Send + Sync { impl 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::() { @@ -383,6 +425,7 @@ impl Error { impl 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> { @@ -396,6 +439,7 @@ impl Error + Send { impl 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> { @@ -410,8 +454,7 @@ impl Error + Send + Sync { #[cfg(test)] mod tests { use super::Error; - use core::fmt; - use alloc::boxed::Box; + use fmt; #[derive(Debug, PartialEq)] struct A; diff --git a/std/src/num/f32.rs b/ctr-std/src/f32.rs similarity index 89% rename from std/src/num/f32.rs rename to ctr-std/src/f32.rs index f1cfe5a..7a676c0 100644 --- a/std/src/num/f32.rs +++ b/ctr-std/src/f32.rs @@ -12,6 +12,7 @@ //! //! *[See also the `f32` primitive type](../primitive.f32.html).* +#![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] #[cfg(not(test))] @@ -19,22 +20,27 @@ use core::num; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -use libctru::libc::c_int; +use libc::c_int; #[cfg(not(test))] use num::FpCategory; +#[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; #[allow(dead_code)] mod cmath { - use libctru::libc::{c_float, c_int}; + use libc::{c_float, c_int}; - extern "C" { + extern { pub fn cbrtf(n: c_float) -> c_float; pub fn erff(n: c_float) -> c_float; pub fn erfcf(n: c_float) -> c_float; @@ -59,7 +65,7 @@ mod cmath { // See the comments in the `floor` function for why MSVC is special // here. #[cfg(not(target_env = "msvc"))] - extern "C" { + 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; @@ -76,7 +82,7 @@ mod cmath { pub use self::shims::*; #[cfg(target_env = "msvc")] mod shims { - use libctru::libc::{c_float, c_int}; + use libc::{c_float, c_int}; #[inline] pub unsafe fn acosf(n: c_float) -> c_float { @@ -148,10 +154,9 @@ impl f32 { /// assert!(nan.is_nan()); /// assert!(!f.is_nan()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_nan(self) -> bool { - num::Float::is_nan(self) - } + pub fn is_nan(self) -> bool { num::Float::is_nan(self) } /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. @@ -170,10 +175,9 @@ impl f32 { /// assert!(inf.is_infinite()); /// assert!(neg_inf.is_infinite()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_infinite(self) -> bool { - num::Float::is_infinite(self) - } + pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) } /// Returns `true` if this number is neither infinite nor `NaN`. /// @@ -191,10 +195,9 @@ impl f32 { /// assert!(!inf.is_finite()); /// assert!(!neg_inf.is_finite()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_finite(self) -> bool { - num::Float::is_finite(self) - } + pub fn is_finite(self) -> bool { num::Float::is_finite(self) } /// Returns `true` if the number is neither zero, infinite, /// [subnormal][subnormal], or `NaN`. @@ -217,10 +220,9 @@ impl f32 { /// assert!(!lower_than_min.is_normal()); /// ``` /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_normal(self) -> bool { - num::Float::is_normal(self) - } + pub fn is_normal(self) -> bool { num::Float::is_normal(self) } /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific @@ -236,10 +238,9 @@ impl f32 { /// assert_eq!(num.classify(), FpCategory::Normal); /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn classify(self) -> FpCategory { - num::Float::classify(self) - } + pub fn classify(self) -> FpCategory { num::Float::classify(self) } /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. @@ -264,6 +265,11 @@ impl f32 { /// assert!(abs_difference <= f32::EPSILON); /// ``` /// [floating-point]: ../reference.html#machine-types + #[unstable(feature = "float_extras", reason = "signature is undecided", + issue = "27752")] + #[rustc_deprecated(since = "1.11.0", + reason = "never really came to fruition and easily \ + implementable outside the standard library")] #[inline] #[allow(deprecated)] pub fn integer_decode(self) -> (u64, i16, i8) { @@ -279,6 +285,7 @@ impl 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 @@ -309,6 +316,7 @@ impl 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` @@ -328,6 +336,7 @@ impl 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) } @@ -342,6 +351,7 @@ impl 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) } @@ -360,10 +370,9 @@ impl f32 { /// 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() - } + pub fn fract(self) -> f32 { self - self.trunc() } /// Computes the absolute value of `self`. Returns `NAN` if the /// number is `NAN`. @@ -382,10 +391,9 @@ impl f32 { /// /// assert!(f32::NAN.abs().is_nan()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f32 { - num::Float::abs(self) - } + pub fn abs(self) -> f32 { num::Float::abs(self) } /// Returns a number that represents the sign of `self`. /// @@ -403,10 +411,9 @@ impl f32 { /// /// assert!(f32::NAN.signum().is_nan()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f32 { - num::Float::signum(self) - } + pub fn signum(self) -> f32 { num::Float::signum(self) } /// Returns `true` if `self`'s sign bit is positive, including /// `+0.0` and `INFINITY`. @@ -423,10 +430,9 @@ impl f32 { /// // Requires both tests to determine if is `NaN` /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_positive(self) -> bool { - num::Float::is_sign_positive(self) - } + pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) } /// Returns `true` if `self`'s sign is negative, including `-0.0` /// and `NEG_INFINITY`. @@ -443,10 +449,9 @@ impl f32 { /// // Requires both tests to determine if is `NaN`. /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_negative(self) -> bool { - num::Float::is_sign_negative(self) - } + pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -464,6 +469,7 @@ impl f32 { /// /// 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) } @@ -479,10 +485,9 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn recip(self) -> f32 { - num::Float::recip(self) - } + pub fn recip(self) -> f32 { num::Float::recip(self) } /// Raises a number to an integer power. /// @@ -496,10 +501,9 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f32 { - num::Float::powi(self, n) - } + pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) } /// Raises a number to a floating point power. /// @@ -511,6 +515,7 @@ impl f32 { /// /// 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` @@ -535,6 +540,7 @@ impl f32 { /// 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 { @@ -558,6 +564,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp(self) -> f32 { // see notes above in `floor` @@ -579,6 +586,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp2(self) -> f32 { unsafe { intrinsics::exp2f32(self) } @@ -598,6 +606,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln(self) -> f32 { // see notes above in `floor` @@ -624,10 +633,9 @@ impl f32 { /// assert!(abs_difference_10 <= f32::EPSILON); /// assert!(abs_difference_2 <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn log(self, base: f32) -> f32 { - self.ln() / base.ln() - } + pub fn log(self, base: f32) -> f32 { self.ln() / base.ln() } /// Returns the base 2 logarithm of the number. /// @@ -641,6 +649,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f32 { #[cfg(target_os = "android")] @@ -661,6 +670,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log10(self) -> f32 { // see notes above in `floor` @@ -681,10 +691,9 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] #[inline] - pub fn to_degrees(self) -> f32 { - num::Float::to_degrees(self) - } + pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) } /// Converts degrees to radians. /// @@ -697,10 +706,9 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] #[inline] - pub fn to_radians(self) -> f32 { - num::Float::to_radians(self) - } + pub fn to_radians(self) -> f32 { num::Float::to_radians(self) } /// Constructs a floating point number of `x*2^exp`. /// @@ -713,6 +721,12 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[unstable(feature = "float_extras", + reason = "pending integer conventions", + issue = "27752")] + #[rustc_deprecated(since = "1.11.0", + reason = "never really came to fruition and easily \ + implementable outside the standard library")] #[inline] pub fn ldexp(x: f32, exp: isize) -> f32 { unsafe { cmath::ldexpf(x, exp as c_int) } @@ -739,6 +753,12 @@ impl f32 { /// assert!(abs_difference_0 <= f32::EPSILON); /// assert!(abs_difference_1 <= f32::EPSILON); /// ``` + #[unstable(feature = "float_extras", + reason = "pending integer conventions", + issue = "27752")] + #[rustc_deprecated(since = "1.11.0", + reason = "never really came to fruition and easily \ + implementable outside the standard library")] #[inline] pub fn frexp(self) -> (f32, isize) { unsafe { @@ -762,6 +782,12 @@ impl f32 { /// /// assert!(abs_diff <= f32::EPSILON); /// ``` + #[unstable(feature = "float_extras", + reason = "unsure about its place in the world", + issue = "27752")] + #[rustc_deprecated(since = "1.11.0", + reason = "never really came to fruition and easily \ + implementable outside the standard library")] #[inline] pub fn next_after(self, other: f32) -> f32 { unsafe { cmath::nextafterf(self, other) } @@ -777,6 +803,7 @@ impl f32 { /// ``` /// /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f32) -> f32 { unsafe { cmath::fmaxf(self, other) } @@ -792,6 +819,7 @@ impl f32 { /// ``` /// /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f32) -> f32 { unsafe { cmath::fminf(self, other) } @@ -814,6 +842,15 @@ impl f32 { /// 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) } } @@ -830,6 +867,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f32 { unsafe { cmath::cbrtf(self) } @@ -849,6 +887,7 @@ impl f32 { /// /// 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) } @@ -865,6 +904,7 @@ impl f32 { /// /// 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` @@ -885,6 +925,7 @@ impl f32 { /// /// 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` @@ -904,6 +945,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tan(self) -> f32 { unsafe { cmath::tanf(self) } @@ -923,6 +965,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asin(self) -> f32 { unsafe { cmath::asinf(self) } @@ -942,6 +985,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acos(self) -> f32 { unsafe { cmath::acosf(self) } @@ -960,6 +1004,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan(self) -> f32 { unsafe { cmath::atanf(self) } @@ -991,6 +1036,7 @@ impl f32 { /// 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) } @@ -1011,6 +1057,7 @@ impl f32 { /// 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()) @@ -1029,6 +1076,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp_m1(self) -> f32 { unsafe { cmath::expm1f(self) } @@ -1047,6 +1095,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln_1p(self) -> f32 { unsafe { cmath::log1pf(self) } @@ -1067,6 +1116,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sinh(self) -> f32 { unsafe { cmath::sinhf(self) } @@ -1087,6 +1137,7 @@ impl f32 { /// // Same result /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cosh(self) -> f32 { unsafe { cmath::coshf(self) } @@ -1107,6 +1158,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tanh(self) -> f32 { unsafe { cmath::tanhf(self) } @@ -1124,6 +1176,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asinh(self) -> f32 { if self == NEG_INFINITY { @@ -1145,6 +1198,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acosh(self) -> f32 { match self { @@ -1165,6 +1219,7 @@ impl f32 { /// /// 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() @@ -1438,7 +1493,7 @@ mod tests { assert_eq!((-0f32).abs(), 0f32); assert_eq!((-1f32).abs(), 1f32); assert_eq!(NEG_INFINITY.abs(), INFINITY); - assert_eq!((1f32 / NEG_INFINITY).abs(), 0f32); + assert_eq!((1f32/NEG_INFINITY).abs(), 0f32); assert!(NAN.abs().is_nan()); } @@ -1450,7 +1505,7 @@ mod tests { assert_eq!((-0f32).signum(), -1f32); assert_eq!((-1f32).signum(), -1f32); assert_eq!(NEG_INFINITY.signum(), -1f32); - assert_eq!((1f32 / NEG_INFINITY).signum(), -1f32); + assert_eq!((1f32/NEG_INFINITY).signum(), -1f32); assert!(NAN.signum().is_nan()); } @@ -1462,7 +1517,7 @@ mod tests { assert!(!(-0f32).is_sign_positive()); assert!(!(-1f32).is_sign_positive()); assert!(!NEG_INFINITY.is_sign_positive()); - assert!(!(1f32 / NEG_INFINITY).is_sign_positive()); + assert!(!(1f32/NEG_INFINITY).is_sign_positive()); assert!(!NAN.is_sign_positive()); } @@ -1474,7 +1529,7 @@ mod tests { assert!((-0f32).is_sign_negative()); assert!((-1f32).is_sign_negative()); assert!(NEG_INFINITY.is_sign_negative()); - assert!((1f32 / NEG_INFINITY).is_sign_negative()); + assert!((1f32/NEG_INFINITY).is_sign_negative()); assert!(!NAN.is_sign_negative()); } @@ -1712,25 +1767,15 @@ mod tests { assert_eq!((-0f32).frexp(), (-0f32, 0)); } - #[test] - #[cfg_attr(windows, ignore)] - // FIXME #8755 + #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 #[allow(deprecated)] fn test_frexp_nowin() { let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; let nan: f32 = f32::NAN; - assert_eq!(match inf.frexp() { - (x, _) => x, - }, - inf); - assert_eq!(match neg_inf.frexp() { - (x, _) => x, - }, - neg_inf); - assert!(match nan.frexp() { - (x, _) => x.is_nan(), - }) + assert_eq!(match inf.frexp() { (x, _) => x }, inf); + assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); + assert!(match nan.frexp() { (x, _) => x.is_nan() }) } #[test] diff --git a/std/src/num/f64.rs b/ctr-std/src/f64.rs similarity index 86% rename from std/src/num/f64.rs rename to ctr-std/src/f64.rs index 2f23dbe..67a1c30 100644 --- a/std/src/num/f64.rs +++ b/ctr-std/src/f64.rs @@ -2,8 +2,9 @@ // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your // option. This file may not be copied, modified, or distributed // except according to those terms. @@ -11,29 +12,35 @@ //! //! *[See also the `f64` primitive type](../primitive.f64.html).* +#![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] #[cfg(not(test))] use core::num; #[cfg(not(test))] -use core::intrinsics; +use intrinsics; #[cfg(not(test))] -use libctru::libc::c_int; +use libc::c_int; #[cfg(not(test))] -use core::num::FpCategory; +use num::FpCategory; +#[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; #[allow(dead_code)] mod cmath { - use libctru::libc::{c_double, c_int}; + use libc::{c_double, c_int}; #[link_name = "m"] - extern "C" { + 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; @@ -91,10 +98,9 @@ impl f64 { /// assert!(nan.is_nan()); /// assert!(!f.is_nan()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_nan(self) -> bool { - num::Float::is_nan(self) - } + pub fn is_nan(self) -> bool { num::Float::is_nan(self) } /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. @@ -113,10 +119,9 @@ impl f64 { /// assert!(inf.is_infinite()); /// assert!(neg_inf.is_infinite()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_infinite(self) -> bool { - num::Float::is_infinite(self) - } + pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) } /// Returns `true` if this number is neither infinite nor `NaN`. /// @@ -134,10 +139,9 @@ impl f64 { /// assert!(!inf.is_finite()); /// assert!(!neg_inf.is_finite()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_finite(self) -> bool { - num::Float::is_finite(self) - } + pub fn is_finite(self) -> bool { num::Float::is_finite(self) } /// Returns `true` if the number is neither zero, infinite, /// [subnormal][subnormal], or `NaN`. @@ -160,10 +164,9 @@ impl f64 { /// assert!(!lower_than_min.is_normal()); /// ``` /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_normal(self) -> bool { - num::Float::is_normal(self) - } + pub fn is_normal(self) -> bool { num::Float::is_normal(self) } /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific @@ -179,10 +182,9 @@ impl f64 { /// assert_eq!(num.classify(), FpCategory::Normal); /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn classify(self) -> FpCategory { - num::Float::classify(self) - } + pub fn classify(self) -> FpCategory { num::Float::classify(self) } /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. @@ -205,11 +207,14 @@ impl f64 { /// assert!(abs_difference < 1e-10); /// ``` /// [floating-point]: ../reference.html#machine-types + #[unstable(feature = "float_extras", reason = "signature is undecided", + issue = "27752")] + #[rustc_deprecated(since = "1.11.0", + reason = "never really came to fruition and easily \ + implementable outside the standard library")] #[inline] #[allow(deprecated)] - pub fn integer_decode(self) -> (u64, i16, i8) { - num::Float::integer_decode(self) - } + pub fn integer_decode(self) -> (u64, i16, i8) { num::Float::integer_decode(self) } /// Returns the largest integer less than or equal to a number. /// @@ -220,6 +225,7 @@ impl 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) } @@ -234,6 +240,7 @@ impl 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) } @@ -249,6 +256,7 @@ impl 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) } @@ -263,6 +271,7 @@ impl 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) } @@ -279,10 +288,9 @@ impl f64 { /// 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() - } + pub fn fract(self) -> f64 { self - self.trunc() } /// Computes the absolute value of `self`. Returns `NAN` if the /// number is `NAN`. @@ -301,10 +309,9 @@ impl f64 { /// /// assert!(f64::NAN.abs().is_nan()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f64 { - num::Float::abs(self) - } + pub fn abs(self) -> f64 { num::Float::abs(self) } /// Returns a number that represents the sign of `self`. /// @@ -322,10 +329,9 @@ impl f64 { /// /// assert!(f64::NAN.signum().is_nan()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f64 { - num::Float::signum(self) - } + pub fn signum(self) -> f64 { num::Float::signum(self) } /// Returns `true` if `self`'s sign bit is positive, including /// `+0.0` and `INFINITY`. @@ -343,15 +349,14 @@ impl f64 { /// // Requires both tests to determine if is `NaN` /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_positive(self) -> bool { - num::Float::is_sign_positive(self) - } + pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] #[inline] - pub fn is_positive(self) -> bool { - num::Float::is_sign_positive(self) - } + pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) } /// Returns `true` if `self`'s sign is negative, including `-0.0` /// and `NEG_INFINITY`. @@ -369,15 +374,14 @@ impl f64 { /// // Requires both tests to determine if is `NaN`. /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_negative(self) -> bool { - num::Float::is_sign_negative(self) - } + pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) } + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] #[inline] - pub fn is_negative(self) -> bool { - num::Float::is_sign_negative(self) - } + pub fn is_negative(self) -> bool { num::Float::is_sign_negative(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -393,6 +397,7 @@ impl f64 { /// /// 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) } @@ -406,10 +411,9 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn recip(self) -> f64 { - num::Float::recip(self) - } + pub fn recip(self) -> f64 { num::Float::recip(self) } /// Raises a number to an integer power. /// @@ -421,10 +425,9 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f64 { - num::Float::powi(self, n) - } + pub fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) } /// Raises a number to a floating point power. /// @@ -434,6 +437,7 @@ impl f64 { /// /// 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) } @@ -452,6 +456,7 @@ impl f64 { /// 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 { @@ -473,6 +478,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp(self) -> f64 { unsafe { intrinsics::expf64(self) } @@ -488,6 +494,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp2(self) -> f64 { unsafe { intrinsics::exp2f64(self) } @@ -505,6 +512,7 @@ impl f64 { /// /// 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) } }) @@ -525,10 +533,9 @@ impl f64 { /// assert!(abs_difference_10 < 1e-10); /// assert!(abs_difference_2 < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn log(self, base: f64) -> f64 { - self.ln() / base.ln() - } + pub fn log(self, base: f64) -> f64 { self.ln() / base.ln() } /// Returns the base 2 logarithm of the number. /// @@ -540,9 +547,13 @@ impl f64 { /// /// 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) }; }) } @@ -557,6 +568,7 @@ impl f64 { /// /// 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) } }) @@ -573,10 +585,9 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn to_degrees(self) -> f64 { - num::Float::to_degrees(self) - } + pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) } /// Converts degrees to radians. /// @@ -589,10 +600,9 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn to_radians(self) -> f64 { - num::Float::to_radians(self) - } + pub fn to_radians(self) -> f64 { num::Float::to_radians(self) } /// Constructs a floating point number of `x*2^exp`. /// @@ -604,6 +614,12 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[unstable(feature = "float_extras", + reason = "pending integer conventions", + issue = "27752")] + #[rustc_deprecated(since = "1.11.0", + reason = "never really came to fruition and easily \ + implementable outside the standard library")] #[inline] pub fn ldexp(x: f64, exp: isize) -> f64 { unsafe { cmath::ldexp(x, exp as c_int) } @@ -628,6 +644,12 @@ impl f64 { /// assert!(abs_difference_0 < 1e-10); /// assert!(abs_difference_1 < 1e-10); /// ``` + #[unstable(feature = "float_extras", + reason = "pending integer conventions", + issue = "27752")] + #[rustc_deprecated(since = "1.11.0", + reason = "never really came to fruition and easily \ + implementable outside the standard library")] #[inline] pub fn frexp(self) -> (f64, isize) { unsafe { @@ -649,6 +671,12 @@ impl f64 { /// /// assert!(abs_diff < 1e-10); /// ``` + #[unstable(feature = "float_extras", + reason = "unsure about its place in the world", + issue = "27752")] + #[rustc_deprecated(since = "1.11.0", + reason = "never really came to fruition and easily \ + implementable outside the standard library")] #[inline] pub fn next_after(self, other: f64) -> f64 { unsafe { cmath::nextafter(self, other) } @@ -664,6 +692,7 @@ impl f64 { /// ``` /// /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f64) -> f64 { unsafe { cmath::fmax(self, other) } @@ -679,6 +708,7 @@ impl f64 { /// ``` /// /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f64) -> f64 { unsafe { cmath::fmin(self, other) } @@ -699,10 +729,18 @@ impl f64 { /// assert!(abs_difference_x < 1e-10); /// assert!(abs_difference_y < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs_sub(self, other: f64) -> f64 { - unsafe { cmath::fdim(self, other) } - } + #[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. /// @@ -714,6 +752,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f64 { unsafe { cmath::cbrt(self) } @@ -731,6 +770,7 @@ impl f64 { /// /// 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) } @@ -747,6 +787,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sin(self) -> f64 { unsafe { intrinsics::sinf64(self) } @@ -763,6 +804,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cos(self) -> f64 { unsafe { intrinsics::cosf64(self) } @@ -778,6 +820,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-14); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tan(self) -> f64 { unsafe { cmath::tan(self) } @@ -797,6 +840,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asin(self) -> f64 { unsafe { cmath::asin(self) } @@ -816,6 +860,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acos(self) -> f64 { unsafe { cmath::acos(self) } @@ -832,6 +877,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn atan(self) -> f64 { unsafe { cmath::atan(self) } @@ -863,6 +909,7 @@ impl f64 { /// 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) } @@ -883,6 +930,7 @@ impl f64 { /// 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()) @@ -899,6 +947,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp_m1(self) -> f64 { unsafe { cmath::expm1(self) } @@ -917,6 +966,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln_1p(self) -> f64 { unsafe { cmath::log1p(self) } @@ -937,6 +987,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sinh(self) -> f64 { unsafe { cmath::sinh(self) } @@ -957,6 +1008,7 @@ impl f64 { /// // 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) } @@ -977,6 +1029,7 @@ impl f64 { /// /// assert!(abs_difference < 1.0e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn tanh(self) -> f64 { unsafe { cmath::tanh(self) } @@ -992,6 +1045,7 @@ impl f64 { /// /// assert!(abs_difference < 1.0e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asinh(self) -> f64 { if self == NEG_INFINITY { @@ -1011,6 +1065,7 @@ impl f64 { /// /// assert!(abs_difference < 1.0e-10); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acosh(self) -> f64 { match self { @@ -1031,6 +1086,7 @@ impl f64 { /// /// 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() @@ -1236,10 +1292,8 @@ mod tests { #[test] #[allow(deprecated)] fn test_integer_decode() { - assert_eq!(3.14159265359f64.integer_decode(), - (7074237752028906, -51, 1)); - assert_eq!((-8573.5918555f64).integer_decode(), - (4713381968463931, -39, -1)); + assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); + assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); assert_eq!(0f64.integer_decode(), (0, -1075, 1)); assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); @@ -1330,7 +1384,7 @@ mod tests { assert_eq!((-0f64).abs(), 0f64); assert_eq!((-1f64).abs(), 1f64); assert_eq!(NEG_INFINITY.abs(), INFINITY); - assert_eq!((1f64 / NEG_INFINITY).abs(), 0f64); + assert_eq!((1f64/NEG_INFINITY).abs(), 0f64); assert!(NAN.abs().is_nan()); } @@ -1342,7 +1396,7 @@ mod tests { assert_eq!((-0f64).signum(), -1f64); assert_eq!((-1f64).signum(), -1f64); assert_eq!(NEG_INFINITY.signum(), -1f64); - assert_eq!((1f64 / NEG_INFINITY).signum(), -1f64); + assert_eq!((1f64/NEG_INFINITY).signum(), -1f64); assert!(NAN.signum().is_nan()); } @@ -1354,7 +1408,7 @@ mod tests { assert!(!(-0f64).is_sign_positive()); assert!(!(-1f64).is_sign_positive()); assert!(!NEG_INFINITY.is_sign_positive()); - assert!(!(1f64 / NEG_INFINITY).is_sign_positive()); + assert!(!(1f64/NEG_INFINITY).is_sign_positive()); assert!(!NAN.is_sign_positive()); } @@ -1366,7 +1420,7 @@ mod tests { assert!((-0f64).is_sign_negative()); assert!((-1f64).is_sign_negative()); assert!(NEG_INFINITY.is_sign_negative()); - assert!((1f64 / NEG_INFINITY).is_sign_negative()); + assert!((1f64/NEG_INFINITY).is_sign_negative()); assert!(!NAN.is_sign_negative()); } @@ -1604,25 +1658,15 @@ mod tests { assert_eq!((-0f64).frexp(), (-0f64, 0)); } - #[test] - #[cfg_attr(windows, ignore)] - // FIXME #8755 + #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 #[allow(deprecated)] fn test_frexp_nowin() { let inf: f64 = INFINITY; let neg_inf: f64 = NEG_INFINITY; let nan: f64 = NAN; - assert_eq!(match inf.frexp() { - (x, _) => x, - }, - inf); - assert_eq!(match neg_inf.frexp() { - (x, _) => x, - }, - neg_inf); - assert!(match nan.frexp() { - (x, _) => x.is_nan(), - }) + assert_eq!(match inf.frexp() { (x, _) => x }, inf); + assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); + assert!(match nan.frexp() { (x, _) => x.is_nan() }) } #[test] diff --git a/std/src/ffi/c_str.rs b/ctr-std/src/ffi/c_str.rs similarity index 88% rename from std/src/ffi/c_str.rs rename to ctr-std/src/ffi/c_str.rs index 159c683..ad40660 100644 --- a/std/src/ffi/c_str.rs +++ b/ctr-std/src/ffi/c_str.rs @@ -14,7 +14,7 @@ use cmp::Ordering; use error::Error; use fmt::{self, Write}; use io; -use libctru::libc::{self, c_char}; +use libc::{self, c_char}; use mem; use memchr; use ops; @@ -66,6 +66,7 @@ use str::{self, Utf8Error}; /// 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. @@ -133,6 +134,7 @@ pub struct CString { /// println!("string: {}", my_string_safe()); /// ``` #[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 @@ -144,16 +146,19 @@ pub struct CStr { /// An error returned from `CString::new` to indicate that a nul byte was found /// in the vector provided. #[derive(Clone, PartialEq, Eq, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] pub struct NulError(usize, Vec); /// An error returned from `CStr::from_bytes_with_nul` to indicate that a nul /// byte was found too early in the slice provided or one wasn't found at all. #[derive(Clone, PartialEq, Eq, Debug)] +#[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub struct FromBytesWithNulError { _a: () } /// An error returned from `CString::into_string` to indicate that a UTF-8 error /// was encountered during the conversion. #[derive(Clone, PartialEq, Eq, Debug)] +#[stable(feature = "cstring_into", since = "1.7.0")] pub struct IntoStringError { inner: CString, error: Utf8Error, @@ -184,6 +189,7 @@ impl CString { /// This function will return an error if the bytes yielded contain an /// internal 0 byte. The error returned will contain the bytes as well as /// the position of the nul byte. + #[stable(feature = "rust1", since = "1.0.0")] pub fn new>>(t: T) -> Result { Self::_new(t.into()) } @@ -212,6 +218,7 @@ impl CString { /// 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); @@ -228,6 +235,7 @@ impl CString { /// 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. + #[stable(feature = "cstr_memory", since = "1.4.0")] pub unsafe fn from_raw(ptr: *mut c_char) -> CString { let len = libc::strlen(ptr) + 1; // Including the NUL byte let slice = slice::from_raw_parts(ptr, len as usize); @@ -242,6 +250,7 @@ impl CString { /// this string. /// /// Failure to call `from_raw` will lead to a memory leak. + #[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 } @@ -249,6 +258,7 @@ impl CString { /// Converts the `CString` into a `String` if it contains valid Unicode data. /// /// On failure, ownership of the original `CString` is returned. + #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_string(self) -> Result { String::from_utf8(self.into_bytes()) .map_err(|e| IntoStringError { @@ -261,6 +271,7 @@ impl CString { /// /// The returned buffer does **not** contain the trailing nul separator and /// it is guaranteed to not have any interior nul bytes. + #[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(); @@ -270,6 +281,7 @@ impl CString { /// Equivalent to the `into_bytes` function except that the returned vector /// includes the trailing nul byte. + #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes_with_nul(self) -> Vec { self.into_inner().into_vec() } @@ -278,12 +290,14 @@ impl CString { /// /// The returned slice does **not** contain the trailing nul separator and /// it is guaranteed to not have any interior nul bytes. + #[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 byte. + #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes_with_nul(&self) -> &[u8] { &self.inner } @@ -301,6 +315,7 @@ impl CString { // 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) { @@ -308,6 +323,7 @@ impl Drop for CString { } } +#[stable(feature = "rust1", since = "1.0.0")] impl ops::Deref for CString { type Target = CStr; @@ -316,18 +332,21 @@ impl ops::Deref for CString { } } +#[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 { 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, "\"")?; @@ -338,6 +357,7 @@ impl fmt::Debug for CStr { } } +#[stable(feature = "cstr_default", since = "1.10.0")] impl<'a> Default for &'a CStr { fn default() -> &'a CStr { static SLICE: &'static [c_char] = &[0]; @@ -345,6 +365,7 @@ impl<'a> Default for &'a CStr { } } +#[stable(feature = "cstr_default", since = "1.10.0")] impl Default for CString { /// Creates an empty `CString`. fn default() -> CString { @@ -353,6 +374,7 @@ impl Default for CString { } } +#[stable(feature = "cstr_borrow", since = "1.3.0")] impl Borrow for CString { fn borrow(&self) -> &CStr { self } } @@ -372,6 +394,7 @@ impl NulError { /// 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 @@ -385,19 +408,23 @@ impl NulError { /// 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 { fn from(_: NulError) -> io::Error { io::Error::new(io::ErrorKind::InvalidInput, @@ -408,16 +435,19 @@ impl From for io::Error { impl IntoStringError { /// Consumes this error, returning original `CString` which generated the /// error. + #[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" @@ -428,6 +458,7 @@ impl Error for IntoStringError { } } +#[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) @@ -468,6 +499,7 @@ impl CStr { /// } /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { let len = libc::strlen(ptr); mem::transmute(slice::from_raw_parts(ptr, len as usize + 1)) @@ -487,6 +519,7 @@ impl CStr { /// let cstr = CStr::from_bytes_with_nul(b"hello\0"); /// assert!(cstr.is_ok()); /// ``` + #[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { if bytes.is_empty() || memchr::memchr(0, &bytes) != Some(bytes.len() - 1) { @@ -513,6 +546,7 @@ impl CStr { /// assert_eq!(cstr, &*cstring); /// } /// ``` + #[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { mem::transmute(bytes) } @@ -554,6 +588,7 @@ impl CStr { /// *ptr; /// } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() } @@ -570,6 +605,7 @@ impl CStr { /// > **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. + #[stable(feature = "rust1", since = "1.0.0")] pub fn to_bytes(&self) -> &[u8] { let bytes = self.to_bytes_with_nul(); &bytes[..bytes.len() - 1] @@ -583,6 +619,7 @@ impl CStr { /// > **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. + #[stable(feature = "rust1", since = "1.0.0")] pub fn to_bytes_with_nul(&self) -> &[u8] { unsafe { mem::transmute(&self.inner) } } @@ -596,6 +633,7 @@ impl CStr { /// > after a 0-cost 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. + #[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 @@ -615,28 +653,34 @@ impl CStr { /// > after a 0-cost 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. + #[stable(feature = "cstr_to_str", since = "1.4.0")] pub fn to_string_lossy(&self) -> Cow { String::from_utf8_lossy(self.to_bytes()) } } +#[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; @@ -645,12 +689,14 @@ impl ToOwned for CStr { } } +#[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; @@ -660,12 +706,14 @@ impl ops::Index for CString { } } +#[stable(feature = "cstring_asref", since = "1.7.0")] impl AsRef for CStr { fn as_ref(&self) -> &CStr { self } } +#[stable(feature = "cstring_asref", since = "1.7.0")] impl AsRef for CString { fn as_ref(&self) -> &CStr { self @@ -675,10 +723,10 @@ impl AsRef for CString { #[cfg(test)] mod tests { use super::*; - use libc::c_char; - use collections::borrow::Cow::{Borrowed, Owned}; - use collections::borrow::ToOwned; - use core::hash::{Hash, Hasher}; + use os::raw::c_char; + use borrow::Cow::{Borrowed, Owned}; + use hash::{Hash, Hasher}; + use collections::hash_map::DefaultHasher; #[test] fn c_to_rust() { @@ -754,6 +802,22 @@ mod tests { 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"; diff --git a/ctr-std/src/ffi/mod.rs b/ctr-std/src/ffi/mod.rs new file mode 100644 index 0000000..ca1ff18 --- /dev/null +++ b/ctr-std/src/ffi/mod.rs @@ -0,0 +1,24 @@ +// 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. + +#![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/std/src/ffi/os_str.rs b/ctr-std/src/ffi/os_str.rs similarity index 75% rename from std/src/ffi/os_str.rs rename to ctr-std/src/ffi/os_str.rs index 651eaf3..84b50f0 100644 --- a/std/src/ffi/os_str.rs +++ b/ctr-std/src/ffi/os_str.rs @@ -15,9 +15,8 @@ use ops; use cmp; use hash::{Hash, Hasher}; -use sys::wtf8::{Wtf8, Wtf8Buf}; -use sys::{AsInner, IntoInner, FromInner}; -pub use sys::wtf8::EncodeWide; +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. @@ -36,26 +35,26 @@ pub use sys::wtf8::EncodeWide; /// and platform-native string values, and in particular allowing a Rust string /// to be converted into an "OS" string with no cost. #[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { - inner: Wtf8Buf + inner: Buf } /// Slices into OS strings (see `OsString`). +#[stable(feature = "rust1", since = "1.0.0")] pub struct OsStr { - inner: Wtf8 + inner: Slice } impl OsString { /// Constructs a new empty `OsString`. + #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> OsString { - OsString { inner: Wtf8Buf::from_string(String::new()) } - } - - fn _from_bytes(vec: Vec) -> Option { - String::from_utf8(vec).ok().map(OsString::from) + OsString { inner: Buf::from_string(String::new()) } } /// Converts to an `OsStr` slice. + #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &OsStr { self } @@ -63,13 +62,15 @@ impl OsString { /// Converts the `OsString` into a `String` if it contains valid Unicode data. /// /// On failure, ownership of the original `OsString` is returned. + #[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. + #[stable(feature = "rust1", since = "1.0.0")] pub fn push>(&mut self, s: T) { - self.inner.push_wtf8(&s.as_ref().inner) + self.inner.push_slice(&s.as_ref().inner) } /// Creates a new `OsString` with the given capacity. @@ -79,13 +80,15 @@ impl OsString { /// allocate. /// /// See main `OsString` documentation information about encoding. + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn with_capacity(capacity: usize) -> OsString { OsString { - inner: Wtf8Buf::with_capacity(capacity) + inner: Buf::with_capacity(capacity) } } /// Truncates the `OsString` to zero length. + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn clear(&mut self) { self.inner.clear() } @@ -93,6 +96,7 @@ impl OsString { /// Returns the capacity this `OsString` can hold without reallocating. /// /// See `OsString` introduction for information about encoding. + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn capacity(&self) -> usize { self.inner.capacity() } @@ -101,6 +105,7 @@ impl OsString { /// in the given `OsString`. /// /// The collection may reserve more space to avoid frequent reallocations. + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) } @@ -112,34 +117,27 @@ impl OsString { /// 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. + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) } - - /// 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. - /// - /// NOTE: This function was copied from the windows implementation of OsStringExt - pub fn from_wide(wide: &[u16]) -> OsString { - OsString { inner: Wtf8Buf::from_wide(wide) } - } } +#[stable(feature = "rust1", since = "1.0.0")] impl From for OsString { fn from(s: String) -> OsString { - OsString { inner: Wtf8Buf::from_string(s) } + 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; @@ -149,6 +147,7 @@ impl ops::Index for OsString { } } +#[stable(feature = "rust1", since = "1.0.0")] impl ops::Deref for OsString { type Target = OsStr; @@ -158,39 +157,47 @@ impl ops::Deref for OsString { } } +#[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 Debug for OsString { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { 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 = "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 { @@ -206,6 +213,7 @@ impl PartialOrd for OsString { 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 { @@ -213,6 +221,7 @@ impl PartialOrd for OsString { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Ord for OsString { #[inline] fn cmp(&self, other: &OsString) -> cmp::Ordering { @@ -220,6 +229,7 @@ impl Ord for OsString { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Hash for OsString { #[inline] fn hash(&self, state: &mut H) { @@ -229,38 +239,61 @@ impl Hash for OsString { 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: &Wtf8) -> &OsStr { + fn from_inner(inner: &Slice) -> &OsStr { unsafe { mem::transmute(inner) } } /// Yields a `&str` slice if the `OsStr` is valid Unicode. /// /// This conversion may entail doing a check for UTF-8 validity. + #[stable(feature = "rust1", since = "1.0.0")] pub fn to_str(&self) -> Option<&str> { - self.inner.as_str() + self.inner.to_str() } /// Converts an `OsStr` to a `Cow`. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. + #[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`. + #[stable(feature = "rust1", since = "1.0.0")] pub fn to_os_string(&self) -> OsString { - let mut buf = Wtf8Buf::with_capacity(self.inner.len()); - buf.push_wtf8(&self.inner); - OsString { inner: buf } + 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.is_empty() + self.inner.inner.is_empty() } /// Returns the length of this `OsStr`. @@ -271,8 +304,21 @@ impl OsStr { /// other methods like `OsString::with_capacity` to avoid reallocations. /// /// See `OsStr` introduction for more information about encoding. + /// + /// # 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.len() + self.inner.inner.len() } /// Gets the underlying byte representation. @@ -282,46 +328,42 @@ impl OsStr { fn bytes(&self) -> &[u8] { unsafe { mem::transmute(&self.inner) } } - - /// Re-encodes an `OsStr` as a wide character sequence, - /// i.e. potentially ill-formed UTF-16. - /// This is lossless. Note that the encoding does not include a final - /// null. - /// - /// NOTE: This function was copied from the windows implementation of OsStrExt - pub fn encode_wide(&self) -> EncodeWide { - self.inner.encode_wide() - } - } +#[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 { @@ -337,6 +379,7 @@ impl PartialOrd for OsStr { 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 { @@ -347,6 +390,7 @@ impl PartialOrd for OsStr { // 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()) } @@ -354,16 +398,19 @@ impl Ord for OsStr { 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 { @@ -371,6 +418,7 @@ macro_rules! impl_cmp { } } + #[stable(feature = "cmp_os_str", since = "1.8.0")] impl<'a, 'b> PartialOrd<$lhs> for $rhs { #[inline] fn partial_cmp(&self, other: &$lhs) -> Option { @@ -386,6 +434,7 @@ 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) { @@ -393,59 +442,66 @@ impl Hash for OsStr { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Debug for OsStr { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { self.inner.fmt(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() } } +#[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(Wtf8::from_str(self)) + 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: Wtf8Buf) -> OsString { +impl FromInner for OsString { + fn from_inner(buf: Buf) -> OsString { OsString { inner: buf } } } -impl IntoInner for OsString { - fn into_inner(self) -> Wtf8Buf { +impl IntoInner for OsString { + fn into_inner(self) -> Buf { self.inner } } -impl AsInner for OsStr { - fn as_inner(&self) -> &Wtf8 { +impl AsInner for OsStr { + fn as_inner(&self) -> &Slice { &self.inner } } @@ -453,29 +509,29 @@ impl AsInner for OsStr { #[cfg(test)] mod tests { use super::*; - use sys::{AsInner, IntoInner}; + use sys_common::{AsInner, IntoInner}; #[test] fn test_os_string_with_capacity() { let os_string = OsString::with_capacity(0); - assert_eq!(0, os_string.inner.capacity()); + assert_eq!(0, os_string.inner.into_inner().capacity()); let os_string = OsString::with_capacity(10); - assert_eq!(10, os_string.inner.capacity()); + 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.capacity() >= 3); + 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.len()); + assert_eq!(3, os_string.inner.as_inner().len()); os_string.clear(); assert_eq!(&os_string, ""); - assert_eq!(0, os_string.inner.len()); + assert_eq!(0, os_string.inner.as_inner().len()); } #[test] diff --git a/std/src/io/buffered.rs b/ctr-std/src/io/buffered.rs similarity index 92% rename from std/src/io/buffered.rs rename to ctr-std/src/io/buffered.rs index 39733f2..44dd4e9 100644 --- a/std/src/io/buffered.rs +++ b/ctr-std/src/io/buffered.rs @@ -20,11 +20,15 @@ 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` on `TcpStream` results in a system call. -/// A `BufReader` performs large, infrequent reads on the underlying `Read` +/// It can be excessively inefficient to work directly with a [`Read`] instance. +/// For example, every call to [`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. /// +/// [`Read`]: ../../std/io/trait.Read.html +/// [`read`]: ../../std/net/struct.TcpStream.html#method.read +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html +/// /// # Examples /// /// ``` @@ -42,6 +46,7 @@ use memchr; /// # Ok(()) /// # } /// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub struct BufReader { inner: R, buf: Box<[u8]>, @@ -64,6 +69,7 @@ impl BufReader { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: R) -> BufReader { BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) } @@ -84,6 +90,7 @@ impl BufReader { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: R) -> BufReader { BufReader { inner: inner, @@ -111,6 +118,7 @@ impl BufReader { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &R { &self.inner } /// Gets a mutable reference to the underlying reader. @@ -131,6 +139,7 @@ impl BufReader { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut R { &mut self.inner } /// Unwraps this `BufReader`, returning the underlying reader. @@ -151,9 +160,11 @@ impl BufReader { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> R { self.inner } } +#[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 @@ -171,6 +182,7 @@ impl Read for BufReader { } } +#[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 @@ -187,6 +199,7 @@ impl BufRead for BufReader { } } +#[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") @@ -196,6 +209,7 @@ impl fmt::Debug for BufReader where R: fmt::Debug { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Seek for BufReader { /// Seek to an offset, in bytes, in the underlying reader. /// @@ -205,8 +219,8 @@ impl Seek for BufReader { /// /// Seeking always discards the internal buffer, even if the seek position /// would otherwise fall within it. This guarantees that calling - /// `.unwrap()` immediately after a seek yields the underlying reader at - /// the same position. + /// `.into_inner()` immediately after a seek yields the underlying reader + /// at the same position. /// /// See `std::io::Seek` for more details. /// @@ -220,7 +234,7 @@ impl Seek for BufReader { 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 ebibytes and that's absurd. + // 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. @@ -244,7 +258,7 @@ impl Seek for BufReader { /// 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` on `TcpStream` +/// implements [`Write`]. For example, every call to [`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. /// @@ -252,7 +266,7 @@ impl Seek for BufReader { /// /// # Examples /// -/// Let's write the numbers one through ten to a `TcpStream`: +/// Let's write the numbers one through ten to a [`TcpStream`]: /// /// ```no_run /// use std::io::prelude::*; @@ -284,6 +298,11 @@ impl Seek for BufReader { /// 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 +/// [`write`]: ../../std/net/struct.TcpStream.html#method.write +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html +#[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter { inner: Option, buf: Vec, @@ -318,6 +337,7 @@ pub struct BufWriter { /// }; /// ``` #[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] pub struct IntoInnerError(W, Error); impl BufWriter { @@ -331,6 +351,7 @@ impl BufWriter { /// /// 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) } @@ -348,6 +369,7 @@ impl BufWriter { /// 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), @@ -396,6 +418,7 @@ impl BufWriter { /// // 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. @@ -413,6 +436,7 @@ impl BufWriter { /// // 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. @@ -430,6 +454,7 @@ impl BufWriter { /// // 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)), @@ -438,6 +463,7 @@ impl BufWriter { } } +#[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() { @@ -449,8 +475,7 @@ impl Write for BufWriter { self.panicked = false; r } else { - let amt = cmp::min(buf.len(), self.buf.capacity()); - Write::write(&mut self.buf, &buf[..amt]) + Write::write(&mut self.buf, buf) } } fn flush(&mut self) -> io::Result<()> { @@ -458,6 +483,7 @@ impl Write for BufWriter { } } +#[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") @@ -467,6 +493,7 @@ impl fmt::Debug for BufWriter where W: fmt::Debug { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Seek for BufWriter { /// Seek to the offset, in bytes, in the underlying writer. /// @@ -476,6 +503,7 @@ impl Seek for BufWriter { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Drop for BufWriter { fn drop(&mut self) { if self.inner.is_some() && !self.panicked { @@ -514,6 +542,7 @@ impl IntoInnerError { /// } /// }; /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn error(&self) -> &Error { &self.1 } /// Returns the buffered writer instance which generated the error. @@ -546,19 +575,23 @@ impl IntoInnerError { /// } /// }; /// ``` + #[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) @@ -613,6 +646,7 @@ impl fmt::Display for IntoInnerError { /// # Ok(()) /// # } /// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub struct LineWriter { inner: BufWriter, } @@ -632,6 +666,7 @@ impl LineWriter { /// # 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) @@ -652,6 +687,7 @@ impl LineWriter { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: W) -> LineWriter { LineWriter { inner: BufWriter::with_capacity(cap, inner) } } @@ -672,6 +708,7 @@ impl LineWriter { /// # 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. @@ -694,6 +731,7 @@ impl LineWriter { /// # 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. @@ -715,6 +753,7 @@ impl LineWriter { /// # 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 }, e) @@ -722,6 +761,7 @@ impl LineWriter { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Write for LineWriter { fn write(&mut self, buf: &[u8]) -> io::Result { match memchr::memrchr(b'\n', buf) { @@ -740,6 +780,7 @@ impl Write for LineWriter { fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } +#[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") @@ -754,13 +795,10 @@ impl fmt::Debug for LineWriter where W: fmt::Debug { mod tests { use io::prelude::*; use io::{self, BufReader, BufWriter, LineWriter, SeekFrom}; - //use sync::atomic::{AtomicUsize, Ordering}; - //use thread; + use sync::atomic::{AtomicUsize, Ordering}; + use thread; use test; - use collections::{Vec, String}; - use collections::string::ToString; - /// A dummy reader intended at testing short-reads propagation. pub struct ShortReader { lengths: Vec, @@ -1075,9 +1113,8 @@ mod tests { panic!(); } - // NOTE: These tests are for threading stuff that is not yet implemented - /* #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn panic_in_write_doesnt_flush_in_drop() { static WRITES: AtomicUsize = AtomicUsize::new(0); @@ -1113,5 +1150,4 @@ mod tests { BufWriter::new(io::sink()) }); } - */ } diff --git a/std/src/io/cursor.rs b/ctr-std/src/io/cursor.rs similarity index 88% rename from std/src/io/cursor.rs rename to ctr-std/src/io/cursor.rs index befbf14..1b50233 100644 --- a/std/src/io/cursor.rs +++ b/ctr-std/src/io/cursor.rs @@ -10,26 +10,33 @@ use io::prelude::*; +use core::convert::TryInto; use cmp; use io::{self, SeekFrom, Error, ErrorKind}; /// A `Cursor` wraps another type and provides it with a -/// [`Seek`](trait.Seek.html) implementation. +/// [`Seek`] implementation. /// -/// Cursors are typically used with in-memory buffers to allow them to -/// implement `Read` and/or `Write`, allowing these buffers to be used +/// `Cursor`s are typically used with in-memory buffers 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>` and `Cursor<&[u8]>`. +/// are commonly used as a buffer, like `Cursor<`[`Vec`]`>` and +/// `Cursor<`[`&[u8]`][bytes]`>`. /// /// # Examples /// -/// We may want to write bytes to a [`File`][file] in our production +/// 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`: /// -/// [file]: ../fs/struct.File.html +/// [`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::*; @@ -72,6 +79,7 @@ use io::{self, SeekFrom, Error, ErrorKind}; /// 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, @@ -90,6 +98,7 @@ impl Cursor { /// # 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 } } @@ -107,6 +116,7 @@ impl Cursor { /// /// 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. @@ -122,6 +132,7 @@ impl Cursor { /// /// 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. @@ -140,6 +151,7 @@ impl Cursor { /// /// 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. @@ -161,6 +173,7 @@ impl Cursor { /// 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. @@ -180,9 +193,11 @@ impl Cursor { /// 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 pos = match style { @@ -201,6 +216,7 @@ impl io::Seek for Cursor where T: AsRef<[u8]> { } } +#[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)?; @@ -209,6 +225,7 @@ impl Read for Cursor where T: AsRef<[u8]> { } } +#[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); @@ -217,6 +234,7 @@ impl BufRead for Cursor where T: AsRef<[u8]> { fn consume(&mut self, amt: usize) { self.pos += amt as u64; } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for Cursor<&'a mut [u8]> { #[inline] fn write(&mut self, data: &[u8]) -> io::Result { @@ -228,20 +246,23 @@ impl<'a> Write for Cursor<&'a mut [u8]> { 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 { + let pos: usize = self.position().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 pos = self.position(); - let amt = pos.saturating_sub(self.inner.len() as u64); - // use `resize` so that the zero filling is as efficient as possible let len = self.inner.len(); - self.inner.resize(len + amt as usize, 0); - + if len < pos { + // use `resize` so that the zero filling is as efficient as possible + self.inner.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 pos = pos as usize; let space = self.inner.len() - pos; let (left, right) = buf.split_at(cmp::min(space, buf.len())); self.inner[pos..pos + left.len()].copy_from_slice(left); @@ -249,12 +270,13 @@ impl Write for Cursor> { } // Bump us forward - self.set_position(pos + buf.len() as u64); + self.set_position((pos + buf.len()) as u64); Ok(buf.len()) } 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 { @@ -271,8 +293,6 @@ mod tests { use io::prelude::*; use io::{Cursor, SeekFrom}; - use collections::Vec; - #[test] fn test_vec_writer() { let mut writer = Vec::new(); @@ -372,7 +392,7 @@ mod tests { #[test] fn test_mem_reader() { - let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); + 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); @@ -394,7 +414,7 @@ mod tests { #[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 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); @@ -416,7 +436,7 @@ mod tests { #[test] fn read_to_end() { - let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); + 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]); @@ -492,7 +512,7 @@ mod tests { assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); assert_eq!(r.read(&mut [0]).unwrap(), 0); - let mut r = Cursor::new(vec!(10)); + let mut r = Cursor::new(vec![10]); assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); assert_eq!(r.read(&mut [0]).unwrap(), 0); @@ -512,14 +532,14 @@ mod tests { let mut r = Cursor::new(&buf[..]); assert!(r.seek(SeekFrom::End(-2)).is_err()); - let mut r = Cursor::new(vec!(10)); + 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()); + let mut r = Cursor::new(vec![10].into_boxed_slice()); assert!(r.seek(SeekFrom::End(-2)).is_err()); } @@ -569,4 +589,12 @@ mod tests { 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/std/src/io/error.rs b/ctr-std/src/io/error.rs similarity index 50% rename from std/src/io/error.rs rename to ctr-std/src/io/error.rs index bc05469..795c89c 100644 --- a/std/src/io/error.rs +++ b/ctr-std/src/io/error.rs @@ -8,10 +8,11 @@ // 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. @@ -43,6 +44,7 @@ use result; /// 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 @@ -50,14 +52,18 @@ pub type Result = result::Result; /// /// 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`. +/// [`ErrorKind`]. +/// +/// [`ErrorKind`]: enum.ErrorKind.html #[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] pub struct Error { repr: Repr, } enum Repr { Os(i32), + Simple(ErrorKind), Custom(Box), } @@ -71,59 +77,86 @@ struct Custom { /// /// This list is intended to grow over time and it is not recommended to /// exhaustively match against it. -#[derive(Copy, PartialEq, Eq, Clone, Debug)] +/// +/// 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)] 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 + /// 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)`. + /// 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 @@ -132,13 +165,56 @@ pub enum ErrorKind { /// 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, - /// Any I/O error not part of this list. + /// A marker variant that tells the compiler that users of this enum cannot + /// match it exhaustively. + #[unstable(feature = "io_error_internals", + reason = "better expressed through extensible enums that this \ + enum cannot be exhaustively matched against", + issue = "0")] #[doc(hidden)] __Nonexhaustive, } +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", + ErrorKind::__Nonexhaustive => unreachable!() + } + } +} + +/// 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 { + 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. @@ -158,6 +234,7 @@ impl Error { /// // 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> { @@ -173,7 +250,50 @@ impl 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(98); + /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse); + /// # } + /// ``` + /// + /// On Windows: + /// + /// ``` + /// # if cfg!(windows) { + /// use std::io; + /// + /// let error = io::Error::from_raw_os_error(10048); + /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse); + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn from_raw_os_error(code: i32) -> Error { Error { repr: Repr::Os(code) } } @@ -183,10 +303,33 @@ impl Error { /// 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, } } @@ -194,9 +337,32 @@ impl Error { /// /// 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<&(error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(ref c) => Some(&*c.error), } } @@ -206,9 +372,68 @@ impl Error { /// /// 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_owned() + /// } + /// } + /// + /// fn change_message(&mut self, new_message: &str) { + /// self.v = new_message.to_owned(); + /// } + /// } + /// + /// 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 (error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(ref mut c) => Some(&mut *c.error), } } @@ -217,18 +442,60 @@ impl Error { /// /// 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) => ErrorKind::Other, + Repr::Os(code) => sys::decode_error_kind(code), Repr::Custom(ref c) => c.kind, + Repr::Simple(kind) => kind, } } } @@ -237,47 +504,33 @@ impl fmt::Debug for Repr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { Repr::Os(ref code) => - fmt.debug_struct("Os").field("code", code).finish(), + fmt.debug_struct("Os").field("code", code) + .field("message", &sys::os::error_string(*code)).finish(), Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(), + 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) => { - write!(fmt, "os error {}", 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(..) => match self.kind() { - 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", - ErrorKind::__Nonexhaustive => unreachable!() - }, + Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(), Repr::Custom(ref c) => c.error.description(), } } @@ -285,6 +538,7 @@ impl error::Error for Error { fn cause(&self) -> Option<&error::Error> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(ref c) => c.error.cause(), } } @@ -297,7 +551,6 @@ fn _assert_error_is_sync_send() { #[cfg(test)] mod test { - use prelude::v1::*; use super::{Error, ErrorKind}; use error; use fmt; diff --git a/std/src/io/impls.rs b/ctr-std/src/io/impls.rs similarity index 86% rename from std/src/io/impls.rs rename to ctr-std/src/io/impls.rs index 360e734..6b26c01 100644 --- a/std/src/io/impls.rs +++ b/ctr-std/src/io/impls.rs @@ -16,6 +16,7 @@ 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 { @@ -37,6 +38,7 @@ impl<'a, R: Read + ?Sized> Read for &'a mut R { (**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) } @@ -54,10 +56,12 @@ impl<'a, W: Write + ?Sized> Write for &'a mut W { (**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() } @@ -76,6 +80,7 @@ impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Read for Box { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { @@ -97,6 +102,7 @@ impl Read for Box { (**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) } @@ -114,10 +120,12 @@ impl Write for Box { (**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() } @@ -139,6 +147,11 @@ impl BufRead for Box { // ============================================================================= // 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 { @@ -162,6 +175,7 @@ impl<'a> Read for &'a [u8] { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> BufRead for &'a [u8] { #[inline] fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) } @@ -170,6 +184,12 @@ impl<'a> BufRead for &'a [u8] { 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 { @@ -193,6 +213,9 @@ impl<'a> Write for &'a mut [u8] { 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 { @@ -215,8 +238,6 @@ mod tests { use io::prelude::*; use test; - use collections::Vec; - #[bench] fn bench_read_slice(b: &mut test::Bencher) { let buf = [5; 1024]; diff --git a/std/src/io/mod.rs b/ctr-std/src/io/mod.rs similarity index 85% rename from std/src/io/mod.rs rename to ctr-std/src/io/mod.rs index f66aa60..1653790 100644 --- a/std/src/io/mod.rs +++ b/ctr-std/src/io/mod.rs @@ -12,18 +12,15 @@ //! //! 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`][read] and [`Write`][write] traits, which provide the +//! the [`Read`] and [`Write`] traits, which provide the //! most general interface for reading and writing input and output. //! -//! [read]: trait.Read.html -//! [write]: trait.Write.html -//! //! # Read and Write //! -//! Because they are traits, `Read` and `Write` are implemented by a number +//! 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 +//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For //! example, `Read` adds a `read()` method, which we can use on `File`s: //! //! ``` @@ -43,15 +40,15 @@ //! # } //! ``` //! -//! `Read` and `Write` are so important, implementors of the two traits have a +//! [`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! +//! of 'a type that implements the [`Read`] trait'. Much easier! //! //! ## Seek and BufRead //! -//! Beyond that, there are two important traits that are provided: [`Seek`][seek] -//! and [`BufRead`][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 +//! 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: //! //! ``` @@ -75,21 +72,18 @@ //! # } //! ``` //! -//! [seek]: trait.Seek.html -//! [bufread]: trait.BufRead.html -//! -//! `BufRead` uses an internal buffer to provide a number of other ways to read, but +//! [`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 +//! `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 +//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra //! methods to any reader: //! //! ``` @@ -111,8 +105,8 @@ //! # } //! ``` //! -//! `BufWriter` doesn't add any new ways of writing; it just buffers every call -//! to [`write()`][write()]: +//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call +//! to [`write()`]: //! //! ``` //! use std::io; @@ -134,8 +128,6 @@ //! # } //! ``` //! -//! [write()]: trait.Write.html#tymethod.write -//! //! ## Standard input and output //! //! A very common source of input is standard input: @@ -165,13 +157,13 @@ //! # } //! ``` //! -//! Of course, using `io::stdout()` directly is less common than something like -//! `println!`. +//! 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 +//! ways of iterating over I/O. For example, [`Lines`] is used to split over //! lines: //! //! ``` @@ -211,10 +203,10 @@ //! //! ## io::Result //! -//! Last, but certainly not least, is [`io::Result`][result]. This type is used +//! 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 [`try!`][try] macro: +//! module use the [`try!`] macro: //! //! ``` //! use std::io; @@ -230,14 +222,11 @@ //! } //! ``` //! -//! The return type of `read_input()`, `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 +//! 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 `()`. //! -//! [result]: type.Result.html -//! [try]: ../macro.try.html -//! //! ## Platform-specific behavior //! //! Many I/O functions throughout the standard library are documented to indicate @@ -246,6 +235,24 @@ //! 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()`]: trait.Write.html#tymethod.write +//! [`io::stdout()`]: fn.stdout.html +//! [`println!`]: ../macro.println.html +//! [`Lines`]: struct.Lines.html +//! [`io::Result`]: type.Result.html +//! [`try!`]: ../macro.try.html + +#![stable(feature = "rust1", since = "1.0.0")] use cmp; use std_unicode::str as core_str; @@ -255,17 +262,19 @@ use result; use str; use memchr; +#[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::print::{STDOUT, _print}; -//pub use self::stdio::{stdin, stdout, stderr, _print, Stdin, Stdout, Stderr}; -//pub use self::stdio::{StdoutLock, StderrLock, StdinLock}; -#[doc(no_inline, hidden)] -//pub use self::stdio::{set_panic, set_print}; pub mod prelude; mod buffered; @@ -275,10 +284,7 @@ mod impls; mod util; mod print; -//mod lazy; -//mod stdio; - -const DEFAULT_BUF_SIZE: usize = 8 * 1024; +const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; // 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 @@ -411,6 +417,7 @@ fn read_to_end(r: &mut R, buf: &mut Vec) -> Result /// # Ok(()) /// # } /// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -460,6 +467,7 @@ pub trait Read { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn read(&mut self, buf: &mut [u8]) -> Result; /// Read all bytes until EOF in this source, placing them into `buf`. @@ -501,6 +509,7 @@ pub trait Read { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn read_to_end(&mut self, buf: &mut Vec) -> Result { read_to_end(self, buf) } @@ -538,6 +547,7 @@ pub trait Read { /// # Ok(()) /// # } /// ``` + #[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` @@ -598,6 +608,7 @@ pub trait Read { /// # 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) { @@ -649,6 +660,7 @@ pub trait Read { /// # 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. @@ -678,6 +690,7 @@ pub trait Read { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn bytes(self) -> Bytes where Self: Sized { Bytes { inner: self } } @@ -714,6 +727,10 @@ pub trait Read { /// # Ok(()) /// # } /// ``` + #[unstable(feature = "io", reason = "the semantics of a partial read/write \ + of where errors happen is currently \ + unclear and may change", + issue = "27802")] fn chars(self) -> Chars where Self: Sized { Chars { inner: self } } @@ -748,6 +765,7 @@ pub trait Read { /// # 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 } } @@ -781,6 +799,7 @@ pub trait Read { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn take(self, limit: u64) -> Take where Self: Sized { Take { inner: self, limit: limit } } @@ -816,6 +835,7 @@ pub trait Read { /// # Ok(()) /// # } /// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub trait Write { /// Write a buffer into this object, returning how many bytes were written. /// @@ -855,6 +875,7 @@ pub trait Write { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn write(&mut self, buf: &[u8]) -> Result; /// Flush this output stream, ensuring that all intermediately buffered @@ -880,6 +901,7 @@ pub trait Write { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn flush(&mut self) -> Result<()>; /// Attempts to write an entire buffer into this write. @@ -906,6 +928,7 @@ pub trait Write { /// # 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) { @@ -957,6 +980,7 @@ pub trait Write { /// # 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 @@ -1012,6 +1036,7 @@ pub trait Write { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self where Self: Sized { self } } @@ -1041,6 +1066,7 @@ pub trait Write { /// # Ok(()) /// # } /// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub trait Seek { /// Seek to an offset, in bytes, in a stream. /// @@ -1056,6 +1082,7 @@ pub trait Seek { /// 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; } @@ -1065,23 +1092,27 @@ pub trait Seek { /// /// [`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. - Start(u64), + #[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. - End(i64), + #[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. - Current(i64), + #[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) @@ -1118,10 +1149,7 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) /// /// 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()`][readline] method as well as a [`lines()`][lines] iterator. -/// -/// [readline]: #method.read_line -/// [lines]: #method.lines +/// [`read_line()`] method as well as a [`lines()`] iterator. /// /// # Examples /// @@ -1137,14 +1165,17 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) /// } /// ``` /// -/// If you have something that implements `Read`, you can use the [`BufReader` -/// type][bufreader] to turn it into a `BufRead`. +/// If you have something that implements [`Read`], you can use the [`BufReader` +/// type][`BufReader`] to turn it into a `BufRead`. /// -/// For example, [`File`][file] implements `Read`, but not `BufRead`. -/// `BufReader` to the rescue! +/// For example, [`File`] implements [`Read`], but not `BufRead`. +/// [`BufReader`] to the rescue! /// -/// [bufreader]: struct.BufReader.html -/// [file]: ../fs/struct.File.html +/// [`BufReader`]: struct.BufReader.html +/// [`File`]: ../fs/struct.File.html +/// [`read_line()`]: #method.read_line +/// [`lines()`]: #method.lines +/// [`Read`]: trait.Read.html /// /// ``` /// use std::io::{self, BufReader}; @@ -1163,17 +1194,18 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) /// # } /// ``` /// +#[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`][consume] method to function properly. When calling this + /// [`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 + /// 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 + /// [`consume()`]: #tymethod.consume /// /// An empty buffer returned indicates that the stream has reached EOF. /// @@ -1207,43 +1239,43 @@ pub trait BufRead: Read { /// // 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`][fillbuf] method to function properly. This function does + /// [`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. - /// - /// [fillbuf]: #tymethod.fill_buf + /// 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`. + /// [`fill_buf()`]. /// /// # Examples /// - /// Since `consume()` is meant to be used with [`fill_buf()`][fillbuf], + /// 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` is reached. + /// 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 this reader is currently at EOF then this function will not modify - /// `buf` and will return `Ok(n)` where `n` is the number of bytes which - /// were read. + /// 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`. + /// 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. @@ -1253,6 +1285,9 @@ pub trait BufRead: Read { /// A locked standard input implements `BufRead`. In this example, we'll /// read from standard input until we see an `a` byte. /// + /// [`fill_buf()`]: #tymethod.fill_buf + /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted + /// /// ``` /// use std::io; /// use std::io::prelude::*; @@ -1268,6 +1303,7 @@ pub trait BufRead: Read { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { read_until(self, byte, buf) } @@ -1280,25 +1316,24 @@ pub trait BufRead: Read { /// up to, and including, the delimiter (if found) will be appended to /// `buf`. /// - /// If this reader is currently at EOF then this function will not modify - /// `buf` and will return `Ok(n)` where `n` is the number of bytes which - /// were read. + /// If successful, this function will return the total number of bytes read. /// /// # 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. + /// 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. /// /// # Examples /// /// A locked standard input implements `BufRead`. In this example, we'll /// read all of the lines from standard input. If we were to do this in - /// an actual project, the [`lines()`][lines] method would be easier, of + /// an actual project, the [`lines()`] method would be easier, of /// course. /// - /// [lines]: #method.lines + /// [`lines()`]: #method.lines + /// [`read_until()`]: #method.read_until /// /// ``` /// use std::io; @@ -1315,6 +1350,7 @@ pub trait BufRead: Read { /// buffer.clear(); /// } /// ``` + #[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 @@ -1326,17 +1362,21 @@ pub trait BufRead: Read { /// `byte`. /// /// The iterator returned from this function will return instances of - /// `io::Result>`. Each vector returned will *not* have the - /// delimiter byte at the end. + /// [`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. + /// This function will yield errors whenever [`read_until()`] would have + /// also yielded an error. /// /// # Examples /// /// A locked standard input implements `BufRead`. In this example, we'll /// read some input from standard input, splitting on commas. /// + /// [`io::Result`]: type.Result.html + /// [`Vec`]: ../vec/struct.Vec.html + /// [`read_until()`]: #method.read_until + /// /// ``` /// use std::io; /// use std::io::prelude::*; @@ -1347,6 +1387,7 @@ pub trait BufRead: Read { /// println!("{:?}", content.unwrap()); /// } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn split(self, byte: u8) -> Split where Self: Sized { Split { buf: self, delim: byte } } @@ -1354,9 +1395,12 @@ pub trait BufRead: Read { /// Returns an iterator over the lines of this reader. /// /// The iterator returned from this function will yield instances of - /// `io::Result`. Each string returned will *not* have a newline + /// [`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 /// /// A locked standard input implements `BufRead`: @@ -1371,6 +1415,7 @@ pub trait BufRead: Read { /// println!("{}", line.unwrap()); /// } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] fn lines(self) -> Lines where Self: Sized { Lines { buf: self } } @@ -1378,21 +1423,23 @@ pub trait BufRead: Read { /// Adaptor to chain together two readers. /// -/// This struct is generally created by calling [`chain()`][chain] on a reader. -/// Please see the documentation of `chain()` for more details. +/// 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 +/// [`chain()`]: trait.Read.html#method.chain +#[stable(feature = "rust1", since = "1.0.0")] pub struct Chain { first: T, second: U, done_first: bool, } +#[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 => { self.done_first = true; } + 0 if buf.len() != 0 => { self.done_first = true; } n => return Ok(n), } } @@ -1400,6 +1447,7 @@ impl Read for Chain { } } +#[stable(feature = "chain_bufread", since = "1.9.0")] impl BufRead for Chain { fn fill_buf(&mut self) -> Result<&[u8]> { if !self.done_first { @@ -1426,6 +1474,7 @@ impl BufRead for Chain { /// Please see the documentation of `take()` for more details. /// /// [take]: trait.Read.html#method.take +#[stable(feature = "rust1", since = "1.0.0")] pub struct Take { inner: T, limit: u64, @@ -1457,9 +1506,38 @@ impl Take { /// # Ok(()) /// # } /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn limit(&self) -> u64 { self.limit } + + /// Consumes the `Take`, returning the wrapped reader. + /// + /// # Examples + /// + /// ``` + /// #![feature(io_take_into_inner)] + /// + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut file = try!(File::open("foo.txt")); + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// try!(handle.read(&mut buffer)); + /// + /// let file = handle.into_inner(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "io_take_into_inner", issue = "23755")] + pub fn into_inner(self) -> T { + 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 @@ -1474,6 +1552,7 @@ impl Read for Take { } } +#[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 @@ -1508,14 +1587,16 @@ fn read_one_byte(reader: &mut Read) -> Option> { /// An iterator over `u8` values of a reader. /// -/// This struct is generally created by calling [`bytes()`][bytes] on a reader. -/// Please see the documentation of `bytes()` for more details. +/// 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 +/// [`bytes()`]: trait.Read.html#method.bytes +#[stable(feature = "rust1", since = "1.0.0")] pub struct Bytes { inner: R, } +#[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Bytes { type Item = Result; @@ -1530,6 +1611,8 @@ impl Iterator for Bytes { /// Please see the documentation of `chars()` for more details. /// /// [chars]: trait.Read.html#method.chars +#[unstable(feature = "io", reason = "awaiting stability of Read::chars", + issue = "27802")] pub struct Chars { inner: R, } @@ -1537,6 +1620,8 @@ pub struct Chars { /// An enumeration of possible errors that can be generated from the `Chars` /// adapter. #[derive(Debug)] +#[unstable(feature = "io", reason = "awaiting stability of Read::chars", + issue = "27802")] pub enum CharsError { /// Variant representing that the underlying stream was read successfully /// but it did not contain valid utf8 data. @@ -1546,6 +1631,8 @@ pub enum CharsError { Other(Error), } +#[unstable(feature = "io", reason = "awaiting stability of Read::chars", + issue = "27802")] impl Iterator for Chars { type Item = result::Result; @@ -1577,6 +1664,8 @@ impl Iterator for Chars { } } +#[unstable(feature = "io", reason = "awaiting stability of Read::chars", + issue = "27802")] impl std_error::Error for CharsError { fn description(&self) -> &str { match *self { @@ -1592,6 +1681,8 @@ impl std_error::Error for CharsError { } } +#[unstable(feature = "io", reason = "awaiting stability of Read::chars", + issue = "27802")] impl fmt::Display for CharsError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -1610,11 +1701,13 @@ impl fmt::Display for CharsError { /// `BufRead`. Please see the documentation of `split()` for more details. /// /// [split]: trait.BufRead.html#method.split +#[stable(feature = "rust1", since = "1.0.0")] pub struct Split { buf: B, delim: u8, } +#[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Split { type Item = Result>; @@ -1639,10 +1732,12 @@ impl Iterator for Split { /// `BufRead`. Please see the documentation of `lines()` for more details. /// /// [lines]: trait.BufRead.html#method.lines +#[stable(feature = "rust1", since = "1.0.0")] pub struct Lines { buf: B, } +#[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Lines { type Item = Result; @@ -1669,13 +1764,11 @@ mod tests { use io::prelude::*; use io; use super::Cursor; - use super::repeat; use test; - - use collections::{Vec, String}; - use collections::string::ToString; + 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(); @@ -1874,7 +1967,19 @@ mod tests { 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); diff --git a/std/src/io/prelude.rs b/ctr-std/src/io/prelude.rs similarity index 89% rename from std/src/io/prelude.rs rename to ctr-std/src/io/prelude.rs index 8f209e5..8772d0f 100644 --- a/std/src/io/prelude.rs +++ b/ctr-std/src/io/prelude.rs @@ -18,5 +18,7 @@ //! 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/std/src/io/print.rs b/ctr-std/src/io/print.rs similarity index 94% rename from std/src/io/print.rs rename to ctr-std/src/io/print.rs index 2940f35..8a5851b 100644 --- a/std/src/io/print.rs +++ b/ctr-std/src/io/print.rs @@ -4,12 +4,13 @@ use io::{self, Write}; // NOTE: We're just gonna use the spin mutex until we figure out how to properly // implement mutexes with ctrulib functions use spin::Mutex; -use libctru::libc; +use libc; pub static STDOUT: Mutex = Mutex::new(StdoutRaw(())); pub struct StdoutRaw(()); +#[stable(feature = "3ds", since = "1.0.0")] impl Write for StdoutRaw { fn write(&mut self, buf: &[u8]) -> io::Result { unsafe { diff --git a/std/src/io/util.rs b/ctr-std/src/io/util.rs similarity index 92% rename from std/src/io/util.rs rename to ctr-std/src/io/util.rs index 1bcc5a6..2c68802 100644 --- a/std/src/io/util.rs +++ b/ctr-std/src/io/util.rs @@ -42,6 +42,7 @@ use io::{self, Read, Write, ErrorKind, BufRead}; /// # Ok(()) /// # } /// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub fn copy(reader: &mut R, writer: &mut W) -> io::Result where R: Read, W: Write { @@ -65,6 +66,7 @@ pub fn copy(reader: &mut R, writer: &mut W) -> io::Result< /// the documentation of `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. @@ -82,11 +84,14 @@ pub struct Empty { _priv: () } /// 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 { fn read(&mut self, _buf: &mut [u8]) -> io::Result { Ok(0) } } +#[stable(feature = "rust1", since = "1.0.0")] impl BufRead for Empty { fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) } fn consume(&mut self, _n: usize) {} @@ -98,6 +103,7 @@ impl BufRead for Empty { /// 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. @@ -114,8 +120,10 @@ pub struct Repeat { byte: u8 } /// 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 { fn read(&mut self, buf: &mut [u8]) -> io::Result { for slot in &mut *buf { @@ -131,6 +139,7 @@ impl Read for Repeat { /// 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. @@ -147,8 +156,10 @@ pub struct Sink { _priv: () } /// 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 { fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } diff --git a/ctr-std/src/lib.rs b/ctr-std/src/lib.rs new file mode 100644 index 0000000..b43e108 --- /dev/null +++ b/ctr-std/src/lib.rs @@ -0,0 +1,174 @@ +#![feature(alloc)] +#![feature(allow_internal_unstable)] +#![feature(box_syntax)] +#![feature(collections)] +#![feature(const_fn)] +#![feature(compiler_builtins_lib)] +#![feature(core_intrinsics)] +#![feature(char_escape_debug)] +#![feature(float_extras)] +#![feature(fused)] +#![feature(int_error_internals)] +#![feature(lang_items)] +#![feature(macro_reexport)] +#![feature(optin_builtin_traits)] +#![feature(prelude_import)] +#![feature(raw)] +#![feature(slice_concat_ext)] +#![feature(slice_patterns)] +#![feature(staged_api)] +#![feature(str_internals)] +#![feature(thread_local)] +#![feature(try_from)] +#![feature(unicode)] +#![feature(zero_one)] +#![allow(non_camel_case_types, dead_code, unused_features)] +#![no_std] + +#![stable(feature = "rust1", since = "1.0.0")] + +#[prelude_import] +#[allow(unused)] +use prelude::v1::*; + +#[macro_reexport(assert, assert_eq, debug_assert, debug_assert_eq, + unreachable, unimplemented, write, writeln, try)] +extern crate core as __core; + +#[macro_use] +#[macro_reexport(vec, format)] +extern crate collections as core_collections; + +extern crate alloc; +extern crate std_unicode; +extern crate alloc_system; + +// compiler-rt intrinsics +extern crate compiler_builtins; + +// 3ds-specific dependencies +extern crate ctr_libc as libc; + +// stealing spin's mutex implementation for now +extern crate spin; + +// 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 reexports +#[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 = "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::boxed; +#[stable(feature = "rust1", since = "1.0.0")] +pub use alloc::rc; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::borrow; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::fmt; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::slice; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::str; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::string; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::vec; +#[stable(feature = "rust1", since = "1.0.0")] +pub use std_unicode::char; + +pub mod f32; +pub mod f64; + +pub mod ascii; +pub mod error; +pub mod ffi; +pub mod io; +pub mod num; +pub mod os; +pub mod path; +pub mod sync; + +// Platform-abstraction modules +#[macro_use] +mod sys_common; +mod sys; + +// Private support modules +mod panicking; +mod memchr; + +// The runtime entry point and a few unstable public functions used by the +// compiler +pub mod rt; + +// NOTE: These two are "undefined" symbols that LLVM emits but that +// we never actually use +#[doc(hidden)] + +#[stable(feature = "3ds", since = "1.0.0")] +#[no_mangle] +pub unsafe extern "C" fn __aeabi_unwind_cpp_pr0() { + intrinsics::unreachable() +} + +#[stable(feature = "3ds", since = "1.0.0")] +#[doc(hidden)] +#[no_mangle] +pub unsafe extern "C" fn __aeabi_unwind_cpp_pr1() { + intrinsics::unreachable() +} diff --git a/ctr-std/src/macros.rs b/ctr-std/src/macros.rs new file mode 100644 index 0000000..0ce6b0a --- /dev/null +++ b/ctr-std/src/macros.rs @@ -0,0 +1,481 @@ +// 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 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. +/// +/// The multi-argument form of this macro panics with a string and has the +/// `format!` syntax for building a string. +/// +/// # 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, { + // static requires less code at runtime, more constant data + static _FILE_LINE: (&'static str, u32) = (file!(), line!()); + &_FILE_LINE + }) + }); + ($fmt:expr, $($arg:tt)+) => ({ + $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), { + // The leading _'s are to avoid dead code warnings if this is + // used inside a dead function. Just `#[allow(dead_code)]` is + // insufficient, since the user may have + // `#[forbid(dead_code)]` and which cannot be overridden. + static _FILE_LINE: (&'static str, u32) = (file!(), line!()); + &_FILE_LINE + }) + }); +} + +/// 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()` to ensure the output is emitted +/// immediately. +/// +/// # 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. +/// +/// # Panics +/// +/// Panics if writing to `io::stdout()` fails. +/// +/// # Examples +/// +/// ``` +/// println!(); +/// println!("hello there!"); +/// println!("format {} arguments", "some"); +/// ``` +#[macro_export] +#[stable(feature = "rust1", since = "1.0.0")] +macro_rules! println { + () => (print!("\n")); + ($fmt:expr) => (print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); +} + +/// 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)] +pub mod builtin { + /// The core macro for formatted string creation & output. + /// + /// This macro produces a value of type [`fmt::Arguments`]. This value can be + /// passed to the functions in [`std::fmt`] for performing useful functions. + /// All other formatting macros ([`format!`], [`write!`], [`println!`], etc) are + /// proxied through this one. + /// + /// For more information, see the documentation in [`std::fmt`]. + /// + /// [`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")] + #[macro_export] + macro_rules! format_args { ($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. + /// + /// # Examples + /// + /// ``` + /// let path: &'static str = env!("PATH"); + /// println!("the $PATH variable at the time of compiling was: {}", path); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + macro_rules! env { ($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`. + /// + /// A compile time error is never emitted when using this macro regardless + /// of whether the environment variable is present or not. + /// + /// # Examples + /// + /// ``` + /// let key: Option<&'static str> = option_env!("SECRET_KEY"); + /// println!("the secret key might be: {:?}", key); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + macro_rules! option_env { ($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")] + #[macro_export] + macro_rules! concat_idents { + ($($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")] + #[macro_export] + macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }) } + + /// A macro which expands to the line number on which it was invoked. + /// + /// The expanded expression has type `u32`, and the returned line is not + /// the invocation of the `line!()` macro itself, but rather the first macro + /// invocation leading up to the invocation of the `line!()` macro. + /// + /// # Examples + /// + /// ``` + /// let current_line = line!(); + /// println!("defined on line: {}", current_line); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + macro_rules! line { () => ({ /* compiler built-in */ }) } + + /// A macro which expands to the column number on which it was invoked. + /// + /// The expanded expression has type `u32`, and the returned column is not + /// the invocation of the `column!()` macro itself, but rather the first macro + /// invocation leading up to the invocation of the `column!()` macro. + /// + /// # Examples + /// + /// ``` + /// let current_col = column!(); + /// println!("defined on column: {}", current_col); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + macro_rules! column { () => ({ /* compiler built-in */ }) } + + /// A macro which expands to the file name from which it was invoked. + /// + /// 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. + /// + /// # Examples + /// + /// ``` + /// let this_file = file!(); + /// println!("defined in file: {}", this_file); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + macro_rules! file { () => ({ /* compiler built-in */ }) } + + /// A macro which stringifies its argument. + /// + /// 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")] + #[macro_export] + 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 + /// + /// ```rust,ignore + /// let secret_key = include_str!("secret-key.ascii"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + macro_rules! include_str { ($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 + /// + /// ```rust,ignore + /// let secret_key = include_bytes!("secret-key.bin"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + macro_rules! include_bytes { ($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")] + #[macro_export] + macro_rules! module_path { () => ({ /* compiler built-in */ }) } + + /// Boolean evaluation of configuration flags. + /// + /// 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](../reference.html#conditional-compilation). + /// + /// # Examples + /// + /// ``` + /// let my_directory = if cfg!(windows) { + /// "windows-specific-directory" + /// } else { + /// "unix-directory" + /// }; + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + 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 unhygenically. 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 + /// + /// ```ignore + /// fn foo() { + /// include!("/path/to/a/file") + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } +} diff --git a/ctr-std/src/memchr.rs b/ctr-std/src/memchr.rs new file mode 100644 index 0000000..7c8c97a --- /dev/null +++ b/ctr-std/src/memchr.rs @@ -0,0 +1,143 @@ +// 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.) +/// +/// # Example +/// +/// This shows how to find the first position of a byte in a byte string. +/// +/// ```rust,ignore +/// 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. +/// +/// # Example +/// +/// This shows how to find the last position of a byte in a byte string. +/// +/// ```rust,ignore +/// 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/std/src/num/mod.rs b/ctr-std/src/num.rs similarity index 89% rename from std/src/num/mod.rs rename to ctr-std/src/num.rs index 1aa23b8..d1c2fc3 100644 --- a/std/src/num/mod.rs +++ b/ctr-std/src/num.rs @@ -13,17 +13,19 @@ //! 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")] #[allow(deprecated)] pub use core::num::{Zero, One}; +#[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; -#[cfg(test)] -use fmt; -#[cfg(test)] -use ops::{Add, Sub, Mul, Div, Rem}; +#[cfg(test)] use fmt; +#[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; /// Helper function for testing numeric operations #[cfg(test)] @@ -34,11 +36,11 @@ pub fn test_num(ten: T, two: T) where + 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); + 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)] @@ -54,9 +56,9 @@ mod tests { 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!(3_usize.saturating_add(MAX-1), MAX); assert_eq!(MAX.saturating_add(MAX), MAX); - assert_eq!((MAX - 2).saturating_add(1), MAX - 1); + assert_eq!((MAX-2).saturating_add(1), MAX-1); } #[test] @@ -65,16 +67,16 @@ mod tests { 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); + assert_eq!((MAX-1).saturating_sub(MAX), 0); } #[test] fn test_saturating_add_int() { - use isize::{MIN, MAX}; + use isize::{MIN,MAX}; assert_eq!(3i32.saturating_add(5), 8); - assert_eq!(3isize.saturating_add(MAX - 1), MAX); + 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!((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); @@ -82,14 +84,14 @@ mod tests { #[test] fn test_saturating_sub_int() { - use isize::{MIN, MAX}; + 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!(3isize.saturating_sub(-(MAX-1)), MAX); assert_eq!(MAX.saturating_sub(-MAX), MAX); - assert_eq!((MAX - 2).saturating_sub(-1), MAX - 1); + assert_eq!((MAX-2).saturating_sub(-1), MAX-1); } #[test] @@ -193,7 +195,7 @@ mod tests { #[test] fn test_pow() { - fn naive_pow + Copy>(one: T, base: T, exp: usize) -> T { + fn naive_pow + Copy>(one: T, base: T, exp: usize) -> T { (0..exp).fold(one, |acc, _| acc * base) } macro_rules! assert_pow { @@ -286,8 +288,6 @@ mod bench { #[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)); - }); + b.iter(|| {v.iter().fold(0u32, |old, new| old.pow(*new as u32));}); } } diff --git a/ctr-std/src/os/mod.rs b/ctr-std/src/os/mod.rs new file mode 100644 index 0000000..bd05ac3 --- /dev/null +++ b/ctr-std/src/os/mod.rs @@ -0,0 +1,17 @@ +// 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)] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use sys::ext as unix; diff --git a/std/src/panicking.rs b/ctr-std/src/panicking.rs similarity index 87% rename from std/src/panicking.rs rename to ctr-std/src/panicking.rs index b02dd4f..2b5a178 100644 --- a/std/src/panicking.rs +++ b/ctr-std/src/panicking.rs @@ -11,8 +11,9 @@ //! Implementation of various bits and pieces of the `panic!` macro and //! associated runtime pieces. -use fmt::{self, Display}; use any::Any; +use fmt; +use __core::fmt::Display; ///The compiler wants this to be here. Otherwise it won't be happy. And we like happy compilers. #[lang = "eh_personality"] @@ -20,7 +21,7 @@ extern fn eh_personality() {} /// Entry point of panic from the libcore crate. #[lang = "panic_fmt"] -extern fn panic_fmt(msg: fmt::Arguments, file: &'static str, line: u32) -> ! { +extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u32) -> ! { begin_panic_fmt(&msg, &(file, line)) } @@ -30,8 +31,10 @@ extern fn panic_fmt(msg: fmt::Arguments, file: &'static str, line: u32) -> ! { /// 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. -#[inline(never)] -#[cold] +#[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: &(&'static str, u32)) -> ! { use fmt::Write; diff --git a/std/src/path.rs b/ctr-std/src/path.rs similarity index 85% rename from std/src/path.rs rename to ctr-std/src/path.rs index 428296f..92c561f 100644 --- a/std/src/path.rs +++ b/ctr-std/src/path.rs @@ -97,21 +97,23 @@ //! normalization is possible to build on top of the components APIs, //! and will be included in this library in the near future. +#![stable(feature = "rust1", since = "1.0.0")] + use ascii::*; -use borrow::{Borrow, ToOwned, Cow}; +use borrow::{Borrow, Cow}; use cmp; -//use error::Error; +use error::Error; use fmt; //use fs; use hash::{Hash, Hasher}; //use io; +use iter::{self, FusedIterator}; use mem; use ops::{self, Deref}; -use iter; use ffi::{OsStr, OsString}; -use self::platform::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; +use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; //////////////////////////////////////////////////////////////////////////////// // GENERAL NOTES @@ -123,35 +125,6 @@ use self::platform::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; // OsStr APIs for parsing, but it will take a while for those to become // available. -//////////////////////////////////////////////////////////////////////////////// -// Platform-specific definitions -//////////////////////////////////////////////////////////////////////////////// - -// The following modules give the most basic tools for parsing paths on various -// platforms. The bulk of the code is devoted to parsing prefixes on Windows. - -mod platform { - use super::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 = '/'; -} - //////////////////////////////////////////////////////////////////////////////// // Windows Prefixes //////////////////////////////////////////////////////////////////////////////// @@ -164,29 +137,37 @@ mod platform { /// `/` is *not* treated as a separator and essentially no normalization is /// performed. #[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] +#[stable(feature = "rust1", since = "1.0.0")] pub enum Prefix<'a> { /// Prefix `\\?\`, together with the given component immediately following it. - Verbatim(&'a OsStr), + #[stable(feature = "rust1", since = "1.0.0")] + Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), + /// Prefix `\\?\UNC\`, with the "server" and "share" components following it. + #[stable(feature = "rust1", since = "1.0.0")] VerbatimUNC( - &'a OsStr, - &'a OsStr, + #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, + #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, ), /// Prefix like `\\?\C:\`, for the given drive letter - VerbatimDisk(u8), + #[stable(feature = "rust1", since = "1.0.0")] + VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8), /// Prefix `\\.\`, together with the given component immediately following it. - DeviceNS(&'a OsStr), + #[stable(feature = "rust1", since = "1.0.0")] + DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), /// Prefix `\\server\share`, with the given "server" and "share" components. + #[stable(feature = "rust1", since = "1.0.0")] UNC( - &'a OsStr, - &'a OsStr, + #[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. - Disk(u8), + #[stable(feature = "rust1", since = "1.0.0")] + Disk(#[stable(feature = "rust1", since = "1.0.0")] u8), } impl<'a> Prefix<'a> { @@ -223,10 +204,11 @@ impl<'a> Prefix<'a> { /// Determines if the prefix is verbatim, i.e. begins with `\\?\`. #[inline] + #[stable(feature = "rust1", since = "1.0.0")] pub fn is_verbatim(&self) -> bool { use self::Prefix::*; match *self { - Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(_, _) => true, + Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..) => true, _ => false, } } @@ -260,12 +242,14 @@ impl<'a> Prefix<'a> { /// assert!(path::is_separator('/')); /// 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 for the current platform -pub const MAIN_SEPARATOR: char = platform::MAIN_SEP; +#[stable(feature = "rust1", since = "1.0.0")] +pub const MAIN_SEPARATOR: char = ::sys::path::MAIN_SEP; //////////////////////////////////////////////////////////////////////////////// // Misc helpers @@ -359,6 +343,7 @@ enum State { /// A Windows path prefix, e.g. `C:` or `\\server\share`. /// /// Does not occur on Unix. +#[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Eq, Debug)] pub struct PrefixComponent<'a> { /// The prefix as an unparsed `OsStr` slice. @@ -370,34 +355,40 @@ pub struct PrefixComponent<'a> { impl<'a> PrefixComponent<'a> { /// The parsed prefix data. + #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> Prefix<'a> { self.parsed } /// The raw `OsStr` slice for this prefix. + #[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); @@ -429,29 +420,36 @@ impl<'a> Hash for PrefixComponent<'a> { /// /// [`path::Components`]: struct.Components.html #[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`. /// /// Does not occur on Unix. + #[stable(feature = "rust1", since = "1.0.0")] Prefix( - PrefixComponent<'a> + #[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a> ), /// The root directory component, appears after any prefix and before anything else + #[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, i.e. `a` and `b` in `a/b` - Normal(&'a OsStr), + #[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 + #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(self) -> &'a OsStr { match self { Component::Prefix(p) => p.as_os_str(), @@ -463,6 +461,7 @@ impl<'a> Component<'a> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> AsRef for Component<'a> { fn as_ref(&self) -> &OsStr { self.as_os_str() @@ -490,6 +489,7 @@ impl<'a> AsRef for Component<'a> { /// /// [`path::Path::components`]: struct.Path.html#method.components #[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] pub struct Components<'a> { // The path left to parse components from path: &'a [u8], @@ -510,10 +510,30 @@ pub struct Components<'a> { /// An iterator over the components of a path, as `OsStr` slices. #[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] @@ -580,6 +600,7 @@ impl<'a> Components<'a> { /// /// 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 { @@ -678,37 +699,62 @@ impl<'a> Components<'a> { } } +#[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. + #[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; @@ -717,12 +763,17 @@ impl<'a> Iterator for Iter<'a> { } } +#[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) } } +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for Iter<'a> {} + +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> Iterator for Components<'a> { type Item = Component<'a>; @@ -775,6 +826,7 @@ impl<'a> Iterator for Components<'a> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> DoubleEndedIterator for Components<'a> { fn next_back(&mut self) -> Option> { while !self.finished() { @@ -821,20 +873,27 @@ impl<'a> DoubleEndedIterator for Components<'a> { } } +#[unstable(feature = "fused", issue = "35602")] +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()) @@ -845,11 +904,17 @@ impl<'a> cmp::Ord for Components<'a> { // Basic types and traits //////////////////////////////////////////////////////////////////////////////// -/// An owned, mutable path (akin to `String`). +/// 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. /// -/// 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. @@ -865,6 +930,7 @@ impl<'a> cmp::Ord for Components<'a> { /// path.set_extension("dll"); /// ``` #[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] pub struct PathBuf { inner: OsString, } @@ -875,11 +941,32 @@ impl PathBuf { } /// 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. + /// 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 } @@ -908,6 +995,7 @@ impl PathBuf { /// path.push("/etc/passwd"); /// assert_eq!(path, PathBuf::from("/etc/passwd")); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn push>(&mut self, path: P) { self._push(path.as_ref()) } @@ -942,10 +1030,27 @@ impl PathBuf { self.inner.push(path); } - /// Truncate `self` to `self.parent()`. + /// Truncate `self` to [`self.parent()`]. /// - /// Returns false and does nothing if `self.file_name()` is `None`. + /// Returns false and does nothing if [`self.file_name()`] is `None`. /// Otherwise, returns `true`. + /// + /// [`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) => { @@ -956,11 +1061,13 @@ impl PathBuf { } } - /// Updates `self.file_name()` to `file_name`. + /// Updates [`self.file_name()`] to `file_name`. /// - /// If `self.file_name()` was `None`, this is equivalent to pushing + /// If [`self.file_name()`] was `None`, this is equivalent to pushing /// `file_name`. /// + /// [`self.file_name()`]: struct.PathBuf.html#method.file_name + /// /// # Examples /// /// ``` @@ -974,6 +1081,7 @@ impl PathBuf { /// 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()) } @@ -986,12 +1094,30 @@ impl PathBuf { self.push(file_name); } - /// Updates `self.extension()` to `extension`. + /// Updates [`self.extension()`] to `extension`. + /// + /// If [`self.file_name()`] is `None`, does nothing and returns `false`. + /// + /// Otherwise, returns `true`; 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 + /// + /// # Examples + /// + /// ``` + /// use std::path::{Path, PathBuf}; /// - /// If `self.file_name()` is `None`, does nothing and returns `false`. + /// let mut p = PathBuf::from("/feel/the"); /// - /// Otherwise, returns `true`; if `self.extension()` is `None`, the extension - /// is added; otherwise it is replaced. + /// 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()) } @@ -1015,30 +1141,53 @@ impl PathBuf { true } - /// Consumes the `PathBuf`, yielding its internal `OsString` storage. + /// 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 } } +#[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(); @@ -1047,6 +1196,7 @@ impl> iter::FromIterator

for PathBuf { } } +#[stable(feature = "rust1", since = "1.0.0")] impl> iter::Extend

for PathBuf { fn extend>(&mut self, iter: I) { for p in iter { @@ -1055,12 +1205,14 @@ impl> iter::Extend

for PathBuf { } } +#[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for PathBuf { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fmt::Debug::fmt(&**self, formatter) } } +#[stable(feature = "rust1", since = "1.0.0")] impl ops::Deref for PathBuf { type Target = Path; @@ -1069,12 +1221,14 @@ impl ops::Deref for PathBuf { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Borrow for PathBuf { fn borrow(&self) -> &Path { self.deref() } } +#[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> { @@ -1082,6 +1236,7 @@ impl<'a> From<&'a Path> for Cow<'a, Path> { } } +#[stable(feature = "cow_from_path", since = "1.6.0")] impl<'a> From for Cow<'a, Path> { #[inline] fn from(s: PathBuf) -> Cow<'a, Path> { @@ -1089,6 +1244,7 @@ impl<'a> From for Cow<'a, Path> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for Path { type Owned = PathBuf; fn to_owned(&self) -> PathBuf { @@ -1096,54 +1252,61 @@ impl ToOwned for Path { } } +#[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[..] } } -impl Into for PathBuf { - fn into(self) -> OsString { - self.inner - } -} - -/// A slice of a path (akin to `str`). +/// 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 `/` or `\`, depending on /// the platform), extracting the file name, determining whether the path is -/// absolute, and so on. More details about the overall approach can be found in -/// the module documentation. +/// absolute, and so on. /// /// This is an *unsized* type, meaning that it must always be used behind a -/// pointer like `&` or `Box`. +/// 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. /// /// # Examples /// @@ -1156,6 +1319,7 @@ impl Into for PathBuf { /// let parent_dir = path.parent(); /// ``` /// +#[stable(feature = "rust1", since = "1.0.0")] pub struct Path { inner: OsStr, } @@ -1163,6 +1327,7 @@ pub struct Path { /// An error returned from the `Path::strip_prefix` method indicating that the /// prefix was not found in `self`. #[derive(Debug, Clone, PartialEq, Eq)] +#[stable(since = "1.7.0", feature = "strip_prefix")] pub struct StripPrefixError(()); impl Path { @@ -1198,11 +1363,14 @@ impl Path { /// 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 { mem::transmute(s.as_ref()) } } - /// Yields the underlying `OsStr` slice. + /// Yields the underlying [`OsStr`] slice. + /// + /// [`OsStr`]: ../ffi/struct.OsStr.html /// /// # Examples /// @@ -1212,14 +1380,17 @@ impl 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. + /// 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 /// /// ``` @@ -1228,14 +1399,17 @@ impl Path { /// let path_str = Path::new("foo.txt").to_str(); /// assert_eq!(path_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`. + /// Converts a `Path` to a [`Cow`]. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. /// + /// [`Cow`]: ../borrow/enum.Cow.html + /// /// # Examples /// /// ``` @@ -1244,11 +1418,14 @@ impl Path { /// let path_str = Path::new("foo.txt").to_string_lossy(); /// assert_eq!(path_str, "foo.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`. + /// Converts a `Path` to an owned [`PathBuf`]. + /// + /// [`PathBuf`]: struct.PathBuf.html /// /// # Examples /// @@ -1258,6 +1435,7 @@ impl Path { /// let path_buf = Path::new("foo.txt").to_path_buf(); /// assert_eq!(path_buf, std::path::PathBuf::from("foo.txt")); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn to_path_buf(&self) -> PathBuf { PathBuf::from(self.inner.to_os_string()) } @@ -1277,6 +1455,7 @@ impl Path { /// /// assert!(!Path::new("foo.txt").is_absolute()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] pub fn is_absolute(&self) -> bool { self.has_root() && (cfg!(unix) || self.prefix().is_some()) @@ -1291,6 +1470,7 @@ impl Path { /// /// assert!(Path::new("foo.txt").is_relative()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn is_relative(&self) -> bool { !self.is_absolute() } @@ -1315,6 +1495,7 @@ impl 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() } @@ -1336,6 +1517,7 @@ impl Path { /// 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(); @@ -1375,6 +1557,7 @@ impl Path { /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name()); /// assert_eq!(None, Path::new("foo.txt/..").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 { @@ -1390,6 +1573,19 @@ impl Path { /// /// If `base` is not a prefix of `self` (i.e. `starts_with` /// returns `false`), returns `Err`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/test/haha/foo.txt"); + /// + /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt"))); + /// assert_eq!(path.strip_prefix("test").is_ok(), false); + /// assert_eq!(path.strip_prefix("/haha").is_ok(), false); + /// ``` + #[stable(since = "1.7.0", feature = "path_strip_prefix")] pub fn strip_prefix<'a, P: ?Sized>(&'a self, base: &'a P) -> Result<&'a Path, StripPrefixError> where P: AsRef @@ -1419,6 +1615,7 @@ impl Path { /// /// 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()) } @@ -1440,6 +1637,7 @@ impl Path { /// /// 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()) } @@ -1448,7 +1646,9 @@ impl Path { iter_after(self.components().rev(), child.components().rev()).is_some() } - /// Extracts the stem (non-extension) portion of `self.file_name()`. + /// Extracts the stem (non-extension) portion of [`self.file_name()`]. + /// + /// [`self.file_name()`]: struct.Path.html#method.file_name /// /// The stem is: /// @@ -1466,11 +1666,14 @@ impl Path { /// /// 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. + /// Extracts the extension of [`self.file_name()`], if possible. + /// + /// [`self.file_name()`]: struct.Path.html#method.file_name /// /// The extension is: /// @@ -1488,13 +1691,17 @@ impl Path { /// /// 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`. + /// Creates an owned [`PathBuf`] with `path` adjoined to `self`. + /// + /// See [`PathBuf::push`] for more details on what it means to adjoin a path. /// - /// 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 /// @@ -1503,6 +1710,7 @@ impl Path { /// /// 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()) } @@ -1513,9 +1721,12 @@ impl Path { buf } - /// Creates an owned `PathBuf` like `self` but with the given file name. + /// Creates an owned [`PathBuf`] like `self` but with the given file name. + /// + /// See [`PathBuf::set_file_name`] for more details. /// - /// See `PathBuf::set_file_name` for more details. + /// [`PathBuf`]: struct.PathBuf.html + /// [`PathBuf::set_file_name`]: struct.PathBuf.html#method.set_file_name /// /// # Examples /// @@ -1525,6 +1736,7 @@ impl Path { /// let path = Path::new("/tmp/foo.txt"); /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt")); /// ``` + #[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()) } @@ -1535,9 +1747,12 @@ impl Path { buf } - /// Creates an owned `PathBuf` like `self` but with the given extension. + /// Creates an owned [`PathBuf`] like `self` but with the given extension. /// - /// See `PathBuf::set_extension` for more details. + /// See [`PathBuf::set_extension`] for more details. + /// + /// [`PathBuf`]: struct.PathBuf.html + /// [`PathBuf::set_extension`]: struct.PathBuf.html#method.set_extension /// /// # Examples /// @@ -1547,6 +1762,7 @@ impl Path { /// 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()) } @@ -1572,6 +1788,7 @@ impl Path { /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt")))); /// assert_eq!(components.next(), None) /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn components(&self) -> Components { let prefix = parse_prefix(self.as_os_str()); Components { @@ -1583,7 +1800,9 @@ impl Path { } } - /// Produce an iterator over the path's components viewed as `OsStr` slices. + /// Produce an iterator over the path's components viewed as [`OsStr`] slices. + /// + /// [`OsStr`]: ../ffi/struct.OsStr.html /// /// # Examples /// @@ -1597,13 +1816,16 @@ impl Path { /// 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 + /// Returns an object that implements [`Display`] for safely printing paths /// that may contain non-Unicode data. /// + /// [`Display`]: ../fmt/trait.Display.html + /// /// # Examples /// /// ``` @@ -1613,16 +1835,12 @@ impl Path { /// /// println!("{}", path.display()); /// ``` + #[stable(feature = "rust1", since = "1.0.0")] pub fn display(&self) -> Display { Display { path: self } } - //NOTE: The following functions rely on filesystem functionality that - //probably have to be implemented in ctru-rs instead of this library, - //and thus are commented out - - /* /// Query the file system to get information about a file, directory, etc. /// /// This function will traverse symbolic links to query information about the @@ -1631,6 +1849,7 @@ impl Path { /// This is an alias to [`fs::metadata`]. /// /// [`fs::metadata`]: ../fs/fn.metadata.html + #[cfg(feature = "fs_not_implemented")] pub fn metadata(&self) -> io::Result { fs::metadata(self) } @@ -1640,49 +1859,47 @@ impl Path { /// This is an alias to [`fs::symlink_metadata`]. /// /// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html - + #[cfg(feature = "fs_not_implemented")] pub fn symlink_metadata(&self) -> io::Result { fs::symlink_metadata(self) } - /// Returns the canonical 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 - + #[cfg(feature = "fs_not_implemented")] 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 - + #[cfg(feature = "fs_not_implemented")] 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`. New errors may - /// be encountered after an iterator is initially constructed. + /// 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 - + #[cfg(feature = "fs_not_implemented")] 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 @@ -1694,12 +1911,11 @@ impl Path { /// use std::path::Path; /// assert_eq!(Path::new("does_not_exist.txt").exists(), false); /// ``` - + #[cfg(feature = "fs_not_implemented")] pub fn exists(&self) -> bool { fs::metadata(self).is_ok() } - /// Returns whether the path is pointing at a regular file. /// /// This function will traverse symbolic links to query information about the @@ -1712,12 +1928,11 @@ impl Path { /// assert_eq!(Path::new("./is_a_directory/").is_file(), false); /// assert_eq!(Path::new("a_file.txt").is_file(), true); /// ``` - + #[cfg(feature = "fs_not_implemented")] pub fn is_file(&self) -> bool { fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) } - /// Returns whether the path is pointing at a directory. /// /// This function will traverse symbolic links to query information about the @@ -1730,19 +1945,20 @@ impl Path { /// assert_eq!(Path::new("./is_a_directory/").is_dir(), true); /// assert_eq!(Path::new("a_file.txt").is_dir(), false); /// ``` - + #[cfg(feature = "fs_not_implemented")] pub fn is_dir(&self) -> bool { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } - */ } +#[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) -> Result<(), fmt::Error> { self.inner.fmt(formatter) @@ -1750,28 +1966,33 @@ impl fmt::Debug for Path { } /// Helper struct for safely printing paths with `format!()` and `{}` +#[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.to_string_lossy(), f) } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> fmt::Display for Display<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.path.to_string_lossy(), 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() { @@ -1780,68 +2001,80 @@ impl Hash for Path { } } +#[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>; @@ -1850,16 +2083,19 @@ impl<'a> IntoIterator for &'a Path { 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 { @@ -1867,6 +2103,7 @@ macro_rules! impl_cmp { } } + #[stable(feature = "cmp_path", since = "1.8.0")] impl<'a, 'b> PartialOrd<$lhs> for $rhs { #[inline] fn partial_cmp(&self, other: &$lhs) -> Option { @@ -1884,16 +2121,19 @@ 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 { @@ -1901,6 +2141,7 @@ macro_rules! impl_cmp_os_str { } } + #[stable(feature = "cmp_path", since = "1.8.0")] impl<'a, 'b> PartialOrd<$lhs> for $rhs { #[inline] fn partial_cmp(&self, other: &$lhs) -> Option { @@ -1925,26 +2166,21 @@ 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 collections::string::{ToString, String}; - use collections::borrow; - use collections::Vec; macro_rules! t( ($path:expr, iter: $iter:expr) => ( @@ -2031,7 +2267,7 @@ mod tests { #[test] fn into() { - use collections::borrow::Cow; + use borrow::Cow; let static_path = Path::new("/home/foo"); let static_cow_path: Cow<'static, Path> = static_path.into(); @@ -3131,7 +3367,7 @@ mod tests { #[test] fn test_eq_recievers() { - use collections::borrow::Cow; + use borrow::Cow; let borrowed: &Path = Path::new("foo/bar"); let mut owned: PathBuf = PathBuf::new(); @@ -3156,10 +3392,11 @@ mod tests { #[test] pub fn test_compare() { - use core::hash::{Hash, Hasher, SipHasher}; + use hash::{Hash, Hasher}; + use collections::hash_map::DefaultHasher; fn hash(t: T) -> u64 { - let mut s = SipHasher::new_with_keys(0, 0); + let mut s = DefaultHasher::new(); t.hash(&mut s); s.finish() } @@ -3278,4 +3515,47 @@ mod tests { ); } } + + #[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); + } } diff --git a/ctr-std/src/prelude/mod.rs b/ctr-std/src/prelude/mod.rs new file mode 100644 index 0000000..f4cd319 --- /dev/null +++ b/ctr-std/src/prelude/mod.rs @@ -0,0 +1,146 @@ +// 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 +//! +//! ```ignore +//! extern crate std; +//! ``` +//! +//! into the crate root of every crate, and +//! +//! ```ignore +//! 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 reexports 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`], 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()`], +//! 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/trait.Clone.html#tymethod.clone +//! [`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/closures.html +//! [book-dtor]: ../../book/drop.html +//! [book-enums]: ../../book/enums.html +//! [book-iter]: ../../book/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 new file mode 100644 index 0000000..9ca5b44 --- /dev/null +++ b/ctr-std/src/prelude/v1.rs @@ -0,0 +1,53 @@ +// 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")] + +// Reexported 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}; + +// Reexported functions +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] pub use mem::drop; + +// Reexported types and traits +#[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 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}; +#[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/std/src/rt.rs b/ctr-std/src/rt.rs similarity index 85% rename from std/src/rt.rs rename to ctr-std/src/rt.rs index 72f276b..178b5a0 100644 --- a/std/src/rt.rs +++ b/ctr-std/src/rt.rs @@ -16,6 +16,12 @@ //! 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)] + use mem; // Reexport some of our utilities which are expected by other crates. diff --git a/ctr-std/src/sync/mod.rs b/ctr-std/src/sync/mod.rs new file mode 100644 index 0000000..487c4c9 --- /dev/null +++ b/ctr-std/src/sync/mod.rs @@ -0,0 +1,29 @@ +// 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::arc::{Arc, Weak}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::sync::atomic; + +// Easy cheat until we get proper locks based on libctru code +#[stable(feature = "3ds", since = "1.0.0")] +pub use spin::{Mutex, MutexGuard}; +#[stable(feature = "3ds", since = "1.0.0")] +pub use spin::{RwLock, RwLockReadGuard, RwLockWriteGuard}; diff --git a/ctr-std/src/sys/mod.rs b/ctr-std/src/sys/mod.rs new file mode 100644 index 0000000..175e227 --- /dev/null +++ b/ctr-std/src/sys/mod.rs @@ -0,0 +1,37 @@ +// 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. +//! +//! The centralization of platform-specific code in this module is +//! enforced by the "platform abstraction layer" tidy script in +//! `tools/tidy/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 indepedent +//! 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. + +pub use self::imp::*; + +#[cfg(unix)] +#[path = "unix/mod.rs"] +mod imp; diff --git a/ctr-std/src/sys/unix/ext/ffi.rs b/ctr-std/src/sys/unix/ext/ffi.rs new file mode 100644 index 0000000..d59b4fc --- /dev/null +++ b/ctr-std/src/sys/unix/ext/ffi.rs @@ -0,0 +1,61 @@ +// 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`. +#[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 + } +} + +/// Unix-specific extensions to `OsStr`. +#[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/unix/ext/mod.rs b/ctr-std/src/sys/unix/ext/mod.rs new file mode 100644 index 0000000..04ea563 --- /dev/null +++ b/ctr-std/src/sys/unix/ext/mod.rs @@ -0,0 +1,41 @@ +// 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. +//! +//! For now, this module is limited to extracting file descriptors, +//! but its functionality will grow over time. +//! +//! # Example +//! +//! ```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")] + +pub mod ffi; + +/// 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::ffi::{OsStrExt, OsStringExt}; +} diff --git a/ctr-std/src/sys/unix/memchr.rs b/ctr-std/src/sys/unix/memchr.rs new file mode 100644 index 0000000..d7e9c2b --- /dev/null +++ b/ctr-std/src/sys/unix/memchr.rs @@ -0,0 +1,51 @@ +// 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)) + } + } + memrchr_specific(needle, haystack) +} diff --git a/ctr-std/src/sys/unix/mod.rs b/ctr-std/src/sys/unix/mod.rs new file mode 100644 index 0000000..698e31a --- /dev/null +++ b/ctr-std/src/sys/unix/mod.rs @@ -0,0 +1,50 @@ +// 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)] + +pub mod ext; +pub mod memchr; +pub mod os; +pub mod os_str; +pub mod path; + +use io::ErrorKind; +use libc; + +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, + } +} + +pub unsafe fn abort_internal() -> ! { + ::libc::abort() +} diff --git a/ctr-std/src/sys/unix/os.rs b/ctr-std/src/sys/unix/os.rs new file mode 100644 index 0000000..de087d9 --- /dev/null +++ b/ctr-std/src/sys/unix/os.rs @@ -0,0 +1,123 @@ +// 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 vec; + +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 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 exit(code: i32) -> ! { + unsafe { libc::exit(code as c_int) } +} diff --git a/ctr-std/src/sys/unix/os_str.rs b/ctr-std/src/sys/unix/os_str.rs new file mode 100644 index 0000000..5a733c0 --- /dev/null +++ b/ctr-std/src/sys/unix/os_str.rs @@ -0,0 +1,119 @@ +// 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::{self, Debug}; +use str; +use mem; +use sys_common::{AsInner, IntoInner}; + +#[derive(Clone, Hash)] +pub struct Buf { + pub inner: Vec +} + +pub struct Slice { + pub inner: [u8] +} + +impl Debug for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.to_string_lossy().fmt(formatter) + } +} + +impl Debug for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.as_slice().fmt(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) + } + + 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) + } +} + +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() } + } +} diff --git a/ctr-std/src/sys/unix/path.rs b/ctr-std/src/sys/unix/path.rs new file mode 100644 index 0000000..bf9af7a --- /dev/null +++ b/ctr-std/src/sys/unix/path.rs @@ -0,0 +1,29 @@ +// 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_common/io.rs b/ctr-std/src/sys_common/io.rs new file mode 100644 index 0000000..23daeeb --- /dev/null +++ b/ctr-std/src/sys_common/io.rs @@ -0,0 +1,179 @@ +// 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 io::ErrorKind; +use io::Read; +use slice::from_raw_parts_mut; + +pub const DEFAULT_BUF_SIZE: usize = 8 * 1024; + +// Provides read_to_end functionality over an uninitialized buffer. +// This function is unsafe because it calls the underlying +// read function with a slice into uninitialized memory. The default +// implementation of read_to_end for readers will zero out new memory in +// the buf before passing it to read, but avoiding this zero can often +// lead to a fairly significant performance win. +// +// Implementations using this method have to adhere to two guarantees: +// * The implementation of read never reads the buffer provided. +// * The implementation of read correctly reports how many bytes were written. +pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec) -> io::Result { + + let start_len = buf.len(); + buf.reserve(16); + + // Always try to read into the empty space of the vector (from the length to the capacity). + // If the vector ever fills up then we reserve an extra byte which should trigger the normal + // reallocation routines for the vector, which will likely double the size. + // + // This function is similar to the read_to_end function in std::io, but the logic about + // reservations and slicing is different enough that this is duplicated here. + loop { + if buf.len() == buf.capacity() { + buf.reserve(1); + } + + let buf_slice = from_raw_parts_mut(buf.as_mut_ptr().offset(buf.len() as isize), + buf.capacity() - buf.len()); + + match r.read(buf_slice) { + Ok(0) => { return Ok(buf.len() - start_len); } + Ok(n) => { let len = buf.len() + n; buf.set_len(len); }, + Err(ref e) if e.kind() == ErrorKind::Interrupted => { } + Err(e) => { return Err(e); } + } + } +} + +#[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) + } +} + +#[cfg(test)] +mod tests { + use io::prelude::*; + use super::*; + use io; + use io::{ErrorKind, Take, Repeat, repeat}; + use slice::from_raw_parts; + + struct ErrorRepeat { + lr: Take + } + + fn error_repeat(byte: u8, limit: u64) -> ErrorRepeat { + ErrorRepeat { lr: repeat(byte).take(limit) } + } + + impl Read for ErrorRepeat { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let ret = self.lr.read(buf); + if let Ok(0) = ret { + return Err(io::Error::new(ErrorKind::Other, "")) + } + ret + } + } + + fn init_vec_data() -> Vec { + let mut vec = vec![10u8; 200]; + unsafe { vec.set_len(0); } + vec + } + + fn assert_all_eq(buf: &[u8], value: u8) { + for n in buf { + assert_eq!(*n, value); + } + } + + fn validate(buf: &Vec, good_read_len: usize) { + assert_all_eq(buf, 1u8); + let cap = buf.capacity(); + let end_slice = unsafe { from_raw_parts(buf.as_ptr().offset(good_read_len as isize), + cap - good_read_len) }; + assert_all_eq(end_slice, 10u8); + } + + #[test] + fn read_to_end_uninit_error() { + let mut er = error_repeat(1,100); + let mut vec = init_vec_data(); + if let Err(_) = unsafe { read_to_end_uninitialized(&mut er, &mut vec) } { + validate(&vec, 100); + } else { + assert!(false); + } + } + + #[test] + fn read_to_end_uninit_zero_len_vec() { + let mut er = repeat(1).take(100); + let mut vec = Vec::new(); + let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; + assert_all_eq(&vec, 1u8); + assert_eq!(vec.len(), n); + } + + #[test] + fn read_to_end_uninit_good() { + let mut er = repeat(1).take(100); + let mut vec = init_vec_data(); + let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; + validate(&vec, 100); + assert_eq!(vec.len(), n); + } + + #[bench] + #[cfg_attr(target_os = "emscripten", ignore)] + fn bench_uninitialized(b: &mut ::test::Bencher) { + b.iter(|| { + let mut lr = repeat(1).take(10000000); + let mut vec = Vec::with_capacity(1024); + unsafe { read_to_end_uninitialized(&mut lr, &mut vec) } + }); + } +} diff --git a/ctr-std/src/sys_common/mod.rs b/ctr-std/src/sys_common/mod.rs new file mode 100644 index 0000000..38057b8 --- /dev/null +++ b/ctr-std/src/sys_common/mod.rs @@ -0,0 +1,76 @@ +// 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 libraries +//! 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)] + +pub mod io; + +// 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; +} + +macro_rules! rtabort { + ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) +} + +// 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/ctru-sys/Cargo.toml b/ctru-sys/Cargo.toml index 578ee82..fa204ee 100644 --- a/ctru-sys/Cargo.toml +++ b/ctru-sys/Cargo.toml @@ -1,5 +1,8 @@ [package] name = "ctru-sys" -version = "0.2.0" +version = "0.3.0" authors = ["Ronald Kinard "] license = "https://en.wikipedia.org/wiki/Zlib_License" + +[dependencies] +ctr-libc = { path = "../ctr-libc", default-features = false } diff --git a/ctru-sys/src/applets/mod.rs b/ctru-sys/src/applets/mod.rs new file mode 100644 index 0000000..73469a3 --- /dev/null +++ b/ctru-sys/src/applets/mod.rs @@ -0,0 +1 @@ +pub mod swkbd; diff --git a/ctru-sys/src/applets/swkbd.rs b/ctru-sys/src/applets/swkbd.rs new file mode 100644 index 0000000..3fba279 --- /dev/null +++ b/ctru-sys/src/applets/swkbd.rs @@ -0,0 +1,258 @@ +// automatically generated by rust-bindgen + + +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] + +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum SwkbdType { + SWKBD_TYPE_NORMAL = 0, + SWKBD_TYPE_QWERTY = 1, + SWKBD_TYPE_NUMPAD = 2, + SWKBD_TYPE_WESTERN = 3, +} +pub const SWKBD_NOTBLANK_NOTEMPTY: SwkbdValidInput = SwkbdValidInput::SWKBD_NOTEMPTY_NOTBLANK; +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum SwkbdValidInput { + SWKBD_ANYTHING = 0, + SWKBD_NOTEMPTY = 1, + SWKBD_NOTEMPTY_NOTBLANK = 2, + SWKBD_NOTBLANK = 3, + SWKBD_FIXEDLEN = 4, +} +pub const SWKBD_BUTTON_CONFIRM: SwkbdButton = SwkbdButton::SWKBD_BUTTON_RIGHT; +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum SwkbdButton { + SWKBD_BUTTON_LEFT = 0, + SWKBD_BUTTON_MIDDLE = 1, + SWKBD_BUTTON_RIGHT = 2, + SWKBD_BUTTON_NONE = 3, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum SwkbdPasswordMode { + SWKBD_PASSWORD_NONE = 0, + SWKBD_PASSWORD_HIDE = 1, + SWKBD_PASSWORD_HIDE_DELAY = 2, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed1 { + SWKBD_FILTER_DIGITS = 1, + SWKBD_FILTER_AT = 2, + SWKBD_FILTER_PERCENT = 4, + SWKBD_FILTER_BACKSLASH = 8, + SWKBD_FILTER_PROFANITY = 16, + SWKBD_FILTER_CALLBACK = 32, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed2 { + SWKBD_PARENTAL = 1, + SWKBD_DARKEN_TOP_SCREEN = 2, + SWKBD_PREDICTIVE_INPUT = 4, + SWKBD_MULTILINE = 8, + SWKBD_FIXED_WIDTH = 16, + SWKBD_ALLOW_HOME = 32, + SWKBD_ALLOW_RESET = 64, + SWKBD_ALLOW_POWER = 128, + SWKBD_DEFAULT_QWERTY = 512, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum SwkbdCallbackResult { + SWKBD_CALLBACK_OK = 0, + SWKBD_CALLBACK_CLOSE = 1, + SWKBD_CALLBACK_CONTINUE = 2, +} +#[derive(Copy, Clone)] +#[repr(i32)] +#[derive(Debug)] +pub enum SwkbdResult { + SWKBD_NONE = -1, + SWKBD_INVALID_INPUT = -2, + SWKBD_OUTOFMEM = -3, + SWKBD_D0_CLICK = 0, + SWKBD_D1_CLICK0 = 1, + SWKBD_D1_CLICK1 = 2, + SWKBD_D2_CLICK0 = 3, + SWKBD_D2_CLICK1 = 4, + SWKBD_D2_CLICK2 = 5, + SWKBD_HOMEPRESSED = 10, + SWKBD_RESETPRESSED = 11, + SWKBD_POWERPRESSED = 12, + SWKBD_PARENTAL_OK = 20, + SWKBD_PARENTAL_FAIL = 21, + SWKBD_BANNED_INPUT = 30, +} +#[repr(C)] +#[derive(Copy)] +pub struct SwkbdDictWord { + pub reading: [u16; 41usize], + pub word: [u16; 41usize], + pub language: u8, + pub all_languages: u8, +} +impl ::core::clone::Clone for SwkbdDictWord { + fn clone(&self) -> Self { + *self + } +} +impl ::core::default::Default for SwkbdDictWord { + fn default() -> Self { + unsafe { ::core::mem::zeroed() } + } +} +pub type SwkbdCallbackFn = + ::core::option::Option SwkbdCallbackResult>; +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct SwkbdStatusData { + pub data: [u32; 17usize], +} +impl ::core::default::Default for SwkbdStatusData { + fn default() -> Self { + unsafe { ::core::mem::zeroed() } + } +} +#[repr(C)] +#[derive(Copy)] +pub struct SwkbdLearningData { + pub data: [u32; 10523usize], +} +impl ::core::clone::Clone for SwkbdLearningData { + fn clone(&self) -> Self { + *self + } +} +impl ::core::default::Default for SwkbdLearningData { + fn default() -> Self { + unsafe { ::core::mem::zeroed() } + } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct SwkbdExtra { + pub initial_text: *const u8, + pub dict: *const SwkbdDictWord, + pub status_data: *mut SwkbdStatusData, + pub learning_data: *mut SwkbdLearningData, + pub callback: SwkbdCallbackFn, + pub callback_user: *mut ::libc::c_void, +} +impl ::core::default::Default for SwkbdExtra { + fn default() -> Self { + unsafe { ::core::mem::zeroed() } + } +} +#[repr(C)] +#[derive(Copy)] +pub struct SwkbdState { + pub type_: i32, + pub num_buttons_m1: i32, + pub valid_input: i32, + pub password_mode: i32, + pub is_parental_screen: i32, + pub darken_top_screen: i32, + pub filter_flags: u32, + pub save_state_flags: u32, + pub max_text_len: u16, + pub dict_word_count: u16, + pub max_digits: u16, + pub button_text: [[u16; 17usize]; 3usize], + pub numpad_keys: [u16; 2usize], + pub hint_text: [u16; 65usize], + pub predictive_input: u8, + pub multiline: u8, + pub fixed_width: u8, + pub allow_home: u8, + pub allow_reset: u8, + pub allow_power: u8, + pub unknown: u8, + pub default_qwerty: u8, + pub button_submits_text: [u8; 4usize], + pub language: u16, + pub initial_text_offset: i32, + pub dict_offset: i32, + pub initial_status_offset: i32, + pub initial_learning_offset: i32, + pub shared_memory_size: usize, + pub version: u32, + pub result: SwkbdResult, + pub status_offset: i32, + pub learning_offset: i32, + pub text_offset: i32, + pub text_length: u16, + pub callback_result: i32, + pub callback_msg: [u16; 257usize], + pub skip_at_check: u8, + pub union: _bindgen_data_1_, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union _bindgen_data_1_ { + pub reserved: [u8; 171usize], + pub extra: SwkbdExtra, +} +impl ::core::clone::Clone for SwkbdState { + fn clone(&self) -> Self { + *self + } +} +impl ::core::default::Default for SwkbdState { + fn default() -> Self { + unsafe { ::core::mem::zeroed() } + } +} +extern "C" { + pub fn swkbdInit(swkbd: *mut SwkbdState, + type_: SwkbdType, + numButtons: i32, + maxTextLength: i32); + pub fn swkbdSetFeatures(swkbd: *mut SwkbdState, features: u32); + pub fn swkbdSetHintText(swkbd: *mut SwkbdState, text: *const u8); + pub fn swkbdSetButton(swkbd: *mut SwkbdState, + button: SwkbdButton, + text: *const u8, + submit: u8); + pub fn swkbdSetInitialText(swkbd: *mut SwkbdState, text: *const u8); + pub fn swkbdSetDictWord(word: *mut SwkbdDictWord, + reading: *const u8, + text: *const u8); + pub fn swkbdSetDictionary(swkbd: *mut SwkbdState, + dict: *const SwkbdDictWord, + wordCount: i32); + pub fn swkbdSetStatusData(swkbd: *mut SwkbdState, + data: *mut SwkbdStatusData, + in_: u8, + out: u8); + pub fn swkbdSetLearningData(swkbd: *mut SwkbdState, + data: *mut SwkbdLearningData, + in_: u8, + out: u8); + pub fn swkbdSetFilterCallback(swkbd: *mut SwkbdState, + callback: SwkbdCallbackFn, + user: *mut ::libc::c_void); + pub fn swkbdInputText(swkbd: *mut SwkbdState, + buf: *mut u8, + bufsize: usize) + -> SwkbdButton; +} diff --git a/ctru-sys/src/lib.rs b/ctru-sys/src/lib.rs index fdfae33..5bbc54d 100644 --- a/ctru-sys/src/lib.rs +++ b/ctru-sys/src/lib.rs @@ -2,18 +2,23 @@ * C bindings generation: * bindgen --match=file.h --use-core --ctypes-prefix=libc -- --sysroot=$DEVKITARM/arm-none-eabi -I$CTRULIB/include $CTRULIB/include/3ds.h * - * bindgen --sysroot=$DEVKITARM/arm-none-eabi -I$CTRULIB/include $CTRULIB/include/3ds.h */ #![no_std] #![allow(non_camel_case_types, non_snake_case, overflowing_literals)] +#![feature(untagged_unions)] +extern crate ctr_libc as libc; + +pub mod applets; pub mod console; pub mod env; pub mod gfx; pub mod gpu; pub mod ipc; +pub mod ndsp; pub mod os; +pub mod romfs; pub mod sdmc; pub mod services; pub mod svc; diff --git a/ctru-sys/src/ndsp/channel.rs b/ctru-sys/src/ndsp/channel.rs new file mode 100644 index 0000000..be5b91e --- /dev/null +++ b/ctru-sys/src/ndsp/channel.rs @@ -0,0 +1,82 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] + +use ::types::*; +use super::ndsp::ndspWaveBuf; + +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed1 { + NDSP_ENCODING_PCM8 = 0, + NDSP_ENCODING_PCM16 = 1, + NDSP_ENCODING_ADPCM = 2, +} +pub const NDSP_FORMAT_PCM8: Enum_Unnamed2 = + Enum_Unnamed2::NDSP_FORMAT_MONO_PCM8; +pub const NDSP_FORMAT_PCM16: Enum_Unnamed2 = + Enum_Unnamed2::NDSP_FORMAT_MONO_PCM16; +pub const NDSP_FORMAT_ADPCM: Enum_Unnamed2 = + Enum_Unnamed2::NDSP_FORMAT_MONO_ADPCM; +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed2 { + NDSP_FORMAT_MONO_PCM8 = 1, + NDSP_FORMAT_MONO_PCM16 = 5, + NDSP_FORMAT_MONO_ADPCM = 9, + NDSP_FORMAT_STEREO_PCM8 = 2, + NDSP_FORMAT_STEREO_PCM16 = 6, + NDSP_FRONT_BYPASS = 16, + NDSP_3D_SURROUND_PREPROCESSED = 64, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum ndspInterpType { + NDSP_INTERP_POLYPHASE = 0, + NDSP_INTERP_LINEAR = 1, + NDSP_INTERP_NONE = 2, +} +extern "C" { + pub fn ndspChnReset(id: ::libc::c_int); + pub fn ndspChnInitParams(id: ::libc::c_int); + pub fn ndspChnIsPlaying(id: ::libc::c_int) -> u8; + pub fn ndspChnGetSamplePos(id: ::libc::c_int) -> u32_; + pub fn ndspChnGetWaveBufSeq(id: ::libc::c_int) -> u16_; + pub fn ndspChnIsPaused(id: ::libc::c_int) -> u8; + pub fn ndspChnSetPaused(id: ::libc::c_int, paused: u8); + pub fn ndspChnSetFormat(id: ::libc::c_int, format: u16_); + pub fn ndspChnSetInterp(id: ::libc::c_int, type_: ndspInterpType); + pub fn ndspChnSetRate(id: ::libc::c_int, rate: f32); + pub fn ndspChnSetMix(id: ::libc::c_int, mix: *mut f32); + pub fn ndspChnSetAdpcmCoefs(id: ::libc::c_int, coefs: *mut u16_); + pub fn ndspChnWaveBufClear(id: ::libc::c_int); + pub fn ndspChnWaveBufAdd(id: ::libc::c_int, buf: *mut ndspWaveBuf); + pub fn ndspChnIirMonoSetEnable(id: ::libc::c_int, enable: u8); + pub fn ndspChnIirMonoSetParamsCustomFilter(id: ::libc::c_int, a0: f32, + a1: f32, b0: f32) -> u8; + pub fn ndspChnIirMonoSetParamsLowPassFilter(id: ::libc::c_int, f0: f32) + -> u8; + pub fn ndspChnIirMonoSetParamsHighPassFilter(id: ::libc::c_int, f0: f32) + -> u8; + pub fn ndspChnIirBiquadSetEnable(id: ::libc::c_int, enable: u8); + pub fn ndspChnIirBiquadSetParamsCustomFilter(id: ::libc::c_int, a0: f32, + a1: f32, a2: f32, b0: f32, + b1: f32, b2: f32) -> u8; + pub fn ndspChnIirBiquadSetParamsLowPassFilter(id: ::libc::c_int, f0: f32, + Q: f32) -> u8; + pub fn ndspChnIirBiquadSetParamsHighPassFilter(id: ::libc::c_int, f0: f32, + Q: f32) -> u8; + pub fn ndspChnIirBiquadSetParamsBandPassFilter(id: ::libc::c_int, f0: f32, + Q: f32) -> u8; + pub fn ndspChnIirBiquadSetParamsNotchFilter(id: ::libc::c_int, f0: f32, + Q: f32) -> u8; + pub fn ndspChnIirBiquadSetParamsPeakingEqualizer(id: ::libc::c_int, + f0: f32, Q: f32, + gain: f32) -> u8; +} diff --git a/ctru-sys/src/ndsp/mod.rs b/ctru-sys/src/ndsp/mod.rs new file mode 100644 index 0000000..bfebfe6 --- /dev/null +++ b/ctru-sys/src/ndsp/mod.rs @@ -0,0 +1,2 @@ +pub mod channel; +pub mod ndsp; diff --git a/ctru-sys/src/ndsp/ndsp.rs b/ctru-sys/src/ndsp/ndsp.rs new file mode 100644 index 0000000..6139f26 --- /dev/null +++ b/ctru-sys/src/ndsp/ndsp.rs @@ -0,0 +1,112 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum ndspOutputMode { + NDSP_OUTPUT_MONO = 0, + NDSP_OUTPUT_STEREO = 1, + NDSP_OUTPUT_SURROUND = 2, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum ndspClippingMode { NDSP_CLIP_NORMAL = 0, NDSP_CLIP_SOFT = 1, } +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum ndspSpeakerPos { + NDSP_SPKPOS_SQUARE = 0, + NDSP_SPKPOS_WIDE = 1, + NDSP_SPKPOS_NUM = 2, +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct ndspAdpcmData { + pub index: u16_, + pub history0: s16, + pub history1: s16, +} +impl ::core::default::Default for ndspAdpcmData { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +pub type ndspWaveBuf = tag_ndspWaveBuf; +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed1 { + NDSP_WBUF_FREE = 0, + NDSP_WBUF_QUEUED = 1, + NDSP_WBUF_PLAYING = 2, + NDSP_WBUF_DONE = 3, +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct tag_ndspWaveBuf { + pub _bindgen_data_1_: [u64; 1usize], + pub nsamples: u32_, + pub adpcm_data: *mut ndspAdpcmData, + pub offset: u32_, + pub looping: u8, + pub status: u8_, + pub sequence_id: u16_, + pub next: *mut ndspWaveBuf, +} +impl tag_ndspWaveBuf { + pub unsafe fn data_pcm8(&mut self) -> *mut *mut s8 { + let raw: *mut u8 = ::core::mem::transmute(&self._bindgen_data_1_); + ::core::mem::transmute(raw.offset(0)) + } + pub unsafe fn data_pcm16(&mut self) -> *mut *mut s16 { + let raw: *mut u8 = ::core::mem::transmute(&self._bindgen_data_1_); + ::core::mem::transmute(raw.offset(0)) + } + pub unsafe fn data_adpcm(&mut self) -> *mut *mut u8_ { + let raw: *mut u8 = ::core::mem::transmute(&self._bindgen_data_1_); + ::core::mem::transmute(raw.offset(0)) + } + pub unsafe fn data_vaddr(&mut self) -> *mut *const ::libc::c_void { + let raw: *mut u8 = ::core::mem::transmute(&self._bindgen_data_1_); + ::core::mem::transmute(raw.offset(0)) + } +} +impl ::core::default::Default for tag_ndspWaveBuf { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +pub type ndspCallback = + ::core::option::Option; +pub type ndspAuxCallback = + ::core::option::Option; +extern "C" { + pub fn ndspUseComponent(binary: *const ::libc::c_void, size: u32_, + progMask: u16_, dataMask: u16_); + pub fn ndspInit() -> Result; + pub fn ndspExit(); + pub fn ndspGetDroppedFrames() -> u32_; + pub fn ndspGetFrameCount() -> u32_; + pub fn ndspSetMasterVol(volume: f32); + pub fn ndspSetOutputMode(mode: ndspOutputMode); + pub fn ndspSetClippingMode(mode: ndspClippingMode); + pub fn ndspSetOutputCount(count: ::libc::c_int); + pub fn ndspSetCapture(capture: *mut ndspWaveBuf); + pub fn ndspSetCallback(callback: ndspCallback, data: *mut ::libc::c_void); + pub fn ndspSurroundSetDepth(depth: u16_); + pub fn ndspSurroundSetPos(pos: ndspSpeakerPos); + pub fn ndspSurroundSetRearRatio(ratio: u16_); + pub fn ndspAuxSetEnable(id: ::libc::c_int, enable: u8); + pub fn ndspAuxSetFrontBypass(id: ::libc::c_int, bypass: u8); + pub fn ndspAuxSetVolume(id: ::libc::c_int, volume: f32); + pub fn ndspAuxSetCallback(id: ::libc::c_int, callback: ndspAuxCallback, + data: *mut ::libc::c_void); +} + +use ::types::*; diff --git a/ctru-sys/src/os.rs b/ctru-sys/src/os.rs index 768ece0..c3dff74 100644 --- a/ctru-sys/src/os.rs +++ b/ctru-sys/src/os.rs @@ -1,53 +1,47 @@ -//TODO: Fix Bindgen's issues again. +/* automatically generated by rust-bindgen */ -use libc::c_void; -use types::*; - -#[inline] -pub fn SYSTEM_VERSION(major: i32, minor: i32, revision: i32) { - (((major)<<24)|((minor)<<16)|((revision)<<8)); -} - -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed1 { +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum MemRegion { MEMREGION_ALL = 0, MEMREGION_APPLICATION = 1, MEMREGION_SYSTEM = 2, MEMREGION_BASE = 3, } -pub type MemRegion = Enum_Unnamed1; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed2 { - pub build: u8, - pub minor: u8, - pub mainver: u8, - pub reserved_x3: u8, - pub region: u8, - pub reserved_x5: [u8; 3usize], -} -impl ::core::clone::Clone for Struct_Unnamed2 { - fn clone(&self) -> Self { *self } +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct OS_VersionBin { + pub build: u8_, + pub minor: u8_, + pub mainver: u8_, + pub reserved_x3: u8_, + pub region: ::libc::c_char, + pub reserved_x5: [u8_; 3usize], } -impl ::core::default::Default for Struct_Unnamed2 { +impl ::core::default::Default for OS_VersionBin { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type OS_VersionBin = Struct_Unnamed2; extern "C" { - pub fn osConvertVirtToPhys(vaddr: *const c_void) -> u32; - pub fn osConvertOldLINEARMemToNew(vaddr: *const c_void) - -> *mut c_void; - pub fn osStrError(error: u32) -> *const u8; + pub fn osConvertVirtToPhys(vaddr: *const ::libc::c_void) -> u32_; + pub fn osConvertOldLINEARMemToNew(vaddr: *const ::libc::c_void) + -> *mut ::libc::c_void; + pub fn osStrError(error: u32_) -> *const ::libc::c_char; pub fn osGetMemRegionUsed(region: MemRegion) -> s64; - pub fn osGetTime() -> u64; + pub fn osGetTime() -> u64_; pub fn osSetSpeedupEnable(enable: u8); pub fn osGetSystemVersionData(nver_versionbin: *mut OS_VersionBin, cver_versionbin: *mut OS_VersionBin) -> Result; pub fn osGetSystemVersionDataString(nver_versionbin: *mut OS_VersionBin, cver_versionbin: *mut OS_VersionBin, - sysverstr: - *mut u8, - sysverstr_maxsize: u32) -> Result; + sysverstr: *mut ::libc::c_char, + sysverstr_maxsize: u32_) -> Result; } + +use ::types::*; diff --git a/ctru-sys/src/romfs.rs b/ctru-sys/src/romfs.rs new file mode 100644 index 0000000..dc25e39 --- /dev/null +++ b/ctru-sys/src/romfs.rs @@ -0,0 +1,64 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct romfs_header { + pub headerSize: u32_, + pub dirHashTableOff: u32_, + pub dirHashTableSize: u32_, + pub dirTableOff: u32_, + pub dirTableSize: u32_, + pub fileHashTableOff: u32_, + pub fileHashTableSize: u32_, + pub fileTableOff: u32_, + pub fileTableSize: u32_, + pub fileDataOff: u32_, +} +impl ::core::default::Default for romfs_header { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct romfs_dir { + pub parent: u32_, + pub sibling: u32_, + pub childDir: u32_, + pub childFile: u32_, + pub nextHash: u32_, + pub nameLen: u32_, + pub name: [u16_; 0usize], +} +impl ::core::default::Default for romfs_dir { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct romfs_file { + pub parent: u32_, + pub sibling: u32_, + pub dataOff: u64_, + pub dataSize: u64_, + pub nextHash: u32_, + pub nameLen: u32_, + pub name: [u16_; 0usize], +} +impl ::core::default::Default for romfs_file { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +pub enum romfs_mount { } +extern "C" { + pub fn romfsMount(mount: *mut *mut romfs_mount) -> Result; + pub fn romfsMountFromFile(file: Handle, offset: u32_, + mount: *mut *mut romfs_mount) -> Result; + pub fn romfsBind(mount: *mut romfs_mount) -> Result; + pub fn romfsUnmount(mount: *mut romfs_mount) -> Result; +} + +use ::types::*; diff --git a/ctru-sys/src/sdmc.rs b/ctru-sys/src/sdmc.rs index ee70839..9cf1209 100644 --- a/ctru-sys/src/sdmc.rs +++ b/ctru-sys/src/sdmc.rs @@ -1,7 +1,29 @@ -use Result; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +use ::types::*; +use services::fs::FS_DirectoryEntry; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct sdmc_dir_t { + pub magic: u32_, + pub fd: Handle, + pub index: ::libc::ssize_t, + pub size: ::libc::size_t, + pub entry_data: [FS_DirectoryEntry; 32usize], +} +impl ::core::default::Default for sdmc_dir_t { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} extern "C" { pub fn sdmcInit() -> Result; + pub fn sdmcWriteSafe(enable: u8); pub fn sdmcExit() -> Result; + pub fn sdmc_getmtime(name: *const ::libc::c_char, mtime: *mut u64_) + -> Result; } diff --git a/ctru-sys/src/services/apt.rs b/ctru-sys/src/services/apt.rs index 22acd27..d713102 100644 --- a/ctru-sys/src/services/apt.rs +++ b/ctru-sys/src/services/apt.rs @@ -143,7 +143,7 @@ pub type aptMessageCb = ::core::option::Option; + msgsize: ::libc::size_t)>; extern "C" { pub fn aptInit() -> Result; pub fn aptExit(); @@ -157,7 +157,7 @@ extern "C" { pub fn aptSetMessageCallback(callback: aptMessageCb, user: *mut ::libc::c_void); pub fn aptLaunchLibraryApplet(appId: NS_APPID, buf: *mut ::libc::c_void, - bufsize: size_t, handle: Handle) -> u8; + bufsize: ::libc::size_t, handle: Handle) -> u8; pub fn APT_GetLockHandle(flags: u16_, lockHandle: *mut Handle) -> Result; pub fn APT_Initialize(appId: NS_APPID, attr: APT_AppletAttr, signalEvent: *mut Handle, resumeEvent: *mut Handle) @@ -178,31 +178,31 @@ extern "C" { titleversion: *mut u16_) -> Result; pub fn APT_GetProgramID(pProgramID: *mut u64_) -> Result; pub fn APT_PrepareToJumpToHomeMenu() -> Result; - pub fn APT_JumpToHomeMenu(param: *const ::libc::c_void, paramSize: size_t, + pub fn APT_JumpToHomeMenu(param: *const ::libc::c_void, paramSize: ::libc::size_t, handle: Handle) -> Result; pub fn APT_PrepareToJumpToApplication(exiting: u8) -> Result; pub fn APT_JumpToApplication(param: *const ::libc::c_void, - paramSize: size_t, handle: Handle) -> Result; + paramSize: ::libc::size_t, handle: Handle) -> Result; pub fn APT_IsRegistered(appID: NS_APPID, out: *mut u8) -> Result; pub fn APT_InquireNotification(appID: u32_, signalType: *mut APT_Signal) -> Result; pub fn APT_NotifyToWait(appID: NS_APPID) -> Result; pub fn APT_AppletUtility(id: ::libc::c_int, out: *mut ::libc::c_void, - outSize: size_t, in_: *const ::libc::c_void, - inSize: size_t) -> Result; + outSize: ::libc::size_t, in_: *const ::libc::c_void, + inSize: ::libc::size_t) -> Result; pub fn APT_SleepIfShellClosed() -> Result; pub fn APT_TryLockTransition(transition: u32_, succeeded: *mut u8) -> Result; pub fn APT_UnlockTransition(transition: u32_) -> Result; pub fn APT_GlanceParameter(appID: NS_APPID, buffer: *mut ::libc::c_void, - bufferSize: size_t, sender: *mut NS_APPID, + bufferSize: ::libc::size_t, sender: *mut NS_APPID, command: *mut APT_Command, - actualSize: *mut size_t, + actualSize: *mut ::libc::size_t, parameter: *mut Handle) -> Result; pub fn APT_ReceiveParameter(appID: NS_APPID, buffer: *mut ::libc::c_void, - bufferSize: size_t, sender: *mut NS_APPID, + bufferSize: ::libc::size_t, sender: *mut NS_APPID, command: *mut APT_Command, - actualSize: *mut size_t, + actualSize: *mut ::libc::size_t, parameter: *mut Handle) -> Result; pub fn APT_SendParameter(source: NS_APPID, dest: NS_APPID, command: APT_Command, @@ -217,24 +217,24 @@ extern "C" { pub fn APT_ReplySleepNotificationComplete(appID: NS_APPID) -> Result; pub fn APT_PrepareToCloseApplication(cancelPreload: u8) -> Result; pub fn APT_CloseApplication(param: *const ::libc::c_void, - paramSize: size_t, handle: Handle) -> Result; + paramSize: ::libc::size_t, handle: Handle) -> Result; pub fn APT_SetAppCpuTimeLimit(percent: u32_) -> Result; pub fn APT_GetAppCpuTimeLimit(percent: *mut u32_) -> Result; pub fn APT_CheckNew3DS(out: *mut u8) -> Result; pub fn APT_PrepareToDoApplicationJump(flags: u8_, programID: u64_, mediatype: u8_) -> Result; pub fn APT_DoApplicationJump(param: *const ::libc::c_void, - paramSize: size_t, + paramSize: ::libc::size_t, hmac: *const ::libc::c_void) -> Result; pub fn APT_PrepareToStartLibraryApplet(appID: NS_APPID) -> Result; pub fn APT_StartLibraryApplet(appID: NS_APPID, param: *const ::libc::c_void, - paramSize: size_t, handle: Handle) + paramSize: ::libc::size_t, handle: Handle) -> Result; pub fn APT_PrepareToStartSystemApplet(appID: NS_APPID) -> Result; pub fn APT_StartSystemApplet(appID: NS_APPID, param: *const ::libc::c_void, - paramSize: size_t, handle: Handle) -> Result; + paramSize: ::libc::size_t, handle: Handle) -> Result; pub fn APT_GetSharedFont(fontHandle: *mut Handle, mapAddr: *mut u32_) -> Result; } diff --git a/ctru-sys/src/services/mod.rs b/ctru-sys/src/services/mod.rs index 30d0f68..880b32d 100644 --- a/ctru-sys/src/services/mod.rs +++ b/ctru-sys/src/services/mod.rs @@ -25,7 +25,6 @@ pub mod ptmsysm; pub mod ptmu; pub mod pxidev; pub mod qtm; -pub mod soc; pub mod srvpm; pub mod sslc; pub mod uds; diff --git a/ctru-sys/src/services/nfc.rs b/ctru-sys/src/services/nfc.rs index 09a6a63..c6ac09e 100644 --- a/ctru-sys/src/services/nfc.rs +++ b/ctru-sys/src/services/nfc.rs @@ -116,10 +116,10 @@ extern "C" { pub fn nfcGetTagInfo(out: *mut NFC_TagInfo) -> Result; pub fn nfcOpenAppData(amiibo_appid: u32_) -> Result; pub fn nfcInitializeWriteAppData(amiibo_appid: u32_, - buf: *const ::libc::c_void, size: size_t) + buf: *const ::libc::c_void, size: ::libc::size_t) -> Result; - pub fn nfcReadAppData(buf: *mut ::libc::c_void, size: size_t) -> Result; - pub fn nfcWriteAppData(buf: *const ::libc::c_void, size: size_t, + pub fn nfcReadAppData(buf: *mut ::libc::c_void, size: ::libc::size_t) -> Result; + pub fn nfcWriteAppData(buf: *const ::libc::c_void, size: ::libc::size_t, taginfo: *mut NFC_TagInfo) -> Result; pub fn nfcGetAmiiboSettings(out: *mut NFC_AmiiboSettings) -> Result; pub fn nfcGetAmiiboConfig(out: *mut NFC_AmiiboConfig) -> Result; diff --git a/ctru-sys/src/services/ps.rs b/ctru-sys/src/services/ps.rs index 8198dbb..3a1e16c 100644 --- a/ctru-sys/src/services/ps.rs +++ b/ctru-sys/src/services/ps.rs @@ -47,7 +47,7 @@ extern "C" { nonce: *mut u8_) -> Result; pub fn PS_GetLocalFriendCodeSeed(seed: *mut u64_) -> Result; pub fn PS_GetDeviceId(device_id: *mut u32_) -> Result; - pub fn PS_GenerateRandomBytes(out: *mut ::libc::c_void, len: size_t) + pub fn PS_GenerateRandomBytes(out: *mut ::libc::c_void, len: ::libc::size_t) -> Result; } use ::types::*; diff --git a/ctru-sys/src/services/soc.rs b/ctru-sys/src/services/soc.rs index 8fa7a3d..94ac632 100644 --- a/ctru-sys/src/services/soc.rs +++ b/ctru-sys/src/services/soc.rs @@ -92,7 +92,7 @@ extern "C" { pub fn socInit(context_addr: *mut u32_, context_size: u32_) -> Result; pub fn socExit() -> Result; pub fn gethostid() -> ::libc::c_long; - pub fn gethostname(name: *mut ::libc::c_char, namelen: size_t) + pub fn gethostname(name: *mut ::libc::c_char, namelen: ::libc::size_t) -> ::libc::c_int; pub fn SOCU_ShutdownSockets() -> ::libc::c_int; pub fn SOCU_CloseSockets() -> ::libc::c_int; diff --git a/ctru-sys/src/services/sslc.rs b/ctru-sys/src/services/sslc.rs index 5a18e59..f310269 100644 --- a/ctru-sys/src/services/sslc.rs +++ b/ctru-sys/src/services/sslc.rs @@ -89,9 +89,9 @@ extern "C" { internal_retval: *mut ::libc::c_int, out: *mut u32_) -> Result; pub fn sslcRead(context: *mut sslcContext, buf: *mut ::libc::c_void, - len: size_t, peek: u8) -> Result; + len: ::libc::size_t, peek: u8) -> Result; pub fn sslcWrite(context: *mut sslcContext, buf: *const ::libc::c_void, - len: size_t) -> Result; + len: ::libc::size_t) -> Result; pub fn sslcContextSetRootCertChain(context: *mut sslcContext, handle: u32_) -> Result; pub fn sslcContextSetClientCert(context: *mut sslcContext, handle: u32_) diff --git a/ctru-sys/src/svc.rs b/ctru-sys/src/svc.rs index 88a6992..fb41bc0 100644 --- a/ctru-sys/src/svc.rs +++ b/ctru-sys/src/svc.rs @@ -4,10 +4,6 @@ non_camel_case_types, non_upper_case_globals, non_snake_case)] - -use ::{Handle, Result}; -use ::ThreadFunc; - #[derive(Copy, Clone)] #[repr(u32)] #[derive(Debug)] @@ -56,10 +52,10 @@ pub enum MemPerm { #[derive(Copy, Clone)] #[derive(Debug)] pub struct MemInfo { - pub base_addr: u32, - pub size: u32, - pub perm: u32, - pub state: u32, + pub base_addr: u32_, + pub size: u32_, + pub perm: u32_, + pub state: u32_, } impl ::core::default::Default for MemInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -68,7 +64,7 @@ impl ::core::default::Default for MemInfo { #[derive(Copy, Clone)] #[derive(Debug)] pub struct PageInfo { - pub flags: u32, + pub flags: u32_, } impl ::core::default::Default for PageInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -99,10 +95,10 @@ pub enum ProcessEventReason { REASON_CREATE = 1, REASON_ATTACH = 2, } #[derive(Copy, Clone)] #[derive(Debug)] pub struct ProcessEvent { - pub program_id: u64, - pub process_name: [u8; 8usize], - pub process_id: u32, - pub reason: u32, + pub program_id: u64_, + pub process_name: [u8_; 8usize], + pub process_id: u32_, + pub reason: u32_, } impl ::core::default::Default for ProcessEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -119,7 +115,7 @@ pub enum ExitProcessEventReason { #[derive(Copy, Clone)] #[derive(Debug)] pub struct ExitProcessEvent { - pub reason: u32, + pub reason: u32_, } impl ::core::default::Default for ExitProcessEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -128,9 +124,9 @@ impl ::core::default::Default for ExitProcessEvent { #[derive(Copy, Clone)] #[derive(Debug)] pub struct CreateThreadEvent { - pub creator_thread_id: u32, - pub base_addr: u32, - pub entry_point: u32, + pub creator_thread_id: u32_, + pub base_addr: u32_, + pub entry_point: u32_, } impl ::core::default::Default for CreateThreadEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -148,7 +144,7 @@ pub enum ExitThreadEventReason { #[derive(Copy, Clone)] #[derive(Debug)] pub struct ExitThreadEvent { - pub reason: u32, + pub reason: u32_, } impl ::core::default::Default for ExitThreadEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -179,9 +175,9 @@ pub enum ExceptionEventType { #[derive(Copy, Clone)] #[derive(Debug)] pub struct ExceptionEvent { - pub type_: u32, - pub address: u32, - pub argument: u32, + pub type_: u32_, + pub address: u32_, + pub argument: u32_, } impl ::core::default::Default for ExceptionEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -190,7 +186,7 @@ impl ::core::default::Default for ExceptionEvent { #[derive(Copy, Clone)] #[derive(Debug)] pub struct SchedulerInOutEvent { - pub clock_tick: u64, + pub clock_tick: u64_, } impl ::core::default::Default for SchedulerInOutEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -199,8 +195,8 @@ impl ::core::default::Default for SchedulerInOutEvent { #[derive(Copy, Clone)] #[derive(Debug)] pub struct SyscallInOutEvent { - pub clock_tick: u64, - pub syscall: u32, + pub clock_tick: u64_, + pub syscall: u32_, _bindgen_padding_0_: [u8; 4usize], } impl ::core::default::Default for SyscallInOutEvent { @@ -210,8 +206,8 @@ impl ::core::default::Default for SyscallInOutEvent { #[derive(Copy, Clone)] #[derive(Debug)] pub struct OutputStringEvent { - pub string_addr: u32, - pub string_size: u32, + pub string_addr: u32_, + pub string_size: u32_, } impl ::core::default::Default for OutputStringEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -220,10 +216,10 @@ impl ::core::default::Default for OutputStringEvent { #[derive(Copy, Clone)] #[derive(Debug)] pub struct MapEvent { - pub mapped_addr: u32, - pub mapped_size: u32, - pub memperm: u32, - pub memstate: u32, + pub mapped_addr: u32_, + pub mapped_size: u32_, + pub memperm: u32_, + pub memstate: u32_, } impl ::core::default::Default for MapEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -250,9 +246,9 @@ pub enum DebugEventType { #[derive(Copy, Clone)] #[derive(Debug)] pub struct DebugEventInfo { - pub type_: u32, - pub thread_id: u32, - pub unknown: [u32; 2usize], + pub type_: u32_, + pub thread_id: u32_, + pub unknown: [u32_; 2usize], pub _bindgen_data_1_: [u64; 3usize], } impl DebugEventInfo { @@ -300,21 +296,21 @@ impl ::core::default::Default for DebugEventInfo { #[derive(Copy, Clone)] #[derive(Debug)] pub struct CodeSetInfo { - pub name: [u8; 8usize], - pub unk1: u16, - pub unk2: u16, - pub unk3: u32, - pub text_addr: u32, - pub text_size: u32, - pub ro_addr: u32, - pub ro_size: u32, - pub rw_addr: u32, - pub rw_size: u32, - pub text_size_total: u32, - pub ro_size_total: u32, - pub rw_size_total: u32, - pub unk4: u32, - pub program_id: u64, + pub name: [u8_; 8usize], + pub unk1: u16_, + pub unk2: u16_, + pub unk3: u32_, + pub text_addr: u32_, + pub text_size: u32_, + pub ro_addr: u32_, + pub ro_size: u32_, + pub rw_addr: u32_, + pub rw_size: u32_, + pub text_size_total: u32_, + pub ro_size_total: u32_, + pub rw_size_total: u32_, + pub unk4: u32_, + pub program_id: u64_, } impl ::core::default::Default for CodeSetInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -324,62 +320,62 @@ impl ::core::default::Default for CodeSetInfo { #[derive(Debug)] pub struct StartupInfo { pub priority: ::libc::c_int, - pub stack_size: u32, + pub stack_size: u32_, pub argc: ::libc::c_int, - pub argv: *mut u16, - pub envp: *mut u16, + pub argv: *mut u16_, + pub envp: *mut u16_, } impl ::core::default::Default for StartupInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } extern "C" { - pub fn svcControlMemory(addr_out: *mut u32, addr0: u32, addr1: u32, - size: u32, op: MemOp, perm: MemPerm) -> Result; - pub fn svcControlProcessMemory(process: Handle, addr0: u32, addr1: u32, - size: u32, type_: u32, perm: u32) + pub fn svcControlMemory(addr_out: *mut u32_, addr0: u32_, addr1: u32_, + size: u32_, op: MemOp, perm: MemPerm) -> Result; + pub fn svcControlProcessMemory(process: Handle, addr0: u32_, addr1: u32_, + size: u32_, type_: u32_, perm: u32_) -> Result; - pub fn svcCreateMemoryBlock(memblock: *mut Handle, addr: u32, size: u32, + pub fn svcCreateMemoryBlock(memblock: *mut Handle, addr: u32_, size: u32_, my_perm: MemPerm, other_perm: MemPerm) -> Result; - pub fn svcMapMemoryBlock(memblock: Handle, addr: u32, my_perm: MemPerm, + pub fn svcMapMemoryBlock(memblock: Handle, addr: u32_, my_perm: MemPerm, other_perm: MemPerm) -> Result; - pub fn svcMapProcessMemory(process: Handle, startAddr: u32, - endAddr: u32) -> Result; - pub fn svcUnmapProcessMemory(process: Handle, startAddr: u32, - endAddr: u32) -> Result; - pub fn svcUnmapMemoryBlock(memblock: Handle, addr: u32) -> Result; + pub fn svcMapProcessMemory(process: Handle, startAddr: u32_, + endAddr: u32_) -> Result; + pub fn svcUnmapProcessMemory(process: Handle, startAddr: u32_, + endAddr: u32_) -> Result; + pub fn svcUnmapMemoryBlock(memblock: Handle, addr: u32_) -> Result; pub fn svcStartInterProcessDma(dma: *mut Handle, dstProcess: Handle, dst: *mut ::libc::c_void, srcProcess: Handle, - src: *const ::libc::c_void, size: u32, + src: *const ::libc::c_void, size: u32_, dmaConfig: *mut ::libc::c_void) -> Result; pub fn svcStopDma(dma: Handle) -> Result; pub fn svcGetDmaState(dmaState: *mut ::libc::c_void, dma: Handle) -> Result; - pub fn svcQueryMemory(info: *mut MemInfo, out: *mut PageInfo, addr: u32) + pub fn svcQueryMemory(info: *mut MemInfo, out: *mut PageInfo, addr: u32_) -> Result; pub fn svcQueryProcessMemory(info: *mut MemInfo, out: *mut PageInfo, - process: Handle, addr: u32) -> Result; + process: Handle, addr: u32_) -> Result; pub fn svcInvalidateProcessDataCache(process: Handle, addr: *mut ::libc::c_void, - size: u32) -> Result; + size: u32_) -> Result; pub fn svcFlushProcessDataCache(process: Handle, - addr: *const ::libc::c_void, size: u32) + addr: *const ::libc::c_void, size: u32_) -> Result; pub fn svcReadProcessMemory(buffer: *mut ::libc::c_void, debug: Handle, - addr: u32, size: u32) -> Result; + addr: u32_, size: u32_) -> Result; pub fn svcWriteProcessMemory(debug: Handle, buffer: *const ::libc::c_void, - addr: u32, size: u32) -> Result; - pub fn svcOpenProcess(process: *mut Handle, processId: u32) -> Result; + addr: u32_, size: u32_) -> Result; + pub fn svcOpenProcess(process: *mut Handle, processId: u32_) -> Result; pub fn svcExitProcess(); pub fn svcTerminateProcess(process: Handle) -> Result; - pub fn svcGetProcessInfo(out: *mut i64, process: Handle, type_: u32) + pub fn svcGetProcessInfo(out: *mut s64, process: Handle, type_: u32_) -> Result; - pub fn svcGetProcessId(out: *mut u32, handle: Handle) -> Result; - pub fn svcGetProcessList(processCount: *mut i32, processIds: *mut u32, - processIdMaxCount: i32) -> Result; + pub fn svcGetProcessId(out: *mut u32_, handle: Handle) -> Result; + pub fn svcGetProcessList(processCount: *mut s32, processIds: *mut u32_, + processIdMaxCount: s32) -> Result; pub fn svcCreatePort(portServer: *mut Handle, portClient: *mut Handle, - name: *const ::libc::c_char, maxSessions: i32) + name: *const ::libc::c_char, maxSessions: s32) -> Result; pub fn svcConnectToPort(out: *mut Handle, portName: *const ::libc::c_char) -> Result; @@ -388,94 +384,96 @@ extern "C" { ro_ptr: *mut ::libc::c_void, data_ptr: *mut ::libc::c_void) -> Result; pub fn svcCreateProcess(out: *mut Handle, codeset: Handle, - arm11kernelcaps: *const u32, - arm11kernelcaps_num: u32) -> Result; + arm11kernelcaps: *const u32_, + arm11kernelcaps_num: u32_) -> Result; pub fn svcSetProcessAffinityMask(process: Handle, - affinitymask: *const u8, - processorcount: i32) -> Result; - pub fn svcSetProcessIdealProcessor(process: Handle, processorid: i32) + affinitymask: *const u8_, + processorcount: s32) -> Result; + pub fn svcSetProcessIdealProcessor(process: Handle, processorid: s32) -> Result; pub fn svcRun(process: Handle, info: *const StartupInfo) -> Result; pub fn svcCreateThread(thread: *mut Handle, entrypoint: ThreadFunc, - arg: u32, stack_top: *mut u32, - thread_priority: i32, processor_id: i32) -> Result; - pub fn svcOpenThread(thread: *mut Handle, process: Handle, threadId: u32) + arg: u32_, stack_top: *mut u32_, + thread_priority: s32, processor_id: s32) -> Result; + pub fn svcOpenThread(thread: *mut Handle, process: Handle, threadId: u32_) -> Result; pub fn svcExitThread(); - pub fn svcSleepThread(ns: i64); - pub fn svcGetThreadPriority(out: *mut i32, handle: Handle) -> Result; - pub fn svcSetThreadPriority(thread: Handle, prio: i32) -> Result; - pub fn svcGetThreadAffinityMask(affinitymask: *mut u8, thread: Handle, - processorcount: i32) -> Result; - pub fn svcSetThreadAffinityMask(thread: Handle, affinitymask: *const u8, - processorcount: i32) -> Result; - pub fn svcGetThreadIdealProcessor(processorid: *mut i32, thread: Handle) + pub fn svcSleepThread(ns: s64); + pub fn svcGetThreadPriority(out: *mut s32, handle: Handle) -> Result; + pub fn svcSetThreadPriority(thread: Handle, prio: s32) -> Result; + pub fn svcGetThreadAffinityMask(affinitymask: *mut u8_, thread: Handle, + processorcount: s32) -> Result; + pub fn svcSetThreadAffinityMask(thread: Handle, affinitymask: *const u8_, + processorcount: s32) -> Result; + pub fn svcGetThreadIdealProcessor(processorid: *mut s32, thread: Handle) -> Result; - pub fn svcSetThreadIdealProcessor(thread: Handle, processorid: i32) + pub fn svcSetThreadIdealProcessor(thread: Handle, processorid: s32) -> Result; - pub fn svcGetProcessorID() -> i32; - pub fn svcGetThreadId(out: *mut u32, handle: Handle) -> Result; + pub fn svcGetProcessorID() -> s32; + pub fn svcGetThreadId(out: *mut u32_, handle: Handle) -> Result; pub fn svcGetResourceLimit(resourceLimit: *mut Handle, process: Handle) -> Result; - pub fn svcGetResourceLimitLimitValues(values: *mut i64, + pub fn svcGetResourceLimitLimitValues(values: *mut s64, resourceLimit: Handle, - names: *mut u32, nameCount: i32) + names: *mut u32_, nameCount: s32) -> Result; - pub fn svcGetResourceLimitCurrentValues(values: *mut i64, + pub fn svcGetResourceLimitCurrentValues(values: *mut s64, resourceLimit: Handle, - names: *mut u32, nameCount: i32) + names: *mut u32_, nameCount: s32) -> Result; - pub fn svcGetProcessIdOfThread(out: *mut u32, handle: Handle) -> Result; - pub fn svcGetThreadInfo(out: *mut i64, thread: Handle, + pub fn svcGetProcessIdOfThread(out: *mut u32_, handle: Handle) -> Result; + pub fn svcGetThreadInfo(out: *mut s64, thread: Handle, type_: ThreadInfoType) -> Result; pub fn svcCreateMutex(mutex: *mut Handle, initially_locked: u8) -> Result; pub fn svcReleaseMutex(handle: Handle) -> Result; - pub fn svcCreateSemaphore(semaphore: *mut Handle, initial_count: i32, - max_count: i32) -> Result; - pub fn svcReleaseSemaphore(count: *mut i32, semaphore: Handle, - release_count: i32) -> Result; + pub fn svcCreateSemaphore(semaphore: *mut Handle, initial_count: s32, + max_count: s32) -> Result; + pub fn svcReleaseSemaphore(count: *mut s32, semaphore: Handle, + release_count: s32) -> Result; pub fn svcCreateEvent(event: *mut Handle, reset_type: ResetType) -> Result; pub fn svcSignalEvent(handle: Handle) -> Result; pub fn svcClearEvent(handle: Handle) -> Result; - pub fn svcWaitSynchronization(handle: Handle, nanoseconds: i64) -> Result; - pub fn svcWaitSynchronizationN(out: *mut i32, handles: *mut Handle, - handles_num: i32, wait_all: u8, - nanoseconds: i64) -> Result; + pub fn svcWaitSynchronization(handle: Handle, nanoseconds: s64) -> Result; + pub fn svcWaitSynchronizationN(out: *mut s32, handles: *mut Handle, + handles_num: s32, wait_all: u8, + nanoseconds: s64) -> Result; pub fn svcCreateAddressArbiter(arbiter: *mut Handle) -> Result; - pub fn svcArbitrateAddress(arbiter: Handle, addr: u32, - type_: ArbitrationType, value: i32, - nanoseconds: i64) -> Result; + pub fn svcArbitrateAddress(arbiter: Handle, addr: u32_, + type_: ArbitrationType, value: s32, + nanoseconds: s64) -> Result; pub fn svcSendSyncRequest(session: Handle) -> Result; pub fn svcAcceptSession(session: *mut Handle, port: Handle) -> Result; - pub fn svcReplyAndReceive(index: *mut i32, handles: *mut Handle, - handleCount: i32, replyTarget: Handle) + pub fn svcReplyAndReceive(index: *mut s32, handles: *mut Handle, + handleCount: s32, replyTarget: Handle) -> Result; - pub fn svcBindInterrupt(interruptId: u32, event: Handle, priority: i32, + pub fn svcBindInterrupt(interruptId: u32_, event: Handle, priority: s32, isManualClear: u8) -> Result; - pub fn svcUnbindInterrupt(interruptId: u32, event: Handle) -> Result; + pub fn svcUnbindInterrupt(interruptId: u32_, event: Handle) -> Result; pub fn svcCreateTimer(timer: *mut Handle, reset_type: ResetType) -> Result; - pub fn svcSetTimer(timer: Handle, initial: i64, interval: i64) -> Result; + pub fn svcSetTimer(timer: Handle, initial: s64, interval: s64) -> Result; pub fn svcCancelTimer(timer: Handle) -> Result; pub fn svcClearTimer(timer: Handle) -> Result; - pub fn svcGetSystemTick() -> u64; + pub fn svcGetSystemTick() -> u64_; pub fn svcCloseHandle(handle: Handle) -> Result; pub fn svcDuplicateHandle(out: *mut Handle, original: Handle) -> Result; - pub fn svcGetSystemInfo(out: *mut i64, type_: u32, param: i32) -> Result; - pub fn svcKernelSetState(type_: u32, param0: u32, param1: u32, - param2: u32) -> Result; + pub fn svcGetSystemInfo(out: *mut s64, type_: u32_, param: s32) -> Result; + pub fn svcKernelSetState(type_: u32_, param0: u32_, param1: u32_, + param2: u32_) -> Result; pub fn svcBreak(breakReason: UserBreakType); pub fn svcOutputDebugString(str: *const ::libc::c_char, length: ::libc::c_int) -> Result; - pub fn svcDebugActiveProcess(debug: *mut Handle, processId: u32) + pub fn svcDebugActiveProcess(debug: *mut Handle, processId: u32_) -> Result; pub fn svcBreakDebugProcess(debug: Handle) -> Result; pub fn svcTerminateDebugProcess(debug: Handle) -> Result; pub fn svcGetProcessDebugEvent(info: *mut DebugEventInfo, debug: Handle) -> Result; - pub fn svcContinueDebugEvent(debug: Handle, flags: u32) -> Result; + pub fn svcContinueDebugEvent(debug: Handle, flags: u32_) -> Result; pub fn svcBackdoor(callback: - ::core::option::Option i32>) + ::core::option::Option s32>) -> Result; } + +use ::types::*; diff --git a/ctru-sys/src/sys/inaddr.rs b/ctru-sys/src/sys/inaddr.rs index f16e233..d188f2c 100644 --- a/ctru-sys/src/sys/inaddr.rs +++ b/ctru-sys/src/sys/inaddr.rs @@ -5,11 +5,10 @@ non_upper_case_globals, non_snake_case)] -use ::types::*; use super::socket::*; -pub type in_port_t = uint16_t; -pub type in_addr_t = uint32_t; +pub type in_port_t = ::libc::uint16_t; +pub type in_addr_t = ::libc::uint32_t; #[repr(C)] #[derive(Copy, Clone)] #[derive(Debug)] @@ -41,4 +40,3 @@ pub struct ip_mreq { impl ::core::default::Default for ip_mreq { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - diff --git a/ctru-sys/src/sys/libc.rs b/ctru-sys/src/sys/libc.rs index ab8eb7c..3ae6456 100644 --- a/ctru-sys/src/sys/libc.rs +++ b/ctru-sys/src/sys/libc.rs @@ -85,8 +85,8 @@ pub type fsblkcnt_t = c_uint; pub type fsfilcnt_t = c_uint; extern "C" { - pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; - pub fn memrchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memchr(cx: *const c_void, c: c_int, n: ::libc::size_t) -> *mut c_void; + pub fn memrchr(cx: *const c_void, c: c_int, n: ::libc::size_t) -> *mut c_void; pub fn strlen(cs: *const c_char) -> size_t; - pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; + pub fn write(fd: c_int, buf: *const c_void, count: ::libc::size_t) -> ::libc::ssize_t; } diff --git a/ctru-sys/src/sys/mod.rs b/ctru-sys/src/sys/mod.rs index af15a1c..d2d4cbe 100644 --- a/ctru-sys/src/sys/mod.rs +++ b/ctru-sys/src/sys/mod.rs @@ -1,4 +1,3 @@ -pub mod libc; pub mod lock; -pub mod socket; pub mod inaddr; +pub mod socket; diff --git a/ctru-sys/src/sys/socket.rs b/ctru-sys/src/sys/socket.rs index ec544dc..19d1cb1 100644 --- a/ctru-sys/src/sys/socket.rs +++ b/ctru-sys/src/sys/socket.rs @@ -4,8 +4,8 @@ non_camel_case_types, non_upper_case_globals, non_snake_case)] -pub type socklen_t = uint32_t; -pub type sa_family_t = uint16_t; +pub type socklen_t = ::libc::uint32_t; +pub type sa_family_t = ::libc::uint16_t; #[repr(C)] #[derive(Copy, Clone)] #[derive(Debug)] @@ -53,17 +53,17 @@ extern "C" { optlen: *mut socklen_t) -> ::libc::c_int; pub fn listen(sockfd: ::libc::c_int, backlog: ::libc::c_int) -> ::libc::c_int; - pub fn recv(sockfd: ::libc::c_int, buf: *mut ::libc::c_void, len: size_t, - flags: ::libc::c_int) -> ssize_t; + pub fn recv(sockfd: ::libc::c_int, buf: *mut ::libc::c_void, len: ::libc::size_t, + flags: ::libc::c_int) -> ::libc::ssize_t; pub fn recvfrom(sockfd: ::libc::c_int, buf: *mut ::libc::c_void, - len: size_t, flags: ::libc::c_int, + len: ::libc::size_t, flags: ::libc::c_int, src_addr: *mut sockaddr, addrlen: *mut socklen_t) - -> ssize_t; + -> ::libc::ssize_t; pub fn send(sockfd: ::libc::c_int, buf: *const ::libc::c_void, - len: size_t, flags: ::libc::c_int) -> ssize_t; + len: ::libc::size_t, flags: ::libc::c_int) -> ::libc::ssize_t; pub fn sendto(sockfd: ::libc::c_int, buf: *const ::libc::c_void, - len: size_t, flags: ::libc::c_int, - dest_addr: *const sockaddr, addrlen: socklen_t) -> ssize_t; + len: ::libc::size_t, flags: ::libc::c_int, + dest_addr: *const sockaddr, addrlen: socklen_t) -> ::libc::ssize_t; pub fn setsockopt(sockfd: ::libc::c_int, level: ::libc::c_int, optname: ::libc::c_int, optval: *const ::libc::c_void, optlen: socklen_t) -> ::libc::c_int; @@ -73,5 +73,3 @@ extern "C" { protocol: ::libc::c_int) -> ::libc::c_int; pub fn sockatmark(sockfd: ::libc::c_int) -> ::libc::c_int; } - -use ::types::*; diff --git a/ctru-sys/src/types.rs b/ctru-sys/src/types.rs index 92534b7..d5baa88 100644 --- a/ctru-sys/src/types.rs +++ b/ctru-sys/src/types.rs @@ -22,10 +22,6 @@ pub type vs32 = s32; pub type vs64 = s64; pub type Handle = u32_; pub type Result = s32; -pub type size_t = usize; -pub type ssize_t = isize; -pub type uint32_t = u32; -pub type uint16_t = u16; pub type ThreadFunc = ::core::option::Option; pub type voidfn = ::core::option::Option; diff --git a/src/lib.rs b/src/lib.rs index a4252a1..bfdb614 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #[macro_use] extern crate bitflags; +extern crate widestring; extern crate ctru_sys as libctru; diff --git a/src/services/fs.rs b/src/services/fs.rs index 7e80607..cf1a443 100644 --- a/src/services/fs.rs +++ b/src/services/fs.rs @@ -8,11 +8,13 @@ use std::marker::PhantomData; use std::ptr; use std::slice; use std::mem; -use std::arc::Arc; +use std::sync::Arc; use std::path::{Path, PathBuf}; use std::ffi::OsString; +use widestring::{WideCString, WideCStr}; + use libctru::services::fs::*; bitflags! { @@ -616,8 +618,11 @@ impl<'a> DirEntry<'a> { /// Returns the bare file name of this directory entry without any other leading path /// component. pub fn file_name(&self) -> OsString { - let filename = truncate_utf16_at_nul(&self.entry.name); - OsString::from_wide(filename) + unsafe { + let filename = truncate_utf16_at_nul(&self.entry.name); + let filename = WideCStr::from_ptr_str(filename.as_ptr()); + filename.to_os_string() + } } } @@ -797,8 +802,8 @@ pub fn rename(arch: &Archive, from: P, to: Q) -> Result<(), i32> } // TODO: Determine if we should check UTF-16 paths for interior NULs -fn to_utf16(path: &Path) -> Vec { - path.as_os_str().encode_wide().collect::>() +fn to_utf16(path: &Path) -> WideCString { + WideCString::from_str(path).unwrap() } // Adapted from sys/windows/fs.rs in libstd diff --git a/std/Cargo.toml b/std/Cargo.toml deleted file mode 100644 index f23c3c2..0000000 --- a/std/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "std" -version = "0.0.0" - -[lib] -crate-type = ["rlib"] - -[dependencies.alloc_system3ds] -git = "https://github.com/rust3ds/alloc_system3ds" - -[dependencies.ctru-sys] -path = "../ctru-sys" - -[dependencies.spin] -version = "0.4" diff --git a/std/src/ffi/mod.rs b/std/src/ffi/mod.rs deleted file mode 100644 index d4ed3a7..0000000 --- a/std/src/ffi/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub use self::c_str::{CString, CStr}; -pub use self::os_str::{OsString, OsStr}; - -mod c_str; -mod os_str; diff --git a/std/src/lib.rs b/std/src/lib.rs deleted file mode 100644 index 48d0e1d..0000000 --- a/std/src/lib.rs +++ /dev/null @@ -1,100 +0,0 @@ -#![feature(alloc)] -#![feature(allow_internal_unstable)] -#![feature(collections)] -#![feature(const_fn)] -#![feature(core_intrinsics)] -#![feature(char_escape_debug)] -#![feature(float_extras)] -#![feature(int_error_internals)] -#![feature(lang_items)] -#![feature(macro_reexport)] -#![feature(optin_builtin_traits)] -#![feature(prelude_import)] -#![feature(raw)] -#![feature(slice_concat_ext)] -#![feature(slice_patterns)] -#![feature(str_internals)] -#![feature(try_from)] -#![feature(unicode)] -#![feature(zero_one)] -#![allow(non_camel_case_types)] -#![no_std] - -#[prelude_import] -#[allow(unused)] -use prelude::v1::*; -#[macro_reexport(assert, assert_eq, debug_assert, debug_assert_eq, - unreachable, unimplemented, write, writeln)] -extern crate core as __core; -#[macro_use] -#[macro_reexport(vec, format)] -extern crate collections as core_collections; -extern crate alloc; -extern crate std_unicode; - -extern crate alloc_system; - -extern crate ctru_sys as libctru; -extern crate spin; - -pub use core::any; -pub use core::cell; -pub use core::clone; -pub use core::cmp; -pub use core::convert; -pub use core::default; -pub use core::hash; -pub use core::intrinsics; -pub use core::iter; -pub use core::marker; -pub use core::mem; -pub use core::ops; -pub use core::ptr; -pub use core::raw; -pub use core::result; -pub use core::option; - -pub use alloc::arc; -pub use alloc::boxed; -pub use alloc::rc; - -pub use core_collections::borrow; -pub use core_collections::fmt; -pub use core_collections::slice; -pub use core_collections::str; -pub use core_collections::string; -pub use core_collections::vec; - -pub use std_unicode::char; - -#[macro_use] -pub mod macros; - -pub mod prelude; - -pub use core::isize; -pub use core::i8; -pub use core::i16; -pub use core::i32; -pub use core::i64; - -pub use core::usize; -pub use core::u8; -pub use core::u16; -pub use core::u32; -pub use core::u64; - -#[path = "num/f32.rs"] pub mod f32; -#[path = "num/f64.rs"] pub mod f64; - -pub mod ascii; -pub mod error; -pub mod ffi; -pub mod io; -pub mod num; -pub mod path; -pub mod rt; -pub mod sync; -mod memchr; -mod panicking; -mod sys; diff --git a/std/src/macros.rs b/std/src/macros.rs deleted file mode 100644 index f1a5b75..0000000 --- a/std/src/macros.rs +++ /dev/null @@ -1,105 +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 entry point for panic of Rust threads. -/// -/// 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. -/// -/// The multi-argument form of this macro panics with a string and has the -/// `format!` syntax for building a string. -/// -/// # 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] -macro_rules! panic { - () => ({ - panic!("explicit panic") - }); - ($msg:expr) => ({ - $crate::rt::begin_panic($msg, { - // static requires less code at runtime, more constant data - static _FILE_LINE: (&'static str, u32) = (file!(), line!()); - &_FILE_LINE - }) - }); - ($fmt:expr, $($arg:tt)+) => ({ - $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), { - // The leading _'s are to avoid dead code warnings if this is - // used inside a dead function. Just `#[allow(dead_code)]` is - // insufficient, since the user may have - // `#[forbid(dead_code)]` and which cannot be overridden. - static _FILE_LINE: (&'static str, u32) = (file!(), line!()); - &_FILE_LINE - }) - }); -} - -/// Helper macro for unwrapping `Result` values while returning early with an -/// error if the value of the expression is `Err`. Can only be used in -/// functions that return `Result` because of the early return of `Err` that -/// it provides. -/// -/// # Examples -/// -/// ``` -/// use std::io; -/// use std::fs::File; -/// use std::io::prelude::*; -/// -/// fn write_to_file_using_try() -> Result<(), io::Error> { -/// let mut file = try!(File::create("my_best_friends.txt")); -/// try!(file.write_all(b"This is a list of my best friends.")); -/// println!("I wrote to the file"); -/// Ok(()) -/// } -/// // This is equivalent to: -/// fn write_to_file_using_match() -> Result<(), io::Error> { -/// let mut file = try!(File::create("my_best_friends.txt")); -/// match file.write_all(b"This is a list of my best friends.") { -/// Ok(v) => v, -/// Err(e) => return Err(e), -/// } -/// println!("I wrote to the file"); -/// Ok(()) -/// } -/// ``` -#[macro_export] -macro_rules! try { - ($expr:expr) => (match $expr { - $crate::result::Result::Ok(val) => val, - $crate::result::Result::Err(err) => { - return $crate::result::Result::Err($crate::convert::From::from(err)) - } - }) -} - -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ( - $crate::io::_print(format_args!($($arg)*)); - ); -} - -#[macro_export] -macro_rules! println { - () => (print!("\n")); - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); -} diff --git a/std/src/memchr.rs b/std/src/memchr.rs deleted file mode 100644 index 210ba80..0000000 --- a/std/src/memchr.rs +++ /dev/null @@ -1,397 +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.) -/// -/// # Example -/// -/// This shows how to find the first position of a byte in a byte string. -/// -/// ```rust,ignore -/// use memchr::memchr; -/// -/// let haystack = b"the quick brown fox"; -/// assert_eq!(memchr(b'k', haystack), Some(8)); -/// ``` -pub fn memchr(needle: u8, haystack: &[u8]) -> Option { - fn memchr_specific(needle: u8, haystack: &[u8]) -> Option { - use libctru::libc; - - let p = unsafe { - libc::memchr(haystack.as_ptr() as *const libc::c_void, - needle as libc::c_int, - haystack.len() as libc::size_t) - }; - if p.is_null() { - None - } else { - Some(p as usize - (haystack.as_ptr() as usize)) - } - } - memchr_specific(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. -/// -/// # Example -/// -/// This shows how to find the last position of a byte in a byte string. -/// -/// ```rust,ignore -/// use memchr::memrchr; -/// -/// let haystack = b"the quick brown fox"; -/// assert_eq!(memrchr(b'o', haystack), Some(17)); -/// ``` -pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { - fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option { - use libctru::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() as libc::size_t) - }; - if p.is_null() { - None - } else { - Some(p as usize - (haystack.as_ptr() as usize)) - } - } - memrchr_specific(needle, haystack) -} - -#[allow(dead_code)] -mod fallback { - use core::cmp; - use core::mem; - - const LO_U64: u64 = 0x0101010101010101; - const HI_U64: u64 = 0x8080808080808080; - - // use truncation - const LO_USIZE: usize = LO_U64 as usize; - const HI_USIZE: usize = HI_U64 as usize; - - /// Return `true` if `x` contains any zero byte. - /// - /// From *Matters Computational*, J. Arndt - /// - /// "The idea is to subtract one from each of the bytes and then look for - /// bytes where the borrow propagated all the way to the most significant - /// bit." - #[inline] - fn contains_zero_byte(x: usize) -> bool { - x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 - } - - #[cfg(target_pointer_width = "32")] - #[inline] - fn repeat_byte(b: u8) -> usize { - let mut rep = (b as usize) << 8 | b as usize; - rep = rep << 16 | rep; - rep - } - - #[cfg(target_pointer_width = "64")] - #[inline] - fn repeat_byte(b: u8) -> usize { - let mut rep = (b as usize) << 8 | b as usize; - rep = rep << 16 | rep; - rep = rep << 32 | rep; - rep - } - - /// Return the first index matching the byte `a` in `text`. - pub fn memchr(x: u8, text: &[u8]) -> Option { - // Scan for a single byte value by reading two `usize` words at a time. - // - // Split `text` in three parts - // - unaligned initial part, before the first word aligned address in text - // - body, scan by 2 words at a time - // - the last remaining part, < 2 word size - let len = text.len(); - let ptr = text.as_ptr(); - let usize_bytes = mem::size_of::(); - - // search up to an aligned boundary - let align = (ptr as usize) & (usize_bytes - 1); - let mut offset; - if align > 0 { - offset = cmp::min(usize_bytes - align, len); - if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { - return Some(index); - } - } else { - offset = 0; - } - - // search the body of the text - let repeated_x = repeat_byte(x); - - if len >= 2 * usize_bytes { - while offset <= len - 2 * usize_bytes { - unsafe { - let u = *(ptr.offset(offset as isize) as *const usize); - let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize); - - // break if there is a matching byte - let zu = contains_zero_byte(u ^ repeated_x); - let zv = contains_zero_byte(v ^ repeated_x); - if zu || zv { - break; - } - } - offset += usize_bytes * 2; - } - } - - // find the byte after the point the body loop stopped - text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i) - } - - /// Return the last index matching the byte `a` in `text`. - pub fn memrchr(x: u8, text: &[u8]) -> Option { - // Scan for a single byte value by reading two `usize` words at a time. - // - // Split `text` in three parts - // - unaligned tail, after the last word aligned address in text - // - body, scan by 2 words at a time - // - the first remaining bytes, < 2 word size - let len = text.len(); - let ptr = text.as_ptr(); - let usize_bytes = mem::size_of::(); - - // search to an aligned boundary - let end_align = (ptr as usize + len) & (usize_bytes - 1); - let mut offset; - if end_align > 0 { - offset = if end_align >= len { - 0 - } else { - len - end_align - }; - if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { - return Some(offset + index); - } - } else { - offset = len; - } - - // search the body of the text - let repeated_x = repeat_byte(x); - - while offset >= 2 * usize_bytes { - unsafe { - let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize); - let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize); - - // break if there is a matching byte - let zu = contains_zero_byte(u ^ repeated_x); - let zv = contains_zero_byte(v ^ repeated_x); - if zu || zv { - break; - } - } - offset -= 2 * usize_bytes; - } - - // find the byte before the point the body loop stopped - text[..offset].iter().rposition(|elt| *elt == x) - } - - // test fallback implementations on all platforms - #[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_reversed() { - let mut data = [1u8; 64]; - let needle = 2; - let pos = 40; - data[pos] = needle; - for start in 0..16 { - assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); - } - } -} - -#[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/std/src/prelude/mod.rs b/std/src/prelude/mod.rs deleted file mode 100644 index a3a6d96..0000000 --- a/std/src/prelude/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod v1; diff --git a/std/src/prelude/v1.rs b/std/src/prelude/v1.rs deleted file mode 100644 index e17d2ec..0000000 --- a/std/src/prelude/v1.rs +++ /dev/null @@ -1,49 +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. - -// Reexported core operators -#[doc(no_inline)] -pub use marker::{Copy, Send, Sized, Sync}; -#[doc(no_inline)] -pub use ops::{Drop, Fn, FnMut, FnOnce}; - -// Reexported functions -#[doc(no_inline)] -pub use mem::drop; - -// Reexported types and traits -#[doc(no_inline)] -pub use boxed::Box; -#[doc(no_inline)] -pub use borrow::ToOwned; -#[doc(no_inline)] -pub use clone::Clone; -#[doc(no_inline)] -pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; -#[doc(no_inline)] -pub use convert::{AsRef, AsMut, Into, From}; -#[doc(no_inline)] -pub use default::Default; -#[doc(no_inline)] -pub use iter::{Iterator, Extend, IntoIterator}; -#[doc(no_inline)] -pub use iter::{DoubleEndedIterator, ExactSizeIterator}; -#[doc(no_inline)] -pub use option::Option::{self, Some, None}; -#[doc(no_inline)] -pub use result::Result::{self, Ok, Err}; -#[doc(no_inline)] -pub use slice::SliceConcatExt; -#[doc(no_inline)] -pub use string::{String, ToString}; -#[doc(no_inline)] -pub use vec::Vec; diff --git a/std/src/sync/mod.rs b/std/src/sync/mod.rs deleted file mode 100644 index 62152ed..0000000 --- a/std/src/sync/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod mutex; - -pub use self::mutex::{Mutex, MutexGuard}; - -pub type LockResult = Result; diff --git a/std/src/sync/mutex.rs b/std/src/sync/mutex.rs deleted file mode 100644 index 03ea729..0000000 --- a/std/src/sync/mutex.rs +++ /dev/null @@ -1,92 +0,0 @@ -use cell::UnsafeCell; -use borrow::{Borrow, BorrowMut}; -use ops::{Deref, DerefMut}; - -use super::LockResult; - -use libctru::synchronization::*; - -/// A mutex based on libctru's LightLock primitive -pub struct Mutex { - mutex: Box, - data: UnsafeCell, -} - -/// Mutex guard -#[must_use] -pub struct MutexGuard<'a, T: ?Sized + 'a> { - inner: &'a Mutex, -} - -// NOTE: This is used when implementing condvar, which hasn't been done yet -#[allow(dead_code)] -pub fn guard_lock<'a, T: ?Sized + 'a>(guard: &'a MutexGuard<'a, T>) -> &'a LightLock { - &guard.inner.mutex -} - -impl Mutex { - pub fn new(t: T) -> Mutex { - unsafe { - let mut mutex = Box::new(0); - LightLock_Init(mutex.borrow_mut()); - Mutex { - mutex: mutex, - data: UnsafeCell::new(t), - } - } - } - - pub fn into_inner(self) -> T { - unsafe { self.data.into_inner() } - } -} - -impl Mutex { - pub fn lock(&self) -> MutexGuard { - unsafe { - LightLock_Lock(self.mutex.borrow()); - MutexGuard { inner: self } - } - } - - pub fn try_lock(&self) -> LockResult> { - unsafe { - let locked = LightLock_TryLock(self.mutex.borrow()); - if locked == 0 { - Ok(MutexGuard { inner: self }) - } else { - Err(()) - } - } - } - - pub fn get_mut(&mut self) -> &mut T { - unsafe { &mut *self.data.get() } - } -} - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} - -impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { - fn drop(&mut self) { - unsafe { LightLock_Unlock(self.inner.mutex.borrow()); - } - } -} - -impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.inner.data.get() } - } -} - -impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.inner.data.get() } - } -} - -impl<'a, T: ?Sized> !Send for MutexGuard<'a, T> {} diff --git a/std/src/sys/mod.rs b/std/src/sys/mod.rs deleted file mode 100644 index 86f49e5..0000000 --- a/std/src/sys/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -/// 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; -} - -pub mod wtf8; diff --git a/std/src/sys/wtf8.rs b/std/src/sys/wtf8.rs deleted file mode 100644 index 8f0662c..0000000 --- a/std/src/sys/wtf8.rs +++ /dev/null @@ -1,1204 +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 ascii::*; -use borrow::Cow; -use std_unicode::char; -use fmt; -use hash::{Hash, Hasher}; -use iter::FromIterator; -use mem; -use ops; -use slice; -use str; -use super::AsInner; - -const UTF8_REPLACEMENT_CHARACTER: &'static [u8] = b"\xEF\xBF\xBD"; - -/// 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) -> Result<(), fmt::Error> { - 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() - } -} - -/// 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) -> Result<(), fmt::Error> { - 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) } - } - - /// 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) - } - - /// 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); - } - None => return unsafe { String::from_utf8_unchecked(self.bytes) }, - } - } - } -} - -/// 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 core::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; - loop { - match self.next_surrogate(pos) { - None => break, - Some((surrogate_pos, surrogate)) => { - 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 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) - } - - /// 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); - 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); - 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 = match iter.next() { - None => return None, - Some(&b) => b, - }; - 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, - } - } -} - - -/// 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)) - } -} - -#[derive(Clone)] -pub struct EncodeWide<'a> { - code_points: Wtf8CodePoints<'a>, - extra: u16, -} - -// Copied from libunicode/u_str.rs -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 AsciiExt for Wtf8 { - type Owned = Wtf8Buf; - - fn is_ascii(&self) -> bool { - self.bytes.is_ascii() - } - fn to_ascii_uppercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() } - } - fn to_ascii_lowercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() } - } - fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool { - self.bytes.eq_ignore_ascii_case(&other.bytes) - } - - fn make_ascii_uppercase(&mut self) { - self.bytes.make_ascii_uppercase() - } - fn make_ascii_lowercase(&mut self) { - self.bytes.make_ascii_lowercase() - } -} - -#[cfg(test)] -mod tests { - use collections::borrow::Cow; - use collections::{String, Vec}; - 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_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]); - } -}